#include <mono/mini/mini.h>
#include <mono/mini/jit-icalls.h>
+#include <mono/mini/debugger-agent.h>
+#ifdef TARGET_ARM
+#include <mono/mini/mini-arm.h>
+#endif
/* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
#ifdef _WIN32
* Used for testing.
*/
GSList *jit_classes;
+/* If TRUE, interpreted code will be interrupted at function entry/backward branches */
+static gboolean ss_enabled;
void ves_exec_method (MonoInvocation *frame);
/* Set the current execution state to the resume state in context */
#define SET_RESUME_STATE(context) do { \
ip = (context)->handler_ip; \
+ if (frame->ex) { \
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
+set_context (ThreadContext *context)
+{
+ MonoJitTlsData *jit_tls;
+
+ mono_native_tls_set_value (thread_context_id, context);
+ jit_tls = mono_tls_get_jit_tls ();
+ if (jit_tls)
+ jit_tls->interp_context = context;
+}
+
static void
ves_real_abort (int line, MonoMethod *mh,
const unsigned short *ip, stackval *stack, stackval *sp)
THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
} while (0);
+static RuntimeMethod*
+lookup_runtime_method (MonoDomain *domain, MonoMethod *method)
+{
+ RuntimeMethod *rtm;
+ MonoJitDomainInfo *info;
+
+ info = domain_jit_info (domain);
+ mono_domain_jit_code_hash_lock (domain);
+ rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
+ mono_domain_jit_code_hash_unlock (domain);
+ return rtm;
+}
+
RuntimeMethod*
mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
{
rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
rtm->method = method;
+ rtm->domain = domain;
rtm->param_count = sig->param_count;
rtm->hasthis = sig->hasthis;
rtm->rtype = mini_get_underlying_type (sig->ret);
return mono_interp_get_runtime_method (domain, method, error);
}
+/*
+ * interp_push_lmf:
+ *
+ * Push an LMF frame on the LMF stack
+ * to mark the transition to native code.
+ * This is needed for the native code to
+ * be able to do stack walks.
+ */
+static void
+interp_push_lmf (MonoLMFExt *ext, MonoInvocation *frame)
+{
+ memset (ext, 0, sizeof (MonoLMFExt));
+ ext->interp_exit = TRUE;
+ ext->interp_exit_data = frame;
+
+ mono_push_lmf (ext);
+}
+
+static void
+interp_pop_lmf (MonoLMFExt *ext)
+{
+ mono_pop_lmf (&ext->lmf);
+}
+
static inline RuntimeMethod*
-get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
+get_virtual_method (RuntimeMethod *runtime_method, MonoObject *obj)
{
MonoMethod *m = runtime_method->method;
+ MonoDomain *domain = runtime_method->domain;
+ RuntimeMethod *ret = NULL;
MonoError error;
+#ifndef DISABLE_REMOTING
+ if (mono_object_is_transparent_proxy (obj)) {
+ ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
+ mono_error_assert_ok (&error);
+ return ret;
+ }
+#endif
+
if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
- RuntimeMethod *ret = NULL;
- if (mono_object_is_transparent_proxy (obj)) {
- ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+ if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
} else {
case MONO_TYPE_U4:
result->data.i = *(guint32*)data;
return;
- case MONO_TYPE_R4:
- result->data.f = *(float*)data;
+ case MONO_TYPE_R4: {
+ float tmp;
+ /* memmove handles unaligned case */
+ memmove (&tmp, data, sizeof (float));
+ result->data.f = tmp;
return;
+ }
case MONO_TYPE_I8:
case MONO_TYPE_U8:
- result->data.l = *(gint64*)data;
+ memmove (&result->data.l, data, sizeof (gint64));
return;
case MONO_TYPE_R8:
- result->data.f = *(double*)data;
+ memmove (&result->data.f, data, sizeof (double));
return;
case MONO_TYPE_STRING:
case MONO_TYPE_SZARRAY:
} else
mono_value_copy (result->data.vt, data, type->data.klass);
return;
- case MONO_TYPE_GENERICINST:
+ case MONO_TYPE_GENERICINST: {
+ if (mono_type_generic_inst_is_valuetype (type)) {
+ mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
+ return;
+ }
stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
return;
+ }
default:
g_warning ("got type 0x%02x", type->type);
g_assert_not_reached ();
{
MonoError error;
char *stack_trace = dump_frame (frame);
- MonoDomain *domain = mono_domain_get();
+ MonoDomain *domain = frame->runtime_method->domain;
(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);
#define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
-#define THROW_EX(exception,ex_ip) \
+#define THROW_EX_GENERAL(exception,ex_ip,rethrow) \
do {\
frame->ip = (ex_ip); \
frame->ex = (MonoException*)(exception); \
- FILL_IN_TRACE(frame->ex, frame); \
+ if (!rethrow) { \
+ FILL_IN_TRACE(frame->ex, frame); \
+ } \
goto handle_exception; \
} while (0)
+#define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
+
static MonoObject*
ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
{
{
InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
+#ifdef TARGET_ARM
+ g_assert (mono_arm_eabi_supported ());
+ int i8_align = mono_arm_i8_align ();
+#endif
+
if (sig->hasthis)
margs->ilen++;
break;
#if SIZEOF_VOID_P == 4
case MONO_TYPE_I8:
- g_assert (0);
+#ifdef TARGET_ARM
+ /* pairs begin at even registers */
+ if (i8_align == 8 && margs->ilen & 1)
+ margs->ilen++;
+#endif
+ margs->ilen += 2;
break;
#endif
case MONO_TYPE_R4:
int_i++;
break;
#if SIZEOF_VOID_P == 4
- case MONO_TYPE_I8:
- g_assert (0);
+ case MONO_TYPE_I8: {
+ stackval *sarg = &frame->stack_args [i];
+#ifdef TARGET_ARM
+ /* pairs begin at even registers */
+ if (i8_align == 8 && int_i & 1)
+ int_i++;
+#endif
+ margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
+ int_i++;
+ margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
+#if DEBUG_INTERP
+ g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
+#endif
+ int_i++;
break;
+ }
#endif
case MONO_TYPE_R4:
case MONO_TYPE_R8:
g_assert (!frame->runtime_method);
if (!mono_interp_enter_icall_trampoline) {
- MonoTrampInfo *info;
- mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
- // TODO:
- // mono_tramp_info_register (info, NULL);
+ if (mono_aot_only) {
+ mono_interp_enter_icall_trampoline = mono_aot_get_trampoline ("enter_icall_trampoline");
+ } else {
+ MonoTrampInfo *info;
+ mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
+ // TODO:
+ // mono_tramp_info_register (info, NULL);
+ }
}
InterpMethodArguments *margs = build_args_from_sig (sig, frame);
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);
+ interp_push_lmf (&ext, frame);
mono_interp_enter_icall_trampoline (addr, margs);
- mono_pop_lmf (&ext.lmf);
+ interp_pop_lmf (&ext);
context->managed_code = 1;
- /* domain can only be changed by native code */
- context->domain = mono_domain_get ();
if (*mono_thread_interruption_request_flag ()) {
MonoException *exc = mono_thread_interruption_checkpoint ();
MonoObject *retval = NULL;
MonoMethodSignature *sig = mono_method_signature (method);
MonoClass *klass = mono_class_from_mono_type (sig->ret);
- int i, type, isobject = 0;
- void *ret = NULL;
stackval result;
- stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
+ stackval *args;
ThreadContext context_struct;
MonoInvocation *old_frame = NULL;
jmp_buf env;
if (setjmp(env)) {
if (context != &context_struct) {
- context->domain = mono_domain_get ();
context->current_frame = old_frame;
context->managed_code = 0;
- } else
- mono_native_tls_set_value (thread_context_id, NULL);
+ } else
+ set_context (NULL);
if (exc != NULL)
*exc = (MonoObject *)frame.ex;
return retval;
context_struct.base_frame = &frame;
context_struct.env_frame = &frame;
context_struct.current_env = &env;
- mono_native_tls_set_value (thread_context_id, context);
+ set_context (context);
}
else
old_frame = context->current_frame;
- context->domain = mono_domain_get ();
+ MonoDomain *domain = mono_domain_get ();
- switch (sig->ret->type) {
- case MONO_TYPE_VOID:
- break;
- case MONO_TYPE_STRING:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- isobject = 1;
- break;
- case MONO_TYPE_VALUETYPE:
- retval = mono_object_new_checked (context->domain, klass, error);
- ret = mono_object_unbox (retval);
- if (!sig->ret->data.klass->enumtype)
- result.data.vt = ret;
- else
- result.data.vt = alloca (mono_class_instance_size (klass));
- break;
- case MONO_TYPE_GENERICINST:
- if (!MONO_TYPE_IS_REFERENCE (sig->ret)) {
- retval = mono_object_new_checked (context->domain, klass, error);
- ret = mono_object_unbox (retval);
- if (!sig->ret->data.klass->enumtype)
- result.data.vt = ret;
- else
- result.data.vt = alloca (mono_class_instance_size (klass));
- } else {
- isobject = 1;
- }
- break;
+ MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
- case MONO_TYPE_PTR:
- retval = mono_object_new_checked (context->domain, mono_defaults.int_class, error);
- ret = mono_object_unbox (retval);
- break;
- default:
- retval = mono_object_new_checked (context->domain, klass, error);
- ret = mono_object_unbox (retval);
- break;
- }
+ //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
+
+ result.data.vt = alloca (mono_class_instance_size (klass));
+ args = alloca (sizeof (stackval) * 4);
if (sig->hasthis)
args [0].data.p = obj;
+ else
+ args [0].data.p = NULL;
+ args [1].data.p = params;
+ args [2].data.p = exc;
+ args [3].data.p = method;
- for (i = 0; i < sig->param_count; ++i) {
- int a_index = i + !!sig->hasthis;
- if (sig->params [i]->byref) {
- args [a_index].data.p = params [i];
- continue;
- }
- type = sig->params [i]->type;
-handle_enum:
- switch (type) {
- case MONO_TYPE_U1:
- case MONO_TYPE_I1:
- case MONO_TYPE_BOOLEAN:
- args [a_index].data.i = *(MonoBoolean*)params [i];
- break;
- case MONO_TYPE_U2:
- case MONO_TYPE_I2:
- case MONO_TYPE_CHAR:
- args [a_index].data.i = *(gint16*)params [i];
- break;
-#if SIZEOF_VOID_P == 4
- case MONO_TYPE_U: /* use VAL_POINTER? */
- case MONO_TYPE_I:
-#endif
- case MONO_TYPE_U4:
- case MONO_TYPE_I4:
- args [a_index].data.i = *(gint32*)params [i];
- break;
-#if SIZEOF_VOID_P == 8
- case MONO_TYPE_U:
- case MONO_TYPE_I:
-#endif
- case MONO_TYPE_U8:
- case MONO_TYPE_I8:
- args [a_index].data.l = *(gint64*)params [i];
- break;
- case MONO_TYPE_R4:
- args [a_index].data.f = *(gfloat *) params [i];
- break;
- case MONO_TYPE_R8:
- args [a_index].data.f = *(gdouble *) params [i];
- break;
- case MONO_TYPE_VALUETYPE:
- if (sig->params [i]->data.klass->enumtype) {
- type = mono_class_enum_basetype (sig->params [i]->data.klass)->type;
- goto handle_enum;
- } else {
- args [a_index].data.p = params [i];
- }
- break;
- case MONO_TYPE_STRING:
- case MONO_TYPE_PTR:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_GENERICINST:
- args [a_index].data.p = params [i];
- break;
- default:
- g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type);
- }
- }
+ INIT_FRAME (&frame, context->current_frame, args, &result, domain, invoke_wrapper, error);
- if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
- method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
- INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
if (exc)
frame.invoke_trap = 1;
context->managed_code = 1;
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);
+ set_context (NULL);
else
context->current_frame = old_frame;
if (frame.ex != NULL) {
else
printf("dropped exception...\n");
}
- if (sig->ret->type == MONO_TYPE_VOID && !method->string_ctor)
- return NULL;
- if (isobject || method->string_ctor)
- return result.data.p;
- stackval_to_data (sig->ret, &result, ret, sig->pinvoke);
- return retval;
+ return result.data.p;
}
typedef struct {
memset (context, 0, sizeof (ThreadContext));
context_struct.base_frame = &frame;
context_struct.env_frame = &frame;
- mono_native_tls_set_value (thread_context_id, context);
- }
- else
+ set_context (context);
+ } else {
old_frame = context->current_frame;
- context->domain = mono_domain_get ();
+ }
args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
if (sig->hasthis)
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);
+ set_context (NULL);
else
context->current_frame = old_frame;
return sp;
}
+static stackval *
+do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, MonoInvocation *frame, RuntimeMethod *rmethod)
+{
+ MonoMethodSignature *sig;
+ MonoFtnDesc ftndesc;
+ guint8 res_buf [256];
+ MonoType *type;
+ MonoLMFExt ext;
+
+ //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
+
+ /*
+ * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
+ * by ref and return a return value using an explicit return value argument.
+ */
+ if (!rmethod->jit_wrapper) {
+ MonoMethod *method = rmethod->method;
+ MonoError error;
+
+ sig = mono_method_signature (method);
+ g_assert (sig);
+
+ MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
+ //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
+
+ gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
+ mono_error_assert_ok (&error);
+
+ gpointer addr = mono_jit_compile_method_jit_only (method, &error);
+ g_assert (addr);
+ mono_error_assert_ok (&error);
+
+ rmethod->jit_addr = addr;
+ rmethod->jit_sig = sig;
+ mono_memory_barrier ();
+ rmethod->jit_wrapper = jit_wrapper;
+
+ } else {
+ sig = rmethod->jit_sig;
+ }
+
+ sp -= sig->param_count;
+ if (sig->hasthis)
+ --sp;
+
+ ftndesc.addr = rmethod->jit_addr;
+ ftndesc.arg = NULL;
+
+ // FIXME: Optimize this
+
+ gpointer args [32];
+ int pindex = 0;
+ int stack_index = 0;
+ if (rmethod->hasthis) {
+ args [pindex ++] = sp [0].data.p;
+ stack_index ++;
+ }
+ type = rmethod->rtype;
+ if (type->type != MONO_TYPE_VOID) {
+ if (MONO_TYPE_ISSTRUCT (type))
+ args [pindex ++] = vt_sp;
+ else
+ args [pindex ++] = res_buf;
+ }
+ for (int i = 0; i < rmethod->param_count; ++i) {
+ MonoType *t = rmethod->param_types [i];
+ stackval *sval = &sp [stack_index + i];
+ if (sig->params [i]->byref) {
+ args [pindex ++] = sval->data.p;
+ } else if (MONO_TYPE_ISSTRUCT (t)) {
+ args [pindex ++] = sval->data.p;
+ } else if (MONO_TYPE_IS_REFERENCE (t)) {
+ args [pindex ++] = &sval->data.p;
+ } else {
+ switch (t->type) {
+ case MONO_TYPE_I1:
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I2:
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I4:
+ case MONO_TYPE_U4:
+ case MONO_TYPE_VALUETYPE:
+ args [pindex ++] = &sval->data.i;
+ break;
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_FNPTR:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_OBJECT:
+ args [pindex ++] = &sval->data.p;
+ break;
+ case MONO_TYPE_I8:
+ case MONO_TYPE_U8:
+ args [pindex ++] = &sval->data.l;
+ break;
+ default:
+ printf ("%s\n", mono_type_full_name (t));
+ g_assert_not_reached ();
+ }
+ }
+ }
+
+ interp_push_lmf (&ext, frame);
+
+ switch (pindex) {
+ case 0: {
+ void (*func)(gpointer) = rmethod->jit_wrapper;
+
+ func (&ftndesc);
+ break;
+ }
+ case 1: {
+ void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], &ftndesc);
+ break;
+ }
+ case 2: {
+ void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], args [1], &ftndesc);
+ break;
+ }
+ case 3: {
+ void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], args [1], args [2], &ftndesc);
+ break;
+ }
+ case 4: {
+ void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], args [1], args [2], args [3], &ftndesc);
+ break;
+ }
+ case 5: {
+ void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
+ break;
+ }
+ case 6: {
+ void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
+ break;
+ }
+ case 7: {
+ void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
+
+ func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ interp_pop_lmf (&ext);
+
+ MonoType *rtype = rmethod->rtype;
+ switch (rtype->type) {
+ case MONO_TYPE_VOID:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_ARRAY:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_I:
+ case MONO_TYPE_U:
+ sp->data.p = *(gpointer*)res_buf;
+ break;
+ case MONO_TYPE_I1:
+ sp->data.i = *(gint8*)res_buf;
+ break;
+ case MONO_TYPE_U1:
+ sp->data.i = *(guint8*)res_buf;
+ break;
+ case MONO_TYPE_I2:
+ sp->data.i = *(gint16*)res_buf;
+ break;
+ case MONO_TYPE_U2:
+ sp->data.i = *(guint16*)res_buf;
+ break;
+ case MONO_TYPE_I4:
+ sp->data.i = *(gint32*)res_buf;
+ break;
+ case MONO_TYPE_U4:
+ sp->data.i = *(guint32*)res_buf;
+ break;
+ case MONO_TYPE_VALUETYPE:
+ /* The result was written to vt_sp */
+ sp->data.p = vt_sp;
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (MONO_TYPE_IS_REFERENCE (rtype)) {
+ sp->data.p = *(gpointer*)res_buf;
+ } else {
+ /* The result was written to vt_sp */
+ sp->data.p = vt_sp;
+ }
+ break;
+ default:
+ printf ("%s\n", mono_type_full_name (rtype));
+ g_assert_not_reached ();
+ break;
+ }
+
+ return sp;
+}
+
+static void
+do_debugger_tramp (void (*tramp) (void), MonoInvocation *frame)
+{
+ MonoLMFExt ext;
+ interp_push_lmf (&ext, frame);
+ tramp ();
+ interp_pop_lmf (&ext);
+}
+
+static void
+do_transform_method (MonoInvocation *frame, ThreadContext *context)
+{
+ MonoLMFExt ext;
+
+ /* Use the parent frame as the current frame is not complete yet */
+ interp_push_lmf (&ext, frame->parent);
+
+ frame->ex = mono_interp_transform_method (frame->runtime_method, context);
+ context->managed_code = 1;
+
+ interp_pop_lmf (&ext);
+}
+
/*
* These functions are the entry points into the interpreter from compiled code.
* They are called by the interp_in wrappers. They have the following signature:
gpointer addr;
MonoMethodSignature *sig = mono_method_signature (method);
MonoMethod *wrapper;
- RuntimeMethod *rmethod;
+ RuntimeMethod *rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
/* HACK: method_ptr of delegate should point to a runtime method*/
if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
- return mono_interp_get_runtime_method (mono_domain_get (), method, error);
+ return rmethod;
- rmethod = mono_interp_get_runtime_method (mono_domain_get (), method, error);
if (rmethod->jit_entry)
return rmethod->jit_entry;
wrapper = mini_get_interp_in_wrapper (sig);
* rgctx register using a trampoline.
*/
- // FIXME: AOT
- g_assert (!mono_aot_only);
- addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
+ if (mono_aot_only)
+ addr = mono_aot_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
+ else
+ addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
mono_memory_barrier ();
rmethod->jit_entry = addr;
g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
g_free (mn);
#endif
- frame->ex = mono_interp_transform_method (frame->runtime_method, context);
- context->managed_code = 1;
+
+ do_transform_method (frame, context);
if (frame->ex) {
rtm = NULL;
ip = NULL;
vtalloc = vt_sp;
#endif
locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
+ frame->locals = locals;
child_frame.parent = frame;
if (filter_exception) {
MINT_IN_BREAK;
MINT_IN_CASE(MINT_BREAK)
++ip;
- G_BREAKPOINT (); /* this is not portable... */
+ do_debugger_tramp (mono_debugger_agent_user_break, frame);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDNULL)
sp->data.p = NULL;
vtalloc = vt_sp;
#endif
locals = vt_sp + rtm->vt_stack_size;
+ frame->locals = locals;
ip = rtm->new_body_start; /* bypass storing input args from callers frame */
MINT_IN_BREAK;
}
--sp;
child_frame.stack_args = sp;
+#ifndef DISABLE_REMOTING
/* `this' can be NULL for string:.ctor */
if (csignature->hasthis && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
- child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
+ child_frame.runtime_method = mono_interp_get_runtime_method (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- } else if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
- child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
+ } else
+#endif
+ if (child_frame.runtime_method->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+ child_frame.runtime_method = mono_interp_get_runtime_method (rtm->domain, mono_marshal_get_native_wrapper (child_frame.runtime_method->method, FALSE, FALSE), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
--sp;
child_frame.stack_args = sp;
+#ifndef DISABLE_REMOTING
/* `this' can be NULL for string:.ctor */
if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) {
- child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
+ child_frame.runtime_method = mono_interp_get_runtime_method (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
+#endif
ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
}
child_frame.stack_args = sp;
+#ifndef DISABLE_REMOTING
if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
- child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
+ child_frame.runtime_method = mono_interp_get_runtime_method (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
+#endif
ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1);
}
MINT_IN_CASE(MINT_JIT_CALL) {
- MonoMethodSignature *sig;
RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
- MonoFtnDesc ftndesc;
- guint8 res_buf [256];
- MonoType *type;
- MonoLMFExt ext;
-
- //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
-
- /*
- * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
- * by ref and return a return value using an explicit return value argument.
- */
- if (!rmethod->jit_wrapper) {
- MonoMethod *method = rmethod->method;
- MonoError error;
-
- sig = mono_method_signature (method);
- g_assert (sig);
-
- MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
- //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
-
- gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
- mono_error_assert_ok (&error);
-
- gpointer addr = mono_jit_compile_method_jit_only (method, &error);
- g_assert (addr);
- mono_error_assert_ok (&error);
-
- rmethod->jit_addr = addr;
- rmethod->jit_sig = sig;
- mono_memory_barrier ();
- rmethod->jit_wrapper = jit_wrapper;
-
- } else {
- sig = rmethod->jit_sig;
- }
-
frame->ip = ip;
ip += 2;
- sp -= sig->param_count;
- if (sig->hasthis)
- --sp;
-
- ftndesc.addr = rmethod->jit_addr;
- ftndesc.arg = NULL;
-
- // FIXME: Optimize this
-
- gpointer args [32];
- int pindex = 0;
- int stack_index = 0;
- if (rmethod->hasthis) {
- args [pindex ++] = sp [0].data.p;
- stack_index ++;
- }
- type = rmethod->rtype;
- if (type->type != MONO_TYPE_VOID) {
- if (MONO_TYPE_ISSTRUCT (type))
- args [pindex ++] = vt_sp;
- else
- args [pindex ++] = res_buf;
- }
- for (int i = 0; i < rmethod->param_count; ++i) {
- MonoType *t = rmethod->param_types [i];
- stackval *sval = &sp [stack_index + i];
- if (sig->params [i]->byref) {
- args [pindex ++] = sval->data.p;
- } else if (MONO_TYPE_ISSTRUCT (t)) {
- args [pindex ++] = sval->data.p;
- } else if (MONO_TYPE_IS_REFERENCE (t)) {
- args [pindex ++] = &sval->data.p;
- } else {
- switch (t->type) {
- case MONO_TYPE_I1:
- case MONO_TYPE_U1:
- case MONO_TYPE_I2:
- case MONO_TYPE_U2:
- case MONO_TYPE_I4:
- case MONO_TYPE_U4:
- case MONO_TYPE_VALUETYPE:
- args [pindex ++] = &sval->data.i;
- break;
- case MONO_TYPE_PTR:
- case MONO_TYPE_FNPTR:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- case MONO_TYPE_OBJECT:
- args [pindex ++] = &sval->data.p;
- break;
- case MONO_TYPE_I8:
- case MONO_TYPE_U8:
- args [pindex ++] = &sval->data.l;
- break;
- default:
- printf ("%s\n", mono_type_full_name (t));
- g_assert_not_reached ();
- }
- }
- }
-
- /*
- * 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;
-
- func (&ftndesc);
- break;
- }
- case 1: {
- void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], &ftndesc);
- break;
- }
- case 2: {
- void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], args [1], &ftndesc);
- break;
- }
- case 3: {
- void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], args [1], args [2], &ftndesc);
- break;
- }
- case 4: {
- void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], args [1], args [2], args [3], &ftndesc);
- break;
- }
- case 5: {
- void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
- break;
- }
- case 6: {
- void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
- break;
- }
- case 7: {
- void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
-
- func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
- break;
- }
- default:
- g_assert_not_reached ();
- break;
- }
-
- mono_pop_lmf (&ext.lmf);
+ sp = do_jit_call (sp, vt_sp, context, frame, rmethod);
if (context->has_resume_state) {
/*
else
goto exit_frame;
}
-
- MonoType *rtype = rmethod->rtype;
- switch (rtype->type) {
- case MONO_TYPE_VOID:
- case MONO_TYPE_OBJECT:
- case MONO_TYPE_STRING:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_I:
- case MONO_TYPE_U:
- sp->data.p = *(gpointer*)res_buf;
- break;
- case MONO_TYPE_I1:
- sp->data.i = *(gint8*)res_buf;
- break;
- case MONO_TYPE_U1:
- sp->data.i = *(guint8*)res_buf;
- break;
- case MONO_TYPE_I2:
- sp->data.i = *(gint16*)res_buf;
- break;
- case MONO_TYPE_U2:
- sp->data.i = *(guint16*)res_buf;
- break;
- case MONO_TYPE_I4:
- sp->data.i = *(gint32*)res_buf;
- break;
- case MONO_TYPE_U4:
- sp->data.i = *(guint32*)res_buf;
- break;
- case MONO_TYPE_VALUETYPE:
- /* The result was written to vt_sp */
- sp->data.p = vt_sp;
- break;
- case MONO_TYPE_GENERICINST:
- if (MONO_TYPE_IS_REFERENCE (rtype)) {
- sp->data.p = *(gpointer*)res_buf;
- } else {
- /* The result was written to vt_sp */
- sp->data.p = vt_sp;
- }
- break;
- default:
- printf ("%s\n", mono_type_full_name (rtype));
- g_assert_not_reached ();
- break;
- }
- if (rtype->type != MONO_TYPE_VOID)
+ if (rmethod->rtype->type != MONO_TYPE_VOID)
sp++;
+
MINT_IN_BREAK;
}
this_arg = sp->data.p;
if (!this_arg)
THROW_EX (mono_get_exception_null_reference(), ip - 2);
- child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
+ child_frame.runtime_method = get_virtual_method (child_frame.runtime_method, this_arg);
MonoClass *this_class = this_arg->vtable->klass;
if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
this_arg = sp->data.p;
if (!this_arg)
THROW_EX (mono_get_exception_null_reference(), ip - 2);
- child_frame.runtime_method = get_virtual_method (context->domain, child_frame.runtime_method, this_arg);
+ child_frame.runtime_method = get_virtual_method (child_frame.runtime_method, this_arg);
MonoClass *this_class = this_arg->vtable->klass;
if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) {
goto exit_frame;
MINT_IN_CASE(MINT_RET_VOID)
if (sp > frame->stack)
- g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
+ g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->runtime_method->method, TRUE));
goto exit_frame;
MINT_IN_CASE(MINT_RET_VT)
i32 = READ32(ip + 1);
gint offset;
ip += 2 * (guint32)sp->data.i;
offset = READ32 (ip);
- ip = st + offset;
+ ip = ip + offset;
} else {
ip = st;
}
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_I8)
++ip;
- sp[-1].data.l = *(gint64*)sp[-1].data.p;
+ /* memmove handles unaligned case */
+ memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDIND_I) {
guint16 offset = * (guint16 *)(ip + 1);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CPOBJ) {
c = rtm->data_items[* (guint16 *)(ip + 1)];
- g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
+ g_assert (c->valuetype);
/* if this assertion fails, we need to add a write barrier */
g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
- stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+ if (c->byval_arg.type == MONO_TYPE_VALUETYPE)
+ stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+ else
+ stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
ip += 2;
sp -= 2;
MINT_IN_BREAK;
if (newobj_class->parent == mono_defaults.array_class) {
sp -= csig->param_count;
child_frame.stack_args = sp;
- o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
+ o = ves_array_create (&child_frame, rtm->domain, newobj_class, csig, sp);
if (child_frame.ex)
THROW_EX (child_frame.ex, ip);
goto array_constructed;
} else {
if (newobj_class != mono_defaults.string_class) {
context->managed_code = 0;
- o = mono_object_new_checked (context->domain, newobj_class, &error);
+ o = mono_object_new_checked (rtm->domain, newobj_class, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
context->managed_code = 1;
if (*mono_thread_interruption_request_flag ())
frame->ex_handler = NULL;
if (!sp->data.p)
sp->data.p = mono_get_exception_null_reference ();
+
THROW_EX ((MonoException *)sp->data.p, ip);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
THROW_EX (mono_get_exception_null_reference (), ip);
field = rtm->data_items[* (guint16 *)(ip + 1)];
ip += 2;
+#ifndef DISABLE_REMOTING
if (mono_object_is_transparent_proxy (o)) {
MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- } else {
+ } else
+#endif
addr = (char*)o + field->offset;
- }
stackval_from_data (field->type, &sp [-1], addr, FALSE);
MINT_IN_BREAK;
field = rtm->data_items[* (guint16 *)(ip + 1)];
i32 = READ32(ip + 2);
ip += 4;
+#ifndef DISABLE_REMOTING
if (mono_object_is_transparent_proxy (o)) {
MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- } else {
+ } else
+#endif
addr = (char*)o + field->offset;
- }
sp [-1].data.p = vt_sp;
memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
field = rtm->data_items[* (guint16 *)(ip + 1)];
ip += 2;
+#ifndef DISABLE_REMOTING
if (mono_object_is_transparent_proxy (o)) {
MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
} else
+#endif
stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
sp -= 2;
i32 = READ32(ip + 2);
ip += 4;
+#ifndef DISABLE_REMOTING
if (mono_object_is_transparent_proxy (o)) {
MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
} else
+#endif
memcpy((char*)o + field->offset, sp [-1].data.p, i32);
sp -= 2;
}
MINT_IN_CASE(MINT_LDSFLDA) {
MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
- sp->data.p = mono_class_static_field_address (context->domain, field);
+ sp->data.p = mono_class_static_field_address (rtm->domain, field);
ip += 2;
++sp;
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_LDSFLD) {
MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
- gpointer addr = mono_class_static_field_address (context->domain, field);
+ gpointer addr = mono_class_static_field_address (rtm->domain, field);
stackval_from_data (field->type, sp, addr, FALSE);
ip += 2;
++sp;
}
MINT_IN_CASE(MINT_LDSFLD_VT) {
MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
- gpointer addr = mono_class_static_field_address (context->domain, field);
+ gpointer addr = mono_class_static_field_address (rtm->domain, field);
int size = READ32 (ip + 2);
ip += 4;
}
MINT_IN_CASE(MINT_STSFLD) {
MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
- gpointer addr = mono_class_static_field_address (context->domain, field);
+ gpointer addr = mono_class_static_field_address (rtm->domain, field);
ip += 2;
--sp;
stackval_to_data (field->type, sp, addr, FALSE);
}
MINT_IN_CASE(MINT_STSFLD_VT) {
MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
- gpointer addr = mono_class_static_field_address (context->domain, field);
+ gpointer addr = mono_class_static_field_address (rtm->domain, field);
int size = READ32 (ip + 2);
ip += 4;
if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
int size = mono_class_value_size (c, NULL);
- sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, sp [-1 - offset].data.p, &error);
+ sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
size = (size + 7) & ~7;
vt_sp -= size;
} else {
stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
- sp [-1 - offset].data.p = mono_value_box_checked (context->domain, c, &sp [-1 - offset], &error);
+ sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
ip += 3;
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_NEWARR)
- sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
+ sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
if (!mono_error_ok (&error)) {
THROW_EX (mono_error_convert_to_exception (&error), ip);
}
++sp;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_MONO_NEWOBJ)
- sp->data.p = mono_object_new_checked (context->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
+ sp->data.p = mono_object_new_checked (rtm->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
ip += 2;
sp++;
ip += 3;
MINT_IN_BREAK;
}
+ MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
+ ++ip;
+ mono_memory_barrier ();
+ MINT_IN_BREAK;
+ }
MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
++ip;
MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
gpointer tls_jit = ((gpointer (*)()) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
- if (tls_domain != context->domain || !tls_jit)
- context->original_domain = mono_jit_thread_attach (context->domain);
+ if (tls_domain != rtm->domain || !tls_jit)
+ context->original_domain = mono_jit_thread_attach (rtm->domain);
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_MONO_JIT_DETACH)
++ip;
mono_jit_set_domain (context->original_domain);
MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_MONO_LDDOMAIN)
+ sp->data.p = mono_domain_get ();
+ ++sp;
+ ++ip;
+ MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_SDB_INTR_LOC)
+ if (G_UNLIKELY (ss_enabled)) {
+ static void (*ss_tramp) (void);
+
+ if (!ss_tramp) {
+ void *tramp = mini_get_single_step_trampoline ();
+ mono_memory_barrier ();
+ ss_tramp = tramp;
+ }
+
+ /*
+ * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
+ * the address of that instruction is stored as the seq point address.
+ */
+ frame->ip = ip + 1;
+
+ /*
+ * Use the same trampoline as the JIT. This ensures that
+ * the debugger has the context for the last interpreter
+ * native frame.
+ */
+ do_debugger_tramp (ss_tramp, frame);
+
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+ }
+ ++ip;
+ MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_SDB_SEQ_POINT)
+ /* Just a placeholder for a breakpoint */
+ ++ip;
+ MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
+ static void (*bp_tramp) (void);
+ if (!bp_tramp) {
+ void *tramp = mini_get_breakpoint_trampoline ();
+ mono_memory_barrier ();
+ bp_tramp = tramp;
+ }
+
+ frame->ip = ip;
+
+ /* Use the same trampoline as the JIT */
+ do_debugger_tramp (bp_tramp, frame);
+
+ if (context->has_resume_state) {
+ if (frame == context->handler_frame)
+ SET_RESUME_STATE (context);
+ else
+ goto exit_frame;
+ }
+
+ ++ip;
+ MINT_IN_BREAK;
+ }
#define RELOP(datamem, op) \
--sp; \
if (!sp->data.p)
THROW_EX (mono_get_exception_null_reference (), ip - 2);
- sp->data.p = get_virtual_method (context->domain, m, sp->data.p);
+ sp->data.p = get_virtual_method (m, sp->data.p);
++sp;
MINT_IN_BREAK;
}
ip += 2;
MINT_IN_BREAK;
#endif
- MINT_IN_CASE(MINT_RETHROW)
+ MINT_IN_CASE(MINT_RETHROW) {
/*
* need to clarify what this should actually do:
* start the search from the last found handler in
* We need to NULL frame->ex_handler for the later code to
* actually run the new found handler.
*/
+ int exvar_offset = *(guint16*)(ip + 1);
frame->ex_handler = NULL;
- THROW_EX (frame->ex, ip - 1);
+ THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip - 1, TRUE);
MINT_IN_BREAK;
+ }
MINT_IN_DEFAULT
g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
g_print ("* Matched Filter at '%s'\n", method->name);
#endif
inv->ex_handler = clause;
+ *(MonoException**)(inv->locals + inv->runtime_method->exvar_offsets [i]) = frame->ex;
goto handle_finally;
}
} else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) {
g_print ("* Found handler at '%s'\n", method->name);
#endif
inv->ex_handler = clause;
+ *(MonoException**)(inv->locals + inv->runtime_method->exvar_offsets [i]) = frame->ex;
goto handle_finally;
}
}
{
ThreadContext *context = mono_native_tls_get_value (thread_context_id);
ThreadContext context_struct;
+ MonoDomain *domain = frame->runtime_method->domain;
MonoError error;
jmp_buf env;
}
if (context == NULL) {
context = &context_struct;
- context_struct.domain = mono_domain_get ();
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);
+ set_context (context);
}
frame->ip = NULL;
frame->parent = context->current_frame;
- frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
+ frame->runtime_method = mono_interp_get_runtime_method (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, -1);
mono_unhandled_exception ((MonoObject*)frame->ex);
}
if (context->base_frame == frame)
- mono_native_tls_set_value (thread_context_id, NULL);
+ set_context (NULL);
else
context->current_frame = frame->parent;
}
mono_interp_init ()
{
mono_native_tls_alloc (&thread_context_id, NULL);
- mono_native_tls_set_value (thread_context_id, NULL);
+ set_context (NULL);
mono_interp_transform_init ();
}
* 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)
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+ ThreadContext *context;
+
+ g_assert (jit_tls);
+ context = jit_tls->interp_context;
+ g_assert (context);
context->has_resume_state = TRUE;
- context->handler_frame = frame->interp_frame;
+ context->handler_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;
memset (frame, 0, sizeof (StackFrameInfo));
/* pinvoke frames doesn't have runtime_method set */
- while (iframe && !iframe->runtime_method)
+ while (iframe && !(iframe->runtime_method && iframe->runtime_method->code))
iframe = iframe->parent;
if (!iframe)
return FALSE;
frame->type = FRAME_TYPE_INTERP;
+ // FIXME:
+ frame->domain = mono_domain_get ();
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->native_offset = (guint8*)iframe->ip - (guint8*)iframe->runtime_method->code;
frame->ji = iframe->runtime_method->jinfo;
stack_iter->current = iframe->parent;
return TRUE;
}
+
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
+{
+ RuntimeMethod* rtm;
+
+ rtm = lookup_runtime_method (domain, method);
+ if (rtm)
+ return rtm->jinfo;
+ else
+ return NULL;
+}
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+ guint16 *code = (guint16*)ip;
+ g_assert (*code == MINT_SDB_SEQ_POINT);
+ *code = MINT_SDB_BREAKPOINT;
+}
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+ guint16 *code = (guint16*)ip;
+ g_assert (*code == MINT_SDB_BREAKPOINT);
+ *code = MINT_SDB_SEQ_POINT;
+}
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+ return iframe->runtime_method->jinfo;
+}
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+ return (gpointer)iframe->ip;
+}
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+
+ int arg_offset = iframe->runtime_method->arg_offsets [pos + (iframe->runtime_method->hasthis ? 1 : 0)];
+
+ return iframe->args + arg_offset;
+}
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+
+ return iframe->locals + iframe->runtime_method->local_offsets [pos];
+}
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame)
+{
+ MonoInvocation *iframe = (MonoInvocation*)frame;
+
+ g_assert (iframe->runtime_method);
+ g_assert (iframe->runtime_method->hasthis);
+
+ int arg_offset = iframe->runtime_method->arg_offsets [0];
+
+ return iframe->args + arg_offset;
+}
+
+void
+mono_interp_start_single_stepping (void)
+{
+ ss_enabled = TRUE;
+}
+
+void
+mono_interp_stop_single_stepping (void)
+{
+ ss_enabled = FALSE;
+}