2003-11-16 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / marshal.c
index 7b876671d418cc8e62c032b873a139f9507f928b..3ad6001f79d781667f26da3062543d084b9ce263 100644 (file)
@@ -17,7 +17,9 @@
 #include "metadata/appdomain.h"
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/threadpool.h"
+#include "mono/metadata/monitor.h"
 #include <string.h>
+#include <errno.h>
 
 //#define DEBUG_RUNTIME_CODE
 
@@ -41,6 +43,23 @@ struct _MonoMethodBuilder {
 static void
 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
 
+static MonoMethod *
+mono_find_method_by_name (MonoClass *klass, const char *name, int param_count)
+{
+       MonoMethod *res = NULL;
+       int i;
+
+       for (i = 0; i < klass->method.count; ++i) {
+               if (klass->methods [i]->name[0] == name [0] && 
+                   !strcmp (name, klass->methods [i]->name) &&
+                   klass->methods [i]->signature->param_count == param_count) {
+                       res = klass->methods [i];
+                       break;
+               }
+       }
+       return res;
+}
+
 #ifdef DEBUG_RUNTIME_CODE
 static char*
 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
@@ -58,11 +77,34 @@ static MonoDisHelper marshal_dh = {
 };
 #endif 
 
+/* This mutex protects the various marshalling related caches in MonoImage */
+static CRITICAL_SECTION marshal_mutex;
+
+/* Maps wrapper methods to the methods they wrap */
+static MonoGHashTable *wrapper_hash;
+
+static guint32 last_error_tls_id;
+
+void
+mono_marshal_init (void)
+{
+       static gboolean module_initialized = FALSE;
+
+       if (!module_initialized) {
+               module_initialized = TRUE;
+               InitializeCriticalSection (&marshal_mutex);
+               wrapper_hash = mono_g_hash_table_new (NULL, NULL);
+               last_error_tls_id = TlsAlloc ();
+       }
+}
+
 gpointer
 mono_delegate_to_ftnptr (MonoDelegate *delegate)
 {
-       MonoMethod *method, *wrapper;
+       MonoMethod *method, *wrapper, *invoke;
+       MonoMarshalSpec **mspecs;
        MonoClass *klass;
+       int i;
 
        if (!delegate)
                return NULL;
@@ -72,9 +114,19 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
 
        klass = ((MonoObject *)delegate)->vtable->klass;
        g_assert (klass->delegate);
-       
+
+
        method = delegate->method_info->method;
-       wrapper = mono_marshal_get_managed_wrapper (method, delegate->target);
+       invoke = mono_find_method_by_name (klass, "Invoke", method->signature->param_count);
+
+       mspecs = g_new (MonoMarshalSpec*, invoke->signature->param_count + 1);
+       mono_method_get_marshal_info (invoke, mspecs);
+
+       wrapper = mono_marshal_get_managed_wrapper (method, delegate->target, mspecs);
+
+       for (i = invoke->signature->param_count; i >= 0; i--)
+               g_free (mspecs [i]);
+       g_free (mspecs);
 
        delegate->delegate_trampoline =  mono_compile_method (wrapper);
 
@@ -167,10 +219,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));
@@ -200,25 +252,6 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
        *((char *)dst + size - 2) = 0;
 }
 
-
-static MonoMethod *
-mono_find_method_by_name (MonoClass *klass, const char *name, int param_count)
-{
-       MonoMethod *res = NULL;
-       int i;
-
-       for (i = 0; i < klass->method.count; ++i) {
-               if ((klass->methods [i]->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
-                   klass->methods [i]->name[0] == name [0] && 
-                   !strcmp (name, klass->methods [i]->name) &&
-                   klass->methods [i]->signature->param_count == param_count) {
-                       res = klass->methods [i];
-                       break;
-               }
-       }
-       return res;
-}
-
 void
 mono_mb_free (MonoMethodBuilder *mb)
 {
@@ -344,8 +377,29 @@ mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
 {
         mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
         mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
-        mono_mb_emit_icon (mb, offset);
-        mono_mb_emit_byte (mb, CEE_ADD);
+
+       if (offset) {
+               mono_mb_emit_icon (mb, offset);
+               mono_mb_emit_byte (mb, CEE_ADD);
+       }
+}
+
+static int
+mono_mb_emit_proxy_check (MonoMethodBuilder *mb, int branch_code)
+{
+       int pos;
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoObject, vtable));
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoVTable, klass));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_LDPTR);
+       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, mono_defaults.transparent_proxy_class));
+       mono_mb_emit_byte (mb, branch_code);
+       pos = mb->pos;
+       mono_mb_emit_i4 (mb, 0);
+       return pos;
 }
 
 void
@@ -373,6 +427,14 @@ mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
        mb->pos += 2;
 }
 
+void
+mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
+{
+       mono_mb_emit_byte (mb, CEE_LDSTR);
+       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, str));
+}
+
+
 void
 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
 {
@@ -458,6 +520,16 @@ mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
        }
 }
 
+guint32
+mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
+{
+       guint32 res;
+       mono_mb_emit_byte (mb, op);
+       res = mb->pos;
+       mono_mb_emit_i4 (mb, 0);
+       return res;
+}
+
 void
 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
 {
@@ -481,31 +553,30 @@ mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpoin
 }
 
 void
-mono_mb_emit_exception (MonoMethodBuilder *mb)
+mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name)
 {
        /* fixme: we need a better way to throw exception,
         * supporting several exception types and messages */
-       static MonoMethod *missing_method_ctor = NULL;
+       MonoMethod *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;
-                       }
+       MonoClass *mme = mono_class_from_name (mono_defaults.corlib, "System", exc_name);
+       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) {
+                       ctor = mme->methods [i];
+                       break;
                }
        }
+       g_assert (ctor);
        mono_mb_emit_byte (mb, CEE_NEWOBJ);
-       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, missing_method_ctor));
+       mono_mb_emit_i4 (mb, mono_mb_add_data (mb, 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);
@@ -515,20 +586,30 @@ mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint8 local, gint8 incr)
 
 static void
 emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, 
-                     int usize, int msize)
+                     int usize, int msize, MonoMarshalSpec *mspec)
 {
        switch (conv) {
        case MONO_MARSHAL_CONV_BOOL_I4:
+               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, CEE_LDIND_I4);
                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, 3);
                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, 1);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+               mono_mb_emit_byte (mb, CEE_STIND_I1);
+               break;
+       case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
                mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I2);
+               mono_mb_emit_byte (mb, CEE_BRFALSE_S);
+               mono_mb_emit_byte (mb, 3);
+               mono_mb_emit_byte (mb, CEE_LDC_I4_1);
+               mono_mb_emit_byte (mb, CEE_BR_S);
+               mono_mb_emit_byte (mb, 1);
                mono_mb_emit_byte (mb, CEE_LDC_I4_0);
                mono_mb_emit_byte (mb, CEE_STIND_I1);
                break;
@@ -536,23 +617,20 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                MonoClass *eclass;
                int esize;
 
-               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);
+               if (type->type == MONO_TYPE_SZARRAY) {
+                       eclass = type->data.klass;
                } else {
                        g_assert_not_reached ();
                }
 
-               if (eclass->valuetype)
+               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_icon (mb, mspec->data.array_data.num_elem);
                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);
@@ -563,7 +641,7 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                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_icon (mb, mspec->data.array_data.num_elem * esize);
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_CPBLK);                      
 
@@ -630,14 +708,15 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                // know if thats the correct behaviour
                break;
        }
+       case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
+               g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
+               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 ();
@@ -645,7 +724,8 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
 }
 
 static void
-emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, int usize, int msize)
+emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, int usize, int msize,
+                     MonoMarshalSpec *mspec)
 {
        int pos;
 
@@ -656,6 +736,13 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                mono_mb_emit_byte (mb, CEE_LDIND_U1);
                mono_mb_emit_byte (mb, CEE_STIND_I4);
                break;
+       case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
+               mono_mb_emit_byte (mb, CEE_LDLOC_1);
+               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+               mono_mb_emit_byte (mb, CEE_LDIND_U1);
+               mono_mb_emit_byte (mb, CEE_NEG);
+               mono_mb_emit_byte (mb, CEE_STIND_I2);
+               break;
        case MONO_MARSHAL_CONV_STR_LPWSTR:
        case MONO_MARSHAL_CONV_STR_LPSTR:
        case MONO_MARSHAL_CONV_STR_LPTSTR:
@@ -705,6 +792,20 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
+               MonoClass *eclass;
+               int esize;
+
+               if (type->type == MONO_TYPE_SZARRAY) {
+                       eclass = type->data.klass;
+               } else {
+                       g_assert_not_reached ();
+               }
+
+               if (eclass->valuetype)
+                       esize = mono_class_native_size (eclass, NULL);
+               else
+                       esize = sizeof (gpointer);
+
                if (!usize) 
                        break;
 
@@ -721,7 +822,7 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
                mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArray, vector));
                mono_mb_emit_byte (mb, CEE_ADD);
-               mono_mb_emit_icon (mb, usize);
+               mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
                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);
@@ -765,7 +866,6 @@ emit_str_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
                mono_mb_patch_addr_s (mb, pos, mb->pos - pos - 1);
                break;
        }
-       case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
        default:
                g_warning ("marshalling conversion %d not implemented", conv);
                g_assert_not_reached ();
@@ -778,11 +878,21 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
        MonoMarshalType *info;
        int i;
 
+       if (klass->parent)
+               emit_struct_conv(mb, klass->parent, to_object);
+
        info = mono_marshal_load_type_info (klass);
 
-       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
-               /* we should simply emit a BLKCOPY in this case */
-               g_assert_not_reached ();
+       if (info->native_size == 0)
+               return;
+
+       if (klass->blittable) {
+               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++) {
@@ -802,10 +912,10 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                        msize = klass->instance_size - info->fields [i].field->offset;
                        usize = info->native_size - info->fields [i].offset;
                } else {
-                       msize = klass->fields [i + 1].offset - info->fields [i].field->offset;
+                       msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
                        usize = info->fields [i + 1].offset - info->fields [i].offset;
                }
-               g_assert (msize > 0 && usize > 0);
+               g_assert ((msize >= 0) && (usize >= 0));
 
                switch (conv) {
                case MONO_MARSHAL_CONV_NONE: {
@@ -825,6 +935,9 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                        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);
@@ -840,6 +953,7 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                break;
                        case MONO_TYPE_I2:
                        case MONO_TYPE_U2:
+                       case MONO_TYPE_CHAR:
                                mono_mb_emit_byte (mb, CEE_LDLOC_1);
                                mono_mb_emit_byte (mb, CEE_LDLOC_0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I2);
@@ -847,6 +961,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);
@@ -879,9 +996,9 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                }
                default:
                        if (to_object) 
-                               emit_ptr_to_str_conv (mb, ftype, conv, usize, msize);
+                               emit_ptr_to_str_conv (mb, ftype, conv, usize, msize, info->fields [i].mspec);
                        else
-                               emit_str_to_ptr_conv (mb, ftype, conv, usize, msize);   
+                               emit_str_to_ptr_conv (mb, ftype, conv, usize, msize, info->fields [i].mspec);   
                }
                
                if (to_object) {
@@ -907,6 +1024,32 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
 
        g_assert (delegate);
 
+       if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
+
+               MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
+               if (!tp->klass->contextbound || tp->rp->context != (MonoObject *) mono_context_get ()) {
+
+                       // If the target is a proxy, make a direct call. Is proxy's work
+                       // to make the call asynchronous.
+
+                       MonoAsyncResult *ares;
+                       MonoObject *exc;
+                       MonoArray *out_args;
+                       HANDLE handle;
+                       method = delegate->method_info->method;
+
+                       msg = mono_method_call_message_new (method, params, NULL, &async_callback, &state);
+                       handle = CreateEvent (NULL, TRUE, FALSE, NULL);
+                       ares = mono_async_result_new (mono_domain_get (), handle, state, handle);
+                       ares->async_delegate = (MonoObject *)async_callback;
+                       msg->async_result = ares;
+                       msg->call_type = CallType_BeginInvoke;
+
+                       mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+                       return ares;
+               }
+       }
+
        klass = delegate->object.vtable->klass;
 
        method = mono_get_delegate_invoke (klass);
@@ -921,7 +1064,6 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
        g_assert (method != NULL);
 
        im = mono_get_delegate_invoke (method->klass);
-       
        msg = mono_method_call_message_new (method, params, im, &async_callback, &state);
 
        return mono_thread_pool_add ((MonoObject *)delegate, msg, async_callback, state);
@@ -992,6 +1134,61 @@ mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
        return result;
 }
 
+static inline MonoMethod*
+mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
+{
+       MonoMethod *res;
+
+       EnterCriticalSection (&marshal_mutex);
+       res = g_hash_table_lookup (cache, key);
+       LeaveCriticalSection (&marshal_mutex);
+       return res;
+}
+
+/* Create the method from the builder and place it in the cache */
+static inline MonoMethod*
+mono_mb_create_and_cache (GHashTable *cache, gpointer key,
+                                                          MonoMethodBuilder *mb, MonoMethodSignature *sig,
+                                                          int max_stack)
+{
+       MonoMethod *res;
+
+       EnterCriticalSection (&marshal_mutex);
+       res = g_hash_table_lookup (cache, key);
+       if (!res) {
+               /* This does not acquire any locks */
+               res = mono_mb_create_method (mb, sig, max_stack);
+               g_hash_table_insert (cache, key, res);
+               mono_g_hash_table_insert (wrapper_hash, res, key);
+       }
+       else
+               /* Somebody created it before us */
+               ;
+       LeaveCriticalSection (&marshal_mutex);
+
+       return res;
+}              
+
+MonoMethod *
+mono_marshal_method_from_wrapper (MonoMethod *wrapper)
+{
+       MonoMethod *res;
+
+       g_assert (
+               (wrapper->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) ||
+               (wrapper->wrapper_type == MONO_WRAPPER_SYNCHRONIZED));
+
+       EnterCriticalSection (&marshal_mutex);
+       res = mono_g_hash_table_lookup (wrapper_hash, wrapper);
+       LeaveCriticalSection (&marshal_mutex);
+
+       if (wrapper->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+               /* See mono_marshal_get_remoting_invoke_with_check */
+               return (MonoMethod*)((char*)res - 1);
+       else
+               return res;
+}
+
 MonoMethod *
 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
 {
@@ -1009,7 +1206,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
        sig = method->signature;
 
        cache = method->klass->image->delegate_begin_invoke_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
+       if ((res = mono_marshal_find_in_cache (cache, sig)))
                return res;
 
        g_assert (sig->hasthis);
@@ -1038,9 +1235,8 @@ 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, sig->param_count + 16);
+       res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
-       g_hash_table_insert (cache, sig, res);
        return res;
 }
 
@@ -1081,7 +1277,16 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
        ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
        g_assert (ares);
 
-       res = mono_thread_pool_finish (ares, &out_args, &exc);
+       if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
+               MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
+               msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
+               mono_message_init (domain, msg, delegate->method_info, NULL);
+               msg->call_type = CallType_EndInvoke;
+               msg->async_result = ares;
+               res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+       }
+       else
+               res = mono_thread_pool_finish (ares, &out_args, &exc);
 
        if (exc) {
                char *strace = mono_string_to_utf8 (((MonoException*)exc)->stack_trace);
@@ -1109,6 +1314,7 @@ mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
        case MONO_TYPE_VOID:
                g_assert_not_reached ();
                break;
+       case MONO_TYPE_PTR:
        case MONO_TYPE_STRING:
        case MONO_TYPE_CLASS: 
        case MONO_TYPE_OBJECT: 
@@ -1204,7 +1410,7 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
        sig = method->signature;
 
        cache = method->klass->image->delegate_end_invoke_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
+       if ((res = mono_marshal_find_in_cache (cache, sig)))
                return res;
 
        g_assert (sig->hasthis);
@@ -1238,9 +1444,9 @@ mono_marshal_get_delegate_end_invoke (MonoMethod *method)
        } else
                mono_mb_emit_restore_result (mb, sig->ret);
 
-       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       res = mono_mb_create_and_cache (cache, sig,
+                                                                                mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
-       g_hash_table_insert (cache, sig, res);
 
        return res;
 }
@@ -1261,6 +1467,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 = (gpointer*) alloca(count*sizeof(gpointer));
+
+               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);
@@ -1295,18 +1523,15 @@ mono_marshal_get_remoting_invoke (MonoMethod *method)
                return method;
 
        cache = method->klass->image->remoting_invoke_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+       if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
        if (!csig) {
-               int sigsize = sizeof (MonoMethodSignature) + 2 * sizeof (MonoType *);
-               csig = g_malloc0 (sigsize);
-
-               /* MonoObject *remoting_wrapper (MonoMethod *method, gpointer params[]) */
-               csig->param_count = 2;
-               csig->ret = &mono_defaults.object_class->byval_arg;
+               csig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
                csig->params [0] = &mono_defaults.int_class->byval_arg;
                csig->params [1] = &mono_defaults.int_class->byval_arg;
+               csig->ret = &mono_defaults.object_class->byval_arg;
+               csig->pinvoke = 1;
        }
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE);
@@ -1320,14 +1545,67 @@ 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_and_cache (cache, method, mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+
+       return res;
+}
+
+MonoMethod *
+mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
+{
+       MonoMethodSignature *sig;
+       MonoMethodBuilder *mb;
+       MonoMethod *res, *native;
+       GHashTable *cache;
+       int i, pos;
+
+       g_assert (method);
+
+       if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
+               return method;
+
+       sig = method->signature;
+
+       /* we cant remote methods without this pointer */
+       g_assert (sig->hasthis);
+
+       cache = method->klass->image->remoting_invoke_cache;
+       if ((res = mono_marshal_find_in_cache (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);
+       res = mono_mb_create_and_cache (cache, (char*)method + 1,
+                                                                                mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
-       g_hash_table_insert (cache, method, res);
+
        return res;
 }
 
@@ -1351,7 +1629,7 @@ mono_marshal_get_delegate_invoke (MonoMethod *method)
        sig = method->signature;
 
        cache = method->klass->image->delegate_invoke_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, sig)))
+       if ((res = mono_marshal_find_in_cache (cache, sig)))
                return res;
 
        sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
@@ -1438,11 +1716,10 @@ mono_marshal_get_delegate_invoke (MonoMethod *method)
        mono_mb_patch_addr (mb, pos1, mb->pos - (pos1 + 4));
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       res = mono_mb_create_and_cache (cache, sig,
+                                                                                mb, sig, sig->param_count + 16);
        mono_mb_free (mb);
 
-       g_hash_table_insert (cache, sig, res);
-
        return res;     
 }
 
@@ -1467,7 +1744,7 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
        g_assert (method);
 
        cache = method->klass->image->runtime_invoke_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+       if ((res = mono_marshal_find_in_cache (cache, method)))
                return res;
        
        /* to make it work with our special string constructors */
@@ -1680,15 +1957,14 @@ handle_enum:
        mono_mb_emit_ldloc (mb, 0);
        mono_mb_emit_byte (mb, CEE_RET);
        
-       res = mono_mb_create_method (mb, csig, sig->param_count + 16);
+       res = mono_mb_create_and_cache (cache, method,
+                                                                                mb, csig, 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;     
 }
 
@@ -1696,7 +1972,7 @@ handle_enum:
  * generates IL code to call managed methods from unmanaged code 
  */
 MonoMethod *
-mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
+mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMarshalSpec **mspecs)
 {
        MonoMethodSignature *sig, *csig;
        MonoMethodBuilder *mb;
@@ -1704,17 +1980,28 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        MonoMethod *res;
        GHashTable *cache;
        int i, pos, sigsize, *tmp_locals;
+       static MonoMethodSignature *alloc_sig = NULL;
+       int retobj_var = 0;
 
        g_assert (method != NULL);
+       g_assert (!method->signature->pinvoke);
 
        cache = method->klass->image->managed_wrapper_cache;
-       if (!this && (res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+       if (!this && (res = mono_marshal_find_in_cache (cache, method)))
                return res;
 
+       /* Under MS, the allocation should be done using CoTaskMemAlloc */
+       if (!alloc_sig) {
+               alloc_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+               alloc_sig->params [0] = &mono_defaults.int_class->byval_arg;
+               alloc_sig->ret = &mono_defaults.int_class->byval_arg;
+               alloc_sig->pinvoke = 1;
+       }
+
        if (this) {
                /* fime: howto free that memory ? */
        }
-       
+
        sig = method->signature;
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
@@ -1726,6 +2013,11 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        /* allocate local 2 (boolean) delete_old */
        mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
 
+       if (!MONO_TYPE_IS_VOID(sig->ret)) {
+               /* allocate local 3 to store the return value */
+               mono_mb_add_local (mb, sig->ret);
+       }
+
        mono_mb_emit_byte (mb, CEE_LDNULL);
        mono_mb_emit_byte (mb, CEE_STLOC_2);
 
@@ -1735,6 +2027,14 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        csig->hasthis = 0;
        csig->pinvoke = 1;
 
+#ifdef PLATFORM_WIN32
+       /* 
+        * Under windows, delegates passed to native code must use the STDCALL
+        * calling convention.
+        */
+       csig->call_convention = MONO_CALL_STDCALL;
+#endif
+
        /* fixme: howto handle this ? */
        if (sig->hasthis) {
 
@@ -1755,27 +2055,132 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        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];
 
                tmp_locals [i] = 0;
                
-               switch (t->type) {
-               case MONO_TYPE_VALUETYPE:
+               if (spec && spec->native == MONO_NATIVE_CUSTOM) {
+                       MonoType *mtype;
+                       MonoClass *mklass;
+                       MonoMethod *marshal_native_to_managed;
+                       MonoMethod *get_instance;
+
+                       mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
+                       g_assert (mtype != NULL);
+                       mklass = mono_class_from_mono_type (mtype);
+                       g_assert (mklass != NULL);
+
+                       marshal_native_to_managed = mono_find_method_by_name (mklass, "MarshalNativeToManaged", 1);
+                       g_assert (marshal_native_to_managed);
+                       get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
+                       g_assert (get_instance);
                        
-                       klass = sig->params [i]->data.klass;
-                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                           klass->blittable || klass->enumtype)
-                               break;
+                       switch (t->type) {
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                               if (t->byref)
+                                       break;
 
-                       tmp_locals [i] = mono_mb_add_local (mb, &klass->byval_arg);
+                               tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.object_class->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);
+                               mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
 
-                       if (t->byref) {
-                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_byte (mb, CEE_CALL);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
+                               
+                               mono_mb_emit_ldarg (mb, i);
+                               
+                               mono_mb_emit_byte (mb, CEE_CALLVIRT);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
+                               
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+                               break;
+                       default:
+                               g_warning ("custom marshalling of type %x is currently not supported", t->type);
+                               g_assert_not_reached ();
+                               break;
+                       }
+                       continue;
+               }
+
+               switch (t->type) {
+               case MONO_TYPE_CLASS: {
+                       klass = t->data.klass;
+
+                       /* FIXME: Raise a MarshalDirectiveException here */
+                       g_assert ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT);
+
+                       tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                       if (t->attrs & PARAM_ATTRIBUTE_OUT) {
+                               mono_mb_emit_byte (mb, CEE_LDNULL);
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+                               break;
+                       }
+
+                       /* Set src */
+                       mono_mb_emit_ldarg (mb, i);
+                       if (t->byref) {
+                               int pos2;
+
+                               /* Check for NULL and raise an exception */
+                               mono_mb_emit_byte (mb, CEE_BRTRUE);
+                               pos2 = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               mono_mb_emit_exception (mb, "ArgumentNullException");
+
+                               mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
+                               mono_mb_emit_ldarg (mb, i);
+                               mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       }                               
+
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       mono_mb_emit_stloc (mb, tmp_locals [i]);
+
+                       mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                       mono_mb_emit_byte (mb, CEE_BRFALSE);
+                       pos = mb->pos;
+                       mono_mb_emit_i4 (mb, 0);
+
+                       /* Create and set dst */
+                       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_stloc (mb, tmp_locals [i]);
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       mono_mb_emit_icon (mb, sizeof (MonoObject));
+                       mono_mb_emit_byte (mb, CEE_ADD);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1); 
+
+                       /* emit valuetype conversion code */
+                       emit_struct_conv (mb, klass, TRUE);
+
+                       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+                       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)
+                               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);
@@ -1848,15 +2253,23 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                        }
                        break;  
                case MONO_TYPE_CLASS:  
+                       if (t->byref)
+                               mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
+                       else
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       break;
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
                case MONO_TYPE_OBJECT:
-                       /* fixme: conversions ? */
-                       mono_mb_emit_ldarg (mb, i);
+                       if (tmp_locals [i])
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       else
+                               mono_mb_emit_ldarg (mb, i);
                        break;
                case MONO_TYPE_VALUETYPE:
                        klass = sig->params [i]->data.klass;
-                       if (klass->blittable || klass->enumtype) {
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
+                           klass->blittable || klass->enumtype) {
                                mono_mb_emit_ldarg (mb, i);
                                break;
                        }
