X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fmarshal.c;h=09a493a41b2e6845edd54f48276a55d676bad919;hb=64e2556130a5220a09a770b85b442d0ff34bcbda;hp=34f0acc29115d2558ac90bdb81746f057ad86be7;hpb=ccad309cf0f05e28b5c00d3a9fc2b506a59ac411;p=mono.git diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 34f0acc2911..09a493a41b2 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" @@ -3832,7 +3837,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; @@ -4069,13 +4073,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; } @@ -4671,8 +4673,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 (); @@ -4690,8 +4692,8 @@ mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del) 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); @@ -4841,7 +4843,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) { MonoMethodSignature *sig, *csig, *callsig; MonoExceptionClause *clause; - MonoMethodHeader *header; MonoMethodBuilder *mb; GHashTable *cache = NULL; MonoClass *target_klass; @@ -4852,6 +4853,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) int i, pos, posna; char *name; gboolean need_direct_wrapper = FALSE; + int *tmp_nullable_locals; g_assert (method); @@ -4873,7 +4875,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method) 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)) { /* @@ -4902,6 +4904,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 @@ -5003,6 +5011,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; @@ -5015,6 +5025,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; } @@ -5123,6 +5143,26 @@ 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); @@ -5169,12 +5209,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 */ @@ -5205,10 +5248,6 @@ handle_enum: mono_mb_free (mb); - header = ((MonoMethodNormal *)res)->header; - header->num_clauses = 1; - header->clauses = clause; - return res; } @@ -5258,9 +5297,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); @@ -6059,7 +6098,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); @@ -8469,7 +8508,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); } @@ -9811,7 +9850,6 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method; MonoMethodSignature *sig; MonoExceptionClause *clause; - MonoMethodHeader *header; MonoMethodBuilder *mb; MonoMethod *res; GHashTable *cache; @@ -9861,6 +9899,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) mono_loader_unlock (); clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY; + mono_loader_lock (); + if (!enter_method) { MonoMethodDesc *desc; @@ -9880,6 +9920,8 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method) mono_method_desc_free (desc); } + mono_loader_unlock (); + /* Push this or the type object */ if (method->flags & METHOD_ATTRIBUTE_STATIC) { /* We have special handling for this in the JIT */ @@ -9928,14 +9970,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; } @@ -10284,46 +10324,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) { @@ -10734,6 +10734,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetIUnknownForObjectInternal (M if (!object) return NULL; + mono_init_com_types (); + if (cominterop_object_is_rcw (object)) { MonoClass *klass = NULL; MonoRealProxy* real_proxy = NULL; @@ -10794,6 +10796,8 @@ void* ves_icall_System_Runtime_InteropServices_Marshal_GetIDispatchForObjectInternal (MonoObject* object) { #ifndef DISABLE_COM + mono_init_com_types (); + return cominterop_get_idispatch_for_object (object); #else g_assert_not_reached (); @@ -11537,6 +11541,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; @@ -11581,7 +11587,7 @@ 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; } @@ -11921,10 +11927,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); @@ -12212,6 +12218,9 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) mspecs [0] = NULL; } + /* skip visiblity since we call internal methods */ + mb->skip_visibility = TRUE; + cominterop_setup_marshal_context (&m, adjust_method); m.mb = mb; mono_marshal_emit_managed_wrapper (mb, sig_adjusted, mspecs, &m, adjust_method, NULL); @@ -12221,9 +12230,6 @@ cominterop_get_ccw (MonoObject* object, MonoClass* itf) 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); @@ -12320,7 +12326,6 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) MonoMarshalSpec **mspecs; MonoMethodSignature *sig, *sig_native; MonoExceptionClause *main_clause = NULL; - MonoMethodHeader *header; int pos_leave; int hr = 0; int i; @@ -12395,6 +12400,8 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) main_clause->handler_len = mono_mb_get_pos (mb) - main_clause->handler_offset; /* end catch */ + mono_mb_set_clauses (mb, 1, main_clause); + mono_mb_patch_branch (mb, pos_leave); mono_mb_emit_ldloc (mb, hr); @@ -12415,12 +12422,6 @@ cominterop_get_managed_wrapper_adjusted (MonoMethod *method) 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; } @@ -12654,7 +12655,6 @@ mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method) MonoMethodBuilder *mb; MonoMethodSignature *sig, *csig; MonoExceptionClause *clause; - MonoMethodHeader *header; MonoImage *image; MonoClass *klass; GHashTable *cache; @@ -12773,6 +12773,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 */ @@ -12789,9 +12791,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 (); +}