Merge pull request #3100 from lambdageek/dev/monoerror-exns
[mono.git] / mono / metadata / object.c
index 7e967ff304cd68de9a746a6a5973acfa55030c73..c9ed5ebe1e8572240f3025476c134e47cf805906 100644 (file)
@@ -47,6 +47,7 @@
 #include <mono/utils/mono-memory-model.h>
 #include <mono/utils/checked-build.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include "cominterop.h"
 
 static void
@@ -457,6 +458,7 @@ mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
                        MonoException *exc_to_store = mono_error_convert_to_exception (error);
                        /* What we really want to do here is clone the error object and store one copy in the
                         * domain's exception hash and use the other one to error out here. */
+                       mono_error_init (error);
                        mono_error_set_exception_instance (error, exc_to_store);
                        /*
                         * Store the exception object so it could be thrown on subsequent
@@ -541,7 +543,7 @@ mono_release_type_locks (MonoInternalThread *thread)
 #ifndef DISABLE_REMOTING
 
 static gpointer
-default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
+default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
 {
        g_error ("remoting not installed");
        return NULL;
@@ -2215,7 +2217,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
         * re-acquire them and check if another thread has created the vtable in the meantime.
         */
        /* Special case System.MonoType to avoid infinite recursion */
-       if (klass != mono_defaults.monotype_class) {
+       if (klass != mono_defaults.runtimetype_class) {
                vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
                if (!is_ok (error)) {
                        mono_domain_unlock (domain);
@@ -2223,7 +2225,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                        return NULL;
                }
 
-               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
+               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
                        /* This is unregistered in
                           unregister_vtable_reflection_type() in
                           domain.c. */
@@ -2274,7 +2276,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                klass->runtime_info = runtime_info;
        }
 
-       if (klass == mono_defaults.monotype_class) {
+       if (klass == mono_defaults.runtimetype_class) {
                vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
                if (!is_ok (error)) {
                        mono_domain_unlock (domain);
@@ -2282,7 +2284,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
                        return NULL;
                }
 
-               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
+               if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
                        /* This is unregistered in
                           unregister_vtable_reflection_type() in
                           domain.c. */
@@ -2305,25 +2307,27 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
  * mono_class_proxy_vtable:
  * @domain: the application domain
  * @remove_class: the remote class
+ * @error: set on error
  *
  * Creates a vtable for transparent proxies. It is basically
  * a copy of the real vtable of the class wrapped in @remote_class,
  * but all function pointers invoke the remoting functions, and
  * vtable->klass points to the transparent proxy class, and not to @class.
+ *
+ * On failure returns NULL and sets @error
  */
 static MonoVTable *
-mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
+mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       MonoError error;
        MonoVTable *vt, *pvt;
        int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
        MonoClass *k;
        GSList *extra_interfaces = NULL;
        MonoClass *klass = remote_class->proxy_class;
        gpointer *interface_offsets;
-       uint8_t *bitmap;
+       uint8_t *bitmap = NULL;
        int bsize;
        size_t imt_table_bytes;
        
@@ -2331,6 +2335,8 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        int bcsize;
 #endif
 
+       mono_error_init (error);
+
        vt = mono_class_vtable (domain, klass);
        g_assert (vt); /*FIXME property handle failure*/
        max_interface_id = vt->max_interface_id;
@@ -2351,8 +2357,9 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                
                method_count = mono_class_num_methods (iclass);
        
-               ifaces = mono_class_get_implemented_interfaces (iclass, &error);
-               g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
+               ifaces = mono_class_get_implemented_interfaces (iclass, error);
+               if (!is_ok (error))
+                       goto failure;
                if (ifaces) {
                        for (i = 0; i < ifaces->len; ++i) {
                                MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
@@ -2365,6 +2372,7 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                                method_count += mono_class_num_methods (ic);
                        }
                        g_ptr_array_free (ifaces, TRUE);
+                       ifaces = NULL;
                }
 
                extra_interface_vtsize += method_count * sizeof (gpointer);
@@ -2394,9 +2402,11 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        for (i = 0; i < klass->vtable_size; ++i) {
                MonoMethod *cm;
                    
-               if ((cm = klass->vtable [i]))
-                       pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
-               else
+               if ((cm = klass->vtable [i])) {
+                       pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
+                       if (!is_ok (error))
+                               goto failure;
+               } else
                        pvt->vtable [i] = NULL;
        }
 
@@ -2406,8 +2416,11 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
                        MonoMethod* m;
                        gpointer iter = NULL;
                        while ((m = mono_class_get_methods (k, &iter)))
-                               if (!pvt->vtable [m->slot])
-                                       pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
+                               if (!pvt->vtable [m->slot]) {
+                                       pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
+                                       if (!is_ok (error))
+                                               goto failure;
+                               }
                }
        }
 
@@ -2439,8 +2452,11 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
 
                        iter = NULL;
                        j = 0;
-                       while ((cm = mono_class_get_methods (interf, &iter)))
-                               pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
+                       while ((cm = mono_class_get_methods (interf, &iter))) {
+                               pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
+                               if (!is_ok (error))
+                                       goto failure;
+                       }
                        
                        slot += mono_class_num_methods (interf);
                }
