2003-04-24 Martin Baulig <martin@ximian.com>
[mono.git] / mono / metadata / marshal.c
index b4b2374dc30b0fc2e13223c2b4406f114ffd5af9..fbe0ae5930a2257635e2e0d1bd05beabdcdd5b08 100644 (file)
@@ -17,6 +17,7 @@
 #include "metadata/appdomain.h"
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/threadpool.h"
+#include "mono/metadata/monitor.h"
 #include <string.h>
 
 //#define DEBUG_RUNTIME_CODE
@@ -167,10 +168,10 @@ mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
        g_assert (dst != NULL);
        g_assert (size > 0);
 
-       if (!src) {
-               memset (dst, 0, size);
+       memset (dst, 0, size);
+       
+       if (!src)
                return;
-       }
 
        s = mono_string_to_utf8 (src);
        len = MIN (size, strlen (s));
@@ -344,8 +345,29 @@ mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
 {
         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
-        mono_mb_emit_icon (mb, offset);
-        mono_mb_emit_byte (mb, CEE_ADD);
+
+       if (offset) {
+               mono_mb_emit_icon (mb, offset);
+               mono_mb_emit_byte (mb, CEE_ADD);
+       }
+}
+
+static int
+mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
+{
+       int pos;
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
+       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_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
+       mono_mb_emit_byte (mb, branch_code);
+       pos = mb->pos;
+       mono_mb_emit_i4 (mb, 0);
+       return pos;
 }
 
 void
@@ -1271,6 +1293,28 @@ mono_remoting_wrapper (MonoMethod *method, gpointer *params)
        /* skip the this pointer */
        params++;
 
+       if (this->klass->contextbound && this->rp->context == (MonoObject *) mono_context_get ())
+       {
+               int i;
+               MonoMethodSignature *sig = method->signature;
+               int count = sig->param_count;
+               gpointer mparams[count];
+
+               for (i=0; i<count; i++) {
+                       MonoClass *class = mono_class_from_mono_type (sig->params [i]);
+                       if (class->valuetype) {
+                               if (sig->params [i]->byref)
+                                       mparams[i] = *((gpointer *)params [i]);
+                               else 
+                                       mparams[i] = params [i];
+                       } else {
+                               mparams[i] = *((gpointer**)params [i]);
+                       }
+               }
+
+               return mono_runtime_invoke (method, this->rp->unwrapped_server, mparams, NULL);
+       }
+
        msg = mono_method_call_message_new (method, params, NULL, NULL, NULL);
 
        res = mono_remoting_invoke ((MonoObject *)this->rp, msg, &exc, &out_args);
@@ -1309,14 +1353,11 @@ mono_marshal_get_remoting_invoke (MonoMethod *method)
                return res;
 
        if (!csig) {
-               int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
-               csig = g_malloc0 (sigsize);
-
-               /* MonoObject *remoting_wrapper (MonoMethod *method, gpointer params[]) */
-               csig->param_count = 2;
-               csig->ret = &mono_defaults.object_class->byval_arg;
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
                csig->params [0] = &mono_defaults.int_class->byval_arg;
                csig->params [1] = &mono_defaults.int_class->byval_arg;
+               csig->ret = &mono_defaults.object_class->byval_arg;
+               csig->pinvoke = 1;
        }
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
@@ -1330,10 +1371,12 @@ mono_marshal_get_remoting_invoke (MonoMethod *method)
        mono_mb_emit_ldloc (mb, params_var);
        mono_mb_emit_native_call (mb, csig, mono_remoting_wrapper);
 
-       if (sig->ret->type == MONO_TYPE_VOID)
+       if (sig->ret->type == MONO_TYPE_VOID) {
                mono_mb_emit_byte (mb, CEE_POP);
-       else
-               mono_mb_emit_restore_result (mb, sig->ret);
+               mono_mb_emit_byte (mb, CEE_RET);
+       } else {
+                mono_mb_emit_restore_result (mb, sig->ret);
+       }
 
        res = mono_mb_create_method (mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
@@ -1341,6 +1384,56 @@ mono_marshal_get_remoting_invoke (MonoMethod *method)
        return res;
 }
 
