2003-11-16 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / marshal.c
index 0094b00484e8ed22c232bf0317dffd28339b0cd2..3ad6001f79d781667f26da3062543d084b9ce263 100644 (file)
@@ -19,6 +19,7 @@
 #include "mono/metadata/threadpool.h"
 #include "mono/metadata/monitor.h"
 #include <string.h>
+#include <errno.h>
 
 //#define DEBUG_RUNTIME_CODE
 
@@ -79,6 +80,11 @@ static MonoDisHelper marshal_dh = {
 /* 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)
 {
@@ -87,6 +93,8 @@ mono_marshal_init (void)
        if (!module_initialized) {
                module_initialized = TRUE;
                InitializeCriticalSection (&marshal_mutex);
+               wrapper_hash = mono_g_hash_table_new (NULL, NULL);
+               last_error_tls_id = TlsAlloc ();
        }
 }
 
@@ -512,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)
 {
@@ -535,25 +553,24 @@ 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);
        
 }
@@ -573,16 +590,26 @@ emit_ptr_to_str_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv con
 {
        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;
@@ -681,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 ();
@@ -708,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:
@@ -831,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 ();
@@ -849,6 +883,9 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
 
        info = mono_marshal_load_type_info (klass);
 
+       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);
@@ -916,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);
@@ -1121,6 +1159,7 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key,
                /* This does not acquire any locks */
                res = mono_mb_create_method (mb, sig, max_stack);
                g_hash_table_insert (cache, key, res);
+               mono_g_hash_table_insert (wrapper_hash, res, key);
        }
        else
                /* Somebody created it before us */
@@ -1130,6 +1169,26 @@ mono_mb_create_and_cache (GHashTable *cache, gpointer key,
        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)
 {
@@ -1921,6 +1980,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
        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);
@@ -1929,10 +1990,18 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
        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);
@@ -1944,6 +2013,11 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
        /* 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);
 
@@ -1953,6 +2027,14 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
        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) {
 
@@ -2025,6 +2107,63 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                }
 
                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;
@@ -2114,6 +2253,11 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                        }
                        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:
@@ -2147,6 +2291,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
        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:
@@ -2162,7 +2307,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                case MONO_TYPE_I8:
                case MONO_TYPE_U8:
                case MONO_TYPE_OBJECT:
-                       mono_mb_emit_byte (mb, CEE_RET);
+                       mono_mb_emit_byte (mb, CEE_STLOC_3);
                        break;
                case MONO_TYPE_STRING:          
                        csig->ret = &mono_defaults.int_class->byval_arg;
@@ -2170,10 +2315,9 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_byte (mb, CEE_MONO_FUNC1);
                        mono_mb_emit_byte (mb, MONO_MARSHAL_CONV_STR_LPSTR);
-                       mono_mb_emit_byte (mb, CEE_RET);
+                       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)
@@ -2187,21 +2331,51 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                        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:
@@ -2209,6 +2383,66 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                        g_assert_not_reached ();
                }
        } else {
+               mono_mb_emit_byte (mb, CEE_STLOC_3);
+       }
+
+       /* Convert byref arguments back */
+       for (i = 0; i < sig->param_count; i ++) {
+               MonoType *t = sig->params [i];
+
+               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);
        }
 
@@ -2219,6 +2453,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoObject *this, MonoMars
                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;
 }
 
@@ -2533,7 +2769,7 @@ mono_marshal_get_stfld_wrapper (MonoType *type)
 
 /*
  * generates IL code for the icall wrapper (the generated method
- * calls the unamnaged code in func)
+ * calls the unmanaged code in func)
  */
 MonoMethod *
 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func)
@@ -2603,17 +2839,21 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
            (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);
+               mono_mb_emit_exception (mb, "MissingMethodException");
                csig = g_memdup (sig, sigsize);
                csig->pinvoke = 0;
                res = mono_mb_create_and_cache (cache, method,
@@ -2906,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 */
@@ -2930,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:
@@ -2999,6 +3345,17 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        /* call the native method */
        mono_mb_emit_native_call (mb, csig, method->addr);
 
+       /* 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];
@@ -3077,7 +3434,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                        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);
@@ -3288,7 +3645,7 @@ 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]);
 
@@ -3307,11 +3664,73 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                                mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
                        }
 
+                       if (t->attrs & PARAM_ATTRIBUTE_OUT) {
+                               /* FIXME: Optimize blittable case */
+                               MonoClass *eklass;
+                               guint32 label1, label2, label3;
+                               int index_var, src_ptr;
+
+                               eklass = klass->element_class;
+                               src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+                               /* 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_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_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);
 
@@ -3327,6 +3746,8 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
                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;
 }
 
@@ -3637,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)
@@ -3842,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 
@@ -4218,6 +4649,11 @@ mono_type_native_stack_size (MonoType *t, gint *align)
        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)
@@ -4235,6 +4671,7 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align,
                return 1;
        case MONO_NATIVE_I2:
        case MONO_NATIVE_U2:
+       case MONO_NATIVE_VARIANTBOOL:
                *align = 2;
                return 2;
        case MONO_NATIVE_I4:
@@ -4244,13 +4681,13 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align,
                return 4;
        case MONO_NATIVE_I8:
        case MONO_NATIVE_U8:
-               *align = 4;
+               *align = ALIGNMENT(guint64);
                return 8;
        case MONO_NATIVE_R4:
                *align = 4;
                return 4;
        case MONO_NATIVE_R8:
-               *align = 4;
+               *align = ALIGNMENT(double);
                return 8;
        case MONO_NATIVE_INT:
        case MONO_NATIVE_UINT:
@@ -4266,10 +4703,9 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, gint32 *align,
        case MONO_NATIVE_IDISPATCH:
        case MONO_NATIVE_INTERFACE:
        case MONO_NATIVE_ASANY:
-       case MONO_NATIVE_VARIANTBOOL:
        case MONO_NATIVE_FUNC:
        case MONO_NATIVE_LPSTRUCT:
-               *align =  4;
+               *align = ALIGNMENT(gpointer);
                return sizeof (gpointer);
        case MONO_NATIVE_STRUCT: 
                klass = mono_class_from_mono_type (type);