@@ -1878,6 +2291,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
        if (!sig->ret->byref) { 
                switch (sig->ret->type) {
                case MONO_TYPE_VOID:
+                       break;
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
@@ -1892,7 +2306,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                case MONO_TYPE_R8:
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
-                       /* do nothing */
+               case MONO_TYPE_OBJECT:
+                       mono_mb_emit_byte (mb, CEE_STLOC_3);
                        break;
                case MONO_TYPE_STRING:          
                        csig->ret = &mono_defaults.int_class->byval_arg;
@@ -1900,9 +2315,9 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                        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_STLOC_3);
                        break;
-               case MONO_TYPE_VALUETYPE: {
-                       int tmp;
+               case MONO_TYPE_VALUETYPE:
                        klass = sig->ret->data.klass;
                        if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
                            klass->blittable || klass->enumtype)
@@ -1916,130 +2331,540 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this)
                        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);
+                       retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+                       g_assert (retobj_var);
                        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_native_call (mb, alloc_sig, mono_marshal_alloc);
                        mono_mb_emit_byte (mb, CEE_STLOC_1);
                        mono_mb_emit_byte (mb, CEE_LDLOC_1);
-                       mono_mb_emit_stloc (mb, tmp);
+                       mono_mb_emit_stloc (mb, retobj_var);
 
                        /* 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;
+               case MONO_TYPE_CLASS: {
+                       int pos2;
+
+                       klass = sig->ret->data.klass;
+
+                       /* FIXME: Raise a MarshalDirectiveException here */
+                       g_assert ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) != TYPE_ATTRIBUTE_AUTO_LAYOUT);
+
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+                       /* Check for null */
+                       mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                       pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+                       mono_mb_emit_byte (mb, CEE_STLOC_3);
+                       pos2 = mono_mb_emit_branch (mb, CEE_BR);
+
+                       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+
+                       /* Set src */
+                       mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                       mono_mb_emit_icon (mb, sizeof (MonoObject));
+                       mono_mb_emit_byte (mb, CEE_ADD);
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                       /* Allocate and set dest */
+                       mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
+                       mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
+                       mono_mb_emit_byte (mb, CEE_DUP);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+                       mono_mb_emit_byte (mb, CEE_STLOC_3);
+
+                       emit_struct_conv (mb, klass, FALSE);
+
+                       mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
                        break;
                }
                default:
                        g_warning ("return type 0x%02x unknown", sig->ret->type);       
                        g_assert_not_reached ();
                }
+       } else {
+               mono_mb_emit_byte (mb, CEE_STLOC_3);
        }
 
-       mono_mb_emit_byte (mb, CEE_RET);
+       /* Convert byref arguments back */
+       for (i = 0; i < sig->param_count; i ++) {
+               MonoType *t = sig->params [i];
 
-       res = mono_mb_create_method (mb, csig, sig->param_count + 16);
-       mono_mb_free (mb);
+               if (!t->byref)
+                       break;
+
+               switch (t->type) {
+               case MONO_TYPE_CLASS: {
+                       int pos2;
+
+                       klass = t->data.klass;
+
+                       /* Check for null */
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+                       mono_mb_emit_ldarg (mb, i);
+                       mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                       mono_mb_emit_byte (mb, CEE_STIND_I);
+                       pos2 = mono_mb_emit_branch (mb, CEE_BR);
+                       
+                       mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));                      
+                       
+                       /* Set src */
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       mono_mb_emit_icon (mb, sizeof (MonoObject));
+                       mono_mb_emit_byte (mb, CEE_ADD);
+                       mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                       /* Allocate and set dest */
+                       mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
+                       mono_mb_emit_native_call (mb, alloc_sig, mono_marshal_alloc);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                       /* Update argument pointer */
+                       mono_mb_emit_ldarg (mb, i);
+                       mono_mb_emit_byte (mb, CEE_LDLOC_1);
+                       mono_mb_emit_byte (mb, CEE_STIND_I);
+
+                       /* emit valuetype conversion code */
+                       emit_struct_conv (mb, klass, FALSE);
+
+                       mono_mb_patch_addr (mb, pos2, mb->pos - (pos2 + 4));
+                       break;
+               }
+               }
+       }
+
+       if (retobj_var) {
+               mono_mb_emit_ldloc (mb, retobj_var);
+               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));
+       }
+       else {
+               if (!MONO_TYPE_IS_VOID(sig->ret))
+                       mono_mb_emit_byte (mb, CEE_LDLOC_3);
+               mono_mb_emit_byte (mb, CEE_RET);
+       }
 
        if (!this)
-               g_hash_table_insert (cache, method, res);
+               res = mono_mb_create_and_cache (cache, method,
+                                                                                        mb, csig, sig->param_count + 16);
+       else
+               res = mono_mb_create_method (mb, csig, sig->param_count + 16);
+       mono_mb_free (mb);
+
+       //printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size));
 
        return res;
 }
 
 /*
- * generates IL code for the icall wrapper (the generated method
- * calls the unamnaged code in func)
+ * 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_icall_wrapper (MonoMethodSignature *sig, const char *name, gpointer func)
+mono_marshal_get_ldfld_wrapper (MonoType *type)
 {
-       MonoMethodSignature *csig;
+       MonoMethodSignature *sig, *csig;
        MonoMethodBuilder *mb;
        MonoMethod *res;
-       int i, sigsize;
+       MonoClass *klass;
+       static GHashTable *ldfld_hash = NULL; 
+       char *name;
+       int t, pos0, pos1;
 
-       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
+       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;
+       }
+
+       EnterCriticalSection (&marshal_mutex);
+       if (!ldfld_hash) 
+               ldfld_hash = g_hash_table_new (NULL, NULL);
+       res = g_hash_table_lookup (ldfld_hash, klass);
+       LeaveCriticalSection (&marshal_mutex);
+       if (res)
+               return res;
+
+       name = g_strdup_printf ("__ldfld_wrapper_%s.%s", klass->name_space, klass->name); 
+       mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_LDFLD);
+       g_free (name);
 
        mb->method->save_lmf = 1;
 
-       /* we copy the signature, so that we can modify it */
-       sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
+       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;
 
-       if (sig->hasthis)
-               mono_mb_emit_byte (mb, CEE_LDARG_0);
+       mono_mb_emit_ldarg (mb, 0);
+       pos0 = mono_mb_emit_proxy_check (mb, CEE_BNE_UN);
 
-       for (i = 0; i < sig->param_count; i++)
-               mono_mb_emit_ldarg (mb, i + sig->hasthis);
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldarg (mb, 2);
 
-       csig = g_memdup (sig, sigsize);
+       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, func);
+       mono_mb_emit_native_call (mb, csig, mono_load_remote_field_new);
 
-       mono_mb_emit_byte (mb, CEE_RET);
+       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);
+       }
 
-       res = mono_mb_create_method (mb, csig, csig->param_count + 16);
+
+       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_and_cache (ldfld_hash, klass,
+                                                                                mb, sig, sig->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)
+ * 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_native_wrapper (MonoMethod *method)
+mono_marshal_get_stfld_wrapper (MonoType *type)
 {
        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;
+       static GHashTable *stfld_hash = NULL; 
+       char *name;
+       int t, pos;
 
-       g_assert (method != NULL);
+       t = type->type;
 
-       cache = method->klass->image->native_wrapper_cache;
-       if ((res = (MonoMethod *)g_hash_table_lookup (cache, method)))
+       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;
+       }
+
+       EnterCriticalSection (&marshal_mutex);
+       if (!stfld_hash) 
+               stfld_hash = g_hash_table_new (NULL, NULL);
+       res = g_hash_table_lookup (stfld_hash, klass);
+       LeaveCriticalSection (&marshal_mutex);
+       if (res)
                return res;
 
-       sig = method->signature;
+       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);
 
-       if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
-           (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
-               pinvoke = TRUE;
+       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_and_cache (stfld_hash, klass,
+                                                                       mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+       
+       return res;
+}
+
+/*
+ * generates IL code for the icall wrapper (the generated method
+ * calls the unmanaged 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 unmanaged code in method->addr)
+ */
+MonoMethod *
+mono_marshal_get_native_wrapper (MonoMethod *method)
+{
+       MonoMethodSignature *sig, *csig;
+       MonoMethodPInvoke *piinfo;
+       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 = mono_marshal_find_in_cache (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;
+
+       if (!method->addr) {
+               if (pinvoke)
+                       mono_lookup_pinvoke_call (method);
+               else
+                       method->addr = mono_lookup_internal_call (method);
+       }
 
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
 
        mb->method->save_lmf = 1;
 
-       if (pinvoke && !method->addr)
-               mono_lookup_pinvoke_call (method);
+       piinfo = (MonoMethodPInvoke *)method;
 
        if (!method->addr) {
-               mono_mb_emit_exception (mb);
-               res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+               mono_mb_emit_exception (mb, "MissingMethodException");
+               csig = g_memdup (sig, sigsize);
+               csig->pinvoke = 0;
+               res = mono_mb_create_and_cache (cache, method,
+                                                                               mb, csig, csig->param_count + 16);
                mono_mb_free (mb);
-               g_hash_table_insert (cache, method, res);
                return res;
        }
 
-       /* we copy the signature, so that we can modify it */
-       sigsize = sizeof (MonoMethodSignature) + sig->param_count * sizeof (MonoType *);
-
        /* internal calls: we simply push all arguments and call the method (no conversions) */
        if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
 
-               MonoMethodSignature *call_sig;
-
                /* hack - string constructors returns a value */
                if (method->string_ctor) {
                        csig = g_memdup (sig, sigsize);
@@ -2053,27 +2878,27 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                for (i = 0; i < sig->param_count; i++)
                        mono_mb_emit_ldarg (mb, i + sig->hasthis);
 
-               call_sig = g_memdup (csig, sigsize);
-               call_sig->pinvoke = 1;
-
                g_assert (method->addr);
-               mono_mb_emit_native_call (mb, call_sig, method->addr);
+               mono_mb_emit_native_call (mb, csig, method->addr);
 
                mono_mb_emit_byte (mb, CEE_RET);
 
-               res = mono_mb_create_method (mb, csig, sig->param_count + 16);
+               csig = g_memdup (csig, sigsize);
+               csig->pinvoke = 0;
+               res = mono_mb_create_and_cache (cache, method,
+                                                                               mb, csig, csig->param_count + 16);
                mono_mb_free (mb);
-               g_hash_table_insert (cache, method, res);
                return res;
        }
 
        g_assert (pinvoke);
 
-       mspecs = g_new (MonoMarshalSpec, sig->param_count + 1);
+       mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
        mono_method_get_marshal_info (method, mspecs);
 
        /* pinvoke: we need to convert the arguments if necessary */
 
+       /* we copy the signature, so that we can set pinvoke to 0 */
        csig = g_memdup (sig, sigsize);
        csig->pinvoke = 1;
 
@@ -2089,13 +2914,14 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        mono_mb_emit_icon (mb, 0);
        mono_mb_emit_byte (mb, CEE_STLOC_2);
 
-       if (sig->ret->type != MONO_TYPE_VOID) {
+       if (!MONO_TYPE_IS_VOID(sig->ret)) {
                /* allocate local 3 to store the return value */
                mono_mb_add_local (mb, sig->ret);
        }
 
        /* 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];
                MonoMarshalSpec *spec = mspecs [i + 1];
@@ -2103,6 +2929,54 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                argnum = i + sig->hasthis;
                tmp_locals [i] = 0;
 
+               if (spec && spec->native == MONO_NATIVE_CUSTOM) {
+                       MonoType *mtype;
+                       MonoClass *mklass;
+                       MonoMethod *marshal_managed_to_native;
+                       MonoMethod *get_instance;
+
+                       mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
+                       g_assert (mtype != NULL);
+                       mklass = mono_class_from_mono_type (mtype);
+                       g_assert (mklass != NULL);
+
+                       marshal_managed_to_native = mono_find_method_by_name (mklass, "MarshalManagedToNative", 1);
+                       g_assert (marshal_managed_to_native);
+                       get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
+                       g_assert (get_instance);
+                       
+                       switch (t->type) {
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                               if (t->byref)
+                                       break;
+
+                               tmp_locals [i] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                               mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
+
+                               mono_mb_emit_byte (mb, CEE_CALL);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
+                               
+                               mono_mb_emit_ldarg (mb, argnum);
+                               
+                               mono_mb_emit_byte (mb, CEE_CALLVIRT);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_managed_to_native));
+                               
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+                               break;
+                       default:
+                               g_warning ("custom marshalling of type %x is currently not supported", t->type);
+                               g_assert_not_reached ();
+                               break;
+                       }
+                       continue;
+               }
+               
+
                switch (t->type) {
                case MONO_TYPE_VALUETYPE:                       
                        klass = t->data.klass;
@@ -2121,6 +2995,13 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
                        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, 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);
@@ -2128,12 +3009,6 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                mono_mb_emit_i4 (mb, 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, NULL));
-                       mono_mb_emit_byte (mb, CEE_PREFIX1);
-                       mono_mb_emit_byte (mb, CEE_LOCALLOC);
-                       mono_mb_emit_stloc (mb, tmp_locals [i]);
                        /* set dst_ptr */
                        mono_mb_emit_ldloc (mb, tmp_locals [i]);
                        mono_mb_emit_byte (mb, CEE_STLOC_1);
@@ -2145,13 +3020,19 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
                        break;
                case MONO_TYPE_STRING:
-                       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);
+                       if (t->byref) {
+                               if (t->attrs & PARAM_ATTRIBUTE_OUT)
+                                       break;
+
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDIND_I);                            
+                       } else {
+                               mono_mb_emit_ldarg (mb, argnum);
+                       }
+
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
 
@@ -2160,42 +3041,98 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                case MONO_NATIVE_LPWSTR:
                                        mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPWSTR);
                                        break;
+                               case MONO_NATIVE_LPSTR:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                                       break;
                                default:
-                                       g_warning ("marshalling conversion not implemented");
+                                       g_warning ("marshalling conversion %d not implemented", spec->native);
                                        g_assert_not_reached ();
                                }
                        } else {
-                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                               switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
+                               case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                                       break;
+                               case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPWSTR);
+                                       break;
+                               case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPTSTR);
+                                       break;
+                               default:
+                                       mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
+                                       break;                                  
+                               }
                        }
 
                        mono_mb_emit_stloc (mb, tmp_locals [i]);
                        break;
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
-                       if (t->byref)
-                               continue;
+                       klass = t->data.klass;
 
                        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) {
+                       if (klass->delegate) {
+                               g_assert (!t->byref);
                                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) {
+                       } else if (klass == mono_defaults.stringbuilder_class) {
+                               g_assert (!t->byref);
                                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);
-                               mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
-                               /* fixme: convert to what ? */
+                               mono_mb_emit_byte (mb, CEE_LDNULL);
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+
+                               if (t->byref) {
+                                       /* we dont need any conversions for out parameters */
+                                       if (t->attrs & PARAM_ATTRIBUTE_OUT)
+                                               break;
+
+                                       mono_mb_emit_ldarg (mb, argnum);                                
+                                       mono_mb_emit_byte (mb, CEE_LDIND_I);
+
+                               } else {
+                                       mono_mb_emit_ldarg (mb, argnum);
+                                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                                       mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+                               }
+                               
+                               /* store the address of the source into local variable 0 */
+                               mono_mb_emit_byte (mb, CEE_STLOC_0);
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               pos = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               /* allocate space for the native struct and store the address */
+                               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]);
+                               
+                               /* set the src_ptr */
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_icon (mb, sizeof (MonoObject));
+                               mono_mb_emit_byte (mb, CEE_ADD);
+                               mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                               /* set dst_ptr */
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                               mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                               /* emit valuetype conversion code */
+                               emit_struct_conv (mb, klass, FALSE);
+
+                               mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
                        }
 
                        break;
@@ -2209,16 +3146,120 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                        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) 
+                       if (klass->element_class == mono_defaults.string_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_STRARRAY_STRLPARRAY);
-                       else
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+                       }
+                       else if (klass->element_class->blittable) {
+                               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_ARRAY_LPARRAY);
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+                       }
+                       else {
+                               MonoClass *eklass;
+                               guint32 label1, label2, label3;
+                               int index_var, dest_ptr;
+
+                               dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                               /* Check null */
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               label1 = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               /* allocate space for the native struct and store the address */
+                               eklass = klass->element_class;
+                               mono_mb_emit_icon (mb, mono_class_native_size (eklass, NULL));
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDLEN);
+                               mono_mb_emit_byte (mb, CEE_MUL);
+                               mono_mb_emit_byte (mb, CEE_PREFIX1);
+                               mono_mb_emit_byte (mb, CEE_LOCALLOC);
+                               mono_mb_emit_stloc (mb, tmp_locals [i]);
+
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                               mono_mb_emit_stloc (mb, dest_ptr);
+
+                               /* Emit marshalling loop */
+                               index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
+                               mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                               mono_mb_emit_stloc (mb, index_var);
+                               label2 = mb->pos;
+                               mono_mb_emit_ldloc (mb, index_var);
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDLEN);
+                               mono_mb_emit_byte (mb, CEE_BGE);
+                               label3 = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               /* Emit marshalling code */
+
+                               /* set the src_ptr */
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_ldloc (mb, index_var);
+                               mono_mb_emit_byte (mb, CEE_LDELEMA);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
+                               mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                               /* set dst_ptr */
+                               mono_mb_emit_ldloc (mb, dest_ptr);
+                               mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                               /* emit valuetype conversion code */
+                               emit_struct_conv (mb, eklass, FALSE);
+
+                               mono_mb_emit_add_to_local (mb, index_var, 1);
+                               mono_mb_emit_add_to_local (mb, dest_ptr, mono_class_native_size (eklass, NULL));
+
+                               mono_mb_emit_byte (mb, CEE_BR);
+                               mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
+
+                               mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
+                               mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
+                       }
+
+                       break;
+               case MONO_TYPE_BOOLEAN: {
+                       MonoType *local_type;
+                       int variant_bool = 0;
+                       if (!t->byref)
+                               continue;
+                       if (spec == NULL) {
+                               local_type = &mono_defaults.int32_class->byval_arg;
+                       } else {
+                               switch (spec->native) {
+                               case MONO_NATIVE_I1:
+                                       local_type = &mono_defaults.byte_class->byval_arg;
+                                       break;
+                               case MONO_NATIVE_VARIANTBOOL:
+                                       local_type = &mono_defaults.int16_class->byval_arg;
+                                       variant_bool = 1;
+                                       break;
+                               default:
+                                       g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
+                               break;
+                               }
+                       }
+                       csig->params [argnum] = &mono_defaults.int_class->byval_arg;
+                       tmp_locals [i] = mono_mb_add_local (mb, local_type);
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, CEE_LDIND_I1);
+                       if (variant_bool)
+                               mono_mb_emit_byte (mb, CEE_NEG);
                        mono_mb_emit_stloc (mb, tmp_locals [i]);
                        break;
                }
+               }
        }
 
        /* push all arguments */
@@ -2233,9 +3274,11 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
                switch (t->type) {
                case MONO_TYPE_BOOLEAN:
-                       if (t->byref)
-                               g_warning ("byref boolean marshalling not inplemented");
-                       mono_mb_emit_ldarg (mb, argnum);
+                       if (t->byref) {
+                               g_assert (tmp_locals [i]);
+                               mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
+                       } else
+                               mono_mb_emit_ldarg (mb, argnum);
                        break;
                case MONO_TYPE_I1:
                case MONO_TYPE_U1:
@@ -2254,33 +3297,27 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                        break;
                case MONO_TYPE_VALUETYPE:
                        klass = sig->params [i]->data.klass;
-                       if (klass->blittable || 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]);
                        if (!t->byref) {
-                               mono_mb_emit_byte (mb, CEE_LDOBJ);
+                               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:
-                       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:
-                       if (t->byref) {
-                               mono_mb_emit_ldarg (mb, argnum);
-                       } else {
-                               g_assert (tmp_locals [i]);
+                       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;
                case MONO_TYPE_CHAR:
                        /* fixme: dont know how to marshal that. We cant simply
@@ -2308,7 +3345,198 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        /* call the native method */
        mono_mb_emit_native_call (mb, csig, method->addr);
 
-       /* return the result */
+       /* Set LastError if needed */
+       if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
+               MonoMethodSignature *lasterr_sig;
+
+               lasterr_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
+               lasterr_sig->ret = &mono_defaults.void_class->byval_arg;
+               lasterr_sig->pinvoke = 1;
+
+               mono_mb_emit_native_call (mb, lasterr_sig, mono_marshal_set_last_error);
+       }               
+
+       /* convert the result */
+       if (!sig->ret->byref) {
+               MonoMarshalSpec *spec = mspecs [0];
+               type = sig->ret->type;
+
+               if (spec && spec->native == MONO_NATIVE_CUSTOM) {
+                       MonoType *mtype;
+                       MonoClass *mklass;
+                       MonoMethod *marshal_native_to_managed;
+                       MonoMethod *get_instance;
+
+                       mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, method->klass->image);
+                       g_assert (mtype != NULL);
+                       mklass = mono_class_from_mono_type (mtype);
+                       g_assert (mklass != NULL);
+
+                       marshal_native_to_managed = mono_find_method_by_name (mklass, "MarshalNativeToManaged", 1);
+                       g_assert (marshal_native_to_managed);
+                       get_instance = mono_find_method_by_name (mklass, "GetInstance", 1);
+                       g_assert (get_instance);
+                       
+                       switch (type) {
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+
+                               mono_mb_emit_ldstr (mb, spec->data.custom_data.cookie);
+
+                               mono_mb_emit_byte (mb, CEE_CALL);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, get_instance));
+                               
+                               mono_mb_emit_byte (mb, CEE_LDLOC_3);
+                               
+                               mono_mb_emit_byte (mb, CEE_CALLVIRT);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, marshal_native_to_managed));
+                               
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+                               break;
+                       default:
+                               g_warning ("custom marshalling of type %x is currently not supported", type);
+                               g_assert_not_reached ();
+                               break;
+                       }
+               } else {
+
+               handle_enum:
+                       switch (type) {
+                       case MONO_TYPE_VOID:
+                               break;
+                       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 */
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+                               break;
+                       case MONO_TYPE_BOOLEAN:
+                               /* maybe we need to make sure that it fits within 8 bits */
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+                               break;
+                       case MONO_TYPE_VALUETYPE:
+                               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) {
+                                       mono_mb_emit_byte (mb, CEE_STLOC_3);
+                                       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);
+                               /* set dst_ptr */
+                               mono_mb_emit_ldloc_addr (mb, 3);
+                               mono_mb_emit_byte (mb, CEE_STLOC_1);
+                               
+                               /* emit valuetype conversion code */
+                               emit_struct_conv (mb, sig->ret->data.klass, TRUE);
+                               break;
+                       case MONO_TYPE_STRING:
+#ifdef GTK_SHARP_FIXED
+                               mono_mb_emit_byte (mb, CEE_STLOC_0);
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+#endif
+                               
+                               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);
+                               }
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+
+#ifdef GTK_SHARP_FIXED
+                               /* free the string */
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_FREE);
+#endif
+                               break;
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                               klass = sig->ret->data.klass;
+
+                               /* set src */
+                               mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                               mono_mb_emit_byte (mb, CEE_LDNULL);
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+
+
+                               mono_mb_emit_byte (mb, CEE_LDLOC_0);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               pos = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               /* allocate result object */
+
+                               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_STLOC_3);
+                               
+                               /* set dst  */
+
+                               mono_mb_emit_byte (mb, CEE_LDLOC_3);
+                               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                               mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
+                               mono_mb_emit_icon (mb, sizeof (MonoObject));
+                               mono_mb_emit_byte (mb, CEE_ADD);
+                               mono_mb_emit_byte (mb, CEE_STLOC_1);
+                                                       
+                               /* emit conversion code */
+                               emit_struct_conv (mb, klass, TRUE);
+
+                               mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
+                               break;
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                               /* fixme: we need conversions here */
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+                               break;
+                       case MONO_TYPE_CHAR:
+                               /* fixme: we need conversions here */
+                               mono_mb_emit_byte (mb, CEE_STLOC_3);
+                               break;
+                       case MONO_TYPE_TYPEDBYREF:
+                       case MONO_TYPE_FNPTR:
+                       default:
+                               g_warning ("return type 0x%02x unknown", sig->ret->type);       
+                               g_assert_not_reached ();
+                       }
+               }
+       } else {
+               mono_mb_emit_byte (mb, CEE_STLOC_3);
+       }
 
        /* we need to convert byref arguments back and free string arrays */
        for (i = 0; i < sig->param_count; i++) {
@@ -2317,12 +3545,24 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                argnum = i + sig->hasthis;
 
                switch (t->type) {
+               case MONO_TYPE_STRING:
+                       if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
+                               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_FUNC1);
+                               mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_LPSTR_STR);
+                               mono_mb_emit_byte (mb, CEE_STIND_I);            
+                       } else {
+                               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_CLASS:
                case MONO_TYPE_OBJECT:                  
-                       if (t->byref)
-                               continue;
-     
                        if (t->data.klass == mono_defaults.stringbuilder_class) {
+                               g_assert (!t->byref);
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, tmp_locals [i]);
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -2331,7 +3571,47 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                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;
+                       }
+                       
+                       if (!(t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)))
+                               continue;
+
+                       if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
+                               /* allocate a new object new object */
+                               mono_mb_emit_ldarg (mb, argnum);
+                               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);
                        }
+
+                       /* dst = *argument */
+                       mono_mb_emit_ldarg (mb, argnum);
+
+                       if (t->byref)
+                               mono_mb_emit_byte (mb, CEE_LDIND_I);
+
+                       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);
+
+                       mono_mb_emit_byte (mb, CEE_LDLOC_1);
+                       mono_mb_emit_icon (mb, sizeof (MonoObject));
+                       mono_mb_emit_byte (mb, CEE_ADD);
+                       mono_mb_emit_byte (mb, CEE_STLOC_1);
+                       
+                       /* 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_VALUETYPE:
                        if (!t->byref)
@@ -2365,120 +3645,109 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                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);
-                       }
-
-                       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: {
-                       int tmp;
 
-                       klass = sig->ret->data.klass;
-                       if (klass->enumtype) {
-                               type = sig->ret->data.klass->enum_basetype->type;
-                               goto handle_enum;
+                               mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
                        }
 
-                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) ||
-                           klass->blittable)
-                               break;
+                       if (t->attrs & PARAM_ATTRIBUTE_OUT) {
+                               /* FIXME: Optimize blittable case */
+                               MonoClass *eklass;
+                               guint32 label1, label2, label3;
+                               int index_var, src_ptr;
 
-                       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);
+                               eklass = klass->element_class;
+                               src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
-                       /* emit valuetype conversion code */
-                       emit_struct_conv (mb, sig->ret->data.klass, TRUE);
+                               /* Check null */
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_BRFALSE);
+                               label1 = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
 
-                       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);
+                               mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                               mono_mb_emit_stloc (mb, src_ptr);
+
+                               /* Emit marshalling loop */
+                               index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);                                
+                               mono_mb_emit_byte (mb, CEE_LDC_I4_0);
+                               mono_mb_emit_stloc (mb, index_var);
+                               label2 = mb->pos;
+                               mono_mb_emit_ldloc (mb, index_var);
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_byte (mb, CEE_LDLEN);
+                               mono_mb_emit_byte (mb, CEE_BGE);
+                               label3 = mb->pos;
+                               mono_mb_emit_i4 (mb, 0);
+
+                               /* Emit marshalling code */
+
+                               /* set the src_ptr */
+                               mono_mb_emit_ldloc (mb, src_ptr);
+                               mono_mb_emit_byte (mb, CEE_STLOC_0);
+
+                               /* set dst_ptr */
+                               mono_mb_emit_ldarg (mb, argnum);
+                               mono_mb_emit_ldloc (mb, index_var);
+                               mono_mb_emit_byte (mb, CEE_LDELEMA);
+                               mono_mb_emit_i4 (mb, mono_mb_add_data (mb, eklass));
+                               mono_mb_emit_byte (mb, CEE_STLOC_1);
+
+                               /* emit valuetype conversion code */
+                               emit_struct_conv (mb, eklass, TRUE);
+
+                               mono_mb_emit_add_to_local (mb, index_var, 1);
+                               mono_mb_emit_add_to_local (mb, src_ptr, mono_class_native_size (eklass, NULL));
+
+                               mono_mb_emit_byte (mb, CEE_BR);
+                               mono_mb_emit_i4 (mb, label2 - (mb->pos + 4));
+
+                               mono_mb_patch_addr (mb, label1, mb->pos - (label1 + 4));
+                               mono_mb_patch_addr (mb, label3, mb->pos - (label3 + 4));
                        }
                        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 ();
+               case MONO_TYPE_BOOLEAN:
+                       if (!t->byref)
+                               continue;
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_ldloc (mb, tmp_locals [i]);
+                       if (mspecs [i + 1] != NULL && mspecs [i + 1]->native == MONO_NATIVE_VARIANTBOOL)
+                               mono_mb_emit_byte (mb, CEE_NEG);
+                       mono_mb_emit_byte (mb, CEE_STIND_I1);
                }
        }
 
+       if (!MONO_TYPE_IS_VOID(sig->ret))
+               mono_mb_emit_byte (mb, CEE_LDLOC_3);
+
        mono_mb_emit_byte (mb, CEE_RET);
 
-       res = mono_mb_create_method (mb, sig, sig->param_count + 16);
+       csig = g_memdup (sig, sigsize);
+       csig->pinvoke = 0;
+       res = mono_mb_create_and_cache (cache, 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);
 
+       //printf ("CODE FOR %s: \n%s.\n", mono_method_full_name (res, TRUE), mono_disasm_code (0, res, ((MonoMethodNormal*)res)->header->code, ((MonoMethodNormal*)res)->header->code + ((MonoMethodNormal*)res)->header->code_size));
+
        return res;
 }
 
@@ -2503,11 +3772,10 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
 
        mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
 
-       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
+       if (klass->blittable) {
                mono_mb_emit_byte (mb, CEE_LDARG_1);
                mono_mb_emit_byte (mb, CEE_LDARG_0);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_PREFIX1);
                mono_mb_emit_byte (mb, CEE_CPBLK);
@@ -2524,8 +3792,7 @@ mono_marshal_get_struct_to_ptr (MonoClass *klass)
 
                /* initialize src_ptr to point to the start of object data */
                mono_mb_emit_byte (mb, CEE_LDARG_0);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_byte (mb, CEE_STLOC_0);
 
                /* initialize dst_ptr */
@@ -2567,8 +3834,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
 
        if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable) {
                mono_mb_emit_byte (mb, CEE_LDARG_1);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_byte (mb, CEE_LDARG_0);
                mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
                mono_mb_emit_byte (mb, CEE_PREFIX1);
@@ -2586,8 +3852,7 @@ mono_marshal_get_ptr_to_struct (MonoClass *klass)
 
                /* initialize dst_ptr */
                mono_mb_emit_byte (mb, CEE_LDARG_1);
-               mono_mb_emit_icon (mb, sizeof (MonoObject));
-               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                mono_mb_emit_byte (mb, CEE_STLOC_1);
 
                emit_struct_conv (mb, klass, TRUE);
@@ -2602,6 +3867,137 @@ 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 = mono_marshal_find_in_cache (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_and_cache (cache, method,
+                                                                       mb, sig, sig->param_count + 16);
+       mono_mb_free (mb);
+
+       header = ((MonoMethodNormal *)res)->header;
+       header->num_clauses = 1;
+       header->clauses = clause;
+
+       return res;     
+}
+
 /* FIXME: on win32 we should probably use GlobalAlloc(). */
 void*
 mono_marshal_alloc (gpointer size) 
@@ -2620,9 +4016,13 @@ mono_marshal_free (gpointer ptr)
 }
 
 void
-mono_marshal_free_array (gpointer *ptr, int size) {
+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]);
@@ -2658,6 +4058,16 @@ mono_marshal_string_array (MonoArray *array)
        return result;
 }
 
+void
+mono_marshal_set_last_error (void)
+{
+#ifdef WIN32
+       TlsSetValue (last_error_tls_id, (gpointer)GetLastError ());
+#else
+       TlsSetValue (last_error_tls_id, (gpointer)errno);
+#endif
+}
+
 void
 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
                                                                    gpointer dest, gint32 length)
@@ -2671,7 +4081,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *s
        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);
@@ -2694,7 +4105,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer s
        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);
@@ -2861,7 +4273,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
 {
        MONO_ARCH_SAVE_REGS;
 
-       return (GetLastError ());
+       return ((guint32)TlsGetValue (last_error_tls_id));
 }
 
 guint32 
@@ -2941,8 +4353,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t
        MonoMarshalType *info;
        MonoClass *klass;
        char *fname;
-       int i;
-
+       int i, match_index = -1;
+       
        MONO_ARCH_SAVE_REGS;
 
        MONO_CHECK_ARG_NULL (type);
@@ -2951,18 +4363,36 @@ ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionType *t
        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;
-       }
+       while(klass && match_index == -1) {
+               for (i = 0; i < klass->field.count; ++i) {
+                       if (*fname == *klass->fields [i].name && strcmp (fname, klass->fields [i].name) == 0) {
+                               match_index = i;
+                               break;
+                       }
+               }
+
+               if(match_index == -1)
+                       klass = klass->parent;
+        }
+
        g_free (fname);
 