+MonoMethod *
+mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
+{
+       MonoMethodSignature *sig;
+       MonoMethodBuilder *mb;
+       MonoMethod *res, *native;
+       GHashTable *cache;
+       int i, pos;
+
+       g_assert (method);
+
+       if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+               return method;
+
+       sig = method->signature;
+
+       /* we cant remote methods without this pointer */
+       g_assert (sig->hasthis);
+
+       cache = method->klass->image->remoting_invoke_cache;
+       if ((res = (MonoMethod *)g_hash_table_lookup (cache, (char *)method + 1)))
+               return res;
+
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
+
+       mono_mb_emit_ldarg (mb, 0);
+       pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
+
+       native = mono_marshal_get_remoting_invoke (method);
+
+       for (i = 0; i <= sig->param_count; i++)
+               mono_mb_emit_ldarg (mb, i);
+       
+       mono_mb_emit_managed_call (mb, native, native->signature);
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+
+       for (i = 0; i <= sig->param_count; i++)
+               mono_mb_emit_ldarg (mb, i);
+               
+       mono_mb_emit_managed_call (mb, method, method->signature);
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+       g_hash_table_insert (cache, (char *)method + 1, res);
+       return res;
+}
+
 /*
  * the returned method invokes all methods in a multicast delegate 
  */
@@ -1716,6 +1809,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        int i, pos, sigsize, *tmp_locals;
 
        g_assert (method != NULL);
+       g_assert (!method->signature->pinvoke);
 
        cache = method->klass->image->managed_wrapper_cache;
        if (!this && (res = (MonoMethod *)g_hash_table_lookup (cache, method)))
@@ -1903,6 +1997,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                case MONO_TYPE_R8:
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
+               case MONO_TYPE_OBJECT:
                        mono_mb_emit_byte (mb, CEE_RET);
                        break;
                case MONO_TYPE_STRING:          
@@ -1962,18 +2057,328 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        return res;
 }
 
+/*
+ * mono_marshal_get_ldfld_wrapper:
+ * @type: the type of the field
+ *
+ * This method generates a function which can be use to load a field with type
+ * @type from an object. The generated function has the following signature:
+ * <@type> ldfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset)
+ */
+MonoMethod *
+mono_marshal_get_ldfld_wrapper (MonoType *type)
+{
+       MonoMethodSignature *sig, *csig;
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       MonoClass *klass;
+       static GHashTable *ldfld_hash = NULL; 
+       char *name;
+       int t, pos0, pos1;
+
+       if (!ldfld_hash) 
+               ldfld_hash = g_hash_table_new (NULL, NULL);
+
+
+       t = type->type;
+
+       if (!type->byref) {
+               if (type->type == MONO_TYPE_SZARRAY) {
+                       klass = mono_defaults.array_class;
+               } else if (type->type == MONO_TYPE_VALUETYPE) {
+                       klass = type->data.klass;
+                       if (klass->enumtype) {
+                               t = klass->enum_basetype->type;
+                               klass = mono_class_from_mono_type (klass->enum_basetype);
+                       }
+               } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
+                          t == MONO_TYPE_CLASS) { 
+                       klass = mono_defaults.object_class;
+               } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
+                       klass = mono_defaults.int_class;
+               } else {
+                       klass = mono_class_from_mono_type (type);                       
+               }
+       } else {
+               klass = mono_defaults.int_class;
+       }
+
+       if ((res = g_hash_table_lookup (ldfld_hash, klass)))
+               return res;
+
+       name = g_strdup_printf ("__ldfld_wrapper_%s.%s", klass->name_space, klass->name); 
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
+       g_free (name);
+
+       mb->method->save_lmf = 1;
+
+       sig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
+       sig->params [0] = &mono_defaults.object_class->byval_arg;
+       sig->params [1] = &mono_defaults.int_class->byval_arg;
+       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       sig->params [3] = &mono_defaults.int_class->byval_arg;
+       sig->ret = &klass->byval_arg;
+
+       mono_mb_emit_ldarg (mb, 0);
+       pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
+
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
+
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
+       csig->params [0] = &mono_defaults.object_class->byval_arg;
+       csig->params [1] = &mono_defaults.int_class->byval_arg;
+       csig->params [2] = &mono_defaults.int_class->byval_arg;
+       csig->ret = &klass->this_arg;
+       csig->pinvoke = 1;
+
+       mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
+
+       if (klass->valuetype) {
+               mono_mb_emit_byte (mb, CEE_UNBOX);
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));             
+               mono_mb_emit_byte (mb, CEE_BR);
+               pos1 = mb->pos;
+               mono_mb_emit_i4 (mb, 0);
+       } else {
+               mono_mb_emit_byte (mb, CEE_RET);
+       }
+
+
+       mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
+
+       mono_mb_emit_ldarg (mb, 0);
+        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+        mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+       mono_mb_emit_ldarg (mb, 3);
+       mono_mb_emit_byte (mb, CEE_ADD);
+
+       if (klass->valuetype)
+               mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
+
+       switch (t) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+               mono_mb_emit_byte (mb, CEE_LDIND_I1);
+               break;
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+               mono_mb_emit_byte (mb, CEE_LDIND_I2);
+               break;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+               mono_mb_emit_byte (mb, CEE_LDIND_I4);
+               break;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               mono_mb_emit_byte (mb, CEE_LDIND_I8);
+               break;
+       case MONO_TYPE_R4:
+               mono_mb_emit_byte (mb, CEE_LDIND_R4);
+               break;
+       case MONO_TYPE_R8:
+               mono_mb_emit_byte (mb, CEE_LDIND_R8);
+               break;
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               break;
+       case MONO_TYPE_VALUETYPE:
+               g_assert (!klass->enumtype);
+               mono_mb_emit_byte (mb, CEE_LDOBJ);
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
+               break;
+       default:
+               g_warning ("type %x not implemented", type->type);
+               g_assert_not_reached ();
+       }
+
+       mono_mb_emit_byte (mb, CEE_RET);
+       
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+       
+       g_hash_table_insert (ldfld_hash, klass, res);
+
+       return res;
+}
+
+/*
+ * mono_marshal_get_stfld_wrapper:
+ * @type: the type of the field
+ *
+ * This method generates a function which can be use to store a field with type
+ * @type. The generated function has the following signature:
+ * void stfld_wrapper (MonoObject *this, MonoClass *class, MonoClassField *field, int offset, <@type> val)
+ */
+MonoMethod *
+mono_marshal_get_stfld_wrapper (MonoType *type)
+{
+       MonoMethodSignature *sig, *csig;
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       MonoClass *klass;
+       static GHashTable *stfld_hash = NULL; 
+       char *name;
+       int t, pos;
+
+       if (!stfld_hash) 
+               stfld_hash = g_hash_table_new (NULL, NULL);
+
+       t = type->type;
+
+       if (!type->byref) {
+               if (type->type == MONO_TYPE_SZARRAY) {
+                       klass = mono_defaults.array_class;
+               } else if (type->type == MONO_TYPE_VALUETYPE) {
+                       klass = type->data.klass;
+                       if (klass->enumtype) {
+                               t = klass->enum_basetype->type;
+                               klass = mono_class_from_mono_type (klass->enum_basetype);
+                       }
+               } else if (t == MONO_TYPE_OBJECT || t == MONO_TYPE_CLASS || t == MONO_TYPE_STRING ||
+                          t == MONO_TYPE_CLASS) { 
+                       klass = mono_defaults.object_class;
+               } else if (t == MONO_TYPE_PTR || t == MONO_TYPE_FNPTR) {
+                       klass = mono_defaults.int_class;
+               } else {
+                       klass = mono_class_from_mono_type (type);                       
+               }
+       } else {
+               klass = mono_defaults.int_class;
+       }
+
+       if ((res = g_hash_table_lookup (stfld_hash, klass)))
+               return res;
+
+       name = g_strdup_printf ("__stfld_wrapper_%s.%s", klass->name_space, klass->name); 
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STFLD);
+       g_free (name);
+
+       mb->method->save_lmf = 1;
+
+       sig = mono_metadata_signature_alloc (mono_defaults.corlib, 5);
+       sig->params [0] = &mono_defaults.object_class->byval_arg;
+       sig->params [1] = &mono_defaults.int_class->byval_arg;
+       sig->params [2] = &mono_defaults.int_class->byval_arg;
+       sig->params [3] = &mono_defaults.int_class->byval_arg;
+       sig->params [4] = &klass->byval_arg;
+       sig->ret = &mono_defaults.void_class->byval_arg;
+
+       mono_mb_emit_ldarg (mb, 0);
+       pos = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
+
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
+       mono_mb_emit_ldarg (mb, 4);
+
+       if (klass->valuetype) {
+               mono_mb_emit_byte (mb, CEE_BOX);
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));             
+       }
+
+       csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
+       csig->params [0] = &mono_defaults.object_class->byval_arg;
+       csig->params [1] = &mono_defaults.int_class->byval_arg;
+       csig->params [2] = &mono_defaults.int_class->byval_arg;
+       csig->params [3] = &klass->this_arg;
+       csig->ret = &mono_defaults.void_class->byval_arg;
+       csig->pinvoke = 1;
+
+       mono_mb_emit_native_call (mb, csig, mono_store_remote_field_new);
+
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+
+       mono_mb_emit_ldarg (mb, 0);
+        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+        mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+       mono_mb_emit_ldarg (mb, 3);
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_ldarg (mb, 4);
+
+       switch (t) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+               break;
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+               mono_mb_emit_byte (mb, CEE_STIND_I2);
+               break;
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+               mono_mb_emit_byte (mb, CEE_STIND_I4);
+               break;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               mono_mb_emit_byte (mb, CEE_STIND_I8);
+               break;
+       case MONO_TYPE_R4:
+               mono_mb_emit_byte (mb, CEE_STIND_R4);
+               break;
+       case MONO_TYPE_R8:
+               mono_mb_emit_byte (mb, CEE_STIND_R8);
+               break;
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+               break;
+       case MONO_TYPE_VALUETYPE:
+               g_assert (!klass->enumtype);
+               mono_mb_emit_byte (mb, CEE_STOBJ);
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
+               break;
+       default:
+               g_warning ("type %x not implemented", type->type);
+               g_assert_not_reached ();
+       }
+
+       mono_mb_emit_byte (mb, CEE_RET);
+       
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+       
+       g_hash_table_insert (stfld_hash, klass, res);
+
+       return res;
+}
+
 /*
  * generates IL code for the icall wrapper (the generated method
  * calls the unamnaged code in func)
  */
 MonoMethod *
-mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gpointer func)
+mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func)
 {
        MonoMethodSignature *csig;
        MonoMethodBuilder *mb;
        MonoMethod *res;
        int i, sigsize;
 
+       g_assert (sig->pinvoke);
+
        mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
 
        mb->method->save_lmf = 1;
@@ -1987,13 +2392,13 @@ mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gpoi
        for (i = 0; i < sig->param_count; i++)
                mono_mb_emit_ldarg (mb, i + sig->hasthis);
 
-       csig = g_memdup (sig, sigsize);
-       csig->pinvoke = 1;
-
-       mono_mb_emit_native_call (mb, csig, func);
+       mono_mb_emit_native_call (mb, sig, (gpointer) func);
 
        mono_mb_emit_byte (mb, CEE_RET);
 
+       csig = g_memdup (sig, sigsize);
+       csig->pinvoke = 0;
+
        res = mono_mb_create_method (mb, csig, csig->param_count + 16);
        mono_mb_free (mb);
        
@@ -2018,12 +2423,14 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        int type, sigsize;
 
        g_assert (method != NULL);
+       g_assert (method->signature->pinvoke);
 
        cache = method->klass->image->native_wrapper_cache;
        if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
                return res;
 
        sig = method->signature;
+       sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
 
        if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
            (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
@@ -2038,20 +2445,17 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
        if (!method->addr) {
                mono_mb_emit_exception (mb);
-               res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+               csig = g_memdup (sig, sigsize);
+               csig->pinvoke = 0;
+               res = mono_mb_create_method (mb, csig, csig->param_count + 16);
                mono_mb_free (mb);
                g_hash_table_insert (cache, method, res);
                return res;
        }
 
-       /* we copy the signature, so that we can modify it */
-       sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
-
        /* internal calls: we simply push all arguments and call the method (no conversions) */
        if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
 
-               MonoMethodSignature *call_sig;
-
                /* hack - string constructors returns a value */
                if (method->string_ctor) {
                        csig = g_memdup (sig, sigsize);
@@ -2065,15 +2469,14 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                for (i = 0; i < sig->param_count; i++)
                        mono_mb_emit_ldarg (mb, i + sig->hasthis);
 
-               call_sig = g_memdup (csig, sigsize);
-               call_sig->pinvoke = 1;
-
                g_assert (method->addr);
-               mono_mb_emit_native_call (mb, call_sig, method->addr);
+               mono_mb_emit_native_call (mb, csig, method->addr);
 
                mono_mb_emit_byte (mb, CEE_RET);
 
-               res = mono_mb_create_method (mb, csig, sig->param_count + 16);
+               csig = g_memdup (csig, sigsize);
+               csig->pinvoke = 0;
+               res = mono_mb_create_method (mb, csig, csig->param_count + 16);
                mono_mb_free (mb);
                g_hash_table_insert (cache, method, res);
                return res;
@@ -2081,11 +2484,12 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
        g_assert (pinvoke);
 
-       mspecs = g_new (MonoMarshalSpec, sig->param_count + 1);
+       mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
        mono_method_get_marshal_info (method, mspecs);
 
        /* pinvoke: we need to convert the arguments if necessary */
 
+       /* we copy the signature, so that we can set pinvoke to 0 */
        csig = g_memdup (sig, sigsize);
        csig->pinvoke = 1;
 
@@ -2173,8 +2577,11 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                case MONO_NATIVE_LPWSTR:
                                        mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPWSTR);
                                        break;
+                               case MONO_NATIVE_LPSTR:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                                       break;
                                default:
-                                       g_warning ("marshalling conversion not implemented");
+                                       g_warning ("marshalling conversion %d not implemented", spec->native);
                                        g_assert_not_reached ();
                                }
                        } else {
@@ -2184,7 +2591,6 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                        mono_mb_emit_stloc (mb, tmp_locals [i]);
                        break;
                case MONO_TYPE_CLASS:
-               case MONO_TYPE_OBJECT:
                        if (t->byref)
                                continue;
 
@@ -2211,6 +2617,21 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                mono_mb_emit_stloc (mb, tmp_locals [i]);
                        }
 
