Merge pull request #2716 from BrzVlad/fix-tramp-jinfo
[mono.git] / mono / metadata / marshal.c
index 3c6768041b2089b6eba1d60a518d8464943ad3e5..559ecc4cfe4fd1719890485054ac87c112628831 100644 (file)
@@ -143,18 +143,71 @@ 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)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, System.Runtime.InteropServices, UnmanagedFunctionPointerAttribute)
+static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, System.Runtime.InteropServices, ICustomMarshaler)
+
 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
 static MonoMethod *sh_dangerous_add_ref;
 static MonoMethod *sh_dangerous_release;
 
-
 static void
 init_safe_handle ()
 {
        sh_dangerous_add_ref = mono_class_get_method_from_name (
-               mono_defaults.safehandle_class, "DangerousAddRef", 1);
+               mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
        sh_dangerous_release = mono_class_get_method_from_name (
-               mono_defaults.safehandle_class, "DangerousRelease", 0);
+               mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
 }
 
 static void
@@ -277,9 +330,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;
@@ -304,7 +359,8 @@ mono_delegate_to_ftnptr (MonoDelegate *delegate)
                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;
        }
@@ -322,7 +378,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;
 }
@@ -390,23 +450,23 @@ mono_marshal_use_aot_wrappers (gboolean use)
 static void
 parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
 {
-       static MonoClass *UnmanagedFunctionPointerAttribute;
+       MonoError error;
        MonoCustomAttrInfo *cinfo;
        MonoReflectionUnmanagedFunctionPointerAttribute *attr;
 
-       if (!UnmanagedFunctionPointerAttribute)
-               UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
        /* The attribute is only available in Net 2.0 */
-       if (UnmanagedFunctionPointerAttribute) {
+       if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                /* 
                 * 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, UnmanagedFunctionPointerAttribute, &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;
                        } else {
@@ -421,9 +481,11 @@ 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)
 {
+       MonoError error;
        guint32 gchandle;
        MonoDelegate *d;
 
@@ -478,12 +540,18 @@ mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
                        g_free (sig);
                }
 
-               d = (MonoDelegate*)mono_object_new (mono_domain_get (), klass);
+               d = (MonoDelegate*)mono_object_new_checked (mono_domain_get (), klass, &error);
+               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;
 }
@@ -539,9 +607,12 @@ 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)
 {
+       MonoError error;
+       MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get ();
        int len = 0;
 
@@ -550,7 +621,12 @@ mono_string_from_byvalwstr (gunichar2 *data, int max_len)
 
        while (data [len]) len++;
 
-       return mono_string_new_utf16 (domain, data, MIN (len, max_len));
+       res = mono_string_new_utf16_checked (domain, data, MIN (len, max_len), &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+       return res;
 }
 
 gpointer
@@ -672,6 +748,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)
 {
@@ -683,9 +760,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));
@@ -707,6 +784,8 @@ mono_string_builder_new (int starting_string_length)
        static MonoClass *string_builder_class;
        static MonoMethod *sb_ctor;
        static void *args [1];
+
+       MonoError error;
        int initial_len = starting_string_length;
 
        if (initial_len < 0)
@@ -716,7 +795,7 @@ mono_string_builder_new (int starting_string_length)
                MonoMethodDesc *desc;
                MonoMethod *m;
 
-               string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
+               string_builder_class = mono_class_get_string_builder_class ();
                g_assert (string_builder_class);
                desc = mono_method_desc_new (":.ctor(int)", FALSE);
                m = mono_method_desc_search_in_class (desc, string_builder_class);
@@ -730,12 +809,13 @@ mono_string_builder_new (int starting_string_length)
        // array will always be garbage collected.
        args [0] = &initial_len;
 
-       MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
-       MonoObject *exc;
-       g_assert (sb);
+       MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new_checked (mono_domain_get (), string_builder_class, &error);
+       mono_error_assert_ok (&error);
 
-       mono_runtime_invoke (sb_ctor, sb, args, &exc);
-       g_assert (!exc);
+       MonoObject *exc;
+       mono_runtime_try_invoke (sb_ctor, sb, args, &exc, &error);
+       g_assert (exc == NULL);
+       mono_error_assert_ok (&error);
 
        g_assert (sb->chunkChars->max_length >= initial_len);
 
@@ -830,6 +910,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)
@@ -840,7 +922,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);
@@ -850,7 +931,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;
@@ -858,7 +939,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);
@@ -880,6 +962,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)
@@ -897,7 +980,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';
 
@@ -924,6 +1010,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)
 {
@@ -945,7 +1032,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);
@@ -1794,7 +1881,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
                return;
        }
 
-       if (klass != mono_defaults.safehandle_class) {
+       if (klass != mono_class_try_get_safehandle_class ()) {
                if ((klass->flags & TYPE_ATTRIBUTE_LAYOUT_MASK) == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
                        char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
                                                                                 mono_type_full_name (&klass->byval_arg));
@@ -1824,7 +1911,7 @@ emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_obje
                        usize = info->fields [i + 1].offset - info->fields [i].offset;
                }
 
-               if (klass != mono_defaults.safehandle_class){
+               if (klass != mono_class_try_get_safehandle_class ()){
                        /* 
                         * FIXME: Should really check for usize==0 and msize>0, but we apply 
                         * the layout to the managed structure as well.
@@ -2060,24 +2147,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.
                        */
@@ -2097,9 +2186,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;
                }
        }
@@ -2775,9 +2868,11 @@ 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)
 {
+       MonoError error;
        MonoDomain *domain = mono_domain_get ();
        MonoAsyncResult *ares;
        MonoMethod *method = NULL;
@@ -2791,7 +2886,12 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 
        if (!delegate->method_info) {
                g_assert (delegate->method);
-               MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, delegate->method, NULL));
+               MonoReflectionMethod *rm = mono_method_get_object_checked (domain, delegate->method, NULL, &error);
+               if (!mono_error_ok (&error)) {
+                       mono_error_set_pending_exception (&error);
+                       return NULL;
+               }
+               MONO_OBJECT_SETREF (delegate, method_info, rm);
        }
 
        if (!delegate->method_info || !delegate->method_info->method)
@@ -2808,12 +2908,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;
        }
@@ -2821,11 +2921,19 @@ mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
 #ifndef DISABLE_REMOTING
        if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
                MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
-               msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
+               msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
+               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
        {
@@ -2841,7 +2949,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);
@@ -3063,11 +3171,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;
@@ -4319,7 +4429,7 @@ emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
        int pos2;
 
        if (!ICustomMarshaler) {
-               MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "ICustomMarshaler");
+               MonoClass *klass = mono_class_try_get_icustom_marshaler_class ();
                if (!klass) {
                        exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
                        goto handle_exception;
@@ -4671,7 +4781,7 @@ emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
 
        klass = mono_class_from_mono_type (t);
 
-       date_time_class = mono_class_from_name_cached (mono_defaults.corlib, "System", "DateTime");
+       date_time_class = mono_class_get_date_time_class ();
 
        switch (action) {
        case MARSHAL_ACTION_CONV_IN:
@@ -7053,8 +7163,8 @@ emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
                        return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
 #endif
 
-               if (mono_defaults.safehandle_class != NULL && t->data.klass &&
-                   mono_class_is_subclass_of (t->data.klass,  mono_defaults.safehandle_class, FALSE))
+               if (mono_class_try_get_safehandle_class () != NULL && t->data.klass &&
+                   mono_class_is_subclass_of (t->data.klass,  mono_class_try_get_safehandle_class (), FALSE))
                        return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
                
                return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
@@ -7739,9 +7849,10 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
        }
 #else
        MonoMethodSignature *sig, *csig;
+       MonoExceptionClause *clause;
        int i, *tmp_locals;
+       int leave_pos;
        gboolean closed = FALSE;
-       int coop_gc_var, coop_gc_dummy_local;
 
        sig = m->sig;
        csig = m->csig;
@@ -7768,30 +7879,46 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                mono_mb_add_local (mb, sig->ret);
        }
 
