* reflection.c (inflate_mono_method): Reuse method instantiation
[mono.git] / mono / metadata / marshal.c
index 98e60d4ecda8fd60b966d97a8ec8db6ddea9fd23..e6b9b6628bc5326608872431e9d34d2799defef4 100644 (file)
@@ -92,6 +92,8 @@ static GHashTable *wrapper_hash;
 
 static guint32 last_error_tls_id;
 
+static guint32 load_type_info_tls_id;
+
 static void
 delegate_hash_table_add (MonoDelegate *d);
 
@@ -150,7 +152,23 @@ static void
 mono_marshal_set_last_error_windows (int error);
 
 static void
-mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func);
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func);
+
+static void init_safe_handle (void);
+
+/* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
+static MonoMethod *sh_dangerous_add_ref;
+static MonoMethod *sh_dangerous_release;
+
+
+static void
+init_safe_handle ()
+{
+       sh_dangerous_add_ref = mono_class_get_method_from_name (
+               mono_defaults.safehandle_class, "DangerousAddRef", 1);
+       sh_dangerous_release = mono_class_get_method_from_name (
+               mono_defaults.safehandle_class, "DangerousRelease", 0);
+}
 
 static void
 register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
@@ -238,8 +256,12 @@ signature_cominterop (MonoImage *image, MonoMethodSignature *sig)
        // return type is always int32 (HRESULT)
        res->ret = &mono_defaults.int32_class->byval_arg;
 
-       // com is always stdcall
+       // STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
+#ifdef PLATFORM_WIN32
        res->call_convention = MONO_CALL_STDCALL;
+#else
+       res->call_convention = MONO_CALL_C;
+#endif
 
        return res;
 }
@@ -259,6 +281,32 @@ cominterop_get_function_pointer (gpointer itf, int slot)
        return func;
 }
 
+/**
+ * cominterop_object_is_com_object:
+ * @obj: a pointer to the object
+ *
+ * Returns: a value indicating if the object is a
+ * Runtime Callable Wrapper (RCW) for a COM object
+ */
+static gboolean
+cominterop_object_is_rcw (MonoObject *obj)
+{
+       MonoClass *klass = NULL;
+       MonoRealProxy* real_proxy = NULL;
+       if (!obj)
+               return FALSE;
+       klass = mono_object_class (obj);
+       if (klass != mono_defaults.transparent_proxy_class)
+               return FALSE;
+
+       real_proxy = ((MonoTransparentProxy*)obj)->rp;
+       if (!real_proxy)
+               return FALSE;
+
+       klass = mono_object_class (real_proxy);
+       return (klass && klass == mono_defaults.com_interop_proxy_class);
+}
+
 /**
  * cominterop_get_com_slot_for_method:
  * @method: a method
@@ -274,7 +322,7 @@ cominterop_get_com_slot_for_method (MonoMethod* method)
        guint32 offset = 7; 
        guint32 slot = method->slot;
        GPtrArray *ifaces;
-       MonoClass *ic = method->klass;
+       MonoClass *ic = NULL;
        int i;
 
        ifaces = mono_class_get_implemented_interfaces (method->klass);
@@ -291,6 +339,12 @@ cominterop_get_com_slot_for_method (MonoMethod* method)
                g_ptr_array_free (ifaces, TRUE);
        }
 
+       if (!ic)
+               ic = method->klass;
+       
+       g_assert (ic);
+       g_assert (MONO_CLASS_IS_INTERFACE (ic));
+
        if (!interface_type_attribute)
                interface_type_attribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "InterfaceTypeAttribute");
        cinfo = mono_custom_attrs_from_class (ic);
@@ -318,7 +372,8 @@ static MonoReflectionType*
 cominterop_get_method_interface (MonoMethod* method)
 {
        GPtrArray *ifaces;
-       MonoClass *ic = method->klass;
+       MonoType* t = NULL;
+       MonoClass *ic = NULL;
        int i;
        MonoReflectionType* rt = NULL;
 
@@ -335,10 +390,14 @@ cominterop_get_method_interface (MonoMethod* method)
                g_ptr_array_free (ifaces, TRUE);
        }
 
-       if (ic) {
-               MonoType* t = mono_class_get_type (ic);
-               rt = mono_type_get_object (mono_domain_get(), t);
-       }
+       if (!ic)
+               ic = method->klass;
+
+       g_assert (ic);
+       g_assert (MONO_CLASS_IS_INTERFACE (ic));
+
+       t = mono_class_get_type (ic);
+       rt = mono_type_get_object (mono_domain_get(), t);
 
        return rt;
 }
@@ -353,6 +412,7 @@ mono_marshal_init (void)
                InitializeCriticalSection (&marshal_mutex);
                wrapper_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
                last_error_tls_id = TlsAlloc ();
+               load_type_info_tls_id = TlsAlloc ();
 
                register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
                register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
@@ -401,6 +461,7 @@ mono_marshal_init (void)
                register_icall (mono_gc_wbarrier_generic_store, "wb_generic", "void ptr object", FALSE);
                register_icall (cominterop_get_method_interface, "cominterop_get_method_interface", "object ptr", FALSE);
                register_icall (cominterop_get_function_pointer, "cominterop_get_function_pointer", "ptr ptr int32", FALSE);
+               register_icall (cominterop_object_is_rcw, "cominterop_object_is_rcw", "int32 object", FALSE);
        }
 }
 
@@ -408,6 +469,7 @@ void
 mono_marshal_cleanup (void)
 {
        g_hash_table_destroy (wrapper_hash);
+       TlsFree (load_type_info_tls_id);
        TlsFree (last_error_tls_id);
        DeleteCriticalSection (&marshal_mutex);
 }
@@ -477,7 +539,7 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
        // Add the delegate to the delegate hash table
        delegate_hash_table_add (delegate);
 
-       /* when the object is collected, collect the dunamic method, too */
+       /* when the object is collected, collect the dynamic method, too */
        mono_object_register_finalizer ((MonoObject*)delegate);
 
        return delegate->delegate_trampoline;
@@ -560,7 +622,7 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                sig = mono_metadata_signature_dup (mono_method_signature (invoke));
                sig->hasthis = 0;
 
-               wrapper = mono_marshal_get_native_func_wrapper (sig, &piinfo, mspecs, ftn);
+               wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn);
 
                for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
                        if (mspecs [i])
@@ -662,9 +724,9 @@ mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclas
 
                memcpy (native_arr, as, MIN (strlen (as), elnum));
                g_free (as);
-       }
-       else
+       } else {
                g_assert_not_reached ();
+       }
 }
 
 void
@@ -699,6 +761,10 @@ mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
        g_free (ut);
 }
 
+/*
+ * FIXME: This routine does not seem to do what it seems to do
+ * the @text is never copied into the string builder
+ */
 void
 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
 {
@@ -715,6 +781,16 @@ mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
        sb->length = len;
 }
 
+/**
+ * mono_string_builder_to_utf8:
+ * @sb: the string builder
+ *
+ * Converts to utf8 the contents of the MonoStringBuilder.
+ *
+ * Returns: a utf8 string with the contents of the StringBuilder.
+ *
+ * The return value must be released with g_free.
+ */
 gpointer
 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
 {
@@ -739,9 +815,9 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
        tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, res, &error);
        if (error) {
                g_error_free (error);
+               mono_marshal_free (res);
                mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
-       }
-       else {
+       } else {
                memcpy (res, tmp, sb->length + 1);
                g_free (tmp);
        }
@@ -749,6 +825,16 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
        return res;
 }
 
+/**
+ * mono_string_builder_to_utf16:
+ * @sb: the string builder
+ *
+ * Converts to utf16 the contents of the MonoStringBuilder.
+ *
+ * Returns: a utf16 string with the contents of the StringBuilder.
+ *
+ * The return value must not be freed.
+ */
 gpointer
 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
 {
@@ -800,10 +886,10 @@ mono_string_to_lpstr (MonoString *s)
                g_error_free (error);
                mono_raise_exception(exc);
                return NULL;
-       }
-       else {
+       } else {
                as = CoTaskMemAlloc (len + 1);
                memcpy (as, tmp, len + 1);
+               g_free (tmp);
                return as;
        }
 #else
@@ -822,10 +908,20 @@ gpointer
 mono_string_to_bstr (MonoString *string_obj)
 {
 #ifdef PLATFORM_WIN32
+       if (!string_obj)
+               return NULL;
        return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
 #else
-       g_error ("UnmanagedMarshal.BStr is not implemented.");
-       return NULL;
+       int slen = mono_string_length (string_obj);
+       char *ret = g_malloc (slen * 2 + 4 + 2);
+       if (ret == NULL)
+               return NULL;
+       memcpy (ret + 4, mono_string_chars (string_obj), slen * 2);
+       * ((guint32 *) ret) = slen * 2;
+       ret [4 + slen * 2] = 0;
+       ret [5 + slen * 2] = 0;
+
+       return ret + 4;
 #endif
 }
 
@@ -833,11 +929,11 @@ MonoString *
 mono_string_from_bstr (gpointer bstr)
 {
 #ifdef PLATFORM_WIN32
-       MonoDomain *domain = mono_domain_get ();
-       return mono_string_new_utf16 (domain, bstr, SysStringLen (bstr));
+       if (!bstr)
+               return NULL;
+       return mono_string_new_utf16 (mono_domain_get (), bstr, SysStringLen (bstr));
 #else
-       g_error ("UnmanagedMarshal.BStr is not implemented.");
-       return NULL;
+       return mono_string_new_utf16 (mono_domain_get (), bstr, *(guint32 *)((char *)bstr - 4));
 #endif
 }
 
@@ -847,10 +943,19 @@ mono_free_bstr (gpointer bstr)
 #ifdef PLATFORM_WIN32
        SysFreeString ((BSTR)bstr);
 #else
-       g_error ("Free BSTR is not implemented.");
+       g_free (((char *)bstr) - 4);
 #endif
 }
 
+/**
+ * mono_string_to_byvalstr:
+ * @dst: Where to store the null-terminated utf8 decoded string.
+ * @src: the MonoString to copy.
+ * @size: the maximum number of bytes to copy.
+ *
+ * Copies the MonoString pointed to by @src as a utf8 string
+ * into @dst, it copies at most @size bytes into the destination.
+ */
 void
 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
 {
@@ -861,18 +966,27 @@ mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
        g_assert (size > 0);
 
        memset (dst, 0, size);
-       
        if (!src)
                return;
 
        s = mono_string_to_utf8 (src);
        len = MIN (size, strlen (s));
+       if (len >= size)
+               len--;
        memcpy (dst, s, len);
        g_free (s);
-
-       *((char *)dst + size - 1) = 0;
 }
 
+/**
+ * mono_string_to_byvalwstr:
+ * @dst: Where to store the null-terminated utf16 decoded string.
+ * @src: the MonoString to copy.
+ * @size: the maximum number of bytes to copy.
+ *
+ * Copies the MonoString pointed to by @src as a utf16 string into
+ * @dst, it copies at most @size bytes into the destination (including
+ * a terminating 16-bit zero terminator).
+ */
 void
 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
 {
@@ -887,9 +1001,10 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
        }
 
        len = MIN (size, (mono_string_length (src)));
-       memcpy (dst, mono_string_chars (src), len * 2);
-
-       *((gunichar2 *)dst + len - 1) = 0;
+       memcpy (dst, mono_string_chars (src), size * 2);
+       if (size <= mono_string_length (src))
+               len--;
+       *((gunichar2 *) dst + len) = 0;
 }
 
 void
@@ -965,6 +1080,7 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in
 
        mp = mb->method->klass->image->mempool;
 
+       mono_loader_lock ();
        if (mb->dynamic) {
                method = mb->method;
 
@@ -1037,6 +1153,7 @@ mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, in
        printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
 #endif
 
+       mono_loader_unlock ();
        return method;
 }
 
@@ -1698,6 +1815,69 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
        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_OBJECT_INTERFACE:
+       case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
+       case MONO_MARSHAL_CONV_OBJECT_IDISPATCH: {
+               static MonoClass* com_interop_proxy_class = NULL;
+               static MonoMethod* com_interop_proxy_get_proxy = NULL;
+               static MonoMethod* get_transparent_proxy = NULL;
+               int real_proxy;
+               guint32 pos_failed = 0;
+               MonoClass *klass = mono_class_from_mono_type (type);
+
+               mono_mb_emit_ldloc (mb, 1);
+               mono_mb_emit_byte (mb, CEE_LDNULL);
+               mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+               mono_mb_emit_ldloc (mb, 0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+               if (!com_interop_proxy_class)
+                       com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+               if (!com_interop_proxy_get_proxy)
+                       com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
+               if (!get_transparent_proxy)
+                       get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+               real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
+
+               mono_mb_emit_ldloc (mb, 0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
+               mono_mb_emit_icall (mb, type_from_handle);
+               mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
+               mono_mb_emit_stloc (mb, real_proxy);
+
+               
+               mono_mb_emit_ldloc (mb, 1);
+               mono_mb_emit_ldloc (mb, real_proxy);
+               mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
+               if (klass && klass != mono_defaults.object_class)
+                       mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+               mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+               // case if null
+               mono_mb_patch_short_branch (mb, pos_failed);
+               break;
+       }
+
+       case MONO_MARSHAL_CONV_SAFEHANDLE: {
+               /*
+                * Passing SafeHandles as ref does not allow the unmanaged code
+                * to change the SafeHandle value.   If the value is changed,
+                * we should issue a diagnostic exception (NotSupportedException)
+                * that informs the user that changes to handles in unmanaged code
+                * is not supported. 
+                *
+                * Since we currently have no access to the original
+                * SafeHandle that was used during the marshalling,
+                * for now we just ignore this, and ignore/discard any
+                * changes that might have happened to the handle.
+                */
+               break;
+       }
+               
        case MONO_MARSHAL_CONV_STR_BSTR:
        case MONO_MARSHAL_CONV_STR_ANSIBSTR:
        case MONO_MARSHAL_CONV_STR_TBSTR:
@@ -1838,7 +2018,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
 
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
-               pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+               pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
                if (eklass->blittable) {
                        mono_mb_emit_ldloc (mb, 1);
@@ -1907,7 +2087,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                        mono_mb_emit_stloc (mb, 1);
                }
 
-               mono_mb_patch_short_branch (mb, pos);
+               mono_mb_patch_branch (mb, pos);
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
@@ -1932,7 +2112,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_I);
-               pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+               pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
                
                /* save the old src pointer */
                mono_mb_emit_ldloc (mb, 0);
@@ -1957,7 +2137,117 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, dst_var);
                mono_mb_emit_stloc (mb, 1);
 
-               mono_mb_patch_short_branch (mb, pos);
+               mono_mb_patch_branch (mb, pos);
+               break;
+       }
+       case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
+       case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
+       case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN: {
+               guint32 pos_failed = 0, pos_rcw = 0;
+               char * msg;
+
+               mono_mb_emit_ldloc (mb, 1);
+               //mono_mb_emit_ldloc (mb, 0);
+               mono_mb_emit_ptr (mb, 0);
+               //mono_mb_emit_byte (mb, CEE_LDIND_U1);
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+
+               mono_mb_emit_ldloc (mb, 0);     
+               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+               // if null just break, dst was already inited to 0
+               pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+               mono_mb_emit_ldloc (mb, 0);     
+               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+               mono_mb_emit_icall (mb, cominterop_object_is_rcw);
+               pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+               // load dst to store later
+               mono_mb_emit_ldloc (mb, 1);
+
+               // load src
+               mono_mb_emit_ldloc (mb, 0);     
+               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
+               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+               /* load the RCW from the ComInteropProxy*/
+               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
+               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+               if (conv == MONO_MARSHAL_CONV_OBJECT_INTERFACE) {
+                       static MonoMethod* GetInterface = NULL;
+                       
+                       if (!GetInterface)
+                               GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+                       mono_mb_emit_ptr (mb, type);
+                       mono_mb_emit_icall (mb, type_from_handle);
+                       mono_mb_emit_managed_call (mb, GetInterface, NULL);
+               }
+               else if (conv == MONO_MARSHAL_CONV_OBJECT_IUNKNOWN) {
+                       static MonoProperty* iunknown = NULL;
+                       
+                       if (!iunknown)
+                               iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
+                       mono_mb_emit_managed_call (mb, iunknown->get, NULL);
+               }
+               else if (conv == MONO_MARSHAL_CONV_OBJECT_IDISPATCH) {
+                       static MonoProperty* idispatch = NULL;
+                       
+                       if (!idispatch)
+                               idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
+                       mono_mb_emit_managed_call (mb, idispatch->get, NULL);
+               }
+               else {
+               }
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+               
+               // if not rcw
+               mono_mb_patch_short_branch (mb, pos_rcw);
+               msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+
+               // case if null
+               mono_mb_patch_short_branch (mb, pos_failed);
+               break;
+       }
+
+       case MONO_MARSHAL_CONV_SAFEHANDLE: {
+               int dar_release_slot, pos;
+               
+               dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+
+               /*
+                * The following is ifdefed-out, because I have no way of doing the
+                * DangerousRelease when destroying the structure
+                */
+#if 0
+               /* set release = false */
+               mono_mb_emit_icon (mb, 0);
+               mono_mb_emit_stloc (mb, dar_release_slot);
+               if (!sh_dangerous_add_ref)
+                       init_safe_handle ();
+
+               /* safehandle.DangerousAddRef (ref release) */
+               mono_mb_emit_ldloc (mb, 0); /* the source */
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_ldloc_addr (mb, dar_release_slot);
+               mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
+#endif
+               mono_mb_emit_ldloc (mb, 0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+               mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
+               mono_mb_patch_branch (mb, pos);
+               
+               /* Pull the handle field from SafeHandle */
+               mono_mb_emit_ldloc (mb, 1);
+               mono_mb_emit_ldloc (mb, 0);
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_byte (mb, CEE_STIND_I);
                break;
        }
        default: {
@@ -2019,18 +2309,26 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                        usize = info->fields [i + 1].offset - info->fields [i].offset;
                }
 
-               /* 
-                * FIXME: Should really check for usize==0 and msize>0, but we apply 
-                * the layout to the managed structure as well.
-                */
-               if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
-                       if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) || ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
-                       g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a reference field at the same offset as another field.", mono_type_full_name (&klass->byval_arg));
+               if (klass != mono_defaults.safehandle_class){
+                       /* 
+                        * FIXME: Should really check for usize==0 and msize>0, but we apply 
+                        * the layout to the managed structure as well.
+                        */
+                       
+                       if (((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) && (usize == 0)) {
+                               if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
+                                   ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
+                                       g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
+                                                "reference field at the same offset as another field.",
+                                                mono_type_full_name (&klass->byval_arg));
+                       }
+                       
+                       if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
+                               g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute",
+                                        mono_type_full_name (&klass->byval_arg));
+                       
                }
