Merge pull request #2869 from BrzVlad/feature-mod-union-opt
[mono.git] / mono / metadata / marshal.c
index 502012fa3852cb7b8f4e94c160b903c58cea12cf..13ef2b4c486a68e9b8ca8be2303d851b22aebcf2 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  *
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
@@ -211,11 +212,11 @@ init_safe_handle ()
 }
 
 static void
-register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
+register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
 {
        MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
 
-       mono_register_jit_icall (func, name, sig, save);
+       mono_register_jit_icall (func, name, sig, no_wrapper);
 }
 
 MonoMethodSignature*
@@ -237,6 +238,15 @@ mono_marshal_init_tls (void)
        mono_native_tls_alloc (&load_type_info_tls_id, NULL);
 }
 
+static MonoObject*
+mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
+{
+       MonoError error;
+       MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
 void
 mono_marshal_init (void)
 {
@@ -284,7 +294,7 @@ mono_marshal_init (void)
                register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
                register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
                register_icall (g_free, "g_free", "void ptr", FALSE);
-               register_icall (mono_object_isinst, "mono_object_isinst", "object object ptr", FALSE);
+               register_icall (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr", FALSE);
                register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
                register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
                register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
@@ -352,7 +362,7 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
        if (delegate->method_is_virtual)
                method = mono_object_get_virtual_method (delegate->target, method);
 
-       if (mono_method_signature (method)->pinvoke) {
+       if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
                const char *exc_class, *exc_arg;
                gpointer ftnptr;
 
@@ -519,7 +529,11 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
 
                if (use_aot_wrappers) {
                        wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
-                       this_obj = mono_value_box (mono_domain_get (), mono_defaults.int_class, &ftn);
+                       this_obj = mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, &error);
+                       if (!is_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                } else {
                        memset (&piinfo, 0, sizeof (piinfo));
                        parse_unmanaged_function_pointer_attr (klass, &piinfo);
@@ -592,9 +606,11 @@ mono_delegate_free_ftnptr (MonoDelegate *delegate)
        }
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
 static MonoString *
 mono_string_from_byvalstr (const char *data, int max_len)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
 
@@ -604,7 +620,9 @@ mono_string_from_byvalstr (const char *data, int max_len)
        while (len < max_len - 1 && data [len])
                len++;
 
-       return mono_string_new_len (domain, data, len);
+       MonoString *result = mono_string_new_len_checked (domain, data, len, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 /* This is a JIT icall, it sets the pending exception and return NULL on error */
@@ -1112,10 +1130,14 @@ mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
        *((gunichar2 *) dst + len) = 0;
 }
 
+/* this is an icall, it sets the pending exception and returns NULL on error */
 static MonoString*
 mono_string_new_len_wrapper (const char *text, guint length)
 {
-       return mono_string_new_len (mono_domain_get (), text, length);
+       MonoError error;
+       MonoString *result = mono_string_new_len_checked (mono_domain_get (), text, length, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 #ifndef DISABLE_JIT
@@ -1202,7 +1224,8 @@ guint
 mono_type_to_stind (MonoType *type)
 {
        if (type->byref)
-               return CEE_STIND_I;
+               return MONO_TYPE_IS_REFERENCE (type) ? CEE_STIND_REF : CEE_STIND_I;
+
 
 handle_enum:
        switch (type->type) {
@@ -1298,7 +1321,7 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
                mono_mb_emit_op (mb, CEE_NEWARR, eklass);       
-               mono_mb_emit_byte (mb, CEE_STIND_I);
+               mono_mb_emit_byte (mb, CEE_STIND_REF);
 
                if (eklass->blittable) {
                        /* copy the elements */
@@ -1536,16 +1559,23 @@ emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
 }
 
 static gpointer
-conv_to_icall (MonoMarshalConv conv)
+conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
 {
+       int dummy;
+       if (!ind_store_type)
+               ind_store_type = &dummy;
+       *ind_store_type = CEE_STIND_I;
        switch (conv) {
        case MONO_MARSHAL_CONV_STR_LPWSTR:
                return mono_marshal_string_to_utf16;            
        case MONO_MARSHAL_CONV_LPWSTR_STR:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_from_utf16;
        case MONO_MARSHAL_CONV_LPTSTR_STR:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
        case MONO_MARSHAL_CONV_LPSTR_STR:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_new_wrapper;
        case MONO_MARSHAL_CONV_STR_LPTSTR:
 #ifdef TARGET_WIN32
@@ -1558,6 +1588,7 @@ conv_to_icall (MonoMarshalConv conv)
        case MONO_MARSHAL_CONV_STR_BSTR:
                return mono_string_to_bstr;
        case MONO_MARSHAL_CONV_BSTR_STR:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_from_bstr;
        case MONO_MARSHAL_CONV_STR_TBSTR:
        case MONO_MARSHAL_CONV_STR_ANSIBSTR:
@@ -1581,16 +1612,20 @@ conv_to_icall (MonoMarshalConv conv)
        case MONO_MARSHAL_CONV_DEL_FTN:
                return mono_delegate_to_ftnptr;
        case MONO_MARSHAL_CONV_FTN_DEL:
+               *ind_store_type = CEE_STIND_REF;
                return mono_ftnptr_to_delegate;
        case MONO_MARSHAL_CONV_LPSTR_SB:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_utf8_to_builder;
        case MONO_MARSHAL_CONV_LPTSTR_SB:
+               *ind_store_type = CEE_STIND_REF;
 #ifdef TARGET_WIN32
                return mono_string_utf16_to_builder;
 #else
                return mono_string_utf8_to_builder;
 #endif
        case MONO_MARSHAL_CONV_LPWSTR_SB:
+               *ind_store_type = CEE_STIND_REF;
                return mono_string_utf16_to_builder;
        case MONO_MARSHAL_FREE_ARRAY:
                return mono_marshal_free_array;
@@ -1609,6 +1644,7 @@ static void
 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
 {
        int pos;
+       int stind_op;
 
        switch (conv) {
        case MONO_MARSHAL_CONV_BOOL_I4:
@@ -1643,8 +1679,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
-               mono_mb_emit_byte (mb, CEE_STIND_I);    
+               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+               mono_mb_emit_byte (mb, stind_op);
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
@@ -1653,8 +1689,8 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
                mono_mb_emit_ldloc (mb, 1);
                mono_mb_emit_ldloc (mb, 0);
                mono_mb_emit_byte (mb, CEE_LDIND_REF);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
-               mono_mb_emit_byte (mb, CEE_STIND_I);    
+               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+               mono_mb_emit_byte (mb, stind_op);
                break;
        case MONO_MARSHAL_CONV_STR_BYVALSTR: 
        case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
@@ -1664,7 +1700,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); /* src String */
                mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
+               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                break;
        }
        case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
@@ -1843,11 +1879,7 @@ emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv
        }
                
        default: {
-               char *msg = g_strdup_printf ("marshalling conversion %d not implemented", conv);
-               MonoException *exc = mono_get_exception_not_implemented (msg);
-               g_warning ("%s", msg);
-               g_free (msg);
-               mono_raise_exception (exc);
+               g_error ("marshalling conversion %d not implemented", conv);
        }
        }
 }
@@ -1930,8 +1962,9 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
                case MONO_MARSHAL_CONV_NONE: {
                        int t;
 
-                       if (ftype->byref || ftype->type == MONO_TYPE_I ||
-                           ftype->type == MONO_TYPE_U) {
+                       //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
+                       g_assert (!ftype->byref);
+                       if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
                                mono_mb_emit_ldloc (mb, 1);
                                mono_mb_emit_ldloc (mb, 0);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
@@ -2205,7 +2238,9 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
                method = mono_get_delegate_invoke (klass);
        g_assert (method);
 
-       return mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params);
+       MonoAsyncResult *result = mono_threadpool_ms_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 #ifndef DISABLE_JIT
@@ -2334,7 +2369,7 @@ mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_STR_BSTR;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2354,7 +2389,7 @@ mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarsh
                return MONO_MARSHAL_CONV_SB_LPTSTR;
                break;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2377,7 +2412,7 @@ mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec
        case MONO_NATIVE_BSTR:
                return MONO_MARSHAL_CONV_BSTR_STR;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2403,7 +2438,7 @@ mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarsh
                return MONO_MARSHAL_CONV_LPTSTR_SB;
                break;
        default:
-               return (MonoMarshalConv)-1;
+               return MONO_MARSHAL_CONV_INVALID;
        }
 }
 
@@ -2952,7 +2987,8 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
                mono_set_pending_exception ((MonoException*)exc);
        }
 
-       mono_method_return_message_restore (method, params, out_args);
+       mono_method_return_message_restore (method, params, out_args, &error);
+       mono_error_set_pending_exception (&error);
        return res;
 }
 
@@ -4948,8 +4984,8 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                }
 
                /* load pointer to returned value type */
-               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-               mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+               g_assert (m->vtaddr_var);
+               mono_mb_emit_ldloc (mb, m->vtaddr_var);
                /* store the address of the source into local variable 0 */
                mono_mb_emit_stloc (mb, 0);
                /* set dst_ptr */
@@ -5029,8 +5065,8 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
                }
                        
                /* load pointer to returned value type */
-               mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
-               mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+               g_assert (m->vtaddr_var);
+               mono_mb_emit_ldloc (mb, m->vtaddr_var);
                        
                /* store the address of the source into local variable 0 */
                mono_mb_emit_stloc (mb, 0);
@@ -5093,11 +5129,11 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldarg (mb, argnum);
                }
 
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                } else {
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
 
                        mono_mb_emit_stloc (mb, conv_arg);
                }
