Unify stret detection between the generator and platform assemblies, and fix stret detection on watchOS. Fixes #44709.

Unify the code to determine whether a particular return type requires a stret
signature or not between the generator and platform assemblies.

Also fix the stret detection for armv7k, whose calling convention is not
identical to armv7(s): there's the concept of homogeneous structures, which
contains multiple elements of only one type, and which is sometimes passed in
registers on armv7k.

https://bugzilla.xamarin.com/show_bug.cgi?id=44709
This commit is contained in:
Rolf Bjarne Kvinge 2016-10-11 19:24:23 +02:00
Родитель a9188a3bf3
Коммит 9d85ca79ab
7 изменённых файлов: 352 добавлений и 135 удалений

Просмотреть файл

@ -1420,3 +1420,9 @@ This usually indicates a bug in Xamarin.iOS; please file a bug at http://bugzill
The DelegateProxy attribute for the method in question is invalid. The DelegateProxy attribute for the method in question is invalid.
This usually indicates a bug in Xamarin.iOS; please file a bug at http://bugzilla.xamarin.com. This usually indicates a bug in Xamarin.iOS; please file a bug at http://bugzilla.xamarin.com.
<h3><a name="MT8018"/>MT8018: Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.</h3>
This indicates a bug in Xamarin.iOS. Please file a bug at [http://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
<h3><

Просмотреть файл

@ -5,6 +5,7 @@ GENERATOR_SOURCES = \
$(TOP)/src/generator.cs \ $(TOP)/src/generator.cs \
$(TOP)/src/generator-enums.cs \ $(TOP)/src/generator-enums.cs \
$(TOP)/src/generator-filters.cs \ $(TOP)/src/generator-filters.cs \
$(TOP)/src/ObjCRuntime/Stret.cs \
$(MONO_PATH)/mcs/class/Mono.Options/Mono.Options/Options.cs \ $(MONO_PATH)/mcs/class/Mono.Options/Mono.Options/Options.cs \
GENERATOR_DEFINES = -d:GENERATOR -d:NET_4_0 GENERATOR_DEFINES = -d:GENERATOR -d:NET_4_0

Просмотреть файл

@ -567,52 +567,58 @@ namespace XamCore.Registrar {
if (trampoline != Trampoline.None) if (trampoline != Trampoline.None)
return trampoline; return trampoline;
var isStaticTrampoline = IsStatic && !IsCategoryInstance; #if MTOUCH || MMP
trampoline = isStaticTrampoline ? Trampoline.Static : Trampoline.Normal; throw ErrorHelper.CreateError (8018, "Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.");
#else
var return_type = Registrar.GetReturnType (Method); var mi = (System.Reflection.MethodInfo) Method;
var is_value_type = Registrar.IsValueType (return_type) && !Registrar.IsEnum (return_type); bool is_stret;
var is_corlib = is_value_type ? Registrar.IsCorlibType (return_type) : false; #if __WATCHOS__
is_stret = Runtime.Arch == Arch.DEVICE ? Stret.ArmNeedStret (mi) : Stret.X86NeedStret (mi);
if (is_value_type && Registrar.IsGenericType (return_type)) #elif MONOMAC
throw Registrar.CreateException (4104, Method, "The registrar cannot marshal the return value of type `{0}` in the method `{1}.{2}`.", Registrar.GetTypeFullName (return_type), Registrar.GetTypeFullName (DeclaringType.Type), Registrar.GetDescriptiveMethodName (Method)); is_stret = IntPtr.Size == 8 ? Stret.X86_64NeedStret (mi) : Stret.X86NeedStret (mi);
#elif __IOS__
var size = is_value_type ? Registrar.GetValueTypeSize (return_type) : 0; if (Runtime.Arch == Arch.DEVICE) {
is_stret = IntPtr.Size == 4 && Stret.ArmNeedStret (mi);
if (is_value_type && !is_corlib && (!Registrar.IsSimulatorOrDesktop || size > 4)) {
trampoline = isStaticTrampoline ? Trampoline.StaticStret : Trampoline.Stret;
if (Registrar.IsSimulatorOrDesktop) {
if (Registrar.Is64Bits) {
if (size > 16) {
trampoline = isStaticTrampoline ? Trampoline.StaticStret : Trampoline.Stret;
} else { } else {
trampoline = isStaticTrampoline ? Trampoline.Static : Trampoline.Normal; is_stret = IntPtr.Size == 4 ? Stret.X86NeedStret (mi) : Stret.X86_64NeedStret (mi);
} }
#elif __TVOS__
is_stret = Runtime.Arch == Arch.SIMULATOR && Stret.X86_64NeedStret (mi);
#else
#error unknown architecture
#endif
var is_static_trampoline = IsStatic && !IsCategoryInstance;
var is_value_type = Registrar.IsValueType (ReturnType) && !Registrar.IsEnum (ReturnType);
if (is_value_type && Registrar.IsGenericType (ReturnType))
throw Registrar.CreateException (4104, Method, "The registrar cannot marshal the return value of type `{0}` in the method `{1}.{2}`.", Registrar.GetTypeFullName (ReturnType), Registrar.GetTypeFullName (DeclaringType.Type), Registrar.GetDescriptiveMethodName (Method));
if (is_stret) {
if (Registrar.IsSimulatorOrDesktop && !Registrar.Is64Bits) {
trampoline = is_static_trampoline ? Trampoline.X86_DoubleABI_StaticStretTrampoline : Trampoline.X86_DoubleABI_StretTrampoline;
} else { } else {
if (size > 8) { trampoline = is_static_trampoline ? Trampoline.StaticStret : Trampoline.Stret;
trampoline = isStaticTrampoline ? Trampoline.X86_DoubleABI_StaticStretTrampoline : Trampoline.X86_DoubleABI_StretTrampoline;
} else {
trampoline = isStaticTrampoline ? Trampoline.StaticLong : Trampoline.Long;
}
}
} }
} else { } else {
switch (Signature [0]) { switch (Signature [0]) {
case 'Q': case 'Q':
case 'q': case 'q':
trampoline = isStaticTrampoline ? Trampoline.StaticLong : Trampoline.Long; trampoline = is_static_trampoline ? Trampoline.StaticLong : Trampoline.Long;
break; break;
case 'f': case 'f':
trampoline = isStaticTrampoline ? Trampoline.StaticSingle : Trampoline.Single; trampoline = is_static_trampoline ? Trampoline.StaticSingle : Trampoline.Single;
break; break;
case 'd': case 'd':
trampoline = isStaticTrampoline ? Trampoline.StaticDouble : Trampoline.Double; trampoline = is_static_trampoline ? Trampoline.StaticDouble : Trampoline.Double;
break;
default:
trampoline = is_static_trampoline ? Trampoline.Static : Trampoline.Normal;
break; break;
} }
} }
return trampoline; return trampoline;
#endif
} }
set { set {
trampoline = value; trampoline = value;

297
src/ObjCRuntime/Stret.cs Normal file
Просмотреть файл

@ -0,0 +1,297 @@
//
// Stret.cs: Code to determine if a function is a stret function or not.
//
// This file is shared between the product assemblies and the generator.
//
// Authors:
// Rolf Bjarne Kvinge <rolf@xamarin.com>
//
// Copyright 2016 Xamarin Inc.
//
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using XamCore.Foundation;
namespace XamCore.ObjCRuntime
{
class Stret
{
#if __WATCHOS__
static bool IsHomogeneousAggregateSmallEnough_Armv7k (Type t, int members)
{
// https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L5516-L5519
return members <= 4;
}
static bool IsHomogeneousAggregateBaseType_Armv7k (Type t)
{
// https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L5500-L5514
if (t == typeof (float) || t == typeof (double) || t == typeof (nfloat))
return true;
return false;
}
static bool IsHomogeneousAggregate_Armv7k (List<Type> fieldTypes)
{
// Very simplified version of https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L4051
// since C# supports a lot less types than clang does.
if (fieldTypes.Count == 0)
return false;
if (!IsHomogeneousAggregateSmallEnough_Armv7k (fieldTypes [0], fieldTypes.Count))
return false;
if (!IsHomogeneousAggregateBaseType_Armv7k (fieldTypes [0]))
return false;
for (int i = 1; i < fieldTypes.Count; i++) {
if (fieldTypes [0] != fieldTypes [i])
return false;
}
return true;
}
#endif
static bool IsMagicTypeOrCorlibType (Type t)
{
#if __UNIFIED__
switch (t.Name) {
case "nint":
case "nuint":
case "nfloat":
if (t.Namespace != "System")
return false;
return t.Assembly == typeof (NSObject).Assembly;
default:
return t.Assembly == typeof (object).Assembly;
}
#else
return t.Assembly == typeof (object).Assembly;
#endif
}
public static bool ArmNeedStret (MethodInfo mi)
{
#if MONOMAC || __TVOS__
return false;
#else
Type t = mi.ReturnType;
if (!t.IsValueType || t.IsEnum || IsMagicTypeOrCorlibType (t))
return false;
var fieldTypes = new List<Type> ();
var size = GetValueTypeSize (t, fieldTypes, false);
#if __WATCHOS__
// According to clang watchOS passes arguments bigger than 16 bytes by reference.
// https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L5248-L5250
// https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L5542-L5543
if (size <= 16)
return false;
// Except homogeneous aggregates, which are not stret either.
if (IsHomogeneousAggregate_Armv7k (fieldTypes))
return false;
#elif __IOS__
if (size <= 4 && fieldTypes.Count == 1) {
switch (fieldTypes [0].FullName) {
case "System.Char":
case "System.Byte":
case "System.SByte":
case "System.UInt16":
case "System.Int16":
case "System.UInt32":
case "System.Int32":
case "System.IntPtr":
case "System.nuint":
case "System.uint":
return false;
// floating-point types are stret
}
}
#else
#error Unknown architecture
#endif
return true;
#endif // MONOMAC
}
public static bool X86NeedStret (MethodInfo mi)
{
Type t = mi.ReturnType;
if (!t.IsValueType || t.IsEnum || IsMagicTypeOrCorlibType (t))
return false;
var fieldTypes = new List<Type> ();
var size = GetValueTypeSize (t, fieldTypes, false);
if (size > 8)
return true;
if (fieldTypes.Count == 3)
return true;
return false;
}
public static bool X86_64NeedStret (MethodInfo mi)
{
#if __UNIFIED__
Type t = mi.ReturnType;
if (!t.IsValueType || t.IsEnum || IsMagicTypeOrCorlibType (t))
return false;
var fieldTypes = new List<Type> ();
return GetValueTypeSize (t, fieldTypes, true) > 16;
#else
return false;
#endif
}
static int GetValueTypeSize (Type type, List<Type> fieldTypes, bool is_64_bits)
{
int size = 0;
int maxElementSize = 1;
if (type.IsExplicitLayout) {
// Find the maximum of "field size + field offset" for each field.
foreach (var field in type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
var fieldOffset = (FieldOffsetAttribute) Attribute.GetCustomAttribute (field, typeof (FieldOffsetAttribute));
var elementSize = 0;
GetValueTypeSize (type, field.FieldType, fieldTypes, is_64_bits, ref elementSize, ref maxElementSize);
size = Math.Max (size, elementSize + fieldOffset.Value);
}
} else {
GetValueTypeSize (type, type, fieldTypes, is_64_bits, ref size, ref maxElementSize);
}
if (size % maxElementSize != 0)
size += (maxElementSize - size % maxElementSize);
return size;
}
static int AlignAndAdd (Type original_type, int size, int add, ref int max_element_size)
{
max_element_size = Math.Max (max_element_size, add);
if (size % add != 0)
size += add - size % add;
return size += add;
}
static void GetValueTypeSize (Type original_type, Type type, List<Type> field_types, bool is_64_bits, ref int size, ref int max_element_size)
{
// FIXME:
// SIMD types are not handled correctly here (they need 16-bit alignment).
// However we don't annotate those types in any way currently, so first we'd need to
// add the proper attributes so that the generator can distinguish those types from other types.
var type_size = 0;
switch (type.FullName) {
case "System.Char":
case "System.Boolean":
case "System.SByte":
case "System.Byte":
type_size = 1;
break;
case "System.Int16":
case "System.UInt16":
type_size = 2;
break;
case "System.Single":
case "System.Int32":
case "System.UInt32":
type_size = 4;
break;
case "System.Double":
case "System.Int64":
case "System.UInt64":
type_size = 8;
break;
case "System.IntPtr":
case "System.nfloat":
case "System.nuint":
case "System.nint":
type_size = is_64_bits ? 8 : 4;
break;
}
if (type_size != 0) {
field_types.Add (type);
size = AlignAndAdd (original_type, size, type_size, ref max_element_size);
return;
}
// composite struct
foreach (var field in type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
var marshalAs = (MarshalAsAttribute) Attribute.GetCustomAttribute (field, typeof (MarshalAsAttribute));
if (marshalAs == null) {
GetValueTypeSize (original_type, field.FieldType, field_types, is_64_bits, ref size, ref max_element_size);
continue;
}
var multiplier = 1;
switch (marshalAs.Value) {
case UnmanagedType.ByValArray:
var types = new List<Type> ();
GetValueTypeSize (original_type, field.FieldType.GetElementType (), types, is_64_bits, ref type_size, ref max_element_size);
multiplier = marshalAs.SizeConst;
break;
case UnmanagedType.U1:
case UnmanagedType.I1:
type_size = 1;
break;
case UnmanagedType.U2:
case UnmanagedType.I2:
type_size = 2;
break;
case UnmanagedType.U4:
case UnmanagedType.I4:
case UnmanagedType.R4:
type_size = 4;
break;
case UnmanagedType.U8:
case UnmanagedType.I8:
case UnmanagedType.R8:
type_size = 8;
break;
default:
throw new Exception ($"Unhandled MarshalAs attribute: {marshalAs.Value} on field {field.DeclaringType.FullName}.{field.Name}");
}
field_types.Add (field.FieldType);
size = AlignAndAdd (original_type, size, type_size, ref max_element_size);
size += (multiplier - 1) * size;
}
}
public static bool NeedStret (MethodInfo mi)
{
if (X86NeedStret (mi))
return true;
#if __UNIFIED__
if (X86_64NeedStret (mi))
return true;
#endif
#if !MONOMAC
if (ArmNeedStret (mi))
return true;
#endif
return false;
}
}
}

Просмотреть файл

@ -1473,6 +1473,7 @@ SHARED_SOURCES = \
ObjCRuntime/Selector.iOS.cs \ ObjCRuntime/Selector.iOS.cs \
ObjCRuntime/Selector.mac.cs \ ObjCRuntime/Selector.mac.cs \
ObjCRuntime/SelectorMarshaler.cs \ ObjCRuntime/SelectorMarshaler.cs \
ObjCRuntime/Stret.cs \
ObjCRuntime/ThreadSafeAttribute.cs \ ObjCRuntime/ThreadSafeAttribute.cs \
ObjCRuntime/TransientAttribute.cs \ ObjCRuntime/TransientAttribute.cs \
ObjCRuntime/TypeConverter.cs \ ObjCRuntime/TypeConverter.cs \

Просмотреть файл

@ -2348,101 +2348,6 @@ public partial class Generator : IMemberGatherer {
need_stret ? (aligned ? "IntPtr" : "out " + FormatTypeUsedIn (ns.CoreObjCRuntime, mi.ReturnType)) + " retval, " : ""); need_stret ? (aligned ? "IntPtr" : "out " + FormatTypeUsedIn (ns.CoreObjCRuntime, mi.ReturnType)) + " retval, " : "");
} }
bool IsMagicType (Type t)
{
switch (t.Name) {
case "nint":
case "nuint":
case "nfloat":
return t.Assembly == typeof (NSObject).Assembly;
default:
return t.Assembly == typeof (object).Assembly;
}
}
bool ArmNeedStret (MethodInfo mi)
{
Type t = mi.ReturnType;
bool assembly = Compat ? t.Assembly == typeof (object).Assembly : IsMagicType (t);
if (!t.IsValueType || t.IsEnum || assembly)
return false;
#if WATCH
// According to clang watchOS passes arguments bigger than 16 bytes by reference.
// https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L5248-L5250
// https://github.com/llvm-mirror/clang/blob/82f6d5c9ae84c04d6e7b402f72c33638d1fb6bc8/lib/CodeGen/TargetInfo.cpp#L5542-L5543
if (GetValueTypeSize (t, false) <= 16)
return false;
#endif
return true;
}
bool X86NeedStret (MethodInfo mi)
{
Type t = mi.ReturnType;
if (!t.IsValueType || t.IsEnum || t.Assembly == typeof (object).Assembly)
return false;
return GetValueTypeSize (t, false) > 8;
}
bool X86_64NeedStret (MethodInfo mi)
{
Type t = mi.ReturnType;
if (!t.IsValueType || t.IsEnum || t.Assembly == typeof (object).Assembly)
return false;
return GetValueTypeSize (t, true) > 16;
}
public static int GetValueTypeSize (Type type, bool is_64_bits)
{
switch (type.FullName) {
case "System.Char":
case "System.Boolean":
case "System.SByte":
case "System.Byte": return 1;
case "System.Int16":
case "System.UInt16": return 2;
case "System.Single":
case "System.Int32":
case "System.UInt32": return 4;
case "System.Double":
case "System.Int64":
case "System.UInt64": return 8;
case "System.IntPtr":
case "System.nfloat":
case "System.nuint":
case "System.nint": return is_64_bits ? 8 : 4;
default:
int size = 0;
foreach (var field in type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
int s = GetValueTypeSize (field.FieldType, is_64_bits);
if (s == -1)
return -1;
size += s;
}
return size;
}
}
bool NeedStret (MethodInfo mi)
{
if (Compat)
return ArmNeedStret (mi) || X86NeedStret (mi);
bool no_arm_stret = X86NeedStret (mi) || X86_64NeedStret (mi);
if (OnlyDesktop)
return no_arm_stret;
return no_arm_stret || ArmNeedStret (mi);
}
bool IsNativeEnum (Type type) bool IsNativeEnum (Type type)
{ {
return type.IsEnum && HasAttribute (type, typeof (NativeAttribute)); return type.IsEnum && HasAttribute (type, typeof (NativeAttribute));
@ -2483,12 +2388,12 @@ public partial class Generator : IMemberGatherer {
try { try {
if (Compat) { if (Compat) {
bool arm_stret = ArmNeedStret (mi); bool arm_stret = Stret.ArmNeedStret (mi);
bool is_aligned = HasAttribute (mi, typeof (AlignAttribute)); bool is_aligned = HasAttribute (mi, typeof (AlignAttribute));
RegisterMethod (arm_stret, mi, MakeSig (mi, arm_stret, arm_stret && is_aligned), arm_stret && is_aligned); RegisterMethod (arm_stret, mi, MakeSig (mi, arm_stret, arm_stret && is_aligned), arm_stret && is_aligned);
RegisterMethod (arm_stret, mi, MakeSuperSig (mi, arm_stret, arm_stret && is_aligned), arm_stret && is_aligned); RegisterMethod (arm_stret, mi, MakeSuperSig (mi, arm_stret, arm_stret && is_aligned), arm_stret && is_aligned);
bool x86_stret = X86NeedStret (mi); bool x86_stret = Stret.X86NeedStret (mi);
if (x86_stret != arm_stret){ if (x86_stret != arm_stret){
RegisterMethod (x86_stret, mi, MakeSig (mi, x86_stret, x86_stret && is_aligned), x86_stret && is_aligned); RegisterMethod (x86_stret, mi, MakeSig (mi, x86_stret, x86_stret && is_aligned), x86_stret && is_aligned);
RegisterMethod (x86_stret, mi, MakeSuperSig (mi, x86_stret, x86_stret && is_aligned), x86_stret && is_aligned); RegisterMethod (x86_stret, mi, MakeSuperSig (mi, x86_stret, x86_stret && is_aligned), x86_stret && is_aligned);
@ -2505,7 +2410,7 @@ public partial class Generator : IMemberGatherer {
RegisterMethod (false, mi, MakeSig (mi, false, enum_mode: mode), false, mode); RegisterMethod (false, mi, MakeSig (mi, false, enum_mode: mode), false, mode);
RegisterMethod (false, mi, MakeSuperSig (mi, false, enum_mode: mode), false, mode); RegisterMethod (false, mi, MakeSuperSig (mi, false, enum_mode: mode), false, mode);
if (NeedStret (mi)) { if (Stret.NeedStret (mi)) {
RegisterMethod (true, mi, MakeSig (mi, true, enum_mode: mode), false, mode); RegisterMethod (true, mi, MakeSig (mi, true, enum_mode: mode), false, mode);
RegisterMethod (true, mi, MakeSuperSig (mi, true, enum_mode: mode), false, mode); RegisterMethod (true, mi, MakeSuperSig (mi, true, enum_mode: mode), false, mode);
@ -4095,8 +4000,8 @@ public partial class Generator : IMemberGatherer {
return; return;
} }
bool arm_stret = ArmNeedStret (mi); bool arm_stret = Stret.ArmNeedStret (mi);
bool x86_stret = X86NeedStret (mi); bool x86_stret = Stret.X86NeedStret (mi);
bool aligned = HasAttribute (mi, typeof(AlignAttribute)); bool aligned = HasAttribute (mi, typeof(AlignAttribute));
if (OnlyDesktop){ if (OnlyDesktop){
@ -4122,9 +4027,9 @@ public partial class Generator : IMemberGatherer {
void GenerateNewStyleInvoke (bool supercall, MethodInfo mi, MemberInformation minfo, string selector, string[] args, bool assign_to_temp, Type category_type) void GenerateNewStyleInvoke (bool supercall, MethodInfo mi, MemberInformation minfo, string selector, string[] args, bool assign_to_temp, Type category_type)
{ {
bool arm_stret = ArmNeedStret (mi); bool arm_stret = Stret.ArmNeedStret (mi);
bool x86_stret = X86NeedStret (mi); bool x86_stret = Stret.X86NeedStret (mi);
bool x64_stret = X86_64NeedStret (mi); bool x64_stret = Stret.X86_64NeedStret (mi);
bool dual_enum = HasNativeEnumInSignature (mi); bool dual_enum = HasNativeEnumInSignature (mi);
bool is_stret_multi = arm_stret || x86_stret || x64_stret; bool is_stret_multi = arm_stret || x86_stret || x64_stret;
bool need_multi_path = is_stret_multi || dual_enum; bool need_multi_path = is_stret_multi || dual_enum;
@ -4556,7 +4461,7 @@ public partial class Generator : IMemberGatherer {
bool use_temp_return = bool use_temp_return =
minfo.is_return_release || minfo.is_return_release ||
(mi.Name != "Constructor" && (NeedStret (mi) || disposes.Length > 0 || postget != null) && mi.ReturnType != typeof (void)) || (mi.Name != "Constructor" && (Stret.NeedStret (mi) || disposes.Length > 0 || postget != null) && mi.ReturnType != typeof (void)) ||
(HasAttribute (mi, typeof (FactoryAttribute))) || (HasAttribute (mi, typeof (FactoryAttribute))) ||
((body_options & BodyOption.NeedsTempReturn) == BodyOption.NeedsTempReturn) || ((body_options & BodyOption.NeedsTempReturn) == BodyOption.NeedsTempReturn) ||
(mi.ReturnType.IsSubclassOf (typeof (Delegate))) || (mi.ReturnType.IsSubclassOf (typeof (Delegate))) ||

Просмотреть файл

@ -338,6 +338,7 @@ namespace Xamarin.Bundler {
// MT8015 Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com. // MT8015 Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com.
// MT8016 Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com. // MT8016 Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com.
// MT8017 ** reserved Xamarin.Mac ** // MT8017 ** reserved Xamarin.Mac **
// MT8018 Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.
// MT9xxx Licensing // MT9xxx Licensing
// //