[runtime] Mark mono_runtime_run_main external only.
[mono.git] / mono / metadata / object.c
index c5fa20e1bb1e83f5c4010016c514e5ba4de3fe46..98172647db732eedf19e46f5dbbbcb348cdb9a02 100644 (file)
@@ -457,6 +457,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 +542,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 +2216,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 +2224,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 +2275,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 +2283,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 +2306,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 +2334,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 +2356,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 +2371,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 +2401,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 +2415,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 +2451,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 +2476,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 +2748,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 +2771,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 +2793,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 +2808,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 +2828,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 */
 
@@ -2970,7 +3007,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;
 }
@@ -3978,7 +4015,7 @@ mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **
                }
        } else {
                MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &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 result;
        }
 }
@@ -4131,22 +4168,14 @@ mono_runtime_set_main_args (int argc, char* argv[])
        return 0;
 }
 
-/**
- * mono_runtime_run_main:
- * @method: the method to start the application with (usually Main)
- * @argc: number of arguments from the command line
- * @argv: array of strings from the command line
- * @exc: excetption results
- *
- * Execute a standard Main() method (argc/argv contains the
- * executable name). This method also sets the command line argument value
- * needed by System.Environment.
- *
+/*
+ * Prepare an array of arguments in order to execute a standard Main()
+ * method (argc/argv contains the executable name). This method also
+ * sets the command line argument value needed by System.Environment.
  * 
  */
-int
-mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
-                      MonoObject **exc)
+static MonoArray*
+prepare_run_main (MonoMethod *method, int argc, char *argv[])
 {
        MONO_REQ_GC_UNSAFE_MODE;
 
@@ -4237,9 +4266,92 @@ mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
        
        mono_assembly_set_main (method->klass->image->assembly);
 
-       return mono_runtime_exec_main (method, args, exc);
+       return args;
+}
+
+/**
+ * mono_runtime_run_main:
+ * @method: the method to start the application with (usually Main)
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ * @exc: excetption results
+ *
+ * Execute a standard Main() method (argc/argv contains the
+ * executable name). This method also sets the command line argument value
+ * needed by System.Environment.
+ *
+ * 
+ */
+int
+mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
+                      MonoObject **exc)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       MonoError error;
+       MonoArray *args = prepare_run_main (method, argc, argv);
+       int res;
+       if (exc) {
+               res = mono_runtime_try_exec_main (method, args, exc, &error);
+               if (*exc == NULL && !is_ok (&error))
+                       *exc = (MonoObject*) mono_error_convert_to_exception (&error);
+               else
+                       mono_error_cleanup (&error);
+       } else {
+               res = mono_runtime_exec_main_checked (method, args, &error);
+               mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
+       }
+       return res;
+}
+
+/**
+ * mono_runtime_run_main_checked:
+ * @method: the method to start the application with (usually Main)
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ * @error: set on error
+ *
+ * Execute a standard Main() method (argc/argv contains the
+ * executable name). This method also sets the command line argument value
+ * needed by System.Environment.  On failure sets @error.
+ *
+ * 
+ */
+int
+mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
+                              MonoError *error)
+{
+       mono_error_init (error);
+       MonoArray *args = prepare_run_main (method, argc, argv);
+       return mono_runtime_exec_main_checked (method, args, error);
 }
 
+/**
+ * mono_runtime_try_run_main:
+ * @method: the method to start the application with (usually Main)
+ * @argc: number of arguments from the command line
+ * @argv: array of strings from the command line
+ * @exc: set if Main throws an exception
+ * @error: set if Main can't be executed
+ *
+ * Execute a standard Main() method (argc/argv contains the executable
+ * name). This method also sets the command line argument value needed
+ * by System.Environment.  On failure sets @error if Main can't be
+ * executed or @exc if it threw and exception.
+ *
+ * 
+ */
+int
+mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
+                          MonoObject **exc, MonoError *error)
+{
+       g_assert (exc);
+       mono_error_init (error);
+       MonoArray *args = prepare_run_main (method, argc, argv);
+       return mono_runtime_try_exec_main (method, args, exc, error);
+}
+
+
 static MonoObject*
 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
 {
@@ -4598,28 +4710,13 @@ mono_runtime_exec_managed_code (MonoDomain *domain,
        mono_thread_manage ();
 }
 
-/*
- * Execute a standard Main() method (args doesn't contain the
- * executable name).
- */
-int
-mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
+static void
+prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
 {
-       MONO_REQ_GC_UNSAFE_MODE;
-
-       MonoError error;
-       MonoDomain *domain;
-       gpointer pa [1];
-       int rval;
+       MonoInternalThread* thread = mono_thread_internal_current ();
        MonoCustomAttrInfo* cinfo;
        gboolean has_stathread_attribute;
-       MonoInternalThread* thread = mono_thread_internal_current ();
-
-       g_assert (args);
-
-       pa [0] = args;
 
-       domain = mono_object_domain (args);
        if (!domain->entry_assembly) {
                gchar *str;
                MonoAssembly *assembly;
@@ -4639,8 +4736,9 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
                }
        }
 
-       cinfo = mono_custom_attrs_from_method_checked (method, &error);
-       mono_error_cleanup (&error); /* FIXME warn here? */
+       MonoError cattr_error;
+       cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
+       mono_error_cleanup (&cattr_error); /* FIXME warn here? */
        if (cinfo) {
                has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
                if (!cinfo->cached)
@@ -4655,39 +4753,85 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        }
        mono_thread_init_apartment_state ();
 
+}
+
+static int
+do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       gpointer pa [1];
+       int rval;
+
+       mono_error_init (error);
+       g_assert (args);
+
+       pa [0] = args;
+
        /* FIXME: check signature of method */
        if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
                MonoObject *res;
