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:
Rolf Bjarne Kvinge 2016-10-13 19:44:02 +02:00 коммит произвёл GitHub
Родитель 17bb354dca 9d85ca79ab
Коммит 2a9f5a8238
24 изменённых файлов: 1044 добавлений и 896 удалений

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

@ -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;

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

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

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

@ -1473,6 +1473,7 @@ SHARED_SOURCES = \
ObjCRuntime/Selector.iOS.cs \
ObjCRuntime/Selector.mac.cs \
ObjCRuntime/SelectorMarshaler.cs \
ObjCRuntime/Stret.cs \
ObjCRuntime/ThreadSafeAttribute.cs \
ObjCRuntime/TransientAttribute.cs \
ObjCRuntime/TypeConverter.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))) ||

1
tests/.gitignore поставляемый
Просмотреть файл

@ -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
tests/test-libraries/.gitignore поставляемый
Просмотреть файл

@ -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
//