X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=2b66637c2bf6c5368ed6039407034fd3a918e68b;hb=d6cdd9715eff6eeac53c9d0970a90e49b7c80edd;hp=0e622038db80c04f7079df339dfe1027970c8b0f;hpb=032ebf9e2823275fbeebd38ad40f97da4bb47a3e;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 0e622038db8..2b66637c2bf 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -74,6 +74,7 @@ typedef struct _MonoRemotingMethods MonoRemotingMethods; #define mono_marshal_lock() EnterCriticalSection (&marshal_mutex) #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex) static CRITICAL_SECTION marshal_mutex; +static gboolean marshal_mutex_initialized; static guint32 last_error_tls_id; @@ -100,6 +101,9 @@ mono_string_to_lpstr (MonoString *string_obj); static MonoStringBuilder * mono_string_utf8_to_builder2 (char *text); +static MonoStringBuilder * +mono_string_utf16_to_builder2 (gunichar2 *text); + static void mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum); @@ -115,9 +119,6 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params); static MonoObject * mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params); -static MonoObject * -mono_marshal_xdomain_copy_value (MonoObject *val); - static void mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst); @@ -167,7 +168,7 @@ signature_dup (MonoImage *image, MonoMethodSignature *sig) int sigsize; res = mono_metadata_signature_alloc (image, sig->param_count); - sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); + sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *); memcpy (res, sig, sigsize); return res; @@ -193,6 +194,7 @@ mono_marshal_init (void) if (!module_initialized) { module_initialized = TRUE; InitializeCriticalSection (&marshal_mutex); + marshal_mutex_initialized = TRUE; last_error_tls_id = TlsAlloc (); load_type_info_tls_id = TlsAlloc (); @@ -209,6 +211,7 @@ mono_marshal_init (void) register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE); register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE); register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE); + register_icall (mono_free_lparray, "mono_free_lparray", "void object ptr", FALSE); register_icall (mono_byvalarray_to_array, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE); register_icall (mono_array_to_byvalarray, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE); register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE); @@ -222,6 +225,7 @@ mono_marshal_init (void) register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE); register_icall (mono_string_utf8_to_builder2, "mono_string_utf8_to_builder2", "object ptr", FALSE); register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE); + register_icall (mono_string_utf16_to_builder2, "mono_string_utf16_to_builder2", "object ptr", FALSE); register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE); register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE); register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE); @@ -240,7 +244,8 @@ mono_marshal_init (void) register_icall (mono_context_set, "mono_context_set", "void object", FALSE); register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE); register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE); - register_icall (mono_gc_wbarrier_generic_store, "wb_generic", "void ptr object", FALSE); + register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE); + register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE); mono_cominterop_init (); } @@ -254,6 +259,7 @@ mono_marshal_cleanup (void) TlsFree (load_type_info_tls_id); TlsFree (last_error_tls_id); DeleteCriticalSection (&marshal_mutex); + marshal_mutex_initialized = FALSE; } MonoClass *byte_array_class; @@ -302,6 +308,7 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate) { MonoMethod *method, *wrapper; MonoClass *klass; + uint32_t target_handle = 0; if (!delegate) return NULL; @@ -326,9 +333,14 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate) return ftnptr; } - wrapper = mono_marshal_get_managed_wrapper (method, klass, delegate->target); + if (delegate->target) { + /* Produce a location which can be embedded in JITted code */ + target_handle = mono_gchandle_new_weakref (delegate->target, FALSE); + } + + wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle); - delegate->delegate_trampoline = mono_compile_method (wrapper); + delegate->delegate_trampoline = mono_compile_method (wrapper); // Add the delegate to the delegate hash table delegate_hash_table_add (delegate); @@ -371,16 +383,20 @@ delegate_hash_table_remove (MonoDelegate *d) } static void -delegate_hash_table_add (MonoDelegate *d) +delegate_hash_table_add (MonoDelegate *d) { #ifdef HAVE_MOVING_COLLECTOR guint32 gchandle = mono_gchandle_new_weakref ((MonoObject*)d, FALSE); + guint32 old_gchandle; #endif mono_marshal_lock (); if (delegate_hash_table == NULL) delegate_hash_table = delegate_hash_table_new (); #ifdef HAVE_MOVING_COLLECTOR + old_gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline)); g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, GUINT_TO_POINTER (gchandle)); + if (old_gchandle) + mono_gchandle_free (old_gchandle); #else g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d); #endif @@ -486,9 +502,19 @@ mono_delegate_free_ftnptr (MonoDelegate *delegate) } if (ptr) { + uint32_t gchandle; + void **method_data; ji = mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr)); g_assert (ji); + method_data = ((MonoMethodWrapper*)ji->method)->method_data; + + /*the target gchandle is the first entry after size and the wrapper itself.*/ + gchandle = GPOINTER_TO_UINT (method_data [2]); + + if (gchandle) + mono_gchandle_free (gchandle); + mono_runtime_free_method (mono_object_domain (delegate), ji->method); } } @@ -506,13 +532,85 @@ mono_array_to_savearray (MonoArray *array) gpointer mono_array_to_lparray (MonoArray *array) { + gpointer *nativeArray = NULL; + int nativeArraySize = 0; + + int i = 0; + MonoClass *klass; + if (!array) return NULL; +#ifndef DISABLE_COM - /* fixme: maybe we need to make a copy */ + klass = array->obj.vtable->klass; + + switch (klass->element_class->byval_arg.type) { + case MONO_TYPE_VOID: + g_assert_not_reached (); + break; +#ifndef DISABLE_COM + case MONO_TYPE_CLASS: + nativeArraySize = array->max_length; + nativeArray = malloc(sizeof(gpointer) * nativeArraySize); + for(i = 0; i < nativeArraySize; ++i) + nativeArray[i] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((gpointer*)array->vector)[i]); + return nativeArray; +#endif + case MONO_TYPE_U1: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_I1: + case MONO_TYPE_U2: + case MONO_TYPE_CHAR: + case MONO_TYPE_I2: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_U8: + case MONO_TYPE_I8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_VALUETYPE: + case MONO_TYPE_PTR: + /* nothing to do */ + break; + case MONO_TYPE_GENERICINST: + case MONO_TYPE_OBJECT: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_STRING: + default: + g_warning ("type 0x%x not handled", klass->element_class->byval_arg.type); + g_assert_not_reached (); + } +#endif return array->vector; } +void +mono_free_lparray (MonoArray *array, gpointer* nativeArray) +{ +#ifndef DISABLE_COM + MonoClass *klass; + int i = 0; + + if (!array) + return; + + if (!nativeArray) + return; + klass = array->obj.vtable->klass; + + switch (klass->element_class->byval_arg.type) { + case MONO_TYPE_CLASS: + for(i = 0; i < array->max_length; ++i) + mono_marshal_free_ccw(nativeArray[i]); + free(nativeArray); + break; + } +#endif +} + static void mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *elclass, guint32 elnum) { @@ -648,6 +746,45 @@ mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text) sb->length = len; } +MonoStringBuilder * +mono_string_utf16_to_builder2 (gunichar2 *text) +{ + int len; + MonoStringBuilder *sb; + static MonoClass *string_builder_class; + static MonoMethod *sb_ctor; + void *args [1]; + MonoObject *exc; + + if (!text) + return NULL; + + if (!string_builder_class) { + MonoMethodDesc *desc; + + string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder"); + g_assert (string_builder_class); + desc = mono_method_desc_new (":.ctor(int)", FALSE); + sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class); + g_assert (sb_ctor); + mono_method_desc_free (desc); + } + + for (len = 0; text [len] != 0; ++len) + ; + + sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class); + g_assert (sb); + args [0] = &len; + mono_runtime_invoke (sb_ctor, sb, args, &exc); + g_assert (!exc); + + sb->length = len; + memcpy (mono_string_chars (sb->str), text, len * 2); + + return sb; +} + /** * mono_string_builder_to_utf8: * @sb: the string builder @@ -724,13 +861,16 @@ mono_string_builder_to_utf16 (MonoStringBuilder *sb) sb->cached_str = NULL; } + if (sb->length == 0) + *(mono_string_chars (sb->str)) = '\0'; + return mono_string_chars (sb->str); } static gpointer mono_string_to_lpstr (MonoString *s) { -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 char *as, *tmp; glong len; GError *error = NULL; @@ -1144,7 +1284,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 mono_mb_emit_icall (mb, mono_string_from_utf16); #else mono_mb_emit_icall (mb, mono_string_new_wrapper); @@ -1254,9 +1394,13 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv case MONO_MARSHAL_CONV_STR_ANSIBSTR: case MONO_MARSHAL_CONV_STR_TBSTR: case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY: - default: - g_warning ("marshaling conversion %d not implemented", conv); - g_assert_not_reached (); + default: { + char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv); + + mono_mb_emit_exception_marshal_directive (mb, msg); + g_free (msg); + break; + } } } @@ -1271,7 +1415,7 @@ conv_to_icall (MonoMarshalConv conv) case MONO_MARSHAL_CONV_LPSTR_STR: return mono_string_new_wrapper; case MONO_MARSHAL_CONV_STR_LPTSTR: -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 return mono_marshal_string_to_utf16; #else return mono_string_to_lpstr; @@ -1288,7 +1432,7 @@ conv_to_icall (MonoMarshalConv conv) case MONO_MARSHAL_CONV_SB_LPSTR: return mono_string_builder_to_utf8; case MONO_MARSHAL_CONV_SB_LPTSTR: -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 return mono_string_builder_to_utf16; #else return mono_string_builder_to_utf8; @@ -1299,6 +1443,8 @@ conv_to_icall (MonoMarshalConv conv) return mono_array_to_savearray; case MONO_MARSHAL_CONV_ARRAY_LPARRAY: return mono_array_to_lparray; + case MONO_MARSHAL_FREE_LPARRAY: + return mono_free_lparray; case MONO_MARSHAL_CONV_DEL_FTN: return mono_delegate_to_ftnptr; case MONO_MARSHAL_CONV_FTN_DEL: @@ -1306,7 +1452,7 @@ conv_to_icall (MonoMarshalConv conv) case MONO_MARSHAL_CONV_LPSTR_SB: return mono_string_utf8_to_builder; case MONO_MARSHAL_CONV_LPTSTR_SB: -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 return mono_string_utf16_to_builder; #else return mono_string_utf8_to_builder; @@ -1586,7 +1732,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv default: { char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv); MonoException *exc = mono_get_exception_not_implemented (msg); - g_warning (msg); + g_warning ("%s", msg); g_free (msg); mono_raise_exception (exc); } @@ -1621,6 +1767,15 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) return; } + if (klass != mono_defaults.safehandle_class) { + if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.", + mono_type_full_name (&klass->byval_arg)); + mono_mb_emit_exception_marshal_directive (mb, msg); + return; + } + } + for (i = 0; i < info->num_fields; i++) { MonoMarshalNative ntype; MonoMarshalConv conv; @@ -1655,11 +1810,6 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) "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)); - } switch (conv) { @@ -1853,12 +2003,16 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params) { MonoMethodMessage *msg; MonoDelegate *async_callback; + MonoMulticastDelegate *mcast_delegate; MonoObject *state; MonoMethod *im; MonoClass *klass; MonoMethod *method = NULL, *method2 = NULL; g_assert (delegate); + mcast_delegate = (MonoMulticastDelegate *) delegate; + if (mcast_delegate->prev != NULL) + mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target")); if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) { @@ -1871,19 +2025,19 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params) MonoAsyncResult *ares; MonoObject *exc; MonoArray *out_args; - HANDLE handle; method = delegate->method; 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); + ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL); MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate); MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback); MONO_OBJECT_SETREF (msg, async_result, ares); msg->call_type = CallType_BeginInvoke; + exc = NULL; mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args); + if (exc) + mono_raise_exception ((MonoException *) exc); return ares; } } @@ -1998,7 +2152,7 @@ mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *sp case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE: return MONO_NATIVE_LPWSTR; case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO: -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 return MONO_NATIVE_LPWSTR; #else return MONO_NATIVE_LPSTR; @@ -2161,18 +2315,6 @@ mono_marshal_find_in_cache (GHashTable *cache, gpointer key) return res; } -static void -mono_marshal_method_set_wrapper_data (MonoMethod *method, gpointer data) -{ - void **datav; - /* assert */ - if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) - return; - - datav = ((MonoMethodWrapper *)method)->method_data; - datav [1] = data; -} - /* Create the method from the builder and place it in the cache */ MonoMethod* mono_mb_create_and_cache (GHashTable *cache, gpointer key, @@ -2192,7 +2334,7 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key, if (!res) { res = newm; g_hash_table_insert (cache, key, res); - mono_marshal_method_set_wrapper_data (res, key); + mono_marshal_set_wrapper_info (res, key); mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -2265,7 +2407,7 @@ mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb, mono_marshal_lock (); if (!*res) { *res = newm; - mono_marshal_method_set_wrapper_data (*res, key); + mono_marshal_set_wrapper_info (*res, key); mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -2280,14 +2422,89 @@ MonoMethod * mono_marshal_method_from_wrapper (MonoMethod *wrapper) { gpointer res; + int wrapper_type = wrapper->wrapper_type; - if (wrapper->wrapper_type == MONO_WRAPPER_NONE || wrapper->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) + if (wrapper_type == MONO_WRAPPER_NONE || wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) return wrapper; - res = mono_method_get_wrapper_data (wrapper, 1); - if (res == NULL) - return wrapper; - return res; + switch (wrapper_type) { + case MONO_WRAPPER_REMOTING_INVOKE: + case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: + case MONO_WRAPPER_XDOMAIN_INVOKE: + case MONO_WRAPPER_SYNCHRONIZED: + case MONO_WRAPPER_MANAGED_TO_NATIVE: + case MONO_WRAPPER_RUNTIME_INVOKE: + res = mono_method_get_wrapper_data (wrapper, 1); + if (res == NULL) + return wrapper; + return res; + default: + return NULL; + } +} + +/* + * mono_marshal_get_wrapper_info: + * + * Retrieve the pointer stored by mono_marshal_set_wrapper_info. + */ +gpointer +mono_marshal_get_wrapper_info (MonoMethod *wrapper) +{ + g_assert (wrapper->wrapper_type); + + return mono_method_get_wrapper_data (wrapper, 1); +} + +/* + * mono_marshal_set_wrapper_info: + * + * Store an arbitrary pointer inside the wrapper which is retrievable by + * mono_marshal_get_wrapper_info. The format of the data depends on the type of the + * wrapper (method->wrapper_type). + */ +void +mono_marshal_set_wrapper_info (MonoMethod *method, gpointer data) +{ + void **datav; + /* assert */ + if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) + return; + + datav = ((MonoMethodWrapper *)method)->method_data; + datav [1] = data; +} + +/* + * get_wrapper_target_class: + * + * Return the class where a wrapper method should be placed. + */ +static MonoClass* +get_wrapper_target_class (MonoImage *image) +{ + MonoClass *klass; + + /* + * Notes: + * - can't put all wrappers into an mscorlib class, because they reference + * metadata (signature) so they should be put into the same image as the + * method they wrap, so they are unloaded together. + * - putting them into a class with a type initalizer could cause the + * initializer to be executed which can be a problem if the wrappers are + * shared. + * - putting them into an inflated class can cause problems if the the + * class is deleted because it references an image which is unloaded. + * To avoid these problems, we put the wrappers into the class of + * the image. + */ + if (image->dynamic) + klass = ((MonoDynamicImage*)image)->wrappers_type; + else + klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1)); + g_assert (klass); + + return klass; } MonoMethod * @@ -2314,7 +2531,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method) g_assert (sig->hasthis); name = mono_signature_to_name (sig, "begin_invoke"); - mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE); + mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE); g_free (name); params_var = mono_mb_emit_save_args (mb, sig, FALSE); @@ -2361,10 +2578,12 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params) msg = mono_method_call_message_new (method, params, NULL, NULL, NULL); ares = mono_array_get (msg->args, gpointer, sig->param_count - 1); - if (ares == NULL) + if (ares == NULL) { mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type.")); + return NULL; + } - if (ares->async_delegate != (MonoObject*)delegate && mono_framework_version () >= 2) { + if (ares->async_delegate != (MonoObject*)delegate) { mono_raise_exception (mono_get_exception_invalid_operation ( "The IAsyncResult object provided does not match this delegate.")); return NULL; @@ -2435,7 +2654,7 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type) mono_mb_emit_byte (mb, mono_type_to_ldind (return_type)); break; case MONO_TYPE_GENERICINST: - if (!mono_type_generic_inst_is_valuetype (return_type)) + if (!mono_type_generic_inst_is_valuetype (t)) break; /* fall through */ case MONO_TYPE_VALUETYPE: { @@ -2476,7 +2695,7 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method) g_assert (sig->hasthis); name = mono_signature_to_name (sig, "end_invoke"); - mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_END_INVOKE); + mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_END_INVOKE); g_free (name); params_var = mono_mb_emit_save_args (mb, sig, FALSE); @@ -2567,12 +2786,17 @@ mono_marshal_get_remoting_invoke (MonoMethod *method) return method; /* this seems to be the best plase to put this, as all remoting invokes seem to get filtered through here */ - if ((method->klass->is_com_object || method->klass == mono_defaults.com_object_class) && !mono_class_vtable (mono_domain_get (), method->klass)->remote) { + if (method->klass->is_com_object || method->klass == mono_defaults.com_object_class) { + MonoVTable *vtable = mono_class_vtable (mono_domain_get (), method->klass); + g_assert (vtable); /*FIXME do proper error handling*/ + + if (!vtable->remote) { #ifndef DISABLE_COM - return mono_cominterop_get_invoke (method); + return mono_cominterop_get_invoke (method); #else - g_assert_not_reached (); + g_assert_not_reached (); #endif + } } sig = mono_signature_no_pinvoke (method); @@ -2648,7 +2872,7 @@ mono_get_xdomain_marshal_type (MonoType *t) /* mono_marshal_xdomain_copy_value * Makes a copy of "val" suitable for the current domain. */ -static MonoObject * +MonoObject * mono_marshal_xdomain_copy_value (MonoObject *val) { MonoDomain *domain; @@ -3023,6 +3247,8 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_ldloc (mb, loc_array); mono_mb_emit_icon (mb, complex_count); /* The array has an additional slot to hold the ret value */ mono_mb_emit_ldloc (mb, loc_return); + + g_assert (ret_class); /*FIXME properly fail here*/ if (ret_class->valuetype) { mono_mb_emit_op (mb, CEE_BOX, ret_class); } @@ -3425,6 +3651,8 @@ mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTar } else { return mono_marshal_get_remoting_invoke (method); } + /* Not erached */ + return NULL; } G_GNUC_UNUSED static gpointer @@ -3537,6 +3765,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) MonoMethod *target_method = NULL; MonoClass *target_class = NULL; gboolean callvirt = FALSE; + gboolean closed_over_null = FALSE; /* * If the delegate target is null, and the target method is not static, a virtual @@ -3563,6 +3792,9 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) sig = mono_signature_no_pinvoke (method); + if (callvirt) + closed_over_null = sig->param_count == mono_method_signature (del->method)->param_count; + if (callvirt) { /* We need to cache the signature+method pair */ mono_marshal_lock (); @@ -3587,7 +3819,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) static_sig->hasthis = 0; name = mono_signature_to_name (sig, "invoke"); - mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_INVOKE); + mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_INVOKE); g_free (name); /* allocate local 0 (object) */ @@ -3660,11 +3892,18 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) mono_mb_patch_branch (mb, pos0); if (callvirt) { - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_op (mb, CEE_CASTCLASS, target_class); - for (i = 1; i < sig->param_count; ++i) - mono_mb_emit_ldarg (mb, i + 1); - mono_mb_emit_op (mb, CEE_CALLVIRT, target_method); + if (!closed_over_null) { + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_op (mb, CEE_CASTCLASS, target_class); + for (i = 1; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALLVIRT, target_method); + } else { + mono_mb_emit_byte (mb, CEE_LDNULL); + for (i = 0; i < sig->param_count; ++i) + mono_mb_emit_ldarg (mb, i + 1); + mono_mb_emit_op (mb, CEE_CALL, target_method); + } } else { for (i = 0; i < sig->param_count; ++i) mono_mb_emit_ldarg (mb, i + 1); @@ -3690,7 +3929,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) new_key->sig = sig; new_key->method = target_method; g_hash_table_insert (cache, new_key, res); - mono_marshal_method_set_wrapper_data (res, new_key); + mono_marshal_set_wrapper_info (res, new_key); mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -3717,7 +3956,7 @@ signature_dup_add_this (MonoMethodSignature *sig, MonoClass *klass) int i; res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1); - memcpy (res, sig, sizeof (MonoMethodSignature)); + memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE); res->param_count = sig->param_count + 1; res->hasthis = FALSE; for (i = sig->param_count - 1; i >= 0; i --) @@ -3776,12 +4015,37 @@ add_string_ctor_signature (MonoMethod *method) return callsig; } +/* + * mono_marshal_get_string_ctor_signature: + * + * Return the modified signature used by string ctors (they return the newly created + * string). + */ +MonoMethodSignature* +mono_marshal_get_string_ctor_signature (MonoMethod *method) +{ + MonoMethodSignature *sig = lookup_string_ctor_signature (mono_method_signature (method)); + if (!sig) + sig = add_string_ctor_signature (method); + + return sig; +} + static MonoType* -get_runtime_invoke_type (MonoType *t) +get_runtime_invoke_type (MonoType *t, gboolean ret) { if (t->byref) - return &mono_defaults.int_class->byval_arg; + /* Can't share this with 'I' as that needs another indirection */ + return t; + + if (MONO_TYPE_IS_REFERENCE (t)) + return &mono_defaults.object_class->byval_arg; + if (ret) + /* The result needs to be boxed */ + return t; + +handle_enum: switch (t->type) { case MONO_TYPE_U1: return &mono_defaults.sbyte_class->byval_arg; @@ -3792,16 +4056,19 @@ get_runtime_invoke_type (MonoType *t) case MONO_TYPE_U8: return &mono_defaults.int64_class->byval_arg; case MONO_TYPE_BOOLEAN: - return &mono_defaults.byte_class->byval_arg; + return &mono_defaults.sbyte_class->byval_arg; case MONO_TYPE_CHAR: return &mono_defaults.int16_class->byval_arg; case MONO_TYPE_U: + case MONO_TYPE_PTR: return &mono_defaults.int_class->byval_arg; case MONO_TYPE_VALUETYPE: + if (t->data.klass->enumtype) { + t = mono_class_enum_basetype (t->data.klass); + goto handle_enum; + } return t; default: - if (MONO_TYPE_IS_REFERENCE (t)) - return &mono_defaults.object_class->byval_arg; return t; } } @@ -3817,9 +4084,9 @@ mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig) MonoMethodSignature *res = mono_metadata_signature_dup (sig); int i; - res->ret = get_runtime_invoke_type (sig->ret); + res->ret = get_runtime_invoke_type (sig->ret, TRUE); for (i = 0; i < res->param_count; ++i) - res->params [i] = get_runtime_invoke_type (sig->params [i]); + res->params [i] = get_runtime_invoke_type (sig->params [i], FALSE); return res; } @@ -3828,7 +4095,7 @@ static gboolean runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2) { /* Can't share wrappers which return a vtype since it needs to be boxed */ - if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret))) + if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)) && !mono_metadata_type_equal (sig1->ret, sig2->ret)) return FALSE; else return mono_metadata_signature_equal (sig1, sig2); @@ -3856,7 +4123,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) static MonoString *string_dummy = NULL; static MonoMethodSignature *cctor_signature = NULL; static MonoMethodSignature *finalize_signature = NULL; - int i, pos, posna; + int i, pos; char *name; gboolean need_direct_wrapper = FALSE; int *tmp_nullable_locals; @@ -3910,6 +4177,8 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) * Create a new signature to reflect this. */ callsig = signature_dup_add_this (mono_method_signature (method), method->klass); + /* Can't share this as it would be shared with static methods taking an IntPtr argument */ + need_direct_wrapper = TRUE; } else { if (method->dynamic) callsig = signature_dup (method->klass->image, mono_method_signature (method)); @@ -3918,48 +4187,22 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) } } - /* Vtypes/nullables/Byrefs cause too many problems */ - for (i = 0; i < callsig->param_count; ++i) { - if (MONO_TYPE_ISSTRUCT (callsig->params [i]) || callsig->params [i]->byref) - need_direct_wrapper = TRUE; - } + target_klass = get_wrapper_target_class (method->klass->image); - /* - * We try to share runtime invoke wrappers between different methods but have to - * be careful about methods whose klass has a type cctor, since putting the wrapper - * into that klass would mean that calling a method of klass A might invoke the - * type initializer of class B, or throw an exception if the type initializer - * was called before and failed. See #349621 for an example. - * We avoid that for mscorlib methods by putting every wrapper into the object class. - */ - if (method->klass->image == mono_defaults.corlib) + /* Try to share wrappers for non-corlib methods with simple signatures */ + if (mono_metadata_signature_equal (callsig, cctor_signature)) { + callsig = cctor_signature; + target_klass = mono_defaults.object_class; + } else if (mono_metadata_signature_equal (callsig, finalize_signature)) { + callsig = finalize_signature; target_klass = mono_defaults.object_class; - else { - /* Try to share wrappers for non-corlib methods with simple signatures */ - if (mono_metadata_signature_equal (callsig, cctor_signature)) { - callsig = cctor_signature; - target_klass = mono_defaults.object_class; - } else if (mono_metadata_signature_equal (callsig, finalize_signature)) { - callsig = finalize_signature; - target_klass = mono_defaults.object_class; - } else { - // FIXME: This breaks too many things - /* - if (mono_class_get_cctor (method->klass)) - need_direct_wrapper = TRUE; - */ - - /* - * Can't put these wrappers into object, since they reference non-corlib - * metadata (callsig). - */ - target_klass = method->klass; - } } if (need_direct_wrapper) { /* Already searched at the start */ } else { + MonoMethodSignature *tmp_sig; + callsig = mono_marshal_get_runtime_invoke_sig (callsig); cache = get_cache (&target_klass->image->runtime_invoke_cache, @@ -3976,9 +4219,12 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) return res; } - // FIXME: When to free callsig ? + /* Make a copy of the signature from the image mempool */ + tmp_sig = callsig; + callsig = mono_metadata_signature_dup_full (target_klass->image, callsig); + g_free (tmp_sig); } - + /* to make it work with our special string constructors */ if (!string_dummy) { MONO_GC_REGISTER_ROOT (string_dummy); @@ -4007,14 +4253,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) /* allocate local 1 (object) exc */ mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - /* cond set *exc to null */ - mono_mb_emit_byte (mb, CEE_LDARG_2); - mono_mb_emit_byte (mb, CEE_BRFALSE_S); - mono_mb_emit_byte (mb, 3); - mono_mb_emit_byte (mb, CEE_LDARG_2); - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - emit_thread_force_interrupt_checkpoint (mb); if (virtual) { @@ -4057,6 +4295,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) continue; } + /*FIXME 'this doesn't handle generic enums. Shouldn't we?*/ type = sig->params [i]->type; handle_enum: switch (type) { @@ -4087,7 +4326,7 @@ handle_enum: break; case MONO_TYPE_GENERICINST: if (!mono_type_generic_inst_is_valuetype (sig->params [i])) { - mono_mb_emit_byte (mb, CEE_LDIND_I); + mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i])); break; } @@ -4125,7 +4364,6 @@ handle_enum: g_assert_not_reached (); } - switch (sig->ret->type) { case MONO_TYPE_VOID: if (!method->string_ctor) @@ -4159,6 +4397,9 @@ handle_enum: /* nothing to do */ break; case MONO_TYPE_PTR: + /* The result is an IntPtr */ + mono_mb_emit_op (mb, CEE_BOX, mono_defaults.int_class); + break; default: g_assert_not_reached (); } @@ -4215,15 +4456,6 @@ handle_enum: mono_mb_emit_byte (mb, CEE_LDNULL); mono_mb_emit_stloc (mb, 0); - /* Check for the abort exception */ - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_op (mb, CEE_ISINST, mono_defaults.threadabortexception_class); - posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - /* Delay the abort exception */ - mono_mb_emit_icall (mb, ves_icall_System_Threading_Thread_ResetAbort); - - mono_mb_patch_short_branch (mb, posna); mono_mb_emit_branch (mb, CEE_LEAVE); clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; @@ -4235,6 +4467,8 @@ handle_enum: mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_RET); + g_free (tmp_nullable_locals); + if (need_direct_wrapper) { mb->skip_visibility = 1; res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16); @@ -4262,68 +4496,133 @@ handle_enum: mono_marshal_unlock (); } - /* end mono_mb_create_and_cache */ - } + /* end mono_mb_create_and_cache */ + } + + mono_mb_free (mb); + + return res; +} + +/* + * mono_marshal_get_runtime_invoke_dynamic: + * + * Return a method which can be used to invoke managed methods from native code + * dynamically. + * The signature of the returned method is given by RuntimeInvokeDynamicFunction: + * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method) + * ARGS should point to an architecture specific structure containing + * the arguments and space for the return value. + * The other arguments are the same as for runtime_invoke (), except that + * ARGS should contain the this argument too. + * This wrapper serves the same purpose as the runtime-invoke wrappers, but there + * is only one copy of it, which is useful in full-aot. + */ +MonoMethod* +mono_marshal_get_runtime_invoke_dynamic (void) +{ + static MonoMethod *method; + MonoMethodSignature *csig; + MonoExceptionClause *clause; + MonoMethodBuilder *mb; + int pos, posna; + char *name; + + if (method) + return method; + + csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4); + + csig->ret = &mono_defaults.void_class->byval_arg; + csig->params [0] = &mono_defaults.int_class->byval_arg; + csig->params [1] = &mono_defaults.int_class->byval_arg; + csig->params [2] = &mono_defaults.int_class->byval_arg; + csig->params [3] = &mono_defaults.int_class->byval_arg; + + name = g_strdup ("runtime_invoke_dynamic"); + mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_RUNTIME_INVOKE); + g_free (name); + + /* allocate local 0 (object) tmp */ + mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + /* allocate local 1 (object) exc */ + mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + + /* cond set *exc to null */ + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_byte (mb, CEE_BRFALSE_S); + mono_mb_emit_byte (mb, 3); + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + emit_thread_force_interrupt_checkpoint (mb); + + mono_mb_emit_byte (mb, CEE_LDARG_0); + mono_mb_emit_byte (mb, CEE_LDARG_2); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_DYN_CALL); + + pos = mono_mb_emit_branch (mb, CEE_LEAVE); + + clause = mono_image_alloc0 (mono_defaults.corlib, sizeof (MonoExceptionClause)); + clause->flags = MONO_EXCEPTION_CLAUSE_FILTER; + clause->try_len = mono_mb_get_label (mb); + + /* filter code */ + clause->data.filter_offset = mono_mb_get_label (mb); + + mono_mb_emit_byte (mb, CEE_POP); + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_CGT_UN); + mono_mb_emit_byte (mb, CEE_PREFIX1); + mono_mb_emit_byte (mb, CEE_ENDFILTER); + + clause->handler_offset = mono_mb_get_label (mb); - mono_mb_free (mb); + /* handler code */ + /* store exception */ + mono_mb_emit_stloc (mb, 1); + + mono_mb_emit_byte (mb, CEE_LDARG_1); + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_byte (mb, CEE_STIND_REF); - return res; -} + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, 0); -/* - * mono_marshal_get_static_rgctx_invoke: - * @method: a method - * - * Generates a wrapper for calling a generic shared method, either - * static or generic. We need this for virtual generic method lookup - * and ldftn when we do generic code sharing. Instead of producing - * the address of the method we produce the address of a wrapper for - * the method because the wrapper passes the (method) runtime generic - * context argument which calli cannot do. - */ -MonoMethod * -mono_marshal_get_static_rgctx_invoke (MonoMethod *method) -{ - static gboolean inited = FALSE; - static int num_wrappers = 0; + /* Check for the abort exception */ + mono_mb_emit_ldloc (mb, 1); + mono_mb_emit_op (mb, CEE_ISINST, mono_defaults.threadabortexception_class); + posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - MonoMethodBuilder *mb; - MonoMethod *res; - MonoClass *target_klass = method->klass; - MonoMethodSignature *sig = mono_method_signature (method); - int i; - char *name; - GHashTable *cache; - MonoImage *image = method->klass->image; + /* Delay the abort exception */ + mono_mb_emit_icall (mb, ves_icall_System_Threading_Thread_ResetAbort); - cache = get_cache (&image->static_rgctx_invoke_cache, mono_aligned_addr_hash, NULL); - if ((res = mono_marshal_find_in_cache (cache, method))) - return res; + mono_mb_patch_short_branch (mb, posna); + mono_mb_emit_branch (mb, CEE_LEAVE); - if (!inited) { - mono_counters_register ("Static rgctx invoke wrappers", - MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_wrappers); - inited = TRUE; - } - ++num_wrappers; + clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; - name = mono_signature_to_name (mono_method_signature (method), "static_rgctx_invoke"); - mb = mono_mb_new (target_klass, name, MONO_WRAPPER_STATIC_RGCTX_INVOKE); - g_free (name); + mono_mb_set_clauses (mb, 1, clause); - for (i = 0; i < sig->param_count + sig->hasthis; i++) - mono_mb_emit_ldarg (mb, i); - mono_mb_emit_op (mb, CEE_CALL, method); + /* return result */ + mono_mb_patch_branch (mb, pos); + //mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_RET); - mb->skip_visibility = TRUE; - res = mono_mb_create_and_cache (cache, method, mb, mono_method_signature (method), - sig->param_count + sig->hasthis + 4); - res->flags = method->flags; + mono_loader_lock (); + /* double-checked locking */ + if (!method) { + method = mono_mb_create_method (mb, csig, 16); + } + mono_loader_unlock (); mono_mb_free (mb); - return res; + return method; } static void @@ -4887,7 +5186,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type) MonoMethod * mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions) { - MonoMethodSignature *csig; + MonoMethodSignature *csig, *csig2; MonoMethodBuilder *mb; MonoMethod *res; int i; @@ -4898,7 +5197,11 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon mb->method->save_lmf = 1; - /* we copy the signature, so that we can modify it */ + /* Add an explicit this argument */ + if (sig->hasthis) + csig2 = signature_dup_add_this (sig, mono_defaults.object_class); + else + csig2 = signature_dup (mono_defaults.corlib, sig); if (sig->hasthis) mono_mb_emit_byte (mb, CEE_LDARG_0); @@ -4906,7 +5209,7 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon for (i = 0; i < sig->param_count; i++) mono_mb_emit_ldarg (mb, i + sig->hasthis); - mono_mb_emit_native_call (mb, sig, (gpointer) func); + mono_mb_emit_native_call (mb, csig2, (gpointer) func); if (check_exceptions) emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); @@ -5274,13 +5577,44 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, MarshalAction action) { MonoMethodBuilder *mb = m->mb; - MonoClass *klass; + MonoClass *klass, *date_time_class; int pos = 0, pos2; klass = mono_class_from_mono_type (t); + date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime"); + switch (action) { case MARSHAL_ACTION_CONV_IN: + if (klass == date_time_class) { + /* Convert it to an OLE DATE type */ + static MonoMethod *to_oadate; + + if (!to_oadate) + to_oadate = mono_class_get_method_from_name (date_time_class, "ToOADate", 0); + g_assert (to_oadate); + + conv_arg = mono_mb_add_local (mb, &mono_defaults.double_class->byval_arg); + + if (t->byref) { + mono_mb_emit_ldarg (mb, argnum); + pos = mono_mb_emit_branch (mb, CEE_BRFALSE); + } + + if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + if (!t->byref) + m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.double_class->byval_arg; + + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, to_oadate, NULL); + mono_mb_emit_stloc (mb, conv_arg); + } + + if (t->byref) + mono_mb_patch_branch (mb, pos); + break; + } + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable || klass->enumtype) break; @@ -5336,6 +5670,14 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; } + if (klass == date_time_class) { + if (t->byref) + mono_mb_emit_ldloc_addr (mb, conv_arg); + else + mono_mb_emit_ldloc (mb, conv_arg); + break; + } + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable || klass->enumtype) { mono_mb_emit_ldarg (mb, argnum); @@ -5349,6 +5691,26 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_CONV_OUT: + if (klass == date_time_class) { + /* Convert from an OLE DATE type */ + static MonoMethod *from_oadate; + + if (!t->byref) + break; + + if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) { + if (!from_oadate) + from_oadate = mono_class_get_method_from_name (date_time_class, "FromOADate", 1); + g_assert (from_oadate); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_managed_call (mb, from_oadate, NULL); + mono_mb_emit_op (mb, CEE_STOBJ, date_time_class); + } + break; + } + if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable || klass->enumtype) break; @@ -5383,6 +5745,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 3); break; } + /* load pointer to returned value type */ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); mono_mb_emit_byte (mb, CEE_MONO_VTADDR); @@ -5519,7 +5882,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, if (conv == -1) { char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); MonoException *exc = mono_get_exception_not_implemented (msg); - g_warning (msg); + g_warning ("%s", msg); g_free (msg); mono_raise_exception (exc); } @@ -5888,7 +6251,14 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec); MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec); - g_assert (!t->byref); + if (t->byref) { + if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { + char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + } + break; + } + mono_mb_emit_ldarg (mb, argnum); if (conv != -1) @@ -5896,7 +6266,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, else { char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding); MonoException *exc = mono_get_exception_not_implemented (msg); - g_warning (msg); + g_warning ("%s", msg); g_free (msg); mono_raise_exception (exc); } @@ -5976,13 +6346,34 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, encoding = mono_marshal_get_string_encoding (m->piinfo, spec); conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free); - g_assert (!t->byref); g_assert (encoding != -1); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); + if (t->byref) { + g_assert ((t->attrs & PARAM_ATTRIBUTE_OUT)); - mono_mb_emit_icall (mb, conv_to_icall (conv)); + need_free = TRUE; + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + switch (encoding) { + case MONO_NATIVE_LPWSTR: + mono_mb_emit_icall (mb, mono_string_utf16_to_builder2); + break; + case MONO_NATIVE_LPSTR: + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + break; + default: + g_assert_not_reached (); + } + + mono_mb_emit_byte (mb, CEE_STIND_REF); + } else { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + + mono_mb_emit_icall (mb, conv_to_icall (conv)); + } if (need_free) { mono_mb_emit_ldloc (mb, conv_arg); @@ -6476,7 +6867,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, if (conv == -1) { char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding); MonoException *exc = mono_get_exception_not_implemented (msg); - g_warning (msg); + g_warning ("%s", msg); g_free (msg); mono_raise_exception (exc); } @@ -6672,6 +7063,15 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_patch_branch (mb, label1); mono_mb_patch_branch (mb, label3); } + + if (klass->element_class->blittable) { + /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */ + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY)); + } + break; case MARSHAL_ACTION_PUSH: @@ -6796,15 +7196,15 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t, * from 0. */ - if (param_num == -1) + if (param_num == -1) { mono_mb_emit_icon (mb, num_elem); - else { - /* FIXME: Add the two together */ + } else { mono_mb_emit_ldarg (mb, param_num); if (num_elem > 0) { mono_mb_emit_icon (mb, num_elem); mono_mb_emit_byte (mb, CEE_ADD); } + mono_mb_emit_byte (mb, CEE_CONV_OVF_I); } mono_mb_emit_op (mb, CEE_NEWARR, eklass); @@ -7096,9 +7496,9 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, switch (action) { case MARSHAL_ACTION_CONV_IN: { MonoType *local_type; - int variant_bool = 0; - if (!t->byref) - break; + int label_false; + guint8 ldc_op = CEE_LDC_I4_1; + if (spec == NULL) { local_type = &mono_defaults.int32_class->byval_arg; } else { @@ -7109,7 +7509,10 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, break; case MONO_NATIVE_VARIANTBOOL: local_type = &mono_defaults.int16_class->byval_arg; - variant_bool = 1; + ldc_op = CEE_LDC_I4_M1; + break; + case MONO_NATIVE_BOOLEAN: + local_type = &mono_defaults.int32_class->byval_arg; break; default: g_warning ("marshalling bool as native type %x is currently not supported", spec->native); @@ -7117,29 +7520,49 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, break; } } - *conv_arg_type = &mono_defaults.int_class->byval_arg; + if (t->byref) + *conv_arg_type = &mono_defaults.int_class->byval_arg; + else + *conv_arg_type = local_type; conv_arg = mono_mb_add_local (mb, local_type); + mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I1); - if (variant_bool) - mono_mb_emit_byte (mb, CEE_NEG); + if (t->byref) + mono_mb_emit_byte (mb, CEE_LDIND_I1); + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, ldc_op); mono_mb_emit_stloc (mb, conv_arg); + mono_mb_patch_branch (mb, label_false); + break; } case MARSHAL_ACTION_CONV_OUT: + { + int label_false, label_end; if (!t->byref) break; + mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL) - mono_mb_emit_byte (mb, CEE_NEG); + + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); + + label_end = mono_mb_emit_branch (mb, CEE_BR); + mono_mb_patch_branch (mb, label_false); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_patch_branch (mb, label_end); + mono_mb_emit_byte (mb, CEE_STIND_I1); break; + } case MARSHAL_ACTION_PUSH: if (t->byref) mono_mb_emit_ldloc_addr (mb, conv_arg); + else if (conv_arg) + mono_mb_emit_ldloc (mb, conv_arg); else mono_mb_emit_ldarg (mb, argnum); break; @@ -7150,27 +7573,21 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_MANAGED_CONV_IN: { - gint variant_bool = 0; + MonoClass* conv_arg_class = mono_defaults.int32_class; guint8 ldop = CEE_LDIND_I4; - int label1; - - if (!t->byref) - break; + int label_null, label_false; conv_arg = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); - *conv_arg_type = &mono_defaults.int32_class->byval_arg; - if (spec) { switch (spec->native) { case MONO_NATIVE_I1: case MONO_NATIVE_U1: - *conv_arg_type = &mono_defaults.byte_class->this_arg; + conv_arg_class = mono_defaults.byte_class; ldop = CEE_LDIND_I1; break; case MONO_NATIVE_VARIANTBOOL: - *conv_arg_type = &mono_defaults.int16_class->this_arg; - variant_bool = 1; + conv_arg_class = mono_defaults.int16_class; ldop = CEE_LDIND_I2; break; case MONO_NATIVE_BOOLEAN: @@ -7180,24 +7597,36 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, } } - /* Check null */ + if (t->byref) + *conv_arg_type = &conv_arg_class->this_arg; + else + *conv_arg_type = &conv_arg_class->byval_arg; + + mono_mb_emit_ldarg (mb, argnum); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, ldop); + /* Check null */ + if (t->byref) { + label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, ldop); + } else + label_null = 0; - if (variant_bool) - mono_mb_emit_byte (mb, CEE_NEG); + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, CEE_LDC_I4_1); mono_mb_emit_stloc (mb, conv_arg); + mono_mb_patch_branch (mb, label_false); - mono_mb_patch_branch (mb, label1); + if (t->byref) + mono_mb_patch_branch (mb, label_null); break; } case MARSHAL_ACTION_MANAGED_CONV_OUT: { guint8 stop = CEE_STIND_I4; - int label1; + guint8 ldc_op = CEE_LDC_I4_1; + int label_null,label_false, label_end;; if (!t->byref) break; @@ -7209,6 +7638,7 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, break; case MONO_NATIVE_VARIANTBOOL: stop = CEE_STIND_I2; + ldc_op = CEE_LDC_I4_M1; break; default: break; @@ -7217,15 +7647,21 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, /* Check null */ mono_mb_emit_ldarg (mb, argnum); - label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + label_null = mono_mb_emit_branch (mb, CEE_BRFALSE); mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL) - mono_mb_emit_byte (mb, CEE_NEG); - mono_mb_emit_byte (mb, stop); - mono_mb_patch_branch (mb, label1); + label_false = mono_mb_emit_branch (mb, CEE_BRFALSE); + mono_mb_emit_byte (mb, ldc_op); + label_end = mono_mb_emit_branch (mb, CEE_BR); + + mono_mb_patch_branch (mb, label_false); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_patch_branch (mb, label_end); + + mono_mb_emit_byte (mb, stop); + mono_mb_patch_branch (mb, label_null); break; } @@ -7350,6 +7786,10 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, spec->native == MONO_NATIVE_IDISPATCH || spec->native == MONO_NATIVE_INTERFACE)) return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); + if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) && + (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) && + ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH))) + return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action); #endif if (mono_defaults.safehandle_class != NULL && t->data.klass && @@ -7492,7 +7932,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM get_last_error_sig->pinvoke = 1; } -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 /* * Have to call GetLastError () early and without a wrapper, since various runtime components could * clobber its value. @@ -7596,6 +8036,12 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM mono_mb_emit_byte (mb, CEE_RET); } +G_GNUC_UNUSED static void +code_for (MonoMethod *method) { + MonoMethodHeader *header = mono_method_get_header (method); + printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (method, TRUE), mono_disasm_code (0, method, header->code, header->code + header->code_size)); +} + /** * mono_marshal_get_native_wrapper: * @method: The MonoMethod to wrap. @@ -7716,16 +8162,29 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, /* internal calls: we simply push all arguments and call the method (no conversions) */ if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) { + if (sig->hasthis) + csig = signature_dup_add_this (sig, method->klass); + else + csig = signature_dup (method->klass->image, sig); /* hack - string constructors returns a value */ - if (method->string_ctor) { - csig = signature_dup (method->klass->image, sig); + if (method->string_ctor) csig->ret = &mono_defaults.string_class->byval_arg; - } else - csig = sig; - if (sig->hasthis) + if (sig->hasthis) { + int pos; + + /* + * Add a null check since public icalls can be called with 'call' which + * does no such check. + */ + mono_mb_emit_byte (mb, CEE_LDARG_0); + pos = mono_mb_emit_branch (mb, CEE_BRTRUE); + mono_mb_emit_exception (mb, "NullReferenceException", NULL); + mono_mb_patch_branch (mb, pos); + mono_mb_emit_byte (mb, CEE_LDARG_0); + } for (i = 0; i < sig->param_count; i++) mono_mb_emit_ldarg (mb, i + sig->hasthis); @@ -7770,7 +8229,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, mono_metadata_free_marshal_spec (mspecs [i]); g_free (mspecs); - /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */ + /* code_for (res); */ return res; } @@ -7811,17 +8270,27 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig mb, csig, csig->param_count + 16); mono_mb_free (mb); - /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */ + mono_marshal_set_wrapper_info (res, NULL); + + /* code_for (res); */ return res; } -/* FIXME: moving GC */ +/* + * mono_marshal_emit_managed_wrapper: + * + * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of + * the delegate which wraps the managed method to be called. For closed delegates, + * it could have fewer parameters than the method it wraps. + * THIS_LOC is the memory location where the target of the delegate is stored. + */ void -mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this) +mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle) { MonoMethodSignature *sig, *csig; int i, *tmp_locals; + gboolean closed = FALSE; sig = m->sig; csig = m->csig; @@ -7833,6 +8302,16 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i /* allocate local 2 (boolean) delete_old */ mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + if (!sig->hasthis && sig->param_count != invoke_sig->param_count) { + /* Closed delegate */ + g_assert (sig->param_count == invoke_sig->param_count + 1); + closed = TRUE; + /* Use a new signature without the first argument */ + sig = mono_metadata_signature_dup (sig); + memmove (&sig->params [0], &sig->params [1], (sig->param_count - 1) * sizeof (MonoType*)); + sig->param_count --; + } + if (!MONO_TYPE_IS_VOID(sig->ret)) { /* allocate local 3 to store the return value */ mono_mb_add_local (mb, sig->ret); @@ -7845,7 +8324,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i tmp_locals = alloca (sizeof (int) * sig->param_count); for (i = 0; i < sig->param_count; i ++) { MonoType *t = sig->params [i]; - + switch (t->type) { case MONO_TYPE_OBJECT: case MONO_TYPE_CLASS: @@ -7865,16 +8344,18 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i emit_thread_interrupt_checkpoint (mb); - /* fixme: howto handle this ? */ if (sig->hasthis) { - if (this) { - /* FIXME: need a solution for the moving GC here */ - mono_mb_emit_ptr (mb, this); + if (target_handle) { + mono_mb_emit_icon (mb, (gint32)target_handle); + mono_mb_emit_icall (mb, mono_gchandle_get_target); } else { /* fixme: */ g_assert_not_reached (); } - } + } else if (closed) { + mono_mb_emit_icon (mb, (gint32)target_handle); + mono_mb_emit_icall (mb, mono_gchandle_get_target); + } for (i = 0; i < sig->param_count; i++) { MonoType *t = sig->params [i]; @@ -7893,9 +8374,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) { emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT); - } - else - if (!sig->ret->byref) { + } else if (!sig->ret->byref) { switch (sig->ret->type) { case MONO_TYPE_VOID: break; @@ -7977,6 +8456,9 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i mono_mb_emit_ldloc (mb, 3); mono_mb_emit_byte (mb, CEE_RET); } + + if (closed) + g_free (sig); } @@ -7986,7 +8468,7 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature * MonoMethodSignature *sig; int i; -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 /* * Under windows, delegates passed to native code must use the STDCALL * calling convention. @@ -8020,7 +8502,7 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature * * generates IL code to call managed methods from unmanaged code */ MonoMethod * -mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this) +mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle) { static MonoClass *UnmanagedFunctionPointerAttribute; MonoMethodSignature *sig, *csig, *invoke_sig; @@ -8041,10 +8523,10 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, * options. */ cache = get_cache (&method->klass->image->managed_wrapper_cache, mono_aligned_addr_hash, NULL); - if (!this && (res = mono_marshal_find_in_cache (cache, method))) + if (!target_handle && (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 = mono_get_delegate_invoke (delegate_klass); invoke_sig = mono_method_signature (invoke); mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1); @@ -8054,13 +8536,15 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED); + /*the target gchandle must be the first entry after size and the wrapper itself.*/ + mono_mb_add_data (mb, GUINT_TO_POINTER (target_handle)); /* we copy the signature, so that we can modify it */ - if (this) + if (target_handle) /* Need to free this later */ - csig = mono_metadata_signature_dup (sig); + csig = mono_metadata_signature_dup (invoke_sig); else - csig = signature_dup (method->klass->image, sig); + csig = signature_dup (method->klass->image, invoke_sig); csig->hasthis = 0; csig->pinvoke = 1; @@ -8079,31 +8563,78 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, /* The attribute is only available in Net 2.0 */ if (UnmanagedFunctionPointerAttribute) { - MonoReflectionUnmanagedFunctionPointerAttribute *attr; MonoCustomAttrInfo *cinfo; + MonoCustomAttrEntry *attr; /* - * The pinvoke attributes are stored in a real custom attribute so we have to - * construct it. + * The pinvoke attributes are stored in a real custom attribute. Obtain the + * contents of the attribute without constructing it, as that might not be + * possible when running in cross-compiling mode. */ cinfo = mono_custom_attrs_from_class (delegate_klass); + attr = NULL; 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; + for (i = 0; i < cinfo->num_attrs; ++i) { + if (mono_class_has_parent (cinfo->attrs [i].ctor->klass, UnmanagedFunctionPointerAttribute)) { + attr = &cinfo->attrs [i]; + break; + } + } + } + if (attr) { + MonoArray *typed_args, *named_args; + CattrNamedArg *arginfo; + MonoObject *o; + gint32 call_conv; + gint32 charset = 0; + MonoBoolean set_last_error = 0; + MonoBoolean best_fit_mapping = 0; + MonoBoolean throw_on_unmappable = 0; + + mono_reflection_create_custom_attr_data_args (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo); + + g_assert (mono_array_length (typed_args) == 1); + + /* typed args */ + o = mono_array_get (typed_args, MonoObject*, 0); + call_conv = *(gint32*)mono_object_unbox (o); + + /* named args */ + for (i = 0; i < mono_array_length (named_args); ++i) { + CattrNamedArg *narg = &arginfo [i]; + + o = mono_array_get (named_args, MonoObject*, i); + + g_assert (narg->field); + if (!strcmp (narg->field->name, "CharSet")) { + charset = *(gint32*)mono_object_unbox (o); + } else if (!strcmp (narg->field->name, "SetLastError")) { + set_last_error = *(MonoBoolean*)mono_object_unbox (o); + } else if (!strcmp (narg->field->name, "BestFitMapping")) { + best_fit_mapping = *(MonoBoolean*)mono_object_unbox (o); + } else if (!strcmp (narg->field->name, "ThrowOnUnmappableChar")) { + throw_on_unmappable = *(MonoBoolean*)mono_object_unbox (o); + } else { + g_assert_not_reached (); + } } - if (!cinfo->cached) - mono_custom_attrs_free (cinfo); + + g_free (arginfo); + + memset (&piinfo, 0, sizeof (piinfo)); + m.piinfo = &piinfo; + piinfo.piflags = (call_conv << 8) | (charset ? (charset - 1) * 2 : 1) | set_last_error; + + csig->call_convention = call_conv - 1; } + + if (cinfo && !cinfo->cached) + mono_custom_attrs_free (cinfo); } - mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this); + mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle); - if (!this) + if (!target_handle) res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16); else { @@ -8117,7 +8648,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, mono_metadata_free_marshal_spec (mspecs [i]); g_free (mspecs); - /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */ + /* code_for (res); */ return res; } @@ -8162,7 +8693,7 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */ - mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, NULL); + mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, 0); mb->dynamic = 1; method = mono_mb_create_method (mb, csig, sig->param_count + 16); @@ -8752,7 +9283,7 @@ mono_marshal_get_unbox_wrapper (MonoMethod *method) mb, sig, sig->param_count + 16); mono_mb_free (mb); - /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */ + /* code_for (res); */ return res; } @@ -9048,6 +9579,8 @@ mono_marshal_get_array_address (int rank, int elem_size) } } if (!cached) { + ElementAddrWrapperInfo *info; + 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); @@ -9059,6 +9592,12 @@ mono_marshal_get_array_address (int rank, int elem_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; + + info = mono_image_alloc0 (mono_defaults.corlib, sizeof (ElementAddrWrapperInfo)); + info->rank = rank; + info->elem_size = elem_size; + + mono_marshal_set_wrapper_info (ret, info); } mono_marshal_unlock (); return ret; @@ -9069,7 +9608,7 @@ mono_marshal_alloc (gulong size) { gpointer res; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 res = CoTaskMemAlloc (size); #else res = g_try_malloc ((gulong)size); @@ -9082,7 +9621,7 @@ mono_marshal_alloc (gulong size) void mono_marshal_free (gpointer ptr) { -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 CoTaskMemFree (ptr); #else g_free (ptr); @@ -9399,6 +9938,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty type = rtype->type; klass = mono_class_from_mono_type (type); + if (!mono_class_init (klass)) + mono_raise_exception (mono_class_get_exception_for_failure (klass)); + layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK); if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { @@ -9479,6 +10021,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, M MonoObject * ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type) { + MonoClass *klass; MonoDomain *domain = mono_domain_get (); MonoObject *res; @@ -9487,7 +10030,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s MONO_CHECK_ARG_NULL (src); MONO_CHECK_ARG_NULL (type); - res = mono_object_new (domain, mono_class_from_mono_type (type->type)); + klass = mono_class_from_mono_type (type->type); + if (!mono_class_init (klass)) + mono_raise_exception (mono_class_get_exception_for_failure (klass)); + + res = mono_object_new (domain, klass); ptr_to_structure (src, res); @@ -9509,6 +10056,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t fname = mono_string_to_utf8 (field_name); klass = mono_class_from_mono_type (type->type); + if (!mono_class_init (klass)) + mono_raise_exception (mono_class_get_exception_for_failure (klass)); while (klass && match_index == -1) { MonoClassField* field; @@ -9551,7 +10100,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t gpointer ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string) { -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 char* tres, *ret; size_t len; tres = mono_string_to_utf8 (string); @@ -9577,7 +10126,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString if (string == NULL) return NULL; else { -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal ((mono_string_length (string) + 1) * 2); #else @@ -9622,7 +10171,7 @@ mono_struct_delete_old (MonoClass *klass, char *ptr) /* We assume this field points inside a MonoString */ break; case MONO_MARSHAL_CONV_STR_LPTSTR: -#ifdef PLATFORM_WIN32 +#ifdef TARGET_WIN32 /* We assume this field points inside a MonoString * on Win32 */ break; @@ -9651,6 +10200,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MONO_CHECK_ARG_NULL (type); klass = mono_class_from_mono_type (type->type); + if (!mono_class_init (klass)) + mono_raise_exception (mono_class_get_exception_for_failure (klass)); mono_struct_delete_old (klass, (char *)src); } @@ -9666,7 +10217,7 @@ 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 +#ifdef HOST_WIN32 res = GlobalAlloc (GMEM_FIXED, (gulong)size); #else res = g_try_malloc ((gulong)size); @@ -9687,7 +10238,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, i return NULL; } -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 res = GlobalReAlloc (ptr, (gulong)size, GMEM_MOVEABLE); #else res = g_try_realloc (ptr, (gulong)size); @@ -9703,7 +10254,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr) { MONO_ARCH_SAVE_REGS; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 GlobalFree (ptr); #else g_free (ptr); @@ -9715,7 +10266,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size) { MONO_ARCH_SAVE_REGS; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 return CoTaskMemAlloc (size); #else return g_try_malloc ((gulong)size); @@ -9727,7 +10278,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr) { MONO_ARCH_SAVE_REGS; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 CoTaskMemFree (ptr); #else g_free (ptr); @@ -9739,7 +10290,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, { MONO_ARCH_SAVE_REGS; -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 return CoTaskMemRealloc (ptr, size); #else return g_try_realloc (ptr, (gulong)size); @@ -9755,7 +10306,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement MonoDelegate* ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type) { - return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn); + MonoClass *klass = mono_type_get_class (type->type); + if (!mono_class_init (klass)) + mono_raise_exception (mono_class_get_exception_for_failure (klass)); + + return mono_ftnptr_to_delegate (klass, ftn); } /** @@ -9828,7 +10383,7 @@ mono_marshal_load_type_info (MonoClass* klass) layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK; /* The mempool is protected by the loader lock */ - info = mono_image_alloc0 (klass->image, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count); + info = mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count); info->num_fields = count; /* Try to find a size for this type in metadata */ @@ -10161,7 +10716,7 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_ case MONO_TYPE_STRING: switch (string_encoding) { case MONO_NATIVE_LPWSTR: - return mono_string_to_utf16 ((MonoString*)o); + return mono_marshal_string_to_utf16_copy ((MonoString*)o); break; case MONO_NATIVE_LPSTR: return mono_string_to_lpstr ((MonoString*)o); @@ -10383,7 +10938,7 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) /* dup & extend signature */ csig = mono_metadata_signature_alloc (image, param_count); - sig_size = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); + sig_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *); memcpy (csig, sig, sig_size); csig->param_count = param_count; csig->hasthis = 0; @@ -10507,12 +11062,92 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method) { g_assert (method->dynamic); - mono_marshal_lock (); + /* This could be called during shutdown */ + if (marshal_mutex_initialized) + mono_marshal_lock (); /* * FIXME: We currently leak the wrappers. Freeing them would be tricky as * they could be shared with other methods ? */ if (method->klass->image->runtime_invoke_direct_cache) g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method); - mono_marshal_unlock (); + if (marshal_mutex_initialized) + mono_marshal_unlock (); +} + +/* + * mono_marshal_free_inflated_wrappers: + * + * Free wrappers of the inflated method METHOD. + */ + +static gboolean +signature_method_pair_matches_signature (gpointer key, gpointer value, gpointer user_data) +{ + SignatureMethodPair *pair = (SignatureMethodPair*)key; + MonoMethodSignature *sig = (MonoMethodSignature*)user_data; + + return mono_metadata_signature_equal (pair->sig, sig); +} + +void +mono_marshal_free_inflated_wrappers (MonoMethod *method) +{ + MonoMethodSignature *sig = method->signature; + + g_assert (method->is_inflated); + + /* Ignore calls occuring late during cleanup. */ + if (!marshal_mutex_initialized) + return; + + mono_marshal_lock (); + /* + * FIXME: We currently leak the wrappers. Freeing them would be tricky as + * they could be shared with other methods ? + */ + + /* + * indexed by MonoMethodSignature + */ + /* FIXME: This could remove unrelated wrappers as well */ + if (sig && method->klass->image->delegate_begin_invoke_cache) + g_hash_table_remove (method->klass->image->delegate_begin_invoke_cache, sig); + if (sig && method->klass->image->delegate_end_invoke_cache) + g_hash_table_remove (method->klass->image->delegate_end_invoke_cache, sig); + if (sig && method->klass->image->delegate_invoke_cache) + g_hash_table_remove (method->klass->image->delegate_invoke_cache, sig); + if (sig && method->klass->image->runtime_invoke_cache) + g_hash_table_remove (method->klass->image->runtime_invoke_cache, sig); + + /* + * indexed by SignatureMethodPair + */ + if (sig && method->klass->image->delegate_abstract_invoke_cache) + g_hash_table_foreach_remove (method->klass->image->delegate_abstract_invoke_cache, + signature_method_pair_matches_signature, (gpointer)sig); + + /* + * indexed by MonoMethod pointers + */ + if (method->klass->image->runtime_invoke_direct_cache) + g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method); + if (method->klass->image->managed_wrapper_cache) + g_hash_table_remove (method->klass->image->managed_wrapper_cache, method); + if (method->klass->image->native_wrapper_cache) + g_hash_table_remove (method->klass->image->native_wrapper_cache, method); + if (method->klass->image->remoting_invoke_cache) + g_hash_table_remove (method->klass->image->remoting_invoke_cache, method); + if (method->klass->image->synchronized_cache) + g_hash_table_remove (method->klass->image->synchronized_cache, method); + if (method->klass->image->unbox_wrapper_cache) + g_hash_table_remove (method->klass->image->unbox_wrapper_cache, method); + if (method->klass->image->cominterop_invoke_cache) + g_hash_table_remove (method->klass->image->cominterop_invoke_cache, method); + if (method->klass->image->cominterop_wrapper_cache) + g_hash_table_remove (method->klass->image->cominterop_wrapper_cache, method); + if (method->klass->image->thunk_invoke_cache) + g_hash_table_remove (method->klass->image->thunk_invoke_cache, method); + + mono_marshal_unlock (); }