Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mono / metadata / marshal.c
index 82e0b9b69fb17d61e6f69e1cc8fed412c2c1e2db..18f93d260e3897cc70f53bbfde9b45a0229526fb 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"
@@ -143,6 +144,54 @@ static void init_safe_handle (void);
 static void*
 ves_icall_marshal_alloc (gulong size);
 
+void
+mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text);
+
+void
+mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text);
+
+gchar*
+mono_string_builder_to_utf8 (MonoStringBuilder *sb);
+
+gunichar2*
+mono_string_builder_to_utf16 (MonoStringBuilder *sb);
+
+void
+mono_string_to_byvalstr (gpointer dst, MonoString *src, int size);
+
+void
+mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size);
+
+gpointer
+mono_delegate_to_ftnptr (MonoDelegate *delegate);
+
+MonoDelegate*
+mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
+
+gpointer
+mono_array_to_savearray (MonoArray *array);
+
+gpointer
+mono_array_to_lparray (MonoArray *array);
+
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+
+gpointer
+mono_marshal_asany (MonoObject *obj, MonoMarshalNative string_encoding, int param_attrs);
+
+void
+mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs);
+
+gpointer
+mono_array_to_savearray (MonoArray *array);
+
+gpointer
+mono_array_to_lparray (MonoArray *array);
+
+void
+mono_free_lparray (MonoArray *array, gpointer* nativeArray);
+
 /* Lazy class loading functions */
 static GENERATE_GET_CLASS_WITH_CACHE (string_builder, System.Text, StringBuilder)
 static GENERATE_GET_CLASS_WITH_CACHE (date_time, System, DateTime)
@@ -153,7 +202,6 @@ static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, System.Runtime.Inte
 static MonoMethod *sh_dangerous_add_ref;
 static MonoMethod *sh_dangerous_release;
 
-
 static void
 init_safe_handle ()
 {
@@ -164,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*
@@ -190,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)
 {
@@ -237,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);
@@ -283,9 +340,11 @@ mono_marshal_unlock_internal (void)
        mono_marshal_unlock ();
 }
 
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
 gpointer
 mono_delegate_to_ftnptr (MonoDelegate *delegate)
 {
+       MonoError error;
        MonoMethod *method, *wrapper;
        MonoClass *klass;
        uint32_t target_handle = 0;
@@ -303,14 +362,15 @@ 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;
 
                ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
                if (!ftnptr) {
                        g_assert (exc_class);
-                       mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+                       mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System", exc_class, exc_arg));
+                       return NULL;
                }
                return ftnptr;
        }
@@ -328,7 +388,11 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
        delegate_hash_table_add (delegate);
 
        /* when the object is collected, collect the dynamic method, too */
-       mono_object_register_finalizer ((MonoObject*)delegate);
+       mono_object_register_finalizer ((MonoObject*)delegate, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
        return delegate->delegate_trampoline;
 }
@@ -396,6 +460,7 @@ mono_marshal_use_aot_wrappers (gboolean use)
 static void
 parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
 {
+       MonoError error;
        MonoCustomAttrInfo *cinfo;
        MonoReflectionUnmanagedFunctionPointerAttribute *attr;
 
@@ -405,9 +470,12 @@ parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piin
                 * The pinvoke attributes are stored in a real custom attribute so we have to
                 * construct it.
                 */
-               cinfo = mono_custom_attrs_from_class (klass);
+               cinfo = mono_custom_attrs_from_class_checked (klass, &error);
+               if (!mono_error_ok (&error)) {
+                       g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
+                       mono_error_cleanup (&error);
+               }
                if (cinfo && !mono_runtime_get_no_exec ()) {
-                       MonoError error;
                        attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error);
                        if (attr) {
                                piinfo->piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
@@ -423,6 +491,7 @@ parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piin
        }
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error */
 MonoDelegate*
 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
 {
@@ -460,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);
@@ -482,12 +555,17 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                }
 
                d = (MonoDelegate*)mono_object_new_checked (mono_domain_get (), klass, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                mono_delegate_ctor_with_method ((MonoObject*)d, this_obj, mono_compile_method (wrapper), wrapper);
        }
 
-       if (d->object.vtable->domain != mono_domain_get ())
-               mono_raise_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
+       if (d->object.vtable->domain != mono_domain_get ()) {
+               mono_set_pending_exception (mono_get_exception_not_supported ("Delegates cannot be marshalled from native code into a domain other than their home domain"));
+               return NULL;
+       }
 
        return d;
 }
