* reflection.c (inflate_mono_method): Reuse method instantiation
[mono.git] / mono / metadata / marshal.c
index fba1f1e7ecd5ed2efa8f832ccfbdd6ac6fd78522..e6b9b6628bc5326608872431e9d34d2799defef4 100644 (file)
@@ -539,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;
@@ -966,16 +966,15 @@ 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;
 }
 
 /**
@@ -984,8 +983,9 @@ mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
  * @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.
+ * 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)
@@ -1001,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
@@ -2956,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);
@@ -3465,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;
 }
 
@@ -4274,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++)
@@ -4481,8 +4485,6 @@ mono_marshal_get_runtime_invoke (MonoMethod *method)
 
        g_assert (method);
 
-       target_klass = method->klass;
-       
        mono_marshal_lock ();
 
        if (method->string_ctor) {
@@ -4517,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);
@@ -4533,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);
@@ -4630,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;
                        }
@@ -6192,11 +6207,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
        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)))) {
+       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"));
        }
 
@@ -6206,98 +6217,8 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
 
                m->orig_conv_args [argnum] = 0;
-
-               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);
-
-                       *conv_arg_type = &mono_defaults.variant_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);
-
-                       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);
-                       }
-               }
-               else if (klass->delegate) {
+               
+               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));
@@ -6386,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_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;
-               }
                if (klass == mono_defaults.stringbuilder_class) {
                        gboolean need_free;
                        MonoMarshalNative encoding;
@@ -6555,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);
@@ -6760,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, 
@@ -7609,6 +7744,14 @@ 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);
@@ -8157,6 +8300,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                        switch (t->type) {
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_VALUETYPE:
+                       case MONO_TYPE_OBJECT:
                                emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
                                break;
                        }
@@ -9836,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)
 {
@@ -9849,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);
 
@@ -9861,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*
@@ -9888,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)
 {