@@ -5105,7 +5141,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
 
        case MARSHAL_ACTION_CONV_OUT:
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
@@ -5138,10 +5174,11 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
                        mono_mb_emit_byte (mb, CEE_STIND_REF);
                } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
+                       int stind_op;
                        mono_mb_emit_ldarg (mb, argnum);
                        mono_mb_emit_ldloc (mb, conv_arg);
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
-                       mono_mb_emit_byte (mb, CEE_STIND_REF);
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                       mono_mb_emit_byte (mb, stind_op);
                        need_free = TRUE;
                }
 
@@ -5165,14 +5202,14 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                mono_mb_emit_stloc (mb, 0);
                                
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
                }
 
                mono_mb_emit_ldloc (mb, 0);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
+               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, 3);
 
                /* free the string */
@@ -5194,7 +5231,7 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                }
 
                conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
-               if (conv == -1) {
+               if (conv == MONO_MARSHAL_CONV_INVALID) {
                        char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
                        mono_mb_emit_exception_marshal_directive (mb, msg);
                        break;
@@ -5203,27 +5240,28 @@ emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
                mono_mb_emit_ldarg (mb, argnum);
                if (t->byref)
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
-               mono_mb_emit_icall (mb, conv_to_icall (conv));
+               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, conv_arg);
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
                if (t->byref) {
                        if (conv_arg) {
+                               int stind_op;
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                               mono_mb_emit_byte (mb, stind_op);
                        }
                }
                break;
 
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
-               if (conv_to_icall (conv) == mono_marshal_string_to_utf16)
+               if (conv_to_icall (conv, NULL) == mono_marshal_string_to_utf16)
                        /* We need to make a copy so the caller is able to free it */
                        mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
                else
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                mono_mb_emit_stloc (mb, 3);
                break;
 
@@ -5502,7 +5540,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_stloc (mb, conv_arg);
                        } else {
                                mono_mb_emit_ldarg (mb, argnum);
-                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
                                mono_mb_emit_stloc (mb, conv_arg);
                        }
                } else if (klass == mono_defaults.stringbuilder_class) {
@@ -5522,7 +5560,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
                                break;
 
-                       if (conv == -1) {
+                       if (conv == MONO_MARSHAL_CONV_INVALID) {
                                char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
                                mono_mb_emit_exception_marshal_directive (mb, msg);
                                break;
@@ -5532,7 +5570,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                } else if (klass->blittable) {
                        mono_mb_emit_byte (mb, CEE_LDNULL);
@@ -5634,7 +5672,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
 
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        }
 
                        if (need_free) {
@@ -5650,7 +5688,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                                mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                                mono_mb_emit_byte (mb, CEE_STIND_REF);
                        }
                        break;
@@ -5733,7 +5771,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
                        mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
                        mono_mb_emit_ldloc (mb, 0);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                        mono_mb_emit_stloc (mb, 3);
                } else {
                        /* set src */
@@ -5783,7 +5821,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldarg (mb, argnum);
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                        break;
                }
@@ -5857,10 +5895,11 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
        case MARSHAL_ACTION_MANAGED_CONV_OUT:
                if (klass->delegate) {
                        if (t->byref) {
+                               int stind_op;
                                mono_mb_emit_ldarg (mb, argnum);
                                mono_mb_emit_ldloc (mb, conv_arg);
-                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
+                               mono_mb_emit_byte (mb, stind_op);
                                break;
                        }
                }
@@ -5919,7 +5958,7 @@ emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
 
        case MARSHAL_ACTION_MANAGED_CONV_RESULT:
                if (klass->delegate) {
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
                        mono_mb_emit_stloc (mb, 3);
                        break;
                }
@@ -6136,7 +6175,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldarg (mb, argnum);
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
                        mono_mb_emit_stloc (mb, conv_arg);
                } else {
                        MonoClass *eklass;
@@ -6158,9 +6197,9 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
                        }
                        else
