X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=792a1dcf37eae662456b75b0dfa42202ec2db2b0;hb=30305335b8295bfb9426e95443ad2e32784c154f;hp=c7ea811accafaa6df3238554e43b0b60f1b2734b;hpb=b652b273afb68a13de795b298a792cae2953919d;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index c7ea811acca..792a1dcf37e 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -72,11 +72,12 @@ typedef struct _MonoRemotingMethods MonoRemotingMethods; /* * This mutex protects the various marshalling related caches in MonoImage * and a few other data structures static to this file. - * Note that when this lock is held it is not possible to take other runtime - * locks like the loader lock. + * + * The marshal lock is a non-recursive complex lock that sits below the domain lock in the + * runtime locking latice. Which means it can take simple locks suck as the image lock. */ -#define mono_marshal_lock() EnterCriticalSection (&marshal_mutex) -#define mono_marshal_unlock() LeaveCriticalSection (&marshal_mutex) +#define mono_marshal_lock() mono_locks_acquire (&marshal_mutex, MarshalLock) +#define mono_marshal_unlock() mono_locks_release (&marshal_mutex, MarshalLock) static CRITICAL_SECTION marshal_mutex; static gboolean marshal_mutex_initialized; @@ -98,7 +99,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje static void mono_struct_delete_old (MonoClass *klass, char *ptr); -void * +MONO_API void * mono_marshal_string_to_utf16 (MonoString *s); static void * @@ -150,7 +151,7 @@ mono_marshal_check_domain_image (gint32 domain_id, MonoImage *image); static MonoObject * mono_remoting_wrapper (MonoMethod *method, gpointer *params); -void +MONO_API void mono_upgrade_remote_class_wrapper (MonoReflectionType *rtype, MonoTransparentProxy *tproxy); #endif @@ -555,10 +556,13 @@ mono_delegate_free_ftnptr (MonoDelegate *delegate) if (ptr) { uint32_t gchandle; void **method_data; + MonoMethod *method; + 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; + method = mono_jit_info_get_method (ji); + method_data = ((MonoMethodWrapper*)method)->method_data; /*the target gchandle is the first entry after size and the wrapper itself.*/ gchandle = GPOINTER_TO_UINT (method_data [2]); @@ -566,7 +570,7 @@ mono_delegate_free_ftnptr (MonoDelegate *delegate) if (gchandle) mono_gchandle_free (gchandle); - mono_runtime_free_method (mono_object_domain (delegate), ji->method); + mono_runtime_free_method (mono_object_domain (delegate), method); } } @@ -4191,6 +4195,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) MonoGenericContext *ctx = NULL; MonoGenericContainer *container = NULL; MonoMethod *orig_method = NULL; + WrapperInfo *info; /* * If the delegate target is null, and the target method is not static, a virtual @@ -4221,8 +4226,9 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) closed_over_null = sig->param_count == mono_method_signature (del->method)->param_count; if (del && del->method && mono_method_signature (del->method)->param_count == sig->param_count + 1 && (del->method->flags & METHOD_ATTRIBUTE_STATIC)) { + g_assert (!callvirt); invoke_sig = mono_method_signature (del->method); - target_method = del->method; + target_method = NULL; static_method_with_first_arg_bound = TRUE; } @@ -4250,12 +4256,20 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx); if (res) return res; - } else if (callvirt || static_method_with_first_arg_bound) { + } else if (static_method_with_first_arg_bound) { + cache = get_cache (&method->klass->image->delegate_bound_static_invoke_cache, + (GHashFunc)mono_signature_hash, + (GCompareFunc)mono_metadata_signature_equal); + /* + * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig. + */ + res = mono_marshal_find_in_cache (cache, invoke_sig); + if (res) + return res; + } else if (callvirt) { GHashTable **cache_ptr; - if (static_method_with_first_arg_bound) - cache_ptr = &method->klass->image->delegate_bound_static_invoke_cache; - else - cache_ptr = &method->klass->image->delegate_abstract_invoke_cache; + + cache_ptr = &method->klass->image->delegate_abstract_invoke_cache; /* We need to cache the signature+method pair */ mono_marshal_lock (); @@ -4282,7 +4296,14 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (!static_method_with_first_arg_bound) invoke_sig = static_sig; - name = mono_signature_to_name (sig, "invoke"); + if (static_method_with_first_arg_bound) + name = mono_signature_to_name (invoke_sig, "invoke_bound"); + else if (closed_over_null) + name = mono_signature_to_name (invoke_sig, "invoke_closed_over_null"); + else if (callvirt) + name = mono_signature_to_name (invoke_sig, "invoke_callvirt"); + else + name = mono_signature_to_name (sig, "invoke"); if (ctx) mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_INVOKE); else @@ -4402,7 +4423,12 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16); res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx); - } else if (static_method_with_first_arg_bound || callvirt) { + } else if (static_method_with_first_arg_bound) { + res = mono_mb_create_and_cache (cache, invoke_sig, mb, sig, sig->param_count + 16); + + info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND); + mono_marshal_set_wrapper_info (res, info); + } else if (callvirt) { // From mono_mb_create_and_cache newm = mono_mb_create_method (mb, sig, sig->param_count + 16); /*We perform double checked locking, so must fence before publishing*/ @@ -4416,7 +4442,10 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) if (static_method_with_first_arg_bound) new_key->sig = signature_dup (del->method->klass->image, key.sig); g_hash_table_insert (cache, new_key, res); - mono_marshal_set_wrapper_info (res, new_key); + + info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL); + mono_marshal_set_wrapper_info (res, info); + mono_marshal_unlock (); } else { mono_marshal_unlock (); @@ -4424,6 +4453,9 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) } } else { res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16); + + info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_NONE); + mono_marshal_set_wrapper_info (res, info); } mono_mb_free (mb); @@ -4520,9 +4552,12 @@ mono_marshal_get_string_ctor_signature (MonoMethod *method) static MonoType* get_runtime_invoke_type (MonoType *t, gboolean ret) { - if (t->byref) + if (t->byref) { + if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) + return t; /* Can't share this with 'I' as that needs another indirection */ - return t; + return &mono_defaults.int_class->this_arg; + } if (MONO_TYPE_IS_REFERENCE (t)) return &mono_defaults.object_class->byval_arg; @@ -4941,20 +4976,10 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) /* 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) { - /* - * Valuetype methods receive a managed pointer as the this argument. - * Create a new signature to reflect this. - */ - callsig = signature_dup_add_this (method->klass->image, mono_method_signature (method), method->klass); - /* Can't share this as it would be shared with static methods taking an IntPtr argument */ - need_direct_wrapper = TRUE; - } else { - if (method->dynamic) - callsig = signature_dup (method->klass->image, mono_method_signature (method)); - else - callsig = mono_method_signature (method); - } + if (method->dynamic) + callsig = signature_dup (method->klass->image, mono_method_signature (method)); + else + callsig = mono_method_signature (method); } target_klass = get_wrapper_target_class (method->klass->image); @@ -4975,9 +5000,15 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) 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); + if (method->klass->valuetype && mono_method_signature (method)->hasthis) + /* These have a different csig */ + cache = get_cache (&target_klass->image->runtime_invoke_vtype_cache, + (GHashFunc)mono_signature_hash, + (GCompareFunc)runtime_invoke_signature_equal); + else + 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 (); @@ -5001,7 +5032,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual) csig->ret = &mono_defaults.object_class->byval_arg; if (method->klass->valuetype && mono_method_signature (method)->hasthis) - csig->params [0] = callsig->params [0]; + csig->params [0] = get_runtime_invoke_type (&method->klass->this_arg, FALSE); else csig->params [0] = &mono_defaults.object_class->byval_arg; csig->params [1] = &mono_defaults.int_class->byval_arg; @@ -5183,14 +5214,14 @@ mono_marshal_get_runtime_invoke_dynamic (void) mono_mb_emit_byte (mb, CEE_RET); #endif /* DISABLE_JIT */ - mono_loader_lock (); + mono_marshal_lock (); /* double-checked locking */ if (!method) { method = mono_mb_create_method (mb, csig, 16); info = mono_wrapper_info_create (method, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC); mono_marshal_set_wrapper_info (method, info); } - mono_loader_unlock (); + mono_marshal_unlock (); mono_mb_free (mb); @@ -6412,6 +6443,9 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t, break; } + if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT)) + break; + /* Check for null */ mono_mb_emit_ldarg (mb, argnum); pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE); @@ -6929,7 +6963,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t, } #endif - if (t->byref && !t->attrs & PARAM_ATTRIBUTE_IN && t->attrs & PARAM_ATTRIBUTE_OUT) + if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT)) break; if (conv == -1) { @@ -8851,13 +8885,14 @@ mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, pinvoke = TRUE; if (!piinfo->addr) { - if (pinvoke) + if (pinvoke) { if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE) exc_arg = "Method contains unsupported native code"; - else + else if (!aot) mono_lookup_pinvoke_call (method, &exc_class, &exc_arg); - else + } else { piinfo->addr = mono_lookup_internal_call (method); + } } /* hack - redirect certain string constructors to CreateString */ @@ -9168,6 +9203,16 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN); } } + + if (!sig->ret->byref) { + switch (sig->ret->type) { + case MONO_TYPE_STRING: + csig->ret = &mono_defaults.int_class->byval_arg; + break; + default: + break; + } + } #else MonoMethodSignature *sig, *csig; int i, *tmp_locals; @@ -9483,9 +9528,10 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoBoolean set_last_error = 0; MonoBoolean best_fit_mapping = 0; MonoBoolean throw_on_unmappable = 0; + MonoError error; - mono_reflection_create_custom_attr_data_args (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo); - + mono_reflection_create_custom_attr_data_args (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, &error); + g_assert (mono_error_ok (&error)); g_assert (mono_array_length (typed_args) == 1); /* typed args */ @@ -9614,8 +9660,8 @@ mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type) sig = mono_method_signature (method); mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED); -#ifndef DISABLE_JIT param_count = sig->param_count + sig->hasthis; +#ifndef DISABLE_JIT for (i = 0; i < param_count; i++) mono_mb_emit_ldarg (mb, i); @@ -10421,7 +10467,7 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY; #endif - mono_loader_lock (); + mono_marshal_lock (); if (!enter_method) { MonoMethodDesc *desc; @@ -10437,12 +10483,12 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *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); + gettypefromhandle_method = mono_method_desc_search_in_class (desc, mono_defaults.systemtype_class); g_assert (gettypefromhandle_method); mono_method_desc_free (desc); } - mono_loader_unlock (); + mono_marshal_unlock (); #ifndef DISABLE_JIT /* Push this or the type object */ @@ -11464,6 +11510,76 @@ mono_marshal_get_array_address (int rank, int elem_size) return ret; } +/* + * mono_marshal_get_array_accessor_wrapper: + * + * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method. + */ +MonoMethod * +mono_marshal_get_array_accessor_wrapper (MonoMethod *method) +{ + MonoMethodSignature *sig; + MonoMethodBuilder *mb; + MonoMethod *res; + GHashTable *cache; + int i; + MonoGenericContext *ctx = NULL; + MonoMethod *orig_method = NULL; + MonoGenericContainer *container = NULL; + WrapperInfo *info; + + /* + * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics + * inside runtime invoke wrappers, thereby making the wrappers not unshareable. + * FIXME: Use generic methods. + */ + /* + * Check cache + */ + if (ctx) { + cache = NULL; + g_assert_not_reached (); + } else { + cache = get_cache (&method->klass->image->array_accessor_cache, mono_aligned_addr_hash, NULL); + if ((res = mono_marshal_find_in_cache (cache, method))) + return res; + } + + sig = signature_dup (method->klass->image, mono_method_signature (method)); + sig->pinvoke = 0; + + mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNKNOWN); + +#ifndef DISABLE_JIT + /* Call the method */ + if (sig->hasthis) + mono_mb_emit_ldarg (mb, 0); + for (i = 0; i < sig->param_count; i++) + mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE)); + + if (ctx) + mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method (method, &container->context), NULL); + else + mono_mb_emit_managed_call (mb, method, NULL); + mono_mb_emit_byte (mb, CEE_RET); +#endif + + if (ctx) { + MonoMethod *def; + def = mono_mb_create_and_cache (cache, method, mb, sig, sig->param_count + 16); + res = cache_generic_wrapper (cache, orig_method, def, ctx, orig_method); + } else { + res = mono_mb_create_and_cache (cache, method, + mb, sig, sig->param_count + 16); + info = mono_wrapper_info_create (res, WRAPPER_SUBTYPE_ARRAY_ACCESSOR); + info->d.array_accessor.method = method; + mono_marshal_set_wrapper_info (res, info); + } + mono_mb_free (mb); + + return res; +} + void* mono_marshal_alloc (gulong size) { @@ -11569,7 +11685,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *s element_size = mono_array_element_size (src->obj.vtable->klass); /* no references should be involved */ - source_addr = mono_array_addr_with_size (src, element_size, start_index); + source_addr = mono_array_addr_with_size_fast (src, element_size, start_index); memcpy (dest, source_addr, length * element_size); } @@ -11598,7 +11714,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer s element_size = mono_array_element_size (dest->obj.vtable->klass); /* no references should be involved */ - dest_addr = mono_array_addr_with_size (dest, element_size, start_index); + dest_addr = mono_array_addr_with_size_fast (dest, element_size, start_index); memcpy (dest_addr, src, length * element_size); } @@ -11688,7 +11804,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty layout = (klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK); - if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { + if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) { + return sizeof (gpointer); + } else if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) { gchar *msg; MonoException *exc; @@ -12046,7 +12164,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, void* ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index) { - return mono_array_addr_with_size (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index); + return mono_array_addr_with_size_fast (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index); } MonoDelegate* @@ -12101,12 +12219,8 @@ mono_marshal_load_type_info (MonoClass* klass) if (!klass->inited) mono_class_init (klass); - mono_loader_lock (); - - if (klass->marshal_info) { - mono_loader_unlock (); + if (klass->marshal_info) return klass->marshal_info; - } /* * This function can recursively call itself, so we keep the list of classes which are @@ -12182,7 +12296,7 @@ mono_marshal_load_type_info (MonoClass* klass) case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT: size = mono_marshal_type_size (field->type, info->fields [j].mspec, &align, TRUE, klass->unicode); - min_align = packing; + min_align = MAX (align, min_align); info->fields [j].offset = field->offset - sizeof (MonoObject); info->native_size = MAX (info->native_size, info->fields [j].offset + size); break; @@ -12196,9 +12310,12 @@ mono_marshal_load_type_info (MonoClass* klass) * If the provided Size is equal or larger than the calculated size, and there * was no Pack attribute, we set min_align to 1 to avoid native_size being increased */ - if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) + if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) { if (native_size && native_size == info->native_size && klass->packing_size == 0) min_align = 1; + else + min_align = MIN (min_align, packing); + } } if (info->native_size & (min_align - 1)) { @@ -12221,12 +12338,13 @@ mono_marshal_load_type_info (MonoClass* klass) loads_list = g_slist_remove (loads_list, klass); mono_native_tls_set_value (load_type_info_tls_id, loads_list); - /*We do double-checking locking on marshal_info */ - mono_memory_barrier (); - - klass->marshal_info = info; - - mono_loader_unlock (); + mono_marshal_lock (); + if (!klass->marshal_info) { + /*We do double-checking locking on marshal_info */ + mono_memory_barrier (); + klass->marshal_info = info; + } + mono_marshal_unlock (); return klass->marshal_info; } @@ -12835,8 +12953,6 @@ mono_marshal_free_dynamic_wrappers (MonoMethod *method) */ if (image->runtime_invoke_direct_cache) g_hash_table_remove (image->runtime_invoke_direct_cache, method); - if (image->delegate_bound_static_invoke_cache) - g_hash_table_foreach_remove (image->delegate_bound_static_invoke_cache, signature_method_pair_matches_method, method); if (image->delegate_abstract_invoke_cache) g_hash_table_foreach_remove (image->delegate_abstract_invoke_cache, signature_method_pair_matches_method, method); @@ -12887,6 +13003,8 @@ mono_marshal_free_inflated_wrappers (MonoMethod *method) 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); + if (sig && method->klass->image->runtime_invoke_vtype_cache) + g_hash_table_remove (method->klass->image->runtime_invoke_vtype_cache, sig); /* * indexed by SignatureMethodPair @@ -12895,10 +13013,6 @@ mono_marshal_free_inflated_wrappers (MonoMethod *method) g_hash_table_foreach_remove (method->klass->image->delegate_abstract_invoke_cache, signature_method_pair_matches_signature, (gpointer)sig); - if (sig && method->klass->image->delegate_bound_static_invoke_cache) - g_hash_table_foreach_remove (method->klass->image->delegate_bound_static_invoke_cache, - signature_method_pair_matches_signature, (gpointer)sig); - /* * indexed by MonoMethod pointers */