Sat Jan 8 19:03:26 CET 2005 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / marshal.c
index e33175a53c59d33830cbc8f82c1f97a7926e417c..02e6fb9135b9db48354e56a4795b20f44619dc08 100644 (file)
@@ -89,7 +89,7 @@ static MonoDisHelper marshal_dh = {
 static CRITICAL_SECTION marshal_mutex;
 
 /* Maps wrapper methods to the methods they wrap */
-static MonoGHashTable *wrapper_hash;
+static GHashTable *wrapper_hash;
 
 static guint32 last_error_tls_id;
 
@@ -125,8 +125,7 @@ mono_marshal_init (void)
        if (!module_initialized) {
                module_initialized = TRUE;
                InitializeCriticalSection (&marshal_mutex);
-               MONO_GC_REGISTER_ROOT (wrapper_hash);
-               wrapper_hash = mono_g_hash_table_new (NULL, NULL);
+               wrapper_hash = g_hash_table_new (NULL, NULL);
                last_error_tls_id = TlsAlloc ();
 
                register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
@@ -629,7 +628,7 @@ mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
        mono_mb_emit_byte (mb, CEE_ADD);
        mono_mb_emit_byte (mb, CEE_LDIND_I);
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+       mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
        mono_mb_emit_byte (mb, branch_code);
        pos = mb->pos;
@@ -921,6 +920,12 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                mono_mb_emit_icall (mb, mono_string_new_wrapper);
                mono_mb_emit_byte (mb, CEE_STIND_I);            
                break;
+       case MONO_MARSHAL_CONV_STR_BYVALWSTR:
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_icall (mb, mono_string_from_utf16);
+               mono_mb_emit_byte (mb, CEE_STIND_I);            
+               break;          
        case MONO_MARSHAL_CONV_STR_LPTSTR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
                mono_mb_emit_byte (mb, CEE_LDLOC_1);
@@ -981,7 +986,6 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
        case MONO_MARSHAL_CONV_STR_ANSIBSTR:
        case MONO_MARSHAL_CONV_STR_TBSTR:
        case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
-       case MONO_MARSHAL_CONV_STR_BYVALWSTR: 
        default:
                g_warning ("marshaling conversion %d not implemented", conv);
                g_assert_not_reached ();
@@ -1228,7 +1232,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                        continue;
 
                ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
-                       
+
                if (last_field) {
                        msize = klass->instance_size - info->fields [i].field->offset;
                        usize = info->native_size - info->fields [i].offset;
@@ -1342,7 +1346,7 @@ emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
        /* Call DestroyStructure */
        /* FIXME: Only do this if needed */
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+       mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
        mono_mb_emit_ldloc (mb, struct_var);
        mono_mb_emit_icall (mb, mono_struct_delete_old);
@@ -1351,22 +1355,15 @@ emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
 static void
 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoint_func)
 {
-       static MonoMethodSignature *state_check_sig = NULL;
        int pos_noabort;
-       
-       if (!state_check_sig) {
-               state_check_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
-               state_check_sig->ret = &mono_defaults.void_class->byval_arg;
-               state_check_sig->pinvoke = 0;
-       }
-       
+
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
        mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, (gpointer) mono_thread_interruption_request_flag ()));
        mono_mb_emit_byte (mb, CEE_LDIND_I4);
        pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
-       mono_mb_emit_native_call (mb, state_check_sig, checkpoint_func);
+       mono_mb_emit_icall (mb, checkpoint_func);
        
        mono_mb_patch_addr (mb, pos_noabort, mb->pos - (pos_noabort + 4));
 }
@@ -1374,6 +1371,9 @@ emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoin
 static void
 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
 {
+       if (strstr (mb->method->name, "mono_thread_interruption_checkpoint"))
+               return;
+       
        emit_thread_interrupt_checkpoint_call (mb, mono_thread_interruption_checkpoint);
 }
 
@@ -1659,7 +1659,7 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key,
                /* This does not acquire any locks */
                res = mono_mb_create_method (mb, sig, max_stack);
                g_hash_table_insert (cache, key, res);
-               mono_g_hash_table_insert (wrapper_hash, res, key);
+               g_hash_table_insert (wrapper_hash, res, key);
        }
        LeaveCriticalSection (&marshal_mutex);
 
@@ -1716,7 +1716,7 @@ mono_remoting_mb_create_and_cache (MonoMethod *key, MonoMethodBuilder *mb,
        if (*res == NULL) {
                /* This does not acquire any locks */
                *res = mono_mb_create_method (mb, sig, max_stack);
-               mono_g_hash_table_insert (wrapper_hash, *res, key);
+               g_hash_table_insert (wrapper_hash, *res, key);
        }
 
        LeaveCriticalSection (&marshal_mutex);
@@ -1733,7 +1733,7 @@ mono_marshal_method_from_wrapper (MonoMethod *wrapper)
                return wrapper;
 
        EnterCriticalSection (&marshal_mutex);
-       res = mono_g_hash_table_lookup (wrapper_hash, wrapper);
+       res = g_hash_table_lookup (wrapper_hash, wrapper);
        LeaveCriticalSection (&marshal_mutex);
        return res;
 }
@@ -2287,7 +2287,7 @@ mono_marshal_supports_fast_xdomain (MonoMethod *method)
 }
 
 static gint32
-mono_marshal_set_domain_by_id (gint32 id)
+mono_marshal_set_domain_by_id (gint32 id, MonoBoolean push)
 {
        MonoDomain *current_domain = mono_domain_get ();
        MonoDomain *domain = mono_domain_get_by_id (id);
@@ -2295,6 +2295,11 @@ mono_marshal_set_domain_by_id (gint32 id)
        if (!domain || !mono_domain_set (domain, FALSE))        
                mono_raise_exception (mono_get_exception_appdomain_unloaded ());
 
+       if (push)
+               mono_thread_push_appdomain_ref (domain);
+       else
+               mono_thread_pop_appdomain_ref ();
+
        return current_domain->domain_id;
 }
 
@@ -2303,8 +2308,9 @@ mono_marshal_emit_switch_domain (MonoMethodBuilder *mb)
 {
        static MonoMethodSignature *csig = NULL;
        if (!csig) {
-               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
                csig->params [0] = &mono_defaults.int32_class->byval_arg;
+               csig->params [1] = &mono_defaults.int32_class->byval_arg;
                csig->ret = &mono_defaults.int32_class->byval_arg;
                csig->pinvoke = 1;
        }
@@ -2776,6 +2782,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method)
 
        mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoRealProxy, target_domain_id));
        mono_mb_emit_byte (mb, CEE_LDIND_I4);
+       mono_mb_emit_byte (mb, CEE_LDC_I4_1);
 
        /* switch domain */
 
@@ -2826,6 +2833,7 @@ mono_marshal_get_xappdomain_invoke (MonoMethod *method)
        /* Switch domain */
 
        mono_mb_emit_ldloc (mb, loc_old_domainid);
+       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
        mono_marshal_emit_switch_domain (mb);
        mono_mb_emit_byte (mb, CEE_POP);
        
@@ -2960,7 +2968,7 @@ mono_marshal_get_remoting_invoke_for_target (MonoMethod *method, MonoRemotingTar
                return mono_marshal_get_remoting_invoke (method);
 }
 
-static gpointer
+G_GNUC_UNUSED static gpointer
 mono_marshal_load_remoting_wrapper (MonoRealProxy *rp, MonoMethod *method)
 {
        if (rp->target_domain_id != -1)
@@ -3476,7 +3484,7 @@ handle_enum:
        if (!res) {
                res = mono_mb_create_method (mb, csig, sig->param_count + 16);
                g_hash_table_insert (cache, callsig, res);
-               mono_g_hash_table_insert (wrapper_hash, res, callsig);
+               g_hash_table_insert (wrapper_hash, res, callsig);
        }
 
        LeaveCriticalSection (&marshal_mutex);
@@ -3649,7 +3657,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                        if (klass->delegate) {
                                g_assert (!t->byref);
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-                               mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+                               mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
                                mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
                                mono_mb_emit_ldarg (mb, i);
                                mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
@@ -3938,8 +3946,10 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                case MONO_TYPE_VALUETYPE:
                        klass = sig->ret->data.klass;
                        if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                           klass->blittable || klass->enumtype)
+                           klass->blittable || klass->enumtype) {
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
                                break;
+                       }
                        
                        /* load pointer to returned value type */
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -5133,7 +5143,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        g_assert (!t->byref);
                        mono_mb_emit_byte (mb, CEE_STLOC_0);
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-                       mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+                       mono_mb_emit_byte (mb, CEE_MONO_CLASSCONST);
                        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
                        mono_mb_emit_byte (mb, CEE_LDLOC_0);
                        mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
@@ -6197,6 +6207,8 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
 
        g_assert (klass != NULL);
 
+       mono_marshal_load_type_info (klass);
+
        if (klass->str_to_ptr)
                return klass->str_to_ptr;
 
@@ -6260,6 +6272,8 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
 
        g_assert (klass != NULL);
 
+       mono_marshal_load_type_info (klass);
+
        if (klass->ptr_to_str)
                return klass->ptr_to_str;
 
@@ -6429,6 +6443,44 @@ mono_marshal_get_synchronized_wrapper (MonoMethod *method)
        return res;     
 }
 
+
+/*
+ * the returned method calls 'method' unboxing the this argument
+ */
+MonoMethod *
+mono_marshal_get_unbox_wrapper (MonoMethod *method)
+{
+       MonoMethodSignature *sig = method->signature;
+       int i;
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       GHashTable *cache;
+
+       cache = method->klass->image->unbox_wrapper_cache;
+       if ((res = mono_marshal_find_in_cache (cache, method)))
+               return res;
+
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNBOX);
+
+       g_assert (sig->hasthis);
+       
+       mono_mb_emit_ldarg (mb, 0); 
+       mono_mb_emit_icon (mb, sizeof (MonoObject));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       for (i = 0; i < sig->param_count; ++i)
+               mono_mb_emit_ldarg (mb, i + 1);
+       mono_mb_emit_managed_call (mb, method, NULL);
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       res = mono_mb_create_and_cache (cache, method,
+                                                                                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)); */
+
+       return res;     
+}
+
 MonoMethod*
 mono_marshal_get_stelemref ()
 {
@@ -6439,6 +6491,7 @@ mono_marshal_get_stelemref ()
        guint32 b1, b2, b3, b4;
        guint32 copy_pos;
        int aklass, vklass;
+       int array_slot_addr;
        
        if (ret)
                return ret;
@@ -6450,16 +6503,17 @@ mono_marshal_get_stelemref ()
 
        /* void stelemref (void* array, int idx, void* value) */
        sig->ret = &mono_defaults.void_class->byval_arg;
-       sig->params [0] = &mono_defaults.int_class->byval_arg;
+       sig->params [0] = &mono_defaults.object_class->byval_arg;
        sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
-       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       sig->params [2] = &mono_defaults.object_class->byval_arg;
                
        aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
        
        /*
        the method:
-       <check ABC>
+       <ldelema (bound check)>
        if (!value)
                goto store;
        
@@ -6473,7 +6527,7 @@ mono_marshal_get_stelemref ()
                goto long;
        
        store:
-               array [idx] = value;
+               *array_slot_addr = value;
                return;
        
        long:
@@ -6483,12 +6537,12 @@ mono_marshal_get_stelemref ()
                throw new ArrayTypeMismatchException ();
        */
        
-       /* ABC */
+       /* ldelema (implicit bound check) */
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_ldarg (mb, 1);
        mono_mb_emit_byte (mb, CEE_LDELEMA);
-       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.int_class));
-       mono_mb_emit_byte (mb, CEE_POP);
+       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.object_class));
+       mono_mb_emit_stloc (mb, array_slot_addr);
                
        /* if (!value) goto do_store */
        mono_mb_emit_ldarg (mb, 2);
@@ -6545,10 +6599,9 @@ mono_marshal_get_stelemref ()
        copy_pos = mb->pos;
        /* do_store */
        mono_mb_patch_addr (mb, b1, mb->pos - (b1 + 4));
-       mono_mb_emit_ldarg (mb, 0);
-       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldloc (mb, array_slot_addr);
        mono_mb_emit_ldarg (mb, 2);
-       mono_mb_emit_byte (mb, CEE_STELEM_I);
+       mono_mb_emit_byte (mb, CEE_STIND_REF);
        
        mono_mb_emit_byte (mb, CEE_RET);
        
@@ -7266,8 +7319,7 @@ mono_marshal_load_type_info (MonoClass* klass)
  */
 gint32
 mono_class_native_size (MonoClass *klass, guint32 *align)
-{
-       
+{      
        if (!klass->marshal_info)
                mono_marshal_load_type_info (klass);