-                               conv = (MonoMarshalConv)-1;
+                               conv = MONO_MARSHAL_CONV_INVALID;
 
-                       if (is_string && conv == -1) {
+                       if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
                                char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
                                mono_mb_emit_exception_marshal_directive (mb, msg);
                                break;
@@ -6216,12 +6255,13 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        /* Emit marshalling code */
 
                        if (is_string) {
+                               int stind_op;
                                mono_mb_emit_ldloc (mb, dest_ptr);
                                mono_mb_emit_ldloc (mb, src_var);
                                mono_mb_emit_ldloc (mb, index_var);
                                mono_mb_emit_byte (mb, CEE_LDELEM_REF);
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                               mono_mb_emit_byte (mb, stind_op);
                        } else {
                                /* set the src_ptr */
                                mono_mb_emit_ldloc (mb, src_var);
@@ -6285,7 +6325,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
                                mono_mb_emit_op (mb, CEE_NEWARR, klass->element_class);
                                /* Store into argument */
-                               mono_mb_emit_byte (mb, CEE_STIND_I);
+                               mono_mb_emit_byte (mb, CEE_STIND_REF);
                        }
                }
 
@@ -6332,7 +6372,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                gboolean need_free2;
                                MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
 
-                               g_assert (conv != -1);
+                               g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                                /* dest */
                                mono_mb_emit_ldarg (mb, argnum);
@@ -6345,7 +6385,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                                mono_mb_emit_ldloc (mb, src_ptr);
                                mono_mb_emit_byte (mb, CEE_LDIND_I);
 
-                               mono_mb_emit_icall (mb, conv_to_icall (conv));
+                               mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
 
                                if (need_free) {
                                        /* src */
@@ -6407,7 +6447,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        if (t->byref)
                                mono_mb_emit_byte (mb, CEE_LDIND_REF);
                        mono_mb_emit_ldloc (mb, conv_arg);
-                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY));
+                       mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
                }
 
                break;
@@ -6479,7 +6519,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
                }
                else
-                       conv = (MonoMarshalConv)-1;
+                       conv = MONO_MARSHAL_CONV_INVALID;
 
                mono_marshal_load_type_info (eklass);
 
@@ -6574,7 +6614,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* Emit marshalling code */
                if (is_string) {
-                       g_assert (conv != -1);
+                       g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                        mono_mb_emit_ldloc (mb, conv_arg);
                        mono_mb_emit_ldloc (mb, index_var);
@@ -6582,7 +6622,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        mono_mb_emit_ldloc (mb, src_ptr);
                        mono_mb_emit_byte (mb, CEE_LDIND_I);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
                        mono_mb_emit_byte (mb, CEE_STELEM_REF);
                }
                else {
@@ -6642,7 +6682,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                        conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
                }
                else
