frame->stack_args = method_args;
frame->retval = method_retval;
frame->imethod = rmethod;
- frame->ex = NULL;
frame->ip = NULL;
}
// FIXME The inlining of this needs to be reevaluated in the context of later changes.
// Also there is now only one caller, so consider inlining it manually.
static MONO_NEVER_INLINE GSList* // Inlining this causes caller to use more stack.
-set_resume_state (ThreadContext *context, InterpFrame *frame, GSList* finally_ips)
+clear_resume_state (ThreadContext *context, InterpFrame *frame, GSList* finally_ips)
{
/* We have thrown an exception from a finally block. Some of the leave targets were unwound already */
while (finally_ips &&
finally_ips->data >= context->handler_ei->try_start &&
finally_ips->data < context->handler_ei->try_end)
finally_ips = g_slist_remove (finally_ips, finally_ips->data);
- frame->ex = NULL;
context->has_resume_state = 0;
context->handler_frame = NULL;
context->handler_ei = NULL;
+ g_assert (context->exc_gchandle);
+ mono_gchandle_free_internal (context->exc_gchandle);
+ context->exc_gchandle = 0;
return finally_ips;
}
interp_push_lmf (&ext, frame);
frame->ip = ip;
- frame->ex = ex;
if (mono_object_isinst_checked ((MonoObject *) ex, mono_defaults.exception_class, error)) {
MonoException *mono_ex = ex;
}
static gint32
-ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
+ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
{
- g_assert (!frame->ex);
MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
guint32 pos = 0;
guint32 idx = sp [i].data.i;
guint32 lower = ao->bounds [i].lower_bound;
guint32 len = ao->bounds [i].length;
- if (safe && (idx < lower || (idx - lower) >= len)) {
- frame->ex = mono_get_exception_index_out_of_range ();
+ if (safe && (idx < lower || (idx - lower) >= len))
return -1;
- }
pos = (pos * len) + idx - lower;
}
} else {
pos = sp [0].data.i;
- if (safe && pos >= ao->max_length) {
- frame->ex = mono_get_exception_index_out_of_range ();
+ if (safe && pos >= ao->max_length)
return -1;
- }
}
return pos;
}
-static MONO_NEVER_INLINE void
+static MONO_NEVER_INLINE MonoException*
ves_array_set (InterpFrame *frame, stackval *sp, MonoMethodSignature *sig)
{
MonoObject *o = sp->data.o;
g_assert (m_class_get_rank (ac) >= 1);
- gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, TRUE);
- if (frame->ex)
- return;
+ gint32 pos = ves_array_calculate_index (ao, sp + 1, TRUE);
+ if (pos == -1)
+ return mono_get_exception_index_out_of_range ();
int val_index = 1 + m_class_get_rank (ac);
if (sp [val_index].data.p && !m_class_is_valuetype (m_class_get_element_class (mono_object_class (o)))) {
ERROR_DECL (error);
MonoObject *isinst = mono_object_isinst_checked (sp [val_index].data.o, m_class_get_element_class (mono_object_class (o)), error);
mono_error_cleanup (error);
- if (!isinst) {
- frame->ex = mono_get_exception_array_type_mismatch ();
- return;
- }
+ if (!isinst)
+ return mono_get_exception_array_type_mismatch ();
}
gint32 esize = mono_array_element_size (ac);
MonoType *mt = sig->params [m_class_get_rank (ac)];
stackval_to_data (mt, &sp [val_index], ea, FALSE);
+ return NULL;
}
-static void
+static MonoException*
ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
{
MonoObject *o = sp->data.o;
g_assert (m_class_get_rank (ac) >= 1);
- gint32 pos = ves_array_calculate_index (ao, sp + 1, frame, safe);
- if (frame->ex)
- return;
+ gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
+ if (pos == -1)
+ return mono_get_exception_index_out_of_range ();
gint32 esize = mono_array_element_size (ac);
gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);
MonoType *mt = sig->ret;
stackval_from_data (mt, retval, ea, FALSE);
+ return NULL;
}
-static MONO_NEVER_INLINE gpointer
+static MONO_NEVER_INLINE MonoException*
ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
{
MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
g_assert (m_class_get_rank (ac) >= 1);
- gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
- if (frame->ex)
- return NULL;
+ gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
+ if (pos == -1)
+ return mono_get_exception_index_out_of_range ();
- if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type)) {
- frame->ex = mono_get_exception_array_type_mismatch ();
- return NULL;
- }
+ if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
+ return mono_get_exception_array_type_mismatch ();
gint32 esize = mono_array_element_size (ac);
- return mono_array_addr_with_size_fast (ao, esize, pos);
+ sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos);
+ return NULL;
}
#ifdef MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE
MonoLMFExt ext;
gpointer args;
- frame->ex = NULL;
-
g_assert (!frame->imethod);
static MonoPIFunc entry_func = NULL;
interp_pop_lmf (&ext);
#ifdef MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
- if (!frame->ex)
+ if (!context->has_resume_state)
mono_arch_get_native_call_context_ret (&ccontext, frame, sig);
if (ccontext.stack != NULL)
g_free (ccontext.stack);
#else
- if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
+ if (!context->has_resume_state && !MONO_TYPE_ISSTRUCT (sig->ret))
stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
g_free (margs->iargs);
* runtime specifies that the implementation of the method is automatically
* provided by the runtime and is primarily used for the methods of delegates.
*/
-static MONO_NEVER_INLINE void
+static MONO_NEVER_INLINE MonoException*
ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval)
{
const char *name = method->name;
if (!strcmp (name, "UnsafeMov")) {
/* TODO: layout checks */
stackval_from_data (sig->ret, retval, (char*) sp, FALSE);
- return;
- }
- if (!strcmp (name, "UnsafeLoad")) {
- ves_array_get (frame, sp, retval, sig, FALSE);
- return;
+ return NULL;
}
+ if (!strcmp (name, "UnsafeLoad"))
+ return ves_array_get (frame, sp, retval, sig, FALSE);
} else if (mini_class_is_system_array (method->klass)) {
MonoObject *obj = (MonoObject*) sp->data.p;
- if (!obj) {
- frame->ex = mono_get_exception_null_reference ();
- return;
- }
- if (*name == 'S' && (strcmp (name, "Set") == 0)) {
- ves_array_set (frame, sp, sig);
- return;
- }
- if (*name == 'G' && (strcmp (name, "Get") == 0)) {
- ves_array_get (frame, sp, retval, sig, TRUE);
- return;
- }
+ if (!obj)
+ return mono_get_exception_null_reference ();
+ if (*name == 'S' && (strcmp (name, "Set") == 0))
+ return ves_array_set (frame, sp, sig);
+ if (*name == 'G' && (strcmp (name, "Get") == 0))
+ return ves_array_get (frame, sp, retval, sig, TRUE);
}
g_error ("Don't know how to exec runtime method %s.%s::%s",
if (exc)
*exc = NULL;
- frame.ex = NULL;
-
MonoDomain *domain = mono_domain_get ();
if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
interp_exec_method (&frame, context, error);
- if (frame.ex) {
- if (exc) {
- *exc = (MonoObject*) frame.ex;
- return NULL;
- }
- mono_error_set_exception_instance (error, frame.ex);
+ if (context->has_resume_state) {
+ // This can happen on wasm !?
+ MonoException *thrown_exc = (MonoException*) mono_gchandle_get_target_internal (context->exc_gchandle);
+ if (exc)
+ *exc = (MonoObject*)thrown_exc;
+ else
+ mono_error_set_exception_instance (error, thrown_exc);
return NULL;
}
return (MonoObject*)result.data.p;
//printf ("%s\n", mono_method_full_name (method, 1));
- frame.ex = NULL;
-
args = g_newa (stackval, sig->param_count + (sig->hasthis ? 1 : 0));
if (sig->hasthis)
args [0].data.p = data->this_arg;
ERROR_DECL (error);
interp_exec_method (&frame, context, error);
+ g_assert (!context->has_resume_state);
+
if (rmethod->needs_thread_attach)
mono_threads_detach_coop (orig_domain, &attach_cookie);
if (mono_llvm_only) {
- if (frame.ex)
- mono_llvm_reraise_exception (frame.ex);
+ if (context->has_resume_state)
+ mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
} else {
- g_assert (frame.ex == NULL);
+ g_assert (!context->has_resume_state);
}
type = rmethod->rtype;
interp_pop_lmf (&ext);
}
-static MONO_NEVER_INLINE void
+static MONO_NEVER_INLINE MonoException*
do_transform_method (InterpFrame *frame, ThreadContext *context)
{
MonoLMFExt ext;
interp_push_lmf (&ext, frame->parent);
mono_interp_transform_method (frame->imethod, context, error);
- frame->ex = mono_error_convert_to_exception (error);
if (push_lmf)
interp_pop_lmf (&ext);
+
+ return mono_error_convert_to_exception (error);
}
static MONO_NEVER_INLINE guchar*
method = rmethod->method;
sig = mono_method_signature_internal (method);
- frame.ex = NULL;
-
args = (stackval*)alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
init_frame (&frame, NULL, rmethod, args, &result);
ERROR_DECL (error);
interp_exec_method (&frame, context, error);
+ g_assert (!context->has_resume_state);
+
if (rmethod->needs_thread_attach)
mono_threads_detach_coop (orig_domain, &attach_cookie);
- // FIXME:
- g_assert (frame.ex == NULL);
-
/* Write back the return value */
mono_arch_set_native_call_context_ret (ccontext, &frame, sig);
}
};
#endif
- frame->ex = NULL;
#if DEBUG_INTERP
debug_enter (frame, &tracing);
#endif
#endif
frame->ip = NULL;
- do_transform_method (frame, context);
- if (frame->ex)
- THROW_EX (frame->ex, NULL);
+ MonoException *ex = do_transform_method (frame, context);
+ if (ex)
+ THROW_EX (ex, NULL);
EXCEPTION_CHECKPOINT;
}
frame->ip = ip;
mono_interp_transform_method (new_method, context, error);
- frame->ex = mono_error_convert_to_exception (error);
- if (frame->ex)
- goto exit_frame;
+ MonoException *ex = mono_error_convert_to_exception (error);
+ if (ex)
+ THROW_EX (ex, ip);
}
ip += 2;
const gboolean realloc_frame = new_method->alloca_size > frame->imethod->alloca_size;
if (sig->hasthis)
sp--;
- ves_imethod (frame, target_method, sig, sp, retval);
- if (frame->ex)
- THROW_EX (frame->ex, ip);
+ MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval);
+ if (ex)
+ THROW_EX (ex, ip);
if (sig->ret->type != MONO_TYPE_VOID) {
*sp = *retval;
ip += 2; // FIXME: Do this after throw?
child_frame.ip = NULL;
- child_frame.ex = NULL;
child_frame.imethod = (InterpMethod*)frame->imethod->data_items [token];
MonoMethodSignature* const csig = mono_method_signature_internal (child_frame.imethod->method);
MonoClass *klass = (MonoClass*)frame->imethod->data_items [*(guint16 *) (ip - 3 + 1)];
const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC;
- sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
- if (frame->ex)
- THROW_EX (frame->ex, ip);
+ MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
+ if (ex)
+ THROW_EX (ex, ip);
++sp;
MINT_IN_BREAK;
finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
#if DEBUG_INTERP
if (tracing)
- g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
+ g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, context->has_resume_state ? "yes": "no");
#endif
}
}
/* spec says stack should be empty at endfinally so it should be at the start too */
sp = frame->stack;
vt_sp = (guchar*)sp + frame->imethod->stack_size;
- if (frame->ex) {
- sp->data.p = frame->ex;
- ++sp;
- }
+ g_assert (context->exc_gchandle);
+ sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle);
+ ++sp;
- // FIXME Reevaluate if this should be inlined.
- finally_ips = set_resume_state (context, frame, finally_ips);
+ finally_ips = clear_resume_state (context, frame, finally_ips);
// goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack.
// This is a slow/rare path and conserving stack is preferred over its performance otherwise.
- //
goto main_loop;
}
// fall through
if (clause_args && clause_args->base_frame)
memcpy (clause_args->base_frame->stack, frame->stack, frame->imethod->alloca_size);
- if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
+ if (!context->has_resume_state && MONO_PROFILER_ENABLED (method_leave) &&
frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
MonoProfilerCallContext *prof_ctx = NULL;
MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
g_free (prof_ctx);
- } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
- MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
+ } else if (context->has_resume_state && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
+ MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, mono_gchandle_get_target_internal (context->exc_gchandle)));
DEBUG_LEAVE ();
}
context->has_resume_state = TRUE;
context->handler_frame = (InterpFrame*)interp_frame;
context->handler_ei = ei;
- /* This is on the stack, so it doesn't need a wbarrier */
- context->handler_frame->ex = ex;
+ if (context->exc_gchandle)
+ mono_gchandle_free_internal (context->exc_gchandle);
+ context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
/* Ditto */
if (ei)
*(MonoException**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;