+       /*
+        * try {
+        *   mono_jit_attach ();
+        *
+        *   <interrupt check>
+        *
+        *   ret = method (...);
+        * } finally {
+        *   mono_jit_detach ();
+        * }
+        *
+        * return ret;
+        */
+
        if (mono_threads_is_coop_enabled ()) {
-               /* local 4, the local to be used when calling the reset_blocking funcs */
-               /* tons of code hardcode 3 to be the return var */
-               coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
-               /* local 5, the local used to get a stack address for suspend funcs */
-               coop_gc_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               clause = g_new0 (MonoExceptionClause, 1);
+               clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
        }
 
        mono_mb_emit_icon (mb, 0);
        mono_mb_emit_stloc (mb, 2);
 
+       if (mono_threads_is_coop_enabled ()) {
+               /* try { */
+               clause->try_offset = mono_mb_get_label (mb);
+       }
+
        /*
         * Might need to attach the thread to the JIT or change the
         * domain for the callback.
+        *
+        * Also does the (STARTING|BLOCKING|RUNNING) -> RUNNING thread state transtion
+        *
+        * mono_jit_attach ();
         */
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
        mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
 
-       if (mono_threads_is_coop_enabled ()) {
-               /* XXX can we merge reset_blocking_start with JIT_ATTACH above and save one call? */
-               mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
-               mono_mb_emit_icall (mb, mono_threads_reset_blocking_start);
-               mono_mb_emit_stloc (mb, coop_gc_var);
-       }
+       /* <interrupt check> */
+       emit_thread_interrupt_checkpoint (mb);
 
        /* we first do all conversions */
        tmp_locals = (int *)alloca (sizeof (int) * sig->param_count);
@@ -7815,8 +7942,6 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                }
        }
 
-       emit_thread_interrupt_checkpoint (mb);
-
        if (sig->hasthis) {
                if (target_handle) {
                        mono_mb_emit_icon (mb, (gint32)target_handle);
@@ -7843,6 +7968,7 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                        mono_mb_emit_ldarg (mb, i);
        }
 
+       /* ret = method (...) */
        mono_mb_emit_managed_call (mb, method, NULL);
 
        if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
@@ -7922,15 +8048,31 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
        }
 
        if (mono_threads_is_coop_enabled ()) {
-               /* XXX merge reset_blocking_end with detach */
-               mono_mb_emit_ldloc (mb, coop_gc_var);
-               mono_mb_emit_ldloc_addr (mb, coop_gc_dummy_local);
-               mono_mb_emit_icall (mb, mono_threads_reset_blocking_end);
+               leave_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
+
+               /* } finally { */
+               clause->try_len = mono_mb_get_label (mb) - clause->try_offset;
+               clause->handler_offset = mono_mb_get_label (mb);
        }
 
+       /*
+        * Also does the RUNNING -> (BLOCKING|RUNNING) thread state transition
+        *
+        * mono_jit_detach ();
+        */
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
        mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
 
+       if (mono_threads_is_coop_enabled ()) {
+               mono_mb_emit_byte (mb, CEE_ENDFINALLY);
+
+               /* } [endfinally] */
+               clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
+
+               mono_mb_patch_branch (mb, leave_pos);
+       }
+
+       /* return ret; */
        if (m->retobj_var) {
                mono_mb_emit_ldloc (mb, m->retobj_var);
                mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
@@ -7942,6 +8084,10 @@ mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *i
                mono_mb_emit_byte (mb, CEE_RET);
        }
 
+       if (mono_threads_is_coop_enabled ()) {
+               mono_mb_set_clauses (mb, 1, clause);
+       }
+
        if (closed)
                g_free (sig);
 #endif
@@ -7991,7 +8137,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)
 {
-       static MonoClass *UnmanagedFunctionPointerAttribute;
+       MonoError error;
        MonoMethodSignature *sig, *csig, *invoke_sig;
        MonoMethodBuilder *mb;
        MonoMethod *res, *invoke;
@@ -8046,12 +8192,8 @@ mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass,
 
        mono_marshal_set_callconv_from_modopt (invoke, csig);
 
-       /* Handle the UnmanagedFunctionPointerAttribute */
-       if (!UnmanagedFunctionPointerAttribute)
-               UnmanagedFunctionPointerAttribute = mono_class_from_name (mono_defaults.corlib, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
-
        /* The attribute is only available in Net 2.0 */
-       if (UnmanagedFunctionPointerAttribute) {
+       if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
                MonoCustomAttrInfo *cinfo;
                MonoCustomAttrEntry *attr;
 
@@ -8060,12 +8202,13 @@ 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) {
                                MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
-                               if (mono_class_has_parent (ctor_class, UnmanagedFunctionPointerAttribute)) {
+                               if (mono_class_has_parent (ctor_class, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
                                        attr = &cinfo->attrs [i];
                                        break;
                                }
@@ -10081,12 +10224,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;
 }
@@ -10120,6 +10267,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)
 {
@@ -10128,7 +10276,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;
@@ -10251,6 +10402,8 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr,
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
 {
+       MonoError error;
+       MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get (); 
        int len = 0;
        guint16 *t = ptr;
@@ -10261,20 +10414,33 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
        while (*t++)
                len++;
 
-       return mono_string_new_utf16 (domain, ptr, len);
+       res = mono_string_new_utf16_checked (domain, ptr, len, &error);
+       if (!mono_error_ok (&error)) {
+               mono_error_set_pending_exception (&error);
+               return NULL;
+       }
+       return res;
 }
 
 MonoString *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
 {
+       MonoError error;
+       MonoString *res = NULL;
        MonoDomain *domain = mono_domain_get (); 
 
+       mono_error_init (&error);
+
        if (ptr == NULL) {
-               mono_set_pending_exception (mono_get_exception_argument_null ("ptr"));
-               return NULL;
+               res = NULL;
+               mono_error_set_argument_null (&error, "ptr", "");
        } else {
-               return mono_string_new_utf16 (domain, ptr, len);
+               res = mono_string_new_utf16_checked (domain, ptr, len, &error);
        }
+
+       if (!mono_error_ok (&error))
+               mono_error_set_pending_exception (&error);
+       return res;
 }
 
 guint32 
@@ -10320,6 +10486,7 @@ ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionType *rty
 void
 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
 {
+       MonoError error;
        MonoMethod *method;
        gpointer pa [3];
 
@@ -10332,27 +10499,32 @@ ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj
        pa [1] = &dst;
        pa [2] = &delete_old;
 
-       mono_runtime_invoke (method, NULL, pa, NULL);
+       mono_runtime_invoke_checked (method, NULL, pa, &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)
 {
        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 (method, NULL, pa, NULL);
+       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,);
@@ -10371,12 +10543,15 @@ 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 *
 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
 {
+       MonoError error;
        MonoClass *klass;
        MonoDomain *domain = mono_domain_get (); 
        MonoObject *res;
@@ -10391,9 +10566,17 @@ ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer s
                return NULL;
        }
 
-       res = mono_object_new (domain, klass);
+       res = mono_object_new_checked (domain, klass, &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;
 }
@@ -10576,8 +10759,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;
 }
@@ -10589,7 +10774,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;
        }
 
@@ -10598,8 +10783,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;
 }
@@ -10628,8 +10815,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;
 }
 
@@ -10653,8 +10842,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;
 }
 
@@ -10676,6 +10867,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:
  *
@@ -11052,6 +11249,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)
 {
@@ -11109,7 +11307,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);
@@ -11118,7 +11319,11 @@ mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_
                        pa [1] = &res;
                        pa [2] = &delete_old;
 
-                       mono_runtime_invoke (method, NULL, pa, NULL);
+                       mono_runtime_invoke_checked (method, NULL, pa, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return NULL;
+                       }
                }
 
                return res;
@@ -11126,13 +11331,15 @@ 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)
 {
+       MonoError error;
        MonoType *t;
        MonoClass *klass;
 
@@ -11167,7 +11374,11 @@ mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_e
                        pa [0] = &ptr;
                        pa [1] = o;
 
-                       mono_runtime_invoke (method, NULL, pa, NULL);
+                       mono_runtime_invoke_checked (method, NULL, pa, &error);
+                       if (!mono_error_ok (&error)) {
+                               mono_error_set_pending_exception (&error);
+                               return;
+                       }
                }
 
                if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {