Merge pull request #988 from rolfbjarne/bug44709d
Unify stret detection between the generator and platform assemblies, and fix stret detection on watchOS. Fixes #44709.
This commit is contained in:
Коммит
2a9f5a8238
|
@ -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.
|
||||
|
||||
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><
|
||||
|
|
|
@ -101,9 +101,8 @@ marshal_return_value (void *context, const char *type, size_t size, void *vvalue
|
|||
it->state->double_ret = *(double *) mono_object_unbox (value);
|
||||
break;
|
||||
case _C_STRUCT_B:
|
||||
if (it->state->type == Tramp_DoubleStret || it->state->type == Tramp_StaticDoubleStret) {
|
||||
void *unboxed = mono_object_unbox (value);
|
||||
memcpy ((void *) it->stret, unboxed, size);
|
||||
if ((it->state->type & Tramp_Stret) == Tramp_Stret) {
|
||||
memcpy ((void *) it->stret, mono_object_unbox (value), size);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -127,9 +126,6 @@ marshal_return_value (void *context, const char *type, size_t size, void *vvalue
|
|||
it->state->edx = v[1];
|
||||
} else if (size == 4) {
|
||||
it->state->eax = *(uint32_t *) mono_object_unbox (value);
|
||||
} else if (size > 8) {
|
||||
// Passed in memory. it->stret points to caller-allocated memory.
|
||||
memcpy ((void *) it->stret, mono_object_unbox (value), size);
|
||||
} else {
|
||||
*exception_gchandle = create_mt_exception (xamarin_strdup_printf ("Xamarin.iOS: Cannot marshal struct return type %s (size: %i)\n", type, (int) size));
|
||||
}
|
||||
|
|
|
@ -370,6 +370,11 @@ marshal_return_value (void *context, const char *type, size_t size, void *vvalue
|
|||
*
|
||||
*/
|
||||
|
||||
if ((it->state->type & Tramp_Stret) == Tramp_Stret) {
|
||||
memcpy ((void *) it->state->rdi, mono_object_unbox (value), size);
|
||||
break;
|
||||
}
|
||||
|
||||
if (size > 8 && size <= 16) {
|
||||
uint64_t *i_ptr = &it->state->rax;
|
||||
uint64_t *f_ptr = (uint64_t *) &it->state->xmm0;
|
||||
|
@ -455,16 +460,16 @@ marshal_return_value (void *context, const char *type, size_t size, void *vvalue
|
|||
|
||||
};
|
||||
} else if (size == 8) {
|
||||
if (!strcmp (type, "[ff]") || !strcmp (type, "[d]")) {
|
||||
type = skip_type_name (type);
|
||||
if (!strncmp (type, "ff}", 3) || !strncmp (type, "d}", 2)) {
|
||||
// the only two fully fp combinations are: ff and d
|
||||
it->state->xmm0 = *(float *) mono_object_unbox (value);
|
||||
memcpy (&it->state->xmm0, mono_object_unbox (value), 8);
|
||||
} else {
|
||||
// all other combinations would contain at least one INTEGER-class type.
|
||||
it->state->rax = *(uint64_t *) mono_object_unbox (value);
|
||||
}
|
||||
} else if (size > 16) {
|
||||
// Passed in memory. %rdi points to caller-allocated memory.
|
||||
memcpy ((void *) it->state->rdi, mono_object_unbox (value), size);
|
||||
} else if (size < 8) {
|
||||
memcpy (&it->state->rax, mono_object_unbox (value), size);
|
||||
} else {
|
||||
*exception_gchandle = create_mt_exception (xamarin_strdup_printf ("Xamarin.iOS: Cannot marshal struct return type %s (size: %i)\n", type, (int) size));
|
||||
return;
|
||||
|
|
|
@ -5,6 +5,7 @@ GENERATOR_SOURCES = \
|
|||
$(TOP)/src/generator.cs \
|
||||
$(TOP)/src/generator-enums.cs \
|
||||
$(TOP)/src/generator-filters.cs \
|
||||
$(TOP)/src/ObjCRuntime/Stret.cs \
|
||||
$(MONO_PATH)/mcs/class/Mono.Options/Mono.Options/Options.cs \
|
||||
|
||||
GENERATOR_DEFINES = -d:GENERATOR -d:NET_4_0
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using XamCore.Foundation;
|
||||
using XamCore.ObjCRuntime;
|
||||
|
||||
|
@ -81,10 +83,19 @@ namespace XamCore.MetalPerformanceShaders {
|
|||
}
|
||||
|
||||
// MPSImageHistogram.h
|
||||
[StructLayout (LayoutKind.Explicit)]
|
||||
public struct MPSImageHistogramInfo {
|
||||
[FieldOffset (0)]
|
||||
public nuint NumberOfHistogramEntries;
|
||||
#if ARCH_64
|
||||
[FieldOffset (8)]
|
||||
#else
|
||||
[FieldOffset (4)]
|
||||
#endif
|
||||
public bool HistogramForAlpha;
|
||||
[FieldOffset (16)]
|
||||
public Vector4 MinPixelValue;
|
||||
[FieldOffset (32)]
|
||||
public Vector4 MaxPixelValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -567,52 +567,58 @@ namespace XamCore.Registrar {
|
|||
if (trampoline != Trampoline.None)
|
||||
return trampoline;
|
||||
|
||||
var isStaticTrampoline = IsStatic && !IsCategoryInstance;
|
||||
trampoline = isStaticTrampoline ? Trampoline.Static : Trampoline.Normal;
|
||||
#if MTOUCH || MMP
|
||||
throw ErrorHelper.CreateError (8018, "Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.");
|
||||
#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);
|
||||
|
||||
var return_type = Registrar.GetReturnType (Method);
|
||||
var is_value_type = Registrar.IsValueType (return_type) && !Registrar.IsEnum (return_type);
|
||||
var is_corlib = is_value_type ? Registrar.IsCorlibType (return_type) : false;
|
||||
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_value_type && Registrar.IsGenericType (return_type))
|
||||
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));
|
||||
|
||||
var size = is_value_type ? Registrar.GetValueTypeSize (return_type) : 0;
|
||||
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (is_stret) {
|
||||
if (Registrar.IsSimulatorOrDesktop && !Registrar.Is64Bits) {
|
||||
trampoline = is_static_trampoline ? Trampoline.X86_DoubleABI_StaticStretTrampoline : Trampoline.X86_DoubleABI_StretTrampoline;
|
||||
} else {
|
||||
trampoline = is_static_trampoline ? Trampoline.StaticStret : Trampoline.Stret;
|
||||
}
|
||||
} else {
|
||||
switch (Signature [0]) {
|
||||
case 'Q':
|
||||
case 'q':
|
||||
trampoline = isStaticTrampoline ? Trampoline.StaticLong : Trampoline.Long;
|
||||
trampoline = is_static_trampoline ? Trampoline.StaticLong : Trampoline.Long;
|
||||
break;
|
||||
case 'f':
|
||||
trampoline = isStaticTrampoline ? Trampoline.StaticSingle : Trampoline.Single;
|
||||
trampoline = is_static_trampoline ? Trampoline.StaticSingle : Trampoline.Single;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return trampoline;
|
||||
#endif
|
||||
}
|
||||
set {
|
||||
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.mac.cs \
|
||||
ObjCRuntime/SelectorMarshaler.cs \
|
||||
ObjCRuntime/Stret.cs \
|
||||
ObjCRuntime/ThreadSafeAttribute.cs \
|
||||
ObjCRuntime/TransientAttribute.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, " : "");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return type.IsEnum && HasAttribute (type, typeof (NativeAttribute));
|
||||
|
@ -2483,12 +2388,12 @@ public partial class Generator : IMemberGatherer {
|
|||
|
||||
try {
|
||||
if (Compat) {
|
||||
bool arm_stret = ArmNeedStret (mi);
|
||||
bool arm_stret = Stret.ArmNeedStret (mi);
|
||||
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, 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){
|
||||
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);
|
||||
|
@ -2505,7 +2410,7 @@ public partial class Generator : IMemberGatherer {
|
|||
RegisterMethod (false, mi, MakeSig (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, MakeSuperSig (mi, true, enum_mode: mode), false, mode);
|
||||
|
||||
|
@ -4095,8 +4000,8 @@ public partial class Generator : IMemberGatherer {
|
|||
return;
|
||||
}
|
||||
|
||||
bool arm_stret = ArmNeedStret (mi);
|
||||
bool x86_stret = X86NeedStret (mi);
|
||||
bool arm_stret = Stret.ArmNeedStret (mi);
|
||||
bool x86_stret = Stret.X86NeedStret (mi);
|
||||
bool aligned = HasAttribute (mi, typeof(AlignAttribute));
|
||||
|
||||
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)
|
||||
{
|
||||
bool arm_stret = ArmNeedStret (mi);
|
||||
bool x86_stret = X86NeedStret (mi);
|
||||
bool x64_stret = X86_64NeedStret (mi);
|
||||
bool arm_stret = Stret.ArmNeedStret (mi);
|
||||
bool x86_stret = Stret.X86NeedStret (mi);
|
||||
bool x64_stret = Stret.X86_64NeedStret (mi);
|
||||
bool dual_enum = HasNativeEnumInSignature (mi);
|
||||
bool is_stret_multi = arm_stret || x86_stret || x64_stret;
|
||||
bool need_multi_path = is_stret_multi || dual_enum;
|
||||
|
@ -4556,7 +4461,7 @@ public partial class Generator : IMemberGatherer {
|
|||
|
||||
bool use_temp_return =
|
||||
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))) ||
|
||||
((body_options & BodyOption.NeedsTempReturn) == BodyOption.NeedsTempReturn) ||
|
||||
(mi.ReturnType.IsSubclassOf (typeof (Delegate))) ||
|
||||
|
|
|
@ -25,4 +25,5 @@ mac-test-package
|
|||
.nuget
|
||||
logs
|
||||
*.mSYM
|
||||
*.generated.cs
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Bindings.Test {
|
|||
* ObjC test class used for registrar
|
||||
*/
|
||||
[BaseType (typeof (NSObject))]
|
||||
interface ObjCRegistrarTest {
|
||||
partial interface ObjCRegistrarTest {
|
||||
[Export ("Pi1")]
|
||||
int Pi1 { get; set; }
|
||||
|
||||
|
@ -137,15 +137,6 @@ namespace Bindings.Test {
|
|||
[Export ("Pc5")]
|
||||
sbyte Pc5 { get; set; }
|
||||
|
||||
[Export ("PSiid1")]
|
||||
Siid PSiid { get; set; }
|
||||
|
||||
[Export ("PSd1")]
|
||||
Sd PSd { get; set; }
|
||||
|
||||
[Export ("PSf1")]
|
||||
Sf PSf { get; set; }
|
||||
|
||||
[Export ("V")]
|
||||
void V ();
|
||||
|
||||
|
|
|
@ -7,32 +7,6 @@ using nint=System.Int32;
|
|||
|
||||
namespace Bindings.Test
|
||||
{
|
||||
public struct Sd { public double d1; }
|
||||
public struct Sdd { public double d1; public double d2; }
|
||||
public struct Sddd { public double d1; public double d2; public double d3; }
|
||||
public struct Sdddd { public double d1; public double d2; public double d3; public double d4; }
|
||||
public struct Si { public int i1; }
|
||||
public struct Sii { public int i1; public int i2; }
|
||||
public struct Siii { public int i1; public int i2; public int i3; }
|
||||
public struct Siiii { public int i1; public int i2; public int i3; public int i4; }
|
||||
public struct Siiiii { public int i1; public int i2; public int i3; public int i4; public int i5; }
|
||||
public struct Sid { public int i1; public double d2; }
|
||||
public struct Sdi { public double d1; public int i2; }
|
||||
public struct Sidi { public int i1; public double d2; public int i3; }
|
||||
public struct Siid { public int i1; public int i2; public double d3; }
|
||||
public struct Sddi { public double d1; public double d2; public int i3; }
|
||||
public struct Sl { public nint l1; }
|
||||
public struct Sll { public nint l1; public nint l2; }
|
||||
public struct Slll { public nint l1; public nint l2; public nint l3; }
|
||||
public struct Scccc { public char c1; public char c2; public char c3; public char c4; }
|
||||
public struct Sffff { public float f1; public float f2; public float f3; public float f4; }
|
||||
public struct Sif { public int i1; public float f2; }
|
||||
public struct Sf { public float f1; }
|
||||
public struct Sff { public float f1; public float f2; }
|
||||
public struct Siff { public int i1; public float f2; public float f3; }
|
||||
public struct Siiff { public int i1; public int i2; public float f3; public float f4; }
|
||||
public struct Sfi { public float f1; public int i2; }
|
||||
|
||||
public static class CFunctions {
|
||||
[DllImport ("__Internal")]
|
||||
public static extern int theUltimateAnswer ();
|
||||
|
|
|
@ -47,10 +47,12 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ObjcBindingApiDefinition Include="ApiDefinition.cs" />
|
||||
<ObjcBindingApiDefinition Include="ApiDefinition.generated.cs" />
|
||||
<ObjcBindingApiDefinition Include="ApiProtocol.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ObjcBindingCoreSource Include="StructsAndEnums.cs" />
|
||||
<ObjcBindingCoreSource Include="StructsAndEnums.generated.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.ObjCBinding.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -74,8 +76,26 @@
|
|||
<None Include="..\..\tests\test-libraries\libtest.h">
|
||||
<Link>libtest.h</Link>
|
||||
</None>
|
||||
<None Include="..\..\tests\test-libraries\libtest.structs.h">
|
||||
<Link>libtest.structs.h</Link>
|
||||
</None>
|
||||
<None Include="..\..\tests\test-libraries\libtest.properties.h">
|
||||
<Link>libtest.properties.h</Link>
|
||||
</None>
|
||||
<None Include="..\..\tests\test-libraries\testgenerator.cs">
|
||||
<Link>testgenerator.cs</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Target Name="BeforeBuild" Inputs="..\..\tests\test-libraries\libtest.m" Outputs="..\..\tests\test-libraries\.libs\ios\libtest.a">
|
||||
<ItemGroup>
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\*.m" />
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\*.h" />
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\*.cs" />
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\Makefile" />
|
||||
<GeneratedTestOutput Include="..\..\tests\test-libraries\.libs\ios\libtest.a" />
|
||||
<GeneratedTestOutput Include="ApiDefinition.generated.cs" />
|
||||
<GeneratedTestOutput Include="StructsAndEnums.generated.cs" />
|
||||
</ItemGroup>
|
||||
<Target Name="BeforeBuild" Inputs="@(GeneratedTestInput)" Outputs="@(GeneratedTestOutput)">
|
||||
<Exec Command="make -j8 -C ..\..\tests\test-libraries" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -1638,151 +1638,14 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
public void Test_D ()
|
||||
{
|
||||
using (var tc = new ObjCRegistrarTest ()) {
|
||||
Verify (tc, Pd1: 0);
|
||||
Assert.AreEqual (tc.Pd1, 0, "Pd1");
|
||||
Assert.AreEqual (0, tc.D (), "1");
|
||||
tc.Pd1 = 1.2;
|
||||
Assert.AreEqual (1.2, tc.D (), "2");
|
||||
Verify (tc, Pd1: 1.2);
|
||||
Assert.AreEqual (tc.Pd1, 1.2, "Pd1");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_Sd ()
|
||||
{
|
||||
using (var tc = new ObjCRegistrarTest ()) {
|
||||
Assert.AreEqual (0, tc.Sd ().d1, "1");
|
||||
Verify (tc, PSd1: new Sd () );
|
||||
tc.PSd = new Sd () { d1 = 1.23 };
|
||||
Assert.AreEqual (1.23, tc.Sd ().d1, "2");
|
||||
Verify (tc, PSd1: new Sd () { d1 = 1.23 });
|
||||
}
|
||||
}
|
||||
|
||||
void Verify (ObjCRegistrarTest obj, string msg = null,
|
||||
int? Pi1 = null,
|
||||
int? Pi2 = null,
|
||||
int? Pi3 = null,
|
||||
int? Pi4 = null,
|
||||
int? Pi5 = null,
|
||||
int? Pi6 = null,
|
||||
int? Pi7 = null,
|
||||
int? Pi8 = null,
|
||||
int? Pi9 = null,
|
||||
float? Pf1 = null,
|
||||
float? Pf2 = null,
|
||||
float? Pf3 = null,
|
||||
float? Pf4 = null,
|
||||
float? Pf5 = null,
|
||||
float? Pf6 = null,
|
||||
float? Pf7 = null,
|
||||
float? Pf8 = null,
|
||||
float? Pf9 = null,
|
||||
double? Pd1 = null,
|
||||
double? Pd2 = null,
|
||||
double? Pd3 = null,
|
||||
double? Pd4 = null,
|
||||
double? Pd5 = null,
|
||||
double? Pd6 = null,
|
||||
double? Pd7 = null,
|
||||
double? Pd8 = null,
|
||||
double? Pd9 = null,
|
||||
char? Pc1 = null,
|
||||
char? Pc2 = null,
|
||||
char? Pc3 = null,
|
||||
char? Pc4 = null,
|
||||
char? Pc5 = null,
|
||||
char? Pc6 = null,
|
||||
char? Pc7 = null,
|
||||
char? Pc8 = null,
|
||||
char? Pc9 = null,
|
||||
|
||||
Siid? PSiid1 = null,
|
||||
Sd? PSd1 = null,
|
||||
Sf? PSf1 = null)
|
||||
{
|
||||
if (Pi1.HasValue)
|
||||
Assert.AreEqual (obj.Pi1, Pi1.Value, "Pi1");
|
||||
if (Pi2.HasValue)
|
||||
Assert.AreEqual (obj.Pi2, Pi2.Value, "Pi2");
|
||||
if (Pi3.HasValue)
|
||||
Assert.AreEqual (obj.Pi3, Pi3.Value, "Pi3");
|
||||
if (Pi4.HasValue)
|
||||
Assert.AreEqual (obj.Pi4, Pi4.Value, "Pi4");
|
||||
if (Pi5.HasValue)
|
||||
Assert.AreEqual (obj.Pi5, Pi5.Value, "Pi5");
|
||||
if (Pi6.HasValue)
|
||||
Assert.AreEqual (obj.Pi6, Pi6.Value, "Pi6");
|
||||
if (Pi7.HasValue)
|
||||
Assert.AreEqual (obj.Pi7, Pi7.Value, "Pi7");
|
||||
if (Pi8.HasValue)
|
||||
Assert.AreEqual (obj.Pi8, Pi8.Value, "Pi8");
|
||||
if (Pi9.HasValue)
|
||||
Assert.AreEqual (obj.Pi9, Pi9.Value, "Pi9");
|
||||
if (Pf1.HasValue)
|
||||
Assert.AreEqual (obj.Pf1, Pf1.Value, "Pf1");
|
||||
if (Pf2.HasValue)
|
||||
Assert.AreEqual (obj.Pf2, Pf2.Value, "Pf2");
|
||||
if (Pf3.HasValue)
|
||||
Assert.AreEqual (obj.Pf3, Pf3.Value, "Pf3");
|
||||
if (Pf4.HasValue)
|
||||
Assert.AreEqual (obj.Pf4, Pf4.Value, "Pf4");
|
||||
if (Pf5.HasValue)
|
||||
Assert.AreEqual (obj.Pf5, Pf5.Value, "Pf5");
|
||||
if (Pf6.HasValue)
|
||||
Assert.AreEqual (obj.Pf6, Pf6.Value, "Pf6");
|
||||
if (Pf7.HasValue)
|
||||
Assert.AreEqual (obj.Pf7, Pf7.Value, "Pf7");
|
||||
if (Pf8.HasValue)
|
||||
Assert.AreEqual (obj.Pf8, Pf8.Value, "Pf8");
|
||||
if (Pf9.HasValue)
|
||||
Assert.AreEqual (obj.Pf9, Pf9.Value, "Pf9");
|
||||
if (Pd1.HasValue)
|
||||
Assert.AreEqual (obj.Pd1, Pd1.Value, "Pd1");
|
||||
if (Pd2.HasValue)
|
||||
Assert.AreEqual (obj.Pd2, Pd2.Value, "Pd2");
|
||||
if (Pd3.HasValue)
|
||||
Assert.AreEqual (obj.Pd3, Pd3.Value, "Pd3");
|
||||
if (Pd4.HasValue)
|
||||
Assert.AreEqual (obj.Pd4, Pd4.Value, "Pd4");
|
||||
if (Pd5.HasValue)
|
||||
Assert.AreEqual (obj.Pd5, Pd5.Value, "Pd5");
|
||||
if (Pd6.HasValue)
|
||||
Assert.AreEqual (obj.Pd6, Pd6.Value, "Pd6");
|
||||
if (Pd7.HasValue)
|
||||
Assert.AreEqual (obj.Pd7, Pd7.Value, "Pd7");
|
||||
if (Pd8.HasValue)
|
||||
Assert.AreEqual (obj.Pd8, Pd8.Value, "Pd8");
|
||||
if (Pd9.HasValue)
|
||||
Assert.AreEqual (obj.Pd9, Pd9.Value, "Pd9");
|
||||
if (Pc1.HasValue)
|
||||
Assert.AreEqual (obj.Pc1, Pc1.Value, "Pc1");
|
||||
if (Pc2.HasValue)
|
||||
Assert.AreEqual (obj.Pc2, Pc2.Value, "Pc2");
|
||||
if (Pc3.HasValue)
|
||||
Assert.AreEqual (obj.Pc3, Pc3.Value, "Pc3");
|
||||
if (Pc4.HasValue)
|
||||
Assert.AreEqual (obj.Pc4, Pc4.Value, "Pc4");
|
||||
if (Pc5.HasValue)
|
||||
Assert.AreEqual (obj.Pc5, Pc5.Value, "Pc5");
|
||||
// if (Pc6.HasValue)
|
||||
// Assert.AreEqual (obj.Pc6, Pc6.Value, "Pc6");
|
||||
// if (Pc7.HasValue)
|
||||
// Assert.AreEqual (obj.Pc7, Pc7.Value, "Pc7");
|
||||
// if (Pc8.HasValue)
|
||||
// Assert.AreEqual (obj.Pc8, Pc8.Value, "Pc8");
|
||||
// if (Pc9.HasValue)
|
||||
// Assert.AreEqual (obj.Pc9, Pc9.Value, "Pc9");
|
||||
|
||||
if (PSiid1.HasValue)
|
||||
Assert.AreEqual (obj.PSiid, PSiid1.Value, "PSiid1");
|
||||
|
||||
if (PSd1.HasValue)
|
||||
Assert.AreEqual (obj.PSd, PSd1.Value, "PSd1");
|
||||
|
||||
if (PSf1.HasValue)
|
||||
Assert.AreEqual (obj.PSf, PSf1.Value, "PSf1");
|
||||
}
|
||||
|
||||
public class TestClass : ObjCRegistrarTest
|
||||
{
|
||||
}
|
||||
|
|
|
@ -43,10 +43,19 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
public class TrampolineTest {
|
||||
public static readonly nfloat pi = 3.14159f;
|
||||
|
||||
public bool IsSim64 { get { return IntPtr.Size == 8 && Runtime.Arch == Arch.SIMULATOR; } }
|
||||
public bool IsSim32 { get { return IntPtr.Size == 4 && Runtime.Arch == Arch.SIMULATOR; } }
|
||||
public bool IsArm64 { get { return IntPtr.Size == 8 && Runtime.Arch == Arch.DEVICE; } }
|
||||
public bool IsArm32 { get { return IntPtr.Size == 4 && Runtime.Arch == Arch.DEVICE; } }
|
||||
public static bool IsSim64 { get { return IntPtr.Size == 8 && Runtime.Arch == Arch.SIMULATOR; } }
|
||||
public static bool IsSim32 { get { return IntPtr.Size == 4 && Runtime.Arch == Arch.SIMULATOR; } }
|
||||
public static bool IsArm64 { get { return IntPtr.Size == 8 && Runtime.Arch == Arch.DEVICE; } }
|
||||
public static bool IsArm32 {
|
||||
get {
|
||||
#if __WATCHOS__
|
||||
return false;
|
||||
#else
|
||||
return IntPtr.Size == 4 && Runtime.Arch == Arch.DEVICE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsArmv7k {
|
||||
get {
|
||||
#if __WATCHOS__
|
||||
|
@ -76,229 +85,6 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
}
|
||||
#endif // !__WATCHOS__
|
||||
|
||||
[Test]
|
||||
public void StretIIIITrampolineTest ()
|
||||
{
|
||||
StretTrampolines obj = new StretTrampolines ();
|
||||
IntPtr class_ptr = Class.GetHandle ("StretTrampolines");
|
||||
IIIIStruct rv = new IIIIStruct ();
|
||||
double rvd;
|
||||
float rvf;
|
||||
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IIIIStruct_objc_msgSend (obj.Handle, new Selector ("Test_IIIIStruct").Handle);
|
||||
} else {
|
||||
IIIIStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_IIIIStruct").Handle);
|
||||
}
|
||||
Assert.That ("[1;2;3;4]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IIIIStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticIIIIStruct").Handle);
|
||||
} else {
|
||||
IIIIStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticIIIIStruct").Handle);
|
||||
}
|
||||
Assert.That ("[10;20;30;40]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IIIIStruct_objc_msgSend (obj.Handle, new Selector ("Test_IIIIStructProperty").Handle);
|
||||
} else {
|
||||
IIIIStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_IIIIStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[100;200;300;400]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IIIIStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticIIIIStructProperty").Handle);
|
||||
} else {
|
||||
IIIIStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticIIIIStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[1000;2000;3000;4000]" == rv.ToString ());
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IIIIStruct_objc_msgSend_out_float (class_ptr, new Selector ("Test_StaticIIIIStruct_out_Float:").Handle, out rvf);
|
||||
} else {
|
||||
IIIIStruct_objc_msgSend_stret_out_float (out rv, class_ptr, new Selector ("Test_StaticIIIIStruct_out_Float:").Handle, out rvf);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[10;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvf == 3.15f);
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IIIIStruct_objc_msgSend_out_double (obj.Handle, new Selector ("Test_IIIIStruct_out_Double:").Handle, out rvd);
|
||||
} else {
|
||||
IIIIStruct_objc_msgSend_stret_out_double (out rv, obj.Handle, new Selector ("Test_IIIIStruct_out_Double:").Handle, out rvd);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[1;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvd == 3.14);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StretFFFFTrampolineTest ()
|
||||
{
|
||||
StretTrampolines obj = new StretTrampolines ();
|
||||
IntPtr class_ptr = Class.GetHandle ("StretTrampolines");
|
||||
var rv = new FFFFStruct ();
|
||||
double rvd;
|
||||
float rvf;
|
||||
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FFFFStruct_objc_msgSend (obj.Handle, new Selector ("Test_FFFFStruct").Handle);
|
||||
} else {
|
||||
FFFFStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_FFFFStruct").Handle);
|
||||
}
|
||||
Assert.That ("[1;2;3;4]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FFFFStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticFFFFStruct").Handle);
|
||||
} else {
|
||||
FFFFStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticFFFFStruct").Handle);
|
||||
}
|
||||
Assert.That ("[10;20;30;40]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FFFFStruct_objc_msgSend (obj.Handle, new Selector ("Test_FFFFStructProperty").Handle);
|
||||
} else {
|
||||
FFFFStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_FFFFStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[100;200;300;400]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FFFFStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticFFFFStructProperty").Handle);
|
||||
} else {
|
||||
FFFFStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticFFFFStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[1000;2000;3000;4000]" == rv.ToString ());
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FFFFStruct_objc_msgSend_out_float (class_ptr, new Selector ("Test_StaticFFFFStruct_out_Float:").Handle, out rvf);
|
||||
} else {
|
||||
FFFFStruct_objc_msgSend_stret_out_float (out rv, class_ptr, new Selector ("Test_StaticFFFFStruct_out_Float:").Handle, out rvf);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[10;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvf == 3.15f);
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FFFFStruct_objc_msgSend_out_double (obj.Handle, new Selector ("Test_FFFFStruct_out_Double:").Handle, out rvd);
|
||||
} else {
|
||||
FFFFStruct_objc_msgSend_stret_out_double (out rv, obj.Handle, new Selector ("Test_FFFFStruct_out_Double:").Handle, out rvd);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[1;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvd == 3.14);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StretFIFITrampolineTest ()
|
||||
{
|
||||
StretTrampolines obj = new StretTrampolines ();
|
||||
IntPtr class_ptr = Class.GetHandle ("StretTrampolines");
|
||||
var rv = new FIFIStruct ();
|
||||
double rvd;
|
||||
float rvf;
|
||||
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FIFIStruct_objc_msgSend (obj.Handle, new Selector ("Test_FIFIStruct").Handle);
|
||||
} else {
|
||||
FIFIStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_FIFIStruct").Handle);
|
||||
}
|
||||
Assert.That ("[1;2;3;4]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FIFIStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticFIFIStruct").Handle);
|
||||
} else {
|
||||
FIFIStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticFIFIStruct").Handle);
|
||||
}
|
||||
Assert.That ("[10;20;30;40]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FIFIStruct_objc_msgSend (obj.Handle, new Selector ("Test_FIFIStructProperty").Handle);
|
||||
} else {
|
||||
FIFIStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_FIFIStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[100;200;300;400]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FIFIStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticFIFIStructProperty").Handle);
|
||||
} else {
|
||||
FIFIStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticFIFIStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[1000;2000;3000;4000]" == rv.ToString ());
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FIFIStruct_objc_msgSend_out_float (class_ptr, new Selector ("Test_StaticFIFIStruct_out_Float:").Handle, out rvf);
|
||||
} else {
|
||||
FIFIStruct_objc_msgSend_stret_out_float (out rv, class_ptr, new Selector ("Test_StaticFIFIStruct_out_Float:").Handle, out rvf);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[10;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvf == 3.15f);
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = FIFIStruct_objc_msgSend_out_double (obj.Handle, new Selector ("Test_FIFIStruct_out_Double:").Handle, out rvd);
|
||||
} else {
|
||||
FIFIStruct_objc_msgSend_stret_out_double (out rv, obj.Handle, new Selector ("Test_FIFIStruct_out_Double:").Handle, out rvd);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[1;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvd == 3.14);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StretIFIFTrampolineTest ()
|
||||
{
|
||||
StretTrampolines obj = new StretTrampolines ();
|
||||
IntPtr class_ptr = Class.GetHandle ("StretTrampolines");
|
||||
var rv = new IFIFStruct ();
|
||||
double rvd;
|
||||
float rvf;
|
||||
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IFIFStruct_objc_msgSend (obj.Handle, new Selector ("Test_IFIFStruct").Handle);
|
||||
} else {
|
||||
IFIFStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_IFIFStruct").Handle);
|
||||
}
|
||||
Assert.That ("[1;2;3;4]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IFIFStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticIFIFStruct").Handle);
|
||||
} else {
|
||||
IFIFStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticIFIFStruct").Handle);
|
||||
}
|
||||
Assert.That ("[10;20;30;40]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IFIFStruct_objc_msgSend (obj.Handle, new Selector ("Test_IFIFStructProperty").Handle);
|
||||
} else {
|
||||
IFIFStruct_objc_msgSend_stret (out rv, obj.Handle, new Selector ("Test_IFIFStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[100;200;300;400]" == rv.ToString ());
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IFIFStruct_objc_msgSend (class_ptr, new Selector ("Test_StaticIFIFStructProperty").Handle);
|
||||
} else {
|
||||
IFIFStruct_objc_msgSend_stret (out rv, class_ptr, new Selector ("Test_StaticIFIFStructProperty").Handle);
|
||||
}
|
||||
Assert.That ("[1000;2000;3000;4000]" == rv.ToString ());
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IFIFStruct_objc_msgSend_out_float (class_ptr, new Selector ("Test_StaticIFIFStruct_out_Float:").Handle, out rvf);
|
||||
} else {
|
||||
IFIFStruct_objc_msgSend_stret_out_float (out rv, class_ptr, new Selector ("Test_StaticIFIFStruct_out_Float:").Handle, out rvf);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[10;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvf == 3.15f);
|
||||
|
||||
rvd = rvf = 0;
|
||||
if (IsSim64 || IsArm64 || IsArmv7k) {
|
||||
rv = IFIFStruct_objc_msgSend_out_double (obj.Handle, new Selector ("Test_IFIFStruct_out_Double:").Handle, out rvd);
|
||||
} else {
|
||||
IFIFStruct_objc_msgSend_stret_out_double (out rv, obj.Handle, new Selector ("Test_IFIFStruct_out_Double:").Handle, out rvd);
|
||||
}
|
||||
//Console.WriteLine ("Got: {0} and {1} and {2}", rv.ToString (), rvf, rvd);
|
||||
Assert.That ("[1;20;300;4000]" == rv.ToString ());
|
||||
Assert.That (rvd == 3.14);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void DoubleReturnTest ()
|
||||
{
|
||||
|
@ -356,82 +142,6 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
extern static void Matrix4_objc_msgSend_stret (out OpenTK.Matrix4 retval, IntPtr receiver, IntPtr selector);
|
||||
#endif // !__WATCHOS__
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void IIIIStruct_objc_msgSend_stret (out IIIIStruct retval, IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static IIIIStruct IIIIStruct_objc_msgSend (IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void IIIIStruct_objc_msgSend_stret_out_double (out IIIIStruct retval, IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static IIIIStruct IIIIStruct_objc_msgSend_out_double (IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void IIIIStruct_objc_msgSend_stret_out_float (out IIIIStruct retval, IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static IIIIStruct IIIIStruct_objc_msgSend_out_float (IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void FFFFStruct_objc_msgSend_stret (out FFFFStruct retval, IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static FFFFStruct FFFFStruct_objc_msgSend (IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void FFFFStruct_objc_msgSend_stret_out_double (out FFFFStruct retval, IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static FFFFStruct FFFFStruct_objc_msgSend_out_double (IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void FFFFStruct_objc_msgSend_stret_out_float (out FFFFStruct retval, IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static FFFFStruct FFFFStruct_objc_msgSend_out_float (IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void IFIFStruct_objc_msgSend_stret (out IFIFStruct retval, IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static IFIFStruct IFIFStruct_objc_msgSend (IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void IFIFStruct_objc_msgSend_stret_out_double (out IFIFStruct retval, IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static IFIFStruct IFIFStruct_objc_msgSend_out_double (IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void IFIFStruct_objc_msgSend_stret_out_float (out IFIFStruct retval, IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static IFIFStruct IFIFStruct_objc_msgSend_out_float (IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void FIFIStruct_objc_msgSend_stret (out FIFIStruct retval, IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static FIFIStruct FIFIStruct_objc_msgSend (IntPtr receiver, IntPtr selector);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void FIFIStruct_objc_msgSend_stret_out_double (out FIFIStruct retval, IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static FIFIStruct FIFIStruct_objc_msgSend_out_double (IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void FIFIStruct_objc_msgSend_stret_out_float (out FIFIStruct retval, IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend")]
|
||||
extern static FIFIStruct FIFIStruct_objc_msgSend_out_float (IntPtr receiver, IntPtr selector, out float arg1);
|
||||
|
||||
|
||||
[DllImport (LIBOBJC_DYLIB, EntryPoint="objc_msgSend_stret")]
|
||||
extern static void double_objc_msgSend_stret_out_double (out double retval, IntPtr receiver, IntPtr selector, out double arg1);
|
||||
|
||||
|
@ -634,14 +344,14 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
PointF point;
|
||||
SizeF size;
|
||||
|
||||
if (IsArm32 && !IsArmv7k) {
|
||||
if (IsArm32) {
|
||||
Messaging.PointF_objc_msgSend_stret (out point, obj.Handle, new Selector ("testPointF").Handle);
|
||||
} else {
|
||||
point = Messaging.PointF_objc_msgSend (obj.Handle, new Selector ("testPointF").Handle);
|
||||
}
|
||||
Assert.That (point == new PointF (pi*2, pi*20), "#testPointF");
|
||||
|
||||
if (IsArm32 && !IsArmv7k) {
|
||||
if (IsArm32) {
|
||||
Messaging.SizeF_objc_msgSend_stret (out size, obj.Handle, new Selector ("testSizeF").Handle);
|
||||
} else {
|
||||
size = Messaging.SizeF_objc_msgSend (obj.Handle, new Selector ("testSizeF").Handle);
|
||||
|
@ -805,88 +515,6 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
}
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
public struct IIIIStruct
|
||||
{
|
||||
public int A, B, C, D;
|
||||
|
||||
public IIIIStruct (int a, int b, int c, int d)
|
||||
{
|
||||
A = a;
|
||||
B = b;
|
||||
C = c;
|
||||
D = d;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("[{0};{1};{2};{3}]", A, B, C, D);
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
public struct FFFFStruct
|
||||
{
|
||||
public float A, B, C, D;
|
||||
|
||||
public FFFFStruct (float a, float b, float c, float d)
|
||||
{
|
||||
A = a;
|
||||
B = b;
|
||||
C = c;
|
||||
D = d;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("[{0};{1};{2};{3}]", A, B, C, D);
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
public struct FIFIStruct
|
||||
{
|
||||
public float A;
|
||||
public int B;
|
||||
public float C;
|
||||
public int D;
|
||||
|
||||
public FIFIStruct (float a, int b, float c, int d)
|
||||
{
|
||||
A = a;
|
||||
B = b;
|
||||
C = c;
|
||||
D = d;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("[{0};{1};{2};{3}]", A, B, C, D);
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
public struct IFIFStruct
|
||||
{
|
||||
public int A;
|
||||
public float B;
|
||||
public int C;
|
||||
public float D;
|
||||
|
||||
public IFIFStruct (int a, float b, int c, float d)
|
||||
{
|
||||
A = a;
|
||||
B = b;
|
||||
C = c;
|
||||
D = d;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format ("[{0};{1};{2};{3}]", A, B, C, D);
|
||||
}
|
||||
}
|
||||
|
||||
[Preserve (AllMembers = true)]
|
||||
[Register ("LongTrampolines")]
|
||||
public class LongTrampolines : NSObject
|
||||
|
@ -913,158 +541,6 @@ namespace MonoTouchFixtures.ObjCRuntime {
|
|||
[Preserve (AllMembers = true)]
|
||||
public class StretTrampolines : NSObject
|
||||
{
|
||||
/* IIII */
|
||||
|
||||
[Export ("Test_IIIIStruct")]
|
||||
IIIIStruct Test_IIIIStruct ()
|
||||
{
|
||||
return new IIIIStruct (1, 2, 3, 4);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticIIIIStruct")]
|
||||
static IIIIStruct Test_StaticIIIIStruct ()
|
||||
{
|
||||
return new IIIIStruct (10, 20, 30, 40);
|
||||
}
|
||||
|
||||
IIIIStruct Test_IIIIStructProperty {
|
||||
[Export ("Test_IIIIStructProperty")]
|
||||
get { return new IIIIStruct (100, 200, 300, 400); }
|
||||
}
|
||||
|
||||
static IIIIStruct Test_StaticIIIIStructProperty {
|
||||
[Export ("Test_StaticIIIIStructProperty")]
|
||||
get { return new IIIIStruct (1000, 2000, 3000, 4000); }
|
||||
}
|
||||
|
||||
[Export ("Test_IIIIStruct_out_Double:")]
|
||||
IIIIStruct Test_IIIIStruct_out_Double (out double foo)
|
||||
{
|
||||
foo = 3.14;
|
||||
return new IIIIStruct (1, 20, 300, 4000);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticIIIIStruct_out_Float:")]
|
||||
static IIIIStruct Test_StaticIIIIStruct_out_Float (out float foo)
|
||||
{
|
||||
foo = 3.15f;
|
||||
return new IIIIStruct (10, 20, 300, 4000);
|
||||
}
|
||||
|
||||
/* FFFF */
|
||||
|
||||
[Export ("Test_FFFFStruct")]
|
||||
FFFFStruct Test_FFFFStruct ()
|
||||
{
|
||||
return new FFFFStruct (1, 2, 3, 4);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticFFFFStruct")]
|
||||
static FFFFStruct Test_StaticFFFFStructStruct ()
|
||||
{
|
||||
return new FFFFStruct (10, 20, 30, 40);
|
||||
}
|
||||
|
||||
FFFFStruct Test_FFFFStructtStructProperty {
|
||||
[Export ("Test_FFFFStructProperty")]
|
||||
get { return new FFFFStruct (100, 200, 300, 400); }
|
||||
}
|
||||
|
||||
static FFFFStruct Test_StaticFFFFStructProperty {
|
||||
[Export ("Test_StaticFFFFStructProperty")]
|
||||
get { return new FFFFStruct (1000, 2000, 3000, 4000); }
|
||||
}
|
||||
|
||||
[Export ("Test_FFFFStruct_out_Double:")]
|
||||
FFFFStruct Test_FFFFStruct_out_Double (out double foo)
|
||||
{
|
||||
foo = 3.14;
|
||||
return new FFFFStruct (1, 20, 300, 4000);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticFFFFStruct_out_Float:")]
|
||||
static FFFFStruct Test_StaticFFFFStruct_out_Float (out float foo)
|
||||
{
|
||||
foo = 3.15f;
|
||||
return new FFFFStruct (10, 20, 300, 4000);
|
||||
}
|
||||
|
||||
/* FIFI */
|
||||
|
||||
[Export ("Test_FIFIStruct")]
|
||||
FIFIStruct Test_FIFIStruct ()
|
||||
{
|
||||
return new FIFIStruct (1, 2, 3, 4);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticFIFIStruct")]
|
||||
static FIFIStruct Test_StaticFIFIStructStruct ()
|
||||
{
|
||||
return new FIFIStruct (10, 20, 30, 40);
|
||||
}
|
||||
|
||||
FIFIStruct Test_FIFIStructtStructProperty {
|
||||
[Export ("Test_FIFIStructProperty")]
|
||||
get { return new FIFIStruct (100, 200, 300, 400); }
|
||||
}
|
||||
|
||||
static FIFIStruct Test_StaticFIFIStructProperty {
|
||||
[Export ("Test_StaticFIFIStructProperty")]
|
||||
get { return new FIFIStruct (1000, 2000, 3000, 4000); }
|
||||
}
|
||||
|
||||
[Export ("Test_FIFIStruct_out_Double:")]
|
||||
FIFIStruct Test_FIFIStruct_out_Double (out double foo)
|
||||
{
|
||||
foo = 3.14;
|
||||
return new FIFIStruct (1, 20, 300, 4000);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticFIFIStruct_out_Float:")]
|
||||
static FIFIStruct Test_StaticFIFIStruct_out_Float (out float foo)
|
||||
{
|
||||
foo = 3.15f;
|
||||
return new FIFIStruct (10, 20, 300, 4000);
|
||||
}
|
||||
|
||||
/* IFIF */
|
||||
|
||||
[Export ("Test_IFIFStruct")]
|
||||
IFIFStruct Test_IFIFStruct ()
|
||||
{
|
||||
return new IFIFStruct (1, 2, 3, 4);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticIFIFStruct")]
|
||||
static IFIFStruct Test_StaticIFIFStructStruct ()
|
||||
{
|
||||
return new IFIFStruct (10, 20, 30, 40);
|
||||
}
|
||||
|
||||
IFIFStruct Test_IFIFStructtStructProperty {
|
||||
[Export ("Test_IFIFStructProperty")]
|
||||
get { return new IFIFStruct (100, 200, 300, 400); }
|
||||
}
|
||||
|
||||
static IFIFStruct Test_StaticIFIFStructProperty {
|
||||
[Export ("Test_StaticIFIFStructProperty")]
|
||||
get { return new IFIFStruct (1000, 2000, 3000, 4000); }
|
||||
}
|
||||
|
||||
[Export ("Test_IFIFStruct_out_Double:")]
|
||||
IFIFStruct Test_IFIFStruct_out_Double (out double foo)
|
||||
{
|
||||
foo = 3.14;
|
||||
return new IFIFStruct (1, 20, 300, 4000);
|
||||
}
|
||||
|
||||
[Export ("Test_StaticIFIFStruct_out_Float:")]
|
||||
static IFIFStruct Test_StaticIFIFStruct_out_Float (out float foo)
|
||||
{
|
||||
foo = 3.15f;
|
||||
return new IFIFStruct (10, 20, 300, 4000);
|
||||
}
|
||||
|
||||
#if !__WATCHOS__
|
||||
[Export ("myTimeRange")]
|
||||
CMTimeRange TimeRange {
|
||||
|
|
|
@ -478,7 +478,9 @@
|
|||
<Compile Include="Foundation\DictionaryContainerTest.cs" />
|
||||
<Compile Include="ObjCRuntime\Messaging.cs" />
|
||||
<Compile Include="ObjCRuntime\TrampolineTest.cs" />
|
||||
<Compile Include="ObjCRuntime\TrampolineTest.generated.cs" />
|
||||
<Compile Include="ObjCRuntime\RegistrarTest.cs" />
|
||||
<Compile Include="ObjCRuntime\RegistrarTest.generated.cs" />
|
||||
<Compile Include="CoreGraphics\DataProviderTest.cs" />
|
||||
<Compile Include="HealthKit\QuantityTypeIdentifierTest.cs" />
|
||||
<Compile Include="HealthKit\CategoryTypeIdentifierTest.cs" />
|
||||
|
@ -753,4 +755,15 @@
|
|||
<ImageAsset Condition="'$(TargetFrameworkIdentifier)' != 'Xamarin.WatchOS'" Include="Assets.xcassets\AppIcons.appiconset\icon-app-76%402x.png" />
|
||||
<ImageAsset Condition="'$(TargetFrameworkIdentifier)' != 'Xamarin.WatchOS'" Include="Assets.xcassets\AppIcons.appiconset\icon-app-83.5%402x.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\*.m" />
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\*.h" />
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\*.cs" />
|
||||
<GeneratedTestInput Include="..\..\tests\test-libraries\Makefile" />
|
||||
<GeneratedTestOutput Include="ObjCRuntime\TrampolineTest.generated.cs" />
|
||||
<GeneratedTestOutput Include="ObjCRuntime\RegistrarTest.generated.cs" />
|
||||
</ItemGroup>
|
||||
<Target Name="BeforeBuild" Inputs="@(GeneratedTestInput)" Outputs="@(GeneratedTestOutput)">
|
||||
<Exec Command="make -j8 -C ..\..\tests\test-libraries" />
|
||||
</Target>
|
||||
</Project>
|
|
@ -3,4 +3,7 @@
|
|||
.libs
|
||||
libtest-ar.m
|
||||
libtest-object.m
|
||||
libtest.structs.h
|
||||
libtest.properties.h
|
||||
libtest.decompile.m
|
||||
|
||||
|
|
|
@ -5,6 +5,30 @@ include $(TOP)/Make.config
|
|||
# in system headers show up.
|
||||
export CCACHE_CPP2=1
|
||||
|
||||
GENERATED_FILES = \
|
||||
libtest.structs.h \
|
||||
libtest.decompile.m \
|
||||
libtest.properties.h \
|
||||
../bindings-test/ApiDefinition.generated.cs \
|
||||
../bindings-test/StructsAndEnums.generated.cs \
|
||||
../monotouch-test/ObjCRuntime/RegistrarTest.generated.cs \
|
||||
../monotouch-test/ObjCRuntime/TrampolineTest.generated.cs \
|
||||
|
||||
GENERATED_FILES_PATTERN = \
|
||||
libtest.structs%h \
|
||||
libtest.decompile%m \
|
||||
libtest.properties%h \
|
||||
../bindings-test/ApiDefinition.generated%cs \
|
||||
../bindings-test/StructsAndEnums.generated%cs \
|
||||
../monotouch-test/ObjCRuntime/RegistrarTest.generated%cs \
|
||||
../monotouch-test/ObjCRuntime/TrampolineTest.generated%cs \
|
||||
|
||||
testgenerator.exe: testgenerator.cs Makefile
|
||||
$(Q) mcs -out:$@ $<
|
||||
|
||||
$(GENERATED_FILES_PATTERN): testgenerator.exe
|
||||
$(Q) mono --debug $<
|
||||
|
||||
libtest-object.m libtest-ar.m:
|
||||
$(Q) ln -fhs libtest.m $@
|
||||
|
||||
|
@ -24,12 +48,13 @@ $(2)_TARGETS = \
|
|||
$$(foreach arch,$(3),.libs/$(1)/libtest-ar.$$(arch).a) \
|
||||
.libs/$(1)/XTest.framework \
|
||||
|
||||
all-local:: $$($(2)_TARGETS)
|
||||
all-local:: $$($(2)_TARGETS) $(GENERATED_FILES)
|
||||
|
||||
clean-$(1):
|
||||
rm -Rf .libs/$(1)
|
||||
|
||||
CLEAN_TARGETS += clean-$(1)
|
||||
EXTRA_DEPENDENCIES = libtest.h $(GENERATED_FILES)
|
||||
|
||||
.libs/$(1)/libtest-object.%.o: export EXTRA_DEFINES=-DPREFIX=1
|
||||
.libs/$(1)/libtest-ar.%.o: export EXTRA_DEFINES=-DPREFIX=2
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -13,31 +13,7 @@ void useZLib ();
|
|||
* Various structs used in ObjCRegistrarTest
|
||||
*/
|
||||
|
||||
struct Sd { double d1; } Sd;
|
||||
struct Sdd { double d1; double d2; } Sdd;
|
||||
struct Sddd { double d1; double d2; double d3; } Sddd;
|
||||
struct Sdddd { double d1; double d2; double d3; double d4; } Sdddd;
|
||||
struct Si { int i1; } Si;
|
||||
struct Sii { int i1; int i2; } Sii;
|
||||
struct Siii { int i1; int i2; int i3; } Siii;
|
||||
struct Siiii { int i1; int i2; int i3; int i4; } Siiii;
|
||||
struct Siiiii { int i1; int i2; int i3; int i4; int i5; } Siiiii;
|
||||
struct Sid { int i1; double d2; } Sid;
|
||||
struct Sdi { double d1; int i2; } Sdi;
|
||||
struct Sidi { int i1; double d2; int i3; } Sidi;
|
||||
struct Siid { int i1; int i2; double d3; } Siid;
|
||||
struct Sddi { double d1; double d2; int i3; } Sddi;
|
||||
struct Sl { long l1; } Sl;
|
||||
struct Sll { long l1; long l2; } Sll;
|
||||
struct Slll { long l1; long l2; long l3; } Slll;
|
||||
struct Scccc { char c1; char c2; char c3; char c4; } Scccc;
|
||||
struct Sffff { float f1; float f2; float f3; float f4; } Sffff;
|
||||
struct Sif { int i1; float f2; } Sif;
|
||||
struct Sf { float f1; } Sf;
|
||||
struct Sff { float f1; float f2; } Sff;
|
||||
struct Siff { int i1; float f2; float f3; } Siff;
|
||||
struct Siiff { int i1; int i2; float f3; float f4; } Siiff;
|
||||
struct Sfi { float f1; int i2; } Sfi;
|
||||
#include "libtest.structs.h"
|
||||
|
||||
typedef unsigned int (^RegistrarTestBlock) (unsigned int magic);
|
||||
|
||||
|
@ -79,9 +55,7 @@ typedef unsigned int (^RegistrarTestBlock) (unsigned int magic);
|
|||
@property char Pc4;
|
||||
@property char Pc5;
|
||||
|
||||
@property struct Siid PSiid1;
|
||||
@property struct Sd PSd1;
|
||||
@property struct Sf PSf1;
|
||||
#include "libtest.properties.h"
|
||||
|
||||
-(void) V;
|
||||
|
||||
|
|
|
@ -80,12 +80,12 @@ static UltimateMachine *shared;
|
|||
|
||||
-(struct Sd) Sd
|
||||
{
|
||||
return _PSd1;
|
||||
return _PSd;
|
||||
}
|
||||
|
||||
-(struct Sf) Sf
|
||||
{
|
||||
return _PSf1;
|
||||
return _PSf;
|
||||
}
|
||||
|
||||
-(void) V:(int)i1 i:(int)i2 i:(int)i3 i:(int)i4 i:(int)i5 i:(int)i6 i:(int)i7
|
||||
|
@ -115,12 +115,12 @@ static UltimateMachine *shared;
|
|||
|
||||
-(void) V:(int)i1 i:(int)i2 Siid:(struct Siid)s1 i:(int)i3 i:(int)i4 d:(double)d1 d:(double)d2 d:(double)d3 i:(int)i5 i:(int)i6 i:(int)i7
|
||||
{
|
||||
_Pi1 = i1; _Pi2 = i2; _PSiid1 = s1; _Pi3 = i3; _Pi4 = i4; _Pd1 = d1; _Pd2 = d2; _Pd3 = d2; _Pi5 = i5; _Pi6 = i6; _Pi7 = i7;
|
||||
_Pi1 = i1; _Pi2 = i2; _PSiid = s1; _Pi3 = i3; _Pi4 = i4; _Pd1 = d1; _Pd2 = d2; _Pd3 = d2; _Pi5 = i5; _Pi6 = i6; _Pi7 = i7;
|
||||
}
|
||||
|
||||
-(void) V:(int)i1 i:(int)i2 f:(float)f1 Siid:(struct Siid)s1 i:(int)i3 i:(int)i4 d:(double)d1 d:(double)d2 d:(double)d3 i:(int)i5 i:(int)i6 i:(int)i7
|
||||
{
|
||||
_Pi1 = i1; _Pi2 = i2; _Pf1 = f1; _PSiid1 = s1; _Pi3 = i3; _Pi4 = i4; _Pd1 = d1; _Pd2 = d2; _Pd3 = d3; _Pi5 = i5; _Pi6 = i6; _Pi7 = i7;
|
||||
_Pi1 = i1; _Pi2 = i2; _Pf1 = f1; _PSiid = s1; _Pi3 = i3; _Pi4 = i4; _Pd1 = d1; _Pd2 = d2; _Pd3 = d3; _Pi5 = i5; _Pi6 = i6; _Pi7 = i7;
|
||||
}
|
||||
|
||||
-(void) V:(char)c1 c:(char)c2 c:(char)c3 c:(char)c4 c:(char)c5 i:(int)i1 d:(double)d1
|
||||
|
@ -253,3 +253,5 @@ static UltimateMachine *shared;
|
|||
// Do nothing
|
||||
}
|
||||
@end
|
||||
|
||||
#include "libtest.decompile.m"
|
||||
|
|
|
@ -0,0 +1,538 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
static class C {
|
||||
[Flags]
|
||||
enum Architecture
|
||||
{
|
||||
None = 0,
|
||||
Sim32 = 1,
|
||||
Sim64 = 2,
|
||||
Arm32 = 4,
|
||||
Armv7k = 8,
|
||||
// Arm64 is never stret
|
||||
}
|
||||
|
||||
// X86: structs > 8 + structs with 3 members.
|
||||
// X64: structs > 16
|
||||
// ARM32: all structs, except those matching an integral platform type (i.e. a struct with a single int, but not a struct with a single float).
|
||||
// ARM64: never
|
||||
// armv7k: > 16, except homogeneous types with no more than 4 elements (i.e. structs with 3 or 4 doubles).
|
||||
// the numbers below are bitmasks of Architecture values.
|
||||
static string [] structs_and_stret = {
|
||||
/* integral types */
|
||||
"c:0", "cc:4", "ccc:5", "cccc:4",
|
||||
"s:0", "ss:4", "sss:5", "ssss:4",
|
||||
"i:0", "ii:4", "iii:5", "iiii:5", "iiiii:15",
|
||||
"l:4", "ll:5", "lll:15", "llll:15", "lllll:15",
|
||||
/* floating point types */
|
||||
"f:4", "ff:4", "fff:5", "ffff:5", "fffff:15",
|
||||
"d:4", "dd:5", "ddd:7", "dddd:7", "ddddd:15",
|
||||
/* mixed types */
|
||||
"if:4", "fi:4", // 8 bytes
|
||||
"iff:5", // 12 bytes
|
||||
"iiff:5", // 16 bytes
|
||||
"id:5", "di:5", // 16 bytes
|
||||
"iid:5", // 16 bytes
|
||||
"idi:15", // 16 bytes on i386 and 24 bytes on x86_64 (due to alignment)
|
||||
"ddi:15", // 24 bytes
|
||||
"didi:15", // 24 bytes on 32-bit arch, 32 bytes on 64-bit arch
|
||||
"idid:15", // 24 bytes on 32-bit arch, 32 bytes on 64-bit arch
|
||||
"dldl:15",
|
||||
"ldld:15",
|
||||
"fifi:5",
|
||||
"ifif:5",
|
||||
};
|
||||
|
||||
static string [] structs = structs_and_stret.Select ((v) => v.IndexOf (':') >= 0 ? v.Substring (0, v.IndexOf (':')) : v).ToArray ();
|
||||
static Architecture [] strets = structs_and_stret.Select ((v) => v.IndexOf (':') >= 0 ? (Architecture) int.Parse (v.Substring (v.IndexOf (':') + 1)) : Architecture.None).ToArray ();
|
||||
|
||||
static string GetNativeName (char t)
|
||||
{
|
||||
switch (t) {
|
||||
case 'f': return "float";
|
||||
case 'd': return "double";
|
||||
case 'c': return "char";
|
||||
case 's': return "short";
|
||||
case 'i': return "int";
|
||||
case 'l': return "long long";
|
||||
default:
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
|
||||
static string GetManagedName (char t)
|
||||
{
|
||||
switch (t) {
|
||||
case 'f': return "float";
|
||||
case 'd': return "double";
|
||||
case 'c': return "byte";
|
||||
case 's': return "short";
|
||||
case 'i': return "int";
|
||||
case 'l': return "long";
|
||||
default:
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
|
||||
static string GetValue (char t, int i, int multiplier = 1)
|
||||
{
|
||||
switch (t) {
|
||||
case 'c':
|
||||
case 's':
|
||||
case 'i':
|
||||
case 'l': return ((i + 1) * multiplier).ToString ();
|
||||
case 'f': return (3.14f * (i + 1) * multiplier) + "f";
|
||||
case 'd': return (1.23f * (i + 1) * multiplier).ToString ();
|
||||
default:
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteLibTestStructH ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
foreach (var s in structs) {
|
||||
w.Append ($"struct S{s} {{ ");
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
w.Append (GetNativeName (s [i])).Append (" x").Append (i).Append ("; ");
|
||||
}
|
||||
w.AppendLine ($"}} S{s};");
|
||||
}
|
||||
|
||||
File.WriteAllText ("libtest.structs.h", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteLibTestDecompileM ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
// This is code to be disassembled to see how it's compiled by clang
|
||||
// to see if a particular structure is using objc_msgSend_stret or not.
|
||||
//
|
||||
// To disassemble:
|
||||
// otool -vVt .libs/ios/libtest.armv7.o
|
||||
//
|
||||
// Then in the _decompile_me output, look for the _____* function call,
|
||||
// matching the structure you want to check, and then backtrack until
|
||||
// you see either an objc_msgSend or objc_msgSend_stret call, and you
|
||||
// have your answer.
|
||||
#if false
|
||||
w.AppendLine ("extern \"C\" {");
|
||||
foreach (var s in structs)
|
||||
w.AppendLine ($"void _____________________________________{s} (struct S{s} x) __attribute__ ((optnone)) {{ }}");
|
||||
w.AppendLine ("void decompile_me () __attribute__ ((optnone))");
|
||||
w.AppendLine ("{");
|
||||
w.AppendLine ("\tObjCRegistrarTest *obj = NULL;");
|
||||
foreach (var s in structs) {
|
||||
w.AppendLine ($"\t_____________________________________{s} ([obj PS{s}]);");
|
||||
}
|
||||
w.AppendLine ("}");
|
||||
w.AppendLine ("}");
|
||||
#endif
|
||||
|
||||
File.WriteAllText ("libtest.decompile.m", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteLibTestPropertiesH ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
foreach (var s in structs)
|
||||
w.AppendLine ($"\t@property struct S{s} PS{s};");
|
||||
|
||||
File.WriteAllText ("libtest.properties.h", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteApiDefinition ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
w.AppendLine (@"using System;
|
||||
#if !__WATCHOS__
|
||||
using System.Drawing;
|
||||
#endif
|
||||
|
||||
#if __UNIFIED__
|
||||
using ObjCRuntime;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
#else
|
||||
using MonoTouch.ObjCRuntime;
|
||||
using MonoTouch.Foundation;
|
||||
using MonoTouch.UIKit;
|
||||
#endif
|
||||
|
||||
namespace Bindings.Test {
|
||||
partial interface ObjCRegistrarTest {
|
||||
|
||||
");
|
||||
|
||||
foreach (var s in structs) {
|
||||
w.AppendLine ($"\t\t[Export (\"PS{s}\")]");
|
||||
w.AppendLine ($"\t\tS{s} PS{s} {{ get; set; }}");
|
||||
w.AppendLine ();
|
||||
}
|
||||
|
||||
w.AppendLine (@" }
|
||||
}");
|
||||
|
||||
File.WriteAllText ("../bindings-test/ApiDefinition.generated.cs", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteStructsAndEnums ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
w.AppendLine (@"using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if !__UNIFIED__
|
||||
using nint=System.Int32;
|
||||
#endif
|
||||
|
||||
namespace Bindings.Test
|
||||
{
|
||||
");
|
||||
|
||||
foreach (var s in structs) {
|
||||
w.AppendLine ($"\tpublic struct S{s} {{ ");
|
||||
w.Append ("\t\t");
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
w.Append ("public ").Append (GetManagedName (s [i])).Append (" x").Append (i).Append ("; ");
|
||||
}
|
||||
w.AppendLine ();
|
||||
w.Append ($"\t\tpublic override string ToString () {{ return $\"S{s} [");
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
w.Append ("{x").Append (i).Append ("};");
|
||||
}
|
||||
w.Length--;
|
||||
w.AppendLine ("]\"; } ");
|
||||
w.AppendLine ("\t}");
|
||||
w.AppendLine ();
|
||||
}
|
||||
|
||||
w.AppendLine (@"}");
|
||||
|
||||
File.WriteAllText ("../bindings-test/StructsAndEnums.generated.cs", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteRegistrarTests ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
w.AppendLine (@"
|
||||
#if XAMCORE_2_0
|
||||
using Foundation;
|
||||
using ObjCRuntime;
|
||||
using MonoTouchException=ObjCRuntime.RuntimeException;
|
||||
using NativeException=Foundation.MonoTouchException;
|
||||
#else
|
||||
using MonoTouch;
|
||||
using MonoTouch.Foundation;
|
||||
using MonoTouch.ObjCRuntime;
|
||||
using MonoTouchException=MonoTouch.RuntimeException;
|
||||
using NativeException=MonoTouch.Foundation.MonoTouchException;
|
||||
#endif
|
||||
using NUnit.Framework;
|
||||
using Bindings.Test;
|
||||
|
||||
using XamarinTests.ObjCRuntime;
|
||||
|
||||
namespace MonoTouchFixtures.ObjCRuntime {
|
||||
|
||||
[TestFixture]
|
||||
[Preserve (AllMembers = true)]
|
||||
public class RegistrarTestGenerated {");
|
||||
|
||||
foreach (var s in structs) {
|
||||
w.AppendLine ("\t\t[Test]");
|
||||
w.AppendLine ($"\t\tpublic void Test_{s} ()");
|
||||
w.AppendLine ("\t\t{");
|
||||
w.AppendLine ("\t\t\tusing (var tc = new ObjCRegistrarTest ()) {");
|
||||
w.AppendLine ($"\t\t\t\tvar s = tc.PS{s};");
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (0, s.x{i}, \"pre-#{i}\");");
|
||||
w.Append ($"\t\t\t\tvar k = new S{s} () {{ ");
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
w.Append ($"x{i} = ").Append (GetValue (s [i], i)).Append (", ");
|
||||
w.Length -= 2;
|
||||
w.AppendLine ("};");
|
||||
w.AppendLine ($"\t\t\t\ttc.PS{s} = k;");
|
||||
w.AppendLine ($"\t\t\t\ts = tc.PS{s};");
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (k.x{i}, s.x{i}, \"post-#{i}\");");
|
||||
w.AppendLine ("\t\t\t}");
|
||||
w.AppendLine ("\t\t}");
|
||||
w.AppendLine ();
|
||||
}
|
||||
|
||||
w.AppendLine (@" }
|
||||
}");
|
||||
|
||||
File.WriteAllText ("../monotouch-test/ObjCRuntime/RegistrarTest.generated.cs", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteTrampolineTests ()
|
||||
{
|
||||
var w = new StringBuilder ();
|
||||
|
||||
w.AppendLine (@"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if XAMCORE_2_0
|
||||
using Foundation;
|
||||
using ObjCRuntime;
|
||||
#else
|
||||
using MonoTouch;
|
||||
using MonoTouch.Foundation;
|
||||
using MonoTouch.ObjCRuntime;
|
||||
#endif
|
||||
using NUnit.Framework;
|
||||
using Bindings.Test;
|
||||
|
||||
using XamarinTests.ObjCRuntime;
|
||||
|
||||
namespace MonoTouchFixtures.ObjCRuntime {
|
||||
|
||||
[TestFixture]
|
||||
[Preserve (AllMembers = true)]
|
||||
public class TrampolineTestGenerated {");
|
||||
w.AppendLine ("\t\tconst string LIBOBJC_DYLIB = \"/usr/lib/libobjc.dylib\";");
|
||||
w.AppendLine ();
|
||||
|
||||
w.AppendLine ("\t\t[Register (\"GeneratedStretTrampolines\")]");
|
||||
w.AppendLine ("\t\t[Preserve (AllMembers = true)]");
|
||||
w.AppendLine ("\t\tpublic class GeneratedStretTrampolines : NSObject {");
|
||||
foreach (var s in structs) {
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\t// {s}");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\t[Export (\"Test_{s}Struct\")]");
|
||||
w.AppendLine ($"\t\t\tS{s} Test_{s}Struct ()");
|
||||
w.AppendLine ($"\t\t\t{{");
|
||||
w.AppendLine ($"\t\t\t\treturn {GenerateNewExpression (s, 1)};");
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\t[Export (\"Test_Static{s}Struct\")]");
|
||||
w.AppendLine ($"\t\t\tstatic S{s} Test_Static{s}Struct ()");
|
||||
w.AppendLine ($"\t\t\t{{");
|
||||
w.AppendLine ($"\t\t\t\treturn {GenerateNewExpression (s, 2)};");
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\tS{s} Test_{s}StructProperty {{");
|
||||
w.AppendLine ($"\t\t\t\t[Export (\"Test_{s}StructProperty\")]");
|
||||
w.AppendLine ($"\t\t\t\tget {{ return {GenerateNewExpression (s, 3)}; }}");
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\tstatic S{s} Test_Static{s}StructProperty {{");
|
||||
w.AppendLine ($"\t\t\t\t[Export (\"Test_Static{s}StructProperty\")]");
|
||||
w.AppendLine ($"\t\t\t\tget {{ return {GenerateNewExpression (s, 4)}; }}");
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\t[Export (\"Test_{s}Struct_out_double:\")]");
|
||||
w.AppendLine ($"\t\t\tS{s} Test_{s}Struct (out double x0)");
|
||||
w.AppendLine ($"\t\t\t{{");
|
||||
w.AppendLine ($"\t\t\t\tx0 = 3.14;");
|
||||
w.AppendLine ($"\t\t\t\treturn {GenerateNewExpression (s, 5)};");
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t\t[Export (\"Test_Static{s}Struct_out_float:\")]");
|
||||
w.AppendLine ($"\t\t\tstatic S{s} Test_Static{s}Struct (out float x0)");
|
||||
w.AppendLine ($"\t\t\t{{");
|
||||
w.AppendLine ($"\t\t\t\tx0 = 3.15f;");
|
||||
w.AppendLine ($"\t\t\t\treturn {GenerateNewExpression (s, 6)};");
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ("\t\t}");
|
||||
|
||||
foreach (var s in structs) {
|
||||
if (s.Length == 1 || s.Contains ('c'))
|
||||
continue; // our trampolines don't currently like structs with a single member, nor char members
|
||||
|
||||
bool never;
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[Test]");
|
||||
w.AppendLine ($"\t\tpublic void Test_{s} ()");
|
||||
w.AppendLine ($"\t\t{{");
|
||||
w.AppendLine ($"\t\t\tIntPtr class_ptr = Class.GetHandle (typeof (GeneratedStretTrampolines));");
|
||||
w.AppendLine ($"\t\t\tS{s} rv = new S{s} ();");
|
||||
w.AppendLine ($"\t\t\tdouble rvd;");
|
||||
w.AppendLine ($"\t\t\tfloat rvf;");
|
||||
w.AppendLine ($"\t\t\tusing (var obj = new GeneratedStretTrampolines ()) {{");
|
||||
|
||||
WriteStretConditions (w, s, out never);
|
||||
if (never) {
|
||||
w.AppendLine ($"\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}Struct\").Handle);");
|
||||
} else {
|
||||
w.AppendLine ($"\t\t\t\t\tS{s}_objc_msgSend_stret (out rv, obj.Handle, new Selector (\"Test_{s}Struct\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}} else {{");
|
||||
w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}Struct\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 1)}).ToString (), rv.ToString (), \"a\");");
|
||||
w.AppendLine ();
|
||||
|
||||
WriteStretConditions (w, s, out never);
|
||||
if (never) {
|
||||
w.AppendLine ($"\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}Struct\").Handle);");
|
||||
} else {
|
||||
w.AppendLine ($"\t\t\t\t\tS{s}_objc_msgSend_stret (out rv, class_ptr, new Selector (\"Test_Static{s}Struct\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}} else {{");
|
||||
w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}Struct\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 2)}).ToString (), rv.ToString (), \"a\");");
|
||||
w.AppendLine ();
|
||||
|
||||
WriteStretConditions (w, s, out never);
|
||||
if (never) {
|
||||
w.AppendLine ($"\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}StructProperty\").Handle);");
|
||||
} else {
|
||||
w.AppendLine ($"\t\t\t\t\tS{s}_objc_msgSend_stret (out rv, obj.Handle, new Selector (\"Test_{s}StructProperty\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}} else {{");
|
||||
w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (obj.Handle, new Selector (\"Test_{s}StructProperty\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 3)}).ToString (), rv.ToString (), \"a\");");
|
||||
w.AppendLine ();
|
||||
|
||||
WriteStretConditions (w, s, out never);
|
||||
if (never) {
|
||||
w.AppendLine ($"\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}StructProperty\").Handle);");
|
||||
} else {
|
||||
w.AppendLine ($"\t\t\t\t\tS{s}_objc_msgSend_stret (out rv, class_ptr, new Selector (\"Test_Static{s}StructProperty\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}} else {{");
|
||||
w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend (class_ptr, new Selector (\"Test_Static{s}StructProperty\").Handle);");
|
||||
w.AppendLine ($"\t\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 4)}).ToString (), rv.ToString (), \"a\");");
|
||||
w.AppendLine ();
|
||||
|
||||
w.AppendLine ($"\t\t\t\trvd = 0;");
|
||||
WriteStretConditions (w, s, out never);
|
||||
if (never) {
|
||||
w.AppendLine ($"\t\t\t\trv = S{s}_objc_msgSend_out_double (obj.Handle, new Selector (\"Test_{s}Struct_out_double:\").Handle, out rvd);");
|
||||
} else {
|
||||
w.AppendLine ($"\t\t\t\t\tS{s}_objc_msgSend_stret_out_double (out rv, obj.Handle, new Selector (\"Test_{s}Struct_out_double:\").Handle, out rvd);");
|
||||
w.AppendLine ($"\t\t\t\t}} else {{");
|
||||
w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend_out_double (obj.Handle, new Selector (\"Test_{s}Struct_out_double:\").Handle, out rvd);");
|
||||
w.AppendLine ($"\t\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 5)}).ToString (), rv.ToString (), \"a\");");
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (3.14, rvd, \"double out\");");
|
||||
w.AppendLine ();
|
||||
|
||||
w.AppendLine ($"\t\t\t\trvf = 0;");
|
||||
WriteStretConditions (w, s, out never);
|
||||
if (never) {
|
||||
w.AppendLine ($"\t\t\t\trv = S{s}_objc_msgSend_out_float (class_ptr, new Selector (\"Test_Static{s}Struct_out_float:\").Handle, out rvf);");
|
||||
} else {
|
||||
w.AppendLine ($"\t\t\t\t\tS{s}_objc_msgSend_stret_out_float (out rv, class_ptr, new Selector (\"Test_Static{s}Struct_out_float:\").Handle, out rvf);");
|
||||
w.AppendLine ($"\t\t\t\t}} else {{");
|
||||
w.AppendLine ($"\t\t\t\t\trv = S{s}_objc_msgSend_out_float (class_ptr, new Selector (\"Test_Static{s}Struct_out_float:\").Handle, out rvf);");
|
||||
w.AppendLine ($"\t\t\t\t}}");
|
||||
}
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (({GenerateNewExpression (s, 6)}).ToString (), rv.ToString (), \"a\");");
|
||||
w.AppendLine ($"\t\t\t\tAssert.AreEqual (3.15f, rvf, \"float out\");");
|
||||
w.AppendLine ();
|
||||
|
||||
w.AppendLine ($"\t\t\t}}");
|
||||
w.AppendLine ($"\t\t}}");
|
||||
|
||||
|
||||
// objc_msgSend variants
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSend\")]");
|
||||
w.AppendLine ($"\t\textern static S{s} S{s}_objc_msgSend (IntPtr received, IntPtr selector);");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSend\")]");
|
||||
w.AppendLine ($"\t\textern static S{s} S{s}_objc_msgSend_out_float (IntPtr received, IntPtr selector, out float x1);");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSend\")]");
|
||||
w.AppendLine ($"\t\textern static S{s} S{s}_objc_msgSend_out_double (IntPtr received, IntPtr selector, out double x1);");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSend_stret\")]");
|
||||
w.AppendLine ($"\t\textern static void S{s}_objc_msgSend_stret (out S{s} rv, IntPtr received, IntPtr selector);");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSend_stret\")]");
|
||||
w.AppendLine ($"\t\textern static void S{s}_objc_msgSend_stret_out_float (out S{s} rv, IntPtr received, IntPtr selector, out float x1);");
|
||||
|
||||
w.AppendLine ();
|
||||
w.AppendLine ($"\t\t[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSend_stret\")]");
|
||||
w.AppendLine ($"\t\textern static void S{s}_objc_msgSend_stret_out_double (out S{s} rv, IntPtr received, IntPtr selector, out double x1);");
|
||||
}
|
||||
|
||||
w.AppendLine (@" }
|
||||
}");
|
||||
|
||||
File.WriteAllText ("../monotouch-test/ObjCRuntime/TrampolineTest.generated.cs", w.ToString ());
|
||||
}
|
||||
|
||||
static void WriteStretConditions (StringBuilder w, string s, out bool never)
|
||||
{
|
||||
var stret = strets [Array.IndexOf (structs, s)];
|
||||
if (stret == Architecture.None) {
|
||||
never = true;
|
||||
} else {
|
||||
never = false;
|
||||
w.Append ("\t\t\t\tif (");
|
||||
if ((stret & Architecture.Arm32) == Architecture.Arm32)
|
||||
w.Append ("TrampolineTest.IsArm32 || ");
|
||||
if ((stret & Architecture.Armv7k) == Architecture.Armv7k)
|
||||
w.Append ("TrampolineTest.IsArmv7k || ");
|
||||
if ((stret & Architecture.Sim32) == Architecture.Sim32)
|
||||
w.Append ("TrampolineTest.IsSim32 || ");
|
||||
if ((stret & Architecture.Sim64) == Architecture.Sim64)
|
||||
w.Append ("TrampolineTest.IsSim64 || ");
|
||||
w.Length -= 4;
|
||||
w.AppendLine (") {");
|
||||
}
|
||||
}
|
||||
|
||||
static string GenerateNewExpression (string s, int multiplier = 1)
|
||||
{
|
||||
var sb = new StringBuilder ();
|
||||
sb.Append ($"new S{s} () {{ ");
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
sb.Append ("x").Append (i).Append (" = ").Append (GetValue (s [i], i, multiplier)).Append (", ");
|
||||
sb.Length -= 2;
|
||||
sb.Append (" }");
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
static void Main ()
|
||||
{
|
||||
while (Path.GetFileName (Environment.CurrentDirectory) != "test-libraries")
|
||||
Environment.CurrentDirectory = Path.GetDirectoryName (Environment.CurrentDirectory);
|
||||
|
||||
/* native code */
|
||||
WriteLibTestStructH ();
|
||||
WriteLibTestDecompileM ();
|
||||
WriteLibTestPropertiesH ();
|
||||
|
||||
/* binding code */
|
||||
WriteApiDefinition ();
|
||||
WriteStructsAndEnums ();
|
||||
|
||||
/* tests */
|
||||
WriteRegistrarTests ();
|
||||
WriteTrampolineTests ();
|
||||
|
||||
Console.WriteLine ("Generated test files");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{CD430449-8E59-4ECD-ADD9-ACF79E9E660B}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>testgenerator</RootNamespace>
|
||||
<AssemblyName>testgenerator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ExternalConsole>true</ExternalConsole>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ExternalConsole>true</ExternalConsole>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="testgenerator.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -339,6 +339,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.
|
||||
// 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 **
|
||||
// MT8018 Internal consistency error. Please file a bug report at http://bugzilla.xamarin.com.
|
||||
// MT9xxx Licensing
|
||||
//
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче