2003-04-24 Martin Baulig <martin@ximian.com>
[mono.git] / mono / metadata / marshal.c
index 3aa5d1b8c465c86db92025f6965799ffc3fb65cc..fbe0ae5930a2257635e2e0d1bd05beabdcdd5b08 100644 (file)
@@ -17,6 +17,8 @@
 #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
 
@@ -37,6 +39,9 @@ struct _MonoMethodBuilder {
        unsigned char *code;
 };
 
+static void
+emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
+
 #ifdef DEBUG_RUNTIME_CODE
 static char*
 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
@@ -46,7 +51,7 @@ indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
 
 static MonoDisHelper marshal_dh = {
        "\n",
-       NULL,
+       "IL_%04x: ",
        "IL_%04x",
        indenter, 
        NULL,
@@ -57,8 +62,7 @@ static MonoDisHelper marshal_dh = {
 gpointer
 mono_delegate_to_ftnptr (MonoDelegate *delegate)
 {
-       MonoMethod *method, *invoke, *wrapper;
-       MonoMethodSignature *sig;
+       MonoMethod *method, *wrapper;
        MonoClass *klass;
 
        if (!delegate)
@@ -71,10 +75,7 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
        g_assert (klass->delegate);
        
        method = delegate->method_info->method;
-       sig = method->signature;
-       
-       invoke = mono_get_delegate_invoke (klass);
-       wrapper = mono_marshal_get_managed_wrapper (invoke, (MonoObject *)delegate);
+       wrapper = mono_marshal_get_managed_wrapper (method, delegate->target);
 
        delegate->delegate_trampoline =  mono_compile_method (wrapper);
 
@@ -97,8 +98,51 @@ mono_array_to_lparray (MonoArray *array)
        if (!array)
                return NULL;
 
-       g_assert_not_reached ();
-       return NULL;
+       /* fixme: maybe we need to make a copy */
+       return array->vector;
+}
+
+void
+mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
+{
+       GError *error = NULL;
+       guint16 *ut;
+       glong items_written;
+       int l;
+
+       if (!sb || !text)
+               return;
+
+       l = strlen (text);
+
+       ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
+
+       if (items_written > sb->capacity)
+               items_written = sb->capacity;
+       
+       if (!error) {
+               memcpy (sb->chars->vector, ut, items_written * 2);
+               sb->length = items_written;
+       } else 
+               g_error_free (error);
+
+       g_free (ut);
+}
+
+gpointer
+mono_string_builder_to_utf8 (MonoStringBuilder *sb)
+{
+       char *res;
+
+       if (!sb)
+               return NULL;
+
+       res = g_malloc (sb->capacity + 1);
+
+       /* fixme: copy the content of the string builder? */
+       res [0] = 0;
+
+       return res;
 }
 
 gpointer
@@ -124,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));
@@ -184,7 +228,7 @@ mono_mb_free (MonoMethodBuilder *mb)
 }
 
 MonoMethodBuilder *
-mono_mb_new (MonoClass *klass, const char *name)
+mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
 {
        MonoMethodBuilder *mb;
        MonoMethod *m;
@@ -200,7 +244,7 @@ mono_mb_new (MonoClass *klass, const char *name)
        m->name = g_strdup (name);
        m->inline_info = 1;
        m->inline_count = -1;
-       m->wrapper_type = MONO_WRAPPER_UNKNOWN;
+       m->wrapper_type = type;
 
        mb->code_size = 256;
        mb->code = g_malloc (mb->code_size);
@@ -273,7 +317,16 @@ mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
 void
 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
 {
-       *((gint32 *)(&mb->code [pos])) = value;
+       mb->code [pos] = value & 0xff;
+       mb->code [pos + 1] = (value >> 8) & 0xff;
+       mb->code [pos + 2] = (value >> 16) & 0xff;
+       mb->code [pos + 3] = (value >> 24) & 0xff;
+}
+
+void
+mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
+{
+       *((gint8 *)(&mb->code [pos])) = value;
 }
 
 void
@@ -287,6 +340,36 @@ mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
        mb->code [mb->pos++] = op;
 }
 
+void
+mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
+{
+        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+        mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+
+       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
 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
 {
@@ -295,7 +378,7 @@ mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
                mb->code = g_realloc (mb->code, mb->code_size);
        }
 
-       *((gint32 *)(&mb->code [mb->pos])) = data;
+       mono_mb_patch_addr (mb, mb->pos, data);
        mb->pos += 4;
 }
 
@@ -307,7 +390,8 @@ mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
                mb->code = g_realloc (mb->code, mb->code_size);
        }
 
-       *((gint16 *)(&mb->code [mb->pos])) = data;
+       mb->code [mb->pos] = data & 0xff;
+       mb->code [mb->pos + 1] = (data >> 8) & 0xff;
        mb->pos += 2;
 }
 
@@ -322,7 +406,7 @@ mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
        } else {
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_LDARG);
-               mono_mb_emit_i4 (mb, argnum);
+               mono_mb_emit_i2 (mb, argnum);
        }
 }
 
@@ -335,7 +419,20 @@ mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
        } else {
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_LDARGA);
-               mono_mb_emit_i4 (mb, argnum);
+               mono_mb_emit_i2 (mb, argnum);
+       }
+}
+
+void
+mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
+{
+       if (locnum < 256) {
+               mono_mb_emit_byte (mb, CEE_LDLOCA_S);
+               mono_mb_emit_byte (mb, locnum);
+       } else {
+               mono_mb_emit_byte (mb, CEE_PREFIX1);
+               mono_mb_emit_byte (mb, CEE_LDLOCA);
+               mono_mb_emit_i2 (mb, locnum);
        }
 }
 
@@ -350,7 +447,7 @@ mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
        } else {
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_LDLOC);
-               mono_mb_emit_i4 (mb, num);
+               mono_mb_emit_i2 (mb, num);
        }
 }
 
@@ -365,7 +462,7 @@ mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
        } else {
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_STLOC);
-               mono_mb_emit_i4 (mb, num);
+               mono_mb_emit_i2 (mb, num);
        }
 }
 
@@ -408,13 +505,29 @@ mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpoin
 void
 mono_mb_emit_exception (MonoMethodBuilder *mb)
 {
-       mono_mb_emit_byte (mb, CEE_LDNULL);
+       /* fixme: we need a better way to throw exception,
+        * supporting several exception types and messages */
+       static MonoMethod *missing_method_ctor = NULL;
+
+       if (!missing_method_ctor) {
+               MonoClass *mme = mono_class_from_name (mono_defaults.corlib, "System", "MissingMethodException");
+               int i;
+               mono_class_init (mme);
+               for (i = 0; i < mme->method.count; ++i) {
+                       if (strcmp (mme->methods [i]->name, ".ctor") == 0 && mme->methods [i]->signature->param_count == 0) {
+                               missing_method_ctor = mme->methods [i];
+                               break;
+                       }
+               }
+       }
+       mono_mb_emit_byte (mb, CEE_NEWOBJ);
+       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, missing_method_ctor));
        mono_mb_emit_byte (mb, CEE_THROW);
        
 }
 
 void
-mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
+mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
 {
        mono_mb_emit_ldloc (mb, local); 
        mono_mb_emit_icon (mb, incr);
@@ -423,18 +536,141 @@ mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
 }
 
 static void
-emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
+emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, 
+                     int usize, int msize)
 {
-       /* fixme: dont know what do do here - docs say 
-          this does not work for value types  */
+       switch (conv) {
+       case MONO_MARSHAL_CONV_BOOL_I4:
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+               mono_mb_emit_byte (mb, 5);
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+               mono_mb_emit_byte (mb, CEE_BR_S);
+               mono_mb_emit_byte (mb, 3);
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+               break;
+       case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
+               MonoClass *eclass;
+               int esize;
 
-       g_warning ("not implemented");
-       g_assert_not_reached ();
+               if (type->type == MONO_TYPE_ARRAY)
+                       eclass = mono_class_from_mono_type (type->data.array->type);
+               else if (type->type == MONO_TYPE_SZARRAY) {
+                       eclass = mono_class_from_mono_type (type->data.type);
+               } else {
+                       g_assert_not_reached ();
+               }
+
+               if (eclass->valuetype)
+                       esize = mono_class_instance_size (eclass) - sizeof (MonoObject);
+               else
+                       esize = sizeof (gpointer);
+
+               /* create a new array */
+               /* fixme: this only works for SZARRAYS */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_icon (mb, msize / esize);
+               mono_mb_emit_byte (mb, CEE_NEWARR);     
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eclass));
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+
+               /* copy the elements */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_icon (mb, usize);
+               mono_mb_emit_byte (mb, CEE_PREFIX1);
+               mono_mb_emit_byte (mb, CEE_CPBLK);                      
+
+               break;
+       }
+       case MONO_MARSHAL_CONV_STR_BYVALSTR: 
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+               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);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+               mono_mb_emit_byte (mb, CEE_STIND_I);            
+               break;
+       case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
+               MonoClass *klass = mono_class_from_mono_type (type);
+               int src_var, dst_var;
+
+               src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               
+               /* *dst = new object */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_NEWOBJ);        
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+       
+               /* save the old src pointer */
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_stloc (mb, src_var);
+               /* save the old dst pointer */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_stloc (mb, dst_var);
+
+               /* dst = pointer to newly created object data */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_icon (mb, sizeof (MonoObject));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_STLOC_1); 
+
+               emit_struct_conv (mb, klass, TRUE);
+               
+               /* restore the old src pointer */
+               mono_mb_emit_ldloc (mb, src_var);
+               mono_mb_emit_byte (mb, CEE_STLOC_0);
+               /* restore the old dst pointer */
+               mono_mb_emit_ldloc (mb, dst_var);
+               mono_mb_emit_byte (mb, CEE_STLOC_1);
+               break;
+       }
+       case MONO_MARSHAL_CONV_DEL_FTN: {
+               // fixme: we never convert functions back to delegates, dont 
+               // know if thats the correct behaviour
+               break;
+       }
+       case MONO_MARSHAL_CONV_STR_LPWSTR:
+       case MONO_MARSHAL_CONV_STR_BSTR:
+       case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+       case MONO_MARSHAL_CONV_STR_TBSTR:
+       case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
+       case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
+       case MONO_MARSHAL_CONV_STR_BYVALWSTR: 
+       case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
+       default:
+               g_warning ("marshaling conversion %d not implemented", conv);
+               g_assert_not_reached ();
+       }
 }
 
 static void
-emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, int msize)
+emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, int usize, int msize)
 {
+       int pos;
+
        switch (conv) {
        case MONO_MARSHAL_CONV_BOOL_I4:
                mono_mb_emit_byte (mb, CEE_LDLOC_1);
@@ -448,24 +684,33 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, in
        case MONO_MARSHAL_CONV_STR_BSTR:
        case MONO_MARSHAL_CONV_STR_ANSIBSTR:
        case MONO_MARSHAL_CONV_STR_TBSTR:
-       case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
-       case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
-               /* free space if ARG_2 == true */
-               mono_mb_emit_byte (mb, CEE_LDARG_2);
+               /* free space if free == true */
+               mono_mb_emit_byte (mb, CEE_LDLOC_2);
                mono_mb_emit_byte (mb, CEE_BRFALSE_S);
                mono_mb_emit_byte (mb, 4);
                mono_mb_emit_byte (mb, CEE_LDLOC_1);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                mono_mb_emit_byte (mb, CEE_MONO_FREE);
-               
+
                mono_mb_emit_byte (mb, CEE_LDLOC_1);
                mono_mb_emit_byte (mb, CEE_LDLOC_0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
                mono_mb_emit_byte (mb, conv);
-               mono_mb_emit_byte (mb, CEE_STIND_I);
+               mono_mb_emit_byte (mb, CEE_STIND_I);    
+               break;
+       case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
+       case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
+       case MONO_MARSHAL_CONV_DEL_FTN:
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+               mono_mb_emit_byte (mb, conv);
+               mono_mb_emit_byte (mb, CEE_STIND_I);    
                break;
        case MONO_MARSHAL_CONV_STR_BYVALSTR: 
        case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
@@ -488,7 +733,8 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, in
                mono_mb_emit_byte (mb, CEE_LDLOC_0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);            
                mono_mb_emit_byte (mb, CEE_BRFALSE_S);
-               mono_mb_emit_byte (mb, 15);
+               pos = mb->pos;
+               mono_mb_emit_byte (mb, 0);
 
                mono_mb_emit_byte (mb, CEE_LDLOC_1);
                mono_mb_emit_byte (mb, CEE_LDLOC_0);    
@@ -500,11 +746,51 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoMarshalConv conv, int usize, in
                mono_mb_emit_icon (mb, usize);
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_CPBLK);                      
+               mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
+               break;
+       }
+       case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
+               int src_var, dst_var;
+
+               src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);            
+               mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+               pos = mb->pos;
+               mono_mb_emit_byte (mb, 0);
+               
+               /* save the old src pointer */
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_stloc (mb, src_var);
+               /* save the old dst pointer */
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_stloc (mb, dst_var);
+
+               /* src = pointer to object data */
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);            
+               mono_mb_emit_icon (mb, sizeof (MonoObject));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_STLOC_0); 
+
+               emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
+               
+               /* restore the old src pointer */
+               mono_mb_emit_ldloc (mb, src_var);
+               mono_mb_emit_byte (mb, CEE_STLOC_0);
+               /* restore the old dst pointer */
+               mono_mb_emit_ldloc (mb, dst_var);
+               mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+               mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
                break;
        }
        case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
        default:
-               g_error ("marshalling conversion %d not implemented", conv);
+               g_warning ("marshalling conversion %d not implemented", conv);
+               g_assert_not_reached ();
        }
 }
 
@@ -516,6 +802,15 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
 
        info = mono_marshal_load_type_info (klass);
 
+       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               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);
+               return;
+       }
+
        for (i = 0; i < info->num_fields; i++) {
                MonoMarshalNative ntype;
                MonoMarshalConv conv;
@@ -539,7 +834,8 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                g_assert (msize > 0 && usize > 0);
 
                switch (conv) {
-               case MONO_MARSHAL_CONV_NONE:
+               case MONO_MARSHAL_CONV_NONE: {
+                       int t;
 
                        if (ftype->byref || ftype->type == MONO_TYPE_I ||
                            ftype->type == MONO_TYPE_U) {
@@ -550,9 +846,14 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                break;
                        }
 
-                       switch (ftype->type) {
+                       t = ftype->type;
+               handle_enum:
+                       switch (t) {
                        case MONO_TYPE_I4:
                        case MONO_TYPE_U4:
+#if SIZEOF_VOID_P == 4
+                       case MONO_TYPE_PTR:
+#endif
                                mono_mb_emit_byte (mb, CEE_LDLOC_1);
                                mono_mb_emit_byte (mb, CEE_LDLOC_0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I4);
@@ -575,6 +876,9 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                break;
                        case MONO_TYPE_I8:
                        case MONO_TYPE_U8:
+#if SIZEOF_VOID_P == 8
+                       case MONO_TYPE_PTR:
+#endif
                                mono_mb_emit_byte (mb, CEE_LDLOC_1);
                                mono_mb_emit_byte (mb, CEE_LDLOC_0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I8);
@@ -593,24 +897,32 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                mono_mb_emit_byte (mb, CEE_STIND_R8);
                                break;
                        case MONO_TYPE_VALUETYPE:
+                               if (ftype->data.klass->enumtype) {
+                                       t = ftype->data.klass->enum_basetype->type;
+                                       goto handle_enum;
+                               }
                                emit_struct_conv (mb, ftype->data.klass, to_object);
-                               break;
+                               continue;
                        default:
-                               g_error ("marshalling type %02x not implemented", ftype->type);
+                               g_warning ("marshaling type %02x not implemented", ftype->type);
+                               g_assert_not_reached ();
                        }
                        break;
-
+               }
                default:
                        if (to_object) 
-                               emit_ptr_to_str_conv (mb, conv, usize, msize);
+                               emit_ptr_to_str_conv (mb, ftype, conv, usize, msize);
                        else
-                               emit_str_to_ptr_conv (mb, conv, usize, msize);  
+                               emit_str_to_ptr_conv (mb, ftype, conv, usize, msize);   
                }
-
-               if (!last_field) {
+               
+               if (to_object) {
+                       mono_mb_emit_add_to_local (mb, 0, usize);
+                       mono_mb_emit_add_to_local (mb, 1, msize);
+               } else {
                        mono_mb_emit_add_to_local (mb, 0, msize);
                        mono_mb_emit_add_to_local (mb, 1, usize);
-               }               
+               }                               
        }
 }
 