-       mono_assert (i < klass->field.count);
+       if(match_index == -1) {
+               MonoException* exc;
+               gchar *tmp;
+
+               /* Get back original class instance */
+              klass = mono_class_from_mono_type (type->type);
 
-       return info->fields [i].offset;
+               tmp = g_strdup_printf ("Field passed in is not a marshaled member of the type %s", klass->name);
+               exc = mono_get_exception_argument ("fieldName", tmp);
+               g_free (tmp);
+               mono_raise_exception ((MonoException*)exc);
+       }
+
+       info = mono_marshal_load_type_info (klass);     
+       return info->fields [match_index].offset;
 }
 
 gpointer
@@ -3039,3 +4469,270 @@ ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src,
        mono_struct_delete_old (klass, (char *)src);
 }
 
+MonoMarshalType *
+mono_marshal_load_type_info (MonoClass* klass)
+{
+       int i, j, count = 0, native_size = 0;
+       MonoMarshalType *info;
+       guint32 layout;
+
+       g_assert (klass != NULL);
+
+       if (klass->marshal_info)
+               return klass->marshal_info;
+
+       if (!klass->inited)
+               mono_class_init (klass);
+       
+       for (i = 0; i < klass->field.count; ++i) {
+               if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
+                       continue;
+               count++;
+       }
+
+       layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
+
+       klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
+       info->num_fields = count;
+       
+       /* Try to find a size for this type in metadata */
+       mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
+
+       if (klass->parent) {
+               int parent_size = mono_class_native_size (klass->parent, NULL);
+
+               /* Add parent size to real size */
+               native_size += parent_size;
+               info->native_size = parent_size;
+       }
+       for (j = i = 0; i < klass->field.count; ++i) {
+               int size, align;
+               
+               if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
+                       continue;
+
+               if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
+                       mono_metadata_field_info (klass->image, klass->field.first + i, 
+                                                 NULL, NULL, &info->fields [j].mspec);
+
+               info->fields [j].field = &klass->fields [i];
+
+               if ((klass->field.count == 1) && (klass->instance_size == sizeof (MonoObject)) &&
+                       (strcmp (klass->fields [i].name, "$PRIVATE$") == 0)) {
+                       /* This field is a hack inserted by MCS to empty structures */
+                       continue;
+               }
+
+               switch (layout) {
+               case TYPE_ATTRIBUTE_AUTO_LAYOUT:
+               case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
+                       size = mono_marshal_type_size (klass->fields [i].type, info->fields [j].mspec, 
+                                                      &align, TRUE, klass->unicode);
+                       align = klass->packing_size ? MIN (klass->packing_size, align): align;  
+                       info->fields [j].offset = info->native_size;
+                       info->fields [j].offset += align - 1;
+                       info->fields [j].offset &= ~(align - 1);
+                       info->native_size = info->fields [j].offset + size;
+                       break;
+               case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
+                       /* FIXME: */
+                       info->fields [j].offset = klass->fields [i].offset - sizeof (MonoObject);
+                       info->native_size = klass->instance_size - sizeof (MonoObject);
+                       break;
+               }       
+               j++;
+       }
+
+       if(layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
+               info->native_size = MAX (native_size, info->native_size);
+       }
+
+       if (info->native_size & (klass->min_align - 1)) {
+               info->native_size += klass->min_align - 1;
+               info->native_size &= ~(klass->min_align - 1);
+       }
+
+       return klass->marshal_info;
+}
+
+/**
+ * mono_class_native_size:
+ * @klass: a class 
+ * 
+ * Returns: the native size of an object instance (when marshaled 
+ * to unmanaged code) 
+ */
+gint32
+mono_class_native_size (MonoClass *klass, guint32 *align)
+{
+       
+       if (!klass->marshal_info)
+               mono_marshal_load_type_info (klass);
+
+       if (align)
+               *align = klass->min_align;
+
+       return klass->marshal_info->native_size;
+}
+
+/*
+ * mono_type_native_stack_size:
+ * @t: the type to return the size it uses on the stack
+ *
+ * Returns: the number of bytes required to hold an instance of this
+ * type on the native stack
+ */
+int
+mono_type_native_stack_size (MonoType *t, gint *align)
+{
+       int tmp;
+
+       g_assert (t != NULL);
+
+       if (!align)
+               align = &tmp;
+
+       if (t->byref) {
+               *align = 4;
+               return 4;
+       }
+
+       switch (t->type){
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_CHAR:
+       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_STRING:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_FNPTR:
+       case MONO_TYPE_ARRAY:
+       case MONO_TYPE_TYPEDBYREF:
+               *align = 4;
+               return 4;
+       case MONO_TYPE_R4:
+               *align = 4;
+               return 4;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_R8:
+               *align = 4;
+               return 8;
+       case MONO_TYPE_VALUETYPE: {
+               guint32 size;
+
+               if (t->data.klass->enumtype)
+                       return mono_type_native_stack_size (t->data.klass->enum_basetype, align);
+               else {
+                       size = mono_class_native_size (t->data.klass, align);
+                       *align = *align + 3;
+                       *align &= ~3;
+                       
+                       size +=  3;
+                       size &= ~3;
+
+                       return size;
+               }
+       }
+       default:
+               g_error ("type 0x%02x unknown", t->type);
+       }
+       return 0;
+}
+
+/* __alignof__ returns the preferred alignment of values not the actual alignment used by
+   the compiler so is wrong e.g. for Linux where doubles are aligned on a 4 byte boundary
+   but __alignof__ returns 8 - using G_STRUCT_OFFSET works better */
+#define ALIGNMENT(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
+
+gint32
+mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align, 
+                       gboolean as_field, gboolean unicode)
+{
+       MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
+       MonoClass *klass;
+
+       switch (native_type) {
+       case MONO_NATIVE_BOOLEAN:
+               *align = 4;
+               return 4;
+       case MONO_NATIVE_I1:
+       case MONO_NATIVE_U1:
+               *align = 1;
+               return 1;
+       case MONO_NATIVE_I2:
+       case MONO_NATIVE_U2:
+       case MONO_NATIVE_VARIANTBOOL:
+               *align = 2;
+               return 2;
+       case MONO_NATIVE_I4:
+       case MONO_NATIVE_U4:
+       case MONO_NATIVE_ERROR:
+               *align = 4;
+               return 4;
+       case MONO_NATIVE_I8:
+       case MONO_NATIVE_U8:
+               *align = ALIGNMENT(guint64);
+               return 8;
+       case MONO_NATIVE_R4:
+               *align = 4;
+               return 4;
+       case MONO_NATIVE_R8:
+               *align = ALIGNMENT(double);
+               return 8;
+       case MONO_NATIVE_INT:
+       case MONO_NATIVE_UINT:
+       case MONO_NATIVE_LPSTR:
+       case MONO_NATIVE_LPWSTR:
+       case MONO_NATIVE_LPTSTR:
+       case MONO_NATIVE_BSTR:
+       case MONO_NATIVE_ANSIBSTR:
+       case MONO_NATIVE_TBSTR:
+       case MONO_NATIVE_LPARRAY:
+       case MONO_NATIVE_SAFEARRAY:
+       case MONO_NATIVE_IUNKNOWN:
+       case MONO_NATIVE_IDISPATCH:
+       case MONO_NATIVE_INTERFACE:
+       case MONO_NATIVE_ASANY:
+       case MONO_NATIVE_FUNC:
+       case MONO_NATIVE_LPSTRUCT:
+               *align = ALIGNMENT(gpointer);
+               return sizeof (gpointer);
+       case MONO_NATIVE_STRUCT: 
+               klass = mono_class_from_mono_type (type);
+               return mono_class_native_size (klass, align);
+       case MONO_NATIVE_BYVALTSTR: {
+               int esize = unicode ? 2: 1;
+               g_assert (mspec);
+               *align = esize;
+               return mspec->data.array_data.num_elem * esize;
+       }
+       case MONO_NATIVE_BYVALARRAY: {
+               int esize;
+               klass = mono_class_from_mono_type (type);
+               esize = mono_class_native_size (klass->element_class, align);
+               g_assert (mspec);
+               return mspec->data.array_data.num_elem * esize;
+       }
+       case MONO_NATIVE_CUSTOM:
+               g_assert_not_reached ();
+               break;
+       case MONO_NATIVE_CURRENCY:
+       case MONO_NATIVE_VBBYREFSTR:
+       default:
+               g_error ("native type %02x not implemented", native_type); 
+               break;
+       }
+       g_assert_not_reached ();
+       return 0;
+}
+