-
-               if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT)
-                       g_error ("Type %s which is passed to unmanaged code must have a StructLayout attribute", mono_type_full_name (&klass->byval_arg));
-
+               
                switch (conv) {
                case MONO_MARSHAL_CONV_NONE: {
                        int t;
@@ -2093,8 +2391,37 @@ emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
                                mono_mb_emit_stloc (mb, 1);
                                break;
                        }
+                       case MONO_TYPE_OBJECT: {
+                               if (to_object) {
+                                       static MonoMethod *variant_clear = NULL;
+                                       static MonoMethod *get_object_for_native_variant = NULL;
+                                       if (!variant_clear)
+                                               variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
+                                       if (!get_object_for_native_variant)
+                                               get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
+                                       mono_mb_emit_ldloc (mb, 1);
+                                       mono_mb_emit_ldloc (mb, 0);
+                                       mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+                                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+                                       mono_mb_emit_ldloc (mb, 0);
+                                       mono_mb_emit_managed_call (mb, variant_clear, NULL);
+                               }
+                               else {
+                                       static MonoMethod *get_native_variant_for_object = NULL;
+
+                                       if (!get_native_variant_for_object)
+                                               get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+
+                                       mono_mb_emit_ldloc (mb, 0);
+                                       mono_mb_emit_byte(mb, CEE_LDIND_REF);
+                                       mono_mb_emit_ldloc (mb, 1);
+                                       mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+                                       }
+                               break;
+                       }
 
-                       default:
+                       default: 
                                g_warning ("marshaling type %02x not implemented", ftype->type);
                                g_assert_not_reached ();
                        }
@@ -2208,6 +2535,7 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
 
                        msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state);
                        handle = CreateEvent (NULL, TRUE, FALSE, NULL);
+                       g_assert(handle != NULL);
                        ares = mono_async_result_new (mono_domain_get (), handle, state, handle, NULL);
                        MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
                        MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
@@ -2629,6 +2957,12 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
        ares = mono_array_get (msg->args, gpointer, sig->param_count - 1);
        g_assert (ares);
 
+       if (ares->async_delegate != delegate && mono_get_runtime_info ()->framework_version [0] >= '2') {
+               mono_raise_exception (mono_get_exception_invalid_operation (
+                       "The IAsyncResult object provided does not match this delegate."));
+               return NULL;
+       }
+
        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);
@@ -2636,9 +2970,9 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
                msg->call_type = CallType_EndInvoke;
                MONO_OBJECT_SETREF (msg, async_result, ares);
                res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
-       }
-       else
+       } else {
                res = mono_thread_pool_finish (ares, &out_args, &exc);
+       }
 
        if (exc) {
                if (((MonoException*)exc)->stack_trace) {
@@ -2849,7 +3183,7 @@ cominterop_get_native_wrapper_adjusted (MonoMethod *method)
 
        mspecs[0] = NULL;
 
-       mono_marshal_emit_native_wrapper(mb_native, sig_native, piinfo, mspecs, piinfo->addr);
+       mono_marshal_emit_native_wrapper(mono_defaults.corlib, mb_native, sig_native, piinfo, mspecs, piinfo->addr);
 
        mono_loader_lock ();
        mono_marshal_lock ();
@@ -3138,9 +3472,6 @@ mono_get_xdomain_marshal_type (MonoType *t)
        }
        }
 
-       if (mono_class_from_mono_type (t) == mono_defaults.stringbuilder_class)
-               return MONO_MARSHAL_COPY;
-       
        return MONO_MARSHAL_SERIALIZE;
 }
 
@@ -3947,14 +4278,14 @@ mono_marshal_get_remoting_invoke_with_check (MonoMethod *method)
        if (method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)
                return method;
 
-       sig = signature_no_pinvoke (method);
-       
        /* we cant remote methods without this pointer */
-       g_assert (sig->hasthis);
+       g_assert (mono_method_signature (method)->hasthis);
 
        if ((res = mono_marshal_remoting_find_in_cache (method, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)))
                return res;
 
+       sig = signature_no_pinvoke (method);
+       
        mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK);
 
        for (i = 0; i <= sig->param_count; i++)
@@ -4038,14 +4369,18 @@ mono_marshal_get_delegate_invoke (MonoMethod *method)
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
        mono_mb_emit_byte (mb, CEE_LDIND_REF);
-       mono_mb_emit_stloc (mb, 0);
 
        /* if prev != null */
-       mono_mb_emit_ldloc (mb, 0);
        pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
        /* then recurse */
-       mono_mb_emit_ldloc (mb, 0);
+
+       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+       mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
+
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoMulticastDelegate, prev));
+       mono_mb_emit_byte (mb, CEE_LDIND_REF);
        for (i = 0; i < sig->param_count; i++)
                mono_mb_emit_ldarg (mb, i + 1);
        mono_mb_emit_managed_call (mb, method, mono_method_signature (method));
@@ -4150,8 +4485,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
 
        g_assert (method);
 
-       target_klass = method->klass;
-       
        mono_marshal_lock ();
 
        if (method->string_ctor) {
@@ -4186,7 +4519,22 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
                }
        }
 
-       cache = method->klass->image->runtime_invoke_cache;
+       target_klass = mono_defaults.object_class;
+       /* 
+        * if types in the signature belong to non-mscorlib, we cache only
+        * in the method image
+        */
+       if (mono_class_from_mono_type (callsig->ret)->image != mono_defaults.corlib) {
+               target_klass = method->klass;
+       } else {
+               for (i = 0; i < callsig->param_count; i++) {
+                       if (mono_class_from_mono_type (callsig->params [i])->image != mono_defaults.corlib) {
+                               target_klass = method->klass;
+                               break;
+                       }
+               }
+       }
+       cache = target_klass->image->runtime_invoke_cache;
 
        /* from mono_marshal_find_in_cache */
        res = g_hash_table_lookup (cache, callsig);
@@ -4202,8 +4550,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
                dealy_abort_sig->pinvoke = 0;
        }
        
-       target_klass = mono_defaults.object_class;
-
        /* to make it work with our special string constructors */
        if (!string_dummy) {
                MONO_GC_REGISTER_ROOT (string_dummy);
@@ -4299,7 +4645,7 @@ handle_enum:
 
                        /* fall through */
                case MONO_TYPE_VALUETYPE:
-                       if (t->data.klass->enumtype) {
+                       if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) {
                                type = t->data.klass->enum_basetype->type;
                                goto handle_enum;
                        }
@@ -4975,13 +5321,38 @@ typedef struct {
        int retobj_var;
        MonoClass *retobj_class;
        MonoMethodSignature *csig; /* Might need to be changed due to MarshalAs directives */
+       MonoImage *image; /* The image to use for looking up custom marshallers */
 } EmitMarshalContext;
 
 typedef enum {
+       /*
+        * This is invoked to convert arguments from the current types to
+        * the underlying types expected by the platform routine.  If required,
+        * the methods create a temporary variable with the proper type, and return
+        * the location for it (either the passed argument, or the newly allocated
+        * local slot).
+        */
        MARSHAL_ACTION_CONV_IN,
+
+       /*
+        * This operation is called to push the actual value that was optionally
+        * converted on the first stage
+        */
        MARSHAL_ACTION_PUSH,
+
+       /*
+        * Convert byref arguments back or free resources allocated during the
+        * CONV_IN stage
+        */
        MARSHAL_ACTION_CONV_OUT,
+
+       /*
+        * The result from the unmanaged call is at the top of the stack when
+        * this action is invoked.    The result should be stored in the
+        * third local variable slot. 
+        */
        MARSHAL_ACTION_CONV_RESULT,
+
        MARSHAL_ACTION_MANAGED_CONV_IN,
        MARSHAL_ACTION_MANAGED_CONV_OUT,
        MARSHAL_ACTION_MANAGED_CONV_RESULT
@@ -5018,7 +5389,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
                g_assert (marshal_native_to_managed);
        }
 
-       mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, mb->method->klass->image);
+       mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
        g_assert (mtype != NULL);
        mklass = mono_class_from_mono_type (mtype);
        g_assert (mklass != NULL);
@@ -5088,6 +5459,10 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
                if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
                        break;
 
+               /* Minic MS.NET behavior */
+               if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
+                       break;
+
                /* Check for null */
                mono_mb_emit_ldarg (mb, argnum);
                if (t->byref)
@@ -5133,6 +5508,16 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldloc (mb, conv_arg);
                        mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
                        mono_mb_emit_byte (mb, CEE_STIND_REF);
+               } else if (t->attrs &PARAM_ATTRIBUTE_OUT) {
+                       mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
+
+                       mono_mb_emit_op (mb, CEE_CALL, get_instance);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
+
+                       /* We have nowhere to store the result */
+                       mono_mb_emit_byte (mb, CEE_POP);
                }
 
                mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
@@ -5654,111 +6039,186 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
 }
 
 static int
-emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
-                                        MonoMarshalSpec *spec, 
-                                        int conv_arg, MonoType **conv_arg_type, 
-                                        MarshalAction action)
+emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t, 
+                        MonoMarshalSpec *spec, int conv_arg, 
+                        MonoType **conv_arg_type, MarshalAction action)
 {
        MonoMethodBuilder *mb = m->mb;
-       MonoClass *klass = t->data.klass;
-       int pos, pos2, loc;
 
-       if (mono_class_from_mono_type (t) == mono_defaults.object_class && 
-               (!spec || (spec && spec->native != MONO_NATIVE_STRUCT)) &&
-               (!spec || (spec && (spec->native != MONO_NATIVE_IUNKNOWN &&
-                       spec->native != MONO_NATIVE_IDISPATCH &&
-                       spec->native != MONO_NATIVE_INTERFACE)))) {
-               mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
-       }
+       switch (action){
+       case MARSHAL_ACTION_CONV_IN: {
+               MonoType *intptr_type;
+               int dar_release_slot, pos;
 
-       switch (action) {
-       case MARSHAL_ACTION_CONV_IN:
-               *conv_arg_type = &mono_defaults.int_class->byval_arg;
-               conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               intptr_type = &mono_defaults.int_class->byval_arg;
+               conv_arg = mono_mb_add_local (mb, intptr_type);
+               *conv_arg_type = intptr_type;
 
-               m->orig_conv_args [argnum] = 0;
+               if (!sh_dangerous_add_ref)
+                       init_safe_handle ();
 
-               if (spec && spec->native == MONO_NATIVE_STRUCT)
-               {
-                       static MonoMethod *get_native_variant_for_object = NULL;
-                       int local_variant;
-                       if (!get_native_variant_for_object)
-                               get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+               mono_mb_emit_ldarg (mb, argnum);
+               pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
+               mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
+               
+               mono_mb_patch_branch (mb, pos);
+               if (t->byref){
+                       /*
+                        * My tests in show that ref SafeHandles are not really
+                        * passed as ref objects.  Instead a NULL is passed as the
+                        * value of the ref
+                        */
+                       mono_mb_emit_icon (mb, 0);
+                       mono_mb_emit_stloc (mb, conv_arg);
+                       break;
+               } 
 
-                       *conv_arg_type = &mono_defaults.variant_class->byval_arg;
+               /* Create local to hold the ref parameter to DangerousAddRef */
+               dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
 
-                       local_variant = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
-                       conv_arg = local_variant;
-                       mono_mb_emit_ldarg (mb, argnum);
-                       if (t->byref)
-                               mono_mb_emit_byte(mb, CEE_LDIND_REF);
-                       mono_mb_emit_ldloc_addr (mb, local_variant);
-                       mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
-               }
-               else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
-                       spec->native == MONO_NATIVE_IDISPATCH ||
-                       spec->native == MONO_NATIVE_INTERFACE)) {
-                       mono_mb_emit_ptr (mb, 0);
-                       mono_mb_emit_stloc (mb, conv_arg);
+               /* set release = false; */
+               mono_mb_emit_icon (mb, 0);
+               mono_mb_emit_stloc (mb, dar_release_slot);
 
-                       if (t->byref) {
-                               /* we dont need any conversions for out parameters */
-                               if (t->attrs & PARAM_ATTRIBUTE_OUT)
-                                       break;
-                               else {
-                                       char *msg = g_strdup_printf ("non out object references are no implemented");
-                                       MonoException *exc = mono_get_exception_not_implemented (msg);
-                                       g_warning (msg);
-                                       g_free (msg);
-                                       mono_raise_exception (exc);
+               /* safehandle.DangerousAddRef (ref release) */
+               mono_mb_emit_ldarg (mb, argnum);
+               mono_mb_emit_ldloc_addr (mb, dar_release_slot);
+               mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
 
-                               }
-                       } else {
-                               guint32 pos_failed = 0;
-                               mono_mb_emit_ldarg (mb, argnum);        
-                               // if null just break, conv arg was already inited to 0
-                               pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
+               /* Pull the handle field from SafeHandle */
+               mono_mb_emit_ldarg (mb, argnum);
+               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_stloc (mb, conv_arg);
 
-                               mono_mb_emit_ldarg (mb, argnum);
-                               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
-                               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+               break;
+       }
 
-                               /* load the RCW from the ComInteropProxy*/
-                               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
-                               mono_mb_emit_byte (mb, CEE_LDIND_REF);
+       case MARSHAL_ACTION_PUSH:
+               if (t->byref)
+                       mono_mb_emit_ldloc_addr (mb, conv_arg);
+               else 
+                       mono_mb_emit_ldloc (mb, conv_arg);
+               break;
 
-                               if (klass && klass != mono_defaults.object_class) {
-                                       static MonoMethod* GetInterface = NULL;
-                                       
-                                       if (!GetInterface)
-                                               GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
-                                       mono_mb_emit_ptr (mb, t);
-                                       mono_mb_emit_icall (mb, type_from_handle);
-                                       mono_mb_emit_managed_call (mb, GetInterface, NULL);
-                               }
-                               else if (spec->native == MONO_NATIVE_IUNKNOWN) {
-                                       static MonoProperty* iunknown = NULL;
-                                       
-                                       if (!iunknown)
-                                               iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
-                                       mono_mb_emit_managed_call (mb, iunknown->get, NULL);
-                               }
-                               else if (spec->native == MONO_NATIVE_IDISPATCH) {
-                                       static MonoProperty* idispatch = NULL;
-                                       
-                                       if (!idispatch)
-                                               idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
-                                       mono_mb_emit_managed_call (mb, idispatch->get, NULL);
-                               }
-                               else {
-                               }
-                               mono_mb_emit_stloc (mb, conv_arg);
-                               
-                               // case if null
-                               mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
+       case MARSHAL_ACTION_CONV_OUT: {
+               /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
+               int dar_release_slot = conv_arg + 1;
+               int label_next;
+
+               if (!sh_dangerous_release)
+                       init_safe_handle ();
+
+               if (t->byref){
+                       MonoMethod *ctor;
+                       
+                       /*
+                        * My tests indicate that ref SafeHandles parameters are not actually
+                        * passed by ref, but instead a new Handle is created regardless of
+                        * whether a change happens in the unmanaged side.
+                        *
+                        * Also, the Handle is created before calling into unmanaged code,
+                        * but we do not support that mechanism (getting to the original
+                        * handle) and it makes no difference where we create this
+                        */
+                       ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
+                       if (ctor == NULL){
+                               mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
+                               break;
                        }
+                       /* refval = new SafeHandleDerived ()*/
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
+                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+                       /* refval.handle = returned_handle */
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, CEE_LDIND_REF);
+                       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_byte (mb, CEE_STIND_I);
+               } else {
+                       mono_mb_emit_ldloc (mb, dar_release_slot);
+                       label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
+                       mono_mb_patch_addr (mb, label_next, mb->pos - (label_next + 4));
                }
-               else if (klass->delegate) {
+               break;
+       }
+               
+       case MARSHAL_ACTION_CONV_RESULT: {
+               MonoMethod *ctor = NULL;
+               int intptr_handle_slot;
+               
+               if (t->data.klass->flags & TYPE_ATTRIBUTE_ABSTRACT){
+                       mono_mb_emit_byte (mb, CEE_POP);
+                       mono_mb_emit_exception_marshal_directive (mb, "Returned SafeHandles should not be abstract");
+                       break;
+               }
+
+               ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
+               if (ctor == NULL){
+                       mono_mb_emit_byte (mb, CEE_POP);
+                       mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
+                       break;
+               }
+               /* Store the IntPtr results into a local */
+               intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               mono_mb_emit_stloc (mb, intptr_handle_slot);
+
+               /* Create return value */
+               mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
+               mono_mb_emit_stloc (mb, 3);
+
+               /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
+               mono_mb_emit_ldloc (mb, 3);
+               mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoSafeHandle, handle));
+               mono_mb_emit_ldloc (mb, intptr_handle_slot);
+               mono_mb_emit_byte (mb, CEE_STIND_I);
+               break;
+       }
+               
+       case MARSHAL_ACTION_MANAGED_CONV_IN:
+               fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
+               break;
+               
+       case MARSHAL_ACTION_MANAGED_CONV_OUT:
+               fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
+               break;
+
+       case MARSHAL_ACTION_MANAGED_CONV_RESULT:
+               fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
+               break;
+       default:
+               printf ("Unhandled case for MarshalAction: %d\n", action);
+       }
+
+       return conv_arg;
+}
+
+static int
+emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
+                    MonoMarshalSpec *spec, 
+                    int conv_arg, MonoType **conv_arg_type, 
+                    MarshalAction action)
+{
+       MonoMethodBuilder *mb = m->mb;
+       MonoClass *klass = t->data.klass;
+       int pos, pos2, loc;
+
+       if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
+               mono_raise_exception (mono_get_exception_not_implemented ("Marshalling of type object is not implemented"));
+       }
+
+       switch (action) {
+       case MARSHAL_ACTION_CONV_IN:
+               *conv_arg_type = &mono_defaults.int_class->byval_arg;
+               conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+               m->orig_conv_args [argnum] = 0;
+               
+               if (klass->delegate) {
                        g_assert (!t->byref);
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
@@ -5782,9 +6242,17 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
 
                        mono_mb_emit_stloc (mb, conv_arg);
                } else if (klass->blittable) {
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+                       mono_mb_emit_stloc (mb, conv_arg);
+
+                       mono_mb_emit_ldarg (mb, argnum);
+                       pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_ldflda (mb, sizeof (MonoObject));
                        mono_mb_emit_stloc (mb, conv_arg);
+
+                       mono_mb_patch_branch (mb, pos);
                        break;
                } else {
                        mono_mb_emit_byte (mb, CEE_LDNULL);
@@ -5839,70 +6307,6 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                break;
 
        case MARSHAL_ACTION_CONV_OUT:
-               if (spec && spec->native == MONO_NATIVE_STRUCT) {
-                       static MonoMethod *variant_clear = NULL;
-                       static MonoMethod *get_object_for_native_variant = NULL;
-                       if (!variant_clear)
-                               variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
-                       if (!get_object_for_native_variant)
-                               get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
-                       if (t->byref) {
-                               mono_mb_emit_ldarg (mb, argnum);
-                               mono_mb_emit_ldloc_addr (mb, conv_arg);
-                               mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
-                               mono_mb_emit_byte (mb, CEE_STIND_REF);
-                       }
-
-                       mono_mb_emit_ldloc_addr (mb, conv_arg);
-                       mono_mb_emit_managed_call (mb, variant_clear, NULL);
-                       break;
-               }
-
-               if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
-                       spec->native == MONO_NATIVE_IDISPATCH ||
-                       spec->native == MONO_NATIVE_INTERFACE)) {
-                       if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
-                               static MonoClass* com_interop_proxy_class = NULL;
-                               static MonoMethod* com_interop_proxy_get_proxy = NULL;
-                               static MonoMethod* get_transparent_proxy = NULL;
-                               int real_proxy;
-                               guint32 pos_failed = 0;
-
-                               mono_mb_emit_ldarg (mb, argnum);
-                               mono_mb_emit_byte (mb, CEE_LDNULL);
-                               mono_mb_emit_byte (mb, CEE_STIND_REF);
-
-                               mono_mb_emit_ldloc (mb, conv_arg);
-                               pos_failed = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
-                               if (!com_interop_proxy_class)
-                                       com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
-                               if (!com_interop_proxy_get_proxy)
-                                       com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
-                               if (!get_transparent_proxy)
-                                       get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
-
-                               real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
-
-                               mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
-                               mono_mb_emit_icall (mb, type_from_handle);
-                               mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
-                               mono_mb_emit_stloc (mb, real_proxy);
-
-                               
-                               mono_mb_emit_ldarg (mb, argnum);
-                               mono_mb_emit_ldloc (mb, real_proxy);
-                               mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
-                               if (klass && klass != mono_defaults.object_class)
-                                       mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
-                               mono_mb_emit_byte (mb, CEE_STIND_REF);
-
-                               // case if null
-                               mono_mb_patch_addr (mb, pos_failed, mb->pos - (pos_failed + 4));
-                       }
-                               break;
-               }
                if (klass == mono_defaults.stringbuilder_class) {
                        gboolean need_free;
                        MonoMarshalNative encoding;
@@ -6008,11 +6412,6 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldloc (mb, 0);
                        mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
                        mono_mb_emit_stloc (mb, 3);
-               } else if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
-                       spec->native == MONO_NATIVE_IDISPATCH ||
-                       spec->native == MONO_NATIVE_INTERFACE)) {
-                       char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
-                       mono_mb_emit_exception_marshal_directive (mb, msg);
                } else {
                        /* set src */
                        mono_mb_emit_stloc (mb, 0);
@@ -6213,6 +6612,289 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
        return conv_arg;
 }
 
+static int
+emit_marshal_com_interface (EmitMarshalContext *m, int argnum, MonoType *t,
+                    MonoMarshalSpec *spec, 
+                    int conv_arg, MonoType **conv_arg_type, 
+                    MarshalAction action)
+{
+       MonoMethodBuilder *mb = m->mb;
+       MonoClass *klass = t->data.klass;
+
+       switch (action) {
+       case MARSHAL_ACTION_CONV_IN: {
+               *conv_arg_type = &mono_defaults.int_class->byval_arg;
+               conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+               m->orig_conv_args [argnum] = 0;
+
+               mono_mb_emit_ptr (mb, 0);
+               mono_mb_emit_stloc (mb, conv_arg);
+
+               if (t->byref) {
+                       /* we dont need any conversions for out parameters */
+                       if (t->attrs & PARAM_ATTRIBUTE_OUT)
+                               break;
+                       else {
+                               char *msg = g_strdup_printf ("non out object references are no implemented");
+                               MonoException *exc = mono_get_exception_not_implemented (msg);
+                               g_warning (msg);
+                               g_free (msg);
+                               mono_raise_exception (exc);
+
+                       }
+               } else {
+                       char *msg = NULL;
+                       guint32 pos_failed = 0, pos_rcw = 0;
+                       mono_mb_emit_ldarg (mb, argnum);        
+                       // if null just break, conv arg was already inited to 0
+                       pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_icall (mb, cominterop_object_is_rcw);
+                       pos_rcw = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoTransparentProxy, rp));
+                       mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+                       /* load the RCW from the ComInteropProxy*/
+                       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoComInteropProxy, com_object));
+                       mono_mb_emit_byte (mb, CEE_LDIND_REF);
+
+                       if (klass && klass != mono_defaults.object_class) {
+                               static MonoMethod* GetInterface = NULL;
+                               
+                               if (!GetInterface)
+                                       GetInterface = mono_class_get_method_from_name (mono_defaults.com_object_class, "GetInterface", 1);
+                               mono_mb_emit_ptr (mb, t);
+                               mono_mb_emit_icall (mb, type_from_handle);
+                               mono_mb_emit_managed_call (mb, GetInterface, NULL);
+                       }
+                       else if (spec->native == MONO_NATIVE_IUNKNOWN) {
+                               static MonoProperty* iunknown = NULL;
+                               
+                               if (!iunknown)
+                                       iunknown = mono_class_get_property_from_name (mono_defaults.com_object_class, "IUnknown");
+                               mono_mb_emit_managed_call (mb, iunknown->get, NULL);
+                       }
+                       else if (spec->native == MONO_NATIVE_IDISPATCH) {
+                               static MonoProperty* idispatch = NULL;
+                               
+                               if (!idispatch)
+                                       idispatch = mono_class_get_property_from_name (mono_defaults.com_object_class, "IDispatch");
+                               mono_mb_emit_managed_call (mb, idispatch->get, NULL);
+                       }
+                       else {
+                       }
+                       mono_mb_emit_stloc (mb, conv_arg);
+                       
+                       // if not rcw
+                       mono_mb_patch_short_branch (mb, pos_rcw);
+                       msg = g_strdup ("Marshalling of COM Callable Wrappers is not yet implemented.");
+                       mono_mb_emit_exception_marshal_directive (mb, msg);
+
+                       // case if null
+                       mono_mb_patch_short_branch (mb, pos_failed);
+               }
+               break;
+       }
+       
+       case MARSHAL_ACTION_CONV_OUT: {
+               if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
+                       static MonoClass* com_interop_proxy_class = NULL;
+                       static MonoMethod* com_interop_proxy_get_proxy = NULL;
+                       static MonoMethod* get_transparent_proxy = NULL;
+                       int real_proxy;
+                       guint32 pos_failed = 0;
+
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_byte (mb, CEE_LDNULL);
+                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       pos_failed = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
+
+                       if (!com_interop_proxy_class)
+                               com_interop_proxy_class = mono_class_from_name (mono_defaults.corlib, "Mono.Interop", "ComInteropProxy");
+                       if (!com_interop_proxy_get_proxy)
+                               com_interop_proxy_get_proxy = mono_class_get_method_from_name_flags (com_interop_proxy_class, "GetProxy", 2, METHOD_ATTRIBUTE_PRIVATE);
+                       if (!get_transparent_proxy)
+                               get_transparent_proxy = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
+
+                       real_proxy = mono_mb_add_local (mb, &com_interop_proxy_class->byval_arg);
+
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ptr (mb, &mono_defaults.com_object_class->byval_arg);
+                       mono_mb_emit_icall (mb, type_from_handle);
+                       mono_mb_emit_managed_call (mb, com_interop_proxy_get_proxy, NULL);
+                       mono_mb_emit_stloc (mb, real_proxy);
+
+                       
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_ldloc (mb, real_proxy);
+                       mono_mb_emit_managed_call (mb, get_transparent_proxy, NULL);
+                       if (klass && klass != mono_defaults.object_class)
+                               mono_mb_emit_op (mb, CEE_CASTCLASS, klass);
+                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+
+                       // case if null
+                       mono_mb_patch_short_branch (mb, pos_failed);
+               }
+               break;
+       }
+
+       case MARSHAL_ACTION_PUSH:
+               if (t->byref)
+                       mono_mb_emit_ldloc_addr (mb, conv_arg);
+               else
+                       mono_mb_emit_ldloc (mb, conv_arg);
+               break;
+
+       case MARSHAL_ACTION_CONV_RESULT: {
+               char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+               break;
+       }
+
+       case MARSHAL_ACTION_MANAGED_CONV_IN: {
+               char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+               break;
+       }
+
+       case MARSHAL_ACTION_MANAGED_CONV_OUT: {
+               char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+               break;
+       }
+
+       case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
+               char *msg = g_strdup ("Marshalling of COM Objects is not yet implemented.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+               break;
+       }
+
+       default:
+               g_assert_not_reached ();
+       }
+
+       return conv_arg;
+}
+
+static int
+emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
+                    MonoMarshalSpec *spec, 
+                    int conv_arg, MonoType **conv_arg_type, 
+                    MarshalAction action)
+{
+       MonoMethodBuilder *mb = m->mb;
+       static MonoMethod *get_object_for_native_variant = NULL;
+       static MonoMethod *get_native_variant_for_object = NULL;
+       
+       if (!get_object_for_native_variant)
+               get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
+       g_assert (get_object_for_native_variant);
+
+       if (!get_native_variant_for_object)
+               get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
+       g_assert (get_native_variant_for_object);
+
+       switch (action) {
+       case MARSHAL_ACTION_CONV_IN: {
+               conv_arg = mono_mb_add_local (mb, &mono_defaults.variant_class->byval_arg);
+               
+               if (t->byref)
+                       *conv_arg_type = &mono_defaults.variant_class->this_arg;
+               else
+                       *conv_arg_type = &mono_defaults.variant_class->byval_arg;
+
+               if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
+                       break;
+
+               mono_mb_emit_ldarg (mb, argnum);
+               if (t->byref)
+                       mono_mb_emit_byte(mb, CEE_LDIND_REF);
+               mono_mb_emit_ldloc_addr (mb, conv_arg);
+               mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+               break;
+       }
+
+       case MARSHAL_ACTION_CONV_OUT: {
+               static MonoMethod *variant_clear = NULL;
+
+               if (!variant_clear)
+                       variant_clear = mono_class_get_method_from_name (mono_defaults.variant_class, "Clear", 0);
+               g_assert (variant_clear);
+
+
+               if (t->byref) {
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_ldloc_addr (mb, conv_arg);
+                       mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+               }
+
+               mono_mb_emit_ldloc_addr (mb, conv_arg);
+               mono_mb_emit_managed_call (mb, variant_clear, NULL);
+               break;
+       }
+
+       case MARSHAL_ACTION_PUSH:
+               if (t->byref)
+                       mono_mb_emit_ldloc_addr (mb, conv_arg);
+               else
+                       mono_mb_emit_ldloc (mb, conv_arg);
+               break;
+
+       case MARSHAL_ACTION_CONV_RESULT: {
+               char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+               break;
+       }
+
+       case MARSHAL_ACTION_MANAGED_CONV_IN: {
+               conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
+
+               if (t->byref)
+                       *conv_arg_type = &mono_defaults.variant_class->this_arg;
+               else
+                       *conv_arg_type = &mono_defaults.variant_class->byval_arg;
+
+               if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
+                       break;
+
+               if (t->byref)
+                       mono_mb_emit_ldarg (mb, argnum);
+               else
+                       mono_mb_emit_ldarg_addr (mb, argnum);
+               mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
+               mono_mb_emit_stloc (mb, conv_arg);
+               break;
+       }
+
+       case MARSHAL_ACTION_MANAGED_CONV_OUT: {
+               if (t->byref) {
+                       mono_mb_emit_ldloc (mb, conv_arg);
+                       mono_mb_emit_ldarg (mb, argnum);
+                       mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
+               }
+               break;
+       }
+
+       case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
+               char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
+               mono_mb_emit_exception_marshal_directive (mb, msg);
+               break;
+       }
+
+       default:
+               g_assert_not_reached ();
+       }
+
+       return conv_arg;
+}
+
 static int
 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                        MonoMarshalSpec *spec, 
@@ -7062,6 +7744,18 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
                return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
        case MONO_TYPE_CLASS:
        case MONO_TYPE_OBJECT:
+               if (spec && spec->native == MONO_NATIVE_STRUCT)
+                       return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+
+               if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
+                       spec->native == MONO_NATIVE_IDISPATCH ||
+                       spec->native == MONO_NATIVE_INTERFACE))
+                       return emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+
+               if (mono_defaults.safehandle_class != NULL &&
+                   mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
+                       return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+               
                return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
        case MONO_TYPE_ARRAY:
        case MONO_TYPE_SZARRAY:
@@ -7093,6 +7787,7 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
 
 /**
  * mono_marshal_emit_native_wrapper:
+ * @image: the image to use for looking up custom marshallers
  * @sig: The signature of the native function
  * @piinfo: Marshalling information
  * @mspecs: Marshalling information
@@ -7101,7 +7796,7 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
  * generates IL code for the pinvoke wrapper, the generated code calls @func.
  */
 static void
-mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
+mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
 {
        EmitMarshalContext m;
        MonoMethodSignature *csig;
@@ -7117,6 +7812,7 @@ mono_marshal_emit_native_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *si
        csig = signature_dup (mb->method->klass->image, sig);
        csig->pinvoke = 1;
        m.csig = csig;
+       m.image = image;
 
        /* we allocate local for use with emit_struct_conv() */
        /* allocate local 0 (pointer) src_ptr */
@@ -7417,7 +8113,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
        mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
        mono_method_get_marshal_info (method, mspecs);
 
-       mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, piinfo->addr);
+       mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr);
 
        csig = signature_dup (method->klass->image, sig);
        csig->pinvoke = 0;
@@ -7437,6 +8133,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
 
 /**
  * mono_marshal_get_native_func_wrapper:
+ * @image: The image to use for memory allocation and for looking up custom marshallers.
  * @sig: The signature of the function
  * @func: The native function to wrap
  *
@@ -7444,7 +8141,7 @@ mono_marshal_get_native_wrapper (MonoMethod *method)
  * wrapper.
  */
 MonoMethod *
-mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig, 
+mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig, 
                                                                          MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
 {
        MonoMethodSignature *csig;
@@ -7454,7 +8151,7 @@ mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig,
        GHashTable *cache;
        char *name;
 
-       cache = mono_defaults.corlib->native_wrapper_cache;
+       cache = image->native_wrapper_cache;
        if ((res = mono_marshal_find_in_cache (cache, func)))
                return res;
 
@@ -7462,9 +8159,9 @@ mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig,
        mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
        mb->method->save_lmf = 1;
 
-       mono_marshal_emit_native_wrapper (mb, sig, piinfo, mspecs, func);
+       mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func);
 
-       csig = signature_dup (mb->method->klass->image, sig);
+       csig = signature_dup (image, sig);
        csig->pinvoke = 0;
        res = mono_mb_create_and_cache (cache, func,
                                                                        mb, csig, csig->param_count + 16);
@@ -7472,131 +8169,38 @@ mono_marshal_get_native_func_wrapper (MonoMethodSignature *sig,
 
        /* 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 to call managed methods from unmanaged code 
- */
-MonoMethod *
-mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
-{
-       static MonoClass *UnmanagedFunctionPointerAttribute;
-       MonoMethodSignature *sig, *csig, *invoke_sig;
-       MonoMethodBuilder *mb;
-       MonoMethod *res, *invoke;
-       MonoMarshalSpec **mspecs;
-       MonoMethodPInvoke piinfo;
-       GHashTable *cache;
-       int i, *tmp_locals;
-       EmitMarshalContext m;
-
-       g_assert (method != NULL);
-       g_assert (!mono_method_signature (method)->pinvoke);
-
-       /* 
-        * FIXME: Should cache the method+delegate type pair, since the same method
-        * could be called with different delegates, thus different marshalling
-        * options.
-        */
-       cache = method->klass->image->managed_wrapper_cache;
-       if (!this && (res = mono_marshal_find_in_cache (cache, method)))
-               return res;
-
-       invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
-       invoke_sig = mono_method_signature (invoke);
-
-       mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
-       mono_method_get_marshal_info (invoke, mspecs);
-
-       sig = mono_method_signature (method);
-
-       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
-
-       /* allocate local 0 (pointer) src_ptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 1 (pointer) dst_ptr */
-       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-       /* allocate local 2 (boolean) delete_old */
-       mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
-
-       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_icon (mb, 0);
-       mono_mb_emit_stloc (mb, 2);
-
-       /* we copy the signature, so that we can modify it */
-       csig = signature_dup (method->klass->image, sig);
-       csig->hasthis = 0;
-       csig->pinvoke = 1;
-
-       m.mb = mb;
-       m.sig = sig;
-       m.piinfo = NULL;
-       m.retobj_var = 0;
-       m.csig = csig;
-
-#ifdef PLATFORM_WIN32
-       /* 
-        * Under windows, delegates passed to native code must use the STDCALL
-        * calling convention.
-        */
-       csig->call_convention = MONO_CALL_STDCALL;
-#endif
-
-       /* Change default calling convention if needed */
-       /* Why is this a modopt ? */
-       if (invoke_sig->ret && invoke_sig->ret->num_mods) {
-               for (i = 0; i < invoke_sig->ret->num_mods; ++i) {
-                       MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token);
-                       g_assert (cmod_class);
-                       if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
-                               if (!strcmp (cmod_class->name, "CallConvCdecl"))
-                                       csig->call_convention = MONO_CALL_C;
-                               else if (!strcmp (cmod_class->name, "CallConvStdcall"))
-                                       csig->call_convention = MONO_CALL_STDCALL;
-                               else if (!strcmp (cmod_class->name, "CallConvFastcall"))
-                                       csig->call_convention = MONO_CALL_FASTCALL;
-                               else if (!strcmp (cmod_class->name, "CallConvThiscall"))
-                                       csig->call_convention = MONO_CALL_THISCALL;
-                       }
-               }
-       }
-
-       /* Handle the UnmanagedFunctionPointerAttribute */
-       if (!UnmanagedFunctionPointerAttribute)
-               UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
-       /* The attribute is only available in Net 2.0 */
-       if (UnmanagedFunctionPointerAttribute) {
-               MonoReflectionUnmanagedFunctionPointerAttribute *attr;
-               MonoCustomAttrInfo *cinfo;
-
-               /* 
-                * The pinvoke attributes are stored in a real custom attribute so we have to
-                * construct it.
-                */
-               cinfo = mono_custom_attrs_from_class (delegate_klass);
-               if (cinfo) {
-                       attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
-                       if (attr) {
-                               memset (&piinfo, 0, sizeof (piinfo));
-                               m.piinfo = &piinfo;
-                               piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
+       return res;
+}
+                           
+/* FIXME: moving GC */
+static void
+mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, MonoObject* this)
+{
+       MonoMethodSignature *sig, *csig;
+       int i, *tmp_locals;
 
-                               csig->call_convention = attr->call_conv - 1;
-                       }
-                       if (!cinfo->cached)
-                               mono_custom_attrs_free (cinfo);
-               }
+       sig = m->sig;
+       csig = m->csig;
+
+       /* allocate local 0 (pointer) src_ptr */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 1 (pointer) dst_ptr */
+       mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       /* allocate local 2 (boolean) delete_old */
+       mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
+
+       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_icon (mb, 0);
+       mono_mb_emit_stloc (mb, 2);
+
        /* fixme: howto handle this ? */
        if (sig->hasthis) {
                if (this) {
+                       /* FIXME: need a solution for the moving GC here */
                        mono_mb_emit_ptr (mb, this);
                } else {
                        /* fixme: */
@@ -7616,7 +8220,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
                case MONO_TYPE_STRING:
-                       tmp_locals [i] = emit_marshal (&m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
+                       tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
 
                        break;
                default:
@@ -7643,7 +8247,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
        mono_mb_emit_managed_call (mb, method, NULL);
 
        if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
-               emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
+               emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
        }
        else
        if (!sig->ret->byref) { 
@@ -7669,12 +8273,12 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                        break;
                case MONO_TYPE_STRING:
                        csig->ret = &mono_defaults.int_class->byval_arg;
-                       emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
+                       emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
                        break;
                case MONO_TYPE_VALUETYPE:
                case MONO_TYPE_CLASS:
                case MONO_TYPE_SZARRAY:
-                       emit_marshal (&m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
+                       emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
                        break;
                default:
                        g_warning ("return type 0x%02x unknown", sig->ret->type);       
@@ -7690,13 +8294,14 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                MonoMarshalSpec *spec = mspecs [i + 1];
 
                if (spec && spec->native == MONO_NATIVE_CUSTOM) {
-                       emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
+                       emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
                }
                else if (t->byref) {
                        switch (t->type) {
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_VALUETYPE:
-                               emit_marshal (&m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
+                       case MONO_TYPE_OBJECT:
+                               emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
                                break;
                        }
                }
@@ -7706,7 +8311,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                        case MONO_TYPE_SZARRAY:
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_VALUETYPE:
-                               emit_marshal (&m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
+                               emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
                                break;
                        default:
                                g_assert_not_reached ();
@@ -7714,16 +8319,126 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                }
        }
 
-       if (m.retobj_var) {
-               mono_mb_emit_ldloc (mb, m.retobj_var);
+       if (m->retobj_var) {
+               mono_mb_emit_ldloc (mb, m->retobj_var);
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-               mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m.retobj_class);
+               mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
        }
        else {
                if (!MONO_TYPE_IS_VOID(sig->ret))
                        mono_mb_emit_ldloc (mb, 3);
                mono_mb_emit_byte (mb, CEE_RET);
        }
+}
+
+
+/*
+ * generates IL code to call managed methods from unmanaged code 
+ */
+MonoMethod *
+mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, MonoObject *this)
+{
+       static MonoClass *UnmanagedFunctionPointerAttribute;
+       MonoMethodSignature *sig, *csig, *invoke_sig;
+       MonoMethodBuilder *mb;
+       MonoMethod *res, *invoke;
+       MonoMarshalSpec **mspecs;
+       MonoMethodPInvoke piinfo;
+       GHashTable *cache;
+       int i;
+       EmitMarshalContext m;
+
+       g_assert (method != NULL);
+       g_assert (!mono_method_signature (method)->pinvoke);
+
+       /* 
+        * FIXME: Should cache the method+delegate type pair, since the same method
+        * could be called with different delegates, thus different marshalling
+        * options.
+        */
+       cache = method->klass->image->managed_wrapper_cache;
+       if (!this && (res = mono_marshal_find_in_cache (cache, method)))
+               return res;
+
+       invoke = mono_class_get_method_from_name (delegate_klass, "Invoke", mono_method_signature (method)->param_count);
+       invoke_sig = mono_method_signature (invoke);
+
+       mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
+       mono_method_get_marshal_info (invoke, mspecs);
+
+       sig = mono_method_signature (method);
+
+       mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
+
+
+       /* we copy the signature, so that we can modify it */
+       csig = signature_dup (method->klass->image, sig);
+       csig->hasthis = 0;
+       csig->pinvoke = 1;
+
+       m.mb = mb;
+       m.sig = sig;
+       m.piinfo = NULL;
+       m.retobj_var = 0;
+       m.csig = csig;
+       m.image = method->klass->image;
+
+#ifdef PLATFORM_WIN32
+       /* 
+        * Under windows, delegates passed to native code must use the STDCALL
+        * calling convention.
+        */
+       csig->call_convention = MONO_CALL_STDCALL;
+#endif
+
+       /* Change default calling convention if needed */
+       /* Why is this a modopt ? */
+       if (invoke_sig->ret && invoke_sig->ret->num_mods) {
+               for (i = 0; i < invoke_sig->ret->num_mods; ++i) {
+                       MonoClass *cmod_class = mono_class_get (delegate_klass->image, invoke_sig->ret->modifiers [i].token);
+                       g_assert (cmod_class);
+                       if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
+                               if (!strcmp (cmod_class->name, "CallConvCdecl"))
+                                       csig->call_convention = MONO_CALL_C;
+                               else if (!strcmp (cmod_class->name, "CallConvStdcall"))
+                                       csig->call_convention = MONO_CALL_STDCALL;
+                               else if (!strcmp (cmod_class->name, "CallConvFastcall"))
+                                       csig->call_convention = MONO_CALL_FASTCALL;
+                               else if (!strcmp (cmod_class->name, "CallConvThiscall"))
+                                       csig->call_convention = MONO_CALL_THISCALL;
+                       }
+               }
+       }
+
+       /* Handle the UnmanagedFunctionPointerAttribute */
+       if (!UnmanagedFunctionPointerAttribute)
+               UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
+
+       /* The attribute is only available in Net 2.0 */
+       if (UnmanagedFunctionPointerAttribute) {
+               MonoReflectionUnmanagedFunctionPointerAttribute *attr;
+               MonoCustomAttrInfo *cinfo;
+
+               /* 
+                * The pinvoke attributes are stored in a real custom attribute so we have to
+                * construct it.
+                */
+               cinfo = mono_custom_attrs_from_class (delegate_klass);
+               if (cinfo) {
+                       attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr (cinfo, UnmanagedFunctionPointerAttribute);
+                       if (attr) {
+                               memset (&piinfo, 0, sizeof (piinfo));
+                               m.piinfo = &piinfo;
+                               piinfo.piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
+
+                               csig->call_convention = attr->call_conv - 1;
+                       }
+                       if (!cinfo->cached)
+                               mono_custom_attrs_free (cinfo);
+               }
+       }
+
+       mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, this);
 
        if (!this)
                res = mono_mb_create_and_cache (cache, method,
@@ -8420,6 +9135,174 @@ mono_marshal_get_stelemref ()
        return ret;
 }
 
+typedef struct {
+       int rank;
+       int elem_size;
+       MonoMethod *method;
+} ArrayElemAddr;
+
+/* LOCKING: vars accessed under the marshal lock */
+static ArrayElemAddr *elem_addr_cache = NULL;
+static int elem_addr_cache_size = 0;
+static int elem_addr_cache_next = 0;
+
+/**
+ * mono_marshal_get_array_address:
+ * @rank: rank of the array type
+ * @elem_size: size in bytes of an element of an array.
+ *
+ * Returns a MonoMethd that implements the code to get the address
+ * of an element in a multi-dimenasional array of @rank dimensions.
+ * The returned method takes an array as the first argument and then
+ * @rank indexes for the @rank dimensions.
+ */
+MonoMethod*
+mono_marshal_get_array_address (int rank, int elem_size)
+{
+       MonoMethod *ret;
+       MonoMethodBuilder *mb;
+       MonoMethodSignature *sig;
+       int i, bounds, ind, realidx;
+       int branch_pos, *branch_positions;
+       int cached;
+
+       ret = NULL;
+       mono_marshal_lock ();
+       for (i = 0; i < elem_addr_cache_next; ++i) {
+               if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
+                       ret = elem_addr_cache [i].method;
+                       break;
+               }
+       }
+       mono_marshal_unlock ();
+       if (ret)
+               return ret;
+
+       branch_positions = g_new0 (int, rank);
+
+       sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank);
+
+       /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
+       sig->ret = &mono_defaults.int_class->byval_arg;
+       sig->params [0] = &mono_defaults.object_class->byval_arg;
+       for (i = 0; i < rank; ++i) {
+               sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
+       }
+
+       mb = mono_mb_new (mono_defaults.object_class, "ElementAddr", MONO_WRAPPER_MANAGED_TO_MANAGED);
+       
+       bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+       ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+       realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
+
+       /* bounds = array->bounds; */
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, bounds));
+       mono_mb_emit_byte (mb, CEE_LDIND_I);
+       mono_mb_emit_stloc (mb, bounds);
+
+       /* ind is the overall element index, realidx is the partial index in a single dimension */
+       /* ind = idx0 - bounds [0].lower_bound */
+       mono_mb_emit_ldarg (mb, 1);
+       mono_mb_emit_ldloc (mb, bounds);
+       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I4);
+       mono_mb_emit_byte (mb, CEE_SUB);
+       mono_mb_emit_stloc (mb, ind);
+       /* if (ind >= bounds [0].length) goto exeception; */
+       mono_mb_emit_ldloc (mb, ind);
+       mono_mb_emit_ldloc (mb, bounds);
+       mono_mb_emit_icon (mb, G_STRUCT_OFFSET (MonoArrayBounds, length));
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_LDIND_I4);
+       /* note that we use unsigned comparison */
+       branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
+
+       /* For large ranks (> 4?) use a loop n IL later to reduce code size.
+        * We could also decide to ignore the passed elem_size and get it
+        * from the array object, to reduce the number of methods we generate:
+        * the additional cost is 3 memory loads and a non-immediate mul.
+        */
+       for (i = 1; i < rank; ++i) {
+               /* realidx = idxi - bounds [i].lower_bound */
+               mono_mb_emit_ldarg (mb, 1 + i);
+               mono_mb_emit_ldloc (mb, bounds);
+               mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I4);
+               mono_mb_emit_byte (mb, CEE_SUB);
+               mono_mb_emit_stloc (mb, realidx);
+               /* if (realidx >= bounds [i].length) goto exeception; */
+               mono_mb_emit_ldloc (mb, realidx);
+               mono_mb_emit_ldloc (mb, bounds);
+               mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I4);
+               branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
+               /* ind = ind * bounds [i].length + realidx */
+               mono_mb_emit_ldloc (mb, ind);
+               mono_mb_emit_ldloc (mb, bounds);
+               mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + G_STRUCT_OFFSET (MonoArrayBounds, length));
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_byte (mb, CEE_LDIND_I4);
+               mono_mb_emit_byte (mb, CEE_MUL);
+               mono_mb_emit_ldloc (mb, realidx);
+               mono_mb_emit_byte (mb, CEE_ADD);
+               mono_mb_emit_stloc (mb, ind);
+       }
+
+       /* return array->vector + ind * element_size */
+       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoArray, vector));
+       mono_mb_emit_ldloc (mb, ind);
+       mono_mb_emit_icon (mb, elem_size);
+       mono_mb_emit_byte (mb, CEE_MUL);
+       mono_mb_emit_byte (mb, CEE_ADD);
+       mono_mb_emit_byte (mb, CEE_RET);
+
+       /* patch the branches to get here and throw */
+       for (i = 1; i < rank; ++i) {
+               mono_mb_patch_branch (mb, branch_positions [i]);
+       }
+       mono_mb_patch_branch (mb, branch_pos);
+       /* throw exception */
+       mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
+
+       g_free (branch_positions);
+       mono_loader_lock ();
+       ret = mono_mb_create_method (mb, sig, 4);
+       mono_loader_unlock ();
+       mono_mb_free (mb);
+
+       /* cache the result */
+       cached = 0;
+       mono_marshal_lock ();
+       for (i = 0; i < elem_addr_cache_next; ++i) {
+               if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
+                       /* FIXME: free ret */
+                       ret = elem_addr_cache [i].method;
+                       cached = TRUE;
+                       break;
+               }
+       }
+       if (!cached) {
+               if (elem_addr_cache_next >= elem_addr_cache_size) {
+                       int new_size = elem_addr_cache_size + 4;
+                       ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size);
+                       memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr));
+                       g_free (elem_addr_cache);
+                       elem_addr_cache = new_array;
+                       elem_addr_cache_size = new_size;
+               }
+               elem_addr_cache [elem_addr_cache_next].rank = rank;
+               elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
+               elem_addr_cache [elem_addr_cache_next].method = ret;
+       }
+       mono_marshal_unlock ();
+       return ret;
+}
+
 MonoMethod*
 mono_marshal_get_write_barrier (void)
 {
@@ -8548,10 +9431,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *s
        MONO_CHECK_ARG_NULL (src);
        MONO_CHECK_ARG_NULL (dest);
 
-       g_assert (src->obj.vtable->klass->rank == 1);
-       g_assert (start_index >= 0);
-       g_assert (length >= 0);
-       g_assert (start_index + length <= mono_array_length (src));
+       if (src->obj.vtable->klass->rank != 1)
+               mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
+       if (start_index < 0)
+               mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
+       if (length < 0)
+               mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
+       if (start_index + length > mono_array_length (src))
+               mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
 
        element_size = mono_array_element_size (src->obj.vtable->klass);
 
@@ -8573,10 +9460,14 @@ ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer s
        MONO_CHECK_ARG_NULL (src);
        MONO_CHECK_ARG_NULL (dest);
 
-       g_assert (dest->obj.vtable->klass->rank == 1);
-       g_assert (start_index >= 0);
-       g_assert (length >= 0);
-       g_assert (start_index + length <= mono_array_length (dest));
+       if (dest->obj.vtable->klass->rank != 1)
+               mono_raise_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
+       if (start_index < 0)
+               mono_raise_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
+       if (length < 0)
+               mono_raise_exception (mono_get_exception_argument ("length", "Must be >= 0"));
+       if (start_index + length > mono_array_length (dest))
+               mono_raise_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
 
        element_size = mono_array_element_size (dest->obj.vtable->klass);
          
@@ -8722,8 +9613,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr,
                mono_raise_exception (mono_get_exception_argument_null ("ptr"));
                g_assert_not_reached ();
                return NULL;
-       } else
+       } else {
                return mono_string_new_len (mono_domain_get (), ptr, len);
+       }
 }
 
 MonoString *