@@ -543,6 +621,7 @@ mono_string_from_byvalstr (const char *data, int max_len)
        return mono_string_new_len (domain, data, len);
 }
 
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
 static MonoString *
 mono_string_from_byvalwstr (gunichar2 *data, int max_len)
 {
@@ -557,7 +636,10 @@ mono_string_from_byvalwstr (gunichar2 *data, int max_len)
        while (data [len]) len++;
 
        res = mono_string_new_utf16_checked (domain, data, MIN (len, max_len), &error);
-       mono_error_raise_exception (&error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
        return res;
 }
 
@@ -680,6 +762,7 @@ mono_byvalarray_to_byte_array (MonoArray *arr, gpointer native_arr, guint32 elnu
        mono_byvalarray_to_array (arr, native_arr, mono_defaults.byte_class, elnum);
 }
 
+/* This is a JIT icall, it sets the pending exception and returns on error */
 static void
 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
 {
@@ -691,9 +774,9 @@ mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclas
 
                as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
                if (error) {
-                       MonoException *exc = mono_get_exception_argument ("string", error->message);
+                       mono_set_pending_exception (mono_get_exception_argument ("string", error->message));
                        g_error_free (error);
-                       mono_raise_exception (exc);
+                       return;
                }
 
                memcpy (native_arr, as, MIN (strlen (as), elnum));
@@ -841,6 +924,8 @@ mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
  * Returns: a utf8 string with the contents of the StringBuilder.
  *
  * The return value must be released with g_free.
+ *
+ * This is a JIT icall, it sets the pending exception and returns NULL on error.
  */
 gchar*
 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
@@ -851,7 +936,6 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
        if (!sb)
                return NULL;
 
-
        gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
 
        guint str_len = mono_string_builder_string_length (sb);
@@ -861,7 +945,7 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
        if (gerror) {
                g_error_free (gerror);
                g_free (str_utf16);
-               mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
+               mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
                return NULL;
        } else {
                guint len = mono_string_builder_capacity (sb) + 1;
@@ -869,7 +953,8 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
                if (!mono_error_ok (&error)) {
                        g_free (str_utf16);
                        g_free (tmp);
-                       mono_error_raise_exception (&error);
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
                }
 
                g_assert (str_len < len);
@@ -891,6 +976,7 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
  * Returns: a utf16 string with the contents of the StringBuilder.
  *
  * The return value must not be freed.
+ * This is a JIT icall, it sets the pending exception and returns NULL on error.
  */
 gunichar2*
 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
@@ -908,7 +994,10 @@ mono_string_builder_to_utf16 (MonoStringBuilder *sb)
                len = 1;
 
        gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2), &error);
-       mono_error_raise_exception (&error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
        str[len] = '\0';
 
@@ -935,6 +1024,7 @@ mono_string_builder_to_utf16 (MonoStringBuilder *sb)
        return str;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static gpointer
 mono_string_to_lpstr (MonoString *s)
 {
@@ -956,7 +1046,7 @@ mono_string_to_lpstr (MonoString *s)
        if (error) {
                MonoException *exc = mono_get_exception_argument ("string", error->message);
                g_error_free (error);
-               mono_raise_exception(exc);
+               mono_set_pending_exception (exc);
                return NULL;
        } else {
                as = CoTaskMemAlloc (len + 1);
@@ -1767,11 +1857,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);
        }
        }
 }