+                       break;
+               case MONO_TYPE_OBJECT:
+                       if (t->byref)
+                               continue;
+                       csig->params [argnum] = &mono_defaults.int_class->byval_arg;
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       /* 
+                        * FIXME: this may need special handling to inspect the type
+                        * at runtime.
+                        */
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+                       /* fixme: convert to what ? */
+                       mono_mb_emit_stloc (mb, tmp_locals [i]);
                        break;
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
@@ -2493,7 +2914,9 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       csig = g_memdup (sig, sigsize);
+       csig->pinvoke = 0;
+       res = mono_mb_create_method (mb, csig, csig->param_count + 16);
        mono_mb_free (mb);
 
        g_hash_table_insert (cache, method, res);
@@ -2529,8 +2952,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
        if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
                mono_mb_emit_byte (mb, CEE_LDARG_1);
                mono_mb_emit_byte (mb, CEE_LDARG_0);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_CPBLK);
@@ -2547,8 +2969,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
 
                /* initialize src_ptr to point to the start of object data */
                mono_mb_emit_byte (mb, CEE_LDARG_0);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_byte (mb, CEE_STLOC_0);
 
                /* initialize dst_ptr */
@@ -2590,8 +3011,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
 
        if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
                mono_mb_emit_byte (mb, CEE_LDARG_1);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_byte (mb, CEE_LDARG_0);
                mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_PREFIX1);
@@ -2609,8 +3029,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
 
                /* initialize dst_ptr */
                mono_mb_emit_byte (mb, CEE_LDARG_1);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_byte (mb, CEE_STLOC_1);
 
                emit_struct_conv (mb, klass, TRUE);
@@ -2625,6 +3044,138 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
        return res;
 }
 
