static char* dump_stack (stackval *stack, stackval *sp);
static char* dump_frame (MonoInvocation *inv);
static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top);
-static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception);
+static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally);
typedef void (*ICallMethod) (MonoInvocation *frame);
break_on_method = 1;
}
-static void debug_enter (MonoInvocation *frame, int *tracing)
+static void
+debug_enter (MonoInvocation *frame, int *tracing)
{
if (db_methods) {
g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
#endif
+/* Set the current execution state to the resume state in context */
+#define SET_RESUME_STATE(context) do { \
+ ip = (context)->handler_ip; \
+ sp->data.p = frame->ex; \
+ ++sp; \
+ frame->ex = NULL; \
+ (context)->has_resume_state = 0; \
+ (context)->handler_frame = NULL; \
+ goto main_loop; \
+ } while (0)
+
static void
interp_ex_handler (MonoException *ex) {
MonoError error;
if (context == NULL)
return;
stack_trace = dump_frame (context->current_frame);
- ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
+ ex->stack_trace = mono_string_new_checked (mono_domain_get(), stack_trace, &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
g_free (stack_trace);
if (context->current_env == NULL || strcmp(ex->object.vtable->klass->name, "ExecutionEngineException") == 0) {
char *strace = mono_string_to_utf8_checked (ex->stack_trace, &error);
static void
fill_in_trace (MonoException *exception, MonoInvocation *frame)
{
+ MonoError error;
char *stack_trace = dump_frame (frame);
MonoDomain *domain = mono_domain_get();
- (exception)->stack_trace = mono_string_new (domain, stack_trace);
+ (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
(exception)->trace_ips = get_trace_ips (domain, frame);
g_free (stack_trace);
}
static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
-struct _MethodArguments {
- size_t ilen;
- gpointer *iargs;
- size_t flen;
- double *fargs;
- gpointer *retval;
- size_t is_float_ret;
-};
-
-typedef struct _MethodArguments MethodArguments;
-
// TODO: this function is also arch dependent (register width).
-static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
+static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
{
- // TODO: don't malloc this data structure.
- MethodArguments *margs = g_malloc0 (sizeof (MethodArguments));
+ InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
if (sig->hasthis)
margs->ilen++;
if (margs->flen > 0)
margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
- if (margs->ilen > 12)
+ if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
- if (margs->flen > 3)
+ if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
MonoInvocation *old_frame = context->current_frame;
MonoInvocation *old_env_frame = context->env_frame;
jmp_buf *old_env = context->current_env;
+ MonoLMFExt ext;
if (setjmp (env)) {
context->current_frame = old_frame;
// mono_tramp_info_register (info, NULL);
}
- MethodArguments *margs = build_args_from_sig (sig, frame);
+ InterpMethodArguments *margs = build_args_from_sig (sig, frame);
#if DEBUG_INTERP
g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
context->current_frame = frame;
context->managed_code = 0;
+ /*
+ * Push an LMF frame on the LMF stack
+ * to mark the transition to native code.
+ */
+ memset (&ext, 0, sizeof (ext));
+ ext.interp_exit = TRUE;
+ ext.interp_exit_data = frame;
+
+ mono_push_lmf (&ext);
+
mono_interp_enter_icall_trampoline (addr, margs);
+ mono_pop_lmf (&ext.lmf);
+
context->managed_code = 1;
/* domain can only be changed by native code */
context->domain = mono_domain_get ();
if (context == NULL) {
context = &context_struct;
+ memset (context, 0, sizeof (ThreadContext));
context_struct.base_frame = &frame;
- context_struct.current_frame = NULL;
context_struct.env_frame = &frame;
context_struct.current_env = &env;
- context_struct.search_for_handler = 0;
- context_struct.managed_code = 0;
mono_native_tls_set_value (thread_context_id, context);
}
else
if (exc)
frame.invoke_trap = 1;
context->managed_code = 1;
- ves_exec_method_with_context (&frame, context, NULL, NULL);
+ ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
context->managed_code = 0;
if (context == &context_struct)
mono_native_tls_set_value (thread_context_id, NULL);
}
}
- init_frame (&frame, context->current_frame, data->rmethod, args, &result);
+ init_frame (&frame, NULL, data->rmethod, args, &result);
context->managed_code = 1;
type = rmethod->rtype;
break;
}
- ves_exec_method_with_context (&frame, context, NULL, NULL);
+ ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
context->managed_code = 0;
if (context == &context_struct)
mono_native_tls_set_value (thread_context_id, NULL);
#define MINT_IN_DEFAULT default:
#endif
+/*
+ * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
+ */
static void
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception)
+ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally)
{
MonoInvocation child_frame;
GSList *finally_ips = NULL;
}
}
- ves_exec_method_with_context (&child_frame, context, NULL, NULL);
+ ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
- ves_exec_method_with_context (&child_frame, context, NULL, NULL);
+ ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
- ves_exec_method_with_context (&child_frame, context, NULL, NULL);
+ ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
MonoFtnDesc ftndesc;
guint8 res_buf [256];
MonoType *type;
+ MonoLMFExt ext;
//printf ("%s\n", mono_method_full_name (rmethod->method, 1));
}
}
+ /*
+ * Push an LMF frame on the LMF stack
+ * to mark the transition to compiled code.
+ */
+ memset (&ext, 0, sizeof (ext));
+ ext.interp_exit = TRUE;
+ ext.interp_exit_data = frame;
+
+ mono_push_lmf (&ext);
+
switch (pindex) {
case 0: {
void (*func)(gpointer) = rmethod->jit_wrapper;
break;
}
+ mono_pop_lmf (&ext.lmf);
+
+ if (context->has_resume_state) {
+ /*
+ * If this bit is set, it means the call has thrown the exception, and we
+ * reached this point because the EH code in mono_handle_exception ()
+ * unwound all the JITted frames below us. mono_interp_set_resume_state ()
+ * has set the fields in context to indicate where we have to resume execution.
+ */
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
MonoType *rtype = rmethod->rtype;
switch (rtype->type) {
case MONO_TYPE_VOID:
sp [0].data.p = unboxed;
}
- ves_exec_method_with_context (&child_frame, context, NULL, NULL);
+ ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
sp [0].data.p = unboxed;
}
- ves_exec_method_with_context (&child_frame, context, NULL, NULL);
+ ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
g_assert (csig->call_convention == MONO_CALL_DEFAULT);
- ves_exec_method_with_context (&child_frame, context, NULL, NULL);
+ ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
context->current_frame = frame;
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
if (child_frame.ex) {
/*
* An exception occurred, need to run finally, fault and catch handlers..
MINT_IN_CASE(MINT_LDELEM)
MINT_IN_CASE(MINT_STELEM)
MINT_IN_CASE(MINT_UNBOX_ANY)
-
- MINT_IN_CASE(MINT_REFANYVAL) ves_abort(); MINT_IN_BREAK;
#endif
MINT_IN_CASE(MINT_CKFINITE)
if (!isfinite(sp [-1].data.f))
THROW_EX (mono_get_exception_arithmetic (), ip);
++ip;
MINT_IN_BREAK;
-#if 0
- MINT_IN_CASE(MINT_MKREFANY) ves_abort(); MINT_IN_BREAK;
-#endif
+ MINT_IN_CASE(MINT_MKREFANY) {
+ c = rtm->data_items [*(guint16 *)(ip + 1)];
+
+ /* The value address is on the stack */
+ gpointer addr = sp [-1].data.p;
+ /* Push the typedref value on the stack */
+ sp [-1].data.p = vt_sp;
+ vt_sp += sizeof (MonoTypedRef);
+
+ MonoTypedRef *tref = sp [-1].data.p;
+ tref->klass = c;
+ tref->type = &c->byval_arg;
+ tref->value = addr;
+
+ ip += 2;
+ MINT_IN_BREAK;
+ }
+ MINT_IN_CASE(MINT_REFANYTYPE) {
+ MonoTypedRef *tref = sp [-1].data.p;
+ MonoType *type = tref->type;
+
+ vt_sp -= sizeof (MonoTypedRef);
+ sp [-1].data.p = vt_sp;
+ vt_sp += 8;
+ *(gpointer*)sp [-1].data.p = type;
+ ip ++;
+ MINT_IN_BREAK;
+ }
+ MINT_IN_CASE(MINT_REFANYVAL) {
+ MonoTypedRef *tref = sp [-1].data.p;
+ gpointer addr = tref->value;
+
+ vt_sp -= sizeof (MonoTypedRef);
+
+ sp [-1].data.p = addr;
+ ip ++;
+ MINT_IN_BREAK;
+ }
MINT_IN_CASE(MINT_LDTOKEN)
sp->data.p = vt_sp;
vt_sp += 8;
BINOP_CAST(l, -, guint64);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_ENDFINALLY)
+ ip ++;
+ int clause_index = *ip;
+ if (clause_index == exit_at_finally)
+ goto exit_frame;
while (sp > frame->stack) {
--sp;
}
stackval retval;
memcpy (&dup_frame, inv, sizeof (MonoInvocation));
dup_frame.retval = &retval;
- ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex);
+ ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex, -1);
if (dup_frame.retval->data.i) {
#if DEBUG_INTERP
if (tracing)
frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
context->managed_code = 1;
- ves_exec_method_with_context (frame, context, NULL, NULL);
+ ves_exec_method_with_context (frame, context, NULL, NULL, -1);
context->managed_code = 0;
if (frame->ex) {
if (context != &context_struct && context->current_env) {
if (need_file_info) {
if (column)
*column = 0;
- if (file)
- *file = mono_string_new (mono_domain_get (), "unknown");
+ if (file) {
+ *file = mono_string_new_checked (mono_domain_get (), "unknown", &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ }
}
return TRUE;
filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
- sf->filename = filename? mono_string_new (domain, filename): NULL;
+ sf->filename = NULL;
+ if (filename) {
+ sf->filename = mono_string_new_checked (domain, filename, &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ }
sf->column = 0;
g_free (filename);
return total;
}
+/*
+ * mono_interp_set_resume_state:
+ *
+ * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
+ */
+void
+mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip)
+{
+ ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+
+ context->has_resume_state = TRUE;
+ context->handler_frame = frame->interp_frame;
+ /* This is on the stack, so it doesn't need a wbarrier */
+ context->handler_frame->ex = ex;
+ context->handler_ip = handler_ip;
+}
+
+/*
+ * mono_interp_run_finally:
+ *
+ * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
+ * frame->interp_frame.
+ */
+void
+mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
+{
+ MonoInvocation *iframe = frame->interp_frame;
+ ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+
+ ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index);
+}
+
+typedef struct {
+ MonoInvocation *current;
+} StackIter;
+
+/*
+ * mono_interp_frame_iter_init:
+ *
+ * Initialize an iterator for iterating through interpreted frames.
+ */
+void
+mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
+{
+ StackIter *stack_iter = (StackIter*)iter;
+
+ stack_iter->current = (MonoInvocation*)interp_exit_data;
+}
+
+gboolean
+mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
+{
+ StackIter *stack_iter = (StackIter*)iter;
+ MonoInvocation *iframe = stack_iter->current;
+
+ memset (frame, 0, sizeof (StackFrameInfo));
+ /* pinvoke frames doesn't have runtime_method set */
+ while (iframe && !iframe->runtime_method)
+ iframe = iframe->parent;
+ if (!iframe)
+ return FALSE;
+
+ frame->type = FRAME_TYPE_INTERP;
+ frame->interp_frame = iframe;
+ frame->method = iframe->runtime_method->method;
+ frame->actual_method = frame->method;
+ /* This is the offset in the interpreter IR */
+ frame->native_offset = iframe->ip - iframe->runtime_method->code;
+ frame->ji = iframe->runtime_method->jinfo;
+
+ stack_iter->current = iframe->parent;
+
+ return TRUE;
+}