static guint32 load_type_info_tls_id;
static void
-delegate_hash_table_add (MonoDelegate *d, MonoObject **target_loc);
+delegate_hash_table_add (MonoDelegate *d);
static void
emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
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_nostore, "wb_generic", "void ptr", FALSE);
+ register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
mono_cominterop_init ();
}
{
MonoMethod *method, *wrapper;
MonoClass *klass;
- MonoObject **target_loc;
+ uint32_t target_handle = 0;
if (!delegate)
return NULL;
if (delegate->target) {
/* Produce a location which can be embedded in JITted code */
- target_loc = mono_gc_alloc_fixed (sizeof (MonoObject*), NULL);
- *target_loc = delegate->target;
- } else {
- target_loc = NULL;
+ target_handle = mono_gchandle_new_weakref (delegate->target, FALSE);
}
- wrapper = mono_marshal_get_managed_wrapper (method, klass, target_loc);
+ wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle);
delegate->delegate_trampoline = mono_compile_method (wrapper);
// Add the delegate to the delegate hash table
- delegate_hash_table_add (delegate, target_loc);
+ delegate_hash_table_add (delegate);
/* when the object is collected, collect the dynamic method, too */
mono_object_register_finalizer ((MonoObject*)delegate);
* object pointer itself, otherwise we use a GC handle.
*/
static GHashTable *delegate_hash_table;
-/* Contains root locations pointing to the this arguments of delegates */
-static MonoGHashTable *delegate_target_locations;
static GHashTable *
delegate_hash_table_new (void) {
static void
delegate_hash_table_remove (MonoDelegate *d)
{
- MonoObject **target_loc;
#ifdef HAVE_MOVING_COLLECTOR
guint32 gchandle;
#endif
gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
#endif
g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
- if (delegate_target_locations)
- target_loc = mono_g_hash_table_lookup (delegate_target_locations, d->delegate_trampoline);
- else
- target_loc = NULL;
- if (target_loc)
- mono_g_hash_table_remove (delegate_target_locations, d->delegate_trampoline);
mono_marshal_unlock ();
- if (target_loc) {
- mono_gc_free_fixed (target_loc);
- }
#ifdef HAVE_MOVING_COLLECTOR
mono_gchandle_free (gchandle);
#endif
}
static void
-delegate_hash_table_add (MonoDelegate *d, MonoObject **target_loc)
+delegate_hash_table_add (MonoDelegate *d)
{
#ifdef HAVE_MOVING_COLLECTOR
guint32 gchandle = mono_gchandle_new_weakref ((MonoObject*)d, FALSE);
mono_marshal_lock ();
if (delegate_hash_table == NULL)
delegate_hash_table = delegate_hash_table_new ();
- if (delegate_target_locations == NULL) {
- /* Has to be conservative as the values are not object references */
- delegate_target_locations = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_CONSERVATIVE_GC);
- MONO_GC_REGISTER_ROOT (delegate_target_locations);
- }
#ifdef HAVE_MOVING_COLLECTOR
old_gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, GUINT_TO_POINTER (gchandle));
#else
g_hash_table_insert (delegate_hash_table, d->delegate_trampoline, d);
#endif
- if (target_loc)
- /* This keeps target_loc alive for Boehm */
- mono_g_hash_table_insert (delegate_target_locations, d->delegate_trampoline, target_loc);
mono_marshal_unlock ();
}
}
if (ptr) {
+ uint32_t gchandle;
+ void **method_data;
ji = mono_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (ptr));
g_assert (ji);
+ method_data = ((MonoMethodWrapper*)ji->method)->method_data;
+
+ /*the target gchandle is the first entry after size and the wrapper itself.*/
+ gchandle = GPOINTER_TO_UINT (method_data [2]);
+
+ if (gchandle)
+ mono_gchandle_free (gchandle);
+
mono_runtime_free_method (mono_object_domain (delegate), ji->method);
}
}
case MONO_TYPE_R4:
case MONO_TYPE_R8:
case MONO_TYPE_VALUETYPE:
+ case MONO_TYPE_PTR:
/* nothing to do */
break;
case MONO_TYPE_GENERICINST:
- case MONO_TYPE_PTR:
case MONO_TYPE_OBJECT:
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY:
return res;
}
-static void
-mono_marshal_method_set_wrapper_data (MonoMethod *method, gpointer data)
-{
- void **datav;
- /* assert */
- if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
- return;
-
- datav = ((MonoMethodWrapper *)method)->method_data;
- datav [1] = data;
-}
-
/* Create the method from the builder and place it in the cache */
MonoMethod*
mono_mb_create_and_cache (GHashTable *cache, gpointer key,
if (!res) {
res = newm;
g_hash_table_insert (cache, key, res);
- mono_marshal_method_set_wrapper_data (res, key);
+ mono_marshal_set_wrapper_info (res, key);
mono_marshal_unlock ();
} else {
mono_marshal_unlock ();
mono_marshal_lock ();
if (!*res) {
*res = newm;
- mono_marshal_method_set_wrapper_data (*res, key);
+ mono_marshal_set_wrapper_info (*res, key);
mono_marshal_unlock ();
} else {
mono_marshal_unlock ();
mono_marshal_method_from_wrapper (MonoMethod *wrapper)
{
gpointer res;
+ int wrapper_type = wrapper->wrapper_type;
- if (wrapper->wrapper_type == MONO_WRAPPER_NONE || wrapper->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+ if (wrapper_type == MONO_WRAPPER_NONE || wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
return wrapper;
- res = mono_method_get_wrapper_data (wrapper, 1);
- if (res == NULL)
- return wrapper;
- return res;
+ switch (wrapper_type) {
+ case MONO_WRAPPER_REMOTING_INVOKE:
+ case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
+ case MONO_WRAPPER_XDOMAIN_INVOKE:
+ case MONO_WRAPPER_SYNCHRONIZED:
+ case MONO_WRAPPER_MANAGED_TO_NATIVE:
+ case MONO_WRAPPER_RUNTIME_INVOKE:
+ res = mono_method_get_wrapper_data (wrapper, 1);
+ if (res == NULL)
+ return wrapper;
+ return res;
+ default:
+ return NULL;
+ }
}
+/*
+ * mono_marshal_get_wrapper_info:
+ *
+ * Retrieve the pointer stored by mono_marshal_set_wrapper_info.
+ */
gpointer
-mono_marshal_wrapper_info_from_wrapper (MonoMethod *wrapper)
+mono_marshal_get_wrapper_info (MonoMethod *wrapper)
{
+ g_assert (wrapper->wrapper_type);
+
return mono_method_get_wrapper_data (wrapper, 1);
}
+/*
+ * mono_marshal_set_wrapper_info:
+ *
+ * Store an arbitrary pointer inside the wrapper which is retrievable by
+ * mono_marshal_get_wrapper_info. The format of the data depends on the type of the
+ * wrapper (method->wrapper_type).
+ */
+void
+mono_marshal_set_wrapper_info (MonoMethod *method, gpointer data)
+{
+ void **datav;
+ /* assert */
+ if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+ return;
+
+ datav = ((MonoMethodWrapper *)method)->method_data;
+ datav [1] = data;
+}
+
/*
* get_wrapper_target_class:
*
return NULL;
}
- if (ares->async_delegate != (MonoObject*)delegate && mono_framework_version () >= 2) {
+ if (ares->async_delegate != (MonoObject*)delegate) {
mono_raise_exception (mono_get_exception_invalid_operation (
"The IAsyncResult object provided does not match this delegate."));
return NULL;
MonoMethod *target_method = NULL;
MonoClass *target_class = NULL;
gboolean callvirt = FALSE;
+ gboolean closed_over_null = FALSE;
/*
* If the delegate target is null, and the target method is not static, a virtual
sig = mono_signature_no_pinvoke (method);
+ if (callvirt)
+ closed_over_null = sig->param_count == mono_method_signature (del->method)->param_count;
+
if (callvirt) {
/* We need to cache the signature+method pair */
mono_marshal_lock ();
mono_mb_patch_branch (mb, pos0);
if (callvirt) {
- mono_mb_emit_ldarg (mb, 1);
- mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
- for (i = 1; i < sig->param_count; ++i)
- mono_mb_emit_ldarg (mb, i + 1);
- mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
+ if (!closed_over_null) {
+ mono_mb_emit_ldarg (mb, 1);
+ mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
+ for (i = 1; i < sig->param_count; ++i)
+ mono_mb_emit_ldarg (mb, i + 1);
+ mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
+ } else {
+ mono_mb_emit_byte (mb, CEE_LDNULL);
+ for (i = 0; i < sig->param_count; ++i)
+ mono_mb_emit_ldarg (mb, i + 1);
+ mono_mb_emit_op (mb, CEE_CALL, target_method);
+ }
} else {
for (i = 0; i < sig->param_count; ++i)
mono_mb_emit_ldarg (mb, i + 1);
new_key->sig = sig;
new_key->method = target_method;
g_hash_table_insert (cache, new_key, res);
- mono_marshal_method_set_wrapper_data (res, new_key);
+ mono_marshal_set_wrapper_info (res, new_key);
mono_marshal_unlock ();
} else {
mono_marshal_unlock ();
static MonoType*
get_runtime_invoke_type (MonoType *t, gboolean ret)
{
- if (t->byref) {
- if (t->type == MONO_TYPE_GENERICINST)
- return t;
- else
- return &mono_defaults.int_class->byval_arg;
- }
+ if (t->byref)
+ /* Can't share this with 'I' as that needs another indirection */
+ return t;
if (MONO_TYPE_IS_REFERENCE (t))
return &mono_defaults.object_class->byval_arg;
}
}
-#if 0
- /* 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;
- }
-#endif
+ target_klass = get_wrapper_target_class (method->klass->image);
- /*
- * We try to share runtime invoke wrappers between different methods but have to
- * be careful about methods whose klass has a type cctor, since putting the wrapper
- * into that klass would mean that calling a method of klass A might invoke the
- * type initializer of class B, or throw an exception if the type initializer
- * was called before and failed. See #349621 for an example.
- * We avoid that for mscorlib methods by putting every wrapper into the object class.
- */
- if (method->klass->image == mono_defaults.corlib)
+ /* Try to share wrappers for non-corlib methods with simple signatures */
+ if (mono_metadata_signature_equal (callsig, cctor_signature)) {
+ callsig = cctor_signature;
+ target_klass = mono_defaults.object_class;
+ } else if (mono_metadata_signature_equal (callsig, finalize_signature)) {
+ callsig = finalize_signature;
target_klass = mono_defaults.object_class;
- else {
- /* Try to share wrappers for non-corlib methods with simple signatures */
- if (mono_metadata_signature_equal (callsig, cctor_signature)) {
- callsig = cctor_signature;
- target_klass = mono_defaults.object_class;
- } else if (mono_metadata_signature_equal (callsig, finalize_signature)) {
- callsig = finalize_signature;
- target_klass = mono_defaults.object_class;
- } else {
- // FIXME: This breaks too many things
- /*
- if (mono_class_get_cctor (method->klass))
- need_direct_wrapper = TRUE;
- */
-
- target_klass = get_wrapper_target_class (method->klass->image);
- }
}
if (need_direct_wrapper) {
/* allocate local 1 (object) exc */
mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
- /* cond set *exc to null */
- mono_mb_emit_byte (mb, CEE_LDARG_2);
- mono_mb_emit_byte (mb, CEE_BRFALSE_S);
- mono_mb_emit_byte (mb, 3);
- mono_mb_emit_byte (mb, CEE_LDARG_2);
- mono_mb_emit_byte (mb, CEE_LDNULL);
- mono_mb_emit_byte (mb, CEE_STIND_REF);
-
emit_thread_force_interrupt_checkpoint (mb);
if (virtual) {
/* Check null */
if (t->byref) {
-
label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
mono_mb_emit_ldarg (mb, argnum);
mono_mb_emit_byte (mb, ldop);
- }
+ } else
+ label_null = 0;
label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
mono_mb_emit_byte (mb, CEE_LDC_I4_1);
mono_mb_emit_byte (mb, CEE_RET);
}
+G_GNUC_UNUSED static void
+code_for (MonoMethod *method) {
+ MonoMethodHeader *header = mono_method_get_header (method);
+ printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (method, TRUE), mono_disasm_code (0, method, header->code, header->code + header->code_size));
+}
+
/**
* mono_marshal_get_native_wrapper:
* @method: The MonoMethod to wrap.
if (method->string_ctor)
csig->ret = &mono_defaults.string_class->byval_arg;
- if (sig->hasthis)
+ if (sig->hasthis) {
+ int pos;
+
+ /*
+ * Add a null check since public icalls can be called with 'call' which
+ * does no such check.
+ */
+ mono_mb_emit_byte (mb, CEE_LDARG_0);
+ pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+ mono_mb_emit_exception (mb, "NullReferenceException", NULL);
+ mono_mb_patch_branch (mb, pos);
+
mono_mb_emit_byte (mb, CEE_LDARG_0);
+ }
for (i = 0; i < sig->param_count; i++)
mono_mb_emit_ldarg (mb, i + sig->hasthis);
mono_metadata_free_marshal_spec (mspecs [i]);
g_free (mspecs);
- /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
+ /* code_for (res); */
return res;
}
mb, csig, csig->param_count + 16);
mono_mb_free (mb);
- /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
+ mono_marshal_set_wrapper_info (res, NULL);
+
+ /* code_for (res); */
return res;
}
* THIS_LOC is the memory location where the target of the delegate is stored.
*/
void
-mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject** this_loc)
+mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle)
{
MonoMethodSignature *sig, *csig;
int i, *tmp_locals;
emit_thread_interrupt_checkpoint (mb);
if (sig->hasthis) {
- if (this_loc) {
- mono_mb_emit_ptr (mb, this_loc);
- mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ if (target_handle) {
+ mono_mb_emit_icon (mb, (gint32)target_handle);
+ mono_mb_emit_icall (mb, mono_gchandle_get_target);
} else {
/* fixme: */
g_assert_not_reached ();
}
} else if (closed) {
- mono_mb_emit_ptr (mb, this_loc);
- mono_mb_emit_byte (mb, CEE_LDIND_REF);
+ mono_mb_emit_icon (mb, (gint32)target_handle);
+ mono_mb_emit_icall (mb, mono_gchandle_get_target);
}
for (i = 0; i < sig->param_count; i++) {
* generates IL code to call managed methods from unmanaged code
*/
MonoMethod *
-mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject **this_loc)
+mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
{
static MonoClass *UnmanagedFunctionPointerAttribute;
MonoMethodSignature *sig, *csig, *invoke_sig;
* options.
*/
cache = get_cache (&method->klass->image->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
- if (!this_loc && (res = mono_marshal_find_in_cache (cache, method)))
+ if (!target_handle && (res = mono_marshal_find_in_cache (cache, method)))
return res;
invoke = mono_get_delegate_invoke (delegate_klass);
mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+ /*the target gchandle must be the first entry after size and the wrapper itself.*/
+ mono_mb_add_data (mb, GUINT_TO_POINTER (target_handle));
+
/* we copy the signature, so that we can modify it */
- if (this_loc)
+ if (target_handle)
/* Need to free this later */
csig = mono_metadata_signature_dup (invoke_sig);
else
mono_custom_attrs_free (cinfo);
}
- mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this_loc);
+ mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle);
- if (!this_loc)
+ if (!target_handle)
res = mono_mb_create_and_cache (cache, method,
mb, csig, sig->param_count + 16);
else {
mono_metadata_free_marshal_spec (mspecs [i]);
g_free (mspecs);
- /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
+ /* code_for (res); */
return res;
}
/* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
- mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, NULL);
+ mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, 0);
mb->dynamic = 1;
method = mono_mb_create_method (mb, csig, sig->param_count + 16);
mb, sig, sig->param_count + 16);
mono_mb_free (mb);
- /* printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size)); */
+ /* code_for (res); */
return res;
}
info->rank = rank;
info->elem_size = elem_size;
- mono_marshal_method_set_wrapper_data (ret, info);
+ mono_marshal_set_wrapper_info (ret, info);
}
mono_marshal_unlock ();
return ret;
type = rtype->type;
klass = mono_class_from_mono_type (type);
+ if (!mono_class_init (klass))
+ mono_raise_exception (mono_class_get_exception_for_failure (klass));
+
layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK);
if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
MonoObject *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
{
+ MonoClass *klass;
MonoDomain *domain = mono_domain_get ();
MonoObject *res;
MONO_CHECK_ARG_NULL (src);
MONO_CHECK_ARG_NULL (type);
- res = mono_object_new (domain, mono_class_from_mono_type (type->type));
+ klass = mono_class_from_mono_type (type->type);
+ if (!mono_class_init (klass))
+ mono_raise_exception (mono_class_get_exception_for_failure (klass));
+
+ res = mono_object_new (domain, klass);
ptr_to_structure (src, res);
fname = mono_string_to_utf8 (field_name);
klass = mono_class_from_mono_type (type->type);
+ if (!mono_class_init (klass))
+ mono_raise_exception (mono_class_get_exception_for_failure (klass));
while (klass && match_index == -1) {
MonoClassField* field;
MONO_CHECK_ARG_NULL (type);
klass = mono_class_from_mono_type (type->type);
+ if (!mono_class_init (klass))
+ mono_raise_exception (mono_class_get_exception_for_failure (klass));
mono_struct_delete_old (klass, (char *)src);
}
MonoDelegate*
ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionType *type)
{
- return mono_ftnptr_to_delegate (mono_type_get_class (type->type), ftn);
+ MonoClass *klass = mono_type_get_class (type->type);
+ if (!mono_class_init (klass))
+ mono_raise_exception (mono_class_get_exception_for_failure (klass));
+
+ return mono_ftnptr_to_delegate (klass, ftn);
}
/**
case MONO_TYPE_STRING:
switch (string_encoding) {
case MONO_NATIVE_LPWSTR:
- return mono_string_to_utf16 ((MonoString*)o);
+ return mono_marshal_string_to_utf16_copy ((MonoString*)o);
break;
case MONO_NATIVE_LPSTR:
return mono_string_to_lpstr ((MonoString*)o);
{
g_assert (method->dynamic);
- mono_marshal_lock ();
+ /* This could be called during shutdown */
+ if (marshal_mutex_initialized)
+ mono_marshal_lock ();
/*
* FIXME: We currently leak the wrappers. Freeing them would be tricky as
* they could be shared with other methods ?
*/
if (method->klass->image->runtime_invoke_direct_cache)
g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method);
- mono_marshal_unlock ();
+ if (marshal_mutex_initialized)
+ mono_marshal_unlock ();
}
/*