X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=0e622038db80c04f7079df339dfe1027970c8b0f;hb=0be4b9d8f775612c61487226ba0f1a721b9779fa;hp=8692f3ebe5dab11d236006a338355a3a019dbee2;hpb=2e4a420748c1ee7b4f56237bdea7544d53a93caf;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 8692f3ebe5d..0e622038db8 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -4,11 +4,16 @@ * Author: * Paolo Molaro (lupus@ximian.com) * - * (C) 2002 Ximian, Inc. http://www.ximian.com + * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) * */ #include "config.h" +#ifdef HAVE_ALLOCA_H +#include +#endif + #include "object.h" #include "loader.h" #include "cil-coff.h" @@ -28,6 +33,7 @@ #include "mono/metadata/string-icalls.h" #include "mono/metadata/attrdefs.h" #include "mono/metadata/gc-internal.h" +#include "mono/metadata/cominterop.h" #include "mono/utils/mono-counters.h" #include #include @@ -44,13 +50,6 @@ 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 @@ -76,14 +75,6 @@ typedef struct _MonoRemotingMethods MonoRemotingMethods; #define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex) static CRITICAL_SECTION marshal_mutex; -/* This mutex protects the various cominterop related caches in MonoImage */ -#define mono_cominterop_lock() EnterCriticalSection (&cominterop_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; @@ -106,12 +97,6 @@ mono_marshal_string_to_utf16_copy (MonoString *s); static gpointer mono_string_to_lpstr (MonoString *string_obj); -static MonoString * -mono_string_from_bstr (gpointer bstr); - -static void -mono_free_bstr (gpointer bstr); - static MonoStringBuilder * mono_string_utf8_to_builder2 (char *text); @@ -151,9 +136,6 @@ type_from_handle (MonoType *handle); 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); - static void init_safe_handle (void); /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */ @@ -191,8 +173,8 @@ signature_dup (MonoImage *image, MonoMethodSignature *sig) 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) { @@ -203,362 +185,17 @@ signature_no_pinvoke (MonoMethod *method) return sig; } -/* Begin COM Interop related stuff until seperate file */ - - -/* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */ -#ifdef PLATFORM_WIN32 -#define STDCALL __stdcall -#else -#define STDCALL -#endif - -/* Upon creation of a CCW, only allocate a weak handle and set the - * reference count to 0. If the unmanaged client code decides to addref and - * hold onto the CCW, I then allocate a strong handle. Once the reference count - * goes back to 0, convert back to a weak handle. - */ -typedef struct { - guint32 ref_count; - guint32 gc_handle; - GHashTable* vtable_hash; -} MonoCCW; - -/* This type is the actual pointer passed to unmanaged code - * to represent a COM interface. - */ -typedef struct { - gpointer vtable; - MonoCCW* ccw; -} MonoCCWInterface; - -/* IUnknown */ -static int STDCALL cominterop_ccw_addref (MonoCCWInterface* ccwe); - -static int STDCALL cominterop_ccw_release (MonoCCWInterface* ccwe); - -static int STDCALL cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv); - -/* IDispatch */ -static int STDCALL cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo); - -static int STDCALL cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo); - -static int STDCALL cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid, - gunichar2** rgszNames, guint32 cNames, - guint32 lcid, gint32 *rgDispId); - -static int STDCALL cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember, - gpointer riid, guint32 lcid, - guint16 wFlags, gpointer pDispParams, - gpointer pVarResult, gpointer pExcepInfo, - guint32 *puArgErr); - -static MonoMethod * -cominterop_get_managed_wrapper_adjusted (MonoMethod *method); - -static gpointer -cominterop_get_ccw (MonoObject* object, MonoClass* itf); - -static MonoObject* -cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify); - -/** - * cominterop_method_signature: - * @method: a method - * - * Returns: the corresponding unmanaged method signature for a managed COM - * method. - */ -static MonoMethodSignature* -cominterop_method_signature (MonoMethod* method) -{ - MonoMethodSignature *res; - MonoImage *image = method->klass->image; - MonoMethodSignature *sig = mono_method_signature (method); - gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG; - int sigsize; - int i; - int param_count = sig->param_count + 1; // convert this arg into IntPtr arg - - if (!preserve_sig &&!MONO_TYPE_IS_VOID (sig->ret)) - param_count++; - - 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 - for (i = sig->param_count-1; i >= 0; i--) - res->params[i+1] = sig->params[i]; - - // first arg is interface pointer - res->params[0] = &mono_defaults.int_class->byval_arg; - - if (preserve_sig) { - res->ret = sig->ret; - } - else { - // last arg is return type - if (!MONO_TYPE_IS_VOID (sig->ret)) { - res->params[param_count-1] = mono_metadata_type_dup (image->mempool, sig->ret); - res->params[param_count-1]->byref = 1; - res->params[param_count-1]->attrs = PARAM_ATTRIBUTE_OUT; - } - - // return type is always int32 (HRESULT) - res->ret = &mono_defaults.int32_class->byval_arg; - } - - // no pinvoke - res->pinvoke = FALSE; - - // no hasthis - res->hasthis = 0; - - // set param_count - res->param_count = param_count; - - // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM -#ifdef PLATFORM_WIN32 - res->call_convention = MONO_CALL_STDCALL; -#else - res->call_convention = MONO_CALL_C; -#endif - - return res; -} - -/** - * cominterop_get_function_pointer: - * @itf: a pointer to the COM interface - * @slot: the vtable slot of the method pointer to return - * - * Returns: the unmanaged vtable function pointer from the interface - */ -static gpointer -cominterop_get_function_pointer (gpointer itf, int slot) -{ - gpointer func; - func = *((*(gpointer**)itf)+slot); - return func; -} - -/** - * cominterop_object_is_com_object: - * @obj: a pointer to the object - * - * Returns: a value indicating if the object is a - * Runtime Callable Wrapper (RCW) for a COM object - */ -static gboolean -cominterop_object_is_rcw (MonoObject *obj) -{ - MonoClass *klass = NULL; - MonoRealProxy* real_proxy = NULL; - if (!obj) - return FALSE; - klass = mono_object_class (obj); - if (klass != mono_defaults.transparent_proxy_class) - return FALSE; - - real_proxy = ((MonoTransparentProxy*)obj)->rp; - if (!real_proxy) - return FALSE; - - klass = mono_object_class (real_proxy); - return (klass && klass == mono_defaults.com_interop_proxy_class); -} - -static int -cominterop_get_com_slot_begin (MonoClass* klass) -{ - static MonoClass *interface_type_attribute = NULL; - MonoCustomAttrInfo *cinfo = NULL; - MonoInterfaceTypeAttribute* itf_attr = NULL; - - if (!interface_type_attribute) - interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute"); - cinfo = mono_custom_attrs_from_class (klass); - if (cinfo) { - itf_attr = (MonoInterfaceTypeAttribute*)mono_custom_attrs_get_attr (cinfo, interface_type_attribute); - if (!cinfo->cached) - mono_custom_attrs_free (cinfo); - } - - if (itf_attr && itf_attr->intType == 1) - return 3; /* 3 methods in IUnknown*/ - else - return 7; /* 7 methods in IDispatch*/ -} - -/** - * cominterop_get_method_interface: - * @method: method being called - * - * Returns: the MonoClass* representing the interface on which - * the method is defined. - */ -static MonoClass* -cominterop_get_method_interface (MonoMethod* method) -{ - MonoClass *ic = method->klass; - - /* if method is on a class, we need to look up interface method exists on */ - if (!MONO_CLASS_IS_INTERFACE(method->klass)) { - GPtrArray *ifaces = mono_class_get_implemented_interfaces (method->klass); - if (ifaces) { - int i; - for (i = 0; i < ifaces->len; ++i) { - int offset; - ic = g_ptr_array_index (ifaces, i); - offset = mono_class_interface_offset (method->klass, ic); - if (method->slot >= offset && method->slot < offset + ic->method.count) - break; - ic = NULL; - } - g_ptr_array_free (ifaces, TRUE); - } - } - - g_assert (ic); - g_assert (MONO_CLASS_IS_INTERFACE (ic)); - - return ic; -} - -/** - * cominterop_get_com_slot_for_method: - * @method: a method - * - * Returns: the method's slot in the COM interface vtable - */ -static int -cominterop_get_com_slot_for_method (MonoMethod* method) -{ - guint32 slot = method->slot; - MonoClass *ic = method->klass; - - /* if method is on a class, we need to look up interface method exists on */ - if (!MONO_CLASS_IS_INTERFACE(ic)) { - int offset = 0; - ic = cominterop_get_method_interface (method); - offset = mono_class_interface_offset (method->klass, ic); - g_assert(offset >= 0); - slot -= offset; - } - - g_assert (ic); - g_assert (MONO_CLASS_IS_INTERFACE (ic)); - - return slot + cominterop_get_com_slot_begin (ic); -} - - -static void -cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid); - -static gboolean -cominterop_class_guid (MonoClass* klass, guint8* guid) -{ - static MonoClass *GuidAttribute = NULL; - MonoCustomAttrInfo *cinfo; - - /* Handle the GuidAttribute */ - if (!GuidAttribute) - GuidAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "GuidAttribute"); - - cinfo = mono_custom_attrs_from_class (klass); - if (cinfo) { - MonoReflectionGuidAttribute *attr = (MonoReflectionGuidAttribute*)mono_custom_attrs_get_attr (cinfo, GuidAttribute); - - if (!attr) - return FALSE; - if (!cinfo->cached) - mono_custom_attrs_free (cinfo); - - cominterop_mono_string_to_guid (attr->guid, guid); - return TRUE; - } - return FALSE; -} - -/** - * cominterop_get_interface: - * @obj: managed wrapper object containing COM object - * @ic: interface type to retrieve for COM object - * - * Returns: the COM interface requested - */ -static gpointer -cominterop_get_interface (MonoComObject* obj, MonoClass* ic, gboolean throw_exception) -{ - gpointer itf = NULL; - - g_assert (ic); - g_assert (MONO_CLASS_IS_INTERFACE (ic)); - - mono_cominterop_lock (); - if (obj->itf_hash) - itf = g_hash_table_lookup (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id)); - mono_cominterop_unlock (); - - if (!itf) { - guint8 iid [16]; - int found = cominterop_class_guid (ic, iid); - int hr; - 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); - } - - if (hr >= 0 && itf) { - mono_cominterop_lock (); - if (!obj->itf_hash) - obj->itf_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - g_hash_table_insert (obj->itf_hash, GUINT_TO_POINTER ((guint)ic->interface_id), itf); - mono_cominterop_unlock (); - } - - } - if (throw_exception) - g_assert (itf); - - return itf; -} - -static int -cominterop_get_hresult_for_exception (MonoException* exc) -{ - int hr = 0; - return hr; -} - 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); @@ -567,9 +204,6 @@ mono_marshal_init (void) register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE); register_icall (mono_string_to_utf8, "mono_string_to_utf8", "ptr obj", FALSE); register_icall (mono_string_to_lpstr, "mono_string_to_lpstr", "ptr obj", FALSE); - register_icall (mono_string_to_bstr, "mono_string_to_bstr", "ptr obj", FALSE); - register_icall (mono_string_from_bstr, "mono_string_from_bstr", "obj ptr", FALSE); - register_icall (mono_free_bstr, "mono_free_bstr", "void ptr", FALSE); register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE); register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE); register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE); @@ -607,24 +241,19 @@ 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); - 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); - register_icall (cominterop_get_ccw, "cominterop_get_ccw", "ptr object ptr", FALSE); - 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); + + mono_cominterop_init (); } } void mono_marshal_cleanup (void) { - g_hash_table_destroy (wrapper_hash); + mono_cominterop_cleanup (); + TlsFree (load_type_info_tls_id); TlsFree (last_error_tls_id); DeleteCriticalSection (&marshal_mutex); - DeleteCriticalSection (&cominterop_mutex); } MonoClass *byte_array_class; @@ -685,6 +314,18 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate) method = delegate->method; + if (mono_method_signature (method)->pinvoke) { + const char *exc_class, *exc_arg; + gpointer ftnptr; + + ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg); + if (!ftnptr) { + g_assert (exc_class); + mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg)); + } + return ftnptr; + } + wrapper = mono_marshal_get_managed_wrapper (method, klass, delegate->target); delegate->delegate_trampoline = mono_compile_method (wrapper); @@ -754,6 +395,9 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn) #endif MonoDelegate *d; + if (ftn == NULL) + return NULL; + mono_marshal_lock (); if (delegate_hash_table == NULL) delegate_hash_table = delegate_hash_table_new (); @@ -1018,8 +662,7 @@ gpointer mono_string_builder_to_utf8 (MonoStringBuilder *sb) { GError *error = NULL; - glong *res; - gchar *tmp; + gchar *tmp, *res = NULL; if (!sb) return NULL; @@ -1033,14 +676,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); } @@ -1127,137 +768,6 @@ 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) -{ - if (!string_obj) - return NULL; -#ifdef PLATFORM_WIN32 - return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj)); -#else - 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) -{ - if (!bstr) - return NULL; -#ifdef PLATFORM_WIN32 - return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr)); -#else - 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 - 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 -} - /** * mono_string_to_byvalstr: * @dst: Where to store the null-terminated utf8 decoded string. @@ -1368,21 +878,6 @@ mono_mb_emit_contextbound_check (MonoMethodBuilder *mb, int branch_code) return mono_mb_emit_branch (mb, branch_code); } -static void -mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method) -{ - // get function pointer from 1st arg, the COM interface pointer - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method)); - mono_mb_emit_icall (mb, cominterop_get_function_pointer); - - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF); - mono_mb_emit_calli (mb, sig); - mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); - mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF); -} - static void mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, const char *msg) { @@ -1431,7 +926,7 @@ handle_enum: return CEE_LDIND_R8; case MONO_TYPE_VALUETYPE: if (type->data.klass->enumtype) { - type = type->data.klass->enum_basetype; + type = mono_class_enum_basetype (type->data.klass); goto handle_enum; } return CEE_LDOBJ; @@ -1485,7 +980,7 @@ handle_enum: return CEE_STIND_R8; case MONO_TYPE_VALUETYPE: if (type->data.klass->enumtype) { - type = type->data.klass->enum_basetype; + type = mono_class_enum_basetype (type->data.klass); goto handle_enum; } return CEE_STOBJ; @@ -1722,78 +1217,14 @@ 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: { - static MonoClass* com_interop_proxy_class = NULL; - static MonoMethod* com_interop_proxy_get_proxy = NULL; - static MonoMethod* get_transparent_proxy = NULL; - int real_proxy; - guint32 pos_null = 0, pos_ccw = 0, pos_end = 0; - MonoClass *klass = NULL; - - /* COM types are initialized lazily */ - mono_init_com_types (); - - klass = mono_class_from_mono_type (type); - - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - /* load dst to store later */ - mono_mb_emit_ldloc (mb, 1); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_ccw_object); - pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); - - if (!com_interop_proxy_class) - com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); - if (!com_interop_proxy_get_proxy) - com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE); - if (!get_transparent_proxy) - get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0); - - real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg); - mono_mb_emit_icall (mb, type_from_handle); - mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL); - mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL); - if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) { - g_assert (klass); - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - } - mono_mb_emit_byte (mb, CEE_STIND_REF); - pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S); - - /* is already managed object */ - mono_mb_patch_short_branch (mb, pos_ccw); - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_ccw_object); - - if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) { - g_assert (klass); - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - } - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_patch_short_branch (mb, pos_end); - /* case if null */ - mono_mb_patch_short_branch (mb, pos_null); - break; - } + case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: + mono_cominterop_emit_ptr_to_object_conv (mb, type, conv, mspec); + break; +#endif /* DISABLE_COM */ case MONO_MARSHAL_CONV_SAFEHANDLE: { /* @@ -2095,93 +1526,14 @@ 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: { - guint32 pos_null = 0, pos_rcw = 0, pos_end = 0; - - /* COM types are initialized lazily */ - mono_init_com_types (); - - - mono_mb_emit_ldloc (mb, 1); - mono_mb_emit_icon (mb, 0); - mono_mb_emit_byte (mb, CEE_CONV_U); - mono_mb_emit_byte (mb, CEE_STIND_I); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - // if null just break, dst was already inited to 0 - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_icall (mb, cominterop_object_is_rcw); - pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - // load dst to store later - mono_mb_emit_ldloc (mb, 1); - - // load src - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - /* load the RCW from the ComInteropProxy*/ - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) { - mono_mb_emit_ptr (mb, mono_type_get_class (type)); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_interface); - - } - else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) { - static MonoProperty* iunknown = NULL; - - if (!iunknown) - iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown"); - mono_mb_emit_managed_call (mb, iunknown->get, NULL); - } - else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) { - static MonoProperty* idispatch = NULL; - - if (!idispatch) - idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch"); - mono_mb_emit_managed_call (mb, idispatch->get, NULL); - } - else { - g_assert_not_reached (); - } - mono_mb_emit_byte (mb, CEE_STIND_I); - pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S); - - // if not rcw - mono_mb_patch_short_branch (mb, pos_rcw); - /* load dst to store later */ - mono_mb_emit_ldloc (mb, 1); - /* load src */ - mono_mb_emit_ldloc (mb, 0); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) - mono_mb_emit_ptr (mb, mono_type_get_class (type)); - else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) - mono_mb_emit_ptr (mb, mono_defaults.iunknown_class); - else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) - mono_mb_emit_ptr (mb, mono_defaults.idispatch_class); - else - g_assert_not_reached (); - mono_mb_emit_icall (mb, cominterop_get_ccw); - mono_mb_emit_byte (mb, CEE_STIND_I); - - mono_mb_patch_short_branch (mb, pos_end); - mono_mb_patch_short_branch (mb, pos_null); + case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: + mono_cominterop_emit_object_to_ptr_conv (mb, type, conv, mspec); break; - } +#endif /* DISABLE_COM */ case MONO_MARSHAL_CONV_SAFEHANDLE: { int dar_release_slot, pos; @@ -2348,7 +1700,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object) int src_var, dst_var; if (ftype->data.klass->enumtype) { - ftype = ftype->data.klass->enum_basetype; + ftype = mono_class_enum_basetype (ftype->data.klass); goto handle_enum; } @@ -2490,6 +1842,12 @@ emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb) emit_thread_interrupt_checkpoint_call (mb, mono_thread_force_interruption_checkpoint); } +void +mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb) +{ + emit_thread_interrupt_checkpoint (mb); +} + static MonoAsyncResult * mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params) { @@ -2767,7 +2125,32 @@ mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec } } -static inline MonoMethod* +/* + * 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; +} + +GHashTable* +mono_marshal_get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func) +{ + return get_cache (var, hash_func, equal_func); +} + +MonoMethod* mono_marshal_find_in_cache (GHashTable *cache, gpointer key) { MonoMethod *res; @@ -2778,8 +2161,20 @@ 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* +MonoMethod* mono_mb_create_and_cache (GHashTable *cache, gpointer key, MonoMethodBuilder *mb, MonoMethodSignature *sig, int max_stack) @@ -2797,7 +2192,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 (); @@ -2816,7 +2211,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) { @@ -2842,7 +2240,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); @@ -2867,7 +2265,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 (); @@ -2881,14 +2279,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; } @@ -2905,16 +2303,18 @@ 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); params_var = mono_mb_emit_save_args (mb, sig, FALSE); @@ -2956,7 +2356,7 @@ 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); @@ -2964,7 +2364,7 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params) 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; @@ -3065,16 +2465,18 @@ 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); params_var = mono_mb_emit_save_args (mb, sig, FALSE); @@ -3151,271 +2553,6 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params) return res; } -/** - * cominterop_get_native_wrapper_adjusted: - * @method: managed COM Interop method - * - * Returns: the generated method to call with signature matching - * the unmanaged COM Method signature - */ -static MonoMethod * -cominterop_get_native_wrapper_adjusted (MonoMethod *method) -{ - MonoMethod *res; - MonoMethodBuilder *mb_native; - MonoMarshalSpec **mspecs; - MonoMethodSignature *sig, *sig_native; - MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method; - int i; - - sig = mono_method_signature (method); - - // create unmanaged wrapper - mb_native = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE); - sig_native = cominterop_method_signature (method); - - mspecs = g_new (MonoMarshalSpec*, sig_native->param_count+1); - memset (mspecs, 0, sizeof(MonoMarshalSpec*)*(sig_native->param_count+1)); - - mono_method_get_marshal_info (method, mspecs); - - // move managed args up one - for (i = sig->param_count; i >= 1; i--) - mspecs[i+1] = mspecs[i]; - - // first arg is IntPtr for interface - mspecs[1] = NULL; - - if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG)) { - // move return spec to last param - if (!MONO_TYPE_IS_VOID (sig->ret)) - mspecs[sig_native->param_count] = mspecs[0]; - - mspecs[0] = NULL; - } - - mono_marshal_emit_native_wrapper (method->klass->image, mb_native, sig_native, piinfo, mspecs, piinfo->addr, TRUE); - - res = mono_mb_create_method (mb_native, sig_native, sig_native->param_count + 16); - - mono_mb_free (mb_native); - - for (i = sig_native->param_count; i >= 0; i--) - if (mspecs [i]) - mono_metadata_free_marshal_spec (mspecs [i]); - g_free (mspecs); - - return res; -} - -/** - * cominterop_get_native_wrapper: - * @method: managed method - * - * Returns: the generated method to call - */ -static MonoMethod * -cominterop_get_native_wrapper (MonoMethod *method) -{ - MonoMethod *res; - GHashTable *cache; - MonoMethodBuilder *mb; - MonoMethodSignature *sig, *csig; - - g_assert (method); - - cache = method->klass->image->cominterop_wrapper_cache; - if ((res = mono_marshal_find_in_cache (cache, method))) - return res; - - mono_init_com_types (); - - 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); - - /* if method klass is import, that means method - * is really a com call. let interop system emit it. - */ - if (MONO_CLASS_IS_IMPORT(method->klass)) { - /* FIXME: we have to call actual class .ctor - * instead of just __ComObject .ctor. - */ - if (!strcmp(method->name, ".ctor")) { - static MonoMethod *ctor = NULL; - - if (!ctor) - ctor = mono_class_get_method_from_name (mono_defaults.com_object_class, ".ctor", 0); - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_managed_call (mb, ctor, NULL); - mono_mb_emit_byte (mb, CEE_RET); - } - else { - static MonoMethod * ThrowExceptionForHR = NULL; - MonoMethod *adjusted_method; - int retval = 0; - int ptr_this; - int i; - gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG; - - // add local variables - ptr_this = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - if (!MONO_TYPE_IS_VOID (sig->ret)) - retval = mono_mb_add_local (mb, sig->ret); - - // get the type for the interface the method is defined on - // and then get the underlying COM interface for that type - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ptr (mb, method); - mono_mb_emit_icall (mb, cominterop_get_method_interface); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_interface); - mono_mb_emit_stloc (mb, ptr_this); - - // arg 1 is unmanaged this pointer - mono_mb_emit_ldloc (mb, ptr_this); - - // load args - for (i = 1; i <= sig->param_count; i++) - mono_mb_emit_ldarg (mb, i); - - // push managed return value as byref last argument - if (!MONO_TYPE_IS_VOID (sig->ret) && !preserve_sig) - mono_mb_emit_ldloc_addr (mb, retval); - - adjusted_method = cominterop_get_native_wrapper_adjusted (method); - mono_mb_emit_managed_call (mb, adjusted_method, NULL); - - if (!preserve_sig) { - if (!ThrowExceptionForHR) - ThrowExceptionForHR = mono_class_get_method_from_name (mono_defaults.marshal_class, "ThrowExceptionForHR", 1); - mono_mb_emit_managed_call (mb, ThrowExceptionForHR, NULL); - - // load return value managed is expecting - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_ldloc (mb, retval); - } - - mono_mb_emit_byte (mb, CEE_RET); - } - - - } - /* Does this case ever get hit? */ - else { - char *msg = g_strdup ("non imported interfaces on \ - imported classes is not yet implemented."); - mono_mb_emit_exception (mb, "NotSupportedException", msg); - } - csig = signature_dup (method->klass->image, sig); - csig->pinvoke = 0; - res = mono_mb_create_and_cache (cache, method, - mb, csig, csig->param_count + 16); - mono_mb_free (mb); - return res; -} - -/** - * cominterop_get_invoke: - * @method: managed method - * - * Returns: the generated method that calls the underlying __ComObject - * rather than the proxy object. - */ -static MonoMethod * -cominterop_get_invoke (MonoMethod *method) -{ - MonoMethodSignature *sig; - MonoMethodBuilder *mb; - MonoMethod *res; - int i, temp_obj; - GHashTable* cache = method->klass->image->cominterop_invoke_cache; - - g_assert (method); - - if ((res = mono_marshal_find_in_cache (cache, method))) - return res; - - sig = signature_no_pinvoke (method); - - /* we cant remote methods without this pointer */ - if (!sig->hasthis) - return method; - - mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP_INVOKE); - - /* get real proxy object, which is a ComInteropProxy in this case*/ - temp_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - /* load the RCW from the ComInteropProxy*/ - mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object)); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - /* load args and make the call on the RCW */ - for (i = 1; i <= sig->param_count; i++) - mono_mb_emit_ldarg (mb, i); - - if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) { - MonoMethod * native_wrapper = cominterop_get_native_wrapper(method); - mono_mb_emit_managed_call (mb, native_wrapper, NULL); - } - else { - if (method->flags & METHOD_ATTRIBUTE_VIRTUAL) - mono_mb_emit_op (mb, CEE_CALLVIRT, method); - else - mono_mb_emit_op (mb, CEE_CALL, method); - } - - if (!strcmp(method->name, ".ctor")) { - static MonoClass *com_interop_proxy_class = NULL; - static MonoMethod *cache_proxy = NULL; - - if (!com_interop_proxy_class) - com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy"); - if (!cache_proxy) - cache_proxy = mono_class_get_method_from_name (com_interop_proxy_class, "CacheProxy", 0); - - 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_managed_call (mb, cache_proxy, NULL); - } - - emit_thread_interrupt_checkpoint (mb); - - 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; -} -/* Maps a managed object to its unmanaged representation - * i.e. it's COM Callable Wrapper (CCW). - * Key: MonoObject* - * Value: MonoCCW* - */ -static GHashTable* ccw_hash = NULL; - -/* Maps a CCW interface to it's containing CCW. - * Note that a CCW support many interfaces. - * Key: MonoCCW* - * Value: MonoCCWInterface* - */ -static GHashTable* ccw_interface_hash = NULL; - -/* Maps the IUnknown value of a RCW to - * it's MonoComInteropProxy*. - * Key: void* - * Value: gchandle - */ -static GHashTable* rcw_hash = NULL; - MonoMethod * mono_marshal_get_remoting_invoke (MonoMethod *method) { @@ -3430,10 +2567,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) - return cominterop_get_invoke(method); + 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 mono_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) @@ -3702,7 +2844,6 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in MonoClass *ret_class = NULL; int loc_array=0, loc_return=0, loc_serialized_exc=0; MonoExceptionClause *main_clause; - MonoMethodHeader *header; int pos, pos_leave; gboolean copy_return; @@ -3743,9 +2884,7 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in /* try */ - mono_loader_lock (); main_clause = mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause)); - mono_loader_unlock (); main_clause->try_offset = mono_mb_get_label (mb); /* Clean the call context */ @@ -3939,13 +3078,11 @@ mono_marshal_get_xappdomain_dispatch (MonoMethod *method, int *marshal_types, in mono_mb_emit_byte (mb, CEE_RET); + mono_mb_set_clauses (mb, 1, main_clause); + res = mono_remoting_mb_create_and_cache (method, mb, csig, csig->param_count + 16); mono_mb_free (mb); - header = ((MonoMethodNormal *)res)->header; - header->num_clauses = 1; - header->clauses = main_clause; - return res; } @@ -3985,7 +3122,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; @@ -4277,12 +3414,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) - return cominterop_get_invoke (method); - else + } else if (target_type == MONO_REMOTING_TARGET_COMINTEROP) { +#ifndef DISABLE_COM + return mono_cominterop_get_invoke (method); +#else + g_assert_not_reached (); +#endif + } else { return mono_marshal_get_remoting_invoke (method); + } } G_GNUC_UNUSED static gpointer @@ -4313,7 +3455,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); @@ -4419,7 +3561,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) 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 */ @@ -4434,7 +3576,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; } @@ -4443,7 +3587,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) */ @@ -4534,8 +3678,8 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (callvirt) { // From mono_mb_create_and_cache + mb->skip_visibility = 1; 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 (); @@ -4546,15 +3690,15 @@ 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 (); mono_free_method (newm); } } else { + mb->skip_visibility = 1; res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16); - res->skip_visibility = 1; } mono_mb_free (mb); @@ -4632,28 +3776,90 @@ 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: + return t; + default: + if (MONO_TYPE_IS_REFERENCE (t)) + return &mono_defaults.object_class->byval_arg; + return t; + } +} + /* - * generates IL code for the runtime invoke function - * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method) + * mono_marshal_get_runtime_invoke_sig: * - * we also catch exceptions if exc != null + * Return a common signature used for sharing runtime invoke wrappers. */ -MonoMethod * -mono_marshal_get_runtime_invoke (MonoMethod *method) +static MonoMethodSignature* +mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig) { - MonoMethodSignature *sig, *csig, *callsig; - MonoExceptionClause *clause; - MonoMethodHeader *header; - MonoMethodBuilder *mb; - GHashTable *cache = NULL; - MonoClass *target_klass; - MonoMethod *res = NULL; - static MonoString *string_dummy = NULL; - static MonoMethodSignature *cctor_signature = NULL; + 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) + * + * we also catch exceptions if exc != null + * If VIRTUAL is TRUE, then METHOD is invoked virtually on THIS. This is useful since + * it means that the compiled code for METHOD does not have to be looked up + * before calling the runtime invoke wrapper. In this case, the wrapper ignores + * its METHOD argument. + */ +MonoMethod * +mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) +{ + MonoMethodSignature *sig, *csig, *callsig; + MonoExceptionClause *clause; + MonoMethodBuilder *mb; + GHashTable *cache = NULL; + MonoClass *target_klass; + MonoMethod *res = NULL; + static MonoString *string_dummy = NULL; + static MonoMethodSignature *cctor_signature = NULL; static MonoMethodSignature *finalize_signature = NULL; int i, pos, posna; char *name; gboolean need_direct_wrapper = FALSE; + int *tmp_nullable_locals; g_assert (method); @@ -4667,6 +3873,21 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) finalize_signature->hasthis = 1; } + if (virtual) + need_direct_wrapper = TRUE; + + /* + * 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. + */ + if (virtual) + cache = get_cache (&method->klass->image->runtime_invoke_vcall_cache, mono_aligned_addr_hash, NULL); + else + 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)) { /* @@ -4675,11 +3896,13 @@ 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) callsig = add_string_ctor_signature (method); + /* Can't share this as we push a string as this */ + need_direct_wrapper = TRUE; } else { if (method->klass->valuetype && mono_method_signature (method)->hasthis) { /* @@ -4695,6 +3918,12 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) } } + /* Vtypes/nullables/Byrefs cause too many problems */ + for (i = 0; i < callsig->param_count; ++i) { + if (MONO_TYPE_ISSTRUCT (callsig->params [i]) || callsig->params [i]->byref) + need_direct_wrapper = TRUE; + } + /* * 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 @@ -4729,19 +3958,25 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) } 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; + } + + // FIXME: When to free callsig ? } /* to make it work with our special string constructors */ @@ -4763,7 +3998,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) csig->params [2] = &mono_defaults.int_class->byval_arg; csig->params [3] = &mono_defaults.int_class->byval_arg; - name = mono_signature_to_name (callsig, "runtime_invoke"); + name = mono_signature_to_name (callsig, virtual ? "runtime_invoke_virtual" : "runtime_invoke"); mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE); g_free (name); @@ -4782,6 +4017,11 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) emit_thread_force_interrupt_checkpoint (mb); + if (virtual) { + g_assert (sig->hasthis); + g_assert (method->flags & METHOD_ATTRIBUTE_VIRTUAL); + } + if (sig->hasthis) { if (method->string_ctor) { mono_mb_emit_ptr (mb, string_dummy); @@ -4790,6 +4030,8 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) } } + tmp_nullable_locals = g_new0 (int, sig->param_count); + for (i = 0; i < sig->param_count; i++) { MonoType *t = sig->params [i]; int type; @@ -4802,6 +4044,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))) { + tmp_nullable_locals [i] = 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_locals [i]); + mono_mb_emit_ldloc_addr (mb, tmp_nullable_locals [i]); + } continue; } @@ -4842,7 +4094,7 @@ handle_enum: /* fall through */ case MONO_TYPE_VALUETYPE: if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) { - type = t->data.klass->enum_basetype->type; + type = mono_class_enum_basetype (t->data.klass)->type; goto handle_enum; } mono_mb_emit_byte (mb, CEE_LDIND_I); @@ -4859,7 +4111,9 @@ handle_enum: } } - if (need_direct_wrapper) { + if (virtual) { + mono_mb_emit_op (mb, CEE_CALLVIRT, method); + } else if (need_direct_wrapper) { mono_mb_emit_op (mb, CEE_CALL, method); } else { mono_mb_emit_ldarg (mb, 3); @@ -4910,12 +4164,30 @@ handle_enum: } mono_mb_emit_stloc (mb, 0); + + /* Convert back nullable-byref arguments */ + for (i = 0; i < sig->param_count; i++) { + MonoType *t = sig->params [i]; + + /* + * Box the result and put it back into the array, the caller will have + * to obtain it from there. + */ + if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) { + mono_mb_emit_ldarg (mb, 1); + mono_mb_emit_icon (mb, sizeof (gpointer) * i); + mono_mb_emit_byte (mb, CEE_ADD); + + mono_mb_emit_ldloc (mb, tmp_nullable_locals [i]); + mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t)); + + mono_mb_emit_byte (mb, CEE_STIND_REF); + } + } pos = mono_mb_emit_branch (mb, CEE_LEAVE); - mono_loader_lock (); 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); @@ -4956,12 +4228,15 @@ handle_enum: clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; + mono_mb_set_clauses (mb, 1, clause); + /* return result */ mono_mb_patch_branch (mb, pos); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_RET); if (need_direct_wrapper) { + mb->skip_visibility = 1; res = mono_mb_create_and_cache (cache, method, mb, csig, sig->param_count + 16); } else { /* taken from mono_mb_create_and_cache */ @@ -4980,6 +4255,7 @@ handle_enum: res = newm; g_hash_table_insert (cache, callsig, res); /* 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); } @@ -4991,10 +4267,6 @@ handle_enum: mono_mb_free (mb); - header = ((MonoMethodNormal *)res)->header; - header->num_clauses = 1; - header->clauses = clause; - return res; } @@ -5024,20 +4296,12 @@ mono_marshal_get_static_rgctx_invoke (MonoMethod *method) GHashTable *cache; MonoImage *image = method->klass->image; - if (!(cache = image->static_rgctx_invoke_cache)) { - mono_marshal_lock (); - if (!(cache = image->static_rgctx_invoke_cache)) { - cache = image->static_rgctx_invoke_cache = - g_hash_table_new (mono_aligned_addr_hash, NULL); - } - mono_marshal_unlock (); - } - + cache = get_cache (&image->static_rgctx_invoke_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, method))) return res; if (!inited) { - mono_counters_register ("static rgctx invoke wrappers", + mono_counters_register ("Static rgctx invoke wrappers", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_wrappers); inited = TRUE; } @@ -5052,9 +4316,9 @@ mono_marshal_get_static_rgctx_invoke (MonoMethod *method) mono_mb_emit_op (mb, CEE_CALL, method); mono_mb_emit_byte (mb, CEE_RET); + mb->skip_visibility = TRUE; res = mono_mb_create_and_cache (cache, method, mb, mono_method_signature (method), sig->param_count + sig->hasthis + 4); - res->skip_visibility = TRUE; res->flags = method->flags; mono_mb_free (mb); @@ -5187,7 +4451,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; @@ -5336,7 +4600,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; @@ -5531,7 +4795,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; @@ -5658,51 +4922,6 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gcon return res; } -typedef struct { - MonoMethodBuilder *mb; - MonoMethodSignature *sig; - MonoMethodPInvoke *piinfo; - int *orig_conv_args; /* Locals containing the original values of byref args */ - int retobj_var; - MonoClass *retobj_class; - MonoMethodSignature *csig; /* Might need to be changed due to MarshalAs directives */ - MonoImage *image; /* The image to use for looking up custom marshallers */ -} EmitMarshalContext; - -typedef enum { - /* - * This is invoked to convert arguments from the current types to - * the underlying types expected by the platform routine. If required, - * the methods create a temporary variable with the proper type, and return - * the location for it (either the passed argument, or the newly allocated - * local slot). - */ - MARSHAL_ACTION_CONV_IN, - - /* - * This operation is called to push the actual value that was optionally - * converted on the first stage - */ - MARSHAL_ACTION_PUSH, - - /* - * Convert byref arguments back or free resources allocated during the - * CONV_IN stage - */ - MARSHAL_ACTION_CONV_OUT, - - /* - * The result from the unmanaged call is at the top of the stack when - * this action is invoked. The result should be stored in the - * third local variable slot. - */ - MARSHAL_ACTION_CONV_RESULT, - - MARSHAL_ACTION_MANAGED_CONV_IN, - MARSHAL_ACTION_MANAGED_CONV_OUT, - MARSHAL_ACTION_MANAGED_CONV_RESULT -} MarshalAction; - static int emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, @@ -5853,7 +5072,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 { + } else if (t->attrs & PARAM_ATTRIBUTE_OUT) { mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie)); mono_mb_emit_op (mb, CEE_CALL, get_instance); @@ -6058,7 +5277,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: @@ -6323,7 +5542,6 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, 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))) { @@ -6365,12 +5583,8 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t, 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); @@ -6381,9 +5595,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) @@ -6628,20 +5855,22 @@ 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) { - mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented")); - } - switch (action) { case MARSHAL_ACTION_CONV_IN: *conv_arg_type = &mono_defaults.int_class->byval_arg; conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); m->orig_conv_args [argnum] = 0; - + + if (mono_class_from_mono_type (t) == mono_defaults.object_class) { + char *msg = g_strdup_printf ("Marshalling of type object is not implemented"); + mono_mb_emit_exception_marshal_directive (mb, msg); + break; + } + if (klass->delegate) { if (t->byref) { if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) { @@ -6778,7 +6007,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); } @@ -6804,7 +6033,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); @@ -7071,126 +6300,65 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, } static int -emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, +emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, MonoMarshalSpec *spec, int conv_arg, MonoType **conv_arg_type, MarshalAction action) { MonoMethodBuilder *mb = m->mb; - MonoClass *klass = t->data.klass; - static MonoMethod* get_object_for_iunknown = NULL; - static MonoMethod* get_iunknown_for_object_internal = NULL; - static MonoMethod* get_com_interface_for_object_internal = NULL; - static MonoMethod* get_idispatch_for_object_internal = NULL; - static MonoMethod* marshal_release = NULL; - static MonoMethod* AddRef = NULL; - if (!get_object_for_iunknown) - get_object_for_iunknown = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForIUnknown", 1); - if (!get_iunknown_for_object_internal) - get_iunknown_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIUnknownForObjectInternal", 1); - if (!get_idispatch_for_object_internal) - get_idispatch_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetIDispatchForObjectInternal", 1); - if (!get_com_interface_for_object_internal) - get_com_interface_for_object_internal = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetComInterfaceForObjectInternal", 2); - if (!marshal_release) - marshal_release = mono_class_get_method_from_name (mono_defaults.marshal_class, "Release", 1); - - /* COM types are initialized lazily */ + static MonoMethod *get_object_for_native_variant = NULL; + static MonoMethod *get_native_variant_for_object = NULL; + mono_init_com_types (); + + if (!get_object_for_native_variant) + get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1); + g_assert (get_object_for_native_variant); + + if (!get_native_variant_for_object) + get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2); + g_assert (get_native_variant_for_object); switch (action) { case MARSHAL_ACTION_CONV_IN: { - guint32 pos_null = 0; - - *conv_arg_type = &mono_defaults.int_class->byval_arg; - conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - - mono_mb_emit_ptr (mb, NULL); - mono_mb_emit_stloc (mb, conv_arg); + conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg); + + if (t->byref) + *conv_arg_type = &mono_defaults.variant_class->this_arg; + else + *conv_arg_type = &mono_defaults.variant_class->byval_arg; - /* we dont need any conversions for out parameters */ - 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); - if (t->byref) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - /* if null just break, conv arg was already inited to 0 */ - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - mono_mb_emit_ldarg (mb, argnum); if (t->byref) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - - if (klass && klass != mono_defaults.object_class) { - mono_mb_emit_ptr (mb, t); - mono_mb_emit_icall (mb, type_from_handle); - mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL); - } - else if (spec->native == MONO_NATIVE_IUNKNOWN) - mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL); - else if (spec->native == MONO_NATIVE_IDISPATCH) - mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL); - else if (!klass && spec->native == MONO_NATIVE_INTERFACE) - mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL); - else - g_assert_not_reached (); - mono_mb_emit_stloc (mb, conv_arg); - mono_mb_patch_short_branch (mb, pos_null); + mono_mb_emit_byte(mb, CEE_LDIND_REF); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); break; } case MARSHAL_ACTION_CONV_OUT: { - if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) { - int ccw_obj; - guint32 pos_null = 0, pos_ccw = 0, pos_end = 0; - ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_emit_ldloc (mb, conv_arg); - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_ccw_object); - mono_mb_emit_stloc (mb, ccw_obj); - mono_mb_emit_ldloc (mb, ccw_obj); - pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); - - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL); + static MonoMethod *variant_clear = NULL; - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - mono_mb_emit_byte (mb, CEE_STIND_REF); + if (!variant_clear) + variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0); + g_assert (variant_clear); - pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S); - /* is already managed object */ - mono_mb_patch_short_branch (mb, pos_ccw); + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, ccw_obj); - - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); mono_mb_emit_byte (mb, CEE_STIND_REF); - - mono_mb_patch_short_branch (mb, pos_end); - - /* need to call Release to follow COM rules of ownership */ - mono_mb_emit_ldloc (mb, conv_arg); - mono_mb_emit_managed_call (mb, marshal_release, NULL); - mono_mb_emit_byte (mb, CEE_POP); - - /* case if null */ - mono_mb_patch_short_branch (mb, pos_null); } + + mono_mb_emit_ldloc_addr (mb, conv_arg); + mono_mb_emit_managed_call (mb, variant_clear, NULL); break; } + case MARSHAL_ACTION_PUSH: if (t->byref) mono_mb_emit_ldloc_addr (mb, conv_arg); @@ -7199,290 +6367,36 @@ emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t, break; case MARSHAL_ACTION_CONV_RESULT: { - int ccw_obj, ret_ptr; - guint32 pos_null = 0, pos_ccw = 0, pos_end = 0; - ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - ret_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg); - - /* store return value */ - mono_mb_emit_stloc (mb, ret_ptr); - - mono_mb_emit_ldloc (mb, ret_ptr); - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - mono_mb_emit_ldloc (mb, ret_ptr); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_ccw_object); - mono_mb_emit_stloc (mb, ccw_obj); - mono_mb_emit_ldloc (mb, ccw_obj); - pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); - - mono_mb_emit_ldloc (mb, ret_ptr); - mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL); - - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - mono_mb_emit_stloc (mb, 3); - - pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S); - - /* is already managed object */ - mono_mb_patch_short_branch (mb, pos_ccw); - mono_mb_emit_ldloc (mb, ccw_obj); - - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - mono_mb_emit_stloc (mb, 3); - - mono_mb_patch_short_branch (mb, pos_end); - - /* need to call Release to follow COM rules of ownership */ - mono_mb_emit_ldloc (mb, ret_ptr); - mono_mb_emit_managed_call (mb, marshal_release, NULL); - mono_mb_emit_byte (mb, CEE_POP); - - /* case if null */ - mono_mb_patch_short_branch (mb, pos_null); + char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); + mono_mb_emit_exception_marshal_directive (mb, msg); break; - } + } case MARSHAL_ACTION_MANAGED_CONV_IN: { - int ccw_obj; - guint32 pos_null = 0, pos_ccw = 0, pos_end = 0; - ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - - klass = mono_class_from_mono_type (t); - conv_arg = mono_mb_add_local (mb, &klass->byval_arg); - *conv_arg_type = &mono_defaults.int_class->byval_arg; - - mono_mb_emit_byte (mb, CEE_LDNULL); - mono_mb_emit_stloc (mb, conv_arg); - if (t->attrs & PARAM_ATTRIBUTE_OUT) - break; - - mono_mb_emit_ldarg (mb, argnum); - if (t->byref) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - mono_mb_emit_ldarg (mb, argnum); if (t->byref) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_icon (mb, TRUE); - mono_mb_emit_icall (mb, cominterop_get_ccw_object); - mono_mb_emit_stloc (mb, ccw_obj); - mono_mb_emit_ldloc (mb, ccw_obj); - pos_ccw = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + *conv_arg_type = &mono_defaults.variant_class->this_arg; + else + *conv_arg_type = &mono_defaults.variant_class->byval_arg; + if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT) + break; - mono_mb_emit_ldarg (mb, argnum); if (t->byref) - mono_mb_emit_byte (mb, CEE_LDIND_REF); - mono_mb_emit_managed_call (mb, get_object_for_iunknown, NULL); - - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); - mono_mb_emit_stloc (mb, conv_arg); - pos_end = mono_mb_emit_short_branch (mb, CEE_BR_S); - - /* is already managed object */ - mono_mb_patch_short_branch (mb, pos_ccw); - mono_mb_emit_ldloc (mb, ccw_obj); - if (klass && klass != mono_defaults.object_class) - mono_mb_emit_op (mb, CEE_CASTCLASS, klass); + mono_mb_emit_ldarg (mb, argnum); + else + mono_mb_emit_ldarg_addr (mb, argnum); + mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); mono_mb_emit_stloc (mb, conv_arg); - - mono_mb_patch_short_branch (mb, pos_end); - /* case if null */ - mono_mb_patch_short_branch (mb, pos_null); break; } case MARSHAL_ACTION_MANAGED_CONV_OUT: { - if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) { - guint32 pos_null = 0; - - if (!AddRef) - AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1); - - mono_mb_emit_ldloc (mb, conv_arg); - /* if null just break, conv arg was already inited to 0 */ - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - /* to store later */ - mono_mb_emit_ldarg (mb, argnum); + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) { mono_mb_emit_ldloc (mb, conv_arg); - if (klass && klass != mono_defaults.object_class) { - mono_mb_emit_ptr (mb, t); - mono_mb_emit_icall (mb, type_from_handle); - mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL); - } - else if (spec->native == MONO_NATIVE_IUNKNOWN) - mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL); - else if (spec->native == MONO_NATIVE_IDISPATCH) - mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL); - else if (!klass && spec->native == MONO_NATIVE_INTERFACE) - mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL); - else - g_assert_not_reached (); - mono_mb_emit_byte (mb, CEE_STIND_I); - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_I); - mono_mb_emit_managed_call (mb, AddRef, NULL); - mono_mb_emit_byte (mb, CEE_POP); - - mono_mb_patch_short_branch (mb, pos_null); - } - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_RESULT: { - guint32 pos_null = 0; - int ccw_obj; - ccw_obj = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - - if (!AddRef) - AddRef = mono_class_get_method_from_name (mono_defaults.marshal_class, "AddRef", 1); - - /* store return value */ - mono_mb_emit_stloc (mb, ccw_obj); - - mono_mb_emit_ldloc (mb, ccw_obj); - - /* if null just break, conv arg was already inited to 0 */ - pos_null = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - - /* to store later */ - mono_mb_emit_ldloc (mb, ccw_obj); - if (klass && klass != mono_defaults.object_class) { - mono_mb_emit_ptr (mb, t); - mono_mb_emit_icall (mb, type_from_handle); - mono_mb_emit_managed_call (mb, get_com_interface_for_object_internal, NULL); - } - else if (spec->native == MONO_NATIVE_IUNKNOWN) - mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL); - else if (spec->native == MONO_NATIVE_IDISPATCH) - mono_mb_emit_managed_call (mb, get_idispatch_for_object_internal, NULL); - else if (!klass && spec->native == MONO_NATIVE_INTERFACE) - mono_mb_emit_managed_call (mb, get_iunknown_for_object_internal, NULL); - else - g_assert_not_reached (); - mono_mb_emit_stloc (mb, 3); - mono_mb_emit_ldloc (mb, 3); - - mono_mb_emit_managed_call (mb, AddRef, NULL); - mono_mb_emit_byte (mb, CEE_POP); - - mono_mb_patch_short_branch (mb, pos_null); - break; - } - - default: - g_assert_not_reached (); - } - - return conv_arg; -} - -static int -emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t, - MonoMarshalSpec *spec, - int conv_arg, MonoType **conv_arg_type, - MarshalAction action) -{ - MonoMethodBuilder *mb = m->mb; - static MonoMethod *get_object_for_native_variant = NULL; - static MonoMethod *get_native_variant_for_object = NULL; - - mono_init_com_types (); - - if (!get_object_for_native_variant) - get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1); - g_assert (get_object_for_native_variant); - - if (!get_native_variant_for_object) - get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2); - g_assert (get_native_variant_for_object); - - switch (action) { - case MARSHAL_ACTION_CONV_IN: { - conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg); - - if (t->byref) - *conv_arg_type = &mono_defaults.variant_class->this_arg; - else - *conv_arg_type = &mono_defaults.variant_class->byval_arg; - - if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN)) - break; - - mono_mb_emit_ldarg (mb, argnum); - if (t->byref) - mono_mb_emit_byte(mb, CEE_LDIND_REF); - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); - break; - } - - case MARSHAL_ACTION_CONV_OUT: { - static MonoMethod *variant_clear = NULL; - - if (!variant_clear) - variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0); - g_assert (variant_clear); - - - if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); - mono_mb_emit_byte (mb, CEE_STIND_REF); - } - - mono_mb_emit_ldloc_addr (mb, conv_arg); - mono_mb_emit_managed_call (mb, variant_clear, NULL); - break; - } - - case MARSHAL_ACTION_PUSH: - if (t->byref) - mono_mb_emit_ldloc_addr (mb, conv_arg); - else - mono_mb_emit_ldloc (mb, conv_arg); - break; - - case MARSHAL_ACTION_CONV_RESULT: { - char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type."); - mono_mb_emit_exception_marshal_directive (mb, msg); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_IN: { - conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - - if (t->byref) - *conv_arg_type = &mono_defaults.variant_class->this_arg; - else - *conv_arg_type = &mono_defaults.variant_class->byval_arg; - - if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN)) - break; - - if (t->byref) - mono_mb_emit_ldarg (mb, argnum); - else - mono_mb_emit_ldarg_addr (mb, argnum); - mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL); - mono_mb_emit_stloc (mb, conv_arg); - break; - } - - case MARSHAL_ACTION_MANAGED_CONV_OUT: { - if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT) { - 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); + mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); } break; } @@ -8235,6 +7149,86 @@ emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t, mono_mb_emit_stloc (mb, 3); break; + case MARSHAL_ACTION_MANAGED_CONV_IN: { + gint variant_bool = 0; + guint8 ldop = CEE_LDIND_I4; + int label1; + + if (!t->byref) + break; + + conv_arg = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg); + + *conv_arg_type = &mono_defaults.int32_class->byval_arg; + + if (spec) { + switch (spec->native) { + case MONO_NATIVE_I1: + case MONO_NATIVE_U1: + *conv_arg_type = &mono_defaults.byte_class->this_arg; + ldop = CEE_LDIND_I1; + break; + case MONO_NATIVE_VARIANTBOOL: + *conv_arg_type = &mono_defaults.int16_class->this_arg; + variant_bool = 1; + ldop = CEE_LDIND_I2; + break; + case MONO_NATIVE_BOOLEAN: + break; + default: + g_warning ("marshalling bool as native type %x is currently not supported", spec->native); + } + } + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, ldop); + + if (variant_bool) + mono_mb_emit_byte (mb, CEE_NEG); + mono_mb_emit_stloc (mb, conv_arg); + + mono_mb_patch_branch (mb, label1); + break; + } + + case MARSHAL_ACTION_MANAGED_CONV_OUT: { + guint8 stop = CEE_STIND_I4; + int label1; + + if (!t->byref) + break; + if (spec) { + switch (spec->native) { + case MONO_NATIVE_I1: + case MONO_NATIVE_U1: + stop = CEE_STIND_I1; + break; + case MONO_NATIVE_VARIANTBOOL: + stop = CEE_STIND_I2; + break; + default: + break; + } + } + + /* Check null */ + mono_mb_emit_ldarg (mb, argnum); + label1 = mono_mb_emit_branch (mb, CEE_BRFALSE); + + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_ldloc (mb, conv_arg); + if (spec != NULL && spec->native == MONO_NATIVE_VARIANTBOOL) + mono_mb_emit_byte (mb, CEE_NEG); + mono_mb_emit_byte (mb, stop); + + mono_mb_patch_branch (mb, label1); + break; + } + default: g_assert_not_reached (); } @@ -8251,7 +7245,7 @@ emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t, switch (action) { case MARSHAL_ACTION_CONV_IN: - if (MONO_TYPE_ISSTRUCT (t->data.type)) { + if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) { char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1); mono_mb_emit_exception_marshal_directive (m->mb, msg); } @@ -8351,12 +7345,14 @@ 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); + return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action); +#endif - if (mono_defaults.safehandle_class != NULL && + if (mono_defaults.safehandle_class != NULL && t->data.klass && mono_class_is_subclass_of (t->data.klass, mono_defaults.safehandle_class, FALSE)) return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action); @@ -8384,6 +7380,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; @@ -8395,13 +7396,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) +void +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; @@ -8459,17 +7461,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 */ @@ -8508,7 +7520,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM case MONO_TYPE_VALUETYPE: klass = sig->ret->data.klass; if (klass->enumtype) { - type = sig->ret->data.klass->enum_basetype->type; + type = mono_class_enum_basetype (sig->ret->data.klass)->type; goto handle_enum; } emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT); @@ -8534,6 +7546,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: @@ -8609,12 +7622,20 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, g_assert (method != NULL); g_assert (mono_method_signature (method)->pinvoke); - cache = method->klass->image->native_wrapper_cache; + if (aot) + cache = get_cache (&method->klass->image->native_wrapper_aot_cache, mono_aligned_addr_hash, NULL); + else + cache = get_cache (&method->klass->image->native_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, method))) return res; - if (MONO_CLASS_IS_IMPORT (method->klass)) - return cominterop_get_native_wrapper (method); + if (MONO_CLASS_IS_IMPORT (method->klass)) { +#ifndef DISABLE_COM + return mono_cominterop_get_native_wrapper (method); +#else + g_assert_not_reached (); +#endif + } sig = mono_method_signature (method); @@ -8730,12 +7751,13 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, } g_assert (pinvoke); - g_assert (piinfo->addr); + 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; @@ -8773,7 +7795,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig GHashTable *cache; char *name; - cache = image->native_wrapper_cache; + cache = get_cache (&image->native_wrapper_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, func))) return res; @@ -8781,7 +7803,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; @@ -8795,7 +7817,7 @@ mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig } /* FIXME: moving GC */ -static void +void mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this) { MonoMethodSignature *sig, *csig; @@ -8831,6 +7853,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i case MONO_TYPE_ARRAY: case MONO_TYPE_SZARRAY: case MONO_TYPE_STRING: + case MONO_TYPE_BOOLEAN: tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN); break; @@ -8879,6 +7902,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: @@ -8923,6 +7947,8 @@ 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: + case MONO_TYPE_BOOLEAN: emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT); break; } @@ -9014,7 +8040,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; @@ -9201,7 +8227,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; @@ -9283,7 +8309,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; @@ -9348,7 +8374,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; @@ -9479,7 +8505,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass) mono_mb_emit_byte (mb, CEE_RET); - res = mono_mb_create_method (mb, signature_no_pinvoke (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; @@ -9563,10 +8589,9 @@ 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; MonoMethodBuilder *mb; MonoMethod *res; GHashTable *cache; @@ -9577,7 +8602,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; @@ -9611,11 +8636,11 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) /* this */ this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg); - mono_loader_lock (); 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; @@ -9623,21 +8648,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); @@ -9677,14 +8710,12 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) mono_mb_emit_ldloc (mb, ret_local); mono_mb_emit_byte (mb, CEE_RET); + mono_mb_set_clauses (mb, 1, clause); + res = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16); mono_mb_free (mb); - header = ((MonoMethodNormal *)res)->header; - header->num_clauses = 1; - header->clauses = clause; - return res; } @@ -9701,7 +8732,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; @@ -10033,46 +9064,6 @@ mono_marshal_get_array_address (int rank, int elem_size) return ret; } -MonoMethod* -mono_marshal_get_write_barrier (void) -{ - static MonoMethod* ret = NULL; - MonoMethodSignature *sig; - MonoMethodBuilder *mb; - int max_stack = 2; - - if (ret) - return ret; - - mb = mono_mb_new (mono_defaults.object_class, "writebarrier", MONO_WRAPPER_WRITE_BARRIER); - - sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2); - - /* void writebarrier (MonoObject** addr, MonoObject* obj) */ - sig->ret = &mono_defaults.void_class->byval_arg; - sig->params [0] = &mono_defaults.object_class->this_arg; - sig->params [1] = &mono_defaults.object_class->byval_arg; - - /* just the store right now: add an hook for the GC to use, maybe something - * that can be used for stelemref as well - * We need a write barrier variant to be used with struct copies as well, though - * there are also other approaches possible, like writing a wrapper specific to - * the struct or to the reference pattern in the struct... - * Depending on the GC, we may want variants that take the object we store to - * when it is available. - */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_icall (mb, mono_gc_wbarrier_generic_store); - /*mono_mb_emit_byte (mb, CEE_STIND_REF);*/ - - mono_mb_emit_byte (mb, CEE_RET); - - ret = mono_mb_create_method (mb, sig, max_stack); - mono_mb_free (mb); - return ret; -} - void* mono_marshal_alloc (gulong size) { @@ -10387,210 +9378,32 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *pt } } -MonoString * -ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr) +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void) { MONO_ARCH_SAVE_REGS; - return mono_string_from_bstr(ptr); + return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id))); } -gpointer -ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr) +guint32 +ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype) { + MonoClass *klass; + MonoType *type; + guint32 layout; + MONO_ARCH_SAVE_REGS; - return mono_string_to_bstr(ptr); -} + MONO_CHECK_ARG_NULL (rtype); -typedef struct -{ - int (STDCALL *QueryInterface)(gpointer pUnk, gpointer riid, gpointer* ppv); - int (STDCALL *AddRef)(gpointer pUnk); - int (STDCALL *Release)(gpointer pUnk); -} MonoIUnknown; + type = rtype->type; + klass = mono_class_from_mono_type (type); + layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK); -void -ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr) -{ - MONO_ARCH_SAVE_REGS; - - mono_free_bstr (ptr); -} - -int -ves_icall_System_Runtime_InteropServices_Marshal_AddRefInternal (gpointer pUnk) -{ - g_assert (pUnk); - return (*(MonoIUnknown**)pUnk)->AddRef(pUnk); -} - -int -ves_icall_System_Runtime_InteropServices_Marshal_QueryInterfaceInternal (gpointer pUnk, gpointer riid, gpointer* ppv) -{ - g_assert (pUnk); - return (*(MonoIUnknown**)pUnk)->QueryInterface(pUnk, riid, ppv); -} - -int -ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (gpointer pUnk) -{ - g_assert (pUnk); - return (*(MonoIUnknown**)pUnk)->Release(pUnk); -} - -static void* -cominterop_get_idispatch_for_object (MonoObject* object) -{ - if (!object) - return NULL; - - if (cominterop_object_is_rcw (object)) { - return cominterop_get_interface (((MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp)->com_object, - mono_defaults.idispatch_class, TRUE); - } - else { - return cominterop_get_ccw (object, mono_defaults.idispatch_class); - } -} - -void* -ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (MonoObject* object) -{ - if (!object) - return NULL; - - if (cominterop_object_is_rcw (object)) { - MonoClass *klass = NULL; - MonoRealProxy* real_proxy = NULL; - if (!object) - return NULL; - klass = mono_object_class (object); - if (klass != mono_defaults.transparent_proxy_class) { - g_assert_not_reached (); - return NULL; - } - - real_proxy = ((MonoTransparentProxy*)object)->rp; - if (!real_proxy) { - g_assert_not_reached (); - return NULL; - } - - klass = mono_object_class (real_proxy); - if (klass != mono_defaults.com_interop_proxy_class) { - g_assert_not_reached (); - return NULL; - } - - if (!((MonoComInteropProxy*)real_proxy)->com_object) { - g_assert_not_reached (); - return NULL; - } - - return ((MonoComInteropProxy*)real_proxy)->com_object->iunknown; - } - else { - return cominterop_get_ccw (object, mono_defaults.iunknown_class); - } -} - -MonoObject* -ves_icall_System_Runtime_InteropServices_Marshal_GetObjectForCCW (void* pUnk) -{ - MonoObject* object = NULL; - - if (!pUnk) - return NULL; - - /* see if it is a CCW */ - object = cominterop_get_ccw_object ((MonoCCWInterface*)pUnk, TRUE); - - return object; -} - -void* -ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object) -{ - return cominterop_get_idispatch_for_object (object); -} - -void* -ves_icall_System_Runtime_InteropServices_Marshal_GetCCW (MonoObject* object, MonoReflectionType* type) -{ - MonoClass* klass = NULL; - void* itf = NULL; - g_assert (type); - g_assert (type->type); - klass = mono_type_get_class (type->type); - g_assert (klass); - itf = cominterop_get_ccw (object, klass); - g_assert (itf); - return itf; -} - - -MonoBoolean -ves_icall_System_Runtime_InteropServices_Marshal_IsComObject (MonoObject* object) -{ - return (MonoBoolean)cominterop_object_is_rcw (object); -} - -gint32 -ves_icall_System_Runtime_InteropServices_Marshal_ReleaseComObjectInternal (MonoObject* object) -{ - MonoComInteropProxy* proxy = NULL; - gint32 ref_count = 0; - - g_assert (object); - g_assert (cominterop_object_is_rcw (object)); - - proxy = (MonoComInteropProxy*)((MonoTransparentProxy*)object)->rp; - g_assert (proxy); - - ref_count = InterlockedDecrement (&proxy->ref_count); - g_assert (ref_count >= 0); - - if (ref_count == 0) - ves_icall_System_ComObject_ReleaseInterfaces (proxy->com_object); - - return ref_count; -} - -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_GetComSlotForMethodInfoInternal (MonoReflectionMethod *m) -{ - MONO_ARCH_SAVE_REGS; - - return cominterop_get_com_slot_for_method (m->method); -} - -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void) -{ - MONO_ARCH_SAVE_REGS; - - return (GPOINTER_TO_INT (TlsGetValue (last_error_tls_id))); -} - -guint32 -ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rtype) -{ - MonoClass *klass; - MonoType *type; - guint32 layout; - - MONO_ARCH_SAVE_REGS; - - MONO_CHECK_ARG_NULL (rtype); - - type = rtype->type; - klass = mono_class_from_mono_type (type); - layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK); - - if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { - gchar *msg; - MonoException *exc; + if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + gchar *msg; + MonoException *exc; msg = g_strdup_printf ("Type %s cannot be marshaled as an unmanaged structure.", klass->name); exc = mono_get_exception_argument ("t", msg); @@ -10704,7 +9517,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; } @@ -10945,100 +9758,6 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerIn return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn); } -/* Only used for COM RCWs */ -MonoObject * -ves_icall_System_ComObject_CreateRCW (MonoReflectionType *type) -{ - MonoClass *klass; - MonoDomain *domain; - MonoObject *obj; - - MONO_ARCH_SAVE_REGS; - - domain = mono_object_domain (type); - klass = mono_class_from_mono_type (type->type); - - /* call mono_object_new_alloc_specific instead of mono_object_new - * because we want to actually create object. mono_object_new checks - * to see if type is import and creates transparent proxy. this method - * is called by the corresponding real proxy to create the real RCW. - * Constructor does not need to be called. Will be called later. - */ - obj = mono_object_new_alloc_specific (mono_class_vtable (domain, klass)); - return obj; -} - -static gboolean -cominterop_finalizer (gpointer key, gpointer value, gpointer user_data) -{ - ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (value); - return TRUE; -} - -void -ves_icall_System_ComObject_ReleaseInterfaces (MonoComObject* obj) -{ - g_assert(obj); - if (obj->itf_hash) { - guint32 gchandle = 0; - mono_cominterop_lock (); - gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, obj->iunknown)); - if (gchandle) { - mono_gchandle_free (gchandle); - g_hash_table_remove (rcw_hash, obj->iunknown); - } - - g_hash_table_foreach_remove (obj->itf_hash, cominterop_finalizer, NULL); - ves_icall_System_Runtime_InteropServices_Marshal_ReleaseInternal (obj->iunknown); - obj->itf_hash = obj->iunknown = NULL; - mono_cominterop_unlock (); - } -} - -gpointer -ves_icall_System_ComObject_GetInterfaceInternal (MonoComObject* obj, MonoReflectionType* type, MonoBoolean throw_exception) -{ - return cominterop_get_interface (obj, mono_type_get_class (type->type), (gboolean)throw_exception); -} - -void -ves_icall_Mono_Interop_ComInteropProxy_AddProxy (gpointer pUnk, MonoComInteropProxy* proxy) -{ - guint32 gchandle = 0; - if (!rcw_hash) { - mono_cominterop_lock (); - rcw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - mono_cominterop_unlock (); - } - - gchandle = mono_gchandle_new_weakref ((MonoObject*)proxy, FALSE); - - mono_cominterop_lock (); - g_hash_table_insert (rcw_hash, pUnk, GUINT_TO_POINTER (gchandle)); - mono_cominterop_unlock (); -} - -MonoComInteropProxy* -ves_icall_Mono_Interop_ComInteropProxy_FindProxy (gpointer pUnk) -{ - MonoComInteropProxy* proxy = NULL; - guint32 gchandle = 0; - - mono_cominterop_lock (); - if (rcw_hash) - gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (rcw_hash, pUnk)); - mono_cominterop_unlock (); - if (gchandle) { - proxy = (MonoComInteropProxy*)mono_gchandle_get_target (gchandle); - /* proxy is null means we need to free up old RCW */ - if (!proxy) { - mono_gchandle_free (gchandle); - g_hash_table_remove (rcw_hash, pUnk); - } - } - return proxy; -} - /** * mono_marshal_is_loading_type_info: * @@ -11135,13 +9854,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_with_mempool (klass->image->mempool, klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1, + mono_metadata_field_info_with_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; } @@ -11179,6 +9898,8 @@ mono_marshal_load_type_info (MonoClass* klass) info->native_size &= ~(min_align - 1); } + info->min_align = min_align; + /* Update the class's blittable info, if the layouts don't match */ if (info->native_size != mono_class_value_size (klass, NULL)) klass->blittable = FALSE; @@ -11223,11 +9944,16 @@ mono_class_native_size (MonoClass *klass, guint32 *align) } if (align) - *align = klass->min_align; + *align = klass->marshal_info->min_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 @@ -11246,8 +9972,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){ @@ -11259,6 +9985,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: @@ -11268,24 +9996,33 @@ mono_type_native_stack_size (MonoType *t, guint32 *align) case MONO_TYPE_PTR: case MONO_TYPE_FNPTR: case MONO_TYPE_ARRAY: - *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 (mono_class_enum_basetype (klass), align); else { - size = mono_class_native_size (t->data.klass, align); + size = mono_class_native_size (klass, align); *align = *align + 3; *align &= ~3; @@ -11301,11 +10038,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) @@ -11552,10 +10284,10 @@ mono_marshal_get_generic_array_helper (MonoClass *class, MonoClass *iface, gchar mono_mb_emit_managed_call (mb, method, NULL); mono_mb_emit_byte (mb, CEE_RET); - res = mono_mb_create_method (mb, csig, csig->param_count + 16); - /* We can corlib internal methods */ - res->skip_visibility = TRUE; + mb->skip_visibility = TRUE; + + res = mono_mb_create_method (mb, csig, csig->param_count + 16); mono_mb_free (mb); @@ -11601,573 +10333,6 @@ mono_win32_compat_ZeroMemory (gpointer dest, gsize length) memset (dest, 0, length); } -/* Put COM Interop related stuff here */ - -/** - * cominterop_get_ccw_object: - * @ccw_entry: a pointer to the CCWEntry - * @verify: verify ccw_entry is in fact a ccw - * - * Returns: the corresponding object for the CCW - */ -static MonoObject* -cominterop_get_ccw_object (MonoCCWInterface* ccw_entry, gboolean verify) -{ - MonoCCW *ccw = NULL; - - /* no CCW's exist yet */ - if (!ccw_interface_hash) - return NULL; - - if (verify) { - ccw = g_hash_table_lookup (ccw_interface_hash, ccw_entry); - } - else { - ccw = ccw_entry->ccw; - g_assert (ccw); - } - if (ccw) - return mono_gchandle_get_target (ccw->gc_handle); - else - return NULL; -} - -static void -cominterop_setup_marshal_context (EmitMarshalContext *m, MonoMethod *method) -{ - MonoMethodSignature *sig, *csig; - sig = mono_method_signature (method); - /* we copy the signature, so that we can modify it */ - /* FIXME: which to use? */ - csig = signature_dup (method->klass->image, sig); - /* csig = mono_metadata_signature_dup (sig); */ - - /* STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM */ -#ifdef PLATFORM_WIN32 - csig->call_convention = MONO_CALL_STDCALL; -#else - csig->call_convention = MONO_CALL_C; -#endif - csig->hasthis = 0; - csig->pinvoke = 1; - - m->image = method->klass->image; - m->piinfo = NULL; - m->retobj_var = 0; - m->sig = sig; - m->csig = csig; -} - -/** - * cominterop_get_ccw: - * @object: a pointer to the object - * @itf: interface type needed - * - * Returns: a value indicating if the object is a - * Runtime Callable Wrapper (RCW) for a COM object - */ -static gpointer -cominterop_get_ccw (MonoObject* object, MonoClass* itf) -{ - int i; - MonoCCW *ccw = NULL; - MonoCCWInterface* ccw_entry = NULL; - gpointer *vtable = NULL; - static gpointer iunknown[3] = {NULL, NULL, NULL}; - static gpointer idispatch[4] = {NULL, NULL, NULL, NULL}; - MonoClass* iface = NULL; - MonoClass* klass = NULL; - EmitMarshalContext m; - int start_slot = 3; - int method_count = 0; - GList *ccw_list, *ccw_list_item; - MonoCustomAttrInfo *cinfo = NULL; - - if (!object) - return NULL; - - klass = mono_object_get_class (object); - - if (!ccw_hash) - ccw_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - if (!ccw_interface_hash) - ccw_interface_hash = g_hash_table_new (mono_aligned_addr_hash, NULL); - - ccw_list = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object))); - - ccw_list_item = ccw_list; - while (ccw_list_item) { - MonoCCW* ccw_iter = ccw_list_item->data; - if (mono_gchandle_get_target (ccw_iter->gc_handle) == object) { - ccw = ccw_iter; - break; - } - ccw_list_item = g_list_next(ccw_list_item); - } - - if (!iunknown [0]) { - iunknown [0] = cominterop_ccw_queryinterface; - iunknown [1] = cominterop_ccw_addref; - iunknown [2] = cominterop_ccw_release; - } - - if (!idispatch [0]) { - idispatch [0] = cominterop_ccw_get_type_info_count; - idispatch [1] = cominterop_ccw_get_type_info; - idispatch [2] = cominterop_ccw_get_ids_of_names; - idispatch [3] = cominterop_ccw_invoke; - } - - if (!ccw) { - ccw = g_new0 (MonoCCW, 1); - 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*/ - ccw->gc_handle = mono_gchandle_new_weakref (object, FALSE); - - if (!ccw_list) { - ccw_list = g_list_alloc (); - ccw_list->data = ccw; - } - else - ccw_list = g_list_append (ccw_list, ccw); - g_hash_table_insert (ccw_hash, GINT_TO_POINTER (mono_object_hash (object)), ccw_list); - /* register for finalization to clean up ccw */ - mono_object_register_finalizer (object); - } - - cinfo = mono_custom_attrs_from_class (itf); - if (cinfo) { - static MonoClass* coclass_attribute = NULL; - if (!coclass_attribute) - coclass_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "CoClassAttribute"); - if (mono_custom_attrs_has_attr (cinfo, coclass_attribute)) { - g_assert(itf->interface_count && itf->interfaces[0]); - itf = itf->interfaces[0]; - } - if (!cinfo->cached) - mono_custom_attrs_free (cinfo); - } - - iface = itf; - if (iface == mono_defaults.iunknown_class) { - start_slot = 3; - } - else if (iface == mono_defaults.idispatch_class) { - start_slot = 7; - } - else { - method_count += iface->method.count; - start_slot = cominterop_get_com_slot_begin (iface); - iface = NULL; - } - - ccw_entry = g_hash_table_lookup (ccw->vtable_hash, itf); - - if (!ccw_entry) { - int vtable_index = method_count-1+start_slot; - mono_loader_lock (); - vtable = mono_image_alloc0 (klass->image, sizeof (gpointer)*(method_count+start_slot)); - mono_loader_unlock (); - memcpy (vtable, iunknown, sizeof (iunknown)); - if (start_slot == 7) - memcpy (vtable+3, idispatch, sizeof (idispatch)); - - iface = itf; - for (i = iface->method.count-1; i >= 0;i--) { - int param_index = 0; - MonoMethodBuilder *mb; - MonoMarshalSpec ** mspecs; - MonoMethod *wrapper_method, *adjust_method; - MonoMethod *method = iface->methods [i]; - MonoMethodSignature* sig_adjusted; - MonoMethodSignature* sig = mono_method_signature (method); - gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG; - - - mb = mono_mb_new (iface, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED); - adjust_method = cominterop_get_managed_wrapper_adjusted (method); - sig_adjusted = mono_method_signature (adjust_method); - - mspecs = g_new (MonoMarshalSpec*, sig_adjusted->param_count + 1); - mono_method_get_marshal_info (method, mspecs); - - - /* move managed args up one */ - for (param_index = sig->param_count; param_index >= 1; param_index--) - mspecs [param_index+1] = mspecs [param_index]; - - /* first arg is IntPtr for interface */ - mspecs [1] = NULL; - - /* move return spec to last param */ - if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) { - mspecs [sig_adjusted->param_count] = mspecs [0]; - mspecs [0] = NULL; - } - - cominterop_setup_marshal_context (&m, adjust_method); - m.mb = mb; - 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, m.csig, m.csig->param_count + 16); - mono_marshal_unlock (); - mono_loader_unlock (); - - /* skip visiblity since we call internal methods */ - wrapper_method->skip_visibility = TRUE; - - vtable [vtable_index--] = mono_compile_method (wrapper_method); - - - for (param_index = sig_adjusted->param_count; param_index >= 0; param_index--) - if (mspecs [param_index]) - mono_metadata_free_marshal_spec (mspecs [param_index]); - g_free (mspecs); - } - - ccw_entry = g_new0 (MonoCCWInterface, 1); - ccw_entry->ccw = ccw; - ccw_entry->vtable = vtable; - g_hash_table_insert (ccw->vtable_hash, itf, ccw_entry); - g_hash_table_insert (ccw_interface_hash, ccw_entry, ccw); - } - - return ccw_entry; -} - -static gboolean -mono_marshal_free_ccw_entry (gpointer key, gpointer value, gpointer user_data) -{ - g_assert (value); - g_free (value); - return TRUE; -} - -/** - * mono_marshal_free_ccw: - * @object: the mono object - * - * Returns: whether the object had a CCW - */ -gboolean -mono_marshal_free_ccw (MonoObject* object) -{ - GList *ccw_list, *ccw_list_orig, *ccw_list_item; - /* no ccw's were created */ - if (!ccw_hash || g_hash_table_size (ccw_hash) == 0) - return FALSE; - - /* need to cache orig list address to remove from hash_table if empty */ - mono_cominterop_lock (); - ccw_list = ccw_list_orig = g_hash_table_lookup (ccw_hash, GINT_TO_POINTER (mono_object_hash (object))); - mono_cominterop_unlock (); - - if (!ccw_list) - return FALSE; - - ccw_list_item = ccw_list; - while (ccw_list_item) { - MonoCCW* ccw_iter = ccw_list_item->data; - MonoObject* handle_target = mono_gchandle_get_target (ccw_iter->gc_handle); - - /* Looks like the GC NULLs the weakref handle target before running the - * finalizer. So if we get a NULL target, destroy the CCW as well. */ - if (!handle_target || handle_target == object) { - /* remove all interfaces */ - g_hash_table_foreach_remove (ccw_iter->vtable_hash, mono_marshal_free_ccw_entry, NULL); - g_hash_table_destroy (ccw_iter->vtable_hash); - - /* get next before we delete */ - ccw_list_item = g_list_next(ccw_list_item); - - /* remove ccw from list */ - ccw_list = g_list_remove (ccw_list, ccw_iter); - g_free (ccw_iter); - } - else - ccw_list_item = g_list_next(ccw_list_item); - } - - /* if list is empty remove original address from hash */ - if (g_list_length (ccw_list) == 0) - g_hash_table_remove (ccw_hash, GINT_TO_POINTER (mono_object_hash (object))); - - - return TRUE; -} - -/** - * cominterop_get_native_wrapper_adjusted: - * @method: managed COM Interop method - * - * Returns: the generated method to call with signature matching - * the unmanaged COM Method signature - */ -static MonoMethod * -cominterop_get_managed_wrapper_adjusted (MonoMethod *method) -{ - static MonoMethod *get_hr_for_exception = NULL; - MonoMethod *res = NULL; - MonoMethodBuilder *mb; - MonoMarshalSpec **mspecs; - MonoMethodSignature *sig, *sig_native; - MonoExceptionClause *main_clause = NULL; - MonoMethodHeader *header; - int pos_leave; - int hr = 0; - int i; - gboolean preserve_sig = method->iflags & METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG; - - if (!get_hr_for_exception) - get_hr_for_exception = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetHRForException", -1); - - sig = mono_method_signature (method); - - /* create unmanaged wrapper */ - mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_COMINTEROP); - - sig_native = cominterop_method_signature (method); - - mspecs = g_new0 (MonoMarshalSpec*, sig_native->param_count+1); - - mono_method_get_marshal_info (method, mspecs); - - /* move managed args up one */ - for (i = sig->param_count; i >= 1; i--) - mspecs [i+1] = mspecs [i]; - - /* first arg is IntPtr for interface */ - mspecs [1] = NULL; - - /* move return spec to last param */ - if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) - mspecs [sig_native->param_count] = mspecs [0]; - - mspecs [0] = NULL; - - if (!preserve_sig) { - hr = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg); - - /* try */ - main_clause = g_new0 (MonoExceptionClause, 1); - main_clause->try_offset = mono_mb_get_label (mb); - } - - /* load last param to store result if not preserve_sig and not void */ - if (!preserve_sig && !MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_ldarg (mb, sig_native->param_count-1); - - /* the CCW -> object conversion */ - mono_mb_emit_ldarg (mb, 0); - mono_mb_emit_icon (mb, FALSE); - mono_mb_emit_icall (mb, cominterop_get_ccw_object); - - for (i = 0; i < sig->param_count; i++) - mono_mb_emit_ldarg (mb, i+1); - - mono_mb_emit_managed_call (mb, method, NULL); - - if (!preserve_sig) { - /* store result if not preserve_sig and we have one */ - if (!MONO_TYPE_IS_VOID (sig->ret)) - mono_mb_emit_byte (mb, mono_type_to_stind (sig->ret)); - - pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE); - - /* Main exception catch */ - main_clause->flags = MONO_EXCEPTION_CLAUSE_NONE; - main_clause->try_len = mono_mb_get_pos (mb) - main_clause->try_offset; - main_clause->data.catch_class = mono_defaults.object_class; - - /* handler code */ - main_clause->handler_offset = mono_mb_get_label (mb); - mono_mb_emit_managed_call (mb, get_hr_for_exception, NULL); - mono_mb_emit_stloc (mb, hr); - mono_mb_emit_branch (mb, CEE_LEAVE); - main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset; - /* end catch */ - - mono_mb_patch_branch (mb, pos_leave); - - mono_mb_emit_ldloc (mb, hr); - } - - mono_mb_emit_byte (mb, CEE_RET); - - mono_loader_lock (); - mono_marshal_lock (); - res = mono_mb_create_method (mb, sig_native, sig_native->param_count + 16); - mono_marshal_unlock (); - mono_loader_unlock (); - - mono_mb_free (mb); - - for (i = sig_native->param_count; i >= 0; i--) - if (mspecs [i]) - mono_metadata_free_marshal_spec (mspecs [i]); - g_free (mspecs); - - if (!preserve_sig) { - header = ((MonoMethodNormal *)res)->header; - header->num_clauses = 1; - header->clauses = main_clause; - } - - return res; -} - -/** - * cominterop_mono_string_to_guid: - * - * Converts the standard string representation of a GUID - * to a 16 byte Microsoft GUID. - */ -static void -cominterop_mono_string_to_guid (const MonoString* string, guint8 *guid) { - gunichar2 * chars = mono_string_chars (string); - int i = 0; - static guint8 indexes[16] = {7, 5, 3, 1, 12, 10, 17, 15, 20, 22, 25, 27, 29, 31, 33, 35}; - - for (i = 0; i < sizeof(indexes); i++) - guid [i] = g_unichar_xdigit_value (chars [indexes [i]]) + (g_unichar_xdigit_value (chars [indexes [i] - 1]) << 4); -} - -static gboolean -cominterop_class_guid_equal (guint8* guid, MonoClass* klass) -{ - guint8 klass_guid [16]; - if (cominterop_class_guid (klass, klass_guid)) - return !memcmp (guid, klass_guid, sizeof (klass_guid)); - return FALSE; -} - -static int STDCALL -cominterop_ccw_addref (MonoCCWInterface* ccwe) -{ - gint32 ref_count = 0; - MonoCCW* ccw = ccwe->ccw; - g_assert (ccw); - g_assert (ccw->gc_handle); - g_assert (ccw->ref_count >= 0); - ref_count = InterlockedIncrement ((gint32*)&ccw->ref_count); - if (ref_count == 1) { - guint32 oldhandle = ccw->gc_handle; - g_assert (oldhandle); - /* since we now have a ref count, alloc a strong handle*/ - ccw->gc_handle = mono_gchandle_new (mono_gchandle_get_target (oldhandle), FALSE); - mono_gchandle_free (oldhandle); - } - return ref_count; -} - -static int STDCALL -cominterop_ccw_release (MonoCCWInterface* ccwe) -{ - gint32 ref_count = 0; - MonoCCW* ccw = ccwe->ccw; - g_assert (ccw); - g_assert (ccw->ref_count > 0); - ref_count = InterlockedDecrement ((gint32*)&ccw->ref_count); - if (ref_count == 0) { - /* allow gc of object */ - guint32 oldhandle = ccw->gc_handle; - g_assert (oldhandle); - 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 - -static int STDCALL -cominterop_ccw_queryinterface (MonoCCWInterface* ccwe, guint8* riid, gpointer* ppv) -{ - GPtrArray *ifaces; - MonoClass *itf = NULL; - int i; - MonoCCW* ccw = ccwe->ccw; - MonoClass* klass = NULL; - MonoObject* object = mono_gchandle_get_target (ccw->gc_handle); - - g_assert (object); - klass = mono_object_class (object); - - if (ppv) - *ppv = NULL; - - /* handle IUnknown special */ - if (cominterop_class_guid_equal (riid, mono_defaults.iunknown_class)) { - *ppv = cominterop_get_ccw (object, mono_defaults.iunknown_class); - /* remember to addref on QI */ - cominterop_ccw_addref (*ppv); - return MONO_S_OK; - } - - /* handle IDispatch special */ - if (cominterop_class_guid_equal (riid, mono_defaults.idispatch_class)) { - *ppv = cominterop_get_ccw (object, mono_defaults.idispatch_class); - /* remember to addref on QI */ - cominterop_ccw_addref (*ppv); - return MONO_S_OK; - } - - ifaces = mono_class_get_implemented_interfaces (klass); - if (ifaces) { - for (i = 0; i < ifaces->len; ++i) { - MonoClass *ic = NULL; - ic = g_ptr_array_index (ifaces, i); - if (cominterop_class_guid_equal (riid, ic)) { - itf = ic; - break; - } - } - g_ptr_array_free (ifaces, TRUE); - } - if (itf) { - *ppv = cominterop_get_ccw (object, itf); - /* remember to addref on QI */ - cominterop_ccw_addref (*ppv); - return MONO_S_OK; - } - - return MONO_E_NOINTERFACE; -} - -static int STDCALL -cominterop_ccw_get_type_info_count (MonoCCWInterface* ccwe, guint32 *pctinfo) -{ - return MONO_E_NOTIMPL; -} - -static int STDCALL -cominterop_ccw_get_type_info (MonoCCWInterface* ccwe, guint32 iTInfo, guint32 lcid, gpointer *ppTInfo) -{ - return MONO_E_NOTIMPL; -} - -static int STDCALL -cominterop_ccw_get_ids_of_names (MonoCCWInterface* ccwe, gpointer riid, - gunichar2** rgszNames, guint32 cNames, - guint32 lcid, gint32 *rgDispId) -{ - return MONO_E_NOTIMPL; -} - -static int STDCALL -cominterop_ccw_invoke (MonoCCWInterface* ccwe, guint32 dispIdMember, - gpointer riid, guint32 lcid, - guint16 wFlags, gpointer pDispParams, - gpointer pVarResult, gpointer pExcepInfo, - guint32 *puArgErr) -{ - return MONO_E_NOTIMPL; -} - void mono_marshal_find_nonzero_bit_offset (guint8 *buf, int len, int *byte_offset, guint8 *bitmask) { @@ -12195,7 +10360,6 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) MonoMethodBuilder *mb; MonoMethodSignature *sig, *csig; MonoExceptionClause *clause; - MonoMethodHeader *header; MonoImage *image; MonoClass *klass; GHashTable *cache; @@ -12206,7 +10370,7 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) klass = method->klass; image = method->klass->image; - cache = image->thunk_invoke_cache; + cache = get_cache (&image->thunk_invoke_cache, mono_aligned_addr_hash, NULL); if ((res = mono_marshal_find_in_cache (cache, method))) return res; @@ -12235,7 +10399,7 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) } /* setup exception param as byref+[out] */ - csig->params [param_count - 1] = mono_metadata_type_dup (image->mempool, + csig->params [param_count - 1] = mono_metadata_type_dup (image, &mono_defaults.exception_class->byval_arg); csig->params [param_count - 1]->byref = 1; csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT; @@ -12257,9 +10421,7 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) 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 */ @@ -12314,6 +10476,8 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset; + mono_mb_set_clauses (mb, 1, clause); + mono_mb_patch_branch (mb, pos_leave); /* end-try */ @@ -12330,9 +10494,25 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) 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; } + +/* + * mono_marshal_free_dynamic_wrappers: + * + * Free wrappers of the dynamic method METHOD. + */ +void +mono_marshal_free_dynamic_wrappers (MonoMethod *method) +{ + g_assert (method->dynamic); + + mono_marshal_lock (); + /* + * FIXME: We currently leak the wrappers. Freeing them would be tricky as + * they could be shared with other methods ? + */ + if (method->klass->image->runtime_invoke_direct_cache) + g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method); + mono_marshal_unlock (); +}