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
#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;
* 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);
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. */
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);
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. */
* 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;
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;
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);
method_count += mono_class_num_methods (ic);
}
g_ptr_array_free (ifaces, TRUE);
+ ifaces = NULL;
}
extra_interface_vtsize += method_count * sizeof (gpointer);
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;
}
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;
+ }
}
}
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);
}
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 */
}
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) {
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);
* @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;
MonoRemoteClass *remote_class;
gboolean redo_vtable;
+ mono_error_init (error);
mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
mono_domain_lock (domain);
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 */
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;
}
}
} 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;
}
}
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;
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)
{
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;
}
}
- 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)
}
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
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.
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;
}
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;
}
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;
}
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;
}
#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;
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;
}
}
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;
}
}
/**
- * 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);
// 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))
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
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);