static guint32 last_error_tls_id;
+static guint32 load_type_info_tls_id;
+
static void
delegate_hash_table_add (MonoDelegate *d);
mono_marshal_set_last_error_windows (int error);
static void
-mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func);
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func);
static void
register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
// return type is always int32 (HRESULT)
res->ret = &mono_defaults.int32_class->byval_arg;
- // com is always stdcall
+ // 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;
}
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);
+}
+
/**
* cominterop_get_com_slot_for_method:
* @method: a method
guint32 offset = 7;
guint32 slot = method->slot;
GPtrArray *ifaces;
- MonoClass *ic = method->klass;
+ MonoClass *ic = NULL;
int i;
ifaces = mono_class_get_implemented_interfaces (method->klass);
g_ptr_array_free (ifaces, TRUE);
}
+ if (!ic)
+ ic = method->klass;
+
+ g_assert (ic);
+ g_assert (MONO_CLASS_IS_INTERFACE (ic));
+
if (!interface_type_attribute)
interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
cinfo = mono_custom_attrs_from_class (ic);
cominterop_get_method_interface (MonoMethod* method)
{
GPtrArray *ifaces;
- MonoClass *ic = method->klass;
+ MonoType* t = NULL;
+ MonoClass *ic = NULL;
int i;
MonoReflectionType* rt = NULL;
g_ptr_array_free (ifaces, TRUE);
}
- if (ic) {
- MonoType* t = mono_class_get_type (ic);
- rt = mono_type_get_object (mono_domain_get(), t);
- }
+ if (!ic)
+ ic = method->klass;
+
+ g_assert (ic);
+ g_assert (MONO_CLASS_IS_INTERFACE (ic));
+
+ t = mono_class_get_type (ic);
+ rt = mono_type_get_object (mono_domain_get(), t);
return rt;
}
InitializeCriticalSection (&marshal_mutex);
wrapper_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
last_error_tls_id = TlsAlloc ();
+ load_type_info_tls_id = TlsAlloc ();
register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
register_icall (mono_gc_wbarrier_generic_store, "wb_generic", "void ptr object", FALSE);
register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "object 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);
}
}
mono_marshal_cleanup (void)
{
g_hash_table_destroy (wrapper_hash);
+ TlsFree (load_type_info_tls_id);
TlsFree (last_error_tls_id);
DeleteCriticalSection (&marshal_mutex);
}
sig = mono_metadata_signature_dup (mono_method_signature (invoke));
sig->hasthis = 0;
- wrapper = mono_marshal_get_native_func_wrapper (sig, &piinfo, mspecs, ftn);
+ wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn);
for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
if (mspecs [i])
mono_string_to_bstr (MonoString *string_obj)
{
#ifdef PLATFORM_WIN32
+ if (!string_obj)
+ return NULL;
return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
#else
g_error ("UnmanagedMarshal.BStr is not implemented.");
mono_string_from_bstr (gpointer bstr)
{
#ifdef PLATFORM_WIN32
- MonoDomain *domain = mono_domain_get ();
- return mono_string_new_utf16 (domain, bstr, SysStringLen (bstr));
+ if (!bstr)
+ return NULL;
+ return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
#else
g_error ("UnmanagedMarshal.BStr is not implemented.");
return NULL;
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;
+ 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_failed = 0;
+ MonoClass *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_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ if (!com_interop_proxy_class)
+ com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+ if (!com_interop_proxy_get_proxy)
+ com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
+ if (!get_transparent_proxy)
+ get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+ real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
+
+ mono_mb_emit_ldloc (mb, 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_stloc (mb, real_proxy);
+
+
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_ldloc (mb, real_proxy);
+ mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
+ if (klass && klass != mono_defaults.object_class)
+ mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+ // case if null
+ mono_mb_patch_short_branch (mb, pos_failed);
+ break;
+ }
case MONO_MARSHAL_CONV_STR_BSTR:
case MONO_MARSHAL_CONV_STR_ANSIBSTR:
case MONO_MARSHAL_CONV_STR_TBSTR:
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
if (eklass->blittable) {
mono_mb_emit_ldloc (mb, 1);
mono_mb_emit_stloc (mb, 1);
}
- mono_mb_patch_short_branch (mb, pos);
+ mono_mb_patch_branch (mb, pos);
break;
}
case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_byte (mb, CEE_LDIND_I);
- pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* save the old src pointer */
mono_mb_emit_ldloc (mb, 0);
mono_mb_emit_ldloc (mb, dst_var);
mono_mb_emit_stloc (mb, 1);
- mono_mb_patch_short_branch (mb, pos);
+ mono_mb_patch_branch (mb, pos);
+ break;
+ }
+ case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
+ case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
+ case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
+ guint32 pos_failed = 0, pos_rcw = 0;
+ char * msg;
+
+ mono_mb_emit_ldloc (mb, 1);
+ //mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_ptr (mb, 0);
+ //mono_mb_emit_byte (mb, CEE_LDIND_U1);
+ 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_failed = 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) {
+ static MonoMethod* GetInterface = NULL;
+
+ if (!GetInterface)
+ GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+ mono_mb_emit_ptr (mb, type);
+ mono_mb_emit_icall (mb, type_from_handle);
+ mono_mb_emit_managed_call (mb, GetInterface, NULL);
+ }
+ 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 {
+ }
+ mono_mb_emit_byte (mb, CEE_STIND_I);
+
+ // if not rcw
+ mono_mb_patch_short_branch (mb, pos_rcw);
+ msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented.");
+ mono_mb_emit_exception_marshal_directive (mb, msg);
+
+ // case if null
+ mono_mb_patch_short_branch (mb, pos_failed);
break;
}
default: {
mono_mb_emit_stloc (mb, 1);
break;
}
+ case MONO_TYPE_OBJECT: {
+ if (to_object) {
+ static MonoMethod *variant_clear = NULL;
+ static MonoMethod *get_object_for_native_variant = NULL;
+ if (!variant_clear)
+ variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
+ if (!get_object_for_native_variant)
+ get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+ mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_managed_call (mb, variant_clear, NULL);
+ }
+ else {
+ static MonoMethod *get_native_variant_for_object = NULL;
+ if (!get_native_variant_for_object)
+ get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+
+ mono_mb_emit_ldloc (mb, 0);
+ mono_mb_emit_byte(mb, CEE_LDIND_REF);
+ mono_mb_emit_ldloc (mb, 1);
+ mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+ }
+ break;
+ }
default:
g_warning ("marshaling type %02x not implemented", ftype->type);
mspecs[0] = NULL;
- mono_marshal_emit_native_wrapper(mb_native, sig_native, piinfo, mspecs, piinfo->addr);
+ mono_marshal_emit_native_wrapper(mono_defaults.corlib, mb_native, sig_native, piinfo, mspecs, piinfo->addr);
mono_loader_lock ();
mono_marshal_lock ();
mono_mb_emit_ldarg (mb, 0);
mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
mono_mb_emit_byte (mb, CEE_LDIND_REF);
- mono_mb_emit_stloc (mb, 0);
/* if prev != null */
- mono_mb_emit_ldloc (mb, 0);
pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
/* then recurse */
- mono_mb_emit_ldloc (mb, 0);
+
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
+
+ mono_mb_emit_ldarg (mb, 0);
+ mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
+ mono_mb_emit_byte (mb, CEE_LDIND_REF);
for (i = 0; i < sig->param_count; i++)
mono_mb_emit_ldarg (mb, i + 1);
mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
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 {
g_assert (marshal_native_to_managed);
}
- mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, mb->method->klass->image);
+ mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
g_assert (mtype != NULL);
mklass = mono_class_from_mono_type (mtype);
g_assert (mklass != NULL);
if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
break;
+ /* Minic MS.NET behavior */
+ if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
+ break;
+
/* Check for null */
mono_mb_emit_ldarg (mb, argnum);
if (t->byref)
mono_mb_emit_ldloc (mb, conv_arg);
mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
mono_mb_emit_byte (mb, CEE_STIND_REF);
+ } else if (t->attrs &PARAM_ATTRIBUTE_OUT) {
+ mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
+
+ mono_mb_emit_op (mb, CEE_CALL, get_instance);
+
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
+
+ /* We have nowhere to store the result */
+ mono_mb_emit_byte (mb, CEE_POP);
}
mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
}
} else {
- guint32 pos_failed = 0;
+ char *msg = NULL;
+ guint32 pos_failed = 0, pos_rcw = 0;
mono_mb_emit_ldarg (mb, argnum);
// if null just break, conv arg was already inited to 0
- pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_icall (mb, cominterop_object_is_rcw);
+ pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
}
mono_mb_emit_stloc (mb, conv_arg);
+ // if not rcw
+ mono_mb_patch_short_branch (mb, pos_rcw);
+ msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented.");
+ mono_mb_emit_exception_marshal_directive (mb, msg);
+
// case if null
- mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
+ mono_mb_patch_short_branch (mb, pos_failed);
}
}
else if (klass->delegate) {
mono_mb_emit_stloc (mb, conv_arg);
} else if (klass->blittable) {
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ mono_mb_emit_stloc (mb, conv_arg);
+
+ mono_mb_emit_ldarg (mb, argnum);
+ pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_ldflda (mb, sizeof (MonoObject));
mono_mb_emit_stloc (mb, conv_arg);
+
+ mono_mb_patch_branch (mb, pos);
break;
} else {
mono_mb_emit_byte (mb, CEE_LDNULL);
mono_mb_emit_byte (mb, CEE_STIND_REF);
mono_mb_emit_ldloc (mb, conv_arg);
- pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+ pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
if (!com_interop_proxy_class)
com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
mono_mb_emit_byte (mb, CEE_STIND_REF);
// case if null
- mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
+ mono_mb_patch_short_branch (mb, pos_failed);
}
break;
}
/**
* mono_marshal_emit_native_wrapper:
+ * @image: the image to use for looking up custom marshallers
* @sig: The signature of the native function
* @piinfo: Marshalling information
* @mspecs: Marshalling information
* generates IL code for the pinvoke wrapper, the generated code calls @func.
*/
static void
-mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
{
EmitMarshalContext m;
MonoMethodSignature *csig;
csig = signature_dup (mb->method->klass->image, sig);
csig->pinvoke = 1;
m.csig = csig;
+ m.image = image;
/* we allocate local for use with emit_struct_conv() */
/* allocate local 0 (pointer) src_ptr */
mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
mono_method_get_marshal_info (method, mspecs);
- mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, piinfo->addr);
+ mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr);
csig = signature_dup (method->klass->image, sig);
csig->pinvoke = 0;
/**
* mono_marshal_get_native_func_wrapper:
+ * @image: The image to use for memory allocation and for looking up custom marshallers.
* @sig: The signature of the function
* @func: The native function to wrap
*
* wrapper.
*/
MonoMethod *
-mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig,
+mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig,
MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
{
MonoMethodSignature *csig;
GHashTable *cache;
char *name;
- cache = mono_defaults.corlib->native_wrapper_cache;
+ cache = image->native_wrapper_cache;
if ((res = mono_marshal_find_in_cache (cache, func)))
return res;
mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
mb->method->save_lmf = 1;
- mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, func);
+ mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func);
- csig = signature_dup (mb->method->klass->image, sig);
+ csig = signature_dup (image, sig);
csig->pinvoke = 0;
res = mono_mb_create_and_cache (cache, func,
mb, csig, csig->param_count + 16);
m.piinfo = NULL;
m.retobj_var = 0;
m.csig = csig;
+ m.image = method->klass->image;
#ifdef PLATFORM_WIN32
/*
return mono_string_to_bstr(ptr);
}
-#ifdef __i386__
+// STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
+#ifdef PLATFORM_WIN32
#ifdef _MSC_VER
#define STDCALL __stdcall
#else
g_hash_table_insert (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT, pUnk);
}
+/**
+ * mono_marshal_is_loading_type_info:
+ *
+ * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
+ * thread.
+ */
+static gboolean
+mono_marshal_is_loading_type_info (MonoClass *klass)
+{
+ GSList *loads_list = TlsGetValue (load_type_info_tls_id);
+
+ return g_slist_find (loads_list, klass) != NULL;
+}
+
+/**
+ * mono_marshal_load_type_info:
+ *
+ * Initialize klass->marshal_info using information from metadata. This function can
+ * recursively call itself, and the caller is responsible to avoid that by calling
+ * mono_marshal_is_loading_type_info () beforehand.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
MonoMarshalType *
mono_marshal_load_type_info (MonoClass* klass)
{
MonoClassField* field;
gpointer iter;
guint32 layout;
+ GSList *loads_list;
g_assert (klass != NULL);
if (!klass->inited)
mono_class_init (klass);
+
+ mono_loader_lock ();
+
+ if (klass->marshal_info) {
+ mono_loader_unlock ();
+ return klass->marshal_info;
+ }
+
+ /*
+ * This function can recursively call itself, so we keep the list of classes which are
+ * under initialization in a TLS list.
+ */
+ g_assert (!mono_marshal_is_loading_type_info (klass));
+ loads_list = TlsGetValue (load_type_info_tls_id);
+ loads_list = g_slist_prepend (loads_list, klass);
+ TlsSetValue (load_type_info_tls_id, loads_list);
iter = NULL;
while ((field = mono_class_get_fields (klass, &iter))) {
layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
- klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
+ /* The mempool is protected by the loader lock */
+ info = mono_mempool_alloc0 (klass->image->mempool, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
info->num_fields = count;
/* Try to find a size for this type in metadata */
klass->blittable = FALSE;
/* If this is an array type, ensure that we have element info */
- if (klass->element_class) {
+ if (klass->element_class && !mono_marshal_is_loading_type_info (klass->element_class)) {
mono_marshal_load_type_info (klass->element_class);
}
+ loads_list = TlsGetValue (load_type_info_tls_id);
+ loads_list = g_slist_remove (loads_list, klass);
+ TlsSetValue (load_type_info_tls_id, loads_list);
+
+ klass->marshal_info = info;
+
+ mono_loader_unlock ();
+
return klass->marshal_info;
}
gint32
mono_class_native_size (MonoClass *klass, guint32 *align)
{
- if (!klass->marshal_info)
- mono_marshal_load_type_info (klass);
+ if (!klass->marshal_info) {
+ if (mono_marshal_is_loading_type_info (klass))
+ return 0;
+ else
+ mono_marshal_load_type_info (klass);
+ }
if (align)
*align = klass->min_align;
return sizeof (gpointer);
case MONO_NATIVE_STRUCT:
klass = mono_class_from_mono_type (type);
+ if (klass == mono_defaults.object_class &&
+ (mspec && mspec->native == MONO_NATIVE_STRUCT)) {
+ *align = 16;
+ return 16;
+ }
return mono_class_native_size (klass, align);
case MONO_NATIVE_BYVALTSTR: {
int esize = unicode ? 2: 1;