-               if (exc) {
-                       res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
-                       if (*exc == NULL && !mono_error_ok (&error))
-                               *exc = (MonoObject*) mono_error_convert_to_exception (&error);
-                       else
-                               mono_error_cleanup (&error);
-               } else {
-                       res = mono_runtime_invoke_checked (method, NULL, pa, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
+               res = mono_runtime_invoke_checked (method, NULL, pa, error);
+               if (is_ok (error))
+                       rval = *(guint32 *)((char *)res + sizeof (MonoObject));
+               else
+                       rval = -1;
+               mono_environment_exitcode_set (rval);
+       } else {
+               mono_runtime_invoke_checked (method, NULL, pa, error);
+
+               if (is_ok (error))
+                       rval = 0;
+               else {
+                       /* If the return type of Main is void, only
+                        * set the exitcode if an exception was thrown
+                        * (we don't want to blow away an
+                        * explicitly-set exit code)
+                        */
+                       rval = -1;
+                       mono_environment_exitcode_set (rval);
                }
+       }
+       return rval;
+}
+
+static int
+do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc, MonoError *error)
+{
+       MONO_REQ_GC_UNSAFE_MODE;
+
+       gpointer pa [1];
+       int rval;
+
+       mono_error_init (error);
+       g_assert (args);
+       g_assert (exc);
 
-               if (!exc || !*exc)
+       pa [0] = args;
+
+       /* FIXME: check signature of method */
+       if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
+               MonoObject *res;
+               res = mono_runtime_try_invoke (method, NULL, pa, exc, error);
+               if (*exc == NULL && !mono_error_ok (error))
+                       *exc = (MonoObject*) mono_error_convert_to_exception (error);
+               else
+                       mono_error_cleanup (error);
+
+               if (*exc == NULL)
                        rval = *(guint32 *)((char *)res + sizeof (MonoObject));
                else
                        rval = -1;
 
                mono_environment_exitcode_set (rval);
        } else {
-               if (exc) {
-                       mono_runtime_try_invoke (method, NULL, pa, exc, &error);
-                       if (*exc == NULL && !mono_error_ok (&error))
-                               *exc = (MonoObject*) mono_error_convert_to_exception (&error);
-                       else
-                               mono_error_cleanup (&error);
-               } else {
-                       mono_runtime_invoke_checked (method, NULL, pa, &error);
-                       mono_error_raise_exception (&error); /* FIXME don't raise here */
-               }
+               mono_runtime_try_invoke (method, NULL, pa, exc, error);
+               if (*exc == NULL && !mono_error_ok (error))
+                       *exc = (MonoObject*) mono_error_convert_to_exception (error);
+               else
+                       mono_error_cleanup (error);
 
-               if (!exc || !*exc)
+               if (*exc == NULL)
                        rval = 0;
                else {
                        /* If the return type of Main is void, only
@@ -4703,6 +4847,59 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        return rval;
 }
 
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
+ */
+int
+mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
+{
+       MonoError error;
+       prepare_thread_to_exec_main (mono_object_domain (args), method);
+       if (exc) {
+               int rval = do_try_exec_main (method, args, exc, &error);
+               if (*exc == NULL && !is_ok (&error))
+                       *exc = (MonoObject*) mono_error_convert_to_exception (&error);
+               else
+                       mono_error_cleanup (&error);
+               return rval;
+       } else {
+               int rval = do_exec_main_checked (method, args, &error);
+               mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
+               return rval;
+       }
+}
+
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
+ *
+ * On failure sets @error
+ */
+int
+mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
+{
+       mono_error_init (error);
+       prepare_thread_to_exec_main (mono_object_domain (args), method);
+       return do_exec_main_checked (method, args, error);
+}
+
+/*
+ * Execute a standard Main() method (args doesn't contain the
+ * executable name).
+ *
+ * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
+ */
+int
+mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc, MonoError *error)
+{
+       mono_error_init (error);
+       prepare_thread_to_exec_main (mono_object_domain (args), method);
+       return do_try_exec_main (method, args, exc, error);
+}
+
+
+
 /** invoke_array_extract_argument:
  * @params: array of arguments to the method.
  * @i: the index of the argument to extract.
@@ -5156,7 +5353,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;
 }
@@ -5286,7 +5483,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;
 }
@@ -5374,7 +5571,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;
 }
@@ -5489,7 +5686,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;
 }
 
@@ -6264,7 +6461,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;
@@ -6505,7 +6702,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;
                }
        }
@@ -6795,8 +6993,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;
 }
 
@@ -7543,25 +7743,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);
 
@@ -7569,9 +7768,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))
@@ -7580,12 +7795,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
@@ -7615,7 +7870,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);