+static MonoReflectionType *
+type_from_handle (MonoType *handle)
+{
+       MonoDomain *domain = mono_domain_get (); 
+       MonoClass *klass = mono_class_from_mono_type (handle);
+
+       MONO_ARCH_SAVE_REGS;
+
+       mono_class_init (klass);
+       return mono_type_get_object (domain, handle);
+}
+
+/*
+ * generates IL code for the synchronized wrapper: the generated method
+ * calls METHOD while locking 'this' or the parent type.
+ */
+MonoMethod *
+mono_marshal_get_synchronized_wrapper (MonoMethod *method)
+{
+       static MonoMethodSignature *from_handle_sig = NULL;
+       static MonoMethod *enter_method, *exit_method;
+       MonoMethodSignature *sig;
+       MonoExceptionClause *clause;
+       MonoMethodHeader *header;
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       GHashTable *cache;
+       int i, pos, this_local, ret_local;
+
+       g_assert (method);
+
+       if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
+               return method;
+
+       cache = method->klass->image->synchronized_cache;
+       if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+               return res;
+
+       sig = method->signature;
+
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
+
+       /* result */
+       if (!MONO_TYPE_IS_VOID (sig->ret))
+               ret_local = mono_mb_add_local (mb, sig->ret);
+
+       /* this */
+       this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+       clause = g_new0 (MonoExceptionClause, 1);
+       clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
+
+       if (!enter_method) {
+               MonoMethodDesc *desc;
+
+               desc = mono_method_desc_new ("Monitor:Enter", FALSE);
+               enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
+               g_assert (enter_method);
+               mono_method_desc_free (desc);
+               desc = mono_method_desc_new ("Monitor:Exit", FALSE);
+               exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
+               g_assert (exit_method);
+               mono_method_desc_free (desc);
+
+               /*
+                * GetTypeFromHandle isn't called as a managed method because it has
+                * a funky calling sequence, e.g. ldtoken+GetTypeFromHandle gets
+                * transformed into something else by the JIT.
+                */
+               from_handle_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+               from_handle_sig->params [0] = &mono_defaults.object_class->byval_arg;
+               from_handle_sig->ret = &mono_defaults.object_class->byval_arg;
+       }
+
+       /* Push this or the type object */
+       if (method->flags & METHOD_ATTRIBUTE_STATIC) {
+               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, &method->klass->byval_arg));
+               mono_mb_emit_native_call (mb, from_handle_sig, type_from_handle);
+       }
+       else
+               mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_stloc (mb, this_local);
+
+       /* Call Monitor::Enter() */
+       mono_mb_emit_ldloc (mb, this_local);
+       mono_mb_emit_managed_call (mb, enter_method, NULL);
+
+       clause->try_offset = mb->pos;
+
+       /* 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));
+       mono_mb_emit_managed_call (mb, method, method->signature);
+       if (!MONO_TYPE_IS_VOID (sig->ret))
+               mono_mb_emit_stloc (mb, ret_local);
+
+       mono_mb_emit_byte (mb, CEE_LEAVE);
+       pos = mb->pos;
+       mono_mb_emit_i4 (mb, 0);
+
+       clause->try_len = mb->pos - clause->try_offset;
+       clause->handler_offset = mb->pos;
+
+       /* Call Monitor::Exit() */
+       mono_mb_emit_ldloc (mb, this_local);
+//     mono_mb_emit_native_call (mb, exit_sig, mono_monitor_exit);
+       mono_mb_emit_managed_call (mb, exit_method, NULL);
+       mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+
+       clause->handler_len = mb->pos - clause->handler_offset;
+
+       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+       if (!MONO_TYPE_IS_VOID (sig->ret))
+               mono_mb_emit_ldloc (mb, ret_local);
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+
+       header = ((MonoMethodNormal *)res)->header;
+       header->num_clauses = 1;
+       header->clauses = clause;
+
+       g_hash_table_insert (cache, method, res);
+
+       return res;     
+}
+
 /* FIXME: on win32 we should probably use GlobalAlloc(). */
 void*
 mono_marshal_alloc (gpointer size) 
@@ -2647,7 +3198,6 @@ mono_marshal_free_array (gpointer *ptr, int size)
 {
        int i;
 
-       printf ("TESTFREE %p\n", ptr);
        if (!ptr)
                return;
 
@@ -2670,13 +3220,9 @@ mono_marshal_string_array (MonoArray *array)
        char **result;
        int i, len;
 
-       printf ("TEST %p\n", array);
-
        if (!array)
                return NULL;
 
-       printf ("TEST1 %p\n", array);
-
        len = mono_array_length (array);
 
        result = g_malloc (sizeof (char *) * (len + 1));