@@ -2071,24 +2157,26 @@ mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
 
 #endif /* DISABLE_JIT */
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static MonoAsyncResult *
 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
 {
+       MonoError error;
        MonoMulticastDelegate *mcast_delegate;
        MonoClass *klass;
        MonoMethod *method;
 
        g_assert (delegate);
        mcast_delegate = (MonoMulticastDelegate *) delegate;
-       if (mcast_delegate->delegates != NULL)
-               mono_raise_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
+       if (mcast_delegate->delegates != NULL) {
+               mono_set_pending_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
+               return NULL;
+       }
 
 #ifndef DISABLE_REMOTING
        if (delegate->target && mono_object_class (delegate->target) == mono_defaults.transparent_proxy_class) {
-
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
                if (!mono_class_is_contextbound (tp->remote_class->proxy_class) || tp->rp->context != (MonoObject *) mono_context_get ()) {
-
                        /* If the target is a proxy, make a direct call. Is proxy's work
                        // to make the call asynchronous.
                        */
@@ -2108,9 +2196,13 @@ mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
                        msg->call_type = CallType_BeginInvoke;
 
                        exc = NULL;
-                       mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+                       mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                        if (exc)
-                               mono_raise_exception ((MonoException *) exc);
+                               mono_set_pending_exception ((MonoException *) exc);
                        return ares;
                }
        }
@@ -2123,7 +2215,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
@@ -2786,6 +2880,7 @@ mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
        return res;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static MonoObject *
 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 {
@@ -2804,7 +2899,10 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
        if (!delegate->method_info) {
                g_assert (delegate->method);
                MonoReflectionMethod *rm = mono_method_get_object_checked (domain, delegate->method, NULL, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                MONO_OBJECT_SETREF (delegate, method_info, rm);
        }
 
@@ -2822,12 +2920,12 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 
        ares = (MonoAsyncResult *)mono_array_get (msg->args, gpointer, sig->param_count - 1);
        if (ares == NULL) {
-               mono_raise_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
+               mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
                return NULL;
        }
 
        if (ares->async_delegate != (MonoObject*)delegate) {
-               mono_raise_exception (mono_get_exception_invalid_operation (
+               mono_set_pending_exception (mono_get_exception_invalid_operation (
                        "The IAsyncResult object provided does not match this delegate."));
                return NULL;
        }
@@ -2836,11 +2934,18 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
        if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
                msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                mono_message_init (domain, msg, delegate->method_info, NULL);
                msg->call_type = CallType_EndInvoke;
                MONO_OBJECT_SETREF (msg, async_result, ares);
-               res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args);
+               res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
        } else
 #endif
        {
@@ -2856,7 +2961,7 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
                        MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, mono_string_new (domain, tmp));
                        g_free (tmp);
                }
-               mono_raise_exception ((MonoException*)exc);
+               mono_set_pending_exception ((MonoException*)exc);
        }
 
        mono_method_return_message_restore (method, params, out_args);
@@ -3078,11 +3183,13 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        if (callvirt) {
                subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
                if (target_method->is_inflated) {
+                       MonoError error;
                        MonoType *target_type;
 
                        g_assert (method->signature->hasthis);
-                       target_type = mono_class_inflate_generic_type (method->signature->params [0],
-                               mono_method_get_context (method));
+                       target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
+                               mono_method_get_context (method), &error);
+                       mono_error_assert_ok (&error); /* FIXME don't swallow the error */
                        target_class = mono_class_from_mono_type (target_type);
                } else {
                        target_class = target_method->klass;
@@ -4322,6 +4429,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
                *conv_arg_type = &mono_defaults.int_class->byval_arg;
        return conv_arg;
 #else
+       MonoError error;
        MonoType *mtype;
        MonoClass *mklass;
        static MonoClass *ICustomMarshaler = NULL;
@@ -4354,10 +4462,11 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
        }
 
        if (spec->data.custom_data.image)
-               mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, spec->data.custom_data.image);
+               mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, &error);
        else
-               mtype = mono_reflection_type_from_name (spec->data.custom_data.custom_name, m->image);
+               mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, &error);
        g_assert (mtype != NULL);
+       mono_error_assert_ok (&error);
        mklass = mono_class_from_mono_type (mtype);
        g_assert (mklass != NULL);
 
@@ -4851,8 +4960,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 */
@@ -4932,8 +5041,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);
@@ -7126,10 +7235,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;
@@ -7162,7 +7273,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);
        }
@@ -7172,8 +7283,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 */
                /*
@@ -7192,6 +7310,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)
@@ -7201,12 +7336,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);
@@ -7251,10 +7380,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 */
@@ -7265,7 +7408,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:
@@ -7312,6 +7454,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.
@@ -7349,6 +7516,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 */
 
@@ -7784,6 +7955,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 ();
@@ -7876,6 +8050,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) { 
@@ -8042,6 +8227,7 @@ mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *
 MonoMethod *
 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle)
 {
+       MonoError error;
        MonoMethodSignature *sig, *csig, *invoke_sig;
        MonoMethodBuilder *mb;
        MonoMethod *res, *invoke;
@@ -8052,7 +8238,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
@@ -8106,7 +8292,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
                 * contents of the attribute without constructing it, as that might not be
                 * possible when running in cross-compiling mode.
                 */
-               cinfo = mono_custom_attrs_from_class (delegate_klass);
+               cinfo = mono_custom_attrs_from_class_checked (delegate_klass, &error);
+               mono_error_assert_ok (&error);
                attr = NULL;
                if (cinfo) {
                        for (i = 0; i < cinfo->num_attrs; ++i) {
@@ -8412,7 +8599,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)
@@ -9315,7 +9504,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: */
@@ -9429,7 +9618,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 */
@@ -9755,7 +9944,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));
@@ -10127,12 +10316,16 @@ mono_marshal_alloc (gulong size, MonoError *error)
        return res;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static void*
 ves_icall_marshal_alloc (gulong size)
 {
        MonoError error;
        void *ret = mono_marshal_alloc (size, &error);
-       mono_error_raise_exception (&error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
        return ret;
 }
@@ -10166,6 +10359,7 @@ mono_marshal_string_to_utf16 (MonoString *s)
        return s ? mono_string_chars (s) : NULL;
 }
 
+/* This is a JIT icall, it sets the pending exception and returns NULL on error. */
 static void *
 mono_marshal_string_to_utf16_copy (MonoString *s)
 {
@@ -10174,7 +10368,10 @@ mono_marshal_string_to_utf16_copy (MonoString *s)
        } else {
                MonoError error;
                gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
                memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
                res [mono_string_length (s)] = 0;
                return res;
@@ -10310,7 +10507,10 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
                len++;
 
        res = mono_string_new_utf16_checked (domain, ptr, len, &error);
-       mono_error_raise_exception (&error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
        return res;
 }
 
@@ -10392,29 +10592,31 @@ ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj
        pa [2] = &delete_old;
 
        mono_runtime_invoke_checked (method, NULL, pa, &error);
-       mono_error_raise_exception (&error);
+       if (!mono_error_ok (&error))
+               mono_error_set_pending_exception (&error);
 }
 
 static void
-ptr_to_structure (gpointer src, MonoObject *dst)
+ptr_to_structure (gpointer src, MonoObject *dst, MonoError *error)
 {
-       MonoError error;
        MonoMethod *method;
        gpointer pa [2];
 
+       mono_error_init (error);
+
        method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
 
        pa [0] = &src;
        pa [1] = dst;
 
-       mono_runtime_invoke_checked (method, NULL, pa, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       mono_runtime_invoke_checked (method, NULL, pa, error);
 }
 
 void
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
 {
        MonoType *t;
+       MonoError error;
 
        MONO_CHECK_ARG_NULL (src,);
        MONO_CHECK_ARG_NULL (dst,);
@@ -10433,7 +10635,9 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, M
                return;
        }
 
-       ptr_to_structure (src, dst);
+       ptr_to_structure (src, dst, &error);
+       if (!mono_error_ok (&error))
+               mono_error_set_pending_exception (&error);
 }
 
 MonoObject *
@@ -10455,9 +10659,16 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s
        }
 
        res = mono_object_new_checked (domain, klass, &error);
-       mono_error_raise_exception (&error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
-       ptr_to_structure (src, res);
+       ptr_to_structure (src, res, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
 
        return res;
 }
@@ -10640,8 +10851,10 @@ ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size)
 #else
        res = g_try_malloc (s);
 #endif
-       if (!res)
-               mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
 
        return res;
 }
@@ -10653,7 +10866,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, g
        size_t s = (size_t)size;
 
        if (ptr == NULL) {
-               mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
                return NULL;
        }
 
@@ -10662,8 +10875,10 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, g
 #else
        res = g_try_realloc (ptr, s);
 #endif
-       if (!res)
-               mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
 
        return res;
 }
@@ -10692,8 +10907,10 @@ ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
 
        res = g_try_malloc ((gulong)size);
 #endif
-       if (!res)
-               mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
        return res;
 }
 
@@ -10717,8 +10934,10 @@ ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr,
 #else
        res = g_try_realloc (ptr, (gulong)size);
 #endif
-       if (!res)
-               mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
+       if (!res) {
+               mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
+               return NULL;
+       }
        return res;
 }
 
@@ -10740,6 +10959,12 @@ ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerIn
        return mono_ftnptr_to_delegate (klass, ftn);
 }
 
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegate *delegate)
+{
+       return mono_delegate_to_ftnptr (delegate);
+}
+
 /**
  * mono_marshal_is_loading_type_info:
  *
@@ -11116,6 +11341,7 @@ mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
        return 0;
 }
 
+/* This is a JIT icall, it sets the pending exception and return NULL on error */
 gpointer
 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
 {
@@ -11173,7 +11399,10 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
                        return mono_object_unbox (o);
 
                res = mono_marshal_alloc (mono_class_native_size (klass, NULL), &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
 
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
                        method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
@@ -11183,7 +11412,10 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
                        pa [2] = &delete_old;
 
                        mono_runtime_invoke_checked (method, NULL, pa, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                }
 
                return res;
@@ -11191,10 +11423,11 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
        default:
                break;
        }
-       mono_raise_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
+       mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
        return NULL;
 }
 
+/* This is a JIT icall, it sets the pending exception */
 void
 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
 {
@@ -11234,7 +11467,10 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e
                        pa [1] = o;
 
                        mono_runtime_invoke_checked (method, NULL, pa, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return;
+                       }
                }
 
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {