#define mono_marshal_lock() EnterCriticalSection (&marshal_mutex)
#define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex)
static CRITICAL_SECTION marshal_mutex;
+static gboolean marshal_mutex_initialized;
static guint32 last_error_tls_id;
static void init_safe_handle (void);
+static void runtime_invoke_reset_abort (MonoException *ex);
+
/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
static MonoMethod *sh_dangerous_add_ref;
static MonoMethod *sh_dangerous_release;
int sigsize;
res = mono_metadata_signature_alloc (image, sig->param_count);
- sigsize = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
+ sigsize = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
memcpy (res, sig, sigsize);
return res;
if (!module_initialized) {
module_initialized = TRUE;
InitializeCriticalSection (&marshal_mutex);
+ marshal_mutex_initialized = TRUE;
last_error_tls_id = TlsAlloc ();
load_type_info_tls_id = TlsAlloc ();
register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
+ register_icall (mono_free_lparray, "mono_free_lparray", "void object ptr", FALSE);
register_icall (mono_byvalarray_to_array, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE);
register_icall (mono_array_to_byvalarray, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE);
register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
register_icall (mono_context_set, "mono_context_set", "void object", FALSE);
register_icall (mono_upgrade_remote_class_wrapper, "mono_upgrade_remote_class_wrapper", "void object object", FALSE);
register_icall (type_from_handle, "type_from_handle", "object ptr", FALSE);
- register_icall (mono_gc_wbarrier_generic_store, "wb_generic", "void ptr object", FALSE);
+ register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
+ register_icall (runtime_invoke_reset_abort, "runtime_invoke_reset_abort", "void object", FALSE);
mono_cominterop_init ();
}
TlsFree (load_type_info_tls_id);
TlsFree (last_error_tls_id);
DeleteCriticalSection (&marshal_mutex);
+ marshal_mutex_initialized = FALSE;
}
MonoClass *byte_array_class;
gpointer
mono_array_to_lparray (MonoArray *array)
{
+ gpointer *nativeArray = NULL;
+ int nativeArraySize = 0;
+
+ int i = 0;
+ MonoClass *klass;
+
if (!array)
return NULL;
- /* fixme: maybe we need to make a copy */
+ klass = array->obj.vtable->klass;
+
+ switch (klass->element_class->byval_arg.type) {
+ case MONO_TYPE_VOID:
+ g_assert_not_reached ();
+ break;
+ case MONO_TYPE_CLASS:
+ nativeArraySize = array->max_length;
+ nativeArray = malloc(sizeof(gpointer) * nativeArraySize);
+ for(i = 0; i < nativeArraySize; ++i)
+ nativeArray[i] = ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal(((gpointer*)array->vector)[i]);
+ return nativeArray;
+ case MONO_TYPE_U1:
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_CHAR:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_U8:
+ case MONO_TYPE_I8:
+ case MONO_TYPE_R4:
+ case MONO_TYPE_R8:
+ case MONO_TYPE_VALUETYPE:
+ /* nothing to do */
+ break;
+ case MONO_TYPE_GENERICINST:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_STRING:
+ default:
+ g_warning ("type 0x%x not handled", klass->element_class->byval_arg.type);
+ g_assert_not_reached ();
+ }
+
return array->vector;
}
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray)
+{
+ MonoClass *klass;
+ int i = 0;
+
+ if (!array)
+ return;
+
+ if (!nativeArray)
+ return;
+
+ klass = array->obj.vtable->klass;
+
+ switch (klass->element_class->byval_arg.type) {
+ case MONO_TYPE_CLASS:
+ for(i = 0; i < array->max_length; ++i)
+ mono_marshal_free_ccw(nativeArray[i]);
+ free(nativeArray);
+ break;
+ }
+}
+
static void
mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *elclass, guint32 elnum)
{
return mono_array_to_savearray;
case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
return mono_array_to_lparray;
+ case MONO_MARSHAL_FREE_LPARRAY:
+ return mono_free_lparray;
case MONO_MARSHAL_CONV_DEL_FTN:
return mono_delegate_to_ftnptr;
case MONO_MARSHAL_CONV_FTN_DEL:
} else {
return mono_marshal_get_remoting_invoke (method);
}
+ /* Not erached */
+ return NULL;
}
G_GNUC_UNUSED static gpointer
int i;
res = mono_metadata_signature_alloc (klass->image, sig->param_count + 1);
- memcpy (res, sig, sizeof (MonoMethodSignature));
+ memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
res->param_count = sig->param_count + 1;
res->hasthis = FALSE;
for (i = sig->param_count - 1; i >= 0; i --)
static MonoType*
get_runtime_invoke_type (MonoType *t, gboolean ret)
{
- if (t->byref)
- return &mono_defaults.int_class->byval_arg;
+ if (t->byref) {
+ if (t->type == MONO_TYPE_GENERICINST)
+ return t;
+ else
+ return &mono_defaults.int_class->byval_arg;
+ }
+
+ if (MONO_TYPE_IS_REFERENCE (t))
+ return &mono_defaults.object_class->byval_arg;
+
+ if (ret)
+ /* The result needs to be boxed */
+ return t;
handle_enum:
switch (t->type) {
case MONO_TYPE_PTR:
return &mono_defaults.int_class->byval_arg;
case MONO_TYPE_VALUETYPE:
- if (t->data.klass->enumtype && !ret) {
+ if (t->data.klass->enumtype) {
t = mono_class_enum_basetype (t->data.klass);
goto handle_enum;
}
return t;
default:
- if (MONO_TYPE_IS_REFERENCE (t))
- return &mono_defaults.object_class->byval_arg;
return t;
}
}
runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
{
/* Can't share wrappers which return a vtype since it needs to be boxed */
- if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)))
+ if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)) && !mono_metadata_type_equal (sig1->ret, sig2->ret))
return FALSE;
else
return mono_metadata_signature_equal (sig1, sig2);
}
+/*
+ * get_wrapper_target_class:
+ *
+ * Return the class where a wrapper method should be placed.
+ */
+static MonoClass*
+get_wrapper_target_class (MonoImage *image)
+{
+ MonoClass *klass;
+
+ /*
+ * Notes:
+ * - can't put all wrappers into an mscorlib class, because they reference
+ * metadata (signature) so they should be put into the same image as the
+ * method they wrap, so they are unloaded together.
+ * - putting them into a class with a type initalizer could cause the
+ * initializer to be executed which can be a problem if the wrappers are
+ * shared.
+ * - putting them into an inflated class can cause problems if the the
+ * class is deleted because it references an image which is unloaded.
+ * To avoid these problems, we put the wrappers into the <Module> class of
+ * the image.
+ */
+ if (image->dynamic)
+ klass = ((MonoDynamicImage*)image)->wrappers_type;
+ else
+ klass = mono_class_get (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1));
+ g_assert (klass);
+
+ return klass;
+}
+
+static void
+runtime_invoke_reset_abort (MonoException *ex)
+{
+ if (ex->object.vtable->klass == mono_defaults.threadabortexception_class)
+ ves_icall_System_Threading_Thread_ResetAbort ();
+}
+
/*
* generates IL code for the runtime invoke function
* MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
static MonoString *string_dummy = NULL;
static MonoMethodSignature *cctor_signature = NULL;
static MonoMethodSignature *finalize_signature = NULL;
- int i, pos, posna;
+ int i, pos;
char *name;
gboolean need_direct_wrapper = FALSE;
int *tmp_nullable_locals;
}
}
+#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
/*
* We try to share runtime invoke wrappers between different methods but have to
need_direct_wrapper = TRUE;
*/
- /*
- * Can't put these wrappers into object, since they reference non-corlib
- * metadata (callsig).
- */
- target_klass = method->klass;
+ target_klass = get_wrapper_target_class (method->klass->image);
}
}
break;
case MONO_TYPE_GENERICINST:
if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
- mono_mb_emit_byte (mb, CEE_LDIND_I);
+ mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
break;
}
g_assert_not_reached ();
}
-
switch (sig->ret->type) {
case MONO_TYPE_VOID:
if (!method->string_ctor)
/* nothing to do */
break;
case MONO_TYPE_PTR:
+ /* The result is an IntPtr */
+ mono_mb_emit_op (mb, CEE_BOX, mono_defaults.int_class);
+ break;
default:
g_assert_not_reached ();
}
mono_mb_emit_byte (mb, CEE_LDNULL);
mono_mb_emit_stloc (mb, 0);
- /* Check for the abort exception */
+ /* Check and reset abort exception */
+ /* Done in a separate function to reduce code size */
mono_mb_emit_ldloc (mb, 1);
- mono_mb_emit_op (mb, CEE_ISINST, mono_defaults.threadabortexception_class);
- posna = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+ mono_mb_emit_icall (mb, runtime_invoke_reset_abort);
- /* Delay the abort exception */
- mono_mb_emit_icall (mb, ves_icall_System_Threading_Thread_ResetAbort);
-
- mono_mb_patch_short_branch (mb, posna);
mono_mb_emit_branch (mb, CEE_LEAVE);
clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
return res;
}
-/*
- * mono_marshal_get_static_rgctx_invoke:
- * @method: a method
- *
- * Generates a wrapper for calling a generic shared method, either
- * static or generic. We need this for virtual generic method lookup
- * and ldftn when we do generic code sharing. Instead of producing
- * the address of the method we produce the address of a wrapper for
- * the method because the wrapper passes the (method) runtime generic
- * context argument which calli cannot do.
- */
-MonoMethod *
-mono_marshal_get_static_rgctx_invoke (MonoMethod *method)
-{
- static gboolean inited = FALSE;
- static int num_wrappers = 0;
-
- MonoMethodBuilder *mb;
- MonoMethod *res;
- MonoClass *target_klass = method->klass;
- MonoMethodSignature *sig = mono_method_signature (method);
- int i;
- char *name;
- GHashTable *cache;
- MonoImage *image = method->klass->image;
-
- 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_COUNTER_GENERICS | MONO_COUNTER_INT, &num_wrappers);
- inited = TRUE;
- }
- ++num_wrappers;
-
- name = mono_signature_to_name (mono_method_signature (method), "static_rgctx_invoke");
- mb = mono_mb_new (target_klass, name, MONO_WRAPPER_STATIC_RGCTX_INVOKE);
- g_free (name);
-
- for (i = 0; i < sig->param_count + sig->hasthis; i++)
- mono_mb_emit_ldarg (mb, i);
- mono_mb_emit_op (mb, CEE_CALL, method);
- mono_mb_emit_byte (mb, CEE_RET);
-
- mb->skip_visibility = TRUE;
- res = mono_mb_create_and_cache (cache, method, mb, mono_method_signature (method),
- sig->param_count + sig->hasthis + 4);
- res->flags = method->flags;
-
- mono_mb_free (mb);
-
- return res;
-}
-
static void
mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
{
mono_mb_patch_branch (mb, label1);
mono_mb_patch_branch (mb, label3);
}
+
+ if (klass->element_class->blittable) {
+ /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
+
+ mono_mb_emit_ldarg (mb, argnum);
+ mono_mb_emit_ldloc (mb, conv_arg);
+ mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
+ }
+
break;
case MARSHAL_ACTION_PUSH:
spec->native == MONO_NATIVE_IDISPATCH ||
spec->native == MONO_NATIVE_INTERFACE))
return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+ if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) &&
+ (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) &&
+ (action == MARSHAL_ACTION_CONV_OUT))
+ return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
#endif
if (mono_defaults.safehandle_class != NULL && t->data.klass &&
layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
/* The mempool is protected by the loader lock */
- info = mono_image_alloc0 (klass->image, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
+ info = mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
info->num_fields = count;
/* Try to find a size for this type in metadata */
/* dup & extend signature */
csig = mono_metadata_signature_alloc (image, param_count);
- sig_size = sizeof (MonoMethodSignature) + ((sig->param_count - MONO_ZERO_LEN_ARRAY) * sizeof (MonoType *));
+ sig_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
memcpy (csig, sig, sig_size);
csig->param_count = param_count;
csig->hasthis = 0;
g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method);
mono_marshal_unlock ();
}
+
+/*
+ * mono_marshal_free_inflated_wrappers:
+ *
+ * Free wrappers of the inflated method METHOD.
+ */
+
+static gboolean
+signature_method_pair_matches_signature (gpointer key, gpointer value, gpointer user_data)
+{
+ SignatureMethodPair *pair = (SignatureMethodPair*)key;
+ MonoMethodSignature *sig = (MonoMethodSignature*)user_data;
+
+ return mono_metadata_signature_equal (pair->sig, sig);
+}
+
+void
+mono_marshal_free_inflated_wrappers (MonoMethod *method)
+{
+ MonoMethodSignature *sig = method->signature;
+
+ g_assert (method->is_inflated);
+
+ /* Ignore calls occuring late during cleanup. */
+ if (!marshal_mutex_initialized)
+ return;
+
+ mono_marshal_lock ();
+ /*
+ * FIXME: We currently leak the wrappers. Freeing them would be tricky as
+ * they could be shared with other methods ?
+ */
+
+ /*
+ * indexed by MonoMethodSignature
+ */
+ /* FIXME: This could remove unrelated wrappers as well */
+ if (sig && method->klass->image->delegate_begin_invoke_cache)
+ g_hash_table_remove (method->klass->image->delegate_begin_invoke_cache, sig);
+ if (sig && method->klass->image->delegate_end_invoke_cache)
+ g_hash_table_remove (method->klass->image->delegate_end_invoke_cache, sig);
+ if (sig && method->klass->image->delegate_invoke_cache)
+ g_hash_table_remove (method->klass->image->delegate_invoke_cache, sig);
+ if (sig && method->klass->image->runtime_invoke_cache)
+ g_hash_table_remove (method->klass->image->runtime_invoke_cache, sig);
+
+ /*
+ * indexed by SignatureMethodPair
+ */
+ if (sig && method->klass->image->delegate_abstract_invoke_cache)
+ g_hash_table_foreach_remove (method->klass->image->delegate_abstract_invoke_cache,
+ signature_method_pair_matches_signature, (gpointer)sig);
+
+ /*
+ * indexed by MonoMethod pointers
+ */
+ if (method->klass->image->runtime_invoke_direct_cache)
+ g_hash_table_remove (method->klass->image->runtime_invoke_direct_cache, method);
+ if (method->klass->image->managed_wrapper_cache)
+ g_hash_table_remove (method->klass->image->managed_wrapper_cache, method);
+ if (method->klass->image->native_wrapper_cache)
+ g_hash_table_remove (method->klass->image->native_wrapper_cache, method);
+ if (method->klass->image->remoting_invoke_cache)
+ g_hash_table_remove (method->klass->image->remoting_invoke_cache, method);
+ if (method->klass->image->synchronized_cache)
+ g_hash_table_remove (method->klass->image->synchronized_cache, method);
+ if (method->klass->image->unbox_wrapper_cache)
+ g_hash_table_remove (method->klass->image->unbox_wrapper_cache, method);
+ if (method->klass->image->cominterop_invoke_cache)
+ g_hash_table_remove (method->klass->image->cominterop_invoke_cache, method);
+ if (method->klass->image->cominterop_wrapper_cache)
+ g_hash_table_remove (method->klass->image->cominterop_wrapper_cache, method);
+ if (method->klass->image->thunk_invoke_cache)
+ g_hash_table_remove (method->klass->image->thunk_invoke_cache, method);
+
+ mono_marshal_unlock ();
+}