@@ -689,6 +1001,29 @@ mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolea
        return params_var;
 }
 
+static char*
+mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
+{
+       int i;
+       char *result;
+       GString *res = g_string_new ("");
+
+       if (prefix) {
+               g_string_append (res, prefix);
+               g_string_append_c (res, '_');
+       }
+
+       mono_type_get_desc (res, sig->ret, FALSE);
+
+       for (i = 0; i < sig->param_count; ++i) {
+               g_string_append_c (res, '_');
+               mono_type_get_desc (res, sig->params [i], FALSE);
+       }
+       result = res->str;
+       g_string_free (res, FALSE);
+       return result;
+}
+
 MonoMethod *
 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
 {
@@ -698,6 +1033,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
        MonoMethod *res;
        GHashTable *cache;
        int params_var;
+       char *name;
 
        g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
                  !strcmp (method->name, "BeginInvoke"));
@@ -721,8 +1057,10 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
                csig->params [1] = &mono_defaults.int_class->byval_arg;
        }
 
-       mb = mono_mb_new (method->klass, method->name);
-       mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_BEGIN_INVOKE;
+       name = mono_signature_to_name (sig, "begin_invoke");
+       mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
+       g_free (name);
+
        mb->method->save_lmf = 1;
 
        params_var = mono_mb_emit_save_args (mb, sig, FALSE);
@@ -732,7 +1070,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
        mono_mb_emit_native_call (mb, csig, mono_delegate_begin_invoke);
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, sig, 0);
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
        g_hash_table_insert (cache, sig, res);
        return res;
@@ -832,17 +1170,17 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
                mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
                mono_mb_emit_byte (mb, CEE_LDIND_I2);
                break;
-#if SIZEOF_VOID_P == 4
        case MONO_TYPE_I:
-#endif
+       case MONO_TYPE_U:
+               mono_mb_emit_byte (mb, CEE_UNBOX);
+               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               break;
        case MONO_TYPE_I4:
                mono_mb_emit_byte (mb, CEE_UNBOX);
                mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
                mono_mb_emit_byte (mb, CEE_LDIND_I4);
                break;
-#if SIZEOF_VOID_P == 4
-       case MONO_TYPE_U:
-#endif
        case MONO_TYPE_U4:
                mono_mb_emit_byte (mb, CEE_UNBOX);
                mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_class_from_mono_type (return_type)));
@@ -890,6 +1228,7 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
        MonoMethod *res;
        GHashTable *cache;
        int params_var;
+       char *name;
 
        g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
                  !strcmp (method->name, "EndInvoke"));
@@ -913,8 +1252,10 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
                csig->params [1] = &mono_defaults.int_class->byval_arg;
        }
 
-       mb = mono_mb_new (method->klass, method->name);
-       mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_END_INVOKE;
+       name = mono_signature_to_name (sig, "end_invoke");
+       mb = mono_mb_new (mono_defaults.multicastdelegate_class, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
+       g_free (name);
+
        mb->method->save_lmf = 1;
 
        params_var = mono_mb_emit_save_args (mb, sig, FALSE);
@@ -923,14 +1264,16 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
        mono_mb_emit_ldloc (mb, params_var);
        mono_mb_emit_native_call (mb, csig, mono_delegate_end_invoke);
 
-       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_byte (mb, CEE_RET);
+       } else
                mono_mb_emit_restore_result (mb, sig->ret);
 
-       res = mono_mb_create_method (mb, sig, 0);
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
        g_hash_table_insert (cache, sig, res);
+
        return res;
 }
 
@@ -950,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);
@@ -988,18 +1353,15 @@ 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);
-       mb->method->wrapper_type = MONO_WRAPPER_REMOTING_INVOKE;
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
+       mb->method->save_lmf = 1;
 
        params_var = mono_mb_emit_save_args (mb, sig, TRUE);
 
@@ -1009,142 +1371,177 @@ 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, 0);
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
        g_hash_table_insert (cache, method, res);
        return res;
 }
 
-/*
- * the returned method invokes all methods in a multicast delegate 
- */
 MonoMethod *
-mono_marshal_get_delegate_invoke (MonoMethod *method)
+mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
 {
-       MonoMethodSignature *sig, *static_sig;
-       int i, sigsize;
+       MonoMethodSignature *sig;
        MonoMethodBuilder *mb;
-       MonoMethod *res;
+       MonoMethod *res, *native;
        GHashTable *cache;
-       int pos [3];
+       int i, pos;
+
+       g_assert (method);
+
+       if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+               return method;
 
-       g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
-                 !strcmp (method->name, "Invoke"));
-               
        sig = method->signature;
 
-       cache = method->klass->image->delegate_invoke_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
-               return res;
+       /* 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 
+ */
+MonoMethod *
+mono_marshal_get_delegate_invoke (MonoMethod *method)
+{
+       MonoMethodSignature *sig, *static_sig;
+       int i, sigsize;
+       MonoMethodBuilder *mb;
+       MonoMethod *res;
+       GHashTable *cache;
+       int pos0, pos1;
+       char *name;
+
+       g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
+                 !strcmp (method->name, "Invoke"));
+               
+       sig = method->signature;
+
+       cache = method->klass->image->delegate_invoke_cache;
+       if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
+               return res;
 
        sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
        static_sig = g_memdup (sig, sigsize);
        static_sig->hasthis = 0;
 
-       mb = mono_mb_new (method->klass, method->name);
-       mb->method->wrapper_type = MONO_WRAPPER_DELEGATE_INVOKE;
+       name = mono_signature_to_name (sig, "invoke");
+       mb = mono_mb_new (mono_defaults.multicastdelegate_class, name,  MONO_WRAPPER_DELEGATE_INVOKE);
+       g_free (name);
 
-       /* allocate local 0 (object) prev */
+       /* allocate local 0 (object) */
        mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
-       /* allocate local 1 (object) target */
-       mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
-       /* allocate local 2 (pointer) mptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-
-       /* allocate local 3 to store the return value */
-       if (sig->ret->type != MONO_TYPE_VOID)
-               mono_mb_add_local (mb, sig->ret);
 
        g_assert (sig->hasthis);
+       
+       /*
+        * if (prev != null)
+         *     prev.Invoke( args .. );
+        * return this.<target>( args .. );
+         */
 
-       /* prev = addr of delegate */
+       /* get this->prev */
        mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
+       mono_mb_emit_byte (mb, CEE_LDIND_I );
        mono_mb_emit_stloc (mb, 0);
 
-       /* loop */
-       pos [0] = mb->pos;
-       /* target = delegate->target */
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
-       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, target));
-       mono_mb_emit_byte (mb, CEE_ADD);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 1);
-
-       /* mptr = delegate->method_ptr */
+       /* if prev != null */
        mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
-       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
-       mono_mb_emit_byte (mb, CEE_ADD);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 2);
+       mono_mb_emit_byte (mb, CEE_BRFALSE);
 
-       /* target == null ? */
-       mono_mb_emit_ldloc (mb, 1);
-       mono_mb_emit_byte (mb, CEE_BRTRUE); 
-       pos [1] = mb->pos;
+       pos0 = mb->pos;
        mono_mb_emit_i4 (mb, 0);
 
-       /* emit static method call */
-
+       /* then recurse */
+       mono_mb_emit_ldloc (mb, 0);
        for (i = 0; i < sig->param_count; i++)
                mono_mb_emit_ldarg (mb, i + 1);
-
-       mono_mb_emit_ldloc (mb, 2);
-       mono_mb_emit_byte (mb, CEE_CALLI);
-       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
-
+       mono_mb_emit_managed_call (mb, method, method->signature);
        if (sig->ret->type != MONO_TYPE_VOID)
-               mono_mb_emit_stloc (mb, 3);
+               mono_mb_emit_byte (mb, CEE_POP);
 
-       mono_mb_emit_byte (mb, CEE_BR);
-       pos [2] = mb->pos;
-       mono_mb_emit_i4 (mb, 0);
-   
-       /* target != null, emit non static method call */
+       /* continued or prev == null */
+       mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
 
-       mono_mb_patch_addr (mb, pos [1], mb->pos - (pos [1] + 4));
-       mono_mb_emit_ldloc (mb, 1);
+       /* get this->target */
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, target));
+       mono_mb_emit_byte (mb, CEE_LDIND_I );
+       mono_mb_emit_stloc (mb, 0);
 
-       for (i = 0; i < sig->param_count; i++)
-               mono_mb_emit_ldarg (mb, i + 1);
+       /* if target != null */
+       mono_mb_emit_ldloc (mb, 0);
+       mono_mb_emit_byte (mb, CEE_BRFALSE);
+       pos0 = mb->pos;
+       mono_mb_emit_i4 (mb, 0);
        
-       mono_mb_emit_ldloc (mb, 2);
+       /* then call this->method_ptr nonstatic */
+       mono_mb_emit_ldloc (mb, 0); 
+       for (i = 0; i < sig->param_count; ++i)
+               mono_mb_emit_ldarg (mb, i + 1);
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
+       mono_mb_emit_byte (mb, CEE_LDIND_I );
        mono_mb_emit_byte (mb, CEE_CALLI);
        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, sig));
 
-       if (sig->ret->type != MONO_TYPE_VOID)
-               mono_mb_emit_stloc (mb, 3);
-
-       mono_mb_patch_addr (mb, pos [2], mb->pos - (pos [2] + 4));
-
-       /* prev = delegate->prev */
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-       mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
-       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
-       mono_mb_emit_byte (mb, CEE_ADD);
-       mono_mb_emit_byte (mb, CEE_LDIND_I);
-       mono_mb_emit_stloc (mb, 0);
+       mono_mb_emit_byte (mb, CEE_BR);
+       pos1 = mb->pos;
+       mono_mb_emit_i4 (mb, 0);
 
-       /* if prev != null goto loop */
-       mono_mb_emit_ldloc (mb, 0);
-       mono_mb_emit_byte (mb, CEE_BRTRUE);
-       mono_mb_emit_i4 (mb, pos [0] - (mb->pos + 4));
+       /* else [target == null] call this->method_ptr static */
+       mono_mb_patch_addr (mb, pos0, mb->pos - (pos0 + 4));
 
-       if (sig->ret->type != MONO_TYPE_VOID)
-               mono_mb_emit_ldloc (mb, 3);
+       for (i = 0; i < sig->param_count; ++i)
+               mono_mb_emit_ldarg (mb, i + 1);
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
+       mono_mb_emit_byte (mb, CEE_LDIND_I );
+       mono_mb_emit_byte (mb, CEE_CALLI);
+       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, static_sig));
 
+       /* return */
+       mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, sig, 0);
+       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
 
        g_hash_table_insert (cache, sig, res);
@@ -1191,8 +1588,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
        csig->params [1] = &mono_defaults.int_class->byval_arg;
        csig->params [2] = &mono_defaults.int_class->byval_arg;
 
-       mb = mono_mb_new (method->klass, method->name);
-       mb->method->wrapper_type = MONO_WRAPPER_RUNTIME_INVOKE;
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_RUNTIME_INVOKE);
 
        /* allocate local 0 (object) tmp */
        mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
@@ -1214,6 +1610,10 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
                        mono_mb_emit_i4 (mb, mono_mb_add_data (mb, string_dummy));
                } else {
                        mono_mb_emit_ldarg (mb, 0);
+                       if (method->klass->valuetype) {
+                               mono_mb_emit_byte (mb, CEE_UNBOX);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, method->klass));
+                       } 
                }
        }
 
@@ -1248,15 +1648,13 @@ handle_enum:
                case MONO_TYPE_CHAR:
                        mono_mb_emit_byte (mb, CEE_LDIND_U2);
                        break;
-#if SIZEOF_VOID_P == 4
                case MONO_TYPE_I:
-#endif
+               case MONO_TYPE_U:
+                       mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       break;
                case MONO_TYPE_I4:
                        mono_mb_emit_byte (mb, CEE_LDIND_I4);
                        break;
-#if SIZEOF_VOID_P == 4
-               case MONO_TYPE_U:
-#endif
                case MONO_TYPE_U4:
                        mono_mb_emit_byte (mb, CEE_LDIND_U4);
                        break;
@@ -1266,10 +1664,6 @@ handle_enum:
                case MONO_TYPE_R8:
                        mono_mb_emit_byte (mb, CEE_LDIND_R8);
                        break;
-#if SIZEOF_VOID_P == 8
-               case MONO_TYPE_I:
-               case MONO_TYPE_U:
-#endif
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
                        mono_mb_emit_byte (mb, CEE_LDIND_I8);
@@ -1287,7 +1681,8 @@ handle_enum:
                                type = t->data.klass->enum_basetype->type;
                                goto handle_enum;
                        }
-                       g_assert_not_reached ();
+                       mono_mb_emit_byte (mb, CEE_LDOBJ);
+                       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, t->data.klass));
                        break;
                default:
                        g_assert_not_reached ();
@@ -1305,11 +1700,19 @@ handle_enum:
        } else 
                mono_mb_emit_managed_call (mb, method, NULL);
 
+       if (sig->ret->byref) {
+               /* fixme: */
+               g_assert_not_reached ();
+       }
+
+
        switch (sig->ret->type) {
        case MONO_TYPE_VOID:
                if (!method->string_ctor)
                        mono_mb_emit_byte (mb, CEE_LDNULL);
                break;
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_CHAR:
        case MONO_TYPE_I1:
        case MONO_TYPE_U1:
        case MONO_TYPE_I2:
@@ -1345,26 +1748,27 @@ handle_enum:
        pos = mb->pos;
        mono_mb_emit_i4 (mb, 0);
 
-       /* fixme: use a filter clause and only catch exceptions
-        * when exc != null. With RETHROW we get wrong stack 
-        * traces. */
        clause = g_new0 (MonoExceptionClause, 1);
-       clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
-       clause->try_offset = 0;
+       clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
        clause->try_len = mb->pos;
+
+       /* filter code */
+       clause->token_or_filter = mb->pos;
+       
+       mono_mb_emit_byte (mb, CEE_POP);
+       mono_mb_emit_byte (mb, CEE_LDARG_2);
+       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+       mono_mb_emit_byte (mb, CEE_PREFIX1);
+       mono_mb_emit_byte (mb, CEE_CGT_UN);
+       mono_mb_emit_byte (mb, CEE_PREFIX1);
+       mono_mb_emit_byte (mb, CEE_ENDFILTER);
+
        clause->handler_offset = mb->pos;
 
        /* handler code */
-
        /* store exception */
        mono_mb_emit_stloc (mb, 1);
        
-       mono_mb_emit_byte (mb, CEE_LDARG_2);
-       mono_mb_emit_byte (mb, CEE_BRTRUE_S);
-       mono_mb_emit_byte (mb, 2);
-       mono_mb_emit_byte (mb, CEE_PREFIX1);
-       mono_mb_emit_byte (mb, CEE_RETHROW);
-       
        mono_mb_emit_byte (mb, CEE_LDARG_2);
        mono_mb_emit_ldloc (mb, 1);
        mono_mb_emit_byte (mb, CEE_STIND_I);
@@ -1379,7 +1783,7 @@ handle_enum:
        mono_mb_emit_ldloc (mb, 0);
        mono_mb_emit_byte (mb, CEE_RET);
        
-       res = mono_mb_create_method (mb, csig, 0);
+       res = mono_mb_create_method (mb, csig, sig->param_count + 16);
        mono_mb_free (mb);
 
        header = ((MonoMethodNormal *)res)->header;
@@ -1399,25 +1803,41 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
 {
        MonoMethodSignature *sig, *csig;
        MonoMethodBuilder *mb;
+       MonoClass *klass;
        MonoMethod *res;
        GHashTable *cache;
-       int i, sigsize;
+       int i, pos, sigsize, *tmp_locals;
 
        g_assert (method != NULL);
+       g_assert (!method->signature->pinvoke);
 
        cache = method->klass->image->managed_wrapper_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+       if (!this && (res = (MonoMethod *)g_hash_table_lookup (cache, method)))
                return res;
 
+       if (this) {
+               /* fime: howto free that memory ? */
+       }
+       
        sig = method->signature;
 
-       mb = mono_mb_new (method->klass, method->name);
-       mb->method->wrapper_type = MONO_WRAPPER_NATIVE_TO_MANAGED;
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+
+       /* allocate local 0 (pointer) src_ptr */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 1 (pointer) dst_ptr */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 2 (boolean) delete_old */
+       mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+
+       mono_mb_emit_byte (mb, CEE_LDNULL);
+       mono_mb_emit_byte (mb, CEE_STLOC_2);
 
        /* we copy the signature, so that we can modify it */
        sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
        csig = g_memdup (sig, sigsize);
        csig->hasthis = 0;
+       csig->pinvoke = 1;
 
        /* fixme: howto handle this ? */
        if (sig->hasthis) {
@@ -1434,10 +1854,80 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                }
        } 
 
-       for (i = 0; i < sig->param_count; i++) {
+
+       /* we first do all conversions */
+       tmp_locals = alloca (sizeof (int) * sig->param_count);
+       for (i = 0; i < sig->param_count; i ++) {
                MonoType *t = sig->params [i];
+
+               tmp_locals [i] = 0;
                
                switch (t->type) {
+               case MONO_TYPE_VALUETYPE:
+                       
+                       klass = sig->params [i]->data.klass;
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype)
+                               break;
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &klass->byval_arg);
+
+                       if (t->byref) 
+                               mono_mb_emit_ldarg (mb, i);
+                       else
+                               mono_mb_emit_ldarg_addr (mb, i);
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                       if (t->byref) {
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               pos = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+                       }                       
+
+                       mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                       /* emit valuetype convnversion code code */
+                       emit_struct_conv (mb, klass, TRUE);
+
+                       if (t->byref)
+                               mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+                       break;
+               case MONO_TYPE_STRING:
+                       if (t->byref)
+                               continue;
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+                       csig->params [i] = &mono_defaults.int_class->byval_arg;
+
+                       mono_mb_emit_ldarg (mb, i);
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+                       mono_mb_emit_stloc (mb, tmp_locals [i]);
+                       break;  
+               case MONO_TYPE_ARRAY:
+               case MONO_TYPE_SZARRAY:
+                       if (t->byref)
+                               continue;
+
+                       klass = mono_class_from_mono_type (t);
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+                       csig->params [i] = &mono_defaults.int_class->byval_arg;
+
+                       g_warning ("array marshaling not implemented");
+                       g_assert_not_reached ();
+                       break;
+               }
+       }
+
+       for (i = 0; i < sig->param_count; i++) {
+               MonoType *t = sig->params [i];
+
+               switch (t->type) {
+               case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
                case MONO_TYPE_I2:
@@ -1454,11 +1944,12 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                        mono_mb_emit_ldarg (mb, i);
                        break;
                case MONO_TYPE_STRING:
-                       csig->params [i] = &mono_defaults.int_class->byval_arg;
-                       mono_mb_emit_ldarg (mb, i);
-                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
-                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+                       if (t->byref) {
+                               mono_mb_emit_ldarg (mb, i);
+                       } else {
+                               g_assert (tmp_locals [i]);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       }
                        break;  
                case MONO_TYPE_CLASS:  
                case MONO_TYPE_ARRAY:
@@ -1467,6 +1958,20 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                        /* fixme: conversions ? */
                        mono_mb_emit_ldarg (mb, i);
                        break;
+               case MONO_TYPE_VALUETYPE:
+                       klass = sig->params [i]->data.klass;
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype) {
+                               mono_mb_emit_ldarg (mb, i);
+                               break;
+                       }
+
+                       g_assert (tmp_locals [i]);
+                       if (t->byref)
+                               mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
+                       else
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       break;
                default:
                        g_warning ("type 0x%02x unknown", t->type);     
                        g_assert_not_reached ();
@@ -1474,49 +1979,464 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        }
 
        mono_mb_emit_managed_call (mb, method, NULL);
-       
-       /* fixme: add return type conversions */
 
-       mono_mb_emit_byte (mb, CEE_RET);
+       if (!sig->ret->byref) { 
+               switch (sig->ret->type) {
+               case MONO_TYPE_VOID:
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_R4:
+               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:          
+                       csig->ret = &mono_defaults.int_class->byval_arg;
+
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                       mono_mb_emit_byte (mb, CEE_RET);
+                       break;
+               case MONO_TYPE_VALUETYPE: {
+                       int tmp;
+                       klass = sig->ret->data.klass;
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype)
+                               break;
+                       
+                       /* load pointer to returned value type */
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+                       
+                       /* store the address of the source into local variable 0 */
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+                       /* allocate space for the native struct and
+                        * store the address into dst_ptr */
+                       tmp = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       g_assert (tmp);
+                       mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
+                       mono_mb_emit_byte (mb, CEE_PREFIX1);
+                       mono_mb_emit_byte (mb, CEE_LOCALLOC);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+                       mono_mb_emit_byte (mb, CEE_LDLOC_1);
+                       mono_mb_emit_stloc (mb, tmp);
+
+                       /* emit valuetype conversion code */
+                       emit_struct_conv (mb, klass, FALSE);
+                       mono_mb_emit_ldloc (mb, tmp);
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_RETOBJ);
+                       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
+                       break;
+               }
+               default:
+                       g_warning ("return type 0x%02x unknown", sig->ret->type);       
+                       g_assert_not_reached ();
+               }
+       } else {
+               mono_mb_emit_byte (mb, CEE_RET);
+       }
 
-       res = mono_mb_create_method (mb, csig, 0);
+       res = mono_mb_create_method (mb, csig, sig->param_count + 16);
        mono_mb_free (mb);
 
-       g_hash_table_insert (cache, method, res);
+       if (!this)
+               g_hash_table_insert (cache, method, res);
 
        return res;
 }
 
 /*
- * generates IL code for the pinvoke wrapper (the generated method
- * call the unamnage code in method->addr)
+ * 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_native_wrapper (MonoMethod *method)
+mono_marshal_get_ldfld_wrapper (MonoType *type)
 {
        MonoMethodSignature *sig, *csig;
        MonoMethodBuilder *mb;
        MonoMethod *res;
-       GHashTable *cache;
        MonoClass *klass;
-       gboolean pinvoke = FALSE;
-       int i, argnum, *tmp_locals;
-       int type, sigsize;
+       static GHashTable *ldfld_hash = NULL; 
+       char *name;
+       int t, pos0, pos1;
 
-       g_assert (method != NULL);
+       if (!ldfld_hash) 
+               ldfld_hash = g_hash_table_new (NULL, NULL);
 
-       cache = method->klass->image->native_wrapper_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+
+       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;
 
-       sig = method->signature;
+       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, 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;
+
+       /* we copy the signature, so that we can modify it */
+       sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+
+       if (sig->hasthis)
+               mono_mb_emit_byte (mb, CEE_LDARG_0);
+
+       for (i = 0; i < sig->param_count; i++)
+               mono_mb_emit_ldarg (mb, i + sig->hasthis);
+
+       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);
+       
+       return res;
+}
+
+/*
+ * generates IL code for the pinvoke wrapper (the generated method
+ * calls the unamnage code in method->addr)
+ */
+MonoMethod *
+mono_marshal_get_native_wrapper (MonoMethod *method)
+{
+       MonoMethodSignature *sig, *csig;
+       MonoMethodBuilder *mb;
+       MonoMarshalSpec **mspecs;
+       MonoMethod *res;
+       GHashTable *cache;
+       MonoClass *klass;
+       gboolean pinvoke = FALSE;
+       int i, pos, argnum, *tmp_locals;
+       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))
                pinvoke = TRUE;
 
-       mb = mono_mb_new (method->klass, method->name);
-       mb->method->wrapper_type = MONO_WRAPPER_MANAGED_TO_NATIVE;
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
 
        mb->method->save_lmf = 1;
 
@@ -1525,20 +2445,23 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
        if (!method->addr) {
                mono_mb_emit_exception (mb);
-               res = mono_mb_create_method (mb, sig, 0);
+               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 *);
-       csig = g_memdup (sig, sigsize);
-
+       /* 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)) {
 
-               if (method->string_ctor)
+               /* hack - string constructors returns a value */
+               if (method->string_ctor) {
+                       csig = g_memdup (sig, sigsize);
                        csig->ret = &mono_defaults.string_class->byval_arg;
+               } else
+                       csig = sig;
 
                if (sig->hasthis)
                        mono_mb_emit_byte (mb, CEE_LDARG_0);
@@ -1551,7 +2474,9 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
                mono_mb_emit_byte (mb, CEE_RET);
 
-               res = mono_mb_create_method (mb, csig, 0);
+               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;
@@ -1559,13 +2484,26 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
        g_assert (pinvoke);
 
+       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;
+
        /* we allocate local for use with emit_struct_conv() */
        /* allocate local 0 (pointer) src_ptr */
        mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
        /* allocate local 1 (pointer) dst_ptr */
        mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 2 (pointer) as tmp/scratch storage */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 2 (boolean) delete_old */
+       mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+
+       /* delete_old = FALSE */
+       mono_mb_emit_icon (mb, 0);
+       mono_mb_emit_byte (mb, CEE_STLOC_2);
 
        if (sig->ret->type != MONO_TYPE_VOID) {
                /* allocate local 3 to store the return value */
@@ -1576,51 +2514,101 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        tmp_locals = alloca (sizeof (int) * sig->param_count);
        for (i = 0; i < sig->param_count; i ++) {
                MonoType *t = sig->params [i];
+               MonoMarshalSpec *spec = mspecs [i + 1];
 
                argnum = i + sig->hasthis;
-
-               /* allocate one tmp/scratch storage for each parameter */
-               tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               tmp_locals [i] = 0;
 
                switch (t->type) {
-               case MONO_TYPE_VALUETYPE:
-                       klass = sig->params [i]->data.klass;
-                       if (klass->enumtype)
+               case MONO_TYPE_VALUETYPE:                       
+                       klass = t->data.klass;
+
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype)
                                break;
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
                        
                        /* store the address of the source into local variable 0 */
-                       mono_mb_emit_byte (mb, CEE_LDARGA);
-                       mono_mb_emit_i2 (mb, argnum);
+                       if (t->byref)
+                               mono_mb_emit_ldarg (mb, argnum);
+                       else
+                               mono_mb_emit_ldarg_addr (mb, argnum);
+
                        mono_mb_emit_byte (mb, CEE_STLOC_0);
                        
                        /* allocate space for the native struct and
                         * store the address into local variable 1 (dest) */
-                       mono_mb_emit_icon (mb, mono_class_native_size (klass));
+                       mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
+                       mono_mb_emit_byte (mb, CEE_PREFIX1);
                        mono_mb_emit_byte (mb, CEE_LOCALLOC);
                        mono_mb_emit_stloc (mb, tmp_locals [i]);
+
+                       if (t->byref) {
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               pos = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+                       }
+
+                       /* set dst_ptr */
                        mono_mb_emit_ldloc (mb, tmp_locals [i]);
                        mono_mb_emit_byte (mb, CEE_STLOC_1);
 
-                       /* emit valuetype convnversion code code */
-                       emit_struct_conv (mb, sig->params [i]->data.klass, FALSE);
-
+                       /* emit valuetype conversion code */
+                       emit_struct_conv (mb, klass, FALSE);
+                       
+                       if (t->byref)
+                               mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
                        break;
                case MONO_TYPE_STRING:
-                       /* fixme: load the address instead */
+                       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);
+
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
-                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+
+                       if (spec) {
+                               switch (spec->native) {
+                               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 %d not implemented", spec->native);
+                                       g_assert_not_reached ();
+                               }
+                       } else {
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                       }
+
                        mono_mb_emit_stloc (mb, tmp_locals [i]);
                        break;
                case MONO_TYPE_CLASS:
-               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);
+
                        if (t->data.klass->delegate) {
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                                mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
                                mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_DEL_FTN);
                                mono_mb_emit_stloc (mb, tmp_locals [i]);
+                       } else if (t->data.klass == mono_defaults.stringbuilder_class) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_SB_LPSTR);
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
                        } else {
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -1628,6 +2616,41 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                /* fixme: convert to what ? */
                                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:
+                       if (t->byref)
+                               continue;
+
+                       klass = mono_class_from_mono_type (t);
+
+                       csig->params [argnum] = &mono_defaults.int_class->byval_arg;
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+                       if (klass->element_class == mono_defaults.string_class) 
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STRARRAY_STRLPARRAY);
+                       else
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_ARRAY_LPARRAY);
+                       mono_mb_emit_stloc (mb, tmp_locals [i]);
                        break;
                }
        }
@@ -1642,13 +2665,10 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                
                argnum = i + sig->hasthis;
 
-               if (t->byref) {
-                       mono_mb_emit_ldarg (mb, argnum);
-                       continue;
-               }
-
                switch (t->type) {
                case MONO_TYPE_BOOLEAN:
+                       if (t->byref)
+                               g_warning ("byref boolean marshalling not inplemented");
                        mono_mb_emit_ldarg (mb, argnum);
                        break;
                case MONO_TYPE_I1:
@@ -1668,27 +2688,51 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                        break;
                case MONO_TYPE_VALUETYPE:
                        klass = sig->params [i]->data.klass;
-                       if (klass->enumtype) {
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype) {
                                mono_mb_emit_ldarg (mb, argnum);
                                break;
                        }                       
+                       g_assert (tmp_locals [i]);
                        mono_mb_emit_ldloc (mb, tmp_locals [i]);
-                       //mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-                       //mono_mb_emit_byte (mb, CEE_MONO_LDOBJ);
-                       //mono_mb_emit_i4 (mb, mono_klass_native_size (klass));
-
+                       if (!t->byref) {
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_LDNATIVEOBJ);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, klass));
+                       }
                        break;
                case MONO_TYPE_STRING:
-                       /* fixme: load the address instead */
-                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       if (t->byref) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                       } else {
+                               g_assert (tmp_locals [i]);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       }
                        break;
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
-                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       if (t->byref) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                       } else {
+                               g_assert (tmp_locals [i]);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       }
                        break;
                case MONO_TYPE_CHAR:
+                       /* fixme: dont know how to marshal that. We cant simply
+                        * convert it to a one byte UTF8 character, because an
+                        * unicode character may need more that one byte in UTF8 */
+                       mono_mb_emit_ldarg (mb, argnum);
+                       break;
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
+                       if (t->byref) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                       } else {
+                               g_assert (tmp_locals [i]);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       }
+                       break;
                case MONO_TYPE_TYPEDBYREF:
                case MONO_TYPE_FNPTR:
                default:
@@ -1700,63 +2744,187 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        /* call the native method */
        mono_mb_emit_native_call (mb, csig, method->addr);
 
-       type = sig->ret->type;
-handle_enum:
-       switch (type) {
-       case MONO_TYPE_VOID:
-       case MONO_TYPE_I1:
-       case MONO_TYPE_U1:
-       case MONO_TYPE_I2:
-       case MONO_TYPE_U2:
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_R4:
-       case MONO_TYPE_R8:
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
+       /* return the result */
+
+       /* we need to convert byref arguments back and free string arrays */
+       for (i = 0; i < sig->param_count; i++) {
+               MonoType *t = sig->params [i];
+               
+               argnum = i + sig->hasthis;
+
+               switch (t->type) {
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:                  
+                       if (t->byref)
+                               continue;
+     
+                       if (t->data.klass == mono_defaults.stringbuilder_class) {
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_PROC2);
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_SB);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_FREE);
+                       }
+                       break;
+               case MONO_TYPE_VALUETYPE:
+                       if (!t->byref)
+                               continue;
+       
+                       klass = t->data.klass;
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype)
+                               break;
+
+                       /* dst = argument */
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                       mono_mb_emit_byte (mb, CEE_LDLOC_1);
+                       mono_mb_emit_byte (mb, CEE_BRFALSE);
+                       pos = mb->pos;
+                       mono_mb_emit_i4 (mb, 0);
+
+                       /* src = tmp_locals [i] */
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                       /* emit valuetype conversion code */
+                       emit_struct_conv (mb, klass, TRUE);
+                       
+                       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+                       break;
+               case MONO_TYPE_SZARRAY:
+                       if (t->byref)
+                               continue;
+                       klass = mono_class_from_mono_type (t);
+                       
+                       if (klass->element_class == mono_defaults.string_class) {
+                               g_assert (tmp_locals [i]);
+
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               pos = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDLEN);                              
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_PROC2);
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_FREE_ARRAY);
+
+                               mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+                       }
+
+                       break;
+               }
+       }
+
+       if (!sig->ret->byref) {
+               MonoMarshalSpec *spec = mspecs [0];
+               type = sig->ret->type;
+
+       handle_enum:
+               switch (type) {
+               case MONO_TYPE_VOID:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+               case MONO_TYPE_R4:
+               case MONO_TYPE_R8:
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
                /* no conversions necessary */
-               break;
-       case MONO_TYPE_BOOLEAN:
-               /* maybe we need to make sure that it fits within 8 bits */
-               break;
-       case MONO_TYPE_VALUETYPE:
-               if (sig->ret->data.klass->enumtype) {
-                       type = sig->ret->data.klass->enum_basetype->type;
-                       goto handle_enum;
-               } else {
-                       g_warning ("generic valutype %s not handled", sig->ret->data.klass->name);
+                       break;
+               case MONO_TYPE_BOOLEAN:
+                       /* maybe we need to make sure that it fits within 8 bits */
+                       break;
+               case MONO_TYPE_VALUETYPE: {
+                       int tmp;
+
+                       klass = sig->ret->data.klass;
+                       if (klass->enumtype) {
+                               type = sig->ret->data.klass->enum_basetype->type;
+                               goto handle_enum;
+                       }
+
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable)
+                               break;
+
+                       tmp = mono_mb_add_local (mb, sig->ret);
+                       g_assert (tmp);
+                       /* load pointer to returned value type */
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+                       /* store the address of the source into local variable 0 */
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+                       /* set dst_ptr */
+                       mono_mb_emit_ldloc_addr (mb, tmp);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                       /* emit valuetype conversion code */
+                       emit_struct_conv (mb, sig->ret->data.klass, TRUE);
+
+                       mono_mb_emit_ldloc (mb, tmp);
+                       break;
+               }
+               case MONO_TYPE_STRING:
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
+                       if (spec) {
+                               switch (spec->native) {
+                               case MONO_NATIVE_LPWSTR:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPWSTR_STR);
+                                       break;
+                               default:
+                                       g_warning ("marshalling conversion not implemented");
+                                       g_assert_not_reached ();
+                               }
+                       } else {
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+                       }
+                       break;
+               case MONO_TYPE_ARRAY:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:
+                       /* fixme: we need conversions here */
+                       break;
+               case MONO_TYPE_CHAR:
+                       /* fixme: we need conversions here */
+                       break;
+               case MONO_TYPE_TYPEDBYREF:
+               case MONO_TYPE_FNPTR:
+               default:
+                       g_warning ("return type 0x%02x unknown", sig->ret->type);       
                        g_assert_not_reached ();
                }
-               break;
-       case MONO_TYPE_STRING:
-               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-               mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
-               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
-               break;
-       case MONO_TYPE_ARRAY:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_OBJECT:
-               /* fixme: we need conversions here */
-               break;
-       case MONO_TYPE_CHAR:
-       case MONO_TYPE_TYPEDBYREF:
-       case MONO_TYPE_FNPTR:
-       default:
-               g_warning ("return type 0x%02x unknown", sig->ret->type);       
-               g_assert_not_reached ();
        }
 
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, sig, 0);
+       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);
 
+       for (i = sig->param_count; i >= 0; i--)
+               g_free (mspecs [i]);
+       g_free (mspecs);
+
        return res;
 }
 
@@ -1779,26 +2947,37 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
                stoptr = mono_find_method_by_name (mono_defaults.marshal_class, "StructureToPtr", 3);
        g_assert (stoptr);
 
-       mb = mono_mb_new (stoptr->klass, stoptr->name);
+       mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
 
-       /* allocate local 0 (pointer) src_ptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 1 (pointer) dst_ptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 2 (pointer) as tmp/scratch storage */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       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_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);
+       } else {
 
-       /* 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_byte (mb, CEE_STLOC_0);
+               /* allocate local 0 (pointer) src_ptr */
+               mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               /* allocate local 1 (pointer) dst_ptr */
+               mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               /* allocate local 2 (boolean) delete_old */
+               mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+               mono_mb_emit_byte (mb, CEE_LDARG_2);
+               mono_mb_emit_byte (mb, CEE_STLOC_2);
+
+               /* initialize src_ptr to point to the start of object data */
+               mono_mb_emit_byte (mb, CEE_LDARG_0);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
+               mono_mb_emit_byte (mb, CEE_STLOC_0);
 
-       /* initialize dst_ptr */
-       mono_mb_emit_byte (mb, CEE_LDARG_1);
-       mono_mb_emit_byte (mb, CEE_STLOC_1);
+               /* initialize dst_ptr */
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
+               mono_mb_emit_byte (mb, CEE_STLOC_1);
 
-       emit_struct_conv (mb, klass, FALSE);
+               emit_struct_conv (mb, klass, FALSE);
+       }
 
        mono_mb_emit_byte (mb, CEE_RET);
 
@@ -1828,26 +3007,33 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
                ptostr = mono_find_method_by_name (mono_defaults.marshal_class, "PtrToStructure", 2);
        g_assert (ptostr);
 
-       mb = mono_mb_new (ptostr->klass, ptostr->name);
+       mb = mono_mb_new (klass, ptostr->name, MONO_WRAPPER_UNKNOWN);
 
-       /* allocate local 0 (pointer) src_ptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 1 (pointer) dst_ptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 2 (pointer) as tmp/scratch storage */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
+               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);
+               mono_mb_emit_byte (mb, CEE_CPBLK);
+       } else {
 
-       /* initialize src_ptr to point to the start of object data */
-       mono_mb_emit_byte (mb, CEE_LDARG_0);
-       mono_mb_emit_byte (mb, CEE_STLOC_0);
+               /* allocate local 0 (pointer) src_ptr */
+               mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               /* allocate local 1 (pointer) dst_ptr */
+               mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               
+               /* initialize src_ptr to point to the start of object data */
+               mono_mb_emit_byte (mb, CEE_LDARG_0);
+               mono_mb_emit_byte (mb, CEE_STLOC_0);
 
-       /* 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_byte (mb, CEE_STLOC_1);
+               /* initialize dst_ptr */
+               mono_mb_emit_byte (mb, CEE_LDARG_1);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
+               mono_mb_emit_byte (mb, CEE_STLOC_1);
 
-       emit_struct_conv (mb, klass, TRUE);
+               emit_struct_conv (mb, klass, TRUE);
+       }
 
        mono_mb_emit_byte (mb, CEE_RET);
 
@@ -1858,23 +3044,177 @@ 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) {
+mono_marshal_alloc (gpointer size) 
+{
+       MONO_ARCH_SAVE_REGS;
+
        return g_try_malloc ((gulong)size);
 }
 
 void
-mono_marshal_free (gpointer ptr) {
+mono_marshal_free (gpointer ptr) 
+{
+       MONO_ARCH_SAVE_REGS;
+
        g_free (ptr);
 }
 
-void*
-mono_marshal_realloc (gpointer ptr, gpointer size) {
+void
+mono_marshal_free_array (gpointer *ptr, int size) 
+{
+       int i;
+
+       if (!ptr)
+               return;
+
+       for (i = 0; i < size; i++)
+               if (ptr [i])
+                       g_free (ptr [i]);
+}
+
+void *
+mono_marshal_realloc (gpointer ptr, gpointer size) 
+{
+       MONO_ARCH_SAVE_REGS;
+
        return g_try_realloc (ptr, (gulong)size);
 }
 
-void*
+void *
 mono_marshal_string_array (MonoArray *array)
 {
        char **result;
@@ -1885,11 +3225,14 @@ mono_marshal_string_array (MonoArray *array)
 
        len = mono_array_length (array);
 
-       result = g_malloc (sizeof (char*) * len);
+       result = g_malloc (sizeof (char *) * (len + 1));
        for (i = 0; i < len; ++i) {
-               MonoString *s = (MonoString*)mono_array_get (array, gpointer, i);
+               MonoString *s = (MonoString *)mono_array_get (array, gpointer, i);
                result [i] = s ? mono_string_to_utf8 (s): NULL;
        }
+       /* null terminate the array */
+       result [i] = NULL;
+
        return result;
 }
 
@@ -1900,11 +3243,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *s
        int element_size;
        void *source_addr;
 
+       MONO_ARCH_SAVE_REGS;
+
        MONO_CHECK_ARG_NULL (src);
        MONO_CHECK_ARG_NULL (dest);
 
        g_assert (src->obj.vtable->klass->rank == 1);
-       g_assert (start_index >= 0 && start_index < mono_array_length (src));
+       g_assert (start_index >= 0);
+       g_assert (length >= 0);
        g_assert (start_index + length <= mono_array_length (src));
 
        element_size = mono_array_element_size (src->obj.vtable->klass);
@@ -1921,11 +3267,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer s
        int element_size;
        void *dest_addr;
 
+       MONO_ARCH_SAVE_REGS;
+
        MONO_CHECK_ARG_NULL (src);
        MONO_CHECK_ARG_NULL (dest);
 
        g_assert (dest->obj.vtable->klass->rank == 1);
-       g_assert (start_index >= 0 && start_index < mono_array_length (dest));
+       g_assert (start_index >= 0);
+       g_assert (length >= 0);
        g_assert (start_index + length <= mono_array_length (dest));
 
        element_size = mono_array_element_size (dest->obj.vtable->klass);
@@ -1939,6 +3288,9 @@ gpointer
 ves_icall_System_Runtime_InteropServices_Marshal_ReadIntPtr (gpointer ptr, gint32 offset)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        return *(gpointer*)(p + offset);
 }
 
@@ -1946,6 +3298,9 @@ unsigned char
 ves_icall_System_Runtime_InteropServices_Marshal_ReadByte (gpointer ptr, gint32 offset)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        return *(unsigned char*)(p + offset);
 }
 
@@ -1953,6 +3308,9 @@ gint16
 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt16 (gpointer ptr, gint32 offset)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        return *(gint16*)(p + offset);
 }
 
@@ -1960,6 +3318,9 @@ gint32
 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt32 (gpointer ptr, gint32 offset)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        return *(gint32*)(p + offset);
 }
 
@@ -1967,6 +3328,9 @@ gint64
 ves_icall_System_Runtime_InteropServices_Marshal_ReadInt64 (gpointer ptr, gint32 offset)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        return *(gint64*)(p + offset);
 }
 
@@ -1974,6 +3338,9 @@ void
 ves_icall_System_Runtime_InteropServices_Marshal_WriteByte (gpointer ptr, gint32 offset, unsigned char val)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        *(unsigned char*)(p + offset) = val;
 }
 
@@ -1981,6 +3348,9 @@ void
 ves_icall_System_Runtime_InteropServices_Marshal_WriteIntPtr (gpointer ptr, gint32 offset, gpointer val)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        *(gpointer*)(p + offset) = val;
 }
 
@@ -1988,6 +3358,9 @@ void
 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt16 (gpointer ptr, gint32 offset, gint16 val)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        *(gint16*)(p + offset) = val;
 }
 
@@ -1995,6 +3368,9 @@ void
 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt32 (gpointer ptr, gint32 offset, gint32 val)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        *(gint32*)(p + offset) = val;
 }
 
@@ -2002,20 +3378,69 @@ void
 ves_icall_System_Runtime_InteropServices_Marshal_WriteInt64 (gpointer ptr, gint32 offset, gint64 val)
 {
        char *p = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
        *(gint64*)(p + offset) = val;
 }
 
-MonoString*
-ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAuto (gpointer ptr)
+MonoString *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_string_new (mono_domain_get (), ptr);
+}
+
+MonoString *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_string_new_len (mono_domain_get (), ptr, len);
+}
+
+MonoString *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
+{
+       MonoDomain *domain = mono_domain_get (); 
+       int len = 0;
+       guint16 *t = ptr;
+
+       MONO_ARCH_SAVE_REGS;
+
+       while (*t++)
+               len++;
+
+       return mono_string_new_utf16 (domain, ptr, len);
+}
+
+MonoString *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
 {
        MonoDomain *domain = mono_domain_get (); 
 
-       return mono_string_new (domain, (char *)ptr);
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_string_new_utf16 (domain, ptr, len);
+}
+
+MonoString *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR (gpointer ptr)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       g_warning ("PtrToStringBSTR not implemented");
+       g_assert_not_reached ();
+
+       return NULL;
 }
 
 guint32 
 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
 {
+       MONO_ARCH_SAVE_REGS;
+
        return (GetLastError ());
 }
 
@@ -2024,11 +3449,13 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty
 {
        MonoClass *klass;
 
+       MONO_ARCH_SAVE_REGS;
+
        MONO_CHECK_ARG_NULL (rtype);
 
        klass = mono_class_from_mono_type (rtype->type);
 
-       return mono_class_native_size (klass);
+       return mono_class_native_size (klass, NULL);
 }
 
 void
@@ -2037,6 +3464,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj
        MonoMethod *method;
        gpointer pa [3];
 
+       MONO_ARCH_SAVE_REGS;
+
        MONO_CHECK_ARG_NULL (obj);
        MONO_CHECK_ARG_NULL (dst);
 
@@ -2055,6 +3484,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, M
        MonoMethod *method;
        gpointer pa [2];
 
+       MONO_ARCH_SAVE_REGS;
+
        MONO_CHECK_ARG_NULL (src);
        MONO_CHECK_ARG_NULL (dst);
 
@@ -2065,3 +3496,126 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, M
 
        mono_runtime_invoke (method, NULL, pa, NULL);
 }
+
+MonoObject *
+ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
+{
+       MonoDomain *domain = mono_domain_get (); 
+       MonoObject *res;
+
+       MONO_ARCH_SAVE_REGS;
+
+       MONO_CHECK_ARG_NULL (src);
+       MONO_CHECK_ARG_NULL (type);
+
+       res = mono_object_new (domain, mono_class_from_mono_type (type->type));
+
+       ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (src, res);
+
+       return res;
+}
+
+int
+ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *type, MonoString *field_name)
+{
+       MonoMarshalType *info;
+       MonoClass *klass;
+       char *fname;
+       int i;
+
+       MONO_ARCH_SAVE_REGS;
+
+       MONO_CHECK_ARG_NULL (type);
+       MONO_CHECK_ARG_NULL (field_name);
+
+       fname = mono_string_to_utf8 (field_name);
+       klass = mono_class_from_mono_type (type->type);
+
+       info = mono_marshal_load_type_info (klass);     
+       
+       for (i = 0; i < klass->field.count; ++i) {
+               if (*fname == *klass->fields [i].name && 
+                   strcmp (fname, klass->fields [i].name) == 0)
+                       break;
+       }
+       g_free (fname);
+
+       mono_assert (i < klass->field.count);
+
+       return info->fields [i].offset;
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_string_to_utf8 (string);
+}
+
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return g_memdup (mono_string_chars (string), mono_string_length (string)*2);
+}
+
+static void
+mono_struct_delete_old (MonoClass *klass, char *ptr)
+{
+       MonoMarshalType *info;
+       int i;
+
+       info = mono_marshal_load_type_info (klass);
+
+       for (i = 0; i < info->num_fields; i++) {
+               MonoMarshalNative ntype;
+               MonoMarshalConv conv;
+               MonoType *ftype = info->fields [i].field->type;
+               char *cpos;
+
+               if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
+                       continue;
+
+               ntype = mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, 
+                                               klass->unicode, &conv);
+                       
+               cpos = ptr + info->fields [i].offset;
+
+               switch (conv) {
+               case MONO_MARSHAL_CONV_NONE:
+                       if (MONO_TYPE_ISSTRUCT (ftype)) {
+                               mono_struct_delete_old (ftype->data.klass, cpos);
+                               continue;
+                       }
+                       break;
+               case MONO_MARSHAL_CONV_STR_LPWSTR:
+               case MONO_MARSHAL_CONV_STR_LPSTR:
+               case MONO_MARSHAL_CONV_STR_LPTSTR:
+               case MONO_MARSHAL_CONV_STR_BSTR:
+               case MONO_MARSHAL_CONV_STR_ANSIBSTR:
+               case MONO_MARSHAL_CONV_STR_TBSTR:
+                       g_free (*(gpointer *)cpos);
+                       break;
+               default:
+                       continue;
+               }
+       }
+}
+
+void
+ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
+{
+       MonoClass *klass;
+
+       MONO_ARCH_SAVE_REGS;
+
+       MONO_CHECK_ARG_NULL (src);
+       MONO_CHECK_ARG_NULL (type);
+
+       klass = mono_class_from_mono_type (type->type);
+
+       mono_struct_delete_old (klass, (char *)src);
+}
+