-                       conv = (MonoMarshalConv)-1;
+                       conv = MONO_MARSHAL_CONV_INVALID;
 
                mono_marshal_load_type_info (eklass);
 
@@ -6690,7 +6730,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* Emit marshalling code */
                if (is_string) {
-                       g_assert (conv != -1);
+                       int stind_op;
+                       g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                        /* dest */
                        mono_mb_emit_ldloc (mb, dest_ptr);
@@ -6701,8 +6742,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                        mono_mb_emit_byte (mb, CEE_LDELEM_REF);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
-                       mono_mb_emit_byte (mb, CEE_STIND_I);
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                       mono_mb_emit_byte (mb, stind_op);
                }
                else {
                        char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
@@ -6724,7 +6765,7 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
                MonoClass *eklass;
                guint32 label1, label2, label3;
                int index_var, src, dest, esize;
-               MonoMarshalConv conv = (MonoMarshalConv)-1;
+               MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
                gboolean is_string = FALSE;
                
                g_assert (!t->byref);
@@ -6787,7 +6828,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                /* Emit marshalling code */
                if (is_string) {
-                       g_assert (conv != -1);
+                       int stind_op;
+                       g_assert (conv != MONO_MARSHAL_CONV_INVALID);
 
                        /* dest */
                        mono_mb_emit_ldloc (mb, dest);
@@ -6798,8 +6840,8 @@ emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
 
                        mono_mb_emit_byte (mb, CEE_LDELEM_REF);
 
-                       mono_mb_emit_icall (mb, conv_to_icall (conv));
-                       mono_mb_emit_byte (mb, CEE_STIND_I);
+                       mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
+                       mono_mb_emit_byte (mb, stind_op);
                }
                else {
                        char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
@@ -7151,10 +7193,12 @@ 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:
-#ifndef DISABLE_COM
+#if !defined(DISABLE_COM) && !defined(DISABLE_JIT)
                if (spec && spec->native == MONO_NATIVE_STRUCT)
                        return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
+#endif
 
+#if !defined(DISABLE_COM)
                if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
                        spec->native == MONO_NATIVE_IDISPATCH ||
                        spec->native == MONO_NATIVE_INTERFACE))
@@ -7223,10 +7267,12 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
        EmitMarshalContext m;
        MonoMethodSignature *csig;
        MonoClass *klass;
+       MonoExceptionClause *clause;
        int i, argnum, *tmp_locals;
        int type, param_shift = 0;
        static MonoMethodSignature *get_last_error_sig = NULL;
-       int coop_gc_stack_dummy, coop_gc_var;
+       int coop_gc_stack_dummy, coop_gc_var, coop_unblocked_var;
+       int leave_pos;
 
        memset (&m, 0, sizeof (m));
        m.mb = mb;
@@ -7259,7 +7305,7 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
        mono_mb_emit_icon (mb, 0);
        mono_mb_emit_stloc (mb, 2);
 
-       if (!MONO_TYPE_IS_VOID(sig->ret)) {
+       if (!MONO_TYPE_IS_VOID (sig->ret)) {
                /* allocate local 3 to store the return value */
                mono_mb_add_local (mb, sig->ret);
        }
@@ -7269,8 +7315,15 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
                /* local 5, the local to be used when calling the suspend funcs */
                coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               coop_unblocked_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
+               clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
+               clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
        }
 
+       if (MONO_TYPE_ISSTRUCT (sig->ret))
+               m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
        if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
                /* Return type custom marshaling */
                /*
@@ -7289,6 +7342,23 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                tmp_locals [i] = emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
        }
 
+       // In coop mode need to register blocking state during native call
+       if (mono_threads_is_coop_enabled ()) {
+               // Perform an extra, early lookup of the function address, so any exceptions
+               // potentially resulting from the lookup occur before entering blocking mode.
+               if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
+                       mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
+               }
+
+               clause->try_offset = mono_mb_get_label (mb);
+
+               mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
+               mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
+               mono_mb_emit_stloc (mb, coop_gc_var);
+       }
+
        /* push all arguments */
 
        if (sig->hasthis)
@@ -7298,12 +7368,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
        }                       
 
-       if (mono_threads_is_coop_enabled ()) {
-               mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
-               mono_mb_emit_icall (mb, mono_threads_prepare_blocking);
-               mono_mb_emit_stloc (mb, coop_gc_var);
-       }
-
        /* call the native method */
        if (func_param) {
                mono_mb_emit_byte (mb, CEE_LDARG_0);
@@ -7348,10 +7412,24 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
 #endif
        }               
 
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               MonoClass *klass = mono_class_from_mono_type (sig->ret);
+               mono_class_init (klass);
+               if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) {
+                       /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+                       mono_mb_emit_stloc (mb, m.vtaddr_var);
+               }
+       }
+
+       /* Unblock before converting the result, since that can involve calls into the runtime */
        if (mono_threads_is_coop_enabled ()) {
                mono_mb_emit_ldloc (mb, coop_gc_var);
                mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
                mono_mb_emit_icall (mb, mono_threads_finish_blocking);
+               mono_mb_emit_icon (mb, 1);
+               mono_mb_emit_stloc (mb, coop_unblocked_var);
        }
 
        /* convert the result */
@@ -7362,7 +7440,6 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                if (spec && spec->native == MONO_NATIVE_CUSTOM) {
                        emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
                } else {
-
                handle_enum:
                        switch (type) {
                        case MONO_TYPE_VOID:
@@ -7409,6 +7486,31 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                mono_mb_emit_stloc (mb, 3);
        }
 
+       if (mono_threads_is_coop_enabled ()) {
+               int pos;
+
+               leave_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+               clause->try_len = mono_mb_get_label (mb) - clause->try_offset;
+               clause->handler_offset = mono_mb_get_label (mb);
+
+               mono_mb_emit_ldloc (mb, coop_unblocked_var);
+               mono_mb_emit_icon (mb, 1);
+               pos = mono_mb_emit_branch (mb, CEE_BEQ);
+
+               mono_mb_emit_ldloc (mb, coop_gc_var);
+               mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
+               mono_mb_emit_icall (mb, mono_threads_finish_blocking);
+
+               mono_mb_patch_branch (mb, pos);
+
+               mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+
+               clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+
+               mono_mb_patch_branch (mb, leave_pos);
+       }
+
        /* 
         * Need to call this after converting the result since MONO_VTADDR needs 
         * to be adjacent to the call instruction.
@@ -7446,6 +7548,10 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                mono_mb_emit_ldloc (mb, 3);
 
        mono_mb_emit_byte (mb, CEE_RET);
+
+       if (mono_threads_is_coop_enabled ()) {
+               mono_mb_set_clauses (mb, 1, clause);
+       }
 }
 #endif /* DISABLE_JIT */
 
@@ -7881,6 +7987,9 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                mono_mb_add_local (mb, sig->ret);
        }
 
+       if (MONO_TYPE_ISSTRUCT (sig->ret))
+               m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+
        /*
         * try {
         *   mono_jit_attach ();
@@ -7973,6 +8082,17 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
        /* ret = method (...) */
        mono_mb_emit_managed_call (mb, method, NULL);
 
+       if (MONO_TYPE_ISSTRUCT (sig->ret)) {
+               MonoClass *klass = mono_class_from_mono_type (sig->ret);
+               mono_class_init (klass);
+               if (!(((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) || klass->blittable)) {
+                       /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
+                       mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+                       mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
+                       mono_mb_emit_stloc (mb, m->vtaddr_var);
+               }
+       }
+
        if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
                emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
        } else if (!sig->ret->byref) { 
@@ -8150,7 +8270,7 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
        EmitMarshalContext m;
 
        g_assert (method != NULL);
-       g_assert (!mono_method_signature (method)->pinvoke);
+       g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
 
        /* 
         * FIXME: Should cache the method+delegate type pair, since the same method
@@ -8511,7 +8631,9 @@ mono_marshal_get_castclass_with_cache (void)
 static MonoObject *
 mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
 {
-       MonoObject *isinst = mono_object_isinst (obj, klass);
+       MonoError error;
+       MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
+       mono_error_raise_exception (&error); /* FIXME don't raise here */
 
 #ifndef DISABLE_REMOTING
        if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
@@ -8573,7 +8695,7 @@ mono_marshal_get_isinst_with_cache (void)
 
        // return obj
        mono_mb_patch_branch (mb, positive_cache_hit_pos);
-       mono_mb_emit_ldarg (mb, 0);
+       mono_mb_emit_ldarg (mb, obj_arg_position);
        mono_mb_emit_byte (mb, CEE_RET);
 #endif
 
@@ -9414,7 +9536,7 @@ get_virtual_stelemref_wrapper (int kind)
                /*if (mono_object_isinst (value, aklass)) */
                mono_mb_emit_ldarg (mb, 2);
                mono_mb_emit_ldloc (mb, aklass);
-               mono_mb_emit_icall (mb, mono_object_isinst);
+               mono_mb_emit_icall (mb, mono_object_isinst_icall);
                b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
                /* do_store: */
@@ -9528,7 +9650,7 @@ get_virtual_stelemref_wrapper (int kind)
                /*if (mono_object_isinst (value, aklass)) */
                mono_mb_emit_ldarg (mb, 2);
                mono_mb_emit_ldloc (mb, aklass);
-               mono_mb_emit_icall (mb, mono_object_isinst);
+               mono_mb_emit_icall (mb, mono_object_isinst_icall);
                b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
 
                /* if (vklass->idepth < aklass->idepth) goto failue */
@@ -9854,7 +9976,7 @@ mono_marshal_get_stelemref (void)
        
        mono_mb_emit_ldarg (mb, 2);
        mono_mb_emit_ldloc (mb, aklass);
-       mono_mb_emit_icall (mb, mono_object_isinst);
+       mono_mb_emit_icall (mb, mono_object_isinst_icall);
        
        b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
        mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
@@ -10393,12 +10515,15 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr)
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
 {
-       if (ptr == NULL) {
-               mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
-               return NULL;
-       } else {
-               return mono_string_new_len (mono_domain_get (), ptr, len);
-       }
+       MonoError error;
+       MonoString *result = NULL;
+       mono_error_init (&error);
+       if (ptr == NULL)
+               mono_error_set_argument_null (&error, "ptr", "");
+       else
+               result = mono_string_new_len_checked (mono_domain_get (), ptr, len, &error);
+       mono_error_set_pending_exception (&error);
+       return result;
 }
 
 MonoString *