@@ -8755,8 +9647,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *pt
                mono_raise_exception (mono_get_exception_argument_null ("ptr"));
                g_assert_not_reached ();
                return NULL;
-       } else
+       } else {
                return mono_string_new_utf16 (domain, ptr, len);
+       }
 }
 
 MonoString *
@@ -8775,7 +9668,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString* ptr)
        return mono_string_to_bstr(ptr);
 }
 
-#ifdef  __i386__
+// STDCALL on windows, CDECL everywhere else to work with XPCOM and MainWin COM
+#ifdef  PLATFORM_WIN32
 #ifdef _MSC_VER
 #define STDCALL __stdcall
 #else
@@ -9064,6 +9958,7 @@ mono_struct_delete_old (MonoClass *klass, char *ptr)
                case MONO_MARSHAL_CONV_STR_TBSTR:
                        mono_marshal_free (*(gpointer *)cpos);
                        break;
+
                default:
                        continue;
                }
@@ -9085,8 +9980,6 @@ ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src,
        mono_struct_delete_old (klass, (char *)src);
 }
 
-
-/* FIXME: on win32 we should probably use GlobalAlloc(). */
 void*
 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
 {
@@ -9098,7 +9991,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (int size)
                /* This returns a valid pointer for size 0 on MS.NET */
                size = 4;
 
+#ifdef PLATFORM_WIN32
+       res = GlobalAlloc (GMEM_FIXED, (gulong)size);
+#else
        res = g_try_malloc ((gulong)size);
+#endif
        if (!res)
                mono_gc_out_of_memory ((gulong)size);
 
@@ -9110,7 +10007,11 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
 {
        MONO_ARCH_SAVE_REGS;
 
+#ifdef PLATFORM_WIN32
+       GlobalFree (ptr);
+#else
        g_free (ptr);
+#endif
 }
 
 void*
@@ -9137,6 +10038,18 @@ ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
 #endif
 }
 
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
+{
+       MONO_ARCH_SAVE_REGS;
+
+#ifdef PLATFORM_WIN32
+       return CoTaskMemRealloc (ptr, size);
+#else
+       return g_try_realloc (ptr, (gulong)size);
+#endif
+}
+
 void*
 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
 {
@@ -9232,6 +10145,29 @@ ves_icall_System_ComObject_SetIUnknown (MonoComObject* obj, gpointer pUnk)
        g_hash_table_insert (obj->itf_hash, MONO_IUNKNOWN_INTERFACE_SLOT, pUnk);
 }
 
+/**
+ * mono_marshal_is_loading_type_info:
+ *
+ *  Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
+ * thread.
+ */
+static gboolean
+mono_marshal_is_loading_type_info (MonoClass *klass)
+{
+       GSList *loads_list = TlsGetValue (load_type_info_tls_id);
+
+       return g_slist_find (loads_list, klass) != NULL;
+}
+
+/**
+ * mono_marshal_load_type_info:
+ *
+ *  Initialize klass->marshal_info using information from metadata. This function can
+ * recursively call itself, and the caller is responsible to avoid that by calling 
+ * mono_marshal_is_loading_type_info () beforehand.
+ *
+ * LOCKING: Acquires the loader lock.
+ */
 MonoMarshalType *
 mono_marshal_load_type_info (MonoClass* klass)
 {
@@ -9241,6 +10177,7 @@ mono_marshal_load_type_info (MonoClass* klass)
        MonoClassField* field;
        gpointer iter;
        guint32 layout;
+       GSList *loads_list;
 
        g_assert (klass != NULL);
 
@@ -9249,6 +10186,22 @@ mono_marshal_load_type_info (MonoClass* klass)
 
        if (!klass->inited)
                mono_class_init (klass);
+
+       mono_loader_lock ();
+
+       if (klass->marshal_info) {
+               mono_loader_unlock ();
+               return klass->marshal_info;
+       }
+
+       /*
+        * This function can recursively call itself, so we keep the list of classes which are
+        * under initialization in a TLS list.
+        */
+       g_assert (!mono_marshal_is_loading_type_info (klass));
+       loads_list = TlsGetValue (load_type_info_tls_id);
+       loads_list = g_slist_prepend (loads_list, klass);
+       TlsSetValue (load_type_info_tls_id, loads_list);
        
        iter = NULL;
        while ((field = mono_class_get_fields (klass, &iter))) {
@@ -9261,7 +10214,8 @@ mono_marshal_load_type_info (MonoClass* klass)
 
        layout = klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK;
 
-       klass->marshal_info = info = g_malloc0 (sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
+       /* The mempool is protected by the loader lock */
+       info = mono_mempool_alloc0 (klass->image->mempool, sizeof (MonoMarshalType) + sizeof (MonoMarshalField) * count);
        info->num_fields = count;
        
        /* Try to find a size for this type in metadata */
@@ -9336,10 +10290,18 @@ mono_marshal_load_type_info (MonoClass* klass)
                klass->blittable = FALSE;
 
        /* If this is an array type, ensure that we have element info */
-       if (klass->element_class) {
+       if (klass->element_class && !mono_marshal_is_loading_type_info (klass->element_class)) {
                mono_marshal_load_type_info (klass->element_class);
        }
 
+       loads_list = TlsGetValue (load_type_info_tls_id);
+       loads_list = g_slist_remove (loads_list, klass);
+       TlsSetValue (load_type_info_tls_id, loads_list);
+
+       klass->marshal_info = info;
+
+       mono_loader_unlock ();
+
        return klass->marshal_info;
 }
 
@@ -9353,8 +10315,12 @@ mono_marshal_load_type_info (MonoClass* klass)
 gint32
 mono_class_native_size (MonoClass *klass, guint32 *align)
 {      
-       if (!klass->marshal_info)
-               mono_marshal_load_type_info (klass);
+       if (!klass->marshal_info) {
+               if (mono_marshal_is_loading_type_info (klass))
+                       return 0;
+               else
+                       mono_marshal_load_type_info (klass);
+       }
 
        if (align)
                *align = klass->min_align;
@@ -9495,6 +10461,11 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
                return sizeof (gpointer);
        case MONO_NATIVE_STRUCT: 
                klass = mono_class_from_mono_type (type);
+               if (klass == mono_defaults.object_class &&
+                       (mspec && mspec->native == MONO_NATIVE_STRUCT)) {
+               *align = 16;
+               return 16;
+               }
                return mono_class_native_size (klass, align);
        case MONO_NATIVE_BYVALTSTR: {
                int esize = unicode ? 2: 1;