xamarin-macios/runtime/trampolines-invoke.m

677 строки
25 KiB
Mathematica
Исходник Обычный вид История

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"
#include "product.h"
2016-04-21 15:19:32 +03:00
//#define TRACE
#ifdef TRACE
#define LOGZ(...) fprintf (stderr, __VA_ARGS__);
#else
#define LOGZ(...)
#endif
static guint32
xamarin_get_exception_for_method (int code, guint32 inner_exception_gchandle, const char *reason, SEL sel, id self)
{
guint32 exception_gchandle = 0;
char *msg = xamarin_strdup_printf ("%s\n"
"Additional information:\n"
"\tSelector: %s\n"
"\tType: %s\n", reason, sel_getName (sel), class_getName ([self class]));
exception_gchandle = xamarin_create_product_exception_with_inner_exception (code, inner_exception_gchandle, msg);
xamarin_free (msg);
return exception_gchandle;
}
guint32
xamarin_get_exception_for_parameter (int code, guint32 inner_exception_gchandle, const char *reason, SEL sel, MonoMethod *method, MonoType *p, int i, bool to_managed)
{
guint32 exception_gchandle = 0;
char *to_name = xamarin_type_get_full_name (p, &exception_gchandle);
if (exception_gchandle != 0)
return exception_gchandle;
char *method_full_name = mono_method_full_name (method, TRUE);
char *msg = xamarin_strdup_printf ("%s #%i whose managed type is '%s' %s.\n"
"Additional information:\n"
"\tSelector: %s\n"
"\tMethod: %s\n", reason, i + 1, to_name, to_managed ? "to managed" : "to Objective-C", sel_getName (sel), method_full_name);
exception_gchandle = xamarin_create_product_exception_with_inner_exception (code, inner_exception_gchandle, msg);
xamarin_free (msg);
xamarin_free (to_name);
xamarin_free (method_full_name);
return exception_gchandle;
}
NSString *
xamarin_string_to_nsstring (MonoString *obj, bool retain)
{
if (obj == NULL)
return NULL;
char *str = mono_string_to_utf8 ((MonoString *) obj);
NSString *arg;
if (retain) {
arg = [[NSString alloc] initWithUTF8String:str];
} else {
arg = [NSString stringWithUTF8String:str];
}
mono_free (str);
return arg;
}
MonoString *
xamarin_nsstring_to_string (MonoDomain *domain, NSString *obj)
{
if (obj == NULL)
return NULL;
if (domain == NULL)
domain = mono_domain_get ();
return mono_string_new (domain, [obj UTF8String]);
}
2016-04-21 15:19:32 +03:00
void
xamarin_invoke_trampoline (enum TrampolineType type, id self, SEL sel, iterator_func iterator, marshal_return_value_func marshal_return_value, void *context)
{
// 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).
MONO_ASSERT_GC_SAFE_OR_DETACHED;
MonoObject *exception = NULL;
MonoObject **exception_ptr = xamarin_is_managed_exception_marshaling_disabled () ? NULL : &exception;
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;
const char *ret_type = NULL;
2016-04-21 15:19:32 +03:00
if (is_ctor) {
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);
marshal_return_value (context, "|", sizeof (id), self, NULL, false, NULL, NULL, &exception_gchandle);
xamarin_process_managed_exception_gchandle (exception_gchandle);
2016-04-21 15:19:32 +03:00
return;
}
}
MONO_THREAD_ATTACH; // COOP: This will swith to GC_UNSAFE
MonoDomain *domain = mono_domain_get ();
2016-04-21 15:19:32 +03:00
// pre-prolog
SList *dispose_list = NULL;
SList *free_list = NULL;
2016-04-21 15:19:32 +03:00
int num_arg;
int managed_arg_count;
2016-04-21 15:19:32 +03:00
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 = NULL;
MonoMethod *method;
MonoMethodSignature *msig;
int semantic;
bool isCategoryInstance;
2016-04-21 15:19:32 +03:00
// setup callstack
int frame_length;
void **arg_frame;
void **arg_ptrs;
void **arg_copy = NULL; // used to detect if ref/out parameters were changed.
bool *writeback = NULL; // used to detect if a particular parameter is ref/out parameter.
2016-04-21 15:19:32 +03:00
void *iter = NULL;
gboolean needs_writeback = FALSE; // determines if there are any ref/out parameters.
2016-04-21 15:19:32 +03:00
MonoType *p;
int ofs;
int i;
int mofs = 0;
int desc_arg_count = num_arg + 2; /* 1 for the return value + 1 if this is a category instance method */
size_t desc_size = desc_arg_count * sizeof (BindAsData) + sizeof (MethodDescription);
desc = (MethodDescription *) xamarin_calloc (desc_size);
desc->bindas_count = desc_arg_count;
free_list = s_list_prepend (free_list, desc);
if (is_ctor || is_static) {
xamarin_get_method_for_selector ([self class], sel, is_static, desc, &exception_gchandle);
} else {
xamarin_get_method_and_object_for_selector ([self class], sel, is_static, self, &mthis, desc, &exception_gchandle);
}
if (exception_gchandle != 0) {
exception_gchandle = xamarin_get_exception_for_method (8034, exception_gchandle, "Failed to lookup the required marshalling information.", sel, self);
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);
managed_arg_count = num_arg + (isCategoryInstance ? 1 : 0);
arg_ptrs = (void **) alloca (sizeof (void *) * managed_arg_count);
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);
arg_ptrs [0] = xamarin_get_nsobject_with_type_for_ptr (self, false, p, &exception_gchandle);
if (exception_gchandle != 0) {
exception_gchandle = xamarin_get_exception_for_parameter (8029, exception_gchandle, "Unable to marshal the parameter", sel, method, p, 0, true);
goto exception_handling;
}
2016-04-21 15:19:32 +03:00
mofs = 1;
}
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.
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 *)) {
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;
iterator (IteratorIterate, context, type, size, &arg, &exception_gchandle);
if (exception_gchandle != 0)
goto exception_handling;
if (desc->bindas [i + 1].original_type != NULL) {
arg_ptrs [i + mofs] = xamarin_generate_conversion_to_managed ((id) arg, mono_reflection_type_get_type (desc->bindas [i + 1].original_type), p, method, &exception_gchandle, (void *) INVALID_TOKEN_REF, (void **) &free_list);
if (exception_gchandle != 0)
goto exception_handling;
ofs++;
continue;
}
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);
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 (domain, method, NULL), i, &exception_gchandle);
if (exception_gchandle != 0)
goto exception_handling;
if (!needs_writeback) {
2016-04-21 15:19:32 +03:00
needs_writeback = TRUE;
arg_copy = (void **) calloc (managed_arg_count, sizeof (void *));
writeback = (bool *) calloc (managed_arg_count, sizeof (bool));
}
arg_frame [ofs] = NULL;
arg_ptrs [i + mofs] = &arg_frame [frameofs];
writeback [i + mofs] = TRUE;
if (is_parameter_out) {
2016-04-21 15:19:32 +03:00
LOGZ (" argument %i is an out parameter. Passing in a pointer to a NULL value.\n", i + 1);
if (arg != NULL) {
// Write NULL to the argument we got right away. Managed code might not write to it (or write NULL),
// in which case our code to detect if the value changed will say it didn't and not copy it back.
*(NSObject **) arg = NULL;
}
} else if (xamarin_is_class_nsobject (p_klass)) {
MonoObject *obj;
NSObject *targ = *(NSObject **) arg;
2016-04-21 15:19:32 +03:00
obj = xamarin_get_nsobject_with_type_for_ptr (targ, false, p, &exception_gchandle);
if (exception_gchandle != 0) {
exception_gchandle = xamarin_get_exception_for_parameter (8029, exception_gchandle, "Unable to marshal the byref parameter", sel, method, p, i, true);
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;
LOGZ (" argument %i is a ref NSObject parameter: %p = %p\n", i + 1, arg, obj);
} else {
exception_gchandle = xamarin_get_exception_for_parameter (8029, 0, "Unable to marshal the byref parameter", sel, method, p, i, true);
goto exception_handling;
2016-04-21 15:19:32 +03:00
}
arg_copy [i + mofs] = arg_frame [ofs];
LOGZ (" argument %i's value: %p\n", i + 1, arg_copy [i + mofs]);
break;
2016-04-21 15:19:32 +03:00
}
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)) {
arg_ptrs [i + mofs] = xamarin_get_delegate_for_block_parameter (method, INVALID_TOKEN_REF, 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;
obj = xamarin_get_inative_object_dynamic (id_arg, false, mono_type_get_object (domain, 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 {
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 {
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 (domain, (const char *) arg);
2016-04-21 15:19:32 +03:00
LOGZ (" argument %i is char*: %p = %s\n", i + 1, arg, arg);
break;
}
}
case _C_ID: {
id id_arg = (id) arg;
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 {
if (p_klass == mono_get_string_class ()) {
2016-04-21 15:19:32 +03:00
NSString *str = (NSString *) id_arg;
arg_ptrs [i + mofs] = xamarin_nsstring_to_string (domain, str);
2016-04-21 15:19:32 +03:00
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 (domain, e_klass, [arr count]);
2016-04-21 15:19:32 +03:00
int j;
for (j = 0; j < [arr count]; j++) {
if (e_klass == mono_get_string_class ()) {
NSString *sv = (NSString *) [arr objectAtIndex: j];
mono_array_setref (m_arr, j, xamarin_nsstring_to_string (domain, sv));
2016-04-21 15:19:32 +03:00
} else {
MonoObject *obj;
id targ = [arr objectAtIndex: j];
obj = xamarin_get_nsobject_with_type_for_ptr (targ, false, e, &exception_gchandle);
if (exception_gchandle != 0) {
exception_gchandle = xamarin_get_exception_for_parameter (8029, exception_gchandle, "Unable to marshal the array parameter", sel, method, p, i, true);
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_setref (m_arr, j, obj);
2016-04-21 15:19:32 +03:00
}
}
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;
obj = xamarin_get_nsobject_with_type_for_ptr_created (id_arg, false, p, &created, &exception_gchandle);
if (exception_gchandle != 0) {
exception_gchandle = xamarin_get_exception_for_parameter (8029, exception_gchandle, "Unable to marshal the parameter", sel, method, p, i, true);
goto exception_handling;
}
2016-04-21 15:19:32 +03:00
if (created && obj) {
bool is_transient = xamarin_is_parameter_transient (mono_method_get_object (domain, 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;
obj = xamarin_get_inative_object_dynamic (id_arg, false, mono_type_get_object (domain, 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)) {
arg_ptrs [i + mofs] = xamarin_get_delegate_for_block_parameter (method, INVALID_TOKEN_REF, 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;
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++;
}
}
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 (domain, mono_method_get_class (method));
2016-04-21 15:19:32 +03:00
xamarin_set_nsobject_handle (retval, self);
xamarin_set_nsobject_flags (retval, NSObjectFlagsNativeRef);
mono_runtime_invoke (method, retval, (void **) arg_ptrs, exception_ptr);
if (exception != NULL)
goto exception_handling;
2016-04-21 15:19:32 +03:00
xamarin_create_managed_ref (self, retval, true);
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, " writeback: %i", needs_writeback);
2016-04-21 15:19:32 +03:00
fprintf (stderr, "\n");
#endif
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, " writeback: %i", needs_writeback);
2016-04-21 15:19:32 +03:00
fprintf (stderr, "\n");
#endif
if (exception != NULL)
goto exception_handling;
2016-04-21 15:19:32 +03:00
}
// writeback
if (needs_writeback) {
iter = NULL;
iterator (IteratorStart, context, NULL, 0, NULL, &exception_gchandle); // start
if (exception_gchandle != 0)
goto exception_handling;
for (i = 0; i < num_arg; i++) {
2016-04-21 15:19:32 +03:00
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 *) || !writeback [i + mofs]) {
2016-04-21 15:19:32 +03:00
// Skip over any structs. In any case they can't be write-back parameters.
// Also skip over any arguments we aren't supposed to write back to.
iterator (IteratorIterate, context, type, size, NULL, &exception_gchandle);
if (exception_gchandle != 0)
goto exception_handling;
2016-04-21 15:19:32 +03:00
} else {
void *arg;
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);
MonoObject *value = *(MonoObject **) arg_ptrs [i + mofs];
MonoObject *pvalue = (MonoObject *) arg_copy [i + mofs];
NSObject *obj = NULL;
2016-04-21 15:19:32 +03:00
if (value == pvalue) {
// No need to copy back if the value didn't change
LOGZ (" not writing back managed object to argument at index %i (%p => %p) because it didn't change\n", i, arg, value);
continue;
} else if (arg == NULL) {
LOGZ (" not writing back to a null pointer at index %i\n", i);
continue;
} else if (value == NULL) {
LOGZ (" writing back null to argument at index %i (%p)\n", i + 1, arg);
} else if (p_klass == mono_get_string_class ()) {
obj = xamarin_string_to_nsstring ((MonoString *) value, false);
LOGZ (" writing back managed string %p to argument at index %i (%p)\n", value, i + 1, arg);
2016-04-21 15:19:32 +03:00
} else if (xamarin_is_class_nsobject (p_klass)) {
obj = xamarin_get_handle (value, &exception_gchandle);
if (exception_gchandle != 0)
goto exception_handling;
LOGZ (" writing back managed NSObject %p to argument at index %i (%p)\n", value, i + 1, arg);
2016-04-21 15:19:32 +03:00
} else if (xamarin_is_class_inativeobject (p_klass)) {
obj = xamarin_get_handle_for_inativeobject (value, &exception_gchandle);
if (exception_gchandle != 0)
goto exception_handling;
LOGZ (" writing back managed INativeObject %p to argument at index %i (%p)\n", value, i + 1, arg);
2016-04-21 15:19:32 +03:00
} else {
exception_gchandle = xamarin_get_exception_for_parameter (8030, 0, "Unable to marshal the out/ref parameter", sel, method, p, i, false);
goto exception_handling;
2016-04-21 15:19:32 +03:00
}
*(NSObject **) arg = obj;
2016-04-21 15:19:32 +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
}
ret_type = [sig methodReturnType];
2016-04-21 15:19:32 +03:00
ret_type = xamarin_skip_encoding_flags (ret_type);
if (is_ctor) {
marshal_return_value (context, "|", sizeof (id), self, mono_signature_get_return_type (msig), (desc->semantic & ArgumentSemanticRetainReturnValue) != 0, method, desc, &exception_gchandle);
2016-04-21 15:19:32 +03:00
} else if (*ret_type != 'v') {
marshal_return_value (context, ret_type, [sig methodReturnLength], retval, mono_signature_get_return_type (msig), (desc->semantic & ArgumentSemanticRetainReturnValue) != 0, method, desc, &exception_gchandle);
2016-04-21 15:19:32 +03:00
}
exception_handling:
;
if (dispose_list) {
SList *list = dispose_list;
while (list) {
guint32 dispose_exception_gchandle = 0;
xamarin_dispose ((MonoObject *) list->data, &dispose_exception_gchandle);
if (dispose_exception_gchandle != 0) {
if (exception_gchandle == 0) {
// If we get an exception while disposing, and we don't already have an exception, then we need to throw the dispose exception (later, when done disposing)
exception_gchandle = dispose_exception_gchandle;
} else {
// If we already have an exception, don't overwrite it with an exception from disposing something.
// However we don't want to silently ignore it, so print it.
NSLog (@PRODUCT ": An exception occurred while disposing the object %p:", list->data);
NSLog (@"%@", xamarin_print_all_exceptions (mono_gchandle_get_target (dispose_exception_gchandle)));
}
}
list = list->next;
}
s_list_free (dispose_list);
}
if (free_list) {
SList *list = free_list;
while (list) {
xamarin_free (list->data);
list = list->next;
}
s_list_free (free_list);
}
if (arg_copy != NULL) {
free (arg_copy);
arg_copy = NULL;
}
if (writeback) {
free (writeback);
writeback = NULL;
}
MONO_THREAD_DETACH; // COOP: This will switch to GC_SAFE
if (exception_gchandle != 0) {
xamarin_process_managed_exception_gchandle (exception_gchandle);
} else {
xamarin_process_managed_exception (exception);
}
}