@@ -2461,6 +2477,13 @@ mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mono
        pvt->interface_bitmap = bitmap;
 #endif
        return pvt;
+failure:
+       if (extra_interfaces)
+               g_slist_free (extra_interfaces);
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       g_free (bitmap);
+#endif
+       return NULL;
 }
 
 #endif /* DISABLE_REMOTING */
@@ -2726,17 +2749,20 @@ clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass
 }
 
 gpointer
-mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
+mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
+       mono_error_init (error);
+
        mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
        mono_domain_lock (domain);
        if (rp->target_domain_id != -1) {
                if (remote_class->xdomain_vtable == NULL)
-                       remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
+                       remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
                mono_domain_unlock (domain);
                mono_loader_unlock ();
+               return_val_if_nok (error, NULL);
                return remote_class->xdomain_vtable;
        }
        if (remote_class->default_vtable == NULL) {
@@ -2746,10 +2772,16 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
                klass = mono_class_from_mono_type (type);
 #ifndef DISABLE_COM
                if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
-                       remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
+                       remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
                else
 #endif
-                       remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
+                       remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
+               /* N.B. both branches of the if modify error */
+               if (!is_ok (error)) {
+                       mono_domain_unlock (domain);
+                       mono_loader_unlock ();
+                       return NULL;
+               }
        }
        
        mono_domain_unlock (domain);
@@ -2762,13 +2794,14 @@ mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, Mon
  * @domain: the application domain
  * @tproxy: the proxy whose remote class has to be upgraded.
  * @klass: class to which the remote class can be casted.
+ * @error: set on error
  *
  * Updates the vtable of the remote class by adding the necessary method slots
  * and interface offsets so it can be safely casted to klass. klass can be a
- * class or an interface.
+ * class or an interface.  On success returns TRUE, on failure returns FALSE and sets @error.
  */
-void
-mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
+gboolean
+mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
@@ -2776,6 +2809,7 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla
        MonoRemoteClass *remote_class;
        gboolean redo_vtable;
 
+       mono_error_init (error);
        mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
        mono_domain_lock (domain);
 
@@ -2795,11 +2829,15 @@ mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoCla
 
        if (redo_vtable) {
                tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
-               proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
+               proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
+               if (!is_ok (error))
+                       goto leave;
        }
        
+leave:
        mono_domain_unlock (domain);
        mono_loader_unlock ();
+       return is_ok (error);
 }
 #endif /* DISABLE_REMOTING */
 
@@ -2908,12 +2946,8 @@ do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **ex
        if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
                mono_profiler_method_start_invoke (method);
 
-       MONO_ENTER_GC_UNSAFE;
-
        result = callbacks.runtime_invoke (method, obj, params, exc, error);
 
-       MONO_EXIT_GC_UNSAFE;
-
        if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
                mono_profiler_method_end_invoke (method);
 
@@ -2970,7 +3004,7 @@ mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **
                        mono_error_cleanup (&error);
        } else {
                res = mono_runtime_invoke_checked (method, obj, params, &error);
-               mono_error_raise_exception (&error);
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
        }
        return res;
 }
@@ -3966,6 +4000,44 @@ mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **
        MONO_REQ_GC_UNSAFE_MODE;
 
        MonoError error;
+       if (exc) {
+               MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
+               if (*exc) {
+                       mono_error_cleanup (&error);
+                       return NULL;
+               } else {
+                       if (!is_ok (&error))
+                               *exc = (MonoObject*)mono_error_convert_to_exception (&error);
+                       return result;
+               }
+       } else {
+               MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
+               return result;
+       }
+}
+
+/**
+ * mono_runtime_delegate_try_invoke:
+ * @delegate: pointer to a delegate object.
+ * @params: parameters for the delegate.
+ * @exc: Pointer to the exception result.
+ * @error: set on error
+ *
+ * Invokes the delegate method @delegate with the parameters provided.
+ *
+ * You can pass NULL as the exc argument if you don't want to
+ * catch exceptions, otherwise, *exc will be set to the exception
+ * thrown, if any.  On failure to execute, @error will be set.
+ * if an exception is thrown, you can't use the
+ * MonoObject* result from the function.
+ */
+MonoObject*
+mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       mono_error_init (error);
        MonoMethod *im;
        MonoClass *klass = delegate->vtable->klass;
        MonoObject *o;
@@ -3975,19 +4047,32 @@ mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **
                g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
 
        if (exc) {
-               o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
-               if (*exc == NULL && !mono_error_ok (&error))
-                       *exc = (MonoObject*) mono_error_convert_to_exception (&error);
-               else
-                       mono_error_cleanup (&error);
+               o = mono_runtime_try_invoke (im, delegate, params, exc, error);
        } else {
-               o = mono_runtime_invoke_checked (im, delegate, params, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               o = mono_runtime_invoke_checked (im, delegate, params, error);
        }
 
        return o;
 }
 
+/**
+ * mono_runtime_delegate_invoke_checked:
+ * @delegate: pointer to a delegate object.
+ * @params: parameters for the delegate.
+ * @error: set on error
+ *
+ * Invokes the delegate method @delegate with the parameters provided.
+ *
+ * On failure @error will be set and you can't use the MonoObject*
+ * result from the function.
+ */
+MonoObject*
+mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
+{
+       mono_error_init (error);
+       return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
+}
+
 static char **main_args = NULL;
 static int num_main_args = 0;
 
@@ -4348,11 +4433,11 @@ mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain,
 
 /* Used in call_unhandled_exception_delegate */
 static MonoObject *
-create_unhandled_exception_eventargs (MonoObject *exc)
+create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
-       MonoError error;
+       mono_error_init (error);
        MonoClass *klass;
        gpointer args [2];
        MonoMethod *method = NULL;
@@ -4369,11 +4454,11 @@ create_unhandled_exception_eventargs (MonoObject *exc)
        args [0] = exc;
        args [1] = &is_terminating;
 
-       obj = mono_object_new_checked (mono_domain_get (), klass, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       obj = mono_object_new_checked (mono_domain_get (), klass, error);
+       return_val_if_nok (error, NULL);
 
-       mono_runtime_invoke_checked (method, obj, args, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       mono_runtime_invoke_checked (method, obj, args, error);
+       return_val_if_nok (error, NULL);
 
        return obj;
 }
@@ -4383,6 +4468,7 @@ static void
 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
        MONO_REQ_GC_UNSAFE_MODE;
 
+       MonoError error;
        MonoObject *e = NULL;
        gpointer pa [2];
        MonoDomain *current_domain = mono_domain_get ();
@@ -4393,7 +4479,6 @@ call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, Mon
        g_assert (domain == mono_object_domain (domain->domain));
 
        if (mono_object_domain (exc) != domain) {
-               MonoError error;
 
                exc = mono_object_xdomain_representation (exc, domain, &error);
                if (!exc) {
@@ -4412,14 +4497,20 @@ call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, Mon
        g_assert (mono_object_domain (exc) == domain);
 
        pa [0] = domain->domain;
-       pa [1] = create_unhandled_exception_eventargs (exc);
-       mono_runtime_delegate_invoke (delegate, pa, &e);
+       pa [1] = create_unhandled_exception_eventargs (exc, &error);
+       mono_error_assert_ok (&error);
+       mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
+       if (!is_ok (&error)) {
+               if (e == NULL)
+                       e = (MonoObject*)mono_error_convert_to_exception (&error);
+               else
+                       mono_error_cleanup (&error);
+       }
 
        if (domain != current_domain)
                mono_domain_set_internal_with_options (current_domain, FALSE);
 
        if (e) {
-               MonoError error;
                gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
                if (!mono_error_ok (&error)) {
                        g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
@@ -4490,10 +4581,10 @@ mono_unhandled_exception (MonoObject *exc)
        root_domain = mono_get_root_domain ();
 
        root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       mono_error_assert_ok (&error);
        if (current_domain != root_domain) {
                current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_error_assert_ok (&error);
        }
 
        if (!current_appdomain_delegate && !root_appdomain_delegate) {
@@ -4646,61 +4737,24 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        return rval;
 }
 
-/**
- * mono_runtime_invoke_array:
- * @method: method to invoke
- * @obJ: object instance
- * @params: arguments to the method
- * @exc: exception information.
- *
- * Invokes the method represented by @method on the object @obj.
- *
- * obj is the 'this' pointer, it should be NULL for static
- * methods, a MonoObject* for object instances and a pointer to
- * the value type for value types.
+/** invoke_array_extract_argument:
+ * @params: array of arguments to the method.
+ * @i: the index of the argument to extract.
+ * @t: ith type from the method signature.
+ * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
+ * @error: set on error.
  *
- * The params array contains the arguments to the method with the
- * same convention: MonoObject* pointers for object instances and
- * pointers to the value type otherwise. The _invoke_array
- * variant takes a C# object[] as the params argument (MonoArray
- * *params): in this case the value types are boxed inside the
- * respective reference representation.
- * 
- * From unmanaged code you'll usually use the
- * mono_runtime_invoke_checked() variant.
+ * Given an array of method arguments, return the ith one using the corresponding type
+ * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
  *
- * Note that this function doesn't handle virtual methods for
- * you, it will exec the exact method you pass: we still need to
- * expose a function to lookup the derived class implementation
- * of a virtual method (there are examples of this in the code,
- * though).
- * 
- * You can pass NULL as the exc argument if you don't want to
- * catch exceptions, otherwise, *exc will be set to the exception
- * thrown, if any.  if an exception is thrown, you can't use the
- * MonoObject* result from the function.
- * 
- * If the method returns a value type, it is boxed in an object
- * reference.
+ * On failure sets @error and returns NULL.
  */
-MonoObject*
-mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
-                          MonoObject **exc)
+static gpointer
+invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
 {
-       MONO_REQ_GC_UNSAFE_MODE;
-
-       MonoError error;
-       MonoMethodSignature *sig = mono_method_signature (method);
-       gpointer *pa = NULL;
-       MonoObject *res;
-       int i;
-       gboolean has_byref_nullables = FALSE;
-
-       if (NULL != params) {
-               pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
-               for (i = 0; i < mono_array_length (params); i++) {
-                       MonoType *t = sig->params [i];
-
+       MonoType *t_orig = t;
+       gpointer result = NULL;
+       mono_error_init (error);
                again:
                        switch (t->type) {
                        case MONO_TYPE_U1:
@@ -4718,16 +4772,16 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
-                               if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
+                               if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
                                        /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
-                                       pa [i] = mono_array_get (params, MonoObject*, i);
+                                       result = mono_array_get (params, MonoObject*, i);
                                        if (t->byref)
-                                               has_byref_nullables = TRUE;
+                                               *has_byref_nullables = TRUE;
                                } else {
                                        /* MS seems to create the objects if a null is passed in */
                                        if (!mono_array_get (params, MonoObject*, i)) {
-                                               MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
-                                               mono_error_raise_exception (&error); /* FIXME don't raise here */
+                                               MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
+                                               return_val_if_nok (error, NULL);
                                                mono_array_setref (params, i, o); 
                                        }
 
@@ -4740,12 +4794,12 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                                                 * boxed object in the arg array with the copy.
                                                 */
                                                MonoObject *orig = mono_array_get (params, MonoObject*, i);
-                                               MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), &error);
-                                               mono_error_raise_exception (&error); /* FIXME don't raise here */
+                                               MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
+                                               return_val_if_nok (error, NULL);
                                                mono_array_setref (params, i, copy);
                                        }
                                                
-                                       pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
+                                       result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
                                }
                                break;
                        case MONO_TYPE_STRING:
@@ -4754,10 +4808,10 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_ARRAY:
                        case MONO_TYPE_SZARRAY:
                                if (t->byref)
-                                       pa [i] = mono_array_addr (params, MonoObject*, i);
+                                       result = mono_array_addr (params, MonoObject*, i);
                                        // FIXME: I need to check this code path
                                else
-                                       pa [i] = mono_array_get (params, MonoObject*, i);
+                                       result = mono_array_get (params, MonoObject*, i);
                                break;
                        case MONO_TYPE_GENERICINST:
                                if (t->byref)
@@ -4771,16 +4825,179 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                                /* The argument should be an IntPtr */
                                arg = mono_array_get (params, MonoObject*, i);
                                if (arg == NULL) {
-                                       pa [i] = NULL;
+                                       result = NULL;
                                } else {
                                        g_assert (arg->vtable->klass == mono_defaults.int_class);
-                                       pa [i] = ((MonoIntPtr*)arg)->m_value;
+                                       result = ((MonoIntPtr*)arg)->m_value;
                                }
                                break;
                        }
                        default:
-                               g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
+                               g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
                        }
+       return result;
+}
+/**
+ * mono_runtime_invoke_array:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @exc: exception information.
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ * 
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke_checked() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ * 
+ * You can pass NULL as the exc argument if you don't want to
+ * catch exceptions, otherwise, *exc will be set to the exception
+ * thrown, if any.  if an exception is thrown, you can't use the
+ * MonoObject* result from the function.
+ * 
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
+                          MonoObject **exc)
+{
+       MonoError error;
+       if (exc) {
+               MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
+               if (*exc) {
+                       mono_error_cleanup (&error);
+                       return NULL;
+               } else {
+                       if (!is_ok (&error))
+                               *exc = (MonoObject*)mono_error_convert_to_exception (&error);
+                       return result;
+               }
+       } else {
+               MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
+               return result;
+       }
+}
+
+/**
+ * mono_runtime_invoke_array_checked:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @error: set on failure.
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke_checked() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * On failure or exception, @error will be set. In that case, you
+ * can't use the MonoObject* result from the function.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
+                                  MonoError *error)
+{
+       mono_error_init (error);
+       return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
+}
+
+/**
+ * mono_runtime_try_invoke_array:
+ * @method: method to invoke
+ * @obJ: object instance
+ * @params: arguments to the method
+ * @exc: exception information.
+ * @error: set on failure.
+ *
+ * Invokes the method represented by @method on the object @obj.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ *
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke_checked() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ *
+ * You can pass NULL as the exc argument if you don't want to catch
+ * exceptions, otherwise, *exc will be set to the exception thrown, if
+ * any.  On other failures, @error will be set. If an exception is
+ * thrown or there's an error, you can't use the MonoObject* result
+ * from the function.
+ *
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
+MonoObject*
+mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
+                              MonoObject **exc, MonoError *error)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       mono_error_init (error);
+
+       MonoMethodSignature *sig = mono_method_signature (method);
+       gpointer *pa = NULL;
+       MonoObject *res;
+       int i;
+       gboolean has_byref_nullables = FALSE;
+
+       if (NULL != params) {
+               pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
+               for (i = 0; i < mono_array_length (params); i++) {
+                       MonoType *t = sig->params [i];
+                       pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
+                       return_val_if_nok (error, NULL);
                }
        }
 
@@ -4794,15 +5011,14 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        if (!params)
                                return NULL;
                        else {
-                               MonoObject *result = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], &error);
-                               mono_error_raise_exception (&error); /* FIXME don't raise here */
-                               return result;
+                               return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
                        }
                }
 
                if (!obj) {
-                       obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
-                       g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
+                       obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
+                       mono_error_assert_ok (error);
+                       g_assert (obj); /*maybe we should raise a TLE instead?*/
 #ifndef DISABLE_REMOTING
                        if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
                                method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
@@ -4813,19 +5029,14 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        else
                                o = obj;
                } else if (method->klass->valuetype) {
-                       obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
+                       return_val_if_nok (error, NULL);
                }
 
                if (exc) {
-                       mono_runtime_try_invoke (method, o, pa, exc, &error);
-                       if (*exc == NULL && !mono_error_ok (&error))
-                               *exc = (MonoObject*) mono_error_convert_to_exception (&error);
-                       else
-                               mono_error_cleanup (&error);
+                       mono_runtime_try_invoke (method, o, pa, exc, error);
                } else {
-                       mono_runtime_invoke_checked (method, o, pa, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       mono_runtime_invoke_checked (method, o, pa, error);
                }
 
                return (MonoObject *)obj;
@@ -4834,26 +5045,22 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        MonoObject *nullable;
 
                        /* Convert the unboxed vtype into a Nullable structure */
-                       nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
+                       return_val_if_nok (error, NULL);
 
-                       MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
+                       return_val_if_nok (error, NULL);
                        mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
                        obj = mono_object_unbox (nullable);
                }
 
                /* obj must be already unboxed if needed */
                if (exc) {
-                       res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
-                       if (*exc == NULL && !mono_error_ok (&error))
-                               *exc = (MonoObject*) mono_error_convert_to_exception (&error);
-                       else
-                               mono_error_cleanup (&error);
+                       res = mono_runtime_try_invoke (method, obj, pa, exc, error);
                } else {
-                       res = mono_runtime_invoke_checked (method, obj, pa, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       res = mono_runtime_invoke_checked (method, obj, pa, error);
                }
+               return_val_if_nok (error, NULL);
 
                if (sig->ret->type == MONO_TYPE_PTR) {
                        MonoClass *pointer_class;
@@ -4871,12 +5078,12 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
 
                        g_assert (res->vtable->klass == mono_defaults.int_class);
                        box_args [0] = ((MonoIntPtr*)res)->m_value;
-                       box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+                       box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
+                       return_val_if_nok (error, NULL);
 
-                       res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
+                       res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
                        g_assert (box_exc == NULL);
-                       mono_error_assert_ok (&error);
+                       mono_error_assert_ok (error);
                }
 
                if (has_byref_nullables) {
@@ -4983,7 +5190,7 @@ mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
        if (G_UNLIKELY (!o))
                mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
        else if (G_UNLIKELY (vtable->klass->has_finalize))
-               mono_object_register_finalizer (o, error);
+               mono_object_register_finalizer (o);
 
        return o;
 }
@@ -5113,7 +5320,7 @@ mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
        if (G_UNLIKELY (!o))
                mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
        else if (G_UNLIKELY (vtable->klass->has_finalize))
-               mono_object_register_finalizer (o, error);
+               mono_object_register_finalizer (o);
 
        return o;
 }
@@ -5201,7 +5408,7 @@ mono_object_new_mature (MonoVTable *vtable, MonoError *error)
        if (G_UNLIKELY (!o))
                mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
        else if (G_UNLIKELY (vtable->klass->has_finalize))
-               mono_object_register_finalizer (o, error);
+               mono_object_register_finalizer (o);
 
        return o;
 }
@@ -5316,7 +5523,7 @@ mono_object_clone_checked (MonoObject *obj, MonoError *error)
        mono_gc_wbarrier_object_copy (o, obj);
 
        if (obj->vtable->klass->has_finalize)
-               mono_object_register_finalizer (o, error);
+               mono_object_register_finalizer (o);
        return o;
 }
 
@@ -6091,7 +6298,7 @@ mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, Mo
 #endif
 #endif
        if (klass->has_finalize) {
-               mono_object_register_finalizer (res, error);
+               mono_object_register_finalizer (res);
                return_val_if_nok (error, NULL);
        }
        return res;
@@ -6332,7 +6539,8 @@ mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError
 
                if (*(MonoBoolean *) mono_object_unbox(res)) {
                        /* Update the vtable of the remote type, so it can safely cast to this new type */
-                       mono_upgrade_remote_class (domain, obj, klass);
+                       mono_upgrade_remote_class (domain, obj, klass, error);
+                       return_val_if_nok (error, NULL);
                        return obj;
                }
        }
@@ -6605,6 +6813,48 @@ mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
        return interned;
 }
 
+/*
+ * mono_ldstr_utf8:
+ *
+ *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
+ * of an object.
+ */
+char*
+mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
+{
+       const char *str;
+       size_t len2;
+       long written = 0;
+       char *as;
+       GError *gerror = NULL;
+
+       mono_error_init (error);
+
+       if (!mono_verifier_verify_string_signature (image, idx, NULL))
+               return NULL; /*FIXME we should probably be raising an exception here*/
+       str = mono_metadata_user_string (image, idx);
+
+       len2 = mono_metadata_decode_blob_size (str, &str);
+       len2 >>= 1;
+
+       as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
+       if (gerror) {
+               mono_error_set_argument (error, "string", "%s", gerror->message);
+               g_error_free (gerror);
+               return NULL;
+       }
+       /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
+       if (len2 > written) {
+               /* allocate the total length and copy the part of the string that has been converted */
+               char *as2 = (char *)g_malloc0 (len2);
+               memcpy (as2, as, written);
+               g_free (as);
+               as = as2;
+       }
+
+       return as;
+}
+
 /**
  * mono_string_to_utf8:
  * @s: a System.String
@@ -6622,8 +6872,10 @@ mono_string_to_utf8 (MonoString *s)
        MonoError error;
        char *result = mono_string_to_utf8_checked (s, &error);
        
-       if (!mono_error_ok (&error))
-               mono_error_raise_exception (&error);
+       if (!is_ok (&error)) {
+               mono_error_cleanup (&error);
+               return NULL;
+       }
        return result;
 }
 
@@ -7128,12 +7380,16 @@ ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult
 
        ac = (MonoAsyncCall*) ares->object_data;
        if (!ac) {
-               res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
+               res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
        } else {
                gpointer wait_event = NULL;
 
                ac->msg->exc = NULL;
-               res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
+               res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
                MONO_OBJECT_SETREF (ac, res, res);
 
                mono_monitor_enter ((MonoObject*) ares);
@@ -7301,16 +7557,16 @@ mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject
 
 MonoObject *
 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
-                    MonoObject **exc, MonoArray **out_args) 
+                    MonoObject **exc, MonoArray **out_args, MonoError *error
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
        static MonoClass *object_array_klass;
-       MonoError error;
+       mono_error_init (error);
+
        MonoDomain *domain; 
        MonoMethod *method;
        MonoMethodSignature *sig;
-       MonoObject *ret;
        MonoArray *arr;
        int i, j, outarg_count = 0;
 
@@ -7320,10 +7576,7 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
                if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
                        target = tp->rp->unwrapped_server;
                } else {
-                       ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
-
-                       return ret;
+                       return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
                }
        }
 #endif
@@ -7347,13 +7600,14 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
                object_array_klass = klass;
        }
 
-       arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
-       mono_error_raise_exception (&error); /* FIXME don't raise here */
+       arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
+       return_val_if_nok (error, NULL);
 
        mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
        *exc = NULL;
 
