2016-04-21 15:19:32 +03:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <objc/objc.h>
|
|
|
|
#include <objc/runtime.h>
|
|
|
|
#include <objc/message.h>
|
|
|
|
|
|
|
|
#include "xamarin/xamarin.h"
|
|
|
|
#include "runtime-internal.h"
|
|
|
|
#include "trampolines-internal.h"
|
|
|
|
#include "slinked-list.h"
|
|
|
|
#include "delegates.h"
|
|
|
|
|
|
|
|
//#define TRACE
|
|
|
|
#ifdef TRACE
|
|
|
|
#define LOGZ(...) fprintf (stderr, __VA_ARGS__);
|
|
|
|
#else
|
|
|
|
#define LOGZ(...)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
xamarin_invoke_trampoline (enum TrampolineType type, id self, SEL sel, iterator_func iterator, marshal_return_value_func marshal_return_value, void *context)
|
|
|
|
{
|
2016-02-15 21:02:14 +03:00
|
|
|
// COOP: No managed data in input, but accesses managed data.
|
|
|
|
// COOP: FIXME: This method needs a lot of work when the runtime team
|
|
|
|
// implements a handle api for mono objects.
|
|
|
|
// Random notes:
|
|
|
|
// * Must switch to SAFE mode when calling any external code.
|
|
|
|
// * mono_runtime_invoke will have to change, since 'out/ref'
|
|
|
|
// objects arguments are now put into the arg_ptrs array
|
|
|
|
// (clearly not GC-safe upon return).
|
2016-05-16 20:30:58 +03:00
|
|
|
MONO_ASSERT_GC_SAFE_OR_DETACHED;
|
2016-02-15 21:02:14 +03:00
|
|
|
|
2016-05-11 14:27:51 +03:00
|
|
|
MonoObject *exception = NULL;
|
2016-10-28 20:07:01 +03:00
|
|
|
MonoObject **exception_ptr = xamarin_is_managed_exception_marshaling_disabled () ? NULL : &exception;
|
2016-06-02 13:18:45 +03:00
|
|
|
guint32 exception_gchandle = 0;
|
2016-04-21 15:19:32 +03:00
|
|
|
bool is_static = (type & Tramp_Static) == Tramp_Static;
|
|
|
|
bool is_ctor = type == Tramp_Ctor;
|
2016-06-02 13:18:45 +03:00
|
|
|
const char *ret_type = NULL;
|
2016-04-21 15:19:32 +03:00
|
|
|
|
|
|
|
if (is_ctor) {
|
2016-06-02 13:18:45 +03:00
|
|
|
bool has_nsobject = xamarin_has_nsobject (self, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0) {
|
|
|
|
xamarin_process_managed_exception_gchandle (exception_gchandle);
|
|
|
|
return; // we shouldn't get here.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_nsobject) {
|
2016-04-21 15:19:32 +03:00
|
|
|
self = xamarin_invoke_objc_method_implementation (self, sel, (IMP) xamarin_ctor_trampoline);
|
2016-06-02 13:18:45 +03:00
|
|
|
marshal_return_value (context, "|", sizeof (id), self, NULL, false, NULL, &exception_gchandle);
|
|
|
|
xamarin_process_managed_exception_gchandle (exception_gchandle);
|
2016-04-21 15:19:32 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-16 20:31:56 +03:00
|
|
|
MONO_THREAD_ATTACH; // COOP: This will swith to GC_UNSAFE
|
2016-02-15 21:02:14 +03:00
|
|
|
|
2016-04-21 15:19:32 +03:00
|
|
|
// pre-prolog
|
|
|
|
SList *dispose_list = NULL;
|
|
|
|
int num_arg;
|
|
|
|
NSMethodSignature *sig;
|
|
|
|
|
|
|
|
if (is_static) {
|
|
|
|
sig = [NSMethodSignature signatureWithObjCTypes: method_getTypeEncoding (class_getClassMethod (self, sel))];
|
|
|
|
} else {
|
|
|
|
sig = [self methodSignatureForSelector: sel];
|
|
|
|
}
|
|
|
|
num_arg = [sig numberOfArguments] - 2;
|
|
|
|
|
|
|
|
// prolog
|
|
|
|
MonoObject *mthis = NULL;
|
|
|
|
MethodDescription desc;
|
2016-06-02 13:18:45 +03:00
|
|
|
MonoMethod *method;
|
|
|
|
MonoMethodSignature *msig;
|
|
|
|
int semantic;
|
|
|
|
bool isCategoryInstance;
|
2016-04-21 15:19:32 +03:00
|
|
|
|
|
|
|
// setup callstack
|
2016-06-02 13:18:45 +03:00
|
|
|
int frame_length;
|
|
|
|
void **arg_frame;
|
|
|
|
void **arg_ptrs;
|
2016-04-21 15:19:32 +03:00
|
|
|
void *iter = NULL;
|
|
|
|
gboolean needs_writeback = FALSE;
|
|
|
|
MonoType *p;
|
|
|
|
int ofs;
|
|
|
|
int i;
|
|
|
|
int mofs = 0;
|
|
|
|
|
2016-09-30 22:02:17 +03:00
|
|
|
if (is_ctor || is_static) {
|
2016-06-02 13:18:45 +03:00
|
|
|
desc = xamarin_get_method_for_selector ([self class], sel, &exception_gchandle);
|
|
|
|
} else {
|
|
|
|
desc = xamarin_get_method_and_object_for_selector ([self class], sel, self, &mthis, &exception_gchandle);
|
|
|
|
}
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
|
|
|
|
|
|
|
method = xamarin_get_reflection_method_method (desc.method);
|
|
|
|
msig = mono_method_signature (method);
|
|
|
|
semantic = desc.semantic & ArgumentSemanticMask;
|
|
|
|
isCategoryInstance = (desc.semantic & ArgumentSemanticCategoryInstance) == ArgumentSemanticCategoryInstance;
|
|
|
|
|
|
|
|
frame_length = [sig frameLength] - (sizeof (void *) * (isCategoryInstance ? 1 : 2));
|
|
|
|
arg_frame = (void **) alloca (frame_length);
|
|
|
|
arg_ptrs = (void **) alloca (sizeof (void *) * (num_arg + (isCategoryInstance ? 1 : 0)));
|
|
|
|
|
2016-04-21 15:19:32 +03:00
|
|
|
#ifdef TRACE
|
|
|
|
memset (arg_ptrs, 0xDEADF00D, num_arg * sizeof (void*));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (isCategoryInstance) {
|
|
|
|
// we know this must be an id
|
|
|
|
p = mono_signature_get_params (msig, &iter);
|
2016-06-02 13:18:45 +03:00
|
|
|
arg_ptrs [0] = xamarin_get_nsobject_with_type_for_ptr (self, false, p, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
mofs = 1;
|
|
|
|
}
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorStart, context, NULL, 0, NULL, &exception_gchandle); // start
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
|
|
|
|
for (i = 0, ofs = 0; i < num_arg; i++) {
|
|
|
|
const char *type = xamarin_skip_encoding_flags ([sig getArgumentTypeAtIndex: (i+2)]);
|
|
|
|
int size = xamarin_objc_type_size (type);
|
|
|
|
int frameofs = ofs;
|
|
|
|
p = mono_signature_get_params (msig, &iter);
|
|
|
|
|
|
|
|
#if __SIZEOF_POINTER__ == 4
|
|
|
|
if (*type == 'i' || *type == 'I') {
|
|
|
|
// this might be a [Native] enum, in which case managed code expects a 64-bit value.
|
|
|
|
|
|
|
|
MonoClass *p_klass = mono_class_from_mono_type (p);
|
|
|
|
if (mono_class_is_enum (p_klass) && mono_class_value_size (p_klass, NULL) == 8) {
|
|
|
|
// Don't bother checking for the attribute (it's quite expensive),
|
|
|
|
// just check whether managed code expects a 64-bit value and assume
|
|
|
|
// we end up in this condition because it's a [Native] enum.
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorIterate, context, type, size, &arg_frame [ofs++], &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
arg_frame [ofs++] = 0;
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (size > sizeof (void *)) {
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorIterate, context, type, size, &arg_frame [ofs], &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
ofs += size / sizeof (void *);
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
} else {
|
|
|
|
void *arg;
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorIterate, context, type, size, &arg, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
switch (type [0]) {
|
|
|
|
case _C_PTR: {
|
|
|
|
switch (type [1]) {
|
|
|
|
case _C_ID: {
|
|
|
|
MonoClass *p_klass = mono_class_from_mono_type (p);
|
2016-06-02 13:18:45 +03:00
|
|
|
if (!mono_type_is_byref (p)) {
|
|
|
|
exception = (MonoObject *) mono_get_exception_execution_engine ("Invalid type encoding for parameter");
|
|
|
|
goto exception_handling;
|
|
|
|
}
|
|
|
|
bool is_parameter_out = xamarin_is_parameter_out (mono_method_get_object (mono_domain_get (), method, NULL), i, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
|
|
|
if (is_parameter_out) {
|
2016-04-21 15:19:32 +03:00
|
|
|
arg_frame [ofs] = NULL;
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
needs_writeback = TRUE;
|
|
|
|
LOGZ (" argument %i is an out parameter. Passing in a pointer to a NULL value.\n", i + 1);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (xamarin_is_class_nsobject (p_klass)) {
|
|
|
|
MonoObject *obj;
|
|
|
|
NSObject *targ = *(NSObject **) arg;
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
obj = xamarin_get_nsobject_with_type_for_ptr (targ, false, p, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
#if DEBUG
|
|
|
|
xamarin_verify_parameter (obj, sel, self, targ, i, p_klass, method);
|
|
|
|
#endif
|
|
|
|
arg_frame [ofs] = obj;
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
LOGZ (" argument %i is a ref NSObject parameter: %p = %p\n", i + 1, arg, obj);
|
|
|
|
needs_writeback = TRUE;
|
|
|
|
} else {
|
2016-06-02 13:18:45 +03:00
|
|
|
exception = (MonoObject *) mono_get_exception_execution_engine ("Unable to marshal byref parameter type");
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case _C_PTR: {
|
|
|
|
if (mono_type_is_byref (p)) {
|
|
|
|
arg_ptrs [i + mofs] = arg;
|
|
|
|
} else {
|
|
|
|
arg_frame [ofs] = arg;
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
MonoClass *p_klass = mono_class_from_mono_type (p);
|
|
|
|
if (mono_class_is_delegate (p_klass)) {
|
2016-06-02 13:18:45 +03:00
|
|
|
arg_ptrs [i + mofs] = xamarin_get_delegate_for_block_parameter (method, i, arg, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
} else if (xamarin_is_class_inativeobject (p_klass)) {
|
|
|
|
id id_arg = (id) arg;
|
|
|
|
if (semantic == ArgumentSemanticCopy) {
|
|
|
|
id_arg = [id_arg copy];
|
|
|
|
[id_arg autorelease];
|
|
|
|
}
|
|
|
|
MonoObject *obj;
|
2016-06-02 13:18:45 +03:00
|
|
|
obj = xamarin_get_inative_object_dynamic (id_arg, false, mono_type_get_object (mono_domain_get (), p), &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
LOGZ (" argument %i is ptr/INativeObject %p: %p\n", i + 1, id_arg, obj);
|
|
|
|
arg_ptrs [i + mofs] = obj;
|
|
|
|
} else {
|
|
|
|
arg_frame [ofs] = arg;
|
|
|
|
if (mono_type_is_byref (p)) {
|
|
|
|
arg_ptrs [i + mofs] = arg;
|
|
|
|
} else if (mono_class_is_valuetype (p_klass)) {
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
} else {
|
|
|
|
arg_ptrs [i + mofs] = arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case _C_CLASS: {
|
|
|
|
if (!arg) {
|
|
|
|
arg_ptrs [i + mofs] = NULL;
|
|
|
|
LOGZ (" argument %i is Class: NULL\n", i + 1);
|
|
|
|
break;
|
|
|
|
} else {
|
2016-06-02 13:18:45 +03:00
|
|
|
arg_ptrs [i + mofs] = (void *) xamarin_get_class ((Class) arg, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
LOGZ (" argument %i is Class: %p = %s\n", i + 1, arg, class_getName ((Class) arg));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case _C_SEL: {
|
|
|
|
if (!arg) {
|
|
|
|
arg_ptrs [i + mofs] = NULL;
|
|
|
|
LOGZ (" argument %i is SEL: NULL\n", i + 1);
|
|
|
|
break;
|
|
|
|
} else {
|
2016-06-02 13:18:45 +03:00
|
|
|
arg_ptrs [i + mofs] = (void *) xamarin_get_selector ((SEL) arg, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
LOGZ (" argument %i is SEL: %p = %s\n", i + 1, arg, sel_getName ((SEL) arg));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case _C_CHARPTR: {
|
|
|
|
if (!arg) {
|
|
|
|
arg_ptrs [i + mofs] = NULL;
|
|
|
|
LOGZ (" argument %i is char*: NULL\n", i + 1);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
arg_ptrs [i + mofs] = (void *) mono_string_new (mono_domain_get (), (const char *) arg);
|
|
|
|
LOGZ (" argument %i is char*: %p = %s\n", i + 1, arg, arg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case _C_ID: {
|
|
|
|
id id_arg = (id) arg;
|
2016-05-31 12:58:27 +03:00
|
|
|
MonoClass *p_klass = mono_class_from_mono_type (p);
|
|
|
|
if (p_klass == mono_get_intptr_class ()) {
|
|
|
|
arg_frame [ofs] = id_arg;
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
LOGZ (" argument %i is IntPtr: %p\n", i + 1, id_arg);
|
|
|
|
break;
|
|
|
|
} else if (!id_arg) {
|
2016-04-21 15:19:32 +03:00
|
|
|
arg_ptrs [i + mofs] = NULL;
|
|
|
|
break;
|
|
|
|
} else {
|
2016-05-31 12:58:27 +03:00
|
|
|
if (p_klass == mono_get_string_class ()) {
|
2016-04-21 15:19:32 +03:00
|
|
|
NSString *str = (NSString *) id_arg;
|
|
|
|
arg_ptrs [i + mofs] = mono_string_new (mono_domain_get (), [str UTF8String]);
|
|
|
|
LOGZ (" argument %i is NSString: %p = %s\n", i + 1, id_arg, [str UTF8String]);
|
|
|
|
} else if (xamarin_is_class_array (p_klass)) {
|
|
|
|
#if DEBUG
|
|
|
|
xamarin_check_objc_type (id_arg, [NSArray class], sel, self, i, method);
|
|
|
|
#endif
|
|
|
|
NSArray *arr = (NSArray *) id_arg;
|
|
|
|
MonoClass *e_klass = mono_class_get_element_class (p_klass);
|
|
|
|
MonoType *e = mono_class_get_type (e_klass);
|
|
|
|
MonoArray *m_arr = mono_array_new (mono_domain_get (), e_klass, [arr count]);
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j = 0; j < [arr count]; j++) {
|
|
|
|
if (e_klass == mono_get_string_class ()) {
|
|
|
|
NSString *sv = (NSString *) [arr objectAtIndex: j];
|
|
|
|
mono_array_set (m_arr, MonoString *, j, mono_string_new (mono_domain_get (), [sv UTF8String]));
|
|
|
|
} else {
|
|
|
|
MonoObject *obj;
|
|
|
|
id targ = [arr objectAtIndex: j];
|
2016-06-02 13:18:45 +03:00
|
|
|
obj = xamarin_get_nsobject_with_type_for_ptr (targ, false, e, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
#if DEBUG
|
|
|
|
xamarin_verify_parameter (obj, sel, self, targ, i, e_klass, method);
|
|
|
|
#endif
|
|
|
|
mono_array_set (m_arr, MonoObject *, j, obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LOGZ (" argument %i is NSArray\n", i + 1);
|
|
|
|
arg_ptrs [i + mofs] = m_arr;
|
|
|
|
} else if (xamarin_is_class_nsobject (p_klass)) {
|
|
|
|
if (semantic == ArgumentSemanticCopy) {
|
|
|
|
id_arg = [id_arg copy];
|
|
|
|
[id_arg autorelease];
|
|
|
|
}
|
|
|
|
MonoObject *obj;
|
|
|
|
int32_t created = false;
|
2016-06-02 13:18:45 +03:00
|
|
|
obj = xamarin_get_nsobject_with_type_for_ptr_created (id_arg, false, p, &created, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
|
|
|
|
if (created && obj) {
|
2016-06-02 13:18:45 +03:00
|
|
|
bool is_transient = xamarin_is_parameter_transient (mono_method_get_object (mono_domain_get (), method, NULL), i, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
if (is_transient)
|
|
|
|
dispose_list = s_list_prepend (dispose_list, obj);
|
|
|
|
}
|
|
|
|
#if DEBUG
|
|
|
|
xamarin_verify_parameter (obj, sel, self, id_arg, i, p_klass, method);
|
|
|
|
#endif
|
|
|
|
LOGZ (" argument %i is NSObject %p: %p\n", i + 1, id_arg, obj);
|
|
|
|
arg_ptrs [i + mofs] = obj;
|
|
|
|
} else if (xamarin_is_class_inativeobject (p_klass)) {
|
|
|
|
if (semantic == ArgumentSemanticCopy) {
|
|
|
|
id_arg = [id_arg copy];
|
|
|
|
[id_arg autorelease];
|
|
|
|
}
|
|
|
|
MonoObject *obj;
|
2016-06-02 13:18:45 +03:00
|
|
|
obj = xamarin_get_inative_object_dynamic (id_arg, false, mono_type_get_object (mono_domain_get (), p), &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
LOGZ (" argument %i is NSObject/INativeObject %p: %p\n", i + 1, id_arg, obj);
|
|
|
|
arg_ptrs [i + mofs] = obj;
|
|
|
|
} else if (mono_class_is_delegate (p_klass)) {
|
2016-06-02 13:18:45 +03:00
|
|
|
arg_ptrs [i + mofs] = xamarin_get_delegate_for_block_parameter (method, i, id_arg, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
} else {
|
|
|
|
if (semantic == ArgumentSemanticCopy) {
|
|
|
|
id_arg = [id_arg copy];
|
|
|
|
[id_arg autorelease];
|
|
|
|
}
|
|
|
|
MonoObject *obj;
|
2016-06-02 13:18:45 +03:00
|
|
|
obj = xamarin_get_nsobject_with_type_for_ptr (id_arg, false, p, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
#if DEBUG
|
|
|
|
xamarin_verify_parameter (obj, sel, self, id_arg, i, p_klass, method);
|
|
|
|
#endif
|
|
|
|
arg_ptrs [i + mofs] = obj;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
arg_frame [ofs] = arg;
|
|
|
|
arg_ptrs [i + mofs] = &arg_frame [frameofs];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ofs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorEnd, context, NULL, 0, NULL, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
|
|
|
|
// invoke
|
|
|
|
MonoObject *retval;
|
|
|
|
if (is_ctor) {
|
|
|
|
/*
|
|
|
|
* Some Objective-C classes overwrite retain, release,
|
|
|
|
* retainCount and those methods are not operational
|
|
|
|
* until one of the init methods has been called
|
|
|
|
* (CALayer for example). This means that the standard
|
|
|
|
* code path that we have to Retain in NSObject does not
|
|
|
|
* work for objects surfaced through xamarin_ctor_trampoline.
|
|
|
|
*
|
|
|
|
* To work around this, we will perform the retain here, after
|
|
|
|
* managed code has initialized the NSObject. To let managed
|
|
|
|
* code know to not invoke the Retain in InitializeObject we set
|
|
|
|
* the NativeRef flag on the object.
|
|
|
|
*
|
|
|
|
* This is checked by NSObject.InitializeObject and it
|
|
|
|
* instruct the method to not attempt to call `retain'
|
|
|
|
* on the object
|
|
|
|
*
|
|
|
|
* Instead, when surfacing objects by
|
|
|
|
* xamarin_ctor_trampoline, we perform the retain on
|
|
|
|
* behalf of managed code here (managed code owns one
|
|
|
|
* reference, and unmanaged code the other).
|
|
|
|
*
|
|
|
|
* This problem is documented in the following bug:
|
|
|
|
* https://bugzilla.xamarin.com/show_bug.cgi?id=6556
|
|
|
|
*/
|
|
|
|
retval = mono_object_new (mono_domain_get (), mono_method_get_class (method));
|
|
|
|
|
|
|
|
xamarin_set_nsobject_handle (retval, self);
|
|
|
|
xamarin_set_nsobject_flags (retval, NSObjectFlagsNativeRef);
|
2016-05-11 14:27:51 +03:00
|
|
|
mono_runtime_invoke (method, retval, (void **) arg_ptrs, exception_ptr);
|
2016-06-02 13:18:45 +03:00
|
|
|
if (exception != NULL)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
xamarin_create_managed_ref (self, retval, true);
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
xamarin_register_nsobject (retval, self, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
} else {
|
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
fprintf (stderr, " calling managed method with %i arguments: ", num_arg);
|
|
|
|
for (int i = 0; i < num_arg; i++)
|
|
|
|
fprintf (stderr, "%p ", arg_ptrs [i]);
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
#endif
|
|
|
|
|
2016-05-11 14:27:51 +03:00
|
|
|
retval = mono_runtime_invoke (method, mthis, (void **) arg_ptrs, exception_ptr);
|
2016-04-21 15:19:32 +03:00
|
|
|
|
|
|
|
#ifdef TRACE
|
|
|
|
fprintf (stderr, " called managed method with %i arguments: ", num_arg);
|
|
|
|
for (int i = 0; i < num_arg; i++)
|
|
|
|
fprintf (stderr, "%p ", arg_ptrs [i]);
|
|
|
|
fprintf (stderr, "\n");
|
|
|
|
#endif
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
if (exception != NULL)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// writeback
|
|
|
|
if (needs_writeback) {
|
|
|
|
iter = NULL;
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorStart, context, NULL, 0, NULL, &exception_gchandle); // start
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
for (i = 0, ofs = 0; i < num_arg; i++) {
|
|
|
|
const char *type = [sig getArgumentTypeAtIndex: (i+2)];
|
|
|
|
int size = xamarin_objc_type_size (type);
|
|
|
|
|
|
|
|
p = mono_signature_get_params (msig, &iter);
|
|
|
|
|
|
|
|
if (size > sizeof (void *)) {
|
|
|
|
// Skip over any structs. In any case they can't be write-back parameters.
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorIterate, context, type, size, NULL, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
ofs += size / sizeof (void *);
|
|
|
|
} else {
|
|
|
|
void *arg;
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorIterate, context, type, size, &arg, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
if (type [0] == _C_PTR && type [1] == _C_ID) {
|
|
|
|
MonoClass *p_klass = mono_class_from_mono_type (p);
|
|
|
|
|
|
|
|
if (p_klass == mono_get_string_class ()) {
|
|
|
|
MonoString *value = (MonoString *) arg_frame [ofs];
|
|
|
|
if (value == NULL) {
|
|
|
|
*(NSObject **) arg = NULL;
|
|
|
|
LOGZ (" writing back managed null string to argument at %p\n", arg);
|
|
|
|
} else {
|
|
|
|
char *str = mono_string_to_utf8 (value);
|
|
|
|
*(NSObject **) arg = [[[NSString alloc] initWithUTF8String:str] autorelease];
|
|
|
|
LOGZ (" writing back managed string %p = %s to argument at %p\n", *(NSObject **) arg, str, arg);
|
|
|
|
mono_free (str);
|
|
|
|
}
|
|
|
|
} else if (xamarin_is_class_nsobject (p_klass)) {
|
2016-06-02 13:18:45 +03:00
|
|
|
*(NSObject **) arg = xamarin_get_handle ((MonoObject *) arg_frame [ofs], &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
LOGZ (" writing back managed NSObject %p to argument at %p\n", *(NSObject **) arg, arg);
|
|
|
|
} else if (xamarin_is_class_inativeobject (p_klass)) {
|
2016-06-02 13:18:45 +03:00
|
|
|
*(NSObject **) arg = xamarin_get_handle ((MonoObject *) arg_frame [ofs], &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
LOGZ (" writing back managed INativeObject %p to argument at %p\n", *(NSObject **) arg, arg);
|
|
|
|
} else {
|
2016-06-02 13:18:45 +03:00
|
|
|
char *to_name = xamarin_type_get_full_name (p, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
char *method_full_name = mono_method_full_name (method, TRUE);
|
|
|
|
char *msg = xamarin_strdup_printf ("Unable to marshal the out/ref parameter #%i whose managed type is '%s' to Objective-C.\n"
|
|
|
|
"Additional information:\n"
|
|
|
|
"\tSelector: %s\n"
|
|
|
|
"\tMethod: %s\n", i + 1, to_name, sel_getName (sel), method_full_name);
|
|
|
|
MonoException *exc = xamarin_create_exception (msg);
|
|
|
|
xamarin_free (msg);
|
|
|
|
xamarin_free (to_name);
|
|
|
|
xamarin_free (method_full_name);
|
2016-06-02 13:18:45 +03:00
|
|
|
exception = (MonoObject *) exc;
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ofs++;
|
|
|
|
}
|
|
|
|
}
|
2016-06-02 13:18:45 +03:00
|
|
|
iterator (IteratorEnd, context, NULL, 0, NULL, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dispose_list) {
|
|
|
|
SList *list = dispose_list;
|
|
|
|
while (list) {
|
2016-06-02 13:18:45 +03:00
|
|
|
xamarin_dispose ((MonoObject *) list->data, &exception_gchandle);
|
|
|
|
if (exception_gchandle != 0)
|
|
|
|
goto exception_handling;
|
2016-04-21 15:19:32 +03:00
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
s_list_free (dispose_list);
|
|
|
|
}
|
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
ret_type = [sig methodReturnType];
|
2016-04-21 15:19:32 +03:00
|
|
|
ret_type = xamarin_skip_encoding_flags (ret_type);
|
|
|
|
if (is_ctor) {
|
2016-06-02 13:18:45 +03:00
|
|
|
marshal_return_value (context, "|", sizeof (id), self, mono_signature_get_return_type (msig), (desc.semantic & ArgumentSemanticRetainReturnValue) != 0, method, &exception_gchandle);
|
2016-04-21 15:19:32 +03:00
|
|
|
} else if (*ret_type != 'v') {
|
2016-06-02 13:18:45 +03:00
|
|
|
marshal_return_value (context, ret_type, [sig methodReturnLength], retval, mono_signature_get_return_type (msig), (desc.semantic & ArgumentSemanticRetainReturnValue) != 0, method, &exception_gchandle);
|
2016-04-21 15:19:32 +03:00
|
|
|
}
|
2016-05-11 14:27:51 +03:00
|
|
|
|
2016-06-02 13:18:45 +03:00
|
|
|
exception_handling:
|
|
|
|
;
|
2016-05-16 20:31:56 +03:00
|
|
|
|
|
|
|
MONO_THREAD_DETACH; // COOP: This will switch to GC_SAFE
|
2016-06-02 13:18:45 +03:00
|
|
|
|
|
|
|
if (exception_gchandle != 0) {
|
|
|
|
xamarin_process_managed_exception_gchandle (exception_gchandle);
|
|
|
|
} else {
|
|
|
|
xamarin_process_managed_exception (exception);
|
|
|
|
}
|
2016-05-11 14:27:51 +03:00
|
|
|
}
|