X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=e6b9b6628bc5326608872431e9d34d2799defef4;hb=1e982a83223207df5929053f4f47f68753f43730;hp=a86b6ba26fbbd708a4990276a69d18cc7da6cef2;hpb=9975a45f43793e34318e593ddacd3f332f8d91c0;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index a86b6ba26fb..e6b9b6628bc 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -154,6 +154,22 @@ mono_marshal_set_last_error_windows (int error); static void mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func); +static void init_safe_handle (void); + +/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */ +static MonoMethod *sh_dangerous_add_ref; +static MonoMethod *sh_dangerous_release; + + +static void +init_safe_handle () +{ + sh_dangerous_add_ref = mono_class_get_method_from_name ( + mono_defaults.safehandle_class, "DangerousAddRef", 1); + sh_dangerous_release = mono_class_get_method_from_name ( + mono_defaults.safehandle_class, "DangerousRelease", 0); +} + static void register_icall (gpointer func, const char *name, const char *sigstr, gboolean save) { @@ -523,7 +539,7 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate) // Add the delegate to the delegate hash table delegate_hash_table_add (delegate); - /* when the object is collected, collect the dunamic method, too */ + /* when the object is collected, collect the dynamic method, too */ mono_object_register_finalizer ((MonoObject*)delegate); return delegate->delegate_trampoline; @@ -708,9 +724,9 @@ mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclas memcpy (native_arr, as, MIN (strlen (as), elnum)); g_free (as); - } - else + } else { g_assert_not_reached (); + } } void @@ -745,6 +761,10 @@ mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text) g_free (ut); } +/* + * FIXME: This routine does not seem to do what it seems to do + * the @text is never copied into the string builder + */ void mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text) { @@ -761,6 +781,16 @@ mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text) sb->length = len; } +/** + * mono_string_builder_to_utf8: + * @sb: the string builder + * + * Converts to utf8 the contents of the MonoStringBuilder. + * + * Returns: a utf8 string with the contents of the StringBuilder. + * + * The return value must be released with g_free. + */ gpointer mono_string_builder_to_utf8 (MonoStringBuilder *sb) { @@ -785,9 +815,9 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb) tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error); if (error) { g_error_free (error); + mono_marshal_free (res); mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8")); - } - else { + } else { memcpy (res, tmp, sb->length + 1); g_free (tmp); } @@ -795,6 +825,16 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb) return res; } +/** + * mono_string_builder_to_utf16: + * @sb: the string builder + * + * Converts to utf16 the contents of the MonoStringBuilder. + * + * Returns: a utf16 string with the contents of the StringBuilder. + * + * The return value must not be freed. + */ gpointer mono_string_builder_to_utf16 (MonoStringBuilder *sb) { @@ -846,10 +886,10 @@ mono_string_to_lpstr (MonoString *s) g_error_free (error); mono_raise_exception(exc); return NULL; - } - else { + } else { as = CoTaskMemAlloc (len + 1); memcpy (as, tmp, len + 1); + g_free (tmp); return as; } #else @@ -872,8 +912,16 @@ mono_string_to_bstr (MonoString *string_obj) return NULL; return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj)); #else - g_error ("UnmanagedMarshal.BStr is not implemented."); - return NULL; + int slen = mono_string_length (string_obj); + char *ret = g_malloc (slen * 2 + 4 + 2); + if (ret == NULL) + return NULL; + memcpy (ret + 4, mono_string_chars (string_obj), slen * 2); + * ((guint32 *) ret) = slen * 2; + ret [4 + slen * 2] = 0; + ret [5 + slen * 2] = 0; + + return ret + 4; #endif } @@ -885,8 +933,7 @@ mono_string_from_bstr (gpointer bstr) return NULL; return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr)); #else - g_error ("UnmanagedMarshal.BStr is not implemented."); - return NULL; + return mono_string_new_utf16 (mono_domain_get (), bstr, *(guint32 *)((char *)bstr - 4)); #endif } @@ -896,10 +943,19 @@ mono_free_bstr (gpointer bstr) #ifdef PLATFORM_WIN32 SysFreeString ((BSTR)bstr); #else - g_error ("Free BSTR is not implemented."); + g_free (((char *)bstr) - 4); #endif } +/** + * mono_string_to_byvalstr: + * @dst: Where to store the null-terminated utf8 decoded string. + * @src: the MonoString to copy. + * @size: the maximum number of bytes to copy. + * + * Copies the MonoString pointed to by @src as a utf8 string + * into @dst, it copies at most @size bytes into the destination. + */ void mono_string_to_byvalstr (gpointer dst, MonoString *src, int size) { @@ -910,18 +966,27 @@ mono_string_to_byvalstr (gpointer dst, MonoString *src, int size) g_assert (size > 0); memset (dst, 0, size); - if (!src) return; s = mono_string_to_utf8 (src); len = MIN (size, strlen (s)); + if (len >= size) + len--; memcpy (dst, s, len); g_free (s); - - *((char *)dst + size - 1) = 0; } +/** + * mono_string_to_byvalwstr: + * @dst: Where to store the null-terminated utf16 decoded string. + * @src: the MonoString to copy. + * @size: the maximum number of bytes to copy. + * + * Copies the MonoString pointed to by @src as a utf16 string into + * @dst, it copies at most @size bytes into the destination (including + * a terminating 16-bit zero terminator). + */ void mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size) { @@ -936,9 +1001,10 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size) } len = MIN (size, (mono_string_length (src))); - memcpy (dst, mono_string_chars (src), len * 2); - - *((gunichar2 *)dst + len - 1) = 0; + memcpy (dst, mono_string_chars (src), size * 2); + if (size <= mono_string_length (src)) + len--; + *((gunichar2 *) dst + len) = 0; } void @@ -1014,6 +1080,7 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in mp = mb->method->klass->image->mempool; + mono_loader_lock (); if (mb->dynamic) { method = mb->method; @@ -1086,6 +1153,7 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos)); #endif + mono_loader_unlock (); return method; } @@ -1793,6 +1861,23 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_short_branch (mb, pos_failed); break; } + + case MONO_MARSHAL_CONV_SAFEHANDLE: { + /* + * Passing SafeHandles as ref does not allow the unmanaged code + * to change the SafeHandle value. If the value is changed, + * we should issue a diagnostic exception (NotSupportedException) + * that informs the user that changes to handles in unmanaged code + * is not supported. + * + * Since we currently have no access to the original + * SafeHandle that was used during the marshalling, + * for now we just ignore this, and ignore/discard any + * changes that might have happened to the handle. + */ + break; + } + case MONO_MARSHAL_CONV_STR_BSTR: case MONO_MARSHAL_CONV_STR_ANSIBSTR: case MONO_MARSHAL_CONV_STR_TBSTR: @@ -2127,6 +2212,44 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_short_branch (mb, pos_failed); break; } + + case MONO_MARSHAL_CONV_SAFEHANDLE: { + int dar_release_slot, pos; + + dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + + /* + * The following is ifdefed-out, because I have no way of doing the + * DangerousRelease when destroying the structure + */ +#if 0 + /* set release = false */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, dar_release_slot); + if (!sh_dangerous_add_ref) + init_safe_handle (); + + /* safehandle.DangerousAddRef (ref release) */ + mono_mb_emit_ldloc (mb, 0); /* the source */ + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldloc_addr (mb, dar_release_slot); + mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL); +#endif + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + mono_mb_patch_branch (mb, pos); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } default: { char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv); MonoException *exc = mono_get_exception_not_implemented (msg); @@ -2186,18 +2309,26 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) usize = info->fields [i + 1].offset - info->fields [i].offset; } - /* - * FIXME: Should really check for usize==0 and msize>0, but we apply - * the layout to the managed structure as well. - */ - if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) { - if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) - g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a reference field at the same offset as another field.", mono_type_full_name (&klass->byval_arg)); + if (klass != mono_defaults.safehandle_class){ + /* + * FIXME: Should really check for usize==0 and msize>0, but we apply + * the layout to the managed structure as well. + */ + + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) { + if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || + ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type)))) + g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a " + "reference field at the same offset as another field.", + mono_type_full_name (&klass->byval_arg)); + } + + if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) + g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", + mono_type_full_name (&klass->byval_arg)); + } - - if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) - g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg)); - + switch (conv) { case MONO_MARSHAL_CONV_NONE: { int t; @@ -2278,6 +2409,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) } else { static MonoMethod *get_native_variant_for_object = NULL; + if (!get_native_variant_for_object) get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2); @@ -2289,7 +2421,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) break; } - default: + default: g_warning ("marshaling type %02x not implemented", ftype->type); g_assert_not_reached (); } @@ -2403,6 +2535,7 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params) msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state); handle = CreateEvent (NULL, TRUE, FALSE, NULL); + g_assert(handle != NULL); ares = mono_async_result_new (mono_domain_get (), handle, state, handle, NULL); MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate); MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback); @@ -2824,6 +2957,12 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params) ares = mono_array_get (msg->args, gpointer, sig->param_count - 1); g_assert (ares); + if (ares->async_delegate != delegate && mono_get_runtime_info ()->framework_version [0] >= '2') { + mono_raise_exception (mono_get_exception_invalid_operation ( + "The IAsyncResult object provided does not match this delegate.")); + return NULL; + } + if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) { MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target; msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); @@ -2831,9 +2970,9 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params) msg->call_type = CallType_EndInvoke; MONO_OBJECT_SETREF (msg, async_result, ares); res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args); - } - else + } else { res = mono_thread_pool_finish (ares, &out_args, &exc); + } if (exc) { if (((MonoException*)exc)->stack_trace) { @@ -3333,9 +3472,6 @@ mono_get_xdomain_marshal_type (MonoType *t) } } - if (mono_class_from_mono_type (t) == mono_defaults.stringbuilder_class) - return MONO_MARSHAL_COPY; - return MONO_MARSHAL_SERIALIZE; } @@ -4142,14 +4278,14 @@ mono_marshal_get_remoting_invoke_with_check (MonoMethod *method) if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) return method; - sig = signature_no_pinvoke (method); - /* we cant remote methods without this pointer */ - g_assert (sig->hasthis); + g_assert (mono_method_signature (method)->hasthis); if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) return res; + sig = signature_no_pinvoke (method); + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK); for (i = 0; i <= sig->param_count; i++) @@ -4349,8 +4485,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) g_assert (method); - target_klass = method->klass; - mono_marshal_lock (); if (method->string_ctor) { @@ -4385,7 +4519,22 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) } } - cache = method->klass->image->runtime_invoke_cache; + target_klass = mono_defaults.object_class; + /* + * if types in the signature belong to non-mscorlib, we cache only + * in the method image + */ + if (mono_class_from_mono_type (callsig->ret)->image != mono_defaults.corlib) { + target_klass = method->klass; + } else { + for (i = 0; i < callsig->param_count; i++) { + if (mono_class_from_mono_type (callsig->params [i])->image != mono_defaults.corlib) { + target_klass = method->klass; + break; + } + } + } + cache = target_klass->image->runtime_invoke_cache; /* from mono_marshal_find_in_cache */ res = g_hash_table_lookup (cache, callsig); @@ -4401,8 +4550,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) dealy_abort_sig->pinvoke = 0; } - target_klass = mono_defaults.object_class; - /* to make it work with our special string constructors */ if (!string_dummy) { MONO_GC_REGISTER_ROOT (string_dummy); @@ -4498,7 +4645,7 @@ handle_enum: /* fall through */ case MONO_TYPE_VALUETYPE: - if (t->data.klass->enumtype) { + if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) { type = t->data.klass->enum_basetype->type; goto handle_enum; } @@ -5178,10 +5325,34 @@ typedef struct { } EmitMarshalContext; typedef enum { + /* + * This is invoked to convert arguments from the current types to + * the underlying types expected by the platform routine. If required, + * the methods create a temporary variable with the proper type, and return + * the location for it (either the passed argument, or the newly allocated + * local slot). + */ MARSHAL_ACTION_CONV_IN, + + /* + * This operation is called to push the actual value that was optionally + * converted on the first stage + */ MARSHAL_ACTION_PUSH, + + /* + * Convert byref arguments back or free resources allocated during the + * CONV_IN stage + */ MARSHAL_ACTION_CONV_OUT, + + /* + * The result from the unmanaged call is at the top of the stack when + * this action is invoked. The result should be stored in the + * third local variable slot. + */ MARSHAL_ACTION_CONV_RESULT, + MARSHAL_ACTION_MANAGED_CONV_IN, MARSHAL_ACTION_MANAGED_CONV_OUT, MARSHAL_ACTION_MANAGED_CONV_RESULT @@ -5868,121 +6039,186 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, } static int -emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) +emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, int conv_arg, + MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; - MonoClass *klass = t->data.klass; - int pos, pos2, loc; - if (mono_class_from_mono_type (t) == mono_defaults.object_class && - (!spec || (spec && spec->native != MONO_NATIVE_STRUCT)) && - (!spec || (spec && (spec->native != MONO_NATIVE_IUNKNOWN && - spec->native != MONO_NATIVE_IDISPATCH && - spec->native != MONO_NATIVE_INTERFACE)))) { - mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented")); + switch (action){ + case MARSHAL_ACTION_CONV_IN: { + MonoType *intptr_type; + int dar_release_slot, pos; + + intptr_type = &mono_defaults.int_class->byval_arg; + conv_arg = mono_mb_add_local (mb, intptr_type); + *conv_arg_type = intptr_type; + + if (!sh_dangerous_add_ref) + init_safe_handle (); + + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_exception (mb, "ArgumentNullException", NULL); + + mono_mb_patch_branch (mb, pos); + if (t->byref){ + /* + * My tests in show that ref SafeHandles are not really + * passed as ref objects. Instead a NULL is passed as the + * value of the ref + */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + /* Create local to hold the ref parameter to DangerousAddRef */ + dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + + /* set release = false; */ + mono_mb_emit_icon (mb, 0); + mono_mb_emit_stloc (mb, dar_release_slot); + + /* safehandle.DangerousAddRef (ref release) */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, dar_release_slot); + mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL); + + /* Pull the handle field from SafeHandle */ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, conv_arg); + + break; } - switch (action) { - case MARSHAL_ACTION_CONV_IN: - *conv_arg_type = &mono_defaults.int_class->byval_arg; - conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + case MARSHAL_ACTION_PUSH: + if (t->byref) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; - m->orig_conv_args [argnum] = 0; + case MARSHAL_ACTION_CONV_OUT: { + /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */ + int dar_release_slot = conv_arg + 1; + int label_next; - if (spec && spec->native == MONO_NATIVE_STRUCT) - { - static MonoMethod *get_native_variant_for_object = NULL; - int local_variant; - if (!get_native_variant_for_object) - get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2); + if (!sh_dangerous_release) + init_safe_handle (); - *conv_arg_type = &mono_defaults.variant_class->byval_arg; + if (t->byref){ + MonoMethod *ctor; + + /* + * My tests indicate that ref SafeHandles parameters are not actually + * passed by ref, but instead a new Handle is created regardless of + * whether a change happens in the unmanaged side. + * + * Also, the Handle is created before calling into unmanaged code, + * but we do not support that mechanism (getting to the original + * handle) and it makes no difference where we create this + */ + ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0); + if (ctor == NULL){ + mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required"); + break; + } + /* refval = new SafeHandleDerived ()*/ + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_byte (mb, CEE_STIND_REF); - local_variant = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg); - conv_arg = local_variant; + /* refval.handle = returned_handle */ mono_mb_emit_ldarg (mb, argnum); - if (t->byref) - mono_mb_emit_byte(mb, CEE_LDIND_REF); - mono_mb_emit_ldloc_addr (mb, local_variant); - mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_byte (mb, CEE_STIND_I); + } else { + mono_mb_emit_ldloc (mb, dar_release_slot); + label_next = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL); + mono_mb_patch_addr (mb, label_next, mb->pos - (label_next + 4)); + } + break; + } + + case MARSHAL_ACTION_CONV_RESULT: { + MonoMethod *ctor = NULL; + int intptr_handle_slot; + + if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){ + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract"); + break; } - else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || - spec->native == MONO_NATIVE_IDISPATCH || - spec->native == MONO_NATIVE_INTERFACE)) { - mono_mb_emit_ptr (mb, 0); - mono_mb_emit_stloc (mb, conv_arg); - if (t->byref) { - /* we dont need any conversions for out parameters */ - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - else { - char *msg = g_strdup_printf ("non out object references are no implemented"); - MonoException *exc = mono_get_exception_not_implemented (msg); - g_warning (msg); - g_free (msg); - mono_raise_exception (exc); + ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0); + if (ctor == NULL){ + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required"); + break; + } + /* Store the IntPtr results into a local */ + intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + mono_mb_emit_stloc (mb, intptr_handle_slot); - } - } else { - char *msg = NULL; - guint32 pos_failed = 0, pos_rcw = 0; - mono_mb_emit_ldarg (mb, argnum); - // if null just break, conv arg was already inited to 0 - pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + /* Create return value */ + mono_mb_emit_op (mb, CEE_NEWOBJ, ctor); + mono_mb_emit_stloc (mb, 3); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_icall (mb, cominterop_object_is_rcw); - pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */ + mono_mb_emit_ldloc (mb, 3); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle)); + mono_mb_emit_ldloc (mb, intptr_handle_slot); + mono_mb_emit_byte (mb, CEE_STIND_I); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n"); + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n"); + break; - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); + case MARSHAL_ACTION_MANAGED_CONV_RESULT: + fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n"); + break; + default: + printf ("Unhandled case for MarshalAction: %d\n", action); + } - /* load the RCW from the ComInteropProxy*/ - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); + return conv_arg; +} - if (klass && klass != mono_defaults.object_class) { - static MonoMethod* GetInterface = NULL; - - if (!GetInterface) - GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1); - mono_mb_emit_ptr (mb, t); - mono_mb_emit_icall (mb, type_from_handle); - mono_mb_emit_managed_call (mb, GetInterface, NULL); - } - else if (spec->native == MONO_NATIVE_IUNKNOWN) { - static MonoProperty* iunknown = NULL; - - if (!iunknown) - iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown"); - mono_mb_emit_managed_call (mb, iunknown->get, NULL); - } - else if (spec->native == MONO_NATIVE_IDISPATCH) { - static MonoProperty* idispatch = NULL; - - if (!idispatch) - idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch"); - mono_mb_emit_managed_call (mb, idispatch->get, NULL); - } - else { - } - mono_mb_emit_stloc (mb, conv_arg); - - // if not rcw - mono_mb_patch_short_branch (mb, pos_rcw); - msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); +static int +emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass = t->data.klass; + int pos, pos2, loc; - // case if null - mono_mb_patch_short_branch (mb, pos_failed); - } - } - else if (klass->delegate) { + if (mono_class_from_mono_type (t) == mono_defaults.object_class) { + mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented")); + } + + switch (action) { + case MARSHAL_ACTION_CONV_IN: + *conv_arg_type = &mono_defaults.int_class->byval_arg; + conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + + m->orig_conv_args [argnum] = 0; + + if (klass->delegate) { g_assert (!t->byref); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN)); @@ -6071,70 +6307,6 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_CONV_OUT: - if (spec && spec->native == MONO_NATIVE_STRUCT) { - static MonoMethod *variant_clear = NULL; - static MonoMethod *get_object_for_native_variant = NULL; - if (!variant_clear) - variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0); - if (!get_object_for_native_variant) - get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1); - if (t->byref) { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - } - - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, variant_clear, NULL); - break; - } - - if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || - spec->native == MONO_NATIVE_IDISPATCH || - spec->native == MONO_NATIVE_INTERFACE)) { - if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) { - static MonoClass* com_interop_proxy_class = NULL; - static MonoMethod* com_interop_proxy_get_proxy = NULL; - static MonoMethod* get_transparent_proxy = NULL; - int real_proxy; - guint32 pos_failed = 0; - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_emit_ldloc (mb, conv_arg); - pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - if (!com_interop_proxy_class) - com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); - if (!com_interop_proxy_get_proxy) - com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE); - if (!get_transparent_proxy) - get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0); - - real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg); - - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg); - mono_mb_emit_icall (mb, type_from_handle); - mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL); - mono_mb_emit_stloc (mb, real_proxy); - - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, real_proxy); - mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL); - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - // case if null - mono_mb_patch_short_branch (mb, pos_failed); - } - break; - } if (klass == mono_defaults.stringbuilder_class) { gboolean need_free; MonoMarshalNative encoding; @@ -6240,11 +6412,6 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, 0); mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL)); mono_mb_emit_stloc (mb, 3); - } else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || - spec->native == MONO_NATIVE_IDISPATCH || - spec->native == MONO_NATIVE_INTERFACE)) { - char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); } else { /* set src */ mono_mb_emit_stloc (mb, 0); @@ -6445,6 +6612,289 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, return conv_arg; } +static int +emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + MonoClass *klass = t->data.klass; + + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + *conv_arg_type = &mono_defaults.int_class->byval_arg; + conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + + m->orig_conv_args [argnum] = 0; + + mono_mb_emit_ptr (mb, 0); + mono_mb_emit_stloc (mb, conv_arg); + + if (t->byref) { + /* we dont need any conversions for out parameters */ + if (t->attrs & PARAM_ATTRIBUTE_OUT) + break; + else { + char *msg = g_strdup_printf ("non out object references are no implemented"); + MonoException *exc = mono_get_exception_not_implemented (msg); + g_warning (msg); + g_free (msg); + mono_raise_exception (exc); + + } + } else { + char *msg = NULL; + guint32 pos_failed = 0, pos_rcw = 0; + mono_mb_emit_ldarg (mb, argnum); + // if null just break, conv arg was already inited to 0 + pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icall (mb, cominterop_object_is_rcw); + pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + /* load the RCW from the ComInteropProxy*/ + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + + if (klass && klass != mono_defaults.object_class) { + static MonoMethod* GetInterface = NULL; + + if (!GetInterface) + GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1); + mono_mb_emit_ptr (mb, t); + mono_mb_emit_icall (mb, type_from_handle); + mono_mb_emit_managed_call (mb, GetInterface, NULL); + } + else if (spec->native == MONO_NATIVE_IUNKNOWN) { + static MonoProperty* iunknown = NULL; + + if (!iunknown) + iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown"); + mono_mb_emit_managed_call (mb, iunknown->get, NULL); + } + else if (spec->native == MONO_NATIVE_IDISPATCH) { + static MonoProperty* idispatch = NULL; + + if (!idispatch) + idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch"); + mono_mb_emit_managed_call (mb, idispatch->get, NULL); + } + else { + } + mono_mb_emit_stloc (mb, conv_arg); + + // if not rcw + mono_mb_patch_short_branch (mb, pos_rcw); + msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + + // case if null + mono_mb_patch_short_branch (mb, pos_failed); + } + break; + } + + case MARSHAL_ACTION_CONV_OUT: { + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) { + static MonoClass* com_interop_proxy_class = NULL; + static MonoMethod* com_interop_proxy_get_proxy = NULL; + static MonoMethod* get_transparent_proxy = NULL; + int real_proxy; + guint32 pos_failed = 0; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + mono_mb_emit_ldloc (mb, conv_arg); + pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + + if (!com_interop_proxy_class) + com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); + if (!com_interop_proxy_get_proxy) + com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE); + if (!get_transparent_proxy) + get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0); + + real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg); + + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg); + mono_mb_emit_icall (mb, type_from_handle); + mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL); + mono_mb_emit_stloc (mb, real_proxy); + + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, real_proxy); + mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL); + if (klass && klass != mono_defaults.object_class) + mono_mb_emit_op (mb, CEE_CASTCLASS, klass); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + // case if null + mono_mb_patch_short_branch (mb, pos_failed); + } + break; + } + + case MARSHAL_ACTION_PUSH: + if (t->byref) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + default: + g_assert_not_reached (); + } + + return conv_arg; +} + +static int +emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, + MonoMarshalSpec *spec, + int conv_arg, MonoType **conv_arg_type, + MarshalAction action) +{ + MonoMethodBuilder *mb = m->mb; + static MonoMethod *get_object_for_native_variant = NULL; + static MonoMethod *get_native_variant_for_object = NULL; + + if (!get_object_for_native_variant) + get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1); + g_assert (get_object_for_native_variant); + + if (!get_native_variant_for_object) + get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2); + g_assert (get_native_variant_for_object); + + switch (action) { + case MARSHAL_ACTION_CONV_IN: { + conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg); + + if (t->byref) + *conv_arg_type = &mono_defaults.variant_class->this_arg; + else + *conv_arg_type = &mono_defaults.variant_class->byval_arg; + + if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + mono_mb_emit_ldarg (mb, argnum); + if (t->byref) + mono_mb_emit_byte(mb, CEE_LDIND_REF); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); + break; + } + + case MARSHAL_ACTION_CONV_OUT: { + static MonoMethod *variant_clear = NULL; + + if (!variant_clear) + variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0); + g_assert (variant_clear); + + + if (t->byref) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, variant_clear, NULL); + break; + } + + case MARSHAL_ACTION_PUSH: + if (t->byref) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + + case MARSHAL_ACTION_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_IN: { + conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + + if (t->byref) + *conv_arg_type = &mono_defaults.variant_class->this_arg; + else + *conv_arg_type = &mono_defaults.variant_class->byval_arg; + + if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) + break; + + if (t->byref) + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + if (t->byref) { + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); + } + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_RESULT: { + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + + default: + g_assert_not_reached (); + } + + return conv_arg; +} + static int emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, @@ -7294,6 +7744,18 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action); case MONO_TYPE_CLASS: case MONO_TYPE_OBJECT: + if (spec && spec->native == MONO_NATIVE_STRUCT) + return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + if (spec && (spec->native == MONO_NATIVE_IUNKNOWN || + spec->native == MONO_NATIVE_IDISPATCH || + spec->native == MONO_NATIVE_INTERFACE)) + return emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); + + if (mono_defaults.safehandle_class != NULL && + mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE)) + return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); + return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: @@ -7709,51 +8171,23 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig return res; } - -/* - * generates IL code to call managed methods from unmanaged code - */ -MonoMethod * -mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this) + +/* FIXME: moving GC */ +static void +mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this) { - static MonoClass *UnmanagedFunctionPointerAttribute; - MonoMethodSignature *sig, *csig, *invoke_sig; - MonoMethodBuilder *mb; - MonoMethod *res, *invoke; - MonoMarshalSpec **mspecs; - MonoMethodPInvoke piinfo; - GHashTable *cache; + MonoMethodSignature *sig, *csig; int i, *tmp_locals; - EmitMarshalContext m; - g_assert (method != NULL); - g_assert (!mono_method_signature (method)->pinvoke); + sig = m->sig; + csig = m->csig; - /* - * FIXME: Should cache the method+delegate type pair, since the same method - * could be called with different delegates, thus different marshalling - * options. - */ - cache = method->klass->image->managed_wrapper_cache; - if (!this && (res = mono_marshal_find_in_cache (cache, method))) - return res; - - invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count); - invoke_sig = mono_method_signature (invoke); - - mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1); - mono_method_get_marshal_info (invoke, mspecs); - - sig = mono_method_signature (method); - - mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED); - - /* allocate local 0 (pointer) src_ptr */ - mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - /* allocate local 1 (pointer) dst_ptr */ - mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - /* allocate local 2 (boolean) delete_old */ - mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + /* allocate local 0 (pointer) src_ptr */ + mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + /* allocate local 1 (pointer) dst_ptr */ + mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + /* allocate local 2 (boolean) delete_old */ + mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); if (!MONO_TYPE_IS_VOID(sig->ret)) { /* allocate local 3 to store the return value */ @@ -7763,73 +8197,6 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, mono_mb_emit_icon (mb, 0); mono_mb_emit_stloc (mb, 2); - /* we copy the signature, so that we can modify it */ - csig = signature_dup (method->klass->image, sig); - csig->hasthis = 0; - csig->pinvoke = 1; - - m.mb = mb; - m.sig = sig; - m.piinfo = NULL; - m.retobj_var = 0; - m.csig = csig; - m.image = method->klass->image; - -#ifdef PLATFORM_WIN32 - /* - * Under windows, delegates passed to native code must use the STDCALL - * calling convention. - */ - csig->call_convention = MONO_CALL_STDCALL; -#endif - - /* Change default calling convention if needed */ - /* Why is this a modopt ? */ - if (invoke_sig->ret && invoke_sig->ret->num_mods) { - for (i = 0; i < invoke_sig->ret->num_mods; ++i) { - MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token); - g_assert (cmod_class); - if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) { - if (!strcmp (cmod_class->name, "CallConvCdecl")) - csig->call_convention = MONO_CALL_C; - else if (!strcmp (cmod_class->name, "CallConvStdcall")) - csig->call_convention = MONO_CALL_STDCALL; - else if (!strcmp (cmod_class->name, "CallConvFastcall")) - csig->call_convention = MONO_CALL_FASTCALL; - else if (!strcmp (cmod_class->name, "CallConvThiscall")) - csig->call_convention = MONO_CALL_THISCALL; - } - } - } - - /* Handle the UnmanagedFunctionPointerAttribute */ - if (!UnmanagedFunctionPointerAttribute) - UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute"); - - /* The attribute is only available in Net 2.0 */ - if (UnmanagedFunctionPointerAttribute) { - MonoReflectionUnmanagedFunctionPointerAttribute *attr; - MonoCustomAttrInfo *cinfo; - - /* - * The pinvoke attributes are stored in a real custom attribute so we have to - * construct it. - */ - cinfo = mono_custom_attrs_from_class (delegate_klass); - if (cinfo) { - attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute); - if (attr) { - memset (&piinfo, 0, sizeof (piinfo)); - m.piinfo = &piinfo; - piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error; - - csig->call_convention = attr->call_conv - 1; - } - if (!cinfo->cached) - mono_custom_attrs_free (cinfo); - } - } - /* fixme: howto handle this ? */ if (sig->hasthis) { if (this) { @@ -7853,7 +8220,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: case MONO_TYPE_STRING: - tmp_locals [i] = emit_marshal (&m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN); + tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN); break; default: @@ -7880,7 +8247,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, mono_mb_emit_managed_call (mb, method, NULL); if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) { - emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); + emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); } else if (!sig->ret->byref) { @@ -7906,12 +8273,12 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, break; case MONO_TYPE_STRING: csig->ret = &mono_defaults.int_class->byval_arg; - emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); + emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); break; case MONO_TYPE_VALUETYPE: case MONO_TYPE_CLASS: case MONO_TYPE_SZARRAY: - emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); + emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); break; default: g_warning ("return type 0x%02x unknown", sig->ret->type); @@ -7927,13 +8294,14 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoMarshalSpec *spec = mspecs [i + 1]; if (spec && spec->native == MONO_NATIVE_CUSTOM) { - emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); + emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); } else if (t->byref) { switch (t->type) { case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: - emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); + case MONO_TYPE_OBJECT: + emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); break; } } @@ -7943,7 +8311,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, case MONO_TYPE_SZARRAY: case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: - emit_marshal (&m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); + emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); break; default: g_assert_not_reached (); @@ -7951,16 +8319,126 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, } } - if (m.retobj_var) { - mono_mb_emit_ldloc (mb, m.retobj_var); + if (m->retobj_var) { + mono_mb_emit_ldloc (mb, m->retobj_var); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m.retobj_class); + mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class); } else { if (!MONO_TYPE_IS_VOID(sig->ret)) mono_mb_emit_ldloc (mb, 3); mono_mb_emit_byte (mb, CEE_RET); } +} + + +/* + * generates IL code to call managed methods from unmanaged code + */ +MonoMethod * +mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this) +{ + static MonoClass *UnmanagedFunctionPointerAttribute; + MonoMethodSignature *sig, *csig, *invoke_sig; + MonoMethodBuilder *mb; + MonoMethod *res, *invoke; + MonoMarshalSpec **mspecs; + MonoMethodPInvoke piinfo; + GHashTable *cache; + int i; + EmitMarshalContext m; + + g_assert (method != NULL); + g_assert (!mono_method_signature (method)->pinvoke); + + /* + * FIXME: Should cache the method+delegate type pair, since the same method + * could be called with different delegates, thus different marshalling + * options. + */ + cache = method->klass->image->managed_wrapper_cache; + if (!this && (res = mono_marshal_find_in_cache (cache, method))) + return res; + + invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count); + invoke_sig = mono_method_signature (invoke); + + mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1); + mono_method_get_marshal_info (invoke, mspecs); + + sig = mono_method_signature (method); + + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED); + + + /* we copy the signature, so that we can modify it */ + csig = signature_dup (method->klass->image, sig); + csig->hasthis = 0; + csig->pinvoke = 1; + + m.mb = mb; + m.sig = sig; + m.piinfo = NULL; + m.retobj_var = 0; + m.csig = csig; + m.image = method->klass->image; + +#ifdef PLATFORM_WIN32 + /* + * Under windows, delegates passed to native code must use the STDCALL + * calling convention. + */ + csig->call_convention = MONO_CALL_STDCALL; +#endif + + /* Change default calling convention if needed */ + /* Why is this a modopt ? */ + if (invoke_sig->ret && invoke_sig->ret->num_mods) { + for (i = 0; i < invoke_sig->ret->num_mods; ++i) { + MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token); + g_assert (cmod_class); + if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) { + if (!strcmp (cmod_class->name, "CallConvCdecl")) + csig->call_convention = MONO_CALL_C; + else if (!strcmp (cmod_class->name, "CallConvStdcall")) + csig->call_convention = MONO_CALL_STDCALL; + else if (!strcmp (cmod_class->name, "CallConvFastcall")) + csig->call_convention = MONO_CALL_FASTCALL; + else if (!strcmp (cmod_class->name, "CallConvThiscall")) + csig->call_convention = MONO_CALL_THISCALL; + } + } + } + + /* Handle the UnmanagedFunctionPointerAttribute */ + if (!UnmanagedFunctionPointerAttribute) + UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute"); + + /* The attribute is only available in Net 2.0 */ + if (UnmanagedFunctionPointerAttribute) { + MonoReflectionUnmanagedFunctionPointerAttribute *attr; + MonoCustomAttrInfo *cinfo; + + /* + * The pinvoke attributes are stored in a real custom attribute so we have to + * construct it. + */ + cinfo = mono_custom_attrs_from_class (delegate_klass); + if (cinfo) { + attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute); + if (attr) { + memset (&piinfo, 0, sizeof (piinfo)); + m.piinfo = &piinfo; + piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error; + + csig->call_convention = attr->call_conv - 1; + } + if (!cinfo->cached) + mono_custom_attrs_free (cinfo); + } + } + + mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this); if (!this) res = mono_mb_create_and_cache (cache, method, @@ -8657,6 +9135,174 @@ mono_marshal_get_stelemref () return ret; } +typedef struct { + int rank; + int elem_size; + MonoMethod *method; +} ArrayElemAddr; + +/* LOCKING: vars accessed under the marshal lock */ +static ArrayElemAddr *elem_addr_cache = NULL; +static int elem_addr_cache_size = 0; +static int elem_addr_cache_next = 0; + +/** + * mono_marshal_get_array_address: + * @rank: rank of the array type + * @elem_size: size in bytes of an element of an array. + * + * Returns a MonoMethd that implements the code to get the address + * of an element in a multi-dimenasional array of @rank dimensions. + * The returned method takes an array as the first argument and then + * @rank indexes for the @rank dimensions. + */ +MonoMethod* +mono_marshal_get_array_address (int rank, int elem_size) +{ + MonoMethod *ret; + MonoMethodBuilder *mb; + MonoMethodSignature *sig; + int i, bounds, ind, realidx; + int branch_pos, *branch_positions; + int cached; + + ret = NULL; + mono_marshal_lock (); + for (i = 0; i < elem_addr_cache_next; ++i) { + if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) { + ret = elem_addr_cache [i].method; + break; + } + } + mono_marshal_unlock (); + if (ret) + return ret; + + branch_positions = g_new0 (int, rank); + + sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank); + + /* void* address (void* array, int idx0, int idx1, int idx2, ...) */ + sig->ret = &mono_defaults.int_class->byval_arg; + sig->params [0] = &mono_defaults.object_class->byval_arg; + for (i = 0; i < rank; ++i) { + sig->params [i + 1] = &mono_defaults.int32_class->byval_arg; + } + + mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED); + + bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); + ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); + realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); + + /* bounds = array->bounds; */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, bounds)); + mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_stloc (mb, bounds); + + /* ind is the overall element index, realidx is the partial index in a single dimension */ + /* ind = idx0 - bounds [0].lower_bound */ + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_stloc (mb, ind); + /* if (ind >= bounds [0].length) goto exeception; */ + mono_mb_emit_ldloc (mb, ind); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, length)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + /* note that we use unsigned comparison */ + branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN); + + /* For large ranks (> 4?) use a loop n IL later to reduce code size. + * We could also decide to ignore the passed elem_size and get it + * from the array object, to reduce the number of methods we generate: + * the additional cost is 3 memory loads and a non-immediate mul. + */ + for (i = 1; i < rank; ++i) { + /* realidx = idxi - bounds [i].lower_bound */ + mono_mb_emit_ldarg (mb, 1 + i); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_SUB); + mono_mb_emit_stloc (mb, realidx); + /* if (realidx >= bounds [i].length) goto exeception; */ + mono_mb_emit_ldloc (mb, realidx); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN); + /* ind = ind * bounds [i].length + realidx */ + mono_mb_emit_ldloc (mb, ind); + mono_mb_emit_ldloc (mb, bounds); + mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length)); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_LDIND_I4); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_ldloc (mb, realidx); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_stloc (mb, ind); + } + + /* return array->vector + ind * element_size */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector)); + mono_mb_emit_ldloc (mb, ind); + mono_mb_emit_icon (mb, elem_size); + mono_mb_emit_byte (mb, CEE_MUL); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_RET); + + /* patch the branches to get here and throw */ + for (i = 1; i < rank; ++i) { + mono_mb_patch_branch (mb, branch_positions [i]); + } + mono_mb_patch_branch (mb, branch_pos); + /* throw exception */ + mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL); + + g_free (branch_positions); + mono_loader_lock (); + ret = mono_mb_create_method (mb, sig, 4); + mono_loader_unlock (); + mono_mb_free (mb); + + /* cache the result */ + cached = 0; + mono_marshal_lock (); + for (i = 0; i < elem_addr_cache_next; ++i) { + if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) { + /* FIXME: free ret */ + ret = elem_addr_cache [i].method; + cached = TRUE; + break; + } + } + if (!cached) { + if (elem_addr_cache_next >= elem_addr_cache_size) { + int new_size = elem_addr_cache_size + 4; + ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size); + memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr)); + g_free (elem_addr_cache); + elem_addr_cache = new_array; + elem_addr_cache_size = new_size; + } + elem_addr_cache [elem_addr_cache_next].rank = rank; + elem_addr_cache [elem_addr_cache_next].elem_size = elem_size; + elem_addr_cache [elem_addr_cache_next].method = ret; + } + mono_marshal_unlock (); + return ret; +} + MonoMethod* mono_marshal_get_write_barrier (void) { @@ -8785,10 +9431,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *s MONO_CHECK_ARG_NULL (src); MONO_CHECK_ARG_NULL (dest); - g_assert (src->obj.vtable->klass->rank == 1); - g_assert (start_index >= 0); - g_assert (length >= 0); - g_assert (start_index + length <= mono_array_length (src)); + if (src->obj.vtable->klass->rank != 1) + mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional")); + if (start_index < 0) + mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0")); + if (length < 0) + mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0")); + if (start_index + length > mono_array_length (src)) + mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length")); element_size = mono_array_element_size (src->obj.vtable->klass); @@ -8810,10 +9460,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer s MONO_CHECK_ARG_NULL (src); MONO_CHECK_ARG_NULL (dest); - g_assert (dest->obj.vtable->klass->rank == 1); - g_assert (start_index >= 0); - g_assert (length >= 0); - g_assert (start_index + length <= mono_array_length (dest)); + if (dest->obj.vtable->klass->rank != 1) + mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional")); + if (start_index < 0) + mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0")); + if (length < 0) + mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0")); + if (start_index + length > mono_array_length (dest)) + mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length")); element_size = mono_array_element_size (dest->obj.vtable->klass); @@ -8959,8 +9613,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, mono_raise_exception (mono_get_exception_argument_null ("ptr")); g_assert_not_reached (); return NULL; - } else + } else { return mono_string_new_len (mono_domain_get (), ptr, len); + } } MonoString * @@ -8992,8 +9647,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *pt mono_raise_exception (mono_get_exception_argument_null ("ptr")); g_assert_not_reached (); return NULL; - } else + } else { return mono_string_new_utf16 (domain, ptr, len); + } } MonoString * @@ -9302,6 +9958,7 @@ mono_struct_delete_old (MonoClass *klass, char *ptr) case MONO_MARSHAL_CONV_STR_TBSTR: mono_marshal_free (*(gpointer *)cpos); break; + default: continue; } @@ -9323,8 +9980,6 @@ ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, mono_struct_delete_old (klass, (char *)src); } - -/* FIXME: on win32 we should probably use GlobalAlloc(). */ void* ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size) { @@ -9336,7 +9991,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size) /* This returns a valid pointer for size 0 on MS.NET */ size = 4; +#ifdef PLATFORM_WIN32 + res = GlobalAlloc (GMEM_FIXED, (gulong)size); +#else res = g_try_malloc ((gulong)size); +#endif if (!res) mono_gc_out_of_memory ((gulong)size); @@ -9348,7 +10007,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr) { MONO_ARCH_SAVE_REGS; +#ifdef PLATFORM_WIN32 + GlobalFree (ptr); +#else g_free (ptr); +#endif } void* @@ -9375,6 +10038,18 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr) #endif } +gpointer +ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size) +{ + MONO_ARCH_SAVE_REGS; + +#ifdef PLATFORM_WIN32 + return CoTaskMemRealloc (ptr, size); +#else + return g_try_realloc (ptr, (gulong)size); +#endif +} + void* ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index) {