-       ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
+       MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
+       return_val_if_nok (error, NULL);
 
        for (i = 0, j = 0; i < sig->param_count; i++) {
                if (sig->params [i]->byref) {
@@ -7368,25 +7622,24 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
 }
 
 /**
- * mono_object_to_string:
+ * prepare_to_string_method:
  * @obj: The object
- * @exc: Any exception thrown by ToString (). May be NULL.
+ * @target: Set to @obj or unboxed value if a valuetype
  *
- * Returns: the result of calling ToString () on an object.
+ * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
  */
-MonoString *
-mono_object_to_string (MonoObject *obj, MonoObject **exc)
+static MonoMethod *
+prepare_to_string_method (MonoObject *obj, void **target)
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
        static MonoMethod *to_string = NULL;
-       MonoError error;
        MonoMethod *method;
-       MonoString *s;
-       void *target = obj;
-
+       g_assert (target);
        g_assert (obj);
 
+       *target = obj;
+
        if (!to_string)
                to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
 
@@ -7394,9 +7647,25 @@ mono_object_to_string (MonoObject *obj, MonoObject **exc)
 
        // Unbox value type if needed
        if (mono_class_is_valuetype (mono_method_get_class (method))) {
-               target = mono_object_unbox (obj);
+               *target = mono_object_unbox (obj);
        }
+       return method;
+}
 
+/**
+ * mono_object_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). May be NULL.
+ *
+ * Returns: the result of calling ToString () on an object.
+ */
+MonoString *
+mono_object_to_string (MonoObject *obj, MonoObject **exc)
+{
+       MonoError error;
+       MonoString *s = NULL;
+       void *target;
+       MonoMethod *method = prepare_to_string_method (obj, &target);
        if (exc) {
                s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
                if (*exc == NULL && !mono_error_ok (&error))
@@ -7405,12 +7674,52 @@ mono_object_to_string (MonoObject *obj, MonoObject **exc)
                        mono_error_cleanup (&error);
        } else {
                s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
+               mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
        }
 
        return s;
 }
 
+/**
+ * mono_object_to_string_checked:
+ * @obj: The object
+ * @error: Set on error.
+ *
+ * Returns: the result of calling ToString () on an object. If the
+ * method cannot be invoked or if it raises an exception, sets @error
+ * and returns NULL.
+ */
+MonoString *
+mono_object_to_string_checked (MonoObject *obj, MonoError *error)
+{
+       mono_error_init (error);
+       void *target;
+       MonoMethod *method = prepare_to_string_method (obj, &target);
+       return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
+}
+
+/**
+ * mono_object_try_to_string:
+ * @obj: The object
+ * @exc: Any exception thrown by ToString (). Must not be NULL.
+ * @error: Set if method cannot be invoked.
+ *
+ * Returns: the result of calling ToString () on an object. If the
+ * method cannot be invoked sets @error, if it raises an exception sets @exc,
+ * and returns NULL.
+ */
+MonoString *
+mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
+{
+       g_assert (exc);
+       mono_error_init (error);
+       void *target;
+       MonoMethod *method = prepare_to_string_method (obj, &target);
+       return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
+}
+
+
+
 /**
  * mono_print_unhandled_exception:
  * @exc: The exception
@@ -7440,7 +7749,11 @@ mono_print_unhandled_exception (MonoObject *exc)
                        free_message = TRUE;
                } else {
                        MonoObject *other_exc = NULL;
-                       str = mono_object_to_string (exc, &other_exc);
+                       str = mono_object_try_to_string (exc, &other_exc, &error);
+                       if (other_exc == NULL && !is_ok (&error))
+                               other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
+                       else
+                               mono_error_cleanup (&error);
                        if (other_exc) {
                                char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
                                char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);