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:
Родитель
a9188a3bf3
Коммит
9d85ca79ab
|
@ -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
|
||||||
|
|
|
@ -566,53 +566,59 @@ namespace XamCore.Registrar {
|
||||||
get {
|
get {
|
||||||
if (trampoline != Trampoline.None)
|
if (trampoline != Trampoline.None)
|
||||||
return trampoline;
|
return trampoline;
|
||||||
|
|
||||||
var isStaticTrampoline = IsStatic && !IsCategoryInstance;
|
|
||||||
trampoline = isStaticTrampoline ? Trampoline.Static : Trampoline.Normal;
|
|
||||||
|
|
||||||
var return_type = Registrar.GetReturnType (Method);
|
#if MTOUCH || MMP
|
||||||
var is_value_type = Registrar.IsValueType (return_type) && !Registrar.IsEnum (return_type);
|
throw ErrorHelper.CreateError (8018, "Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.");
|
||||||
var is_corlib = is_value_type ? Registrar.IsCorlibType (return_type) : false;
|
#else
|
||||||
|
var mi = (System.Reflection.MethodInfo) Method;
|
||||||
|
bool is_stret;
|
||||||
|
#if __WATCHOS__
|
||||||
|
is_stret = Runtime.Arch == Arch.DEVICE ? Stret.ArmNeedStret (mi) : Stret.X86NeedStret (mi);
|
||||||
|
#elif MONOMAC
|
||||||
|
is_stret = IntPtr.Size == 8 ? Stret.X86_64NeedStret (mi) : Stret.X86NeedStret (mi);
|
||||||
|
#elif __IOS__
|
||||||
|
if (Runtime.Arch == Arch.DEVICE) {
|
||||||
|
is_stret = IntPtr.Size == 4 && Stret.ArmNeedStret (mi);
|
||||||
|
} else {
|
||||||
|
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 (return_type))
|
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 (return_type), Registrar.GetTypeFullName (DeclaringType.Type), Registrar.GetDescriptiveMethodName (Method));
|
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));
|
||||||
|
|
||||||
var size = is_value_type ? Registrar.GetValueTypeSize (return_type) : 0;
|
if (is_stret) {
|
||||||
|
if (Registrar.IsSimulatorOrDesktop && !Registrar.Is64Bits) {
|
||||||
if (is_value_type && !is_corlib && (!Registrar.IsSimulatorOrDesktop || size > 4)) {
|
trampoline = is_static_trampoline ? Trampoline.X86_DoubleABI_StaticStretTrampoline : Trampoline.X86_DoubleABI_StretTrampoline;
|
||||||
trampoline = isStaticTrampoline ? Trampoline.StaticStret : Trampoline.Stret;
|
} else {
|
||||||
|
trampoline = is_static_trampoline ? Trampoline.StaticStret : Trampoline.Stret;
|
||||||
if (Registrar.IsSimulatorOrDesktop) {
|
|
||||||
if (Registrar.Is64Bits) {
|
|
||||||
if (size > 16) {
|
|
||||||
trampoline = isStaticTrampoline ? Trampoline.StaticStret : Trampoline.Stret;
|
|
||||||
} else {
|
|
||||||
trampoline = isStaticTrampoline ? Trampoline.Static : Trampoline.Normal;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (size > 8) {
|
|
||||||
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;
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
113
src/generator.cs
113
src/generator.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
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче