X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=6d321f9f6a4b48e498b439ab808c203111c97696;hb=e0e4793cf9f5c3a62295173735707b240725830e;hp=88fc5e7b5c400cd22a4e3b079bcb934a95d1f4af;hpb=6fab9958c663f7a606f3e12d4f7508de37298504;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 88fc5e7b5c4..6d321f9f6a4 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -11,6 +11,7 @@ #include "config.h" #include "object.h" #include "loader.h" +#include "cil-coff.h" #include "metadata/marshal.h" #include "metadata/method-builder.h" #include "metadata/tabledefs.h" @@ -25,7 +26,9 @@ #include "mono/metadata/gc-internal.h" #include "mono/metadata/threads-types.h" #include "mono/metadata/string-icalls.h" -#include +#include "mono/metadata/attrdefs.h" +#include "mono/metadata/gc-internal.h" +#include "mono/utils/mono-counters.h" #include #include @@ -41,6 +44,13 @@ typedef enum { MONO_MARSHAL_SERIALIZE /* Value needs to be serialized into the new domain */ } MonoXDomainMarshalType; +typedef enum { + MONO_COM_DEFAULT, + MONO_COM_MS +} MonoCOMProvider; + +static MonoCOMProvider com_provider = MONO_COM_DEFAULT; + enum { #include "mono/cil/opcode.def" LAST = 0xff @@ -71,9 +81,6 @@ static CRITICAL_SECTION marshal_mutex; #define mono_cominterop_unlock() LeaveCriticalSection (&cominterop_mutex) static CRITICAL_SECTION cominterop_mutex; -/* Maps wrapper methods to the methods they wrap */ -static GHashTable *wrapper_hash; - static guint32 last_error_tls_id; static guint32 load_type_info_tls_id; @@ -102,6 +109,9 @@ mono_string_from_bstr (gpointer bstr); static void mono_free_bstr (gpointer bstr); +static MonoStringBuilder * +mono_string_utf8_to_builder2 (char *text); + static void mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum); @@ -139,7 +149,7 @@ static void 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, gboolean check_exceptions); +mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions); static void init_safe_handle (void); @@ -171,17 +181,15 @@ signature_dup (MonoImage *image, MonoMethodSignature *sig) MonoMethodSignature *res; int sigsize; + res = mono_metadata_signature_alloc (image, sig->param_count); sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); - mono_loader_lock (); - res = mono_mempool_alloc (image->mempool, sigsize); - mono_loader_unlock (); memcpy (res, sig, sigsize); return res; } -static MonoMethodSignature* -signature_no_pinvoke (MonoMethod *method) +MonoMethodSignature* +mono_signature_no_pinvoke (MonoMethod *method) { MonoMethodSignature *sig = mono_method_signature (method); if (sig->pinvoke) { @@ -211,6 +219,9 @@ typedef struct { guint32 ref_count; guint32 gc_handle; GHashTable* vtable_hash; +#ifdef PLATFORM_WIN32 + gpointer free_marshaler; +#endif } MonoCCW; /* This type is the actual pointer passed to unmanaged code @@ -221,6 +232,8 @@ typedef struct { MonoCCW* ccw; } MonoCCWInterface; +#ifndef DISABLE_COM + /* IUnknown */ static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe); @@ -273,10 +286,8 @@ cominterop_method_signature (MonoMethod* method) if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret)) param_count++; - sigsize = sizeof (MonoMethodSignature) + ((param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); - mono_loader_lock (); - res = mono_mempool_alloc (image->mempool, sigsize); - mono_loader_unlock (); + res = mono_metadata_signature_alloc (image, param_count); + sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); memcpy (res, sig, sigsize); // now move args forward one @@ -474,6 +485,42 @@ cominterop_class_guid (MonoClass* klass, guint8* guid) return FALSE; } +static gboolean +cominterop_com_visible (MonoClass* klass) +{ + static MonoClass *ComVisibleAttribute = NULL; + MonoCustomAttrInfo *cinfo; + + /* Handle the ComVisibleAttribute */ + if (!ComVisibleAttribute) + ComVisibleAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ComVisibleAttribute"); + + cinfo = mono_custom_attrs_from_class (klass); + if (cinfo) { + MonoReflectionComVisibleAttribute *attr = (MonoReflectionComVisibleAttribute*)mono_custom_attrs_get_attr (cinfo, ComVisibleAttribute); + + if (!attr) + return FALSE; + if (!cinfo->cached) + mono_custom_attrs_free (cinfo); + + if (attr->visible) + return TRUE; + } + return FALSE; +} + +static void cominterop_raise_hr_exception (int hr) +{ + static MonoMethod* throw_exception_for_hr = NULL; + MonoException* ex; + void* params[1] = {&hr}; + if (!throw_exception_for_hr) + throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1); + ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL); + mono_raise_exception (ex); +} + /** * cominterop_get_interface: * @obj: managed wrapper object containing COM object @@ -501,13 +548,7 @@ cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exce g_assert(found); hr = ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (obj->iunknown, iid, &itf); if (hr < 0 && throw_exception) { - static MonoMethod* throw_exception_for_hr = NULL; - MonoException* ex; - void* params[1] = {&hr}; - if (!throw_exception_for_hr) - throw_exception_for_hr = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetExceptionForHR", 1); - ex = (MonoException*)mono_runtime_invoke (throw_exception_for_hr, NULL, params, NULL); - mono_raise_exception (ex); + cominterop_raise_hr_exception (hr); } if (hr >= 0 && itf) { @@ -532,19 +573,26 @@ cominterop_get_hresult_for_exception (MonoException* exc) return hr; } +#endif /* DISABLE_COM */ + void mono_marshal_init (void) { static gboolean module_initialized = FALSE; if (!module_initialized) { + char* com_provider_env = NULL; module_initialized = TRUE; InitializeCriticalSection (&marshal_mutex); InitializeCriticalSection (&cominterop_mutex); - wrapper_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); last_error_tls_id = TlsAlloc (); load_type_info_tls_id = TlsAlloc (); + com_provider_env = getenv ("MONO_COM"); + if (com_provider_env && !strcmp(com_provider_env, "MS")) + com_provider = MONO_COM_MS; + + register_icall (ves_icall_System_Threading_Thread_ResetAbort, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE); register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE); register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE); register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE); @@ -571,6 +619,7 @@ mono_marshal_init (void) register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", FALSE); register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", FALSE); 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_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); @@ -591,6 +640,7 @@ mono_marshal_init (void) 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); +#ifndef DISABLE_COM register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "ptr ptr", FALSE); register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE); register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE); @@ -598,13 +648,13 @@ mono_marshal_init (void) register_icall (cominterop_get_ccw_object, "cominterop_get_ccw_object", "object ptr int32", FALSE); register_icall (cominterop_get_hresult_for_exception, "cominterop_get_hresult_for_exception", "int32 object", FALSE); register_icall (cominterop_get_interface, "cominterop_get_interface", "ptr object ptr int32", FALSE); +#endif /* DISABLE_COM */ } } void mono_marshal_cleanup (void) { - g_hash_table_destroy (wrapper_hash); TlsFree (load_type_info_tls_id); TlsFree (last_error_tls_id); DeleteCriticalSection (&marshal_mutex); @@ -801,7 +851,7 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) g_free (sig); d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass); - mono_delegate_ctor ((MonoObject*)d, NULL, mono_compile_method (wrapper)); + mono_delegate_ctor_with_method ((MonoObject*)d, NULL, mono_compile_method (wrapper), wrapper); } if (d->object.vtable->domain != mono_domain_get ()) @@ -931,6 +981,43 @@ mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text) g_free (ut); } +MonoStringBuilder * +mono_string_utf8_to_builder2 (char *text) +{ + int l; + 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); + } + + l = strlen (text); + + sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class); + g_assert (sb); + args [0] = &l; + mono_runtime_invoke (sb_ctor, sb, args, &exc); + g_assert (!exc); + + mono_string_utf8_to_builder (sb, text); + + return sb; +} + /* * FIXME: This routine does not seem to do what it seems to do * the @text is never copied into the string builder @@ -965,8 +1052,7 @@ gpointer mono_string_builder_to_utf8 (MonoStringBuilder *sb) { GError *error = NULL; - glong *res; - gchar *tmp; + gchar *tmp, *res = NULL; if (!sb) return NULL; @@ -980,14 +1066,12 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb) sb->cached_str = NULL; } - res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1); - - tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error); + tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, NULL, &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 { + res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1); memcpy (res, tmp, sb->length + 1); g_free (tmp); } @@ -1074,46 +1158,134 @@ mono_string_to_ansibstr (MonoString *string_obj) return NULL; } +typedef gpointer (*SysAllocStringLenFunc)(gunichar* str, guint32 len); +typedef guint32 (*SysStringLenFunc)(gpointer bstr); +typedef void (*SysFreeStringFunc)(gunichar* str); + +static SysAllocStringLenFunc sys_alloc_string_len_ms = NULL; +static SysStringLenFunc sys_string_len_ms = NULL; +static SysFreeStringFunc sys_free_string_ms = NULL; + +static gboolean +init_com_provider_ms (void) +{ + static gboolean initialized = FALSE; + char *error_msg; + MonoDl *module = NULL; + const char* scope = "liboleaut32.so"; + + if (initialized) + return TRUE; + + module = mono_dl_open(scope, MONO_DL_LAZY, &error_msg); + if (error_msg) { + g_warning ("Error loading COM support library '%s': %s", scope, error_msg); + g_assert_not_reached (); + return FALSE; + } + error_msg = mono_dl_symbol (module, "SysAllocStringLen", (gpointer*)&sys_alloc_string_len_ms); + if (error_msg) { + g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysAllocStringLen", scope, error_msg); + g_assert_not_reached (); + return FALSE; + } + + error_msg = mono_dl_symbol (module, "SysStringLen", (gpointer*)&sys_string_len_ms); + if (error_msg) { + g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysStringLen", scope, error_msg); + g_assert_not_reached (); + return FALSE; + } + + error_msg = mono_dl_symbol (module, "SysFreeString", (gpointer*)&sys_free_string_ms); + if (error_msg) { + g_warning ("Error loading entry point '%s' in COM support library '%s': %s", "SysFreeString", scope, error_msg); + g_assert_not_reached (); + return FALSE; + } + + initialized = TRUE; + return TRUE; +} + gpointer mono_string_to_bstr (MonoString *string_obj) { -#ifdef PLATFORM_WIN32 if (!string_obj) return NULL; +#ifdef PLATFORM_WIN32 return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj)); #else - 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; + if (com_provider == MONO_COM_DEFAULT) { + int slen = mono_string_length (string_obj); + /* allocate len + 1 utf16 characters plus 4 byte integer for length*/ + char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32)); + if (ret == NULL) + return NULL; + memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2)); + * ((guint32 *) ret) = slen * sizeof(gunichar2); + ret [4 + slen * sizeof(gunichar2)] = 0; + ret [5 + slen * sizeof(gunichar2)] = 0; + + return ret + 4; + } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) { + gpointer ret = NULL; + gunichar* str = NULL; + guint32 len; + len = mono_string_length (string_obj); + str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len, + NULL, NULL, NULL); + ret = sys_alloc_string_len_ms (str, len); + g_free(str); + return ret; + } else { + g_assert_not_reached (); + } #endif } MonoString * mono_string_from_bstr (gpointer bstr) { -#ifdef PLATFORM_WIN32 if (!bstr) return NULL; +#ifdef PLATFORM_WIN32 return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr)); #else - return mono_string_new_utf16 (mono_domain_get (), bstr, *(guint32 *)((char *)bstr - 4) / 2); + if (com_provider == MONO_COM_DEFAULT) { + return mono_string_new_utf16 (mono_domain_get (), bstr, *((guint32 *)bstr - 1) / sizeof(gunichar2)); + } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) { + MonoString* str = NULL; + glong written = 0; + gunichar2* utf16 = NULL; + + utf16 = g_ucs4_to_utf16 (bstr, sys_string_len_ms (bstr), NULL, &written, NULL); + str = mono_string_new_utf16 (mono_domain_get (), utf16, written); + g_free (utf16); + return str; + } else { + g_assert_not_reached (); + } + #endif } void mono_free_bstr (gpointer bstr) { + if (!bstr) + return; #ifdef PLATFORM_WIN32 SysFreeString ((BSTR)bstr); #else - g_free (((char *)bstr) - 4); + if (com_provider == MONO_COM_DEFAULT) { + g_free (((char *)bstr) - 4); + } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) { + sys_free_string_ms (bstr); + } else { + g_assert_not_reached (); + } + #endif } @@ -1206,6 +1378,29 @@ mono_mb_emit_xdomain_check (MonoMethodBuilder *mb, int branch_code) return pos; } +static int +mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code) +{ + static int offset = -1; + static guint8 mask; + + if (offset < 0) + mono_marshal_find_bitfield_offset (MonoClass, contextbound, &offset, &mask); + + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, offset); + mono_mb_emit_byte (mb, CEE_LDIND_U1); + mono_mb_emit_icon (mb, mask); + mono_mb_emit_byte (mb, CEE_AND); + mono_mb_emit_icon (mb, 0); + return mono_mb_emit_branch (mb, branch_code); +} + +#ifndef DISABLE_COM + static void mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method) { @@ -1221,6 +1416,8 @@ mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, M mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF); } +#endif /* DISABLE_COM */ + static void mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, const char *msg) { @@ -1560,6 +1757,8 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv case MONO_MARSHAL_CONV_ARRAY_LPARRAY: g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name); break; + +#ifndef DISABLE_COM case MONO_MARSHAL_CONV_OBJECT_INTERFACE: case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: { @@ -1632,6 +1831,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_short_branch (mb, pos_null); break; } +#endif /* DISABLE_COM */ case MONO_MARSHAL_CONV_SAFEHANDLE: { /* @@ -1933,6 +2133,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_branch (mb, pos); break; } + +#ifndef DISABLE_COM case MONO_MARSHAL_CONV_OBJECT_INTERFACE: case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: { @@ -2020,6 +2222,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv mono_mb_patch_short_branch (mb, pos_null); break; } +#endif /* DISABLE_COM */ case MONO_MARSHAL_CONV_SAFEHANDLE: { int dar_release_slot, pos; @@ -2438,6 +2641,9 @@ mono_signature_to_name (MonoMethodSignature *sig, const char *prefix) mono_type_get_desc (res, sig->ret, FALSE); + if (sig->hasthis) + g_string_append (res, "__this__"); + for (i = 0; i < sig->param_count; ++i) { g_string_append_c (res, '_'); mono_type_get_desc (res, sig->params [i], FALSE); @@ -2533,6 +2739,7 @@ mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec switch (encoding) { case MONO_NATIVE_LPWSTR: + *need_free = FALSE; return MONO_MARSHAL_CONV_LPWSTR_STR; case MONO_NATIVE_LPSTR: return MONO_MARSHAL_CONV_LPSTR_STR; @@ -2601,6 +2808,25 @@ mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec } } +/* + * Return the hash table pointed to by VAR, lazily creating it if neccesary. + */ +static GHashTable* +get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func) +{ + if (!(*var)) { + mono_marshal_lock (); + if (!(*var)) { + GHashTable *cache = + g_hash_table_new (hash_func, equal_func); + mono_memory_barrier (); + *var = cache; + } + mono_marshal_unlock (); + } + return *var; +} + static inline MonoMethod* mono_marshal_find_in_cache (GHashTable *cache, gpointer key) { @@ -2612,6 +2838,18 @@ 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 */ static inline MonoMethod* mono_mb_create_and_cache (GHashTable *cache, gpointer key, @@ -2631,7 +2869,7 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key, if (!res) { res = newm; g_hash_table_insert (cache, key, res); - g_hash_table_insert (wrapper_hash, res, key); + mono_marshal_method_set_wrapper_data (res, key); mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -2650,7 +2888,10 @@ mono_marshal_remoting_find_in_cache (MonoMethod *method, int wrapper_type) MonoRemotingMethods *wrps; mono_marshal_lock (); - wrps = g_hash_table_lookup (method->klass->image->remoting_invoke_cache, method); + if (method->klass->image->remoting_invoke_cache) + wrps = g_hash_table_lookup (method->klass->image->remoting_invoke_cache, method); + else + wrps = NULL; if (wrps) { switch (wrapper_type) { @@ -2676,7 +2917,7 @@ mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb, { MonoMethod **res = NULL; MonoRemotingMethods *wrps; - GHashTable *cache = key->klass->image->remoting_invoke_cache; + GHashTable *cache = get_cache (&key->klass->image->remoting_invoke_cache, mono_aligned_addr_hash, NULL); mono_marshal_lock (); wrps = g_hash_table_lookup (cache, key); @@ -2701,7 +2942,7 @@ mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb, mono_marshal_lock (); if (!*res) { *res = newm; - g_hash_table_insert (wrapper_hash, *res, key); + mono_marshal_method_set_wrapper_data (*res, key); mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -2715,14 +2956,14 @@ mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb, MonoMethod * mono_marshal_method_from_wrapper (MonoMethod *wrapper) { - MonoMethod *res; + gpointer res; - if (wrapper->wrapper_type == MONO_WRAPPER_NONE) + if (wrapper->wrapper_type == MONO_WRAPPER_NONE || wrapper->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) return wrapper; - mono_marshal_lock (); - res = g_hash_table_lookup (wrapper_hash, wrapper); - mono_marshal_unlock (); + res = mono_method_get_wrapper_data (wrapper, 1); + if (res == NULL) + return wrapper; return res; } @@ -2739,26 +2980,25 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method) g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class && !strcmp (method->name, "BeginInvoke")); - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); - cache = method->klass->image->delegate_begin_invoke_cache; + cache = get_cache (&method->klass->image->delegate_begin_invoke_cache, + (GHashFunc)mono_signature_hash, + (GCompareFunc)mono_metadata_signature_equal); if ((res = mono_marshal_find_in_cache (cache, sig))) return res; g_assert (sig->hasthis); name = mono_signature_to_name (sig, "begin_invoke"); - mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE); + mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE); g_free (name); - mb->method->save_lmf = 1; - params_var = mono_mb_emit_save_args (mb, sig, FALSE); mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldloc (mb, params_var); mono_mb_emit_icall (mb, mono_delegate_begin_invoke); - emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16); @@ -2793,14 +3033,15 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params) method = mono_class_get_method_from_name (klass, "EndInvoke", -1); g_assert (method != NULL); - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); msg = mono_method_call_message_new (method, params, NULL, NULL, NULL); ares = mono_array_get (msg->args, gpointer, sig->param_count - 1); - g_assert (ares); + 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.")); - if (ares->async_delegate != (MonoObject*)delegate && mono_get_runtime_info ()->framework_version [0] >= '2') { + if (ares->async_delegate != (MonoObject*)delegate && mono_framework_version () >= 2) { mono_raise_exception (mono_get_exception_invalid_operation ( "The IAsyncResult object provided does not match this delegate.")); return NULL; @@ -2901,26 +3142,25 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method) g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class && !strcmp (method->name, "EndInvoke")); - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); - cache = method->klass->image->delegate_end_invoke_cache; + cache = get_cache (&method->klass->image->delegate_end_invoke_cache, + (GHashFunc)mono_signature_hash, + (GCompareFunc)mono_metadata_signature_equal); if ((res = mono_marshal_find_in_cache (cache, sig))) return res; g_assert (sig->hasthis); name = mono_signature_to_name (sig, "end_invoke"); - mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_END_INVOKE); + mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_END_INVOKE); g_free (name); - mb->method->save_lmf = 1; - params_var = mono_mb_emit_save_args (mb, sig, FALSE); mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldloc (mb, params_var); mono_mb_emit_icall (mb, mono_delegate_end_invoke); - emit_thread_interrupt_checkpoint (mb); if (sig->ret->type == MONO_TYPE_VOID) { mono_mb_emit_byte (mb, CEE_POP); @@ -2961,10 +3201,15 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params) for (i=0; iparams [i]); if (class->valuetype) { - if (sig->params [i]->byref) + if (sig->params [i]->byref) { mparams[i] = *((gpointer *)params [i]); - else - mparams[i] = params [i]; + } else { + /* runtime_invoke expects a boxed instance */ + if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) + mparams[i] = mono_nullable_box (params [i], class); + else + mparams[i] = params [i]; + } } else { mparams[i] = *((gpointer**)params [i]); } @@ -2985,6 +3230,8 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params) return res; } +#ifndef DISABLE_COM + /** * cominterop_get_native_wrapper_adjusted: * @method: managed COM Interop method @@ -3028,7 +3275,45 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method) mspecs[0] = NULL; } - mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, TRUE); + for (i = 1; i < sig_native->param_count; i++) { + int mspec_index = i + 1; + if (mspecs[mspec_index] == NULL) { + // default object to VARIANT + if (sig_native->params[i]->type == MONO_TYPE_OBJECT) { + mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1); + mspecs[mspec_index]->native = MONO_NATIVE_STRUCT; + } + else if (sig_native->params[i]->type == MONO_TYPE_STRING) { + mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1); + mspecs[mspec_index]->native = MONO_NATIVE_BSTR; + } + else if (sig_native->params[i]->type == MONO_TYPE_CLASS) { + mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1); + mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE; + } + } + } + + if (method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG) { + // move return spec to last param + if (!MONO_TYPE_IS_VOID (sig->ret) && mspecs[0] == NULL) { + // default object to VARIANT + if (sig->ret->type == MONO_TYPE_OBJECT) { + mspecs[0] = g_new0 (MonoMarshalSpec, 1); + mspecs[0]->native = MONO_NATIVE_STRUCT; + } + else if (sig->ret->type == MONO_TYPE_STRING) { + mspecs[0] = g_new0 (MonoMarshalSpec, 1); + mspecs[0]->native = MONO_NATIVE_BSTR; + } + else if (sig->ret->type == MONO_TYPE_CLASS) { + mspecs[0] = g_new0 (MonoMarshalSpec, 1); + mspecs[0]->native = MONO_NATIVE_INTERFACE; + } + } + } + + mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, FALSE, TRUE); res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16); @@ -3058,12 +3343,18 @@ cominterop_get_native_wrapper (MonoMethod *method) g_assert (method); - cache = method->klass->image->cominterop_wrapper_cache; + cache = get_cache (&method->klass->image->cominterop_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, method))) return res; mono_init_com_types (); + if (!method->klass->vtable) + mono_class_setup_vtable (method->klass); + + if (!method->klass->methods) + mono_class_setup_methods (method->klass); + sig = mono_method_signature (method); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP); @@ -3162,14 +3453,14 @@ cominterop_get_invoke (MonoMethod *method) MonoMethodBuilder *mb; MonoMethod *res; int i, temp_obj; - GHashTable* cache = method->klass->image->cominterop_invoke_cache; + GHashTable* cache = get_cache (&method->klass->image->cominterop_invoke_cache, mono_aligned_addr_hash, NULL); g_assert (method); if ((res = mono_marshal_find_in_cache (cache, method))) return res; - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); /* we cant remote methods without this pointer */ if (!sig->hasthis) @@ -3226,6 +3517,9 @@ cominterop_get_invoke (MonoMethod *method) return res; } + +#endif /* DISABLE_COM */ + /* Maps a managed object to its unmanaged representation * i.e. it's COM Callable Wrapper (CCW). * Key: MonoObject* @@ -3261,10 +3555,15 @@ 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) && !mono_class_vtable (mono_domain_get (), method->klass)->remote) { +#ifndef DISABLE_COM return cominterop_get_invoke(method); +#else + g_assert_not_reached (); +#endif + } - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); /* we cant remote methods without this pointer */ if (!sig->hasthis) @@ -3575,7 +3874,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in /* try */ mono_loader_lock (); - main_clause = mono_mempool_alloc0 (method->klass->image->mempool, sizeof (MonoExceptionClause)); + main_clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause)); mono_loader_unlock (); main_clause->try_offset = mono_mb_get_label (mb); @@ -3816,7 +4115,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_XDOMAIN_INVOKE))) return res; - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_XDOMAIN_INVOKE); mb->method->save_lmf = 1; @@ -4108,12 +4407,17 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method) MonoMethod * mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTarget target_type) { - if (target_type == MONO_REMOTING_TARGET_APPDOMAIN) + if (target_type == MONO_REMOTING_TARGET_APPDOMAIN) { return mono_marshal_get_xappdomain_invoke (method); - else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) + } else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) { +#ifndef DISABLE_COM return cominterop_get_invoke (method); - else +#else + g_assert_not_reached (); +#endif + } else { return mono_marshal_get_remoting_invoke (method); + } } G_GNUC_UNUSED static gpointer @@ -4144,7 +4448,7 @@ mono_marshal_get_remoting_invoke_with_check (MonoMethod *method) if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) return res; - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK); @@ -4224,6 +4528,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) int pos0; char *name; MonoMethod *target_method = NULL; + MonoClass *target_class = NULL; gboolean callvirt = FALSE; /* @@ -4234,12 +4539,22 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (del && !del->target && del->method && mono_method_signature (del->method)->hasthis) { callvirt = TRUE; target_method = del->method; + if (target_method->is_inflated) { + MonoType *target_type; + + g_assert (method->signature->hasthis); + target_type = mono_class_inflate_generic_type (method->signature->params [0], + mono_method_get_context (method)); + target_class = mono_class_from_mono_type (target_type); + } else { + target_class = del->method->klass; + } } g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class && !strcmp (method->name, "Invoke")); - sig = signature_no_pinvoke (method); + sig = mono_signature_no_pinvoke (method); if (callvirt) { /* We need to cache the signature+method pair */ @@ -4254,7 +4569,9 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (res) return res; } else { - cache = method->klass->image->delegate_invoke_cache; + cache = get_cache (&method->klass->image->delegate_invoke_cache, + (GHashFunc)mono_signature_hash, + (GCompareFunc)mono_metadata_signature_equal); if ((res = mono_marshal_find_in_cache (cache, sig))) return res; } @@ -4263,7 +4580,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 (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_INVOKE); + mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_INVOKE); g_free (name); /* allocate local 0 (object) */ @@ -4337,7 +4654,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (callvirt) { mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_op (mb, CEE_CASTCLASS, target_method->klass); + 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); @@ -4355,6 +4672,9 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (callvirt) { // From mono_mb_create_and_cache newm = mono_mb_create_method (mb, sig, sig->param_count + 16); + newm->skip_visibility = 1; + /*We perform double checked locking, so must fence before publishing*/ + mono_memory_barrier (); mono_marshal_lock (); res = g_hash_table_lookup (cache, &key); if (!res) { @@ -4363,7 +4683,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); - g_hash_table_insert (wrapper_hash, res, new_key); + mono_marshal_method_set_wrapper_data (res, new_key); mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -4371,6 +4691,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) } } else { res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16); + res->skip_visibility = 1; } mono_mb_free (mb); @@ -4448,6 +4769,67 @@ add_string_ctor_signature (MonoMethod *method) return callsig; } +static MonoType* +get_runtime_invoke_type (MonoType *t) +{ + if (t->byref) + return &mono_defaults.int_class->byval_arg; + + switch (t->type) { + case MONO_TYPE_U1: + return &mono_defaults.sbyte_class->byval_arg; + case MONO_TYPE_U2: + return &mono_defaults.int16_class->byval_arg; + case MONO_TYPE_U4: + return &mono_defaults.int32_class->byval_arg; + case MONO_TYPE_U8: + return &mono_defaults.int64_class->byval_arg; + case MONO_TYPE_BOOLEAN: + return &mono_defaults.byte_class->byval_arg; + case MONO_TYPE_CHAR: + return &mono_defaults.int16_class->byval_arg; + case MONO_TYPE_U: + return &mono_defaults.int_class->byval_arg; + case MONO_TYPE_VALUETYPE: + if (t->data.klass->enumtype) + return mono_type_get_underlying_type (t); + else + return t; + default: + if (MONO_TYPE_IS_REFERENCE (t)) + return &mono_defaults.object_class->byval_arg; + return t; + } +} + +/* + * mono_marshal_get_runtime_invoke_sig: + * + * Return a common signature used for sharing runtime invoke wrappers. + */ +static MonoMethodSignature* +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); + for (i = 0; i < res->param_count; ++i) + res->params [i] = get_runtime_invoke_type (sig->params [i]); + + return res; +} + +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))) + return FALSE; + else + return mono_metadata_signature_equal (sig1, sig2); +} + /* * generates IL code for the runtime invoke function * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method) @@ -4465,13 +4847,33 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) MonoClass *target_klass; MonoMethod *res = NULL; static MonoString *string_dummy = NULL; - static MonoMethodSignature *delay_abort_sig = NULL; + static MonoMethodSignature *cctor_signature = NULL; + static MonoMethodSignature *finalize_signature = NULL; int i, pos, posna; char *name; gboolean need_direct_wrapper = FALSE; g_assert (method); + if (!cctor_signature) { + cctor_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0); + cctor_signature->ret = &mono_defaults.void_class->byval_arg; + } + if (!finalize_signature) { + finalize_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0); + finalize_signature->ret = &mono_defaults.void_class->byval_arg; + finalize_signature->hasthis = 1; + } + + /* + * Use a separate cache indexed by methods to speed things up and to avoid the + * boundless mempool growth caused by the signature_dup stuff below. + */ + cache = get_cache (&method->klass->image->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL); + res = mono_marshal_find_in_cache (cache, method); + if (res) + return res; + if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) { /* @@ -4480,7 +4882,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) */ need_direct_wrapper = TRUE; } - + if (method->string_ctor) { callsig = lookup_string_ctor_signature (mono_method_signature (method)); if (!callsig) @@ -4500,57 +4902,59 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) } } - /* See bug #80743 */ /* - * FIXME: Sharing runtime invoke wrappers between different methods means that - * calling a method of klass A might invoke the type initializer of class B. - * Normally, the type initializer of type B was already executed when B's method - * was called but in some complex cases this might not be true. - * See #349621 for an example. We avoid that for mscorlib methods by putting every - * wrapper into the object class, but the non-mscorlib case needs fixing. + * 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) target_klass = mono_defaults.object_class; else { - target_klass = method->klass; - } -#if 0 - 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; - } + /* 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; } } -#endif + if (need_direct_wrapper) { - cache = target_klass->image->runtime_invoke_direct_cache; - res = mono_marshal_find_in_cache (cache, method); + /* Already searched at the start */ } else { - cache = target_klass->image->runtime_invoke_cache; + callsig = mono_marshal_get_runtime_invoke_sig (callsig); + + cache = get_cache (&target_klass->image->runtime_invoke_cache, + (GHashFunc)mono_signature_hash, + (GCompareFunc)runtime_invoke_signature_equal); /* from mono_marshal_find_in_cache */ mono_marshal_lock (); res = g_hash_table_lookup (cache, callsig); mono_marshal_unlock (); - } - if (res) { - return res; - } + if (res) { + g_free (callsig); + return res; + } - if (!delay_abort_sig) { - delay_abort_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0); - delay_abort_sig->ret = &mono_defaults.void_class->byval_arg; - delay_abort_sig->pinvoke = 0; + // FIXME: When to free callsig ? } /* to make it work with our special string constructors */ @@ -4611,6 +5015,16 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) if (t->byref) { mono_mb_emit_byte (mb, CEE_LDIND_I); + /* A Nullable type don't have a boxed form, it's either null or a boxed T. + * So to make this work we unbox it to a local variablee and push a reference to that. + */ + if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) { + int tmp_nullable_local = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg); + + mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t)); + mono_mb_emit_stloc (mb, tmp_nullable_local); + mono_mb_emit_ldloc_addr (mb, tmp_nullable_local); + } continue; } @@ -4723,7 +5137,7 @@ handle_enum: pos = mono_mb_emit_branch (mb, CEE_LEAVE); mono_loader_lock (); - clause = mono_mempool_alloc0 (target_klass->image->mempool, sizeof (MonoExceptionClause)); + clause = mono_image_alloc0 (target_klass->image, sizeof (MonoExceptionClause)); mono_loader_unlock (); clause->flags = MONO_EXCEPTION_CLAUSE_FILTER; clause->try_len = mono_mb_get_label (mb); @@ -4758,7 +5172,7 @@ handle_enum: posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); /* Delay the abort exception */ - mono_mb_emit_native_call (mb, delay_abort_sig, ves_icall_System_Threading_Thread_ResetAbort); + 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); @@ -4788,7 +5202,8 @@ handle_enum: if (!res) { res = newm; g_hash_table_insert (cache, callsig, res); - g_hash_table_insert (wrapper_hash, res, callsig); + /* Can't insert it into wrapper_hash since the key is a signature */ + g_hash_table_insert (method->klass->image->runtime_invoke_direct_cache, method, res); } else { mono_free_method (newm); } @@ -4807,50 +5222,104 @@ handle_enum: return res; } -static void -mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass) -{ - char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit", - klass->name_space, klass->name); - - mono_mb_emit_exception_marshal_directive (mb, msg); -} - /* - * mono_marshal_get_ldfld_remote_wrapper: - * @klass: The return type + * mono_marshal_get_static_rgctx_invoke: + * @method: a method * - * This method generates a wrapper for calling mono_load_remote_field_new with - * the appropriate return type. + * 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_ldfld_remote_wrapper (MonoClass *klass) +mono_marshal_get_static_rgctx_invoke (MonoMethod *method) { - MonoMethodSignature *sig, *csig; + static gboolean inited = FALSE; + static int num_wrappers = 0; + MonoMethodBuilder *mb; MonoMethod *res; - GHashTable *cache; + MonoClass *target_klass = method->klass; + MonoMethodSignature *sig = mono_method_signature (method); + int i; char *name; + GHashTable *cache; + MonoImage *image = method->klass->image; - cache = klass->image->ldfld_remote_wrapper_cache; - if ((res = mono_marshal_find_in_cache (cache, klass))) + cache = get_cache (&image->static_rgctx_invoke_cache, mono_aligned_addr_hash, NULL); + if ((res = mono_marshal_find_in_cache (cache, method))) return res; - /* - * This wrapper is similar to an icall wrapper but all the wrappers - * call the same C function, but with a different signature. - */ - name = g_strdup_printf ("__mono_load_remote_field_new_wrapper_%s.%s", klass->name_space, klass->name); - mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD_REMOTE); + if (!inited) { + mono_counters_register ("static rgctx invoke wrappers", + MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_wrappers); + inited = TRUE; + } + ++num_wrappers; + + 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); + for (i = 0; i < sig->param_count + sig->hasthis; i++) + mono_mb_emit_ldarg (mb, i); + mono_mb_emit_op (mb, CEE_CALL, method); + mono_mb_emit_byte (mb, CEE_RET); + + res = mono_mb_create_and_cache (cache, method, mb, mono_method_signature (method), + sig->param_count + sig->hasthis + 4); + res->skip_visibility = TRUE; + res->flags = method->flags; + + mono_mb_free (mb); + + return res; +} + +static void +mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass) +{ + char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit", + klass->name_space, klass->name); + + mono_mb_emit_exception_marshal_directive (mb, msg); +} + +/* + * mono_marshal_get_ldfld_remote_wrapper: + * @klass: The return type + * + * This method generates a wrapper for calling mono_load_remote_field_new. + * The return type is ignored for now, as mono_load_remote_field_new () always + * returns an object. In the future, to optimize some codepaths, we might + * call a different function that takes a pointer to a valuetype, instead. + */ +MonoMethod * +mono_marshal_get_ldfld_remote_wrapper (MonoClass *klass) +{ + MonoMethodSignature *sig, *csig; + MonoMethodBuilder *mb; + MonoMethod *res; + static MonoMethod* cached = NULL; + + mono_marshal_lock (); + if (cached) { + mono_marshal_unlock (); + return cached; + } + mono_marshal_unlock (); + + mb = mono_mb_new_no_dup_name (mono_defaults.object_class, "__mono_load_remote_field_new_wrapper", MONO_WRAPPER_LDFLD_REMOTE); + mb->method->save_lmf = 1; sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3); sig->params [0] = &mono_defaults.object_class->byval_arg; sig->params [1] = &mono_defaults.int_class->byval_arg; sig->params [2] = &mono_defaults.int_class->byval_arg; - sig->ret = &klass->this_arg; + sig->ret = &mono_defaults.object_class->byval_arg; mono_mb_emit_ldarg (mb, 0); mono_mb_emit_ldarg (mb, 1); @@ -4860,18 +5329,33 @@ mono_marshal_get_ldfld_remote_wrapper (MonoClass *klass) csig->params [0] = &mono_defaults.object_class->byval_arg; csig->params [1] = &mono_defaults.int_class->byval_arg; csig->params [2] = &mono_defaults.int_class->byval_arg; - csig->ret = &klass->this_arg; + csig->ret = &mono_defaults.object_class->byval_arg; csig->pinvoke = 1; mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new); emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); - - res = mono_mb_create_and_cache (cache, klass, - mb, sig, sig->param_count + 16); + + mono_marshal_lock (); + res = cached; + mono_marshal_unlock (); + if (!res) { + MonoMethod *newm; + newm = mono_mb_create_method (mb, sig, 4); + mono_marshal_lock (); + res = cached; + if (!res) { + res = newm; + cached = res; + mono_marshal_unlock (); + } else { + mono_marshal_unlock (); + mono_free_method (newm); + } + } mono_mb_free (mb); - + return res; } @@ -4919,7 +5403,7 @@ mono_marshal_get_ldfld_wrapper (MonoType *type) klass = mono_defaults.int_class; } - cache = klass->image->ldfld_wrapper_cache; + cache = get_cache (&klass->image->ldfld_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -5041,7 +5525,7 @@ mono_marshal_get_ldflda_wrapper (MonoType *type) MonoClass *klass; GHashTable *cache; char *name; - int t, pos0; + int t, pos0, pos1, pos2, pos3; type = mono_type_get_underlying_type (type); t = type->type; @@ -5068,7 +5552,7 @@ mono_marshal_get_ldflda_wrapper (MonoType *type) klass = mono_defaults.int_class; } - cache = klass->image->ldflda_wrapper_cache; + cache = get_cache (&klass->image->ldflda_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -5084,12 +5568,50 @@ mono_marshal_get_ldflda_wrapper (MonoType *type) sig->params [3] = &mono_defaults.int_class->byval_arg; sig->ret = &mono_defaults.int_class->byval_arg; + /* if typeof (this) != transparent_proxy goto pos0 */ mono_mb_emit_ldarg (mb, 0); pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN); - /* FIXME: Only throw this if the object is in another appdomain */ + /* if same_appdomain goto pos1 */ + mono_mb_emit_ldarg (mb, 0); + pos1 = mono_mb_emit_xdomain_check (mb, CEE_BEQ); + mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another appdomain."); + /* same app domain */ + mono_mb_patch_branch (mb, pos1); + + /* if typeof (this) != contextbound goto pos2 */ + mono_mb_emit_ldarg (mb, 0); + pos2 = mono_mb_emit_contextbound_check (mb, CEE_BEQ); + + /* if this->rp->context == mono_context_get goto pos3 */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, context)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_icall (mb, mono_context_get); + pos3 = mono_mb_emit_branch (mb, CEE_BEQ); + + mono_mb_emit_exception_full (mb, "System", "InvalidOperationException", "Attempt to load field address from object in another context."); + + mono_mb_patch_branch (mb, pos2); + mono_mb_patch_branch (mb, pos3); + + /* return the address of the field from this->rp->unwrapped_server */ + mono_mb_emit_ldarg (mb, 0); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, unwrapped_server)); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_OBJADDR); + mono_mb_emit_ldarg (mb, 3); + mono_mb_emit_byte (mb, CEE_ADD); + mono_mb_emit_byte (mb, CEE_RET); + + /* not a proxy: return the address of the field directly */ mono_mb_patch_branch (mb, pos0); mono_mb_emit_ldarg (mb, 0); @@ -5113,6 +5635,8 @@ mono_marshal_get_ldflda_wrapper (MonoType *type) * * This function generates a wrapper for calling mono_store_remote_field_new * with the appropriate signature. + * Similarly to mono_marshal_get_ldfld_remote_wrapper () this doesn't depend on the + * klass argument anymore. */ MonoMethod * mono_marshal_get_stfld_remote_wrapper (MonoClass *klass) @@ -5120,16 +5644,16 @@ mono_marshal_get_stfld_remote_wrapper (MonoClass *klass) MonoMethodSignature *sig, *csig; MonoMethodBuilder *mb; MonoMethod *res; - GHashTable *cache; - char *name; + static MonoMethod *cached = NULL; - cache = klass->image->stfld_remote_wrapper_cache; - if ((res = mono_marshal_find_in_cache (cache, klass))) - return res; + mono_marshal_lock (); + if (cached) { + mono_marshal_unlock (); + return cached; + } + mono_marshal_unlock (); - name = g_strdup_printf ("__mono_store_remote_field_new_wrapper_%s.%s", klass->name_space, klass->name); - mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD_REMOTE); - g_free (name); + mb = mono_mb_new_no_dup_name (mono_defaults.object_class, "__mono_store_remote_field_new_wrapper", MONO_WRAPPER_STFLD_REMOTE); mb->method->save_lmf = 1; @@ -5137,7 +5661,7 @@ mono_marshal_get_stfld_remote_wrapper (MonoClass *klass) sig->params [0] = &mono_defaults.object_class->byval_arg; sig->params [1] = &mono_defaults.int_class->byval_arg; sig->params [2] = &mono_defaults.int_class->byval_arg; - sig->params [3] = &klass->byval_arg; + sig->params [3] = &mono_defaults.object_class->byval_arg; sig->ret = &mono_defaults.void_class->byval_arg; mono_mb_emit_ldarg (mb, 0); @@ -5145,14 +5669,11 @@ mono_marshal_get_stfld_remote_wrapper (MonoClass *klass) mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldarg (mb, 3); - if (klass->valuetype) - mono_mb_emit_op (mb, CEE_BOX, klass); - csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4); csig->params [0] = &mono_defaults.object_class->byval_arg; csig->params [1] = &mono_defaults.int_class->byval_arg; csig->params [2] = &mono_defaults.int_class->byval_arg; - csig->params [3] = &klass->byval_arg; + csig->params [3] = &mono_defaults.object_class->byval_arg; csig->ret = &mono_defaults.void_class->byval_arg; csig->pinvoke = 1; @@ -5160,9 +5681,24 @@ mono_marshal_get_stfld_remote_wrapper (MonoClass *klass) emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); - - res = mono_mb_create_and_cache (cache, klass, - mb, sig, sig->param_count + 16); + + mono_marshal_lock (); + res = cached; + mono_marshal_unlock (); + if (!res) { + MonoMethod *newm; + newm = mono_mb_create_method (mb, sig, 6); + mono_marshal_lock (); + res = cached; + if (!res) { + res = newm; + cached = res; + mono_marshal_unlock (); + } else { + mono_marshal_unlock (); + mono_free_method (newm); + } + } mono_mb_free (mb); return res; @@ -5211,7 +5747,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type) klass = mono_defaults.int_class; } - cache = klass->image->stfld_wrapper_cache; + cache = get_cache (&klass->image->stfld_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -5235,6 +5771,8 @@ mono_marshal_get_stfld_wrapper (MonoType *type) mono_mb_emit_ldarg (mb, 1); mono_mb_emit_ldarg (mb, 2); mono_mb_emit_ldarg (mb, 4); + if (klass->valuetype) + mono_mb_emit_op (mb, CEE_BOX, klass); mono_mb_emit_managed_call (mb, mono_marshal_get_stfld_remote_wrapper (klass), NULL); @@ -5531,7 +6069,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_ldloc (mb, conv_arg); mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed); mono_mb_emit_byte (mb, CEE_STIND_REF); - } else if (t->attrs &PARAM_ATTRIBUTE_OUT) { + } else { mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); mono_mb_emit_op (mb, CEE_CALL, get_instance); @@ -5736,7 +6274,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, MonoClass *klass; int pos = 0, pos2; - klass = t->data.klass; + klass = mono_class_from_mono_type (t); switch (action) { case MARSHAL_ACTION_CONV_IN: @@ -5989,26 +6527,26 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_CONV_OUT: + conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); + if (conv == -1) { + char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) { mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_ldloc (mb, conv_arg); - if (conv == MONO_MARSHAL_CONV_STR_BSTR) { - mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_BSTR_STR)); - // BSTRs always need freed - mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, conv_to_icall (conv)); + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + + if (need_free || (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))) { + mono_mb_emit_ldloc (mb, conv_arg); + if (conv == MONO_MARSHAL_CONV_BSTR_STR) mono_mb_emit_icall (mb, mono_free_bstr); - } else - mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_LPSTR_STR)); - mono_mb_emit_byte (mb, CEE_STIND_REF); - } else { - if (mono_marshal_need_free (t, m->piinfo, spec)) { - mono_mb_emit_ldloc (mb, conv_arg); - if (conv == MONO_MARSHAL_CONV_STR_BSTR) - mono_mb_emit_icall (mb, mono_free_bstr); - else - mono_mb_emit_icall (mb, mono_marshal_free); - } + mono_mb_emit_icall (mb, mono_marshal_free); } break; @@ -6038,16 +6576,12 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, if (conv == MONO_MARSHAL_CONV_BSTR_STR) mono_mb_emit_icall (mb, mono_free_bstr); else - mono_mb_emit_icall (mb, g_free); + mono_mb_emit_icall (mb, mono_marshal_free); break; case MARSHAL_ACTION_MANAGED_CONV_IN: - if (t->byref) { - conv_arg = 0; - break; - } - conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + *conv_arg_type = &mono_defaults.int_class->byval_arg; conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free); @@ -6058,9 +6592,22 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, } mono_mb_emit_ldarg (mb, argnum); + if (t->byref) + mono_mb_emit_byte (mb, CEE_LDIND_I); mono_mb_emit_icall (mb, conv_to_icall (conv)); mono_mb_emit_stloc (mb, conv_arg); - break; + break; + + case MARSHAL_ACTION_MANAGED_CONV_OUT: + if (t->byref) { + if (conv_arg) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + mono_mb_emit_icall (mb, conv_to_icall (conv)); + mono_mb_emit_byte (mb, CEE_STIND_I); + } + } + break; case MARSHAL_ACTION_MANAGED_CONV_RESULT: if (conv_to_icall (conv) == mono_marshal_string_to_utf16) @@ -6305,7 +6852,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, MarshalAction action) { MonoMethodBuilder *mb = m->mb; - MonoClass *klass = t->data.klass; + MonoClass *klass = mono_class_from_mono_type (t); int pos, pos2, loc; if (mono_class_from_mono_type (t) == mono_defaults.object_class) { @@ -6320,9 +6867,13 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, m->orig_conv_args [argnum] = 0; if (klass->delegate) { - if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_OUT)) { - char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented."); - mono_mb_emit_exception_marshal_directive (mb, msg); + if (t->byref) { + if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { + char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented."); + mono_mb_emit_exception_marshal_directive (mb, msg); + } + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_stloc (mb, conv_arg); } else { mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN)); @@ -6451,7 +7002,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, /* allocate a new object */ mono_mb_emit_ldarg (mb, argnum); mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, t->data.klass); + mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass); mono_mb_emit_byte (mb, CEE_STIND_REF); } @@ -6477,7 +7028,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 0); /* emit valuetype conversion code */ - emit_struct_conv (mb, t->data.klass, TRUE); + emit_struct_conv (mb, klass, TRUE); /* Free the structure returned by the native code */ emit_struct_free (mb, klass, conv_arg); @@ -6578,6 +7129,23 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, break; } + if (klass == mono_defaults.stringbuilder_class) { + MonoMarshalNative encoding; + + encoding = mono_marshal_get_string_encoding (m->piinfo, spec); + + // FIXME: + g_assert (encoding == MONO_NATIVE_LPSTR); + + g_assert (!t->byref); + g_assert (encoding != -1); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_icall (mb, mono_string_utf8_to_builder2); + mono_mb_emit_stloc (mb, conv_arg); + break; + } + /* The class can not have an automatic layout */ if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) { mono_mb_emit_auto_layout_exception (mb, klass); @@ -6726,6 +7294,8 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, return conv_arg; } +#ifndef DISABLE_COM + static int emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, @@ -7041,6 +7611,8 @@ emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, return conv_arg; } +#endif /* DISABLE_COM */ + static int emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, @@ -7070,7 +7642,7 @@ emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, else *conv_arg_type = &mono_defaults.variant_class->byval_arg; - if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) + if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) break; mono_mb_emit_ldarg (mb, argnum); @@ -7089,7 +7661,7 @@ emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, g_assert (variant_clear); - if (t->byref) { + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { 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); @@ -7122,7 +7694,7 @@ emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, else *conv_arg_type = &mono_defaults.variant_class->byval_arg; - if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) + if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) break; if (t->byref) @@ -7135,7 +7707,7 @@ emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, } case MARSHAL_ACTION_MANAGED_CONV_OUT: { - if (t->byref) { + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { 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); @@ -8007,10 +8579,12 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, if (spec && spec->native == MONO_NATIVE_STRUCT) return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#ifndef DISABLE_COM 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); +#endif if (mono_defaults.safehandle_class != NULL && mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE)) @@ -8040,6 +8614,11 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, case MONO_TYPE_U8: case MONO_TYPE_FNPTR: return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action); + case MONO_TYPE_GENERICINST: + if (mono_type_generic_inst_is_valuetype (t)) + return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action); + else + return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action); } return conv_arg; @@ -8051,13 +8630,14 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t, * @sig: The signature of the native function * @piinfo: Marshalling information * @mspecs: Marshalling information - * @func: the native function to call + * @aot: whenever the created method will be compiled by the AOT compiler + * @method: if non-NULL, the pinvoke method to call * @check_exceptions: Whenever to check for pending exceptions after the native call * * generates IL code for the pinvoke wrapper, the generated code calls @func. */ static void -mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean check_exceptions) +mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions) { EmitMarshalContext m; MonoMethodSignature *csig; @@ -8115,17 +8695,27 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM if (sig->hasthis) mono_mb_emit_byte (mb, CEE_LDARG_0); - for (i = 0; i < sig->param_count; i++) { emit_marshal (&m, i + sig->hasthis, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH); } /* call the native method */ if (MONO_CLASS_IS_IMPORT (mb->method->klass)) { +#ifndef DISABLE_COM mono_mb_emit_cominterop_call (mb, csig, &piinfo->method); +#else + g_assert_not_reached (); +#endif } else { - mono_mb_emit_native_call (mb, csig, func); + if (aot) { + /* Reuse the ICALL_ADDR opcode for pinvokes too */ + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method); + mono_mb_emit_calli (mb, csig); + } else { + mono_mb_emit_native_call (mb, csig, func); + } } /* Set LastError if needed */ @@ -8190,6 +8780,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM case MONO_TYPE_SZARRAY: case MONO_TYPE_CHAR: case MONO_TYPE_PTR: + case MONO_TYPE_GENERICINST: emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT); break; case MONO_TYPE_TYPEDBYREF: @@ -8248,7 +8839,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM * calls the unmanaged code in piinfo->addr) */ MonoMethod * -mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions) +mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot) { MonoMethodSignature *sig, *csig; MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; @@ -8269,8 +8860,13 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions) if ((res = mono_marshal_find_in_cache (cache, method))) return res; - if (MONO_CLASS_IS_IMPORT (method->klass)) + if (MONO_CLASS_IS_IMPORT (method->klass)) { +#ifndef DISABLE_COM return cominterop_get_native_wrapper (method); +#else + g_assert_not_reached (); +#endif + } sig = mono_method_signature (method); @@ -8280,7 +8876,10 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions) if (!piinfo->addr) { if (pinvoke) - mono_lookup_pinvoke_call (method, &exc_class, &exc_arg); + if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE) + exc_arg = "Method contains unsupported native code"; + else + mono_lookup_pinvoke_call (method, &exc_class, &exc_arg); else piinfo->addr = mono_lookup_internal_call (method); } @@ -8331,8 +8930,12 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions) mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE); mb->method->save_lmf = 1; - - if (!piinfo->addr) { + + /* + * In AOT mode and embedding scenarios, it is possible that the icall is not + * registered in the runtime doing the AOT compilation. + */ + if (!piinfo->addr && !aot) { mono_mb_emit_exception (mb, exc_class, exc_arg); csig = signature_dup (method->klass->image, sig); csig->pinvoke = 0; @@ -8358,8 +8961,14 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions) for (i = 0; i < sig->param_count; i++) mono_mb_emit_ldarg (mb, i + sig->hasthis); - g_assert (piinfo->addr); - mono_mb_emit_native_call (mb, csig, piinfo->addr); + if (aot) { + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method); + mono_mb_emit_calli (mb, csig); + } else { + g_assert (piinfo->addr); + mono_mb_emit_native_call (mb, csig, piinfo->addr); + } if (check_exceptions) emit_thread_interrupt_checkpoint (mb); mono_mb_emit_byte (mb, CEE_RET); @@ -8373,11 +8982,13 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions) } g_assert (pinvoke); + if (!aot) + g_assert (piinfo->addr); mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1); mono_method_get_marshal_info (method, mspecs); - mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, check_exceptions); + mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, aot, check_exceptions); csig = signature_dup (method->klass->image, sig); csig->pinvoke = 0; @@ -8423,7 +9034,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE); mb->method->save_lmf = 1; - mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, TRUE); + mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE); csig = signature_dup (image, sig); csig->pinvoke = 0; @@ -8461,17 +9072,6 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i mono_mb_emit_icon (mb, 0); mono_mb_emit_stloc (mb, 2); - /* fixme: howto handle this ? */ - if (sig->hasthis) { - if (this) { - /* FIXME: need a solution for the moving GC here */ - mono_mb_emit_ptr (mb, this); - } else { - /* fixme: */ - g_assert_not_reached (); - } - } - /* we first do all conversions */ tmp_locals = alloca (sizeof (int) * sig->param_count); for (i = 0; i < sig->param_count; i ++) { @@ -8495,6 +9095,17 @@ 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); + } else { + /* fixme: */ + g_assert_not_reached (); + } + } + for (i = 0; i < sig->param_count; i++) { MonoType *t = sig->params [i]; @@ -8521,6 +9132,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i case MONO_TYPE_BOOLEAN: case MONO_TYPE_I1: case MONO_TYPE_U1: + case MONO_TYPE_CHAR: case MONO_TYPE_I2: case MONO_TYPE_U2: case MONO_TYPE_I4: @@ -8565,6 +9177,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i case MONO_TYPE_CLASS: case MONO_TYPE_VALUETYPE: case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); break; } @@ -8596,19 +9209,55 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i } -/* - * generates IL code to call managed methods from unmanaged code - */ -MonoMethod * -mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this) +static void +mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *csig) { - static MonoClass *UnmanagedFunctionPointerAttribute; - MonoMethodSignature *sig, *csig, *invoke_sig; - MonoMethodBuilder *mb; - MonoMethod *res, *invoke; - MonoMarshalSpec **mspecs; - MonoMethodPInvoke piinfo; - GHashTable *cache; + MonoMethodSignature *sig; + int i; + +#ifdef PLATFORM_WIN32 + /* + * Under windows, delegates passed to native code must use the STDCALL + * calling convention. + */ + csig->call_convention = MONO_CALL_STDCALL; +#endif + + sig = mono_method_signature (method); + + /* Change default calling convention if needed */ + /* Why is this a modopt ? */ + if (sig->ret && sig->ret->num_mods) { + for (i = 0; i < sig->ret->num_mods; ++i) { + MonoClass *cmod_class = mono_class_get (method->klass->image, 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; + } + } + } +} + +/* + * 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; @@ -8620,7 +9269,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, * could be called with different delegates, thus different marshalling * options. */ - cache = method->klass->image->managed_wrapper_cache; + cache = get_cache (&method->klass->image->managed_wrapper_cache, mono_aligned_addr_hash, NULL); if (!this && (res = mono_marshal_find_in_cache (cache, method))) return res; @@ -8651,32 +9300,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, 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; - } - } - } + mono_marshal_set_callconv_from_modopt (invoke, csig); /* Handle the UnmanagedFunctionPointerAttribute */ if (!UnmanagedFunctionPointerAttribute) @@ -8727,6 +9351,80 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, return res; } +gpointer +mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) +{ + MonoMethod *method; + MonoMethodSignature *sig; + MonoMethodBuilder *mb; + int i, param_count; + + g_assert (token); + + method = mono_get_method (image, token, NULL); + g_assert (method); + + if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) { + MonoMethodSignature *csig; + MonoMarshalSpec **mspecs; + EmitMarshalContext m; + + sig = mono_method_signature (method); + g_assert (!sig->hasthis); + + mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1); + mono_method_get_marshal_info (method, mspecs); + + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED); + csig = signature_dup (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 = image; + + mono_marshal_set_callconv_from_modopt (method, csig); + + /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */ + + mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, NULL); + + mb->dynamic = 1; + method = mono_mb_create_method (mb, csig, sig->param_count + 16); + mono_mb_free (mb); + + for (i = sig->param_count; i >= 0; i--) + if (mspecs [i]) + mono_metadata_free_marshal_spec (mspecs [i]); + g_free (mspecs); + + return mono_compile_method (method); + } + + sig = mono_method_signature (method); + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED); + + param_count = sig->param_count + sig->hasthis; + for (i = 0; i < param_count; i++) + mono_mb_emit_ldarg (mb, i); + + if (type & VTFIXUP_TYPE_CALL_MOST_DERIVED) + mono_mb_emit_op (mb, CEE_CALLVIRT, method); + else + mono_mb_emit_op (mb, CEE_CALL, method); + mono_mb_emit_byte (mb, CEE_RET); + + mb->dynamic = 1; + method = mono_mb_create_method (mb, sig, param_count); + mono_mb_free (mb); + + return mono_compile_method (method); +} + static MonoReflectionType * type_from_handle (MonoType *handle) { @@ -8758,7 +9456,7 @@ mono_marshal_get_isinst (MonoClass *klass) char *name; MonoMethodBuilder *mb; - cache = klass->image->isinst_cache; + cache = get_cache (&klass->image->isinst_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -8840,7 +9538,7 @@ mono_marshal_get_castclass (MonoClass *klass) char *name; MonoMethodBuilder *mb; - cache = klass->image->castclass_cache; + cache = get_cache (&klass->image->castclass_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -8905,7 +9603,7 @@ mono_marshal_get_proxy_cancast (MonoClass *klass) MonoMethodDesc *desc; MonoMethodBuilder *mb; - cache = klass->image->proxy_isinst_cache; + cache = get_cache (&klass->image->proxy_isinst_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, klass))) return res; @@ -9036,7 +9734,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass) mono_mb_emit_byte (mb, CEE_RET); - res = mono_mb_create_method (mb, mono_method_signature (stoptr), 0); + res = mono_mb_create_method (mb, mono_signature_no_pinvoke (stoptr), 0); mono_mb_free (mb); klass->marshal_info->str_to_ptr = res; @@ -9063,11 +9761,18 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass) if (klass->marshal_info->ptr_to_str) return klass->marshal_info->ptr_to_str; - if (!ptostr) + if (!ptostr) { + MonoMethodSignature *sig; + /* Create the signature corresponding to static void PtrToStructure (IntPtr ptr, object structure); defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */ - ptostr = mono_create_icall_signature ("void ptr object"); + sig = mono_create_icall_signature ("void ptr object"); + sig = signature_dup (mono_defaults.corlib, sig); + sig->pinvoke = 0; + mono_memory_barrier (); + ptostr = sig; + } mb = mono_mb_new (klass, "PtrToStructure", MONO_WRAPPER_UNKNOWN); @@ -9113,7 +9818,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass) MonoMethod * mono_marshal_get_synchronized_wrapper (MonoMethod *method) { - static MonoMethod *enter_method, *exit_method; + static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method; MonoMethodSignature *sig; MonoExceptionClause *clause; MonoMethodHeader *header; @@ -9127,7 +9832,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) return method; - cache = method->klass->image->synchronized_cache; + cache = get_cache (&method->klass->image->synchronized_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, method))) return res; @@ -9140,14 +9845,34 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) if (!MONO_TYPE_IS_VOID (sig->ret)) ret_local = mono_mb_add_local (mb, sig->ret); + if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) { + mono_class_set_failure (method->klass, MONO_EXCEPTION_TYPE_LOAD, NULL); + /* This will throw the type load exception when the wrapper is compiled */ + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_op (mb, CEE_ISINST, method->klass); + mono_mb_emit_byte (mb, CEE_POP); + + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_emit_ldloc (mb, ret_local); + mono_mb_emit_byte (mb, CEE_RET); + + res = mono_mb_create_and_cache (cache, method, + mb, sig, sig->param_count + 16); + mono_mb_free (mb); + + return res; + } + /* this */ this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); mono_loader_lock (); - clause = mono_mempool_alloc0 (method->klass->image->mempool, sizeof (MonoExceptionClause)); + clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause)); mono_loader_unlock (); clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY; + mono_loader_lock (); + if (!enter_method) { MonoMethodDesc *desc; @@ -9155,21 +9880,29 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class); g_assert (enter_method); mono_method_desc_free (desc); + desc = mono_method_desc_new ("Monitor:Exit", FALSE); exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class); g_assert (exit_method); mono_method_desc_free (desc); + + desc = mono_method_desc_new ("Type:GetTypeFromHandle", FALSE); + gettypefromhandle_method = mono_method_desc_search_in_class (desc, mono_defaults.monotype_class->parent); + g_assert (gettypefromhandle_method); + mono_method_desc_free (desc); } + mono_loader_unlock (); + /* Push this or the type object */ if (method->flags & METHOD_ATTRIBUTE_STATIC) { - /* - * GetTypeFromHandle isn't called as a managed method because it has - * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets - * transformed into something else by the JIT. - */ - mono_mb_emit_ptr (mb, &method->klass->byval_arg); - mono_mb_emit_icall (mb, type_from_handle); + /* We have special handling for this in the JIT */ + int index = mono_mb_add_data (mb, method->klass); + mono_mb_add_data (mb, mono_defaults.typehandle_class); + mono_mb_emit_byte (mb, CEE_LDTOKEN); + mono_mb_emit_i4 (mb, index); + + mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL); } else mono_mb_emit_ldarg (mb, 0); @@ -9186,11 +9919,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) mono_mb_emit_ldarg (mb, 0); for (i = 0; i < sig->param_count; i++) mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE)); - - /* this is needed to avoid recursion */ - mono_mb_emit_byte (mb, CEE_PREFIX1); - mono_mb_emit_op (mb, CEE_LDFTN, method); - mono_mb_emit_calli (mb, mono_method_signature (method)); + + mono_mb_emit_managed_call (mb, method, NULL); if (!MONO_TYPE_IS_VOID (sig->ret)) mono_mb_emit_stloc (mb, ret_local); @@ -9202,7 +9932,6 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) /* Call Monitor::Exit() */ mono_mb_emit_ldloc (mb, this_local); -/* mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit); */ mono_mb_emit_managed_call (mb, exit_method, NULL); mono_mb_emit_byte (mb, CEE_ENDFINALLY); @@ -9237,7 +9966,7 @@ mono_marshal_get_unbox_wrapper (MonoMethod *method) MonoMethod *res; GHashTable *cache; - cache = method->klass->image->unbox_wrapper_cache; + cache = get_cache (&method->klass->image->unbox_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, method))) return res; @@ -9975,6 +10704,23 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk) return (*(MonoIUnknown**)pUnk)->Release(pUnk); } +#ifndef DISABLE_COM + +#define MONO_S_OK 0x00000000L +#define MONO_E_NOINTERFACE 0x80004002L +#define MONO_E_NOTIMPL 0x80004001L + +static gboolean cominterop_can_support_dispatch (MonoClass* klass) +{ + if (!(klass->flags & TYPE_ATTRIBUTE_PUBLIC) ) + return FALSE; + + if (!cominterop_com_visible (klass)) + return FALSE; + + return TRUE; +} + static void* cominterop_get_idispatch_for_object (MonoObject* object) { @@ -9986,16 +10732,24 @@ cominterop_get_idispatch_for_object (MonoObject* object) mono_defaults.idispatch_class, TRUE); } else { + MonoClass* klass = mono_object_class (object); + if (!cominterop_can_support_dispatch (klass) ) + cominterop_raise_hr_exception (MONO_E_NOINTERFACE); return cominterop_get_ccw (object, mono_defaults.idispatch_class); } } +#endif + void* ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object) { +#ifndef DISABLE_COM if (!object) return NULL; + mono_init_com_types (); + if (cominterop_object_is_rcw (object)) { MonoClass *klass = NULL; MonoRealProxy* real_proxy = NULL; @@ -10029,11 +10783,15 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (M else { return cominterop_get_ccw (object, mono_defaults.iunknown_class); } +#else + g_assert_not_reached (); +#endif } MonoObject* ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk) { +#ifndef DISABLE_COM MonoObject* object = NULL; if (!pUnk) @@ -10043,17 +10801,27 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk) object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE); return object; +#else + g_assert_not_reached (); +#endif } void* ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object) { +#ifndef DISABLE_COM + mono_init_com_types (); + return cominterop_get_idispatch_for_object (object); +#else + g_assert_not_reached (); +#endif } void* ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type) { +#ifndef DISABLE_COM MonoClass* klass = NULL; void* itf = NULL; g_assert (type); @@ -10063,18 +10831,26 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, Mon itf = cominterop_get_ccw (object, klass); g_assert (itf); return itf; +#else + g_assert_not_reached (); +#endif } MonoBoolean ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object) { +#ifndef DISABLE_COM return (MonoBoolean)cominterop_object_is_rcw (object); +#else + g_assert_not_reached (); +#endif } gint32 ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object) { +#ifndef DISABLE_COM MonoComInteropProxy* proxy = NULL; gint32 ref_count = 0; @@ -10091,6 +10867,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoO ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object); return ref_count; +#else + g_assert_not_reached (); +#endif } guint32 @@ -10098,7 +10877,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal { MONO_ARCH_SAVE_REGS; +#ifndef DISABLE_COM return cominterop_get_com_slot_for_method (m->method); +#else + g_assert_not_reached (); +#endif } guint32 @@ -10240,7 +11023,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t while ((field = mono_class_get_fields (klass, &iter))) { if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) continue; - if (!strcmp (fname, field->name)) { + if (!strcmp (fname, mono_field_get_name (field))) { match_index = i; break; } @@ -10274,9 +11057,22 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t gpointer ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string) { - MONO_ARCH_SAVE_REGS; +#ifdef PLATFORM_WIN32 + char* tres, *ret; + size_t len; + tres = mono_string_to_utf8 (string); + if (!tres) + return tres; + + len = strlen (tres) + 1; + ret = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (len); + memcpy (ret, tres, len); + g_free (tres); + return ret; +#else return mono_string_to_utf8 (string); +#endif } gpointer @@ -10287,7 +11083,12 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString if (string == NULL) return NULL; else { - gunichar2 *res = g_malloc ((mono_string_length (string) + 1) * 2); +#ifdef PLATFORM_WIN32 + gunichar2 *res = ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal + ((mono_string_length (string) + 1) * 2); +#else + gunichar2 *res = g_malloc ((mono_string_length (string) + 1) * 2); +#endif memcpy (res, mono_string_chars (string), mono_string_length (string) * 2); res [mono_string_length (string)] = 0; return res; @@ -10487,7 +11288,7 @@ ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type) } static gboolean -cominterop_finalizer (gpointer key, gpointer value, gpointer user_data) +cominterop_rcw_interface_finalizer (gpointer key, gpointer value, gpointer user_data) { ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value); return TRUE; @@ -10506,22 +11307,72 @@ ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj) g_hash_table_remove (rcw_hash, obj->iunknown); } - g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL); + g_hash_table_foreach_remove (obj->itf_hash, cominterop_rcw_interface_finalizer, NULL); + g_hash_table_destroy (obj->itf_hash); ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown); obj->itf_hash = obj->iunknown = NULL; mono_cominterop_unlock (); } } +#ifndef DISABLE_COM + +static gboolean +cominterop_rcw_finalizer (gpointer key, gpointer value, gpointer user_data) +{ + guint32 gchandle = 0; + + gchandle = GPOINTER_TO_UINT (value); + if (gchandle) { + MonoComInteropProxy* proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle); + + if (proxy) { + if (proxy->com_object->itf_hash) { + g_hash_table_foreach_remove (proxy->com_object->itf_hash, cominterop_rcw_interface_finalizer, NULL); + g_hash_table_destroy (proxy->com_object->itf_hash); + } + if (proxy->com_object->iunknown) + ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (proxy->com_object->iunknown); + proxy->com_object->itf_hash = proxy->com_object->iunknown = NULL; + } + + mono_gchandle_free (gchandle); + } + + return TRUE; +} + +void +cominterop_release_all_rcws () +{ + if (!rcw_hash) + return; + + mono_cominterop_lock (); + + g_hash_table_foreach_remove (rcw_hash, cominterop_rcw_finalizer, NULL); + g_hash_table_destroy (rcw_hash); + rcw_hash = NULL; + + mono_cominterop_unlock (); +} + +#endif + gpointer ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception) { +#ifndef DISABLE_COM return cominterop_get_interface (obj, mono_type_get_class (type->type), (gboolean)throw_exception); +#else + g_assert_not_reached (); +#endif } void ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy) { +#ifndef DISABLE_COM guint32 gchandle = 0; if (!rcw_hash) { mono_cominterop_lock (); @@ -10534,11 +11385,15 @@ ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropPr mono_cominterop_lock (); g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle)); mono_cominterop_unlock (); +#else + g_assert_not_reached (); +#endif } MonoComInteropProxy* ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk) { +#ifndef DISABLE_COM MonoComInteropProxy* proxy = NULL; guint32 gchandle = 0; @@ -10555,6 +11410,9 @@ ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk) } } return proxy; +#else + g_assert_not_reached (); +#endif } /** @@ -10627,7 +11485,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_mempool_alloc0 (klass->image->mempool, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count); + info = mono_image_alloc0 (klass->image, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count); info->num_fields = count; /* Try to find a size for this type in metadata */ @@ -10653,13 +11511,13 @@ mono_marshal_load_type_info (MonoClass* klass) if (mono_field_is_deleted (field)) continue; if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL) - mono_metadata_field_info (klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1, + mono_metadata_field_info_with_mempool (klass->image->mempool, klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1, NULL, NULL, &info->fields [j].mspec); info->fields [j].field = field; if ((mono_class_num_fields (klass) == 1) && (klass->instance_size == sizeof (MonoObject)) && - (strcmp (field->name, "$PRIVATE$") == 0)) { + (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) { /* This field is a hack inserted by MCS to empty structures */ continue; } @@ -10710,6 +11568,9 @@ mono_marshal_load_type_info (MonoClass* klass) loads_list = g_slist_remove (loads_list, klass); TlsSetValue (load_type_info_tls_id, loads_list); + /*We do double-checking locking on marshal_info */ + mono_memory_barrier (); + klass->marshal_info = info; mono_loader_unlock (); @@ -10743,6 +11604,11 @@ mono_class_native_size (MonoClass *klass, guint32 *align) return klass->marshal_info->native_size; } +/* __alignof__ returns the preferred alignment of values not the actual alignment used by + the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary + but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */ +#define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x) + /* * mono_type_native_stack_size: * @t: the type to return the size it uses on the stack @@ -10761,8 +11627,8 @@ mono_type_native_stack_size (MonoType *t, guint32 *align) align = &tmp; if (t->byref) { - *align = 4; - return 4; + *align = sizeof (gpointer); + return sizeof (gpointer); } switch (t->type){ @@ -10774,6 +11640,8 @@ mono_type_native_stack_size (MonoType *t, guint32 *align) case MONO_TYPE_U2: case MONO_TYPE_I4: case MONO_TYPE_U4: + *align = 4; + return 4; case MONO_TYPE_I: case MONO_TYPE_U: case MONO_TYPE_STRING: @@ -10783,24 +11651,33 @@ mono_type_native_stack_size (MonoType *t, guint32 *align) case MONO_TYPE_PTR: case MONO_TYPE_FNPTR: case MONO_TYPE_ARRAY: - case MONO_TYPE_TYPEDBYREF: - *align = 4; - return 4; + *align = sizeof (gpointer); + return sizeof (gpointer); case MONO_TYPE_R4: *align = 4; return 4; + case MONO_TYPE_R8: + *align = ALIGNMENT (gdouble); + return 8; case MONO_TYPE_I8: case MONO_TYPE_U8: - case MONO_TYPE_R8: - *align = 4; + *align = ALIGNMENT (glong); return 8; + case MONO_TYPE_GENERICINST: + if (!mono_type_generic_inst_is_valuetype (t)) { + *align = sizeof (gpointer); + return sizeof (gpointer); + } + /* Fall through */ + case MONO_TYPE_TYPEDBYREF: case MONO_TYPE_VALUETYPE: { guint32 size; + MonoClass *klass = mono_class_from_mono_type (t); - if (t->data.klass->enumtype) - return mono_type_native_stack_size (t->data.klass->enum_basetype, align); + if (klass->enumtype) + return mono_type_native_stack_size (klass->enum_basetype, align); else { - size = mono_class_native_size (t->data.klass, align); + size = mono_class_native_size (klass, align); *align = *align + 3; *align &= ~3; @@ -10816,11 +11693,6 @@ mono_type_native_stack_size (MonoType *t, guint32 *align) return 0; } -/* __alignof__ returns the preferred alignment of values not the actual alignment used by - the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary - but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */ -#define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x) - gint32 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align, gboolean as_field, gboolean unicode) @@ -11118,6 +11990,8 @@ mono_win32_compat_ZeroMemory (gpointer dest, gsize length) /* Put COM Interop related stuff here */ +#ifndef DISABLE_COM + /** * cominterop_get_ccw_object: * @ccw_entry: a pointer to the CCWEntry @@ -11235,6 +12109,9 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) if (!ccw) { ccw = g_new0 (MonoCCW, 1); +#ifdef PLATFORM_WIN32 + ccw->free_marshaler = 0; +#endif ccw->vtable_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); ccw->ref_count = 0; /* just alloc a weak handle until we are addref'd*/ @@ -11282,7 +12159,7 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) if (!ccw_entry) { int vtable_index = method_count-1+start_slot; mono_loader_lock (); - vtable = mono_mempool_alloc0 (klass->image->mempool, sizeof (gpointer)*(method_count+start_slot)); + vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot)); mono_loader_unlock (); memcpy (vtable, iunknown, sizeof (iunknown)); if (start_slot == 7) @@ -11309,14 +12186,46 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) /* move managed args up one */ - for (param_index = sig->param_count; param_index >= 1; param_index--) - mspecs [param_index+1] = mspecs [param_index]; + for (param_index = sig->param_count; param_index >= 1; param_index--) { + int mspec_index = param_index+1; + mspecs [mspec_index] = mspecs [param_index]; + + if (mspecs[mspec_index] == NULL) { + if (sig_adjusted->params[param_index]->type == MONO_TYPE_OBJECT) { + mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1); + mspecs[mspec_index]->native = MONO_NATIVE_STRUCT; + } + else if (sig_adjusted->params[param_index]->type == MONO_TYPE_STRING) { + mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1); + mspecs[mspec_index]->native = MONO_NATIVE_BSTR; + } + else if (sig_adjusted->params[param_index]->type == MONO_TYPE_CLASS) { + mspecs[mspec_index] = g_new0 (MonoMarshalSpec, 1); + mspecs[mspec_index]->native = MONO_NATIVE_INTERFACE; + } + } + } /* first arg is IntPtr for interface */ mspecs [1] = NULL; /* move return spec to last param */ if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) { + if (mspecs [0] == NULL) { + if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_OBJECT) { + mspecs[0] = g_new0 (MonoMarshalSpec, 1); + mspecs[0]->native = MONO_NATIVE_STRUCT; + } + else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_STRING) { + mspecs[0] = g_new0 (MonoMarshalSpec, 1); + mspecs[0]->native = MONO_NATIVE_BSTR; + } + else if (sig_adjusted->params[sig_adjusted->param_count-1]->type == MONO_TYPE_CLASS) { + mspecs[0] = g_new0 (MonoMarshalSpec, 1); + mspecs[0]->native = MONO_NATIVE_INTERFACE; + } + } + mspecs [sig_adjusted->param_count] = mspecs [0]; mspecs [0] = NULL; } @@ -11326,7 +12235,7 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL); mono_loader_lock (); mono_marshal_lock (); - wrapper_method = mono_mb_create_method (mb, sig_adjusted, sig_adjusted->param_count + 16); + wrapper_method = mono_mb_create_method (mb, m.csig, m.csig->param_count + 16); mono_marshal_unlock (); mono_loader_unlock (); @@ -11414,7 +12323,7 @@ mono_marshal_free_ccw (MonoObject* object) } /** - * cominterop_get_native_wrapper_adjusted: + * cominterop_get_managed_wrapper_adjusted: * @method: managed COM Interop method * * Returns: the generated method to call with signature matching @@ -11589,15 +12498,45 @@ cominterop_ccw_release (MonoCCWInterface* ccwe) /* allow gc of object */ guint32 oldhandle = ccw->gc_handle; g_assert (oldhandle); +#ifdef PLATFORM_WIN32 + if (ccw->free_marshaler) + ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (ccw->free_marshaler); +#endif ccw->gc_handle = mono_gchandle_new_weakref (mono_gchandle_get_target (oldhandle), FALSE); mono_gchandle_free (oldhandle); } return ref_count; } -#define MONO_S_OK 0x00000000L -#define MONO_E_NOINTERFACE 0x80004002L -#define MONO_E_NOTIMPL 0x80004001L +#ifdef PLATFORM_WIN32 +static const IID MONO_IID_IMarshal = {0x3, 0x0, 0x0, {0xC0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46}}; +#endif + +#ifdef PLATFORM_WIN32 +/* All ccw objects are free threaded */ +static int +cominterop_ccw_getfreethreadedmarshaler (MonoCCW* ccw, MonoObject* object, gpointer* ppv) +{ +#ifdef PLATFORM_WIN32 + if (!ccw->free_marshaler) { + int ret = 0; + gpointer tunk; + tunk = cominterop_get_ccw (object, mono_defaults.iunknown_class); + /* remember to addref on QI */ + cominterop_ccw_addref (tunk); + ret = CoCreateFreeThreadedMarshaler (tunk, (LPUNKNOWN*)&ccw->free_marshaler); + cominterop_ccw_release(tunk); + } + + if (!ccw->free_marshaler) + return MONO_E_NOINTERFACE; + + return ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (ccw->free_marshaler, (IID*)&MONO_IID_IMarshal, ppv); +#else + return MONO_E_NOINTERFACE; +#endif +} +#endif static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv) @@ -11615,6 +12554,9 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p if (ppv) *ppv = NULL; + if (!mono_domain_get ()) + mono_thread_attach (mono_get_root_domain ()); + /* handle IUnknown special */ if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) { *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class); @@ -11625,12 +12567,22 @@ cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* p /* handle IDispatch special */ if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) { + if (!cominterop_can_support_dispatch (klass)) + return MONO_E_NOINTERFACE; + *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class); /* remember to addref on QI */ cominterop_ccw_addref (*ppv); return MONO_S_OK; } +#ifdef PLATFORM_WIN32 + /* handle IMarshal special */ + if (0 == memcmp (riid, &MONO_IID_IMarshal, sizeof (IID))) { + return cominterop_ccw_getfreethreadedmarshaler (ccw, object, ppv); + } +#endif + ifaces = mono_class_get_implemented_interfaces (klass); if (ifaces) { for (i = 0; i < ifaces->len; ++i) { @@ -11682,3 +12634,182 @@ cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember, { return MONO_E_NOTIMPL; } + +#else /* DISABLE_COM */ + +gboolean +mono_marshal_free_ccw (MonoObject* object) +{ + return FALSE; +} + +#endif /* DISABLE_COM */ + +void +mono_marshal_find_nonzero_bit_offset (guint8 *buf, int len, int *byte_offset, guint8 *bitmask) +{ + int i; + guint8 byte; + + for (i = 0; i < len; ++i) + if (buf [i]) + break; + + g_assert (i < len); + + byte = buf [i]; + while (byte && !(byte & 1)) + byte >>= 1; + g_assert (byte == 1); + + *byte_offset = i; + *bitmask = buf [i]; +} + +MonoMethod * +mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) +{ + MonoMethodBuilder *mb; + MonoMethodSignature *sig, *csig; + MonoExceptionClause *clause; + MonoMethodHeader *header; + MonoImage *image; + MonoClass *klass; + GHashTable *cache; + MonoMethod *res; + int i, param_count, sig_size, pos_leave; + + g_assert (method); + + klass = method->klass; + image = method->klass->image; + cache = get_cache (&image->thunk_invoke_cache, mono_aligned_addr_hash, NULL); + + if ((res = mono_marshal_find_in_cache (cache, method))) + return res; + + sig = mono_method_signature (method); + mb = mono_mb_new (klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED); + + /* add "this" and exception param */ + param_count = sig->param_count + sig->hasthis + 1; + + /* dup & extend signature */ + csig = mono_metadata_signature_alloc (image, param_count); + sig_size = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *)); + memcpy (csig, sig, sig_size); + csig->param_count = param_count; + csig->hasthis = 0; + csig->pinvoke = 1; + csig->call_convention = MONO_CALL_DEFAULT; + + if (sig->hasthis) { + /* add "this" */ + csig->params [0] = &klass->byval_arg; + /* move params up by one */ + for (i = 0; i < sig->param_count; i++) + csig->params [i + 1] = sig->params [i]; + } + + /* setup exception param as byref+[out] */ + csig->params [param_count - 1] = mono_metadata_type_dup (image->mempool, + &mono_defaults.exception_class->byval_arg); + csig->params [param_count - 1]->byref = 1; + csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT; + + /* convert struct return to object */ + if (MONO_TYPE_ISSTRUCT (sig->ret)) + csig->ret = &mono_defaults.object_class->byval_arg; + + /* local 0 (temp for exception object) */ + mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); + + /* local 1 (temp for result) */ + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_add_local (mb, sig->ret); + + /* clear exception arg */ + mono_mb_emit_ldarg (mb, param_count - 1); + mono_mb_emit_byte (mb, CEE_LDNULL); + mono_mb_emit_byte (mb, CEE_STIND_REF); + + /* try */ + mono_loader_lock (); + clause = mono_image_alloc0 (image, sizeof (MonoExceptionClause)); + mono_loader_unlock (); + clause->try_offset = mono_mb_get_label (mb); + + /* push method's args */ + for (i = 0; i < param_count - 1; i++) { + MonoType *type; + MonoClass *klass; + + mono_mb_emit_ldarg (mb, i); + + /* get the byval type of the param */ + klass = mono_class_from_mono_type (csig->params [i]); + type = &klass->byval_arg; + + /* unbox struct args */ + if (MONO_TYPE_ISSTRUCT (type)) { + mono_mb_emit_op (mb, CEE_UNBOX, klass); + + /* byref args & and the "this" arg must remain a ptr. + Otherwise make a copy of the value type */ + if (!(csig->params [i]->byref || (i == 0 && sig->hasthis))) + mono_mb_emit_op (mb, CEE_LDOBJ, klass); + + csig->params [i] = &mono_defaults.object_class->byval_arg; + } + } + + /* call */ + if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) + mono_mb_emit_op (mb, CEE_CALLVIRT, method); + else + mono_mb_emit_op (mb, CEE_CALL, method); + + /* save result at local 1 */ + if (!MONO_TYPE_IS_VOID (sig->ret)) + mono_mb_emit_stloc (mb, 1); + + pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE); + + /* catch */ + clause->flags = MONO_EXCEPTION_CLAUSE_NONE; + clause->try_len = mono_mb_get_pos (mb) - clause->try_offset; + clause->data.catch_class = mono_defaults.object_class; + + clause->handler_offset = mono_mb_get_label (mb); + + /* store exception at local 0 */ + mono_mb_emit_stloc (mb, 0); + mono_mb_emit_ldarg (mb, param_count - 1); + mono_mb_emit_ldloc (mb, 0); + mono_mb_emit_byte (mb, CEE_STIND_REF); + mono_mb_emit_branch (mb, CEE_LEAVE); + + clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; + + mono_mb_patch_branch (mb, pos_leave); + /* end-try */ + + if (!MONO_TYPE_IS_VOID (sig->ret)) { + mono_mb_emit_ldloc (mb, 1); + + /* box the return value */ + if (MONO_TYPE_ISSTRUCT (sig->ret)) + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret)); + } + + mono_mb_emit_byte (mb, CEE_RET); + + res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16); + mono_mb_free (mb); + + header = ((MonoMethodNormal *)res)->header; + header->num_clauses = 1; + header->clauses = clause; + + return res; +}