-/*
+/**
+ * \file
* PLEASE NOTE: This is a research prototype.
*
*
/* trim excessive headers */
#include <mono/metadata/image.h>
-#include <mono/metadata/assembly.h>
+#include <mono/metadata/assembly-internals.h>
#include <mono/metadata/cil-coff.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/marshal.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/mono-debug.h>
+#include <mono/utils/atomic.h>
#include "interp.h"
#include "interp-internals.h"
#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
#endif
#endif
-#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) \
- do { \
- (frame)->parent = (parent_frame); \
- (frame)->stack_args = (method_args); \
- (frame)->retval = (method_retval); \
- (frame)->runtime_method = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
- (frame)->ex = NULL; \
- (frame)->ip = NULL; \
- (frame)->invoke_trap = 0; \
+static inline void
+init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *rmethod, stackval *method_args, stackval *method_retval)
+{
+ frame->parent = parent_frame;
+ frame->stack_args = method_args;
+ frame->retval = method_retval;
+ frame->runtime_method = rmethod;
+ frame->ex = NULL;
+ frame->ip = NULL;
+ frame->invoke_trap = 0;
+}
+
+#define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
+ RuntimeMethod *_rmethod = mono_interp_get_runtime_method ((domain), (mono_method), (error)); \
+ init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
} while (0)
+/*
+ * List of classes whose methods will be executed by transitioning to JITted code.
+ * 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);
-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);
+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; \
+ 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
-interp_ex_handler (MonoException *ex) {
- MonoError error;
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
- char *stack_trace;
- if (context == NULL)
- return;
- stack_trace = dump_frame (context->current_frame);
- ex->stack_trace = mono_string_new (mono_domain_get(), stack_trace);
- 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);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- fprintf(stderr, "Nothing can catch this exception: ");
- fprintf(stderr, "%s", ex->object.vtable->klass->name);
- if (ex->message != NULL) {
- char *m = mono_string_to_utf8_checked (ex->message, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- fprintf(stderr, ": %s", m);
- g_free(m);
- }
- fprintf(stderr, "\n%s\n", strace);
- g_free (strace);
- if (ex->inner_ex != NULL) {
- ex = (MonoException *)ex->inner_ex;
- fprintf(stderr, "Inner exception: %s", ex->object.vtable->klass->name);
- if (ex->message != NULL) {
- char *m = mono_string_to_utf8_checked (ex->message, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- fprintf(stderr, ": %s", m);
- g_free(m);
- }
- strace = mono_string_to_utf8_checked (ex->stack_trace, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- fprintf(stderr, "\n");
- fprintf(stderr, "%s\n", strace);
- g_free (strace);
- }
- /* wait for other threads to also collapse */
- // Sleep(1000); // TODO: proper sleep
- exit(1);
- }
- context->env_frame->ex = ex;
- context->search_for_handler = 1;
- longjmp (*context->current_env, 1);
+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
THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
} while (0);
-static mono_mutex_t runtime_method_lookup_section;
+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)
{
RuntimeMethod *rtm;
+ MonoJitDomainInfo *info;
+ MonoMethodSignature *sig;
+ int i;
+
error_init (error);
- mono_os_mutex_lock (&runtime_method_lookup_section);
- if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) {
- mono_os_mutex_unlock (&runtime_method_lookup_section);
+ 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);
+ if (rtm)
return rtm;
- }
- rtm = mono_mempool_alloc (domain->mp, sizeof (RuntimeMethod));
- memset (rtm, 0, sizeof (*rtm));
+
+ sig = mono_method_signature (method);
+
+ rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
rtm->method = method;
- rtm->param_count = mono_method_signature (method)->param_count;
- rtm->hasthis = mono_method_signature (method)->hasthis;
- mono_internal_hash_table_insert (&domain->jit_code_hash, method, rtm);
- mono_os_mutex_unlock (&runtime_method_lookup_section);
+ rtm->domain = domain;
+ rtm->param_count = sig->param_count;
+ rtm->hasthis = sig->hasthis;
+ rtm->rtype = mini_get_underlying_type (sig->ret);
+ rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
+ for (i = 0; i < sig->param_count; ++i)
+ rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
+
+ mono_domain_jit_code_hash_lock (domain);
+ if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
+ mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
+ mono_domain_jit_code_hash_unlock (domain);
return rtm;
}
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 {
virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
+
+ if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
+ virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
+ }
+
RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
return virtual_runtime_method;
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 ();
case MONO_TYPE_SZARRAY:
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
- case MONO_TYPE_ARRAY:
+ case MONO_TYPE_ARRAY: {
+ gpointer *p = (gpointer *) data;
+ mono_gc_wbarrier_generic_store (p, val->data.p);
+ return;
+ }
case MONO_TYPE_PTR: {
- gpointer *p = (gpointer*)data;
+ gpointer *p = (gpointer *) data;
*p = val->data.p;
return;
}
} else
mono_value_copy (data, val->data.vt, type->data.klass);
return;
- case MONO_TYPE_GENERICINST:
+ case MONO_TYPE_GENERICINST: {
+ MonoClass *container_class = type->data.generic_class->container_class;
+
+ if (container_class->valuetype && !container_class->enumtype) {
+ mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
+ return;
+ }
stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
return;
+ }
default:
g_warning ("got type %x", type->type);
g_assert_not_reached ();
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);
+ 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);
g_free (stack_trace);
}
#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 (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
+ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
{
uintptr_t *lengths;
intptr_t *lower_bounds;
lengths += klass->rank;
}
obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
+ if (!mono_error_ok (&error)) {
+ frame->ex = mono_error_convert_to_exception (&error);
+ FILL_IN_TRACE (frame->ex, frame);
+ }
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
return obj;
}
static gint32
-ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
+ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame, gboolean safe)
{
g_assert (!frame->ex);
MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
guint32 idx = sp [i].data.i;
guint32 lower = ao->bounds [i].lower_bound;
guint32 len = ao->bounds [i].length;
- if (idx < lower || (idx - lower) >= len) {
+ if (safe && (idx < lower || (idx - lower) >= len)) {
frame->ex = mono_get_exception_index_out_of_range ();
FILL_IN_TRACE (frame->ex, frame);
return -1;
}
} else {
pos = sp [0].data.i;
- if (pos >= ao->max_length) {
+ if (safe && pos >= ao->max_length) {
frame->ex = mono_get_exception_index_out_of_range ();
FILL_IN_TRACE (frame->ex, frame);
return -1;
g_assert (ac->rank >= 1);
- gint32 pos = ves_array_calculate_index (ao, sp, frame);
+ gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
if (frame->ex)
return;
}
static void
-ves_array_get (MonoInvocation *frame)
+ves_array_get (MonoInvocation *frame, gboolean safe)
{
stackval *sp = frame->stack_args + 1;
g_assert (ac->rank >= 1);
- gint32 pos = ves_array_calculate_index (ao, sp, frame);
+ gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
if (frame->ex)
return;
g_assert (ac->rank >= 1);
- gint32 pos = ves_array_calculate_index (ao, sp, frame);
+ gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
if (frame->ex)
return NULL;
MonoError error;
ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+ if (!context)
+ return;
+
MonoInvocation *frame = context->current_frame;
while (frame) {
return;
frame = frame->parent;
}
-
- g_assert (0);
}
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));
+
+#ifdef TARGET_ARM
+ g_assert (mono_arm_eabi_supported ());
+ int i8_align = mono_arm_i8_align ();
+#endif
if (sig->hasthis)
margs->ilen++;
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_STRING:
- case MONO_TYPE_I8:
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_GENERICINST:
+#if SIZEOF_VOID_P == 8
+ case MONO_TYPE_I8:
+#endif
margs->ilen++;
break;
+#if SIZEOF_VOID_P == 4
+ case MONO_TYPE_I8:
+#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:
+#if SIZEOF_VOID_P == 8
case MONO_TYPE_R8:
+#endif
margs->flen++;
break;
+#if SIZEOF_VOID_P == 4
+ case MONO_TYPE_R8:
+ margs->flen += 2;
+ break;
+#endif
default:
g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
}
if (margs->flen > 0)
margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
- if (margs->ilen > 8)
+ 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);
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
case MONO_TYPE_STRING:
- case MONO_TYPE_I8:
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_GENERICINST:
+#if SIZEOF_VOID_P == 8
+ case MONO_TYPE_I8:
+#endif
margs->iargs [int_i] = frame->stack_args [i].data.p;
#if DEBUG_INTERP
- g_print ("build_args_from_sig: margs->iargs[%d]: %p (frame @ %d)\n", int_i, margs->iargs[int_i], i);
+ g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
#endif
int_i++;
break;
+#if SIZEOF_VOID_P == 4
+ 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:
- margs->fargs [int_f] = frame->stack_args [i].data.f;
+ if (ptype == MONO_TYPE_R4)
+ * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
+ else
+ margs->fargs [int_f] = frame->stack_args [i].data.f;
+#if DEBUG_INTERP
+ g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i);
+#endif
+#if SIZEOF_VOID_P == 4
+ int_f += 2;
+#else
int_f++;
+#endif
break;
default:
g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
case MONO_TYPE_VALUETYPE:
case MONO_TYPE_GENERICINST:
margs->retval = &(frame->retval->data.p);
+ margs->is_float_ret = 0;
break;
case MONO_TYPE_R4:
case MONO_TYPE_R8:
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;
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);
+ }
}
- 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;
+ interp_push_lmf (&ext, frame);
+
mono_interp_enter_icall_trampoline (addr, margs);
+ 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 ();
void
mono_interp_init_delegate (MonoDelegate *del)
{
- if (!del->method)
- del->method = ((RuntimeMethod *) del->method_ptr)->method;
+ if (del->method)
+ return;
+ /* shouldn't need a write barrier because we don't write a MonoObject into the field */
+ del->method = ((RuntimeMethod *) del->method_ptr)->method;
}
/*
mono_class_init (method->klass);
+ if (method->klass == mono_defaults.array_class) {
+ if (!strcmp (method->name, "UnsafeMov")) {
+ /* TODO: layout checks */
+ MonoType *mt = mono_method_signature (method)->ret;
+ stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
+ return;
+ }
+ if (!strcmp (method->name, "UnsafeLoad")) {
+ ves_array_get (frame, FALSE);
+ return;
+ }
+ }
+
isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
if (obj && isinst_obj) {
return;
}
if (*name == 'G' && (strcmp (name, "Get") == 0)) {
- ves_array_get (frame);
+ ves_array_get (frame, TRUE);
return;
}
}
method->name);
}
+#if DEBUG_INTERP
static char*
dump_stack (stackval *stack, stackval *sp)
{
}
return g_string_free (str, FALSE);
}
+#endif
static void
dump_stackval (GString *str, stackval *s, MonoType *type)
}
}
+#if DEBUG_INTERP
+static char*
+dump_retval (MonoInvocation *inv)
+{
+ GString *str = g_string_new ("");
+ MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
+
+ if (ret->type != MONO_TYPE_VOID)
+ dump_stackval (str, inv->retval, ret);
+
+ return g_string_free (str, FALSE);
+}
+#endif
+
static char*
dump_args (MonoInvocation *inv)
{
return g_string_free (str, FALSE);
}
-
-static char*
-dump_retval (MonoInvocation *inv)
-{
- GString *str = g_string_new ("");
- MonoType *ret = mono_method_signature (inv->runtime_method->method)->ret;
-
- if (ret->type != MONO_TYPE_VOID)
- dump_stackval (str, inv->retval, ret);
-
- return g_string_free (str, FALSE);
-}
static char*
dump_frame (MonoInvocation *inv)
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;
error_init (error);
+ if (exc)
+ *exc = NULL;
frame.ex = NULL;
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;
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);
+ 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:
isobject = 1;
break;
case MONO_TYPE_VALUETYPE:
- retval = mono_object_new_checked (context->domain, klass, error);
- ret = ((char*)retval) + sizeof (MonoObject);
+ retval = mono_object_new_checked (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 (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;
+
+ case MONO_TYPE_PTR:
+ retval = mono_object_new_checked (domain, mono_defaults.int_class, error);
+ ret = mono_object_unbox (retval);
break;
default:
- retval = mono_object_new_checked (context->domain, klass, error);
- ret = ((char*)retval) + sizeof (MonoObject);
+ retval = mono_object_new_checked (domain, klass, error);
+ ret = mono_object_unbox (retval);
break;
}
+ args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
if (sig->hasthis)
args [0].data.p = obj;
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;
}
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:
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);
+
+ INIT_FRAME (&frame,context->current_frame,args,&result,domain,method,error);
if (exc)
frame.invoke_trap = 1;
context->managed_code = 1;
- ves_exec_method_with_context (&frame, context);
+ 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) {
context->env_frame->ex = frame.ex;
longjmp(*context->current_env, 1);
}
- else
- printf("dropped exception...\n");
+ 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;
+}
+
+typedef struct {
+ RuntimeMethod *rmethod;
+ gpointer this_arg;
+ gpointer res;
+ gpointer args [16];
+ gpointer *many_args;
+} InterpEntryData;
+
+/* Main function for entering the interpreter from compiled code */
+static void
+interp_entry (InterpEntryData *data)
+{
+ MonoInvocation frame;
+ RuntimeMethod *rmethod = data->rmethod;
+ ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+ ThreadContext context_struct;
+ MonoInvocation *old_frame;
+ stackval result;
+ stackval *args;
+ MonoMethod *method;
+ MonoMethodSignature *sig;
+ MonoType *type;
+ int i;
+
+ method = rmethod->method;
+ sig = mono_method_signature (method);
+
+ // FIXME: Optimize this
+
+ //printf ("%s\n", mono_method_full_name (method, 1));
+
+ frame.ex = NULL;
+ if (context == NULL) {
+ context = &context_struct;
+ memset (context, 0, sizeof (ThreadContext));
+ context_struct.base_frame = &frame;
+ context_struct.env_frame = &frame;
+ set_context (context);
+ } else {
+ old_frame = context->current_frame;
+ }
+
+ args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
+ if (sig->hasthis)
+ args [0].data.p = data->this_arg;
+
+ gpointer *params;
+ if (data->many_args)
+ params = data->many_args;
+ else
+ params = data->args;
+ for (i = 0; i < sig->param_count; ++i) {
+ int a_index = i + (sig->hasthis ? 1 : 0);
+ if (sig->params [i]->byref) {
+ args [a_index].data.p = params [i];
+ continue;
+ }
+ type = rmethod->param_types [i];
+ switch (type->type) {
+ case MONO_TYPE_U1:
+ case MONO_TYPE_I1:
+ args [a_index].data.i = *(MonoBoolean*)params [i];
+ break;
+ case MONO_TYPE_U2:
+ case MONO_TYPE_I2:
+ args [a_index].data.i = *(gint16*)params [i];
+ break;
+ case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+ args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
+#else
+ args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
+#endif
+ break;
+ case MONO_TYPE_I:
+#if SIZEOF_VOID_P == 4
+ args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
+#else
+ args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
+#endif
+ break;
+ case MONO_TYPE_U4:
+ args [a_index].data.i = *(guint32*)params [i];
+ break;
+ case MONO_TYPE_I4:
+ args [a_index].data.i = *(gint32*)params [i];
+ break;
+ case MONO_TYPE_U8:
+ args [a_index].data.l = *(guint64*)params [i];
+ break;
+ case MONO_TYPE_I8:
+ args [a_index].data.l = *(gint64*)params [i];
+ break;
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_OBJECT:
+ args [a_index].data.p = *(MonoObject**)params [i];
+ break;
+ case MONO_TYPE_VALUETYPE:
+ args [a_index].data.p = params [i];
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (MONO_TYPE_IS_REFERENCE (type))
+ args [a_index].data.p = params [i];
+ else
+ args [a_index].data.vt = params [i];
+ break;
+ default:
+ printf ("%s\n", mono_type_full_name (sig->params [i]));
+ NOT_IMPLEMENTED;
+ break;
+ }
+ }
+
+ init_frame (&frame, NULL, data->rmethod, args, &result);
+ context->managed_code = 1;
+
+ type = rmethod->rtype;
+ switch (type->type) {
+ case MONO_TYPE_GENERICINST:
+ if (!MONO_TYPE_IS_REFERENCE (type))
+ frame.retval->data.vt = data->res;
+ break;
+ case MONO_TYPE_VALUETYPE:
+ frame.retval->data.vt = data->res;
+ break;
+ default:
+ break;
+ }
+
+ ves_exec_method_with_context (&frame, context, NULL, NULL, -1);
+ context->managed_code = 0;
+ if (context == &context_struct)
+ set_context (NULL);
+ else
+ context->current_frame = old_frame;
+
+ // FIXME:
+ g_assert (frame.ex == NULL);
+
+ type = rmethod->rtype;
+ switch (type->type) {
+ case MONO_TYPE_VOID:
+ break;
+ case MONO_TYPE_I1:
+ *(gint8*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_U1:
+ *(guint8*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_I2:
+ *(gint16*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_U2:
+ *(guint16*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_I4:
+ *(gint32*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_U4:
+ *(guint64*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_I8:
+ *(gint64*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_U8:
+ *(guint64*)data->res = frame.retval->data.i;
+ break;
+ case MONO_TYPE_I:
+#if SIZEOF_VOID_P == 8
+ *(gint64*)data->res = (gint64)frame.retval->data.p;
+#else
+ *(gint32*)data->res = (gint32)frame.retval->data.p;
+#endif
+ break;
+ case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 8
+ *(guint64*)data->res = (guint64)frame.retval->data.p;
+#else
+ *(guint32*)data->res = (guint32)frame.retval->data.p;
+#endif
+ break;
+ case MONO_TYPE_OBJECT:
+ /* No need for a write barrier */
+ *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
+ break;
+ case MONO_TYPE_GENERICINST:
+ if (MONO_TYPE_IS_REFERENCE (type)) {
+ *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
+ } else {
+ /* Already set before the call */
+ }
+ break;
+ case MONO_TYPE_VALUETYPE:
+ /* Already set before the call */
+ break;
+ default:
+ printf ("%s\n", mono_type_full_name (sig->ret));
+ NOT_IMPLEMENTED;
+ break;
}
- 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;
}
static stackval *
switch (op) {
case MINT_ICALL_V_V: {
- void (*func)() = ptr;
+ void (*func)(void) = ptr;
func ();
break;
}
case MINT_ICALL_V_P: {
- gpointer (*func)() = ptr;
+ gpointer (*func)(void) = ptr;
sp++;
sp [-1].data.p = func ();
break;
return sp;
}
-static mono_mutex_t create_method_pointer_mutex;
+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;
-static GHashTable *method_pointer_hash = NULL;
+ sig = mono_method_signature (method);
+ g_assert (sig);
-static MonoMethod *method_pointers [2] = {0};
+ 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));
-static MonoObject *
-mp_tramp_0 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) {
- MonoError error;
- void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method};
- MonoObject *ret = mono_interp_runtime_invoke (method_pointers [0], NULL, params_real, NULL, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- return ret;
+ 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 MonoObject *
-mp_tramp_1 (MonoObject *this_obj, void **params, MonoObject **exc, void *compiled_method) {
- MonoError error;
- void *params_real[] = {this_obj, ¶ms, &exc, &compiled_method};
- MonoObject *ret = mono_interp_runtime_invoke (method_pointers [1], NULL, params_real, NULL, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- return ret;
+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);
}
-gpointer *mp_tramps[] = {(gpointer) mp_tramp_0, (gpointer) mp_tramp_1};
+/*
+ * 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:
+ * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
+ * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
+ * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
+ * more wrappers then these functions.
+ * this/static * ret/void * 16 arguments -> 64 functions.
+ */
+
+#define MAX_INTERP_ENTRY_ARGS 8
+
+#define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
+ InterpEntryData data; \
+ (data).rmethod = (_method); \
+ (data).res = (_res); \
+ (data).this_arg = (_this_arg); \
+ (data).many_args = NULL;
+
+#define INTERP_ENTRY0(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY1(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY2(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY3(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ (data).args [2] = arg3; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY4(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ (data).args [2] = arg3; \
+ (data).args [3] = arg4; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY5(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ (data).args [2] = arg3; \
+ (data).args [3] = arg4; \
+ (data).args [4] = arg5; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY6(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ (data).args [2] = arg3; \
+ (data).args [3] = arg4; \
+ (data).args [4] = arg5; \
+ (data).args [5] = arg6; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY7(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ (data).args [2] = arg3; \
+ (data).args [3] = arg4; \
+ (data).args [4] = arg5; \
+ (data).args [5] = arg6; \
+ (data).args [6] = arg7; \
+ interp_entry (&data); \
+ }
+#define INTERP_ENTRY8(_this_arg, _res, _method) { \
+ INTERP_ENTRY_BASE (_method, _this_arg, _res); \
+ (data).args [0] = arg1; \
+ (data).args [1] = arg2; \
+ (data).args [2] = arg3; \
+ (data).args [3] = arg4; \
+ (data).args [4] = arg5; \
+ (data).args [5] = arg6; \
+ (data).args [6] = arg7; \
+ (data).args [7] = arg8; \
+ interp_entry (&data); \
+ }
-static int tramps_used = 0;
+#define ARGLIST0 RuntimeMethod *rmethod
+#define ARGLIST1 gpointer arg1, RuntimeMethod *rmethod
+#define ARGLIST2 gpointer arg1, gpointer arg2, RuntimeMethod *rmethod
+#define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, RuntimeMethod *rmethod
+#define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, RuntimeMethod *rmethod
+#define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, RuntimeMethod *rmethod
+#define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, RuntimeMethod *rmethod
+#define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, RuntimeMethod *rmethod
+#define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, RuntimeMethod *rmethod
+
+static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
+static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
+static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
+static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
+static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
+static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
+static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
+static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
+static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
+static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
+static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
+static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
+static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
+static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
+static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
+static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
+static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
+static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
+static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
+static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
+static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
+static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
+static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
+static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
+static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
+static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
+static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
+static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY6 (this_arg, res, rmethod)
+static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY6 (this_arg, res, rmethod)
+
+#define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
+
+gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
+gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
+gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
+gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
+
+/* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
+static void
+interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
+{
+ INTERP_ENTRY_BASE (rmethod, this_arg, res);
+ data.many_args = args;
+ interp_entry (&data);
+}
+/*
+ * mono_interp_create_method_pointer:
+ *
+ * Return a function pointer which can be used to call METHOD using the
+ * interpreter. Return NULL for methods which are not supported.
+ */
gpointer
mono_interp_create_method_pointer (MonoMethod *method, MonoError *error)
{
gpointer addr;
- MonoJitInfo *ji;
-
- mono_os_mutex_lock (&create_method_pointer_mutex);
- if (!method_pointer_hash) {
- // FIXME: is registering method table as GC root really necessary?
- // MONO_GC_REGISTER_ROOT_FIXED (method_pointer_hash);
- method_pointer_hash = g_hash_table_new (NULL, NULL);
- }
- addr = g_hash_table_lookup (method_pointer_hash, method);
- if (addr) {
- mono_os_mutex_unlock (&create_method_pointer_mutex);
- return addr;
+ MonoMethodSignature *sig = mono_method_signature (method);
+ MonoMethod *wrapper;
+ 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 rmethod;
+
+ if (rmethod->jit_entry)
+ return rmethod->jit_entry;
+ wrapper = mini_get_interp_in_wrapper (sig);
+
+ gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
+ mono_error_assert_ok (error);
+
+ //printf ("%s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
+ gpointer entry_func;
+ if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
+ entry_func = interp_entry_general;
+ } else if (sig->hasthis) {
+ if (sig->ret->type == MONO_TYPE_VOID)
+ entry_func = entry_funcs_instance [sig->param_count];
+ else
+ entry_func = entry_funcs_instance_ret [sig->param_count];
+ } else {
+ if (sig->ret->type == MONO_TYPE_VOID)
+ entry_func = entry_funcs_static [sig->param_count];
+ else
+ entry_func = entry_funcs_static_ret [sig->param_count];
}
+ g_assert (entry_func);
+
+ /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
+ MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
+ ftndesc->addr = entry_func;
+ ftndesc->arg = rmethod;
+ mono_error_assert_ok (error);
/*
- * If it is a static P/Invoke method, we can just return the pointer
- * to the method implementation.
+ * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
+ * rgctx register using a trampoline.
*/
- if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL && ((MonoMethodPInvoke*) method)->addr) {
- ji = g_new0 (MonoJitInfo, 1);
- ji->d.method = method;
- ji->code_size = 1;
- ji->code_start = addr = ((MonoMethodPInvoke*) method)->addr;
-
- mono_jit_info_table_add (mono_get_root_domain (), ji);
- }
- else {
- g_assert (method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE);
- g_assert (tramps_used < 2);
-
- /* FIXME: needs locking */
- method_pointers [tramps_used] = method;
- addr = mp_tramps [tramps_used];
- tramps_used++;
- }
- g_hash_table_insert (method_pointer_hash, method, addr);
- mono_os_mutex_unlock (&create_method_pointer_mutex);
+ 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;
return addr;
}
#define MINT_IN_DEFAULT default:
#endif
-/*
- * Defining this causes register allocation errors in some versions of gcc:
- * error: unable to find a register to spill in class `SIREG'
+/*
+ * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
*/
-/* #define MINT_USE_DEDICATED_IP_REG */
-
static void
-ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
+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;
const unsigned short *endfinally_ip = NULL;
-#if defined(__GNUC__) && defined (i386) && defined (MINT_USE_DEDICATED_IP_REG)
- register const unsigned short *ip asm ("%esi");
-#else
- register const unsigned short *ip;
-#endif
+ const unsigned short *ip = NULL;
register stackval *sp;
RuntimeMethod *rtm;
#if DEBUG_INTERP
gint tracing = global_tracing;
unsigned char *vtalloc;
+#else
+ gint tracing = 0;
#endif
int i32;
unsigned char *vt_sp;
frame->ip = NULL;
context->current_frame = frame;
-#if DEBUG_INTERP
debug_enter (frame, &tracing);
-#endif
if (!frame->runtime_method->transformed) {
context->managed_code = 0;
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;
}
rtm = frame->runtime_method;
- frame->args = alloca (rtm->alloca_size);
- memset (frame->args, 0, rtm->alloca_size);
-
- sp = frame->stack = (stackval *)((char *)frame->args + rtm->args_size);
- memset (sp, 0, rtm->stack_size);
+ if (!start_with_ip ) {
+ frame->args = alloca (rtm->alloca_size);
+ memset (frame->args, 0, rtm->alloca_size);
+ ip = rtm->code;
+ } else {
+ ip = start_with_ip;
+ }
+ sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
vt_sp = (unsigned char *) sp + rtm->stack_size;
- memset (vt_sp, 0, rtm->vt_stack_size);
#if DEBUG_INTERP
vtalloc = vt_sp;
#endif
-
locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
- memset (vt_sp, 0, rtm->locals_size);
-
+ frame->locals = locals;
child_frame.parent = frame;
- /* ready to go */
- ip = rtm->code;
+ if (filter_exception) {
+ sp->data.p = filter_exception;
+ sp++;
+ }
/*
* using while (ip < end) may result in a 15% performance drop,
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 */
}
}
}
- ves_exec_method_with_context (&child_frame, context);
+ 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..
--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 */
}
- ves_exec_method_with_context (&child_frame, context);
+#endif
+
+ 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..
*/
frame->ex = child_frame.ex;
- goto handle_finally;
+ goto handle_exception;;
}
/* need to handle typedbyref ... */
}
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);
+ 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_BREAK;
}
+
+ MINT_IN_CASE(MINT_JIT_CALL) {
+ RuntimeMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
+ frame->ip = ip;
+ ip += 2;
+ sp = do_jit_call (sp, vt_sp, context, frame, rmethod);
+
+ 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;
+ }
+ if (rmethod->rtype->type != MONO_TYPE_VOID)
+ sp++;
+
+ MINT_IN_BREAK;
+ }
+
MINT_IN_CASE(MINT_CALLVIRT) {
stackval *endsp = sp;
MonoObject *this_arg;
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) {
sp [0].data.p = unboxed;
}
- ves_exec_method_with_context (&child_frame, context);
+ 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..
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) {
sp [0].data.p = unboxed;
}
- ves_exec_method_with_context (&child_frame, context);
+ 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..
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_CASE(MINT_STIND_REF)
++ip;
sp -= 2;
- * (gpointer *) sp->data.p = sp[1].data.p;
+ mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_STIND_I1)
++ip;
sp -= 2;
* (double *) sp->data.p = sp[1].data.f;
MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
+ ++ip;
+ sp -= 2;
+ InterlockedWrite ((gint32 *) sp->data.p, sp [1].data.i);
+ MINT_IN_BREAK;
#define BINOP(datamem, op) \
--sp; \
sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CONV_U4_R8)
- sp [-1].data.i = (guint32)sp [-1].data.f;
+ /* needed on arm64 */
+ if (isinf (sp [-1].data.f))
+ sp [-1].data.i = 0;
+ else
+ sp [-1].data.i = (guint32)sp [-1].data.f;
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CONV_I8_I4)
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CPOBJ) {
c = rtm->data_items[* (guint16 *)(ip + 1)];
- g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
- stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
+ g_assert (c->valuetype);
+ /* if this assertion fails, we need to add a write barrier */
+ g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
+ 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;
token = * (guint16 *)(ip + 1);
ip += 2;
+ child_frame.ip = NULL;
+ child_frame.ex = NULL;
+
child_frame.runtime_method = rtm->data_items [token];
csig = mono_method_signature (child_frame.runtime_method->method);
newobj_class = child_frame.runtime_method->method->klass;
count++;
g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
}*/
-
+
if (newobj_class->parent == mono_defaults.array_class) {
sp -= csig->param_count;
- o = ves_array_create (context->domain, newobj_class, csig, sp);
+ child_frame.stack_args = 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 ())
g_assert (csig->call_convention == MONO_CALL_DEFAULT);
- child_frame.ip = NULL;
- child_frame.ex = NULL;
-
- ves_exec_method_with_context (&child_frame, context);
+ 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..
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)
+ o = sp [-1].data.p;
+ sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
+ ip += 2;
+ MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDFLDA)
o = sp [-1].data.p;
if (!o)
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);
MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
- MINT_IN_CASE(MINT_STFLD_O) STFLD(p, gpointer); MINT_IN_BREAK;
MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
+ MINT_IN_CASE(MINT_STFLD_O)
+ o = sp [-2].data.p;
+ if (!o)
+ THROW_EX (mono_get_exception_null_reference (), ip);
+ sp -= 2;
+ mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
+ ip += 2;
+ MINT_IN_BREAK;
MINT_IN_CASE(MINT_STFLD_VT)
o = sp [-2].data.p;
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;
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_STOBJ) {
- int size;
c = rtm->data_items[* (guint16 *)(ip + 1)];
ip += 2;
- size = mono_class_value_size (c, NULL);
- memcpy(sp [-2].data.p, &sp [-1].data, size);
+
+ g_assert (!c->byval_arg.byref);
+ if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
+ mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
+ else
+ stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
sp -= 2;
MINT_IN_BREAK;
}
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);
}
}
MINT_IN_CASE(MINT_STRLEN)
++ip;
- sp [-1].data.i = mono_string_length ((MonoString*)sp [-1].data.p);
+ o = sp [-1].data.p;
+ if (!o)
+ THROW_EX (mono_get_exception_null_reference (), ip);
+ sp [-1].data.i = mono_string_length ((MonoString*) o);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_ARRAY_RANK)
o = sp [-1].data.p;
MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
+ MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
case MINT_STELEM_I2:
mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
break;
+ case MINT_STELEM_U2:
+ mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
+ break;
case MINT_STELEM_I4:
mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
break;
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
if (sp [2].data.p && !isinst_obj)
THROW_EX (mono_get_exception_array_type_mismatch (), ip);
- mono_array_set ((MonoArray *)o, gpointer, aindex, sp [2].data.p);
+ mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
break;
}
case MINT_STELEM_VT: {
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;
+ }
if (finally_ips) {
ip = finally_ips->data;
finally_ips = g_slist_remove (finally_ips, ip);
MINT_IN_CASE(MINT_ICALL_PPP_V)
MINT_IN_CASE(MINT_ICALL_PPI_V)
sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
+ if (*mono_thread_interruption_request_flag ()) {
+ MonoException *exc = mono_thread_interruption_checkpoint ();
+ if (exc) {
+ frame->ex = exc;
+ context->search_for_handler = 1;
+ }
+ }
if (frame->ex != NULL)
goto handle_exception;
ip += 2;
++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++;
if (sp > frame->stack)
g_warning ("retobj: more values on stack: %d", sp-frame->stack);
goto exit_frame;
+ MINT_IN_CASE(MINT_MONO_TLS) {
+ MonoTlsKey key = *(gint32 *)(ip + 1);
+ sp->data.p = ((gpointer (*)()) mono_tls_get_tls_getter (key, FALSE)) ();
+ sp++;
+ ip += 3;
+ MINT_IN_BREAK;
+ }
+ MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
+ ++ip;
+
+ context->original_domain = NULL;
+ 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 != 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_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;
}
- MINT_IN_CASE(MINT_LDTHISA)
- g_error ("should not happen");
- // sp->data.p = &frame->obj;
- ++ip;
- ++sp;
- MINT_IN_BREAK;
-
#define LDARG(datamem, argtype) \
sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
ip += 2; \
sp [-1].data.p = alloca (len);
MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (header->init_locals)
+ if (header && header->init_locals)
memset (sp [-1].data.p, 0, len);
++ip;
MINT_IN_BREAK;
}
-#if 0
- MINT_IN_CASE(MINT_ENDFILTER) ves_abort(); MINT_IN_BREAK;
-#endif
+ MINT_IN_CASE(MINT_ENDFILTER)
+ /* top of stack is result of filter */
+ frame->retval = &sp [-1];
+ goto exit_frame;
MINT_IN_CASE(MINT_INITOBJ)
--sp;
memset (sp->data.vt, 0, READ32(ip + 1));
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);
inv->ex_handler = NULL; /* clear this in case we are trhowing an exception while handling one - this one wins */
for (i = 0; i < inv->runtime_method->num_clauses; ++i) {
clause = &inv->runtime_method->clauses [i];
- if (clause->flags <= 1 && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
- if (!clause->flags) {
- MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (isinst_obj) {
- /*
- * OK, we found an handler, now we need to execute the finally
- * and fault blocks before branching to the handler code.
- */
- inv->ex_handler = clause;
#if DEBUG_INTERP
- if (tracing)
- g_print ("* Found handler at '%s'\n", method->name);
+ g_print ("* clause [%d]: %p\n", i, clause);
+#endif
+ if (!MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
+ continue;
+ }
+ if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+#if DEBUG_INTERP
+ if (tracing)
+ g_print ("* Filter found at '%s'\n", method->name);
+#endif
+ MonoInvocation dup_frame;
+ 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, -1);
+ if (dup_frame.retval->data.i) {
+#if DEBUG_INTERP
+ if (tracing)
+ 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) {
+ MonoObject *isinst_obj = mono_object_isinst_checked ((MonoObject*)frame->ex, clause->data.catch_class, &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ if (isinst_obj) {
+ /*
+ * OK, we found an handler, now we need to execute the finally
+ * and fault blocks before branching to the handler code.
+ */
+#if DEBUG_INTERP
+ if (tracing)
+ g_print ("* Found handler at '%s'\n", method->name);
#endif
- goto handle_finally;
- }
- } else {
- g_error ("FIXME: handle filter clause");
+ inv->ex_handler = clause;
+ *(MonoException**)(inv->locals + inv->runtime_method->exvar_offsets [i]) = frame->ex;
+ goto handle_finally;
}
}
}
goto handle_finally;
}
die_on_ex:
- ex_obj = (MonoObject*)frame->ex;
+ ex_obj = (MonoObject *) frame->ex;
mono_unhandled_exception (ex_obj);
- exit (1);
+ MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls ();
+ jit_tls->abort_func (ex_obj);
+ g_assert_not_reached ();
}
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);
+ ves_exec_method_with_context (frame, context, NULL, NULL, -1);
context->managed_code = 0;
if (frame->ex) {
if (context != &context_struct && context->current_env) {
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;
}
-static int
-ves_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
-{
- MonoImage *image = mono_assembly_get_image (assembly);
- MonoMethod *method;
- MonoError error;
- int rval;
-
- method = mono_get_method_checked (image, mono_image_get_entry_point (image), NULL, NULL, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-
- if (!method)
- g_error ("No entry point method found in %s", mono_image_get_filename (image));
-
- rval = mono_runtime_run_main_checked (method, argc, argv, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- return rval;
-}
-
-static void
-usage (void)
-{
- fprintf (stderr,
- "mint %s, the Mono ECMA CLI interpreter, (C) 2001, 2002 Ximian, Inc.\n\n"
- "Usage is: mint [options] executable args...\n\n", VERSION);
- fprintf (stderr,
- "Runtime Debugging:\n"
-#ifdef DEBUG_INTERP
- " --debug\n"
-#endif
- " --dieonex\n"
- " --noptr\t\t\tdon't print pointer addresses in trace output\n"
- " --opcode-count\n"
- " --print-vtable\n"
- " --traceclassinit\n"
- "\n"
- "Development:\n"
- " --debug method_name\n"
- " --profile\n"
- " --trace\n"
- " --traceops\n"
- " --regression\n"
- "\n"
- "Runtime:\n"
- " --config filename load the specified config file instead of the default\n"
- " --workers n maximum number of worker threads\n"
- );
- exit (1);
-}
-
-static MonoBoolean
-interp_ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
- MonoReflectionMethod **method,
- gint32 *iloffset, gint32 *native_offset,
- MonoString **file, gint32 *line, gint32 *column)
-{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
- MonoInvocation *inv = context->current_frame;
- MonoError error;
- int i;
-
- for (i = 0; inv && i < skip; inv = inv->parent)
- if (inv->runtime_method != NULL)
- ++i;
-
- if (iloffset)
- *iloffset = 0;
- if (native_offset)
- *native_offset = 0;
- if (method) {
- if (inv == NULL) {
- *method = NULL;
- } else {
- *method = mono_method_get_object_checked (context->domain, inv->runtime_method->method, NULL, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- }
- }
- if (line)
- *line = 0;
- if (need_file_info) {
- if (column)
- *column = 0;
- if (file)
- *file = mono_string_new (mono_domain_get (), "unknown");
- }
-
- return TRUE;
-}
-
-static MonoArray *
-interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
+void
+mono_interp_parse_options (const char *options)
{
- MonoDomain *domain = mono_domain_get ();
- MonoArray *res;
- MonoArray *ta = exc->trace_ips;
- MonoError error;
- int i, len;
-
- if (ta == NULL) {
- /* Exception is not thrown yet */
- MonoArray *array = mono_array_new_checked (domain, mono_defaults.stack_frame_class, 0, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- return array;
- }
-
- len = mono_array_length (ta);
-
- res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
-
- for (i = skip; i < len / 2; i++) {
- MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- gushort *ip = mono_array_get (ta, gpointer, 2 * i + 1);
- RuntimeMethod *rtm = mono_array_get (ta, gpointer, 2 * i);
-
- if (rtm != NULL) {
- sf->method = mono_method_get_object_checked (domain, rtm->method, NULL, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- sf->native_offset = ip - rtm->code;
- }
-
-#if 0
- sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset, domain);
-
- if (need_file_info) {
- gchar *filename;
-
- 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->column = 0;
+ char **args, **ptr;
- g_free (filename);
- }
-#endif
+ args = g_strsplit (options, ",", -1);
+ for (ptr = args; ptr && *ptr; ptr ++) {
+ char *arg = *ptr;
- mono_array_set (res, gpointer, i, sf);
+ if (strncmp (arg, "jit=", 4) == 0)
+ jit_classes = g_slist_prepend (jit_classes, arg + 4);
}
-
- return res;
}
void
mono_interp_init ()
{
mono_native_tls_alloc (&thread_context_id, NULL);
- mono_native_tls_set_value (thread_context_id, NULL);
- mono_os_mutex_init_recursive (&runtime_method_lookup_section);
- mono_os_mutex_init_recursive (&create_method_pointer_mutex);
+ set_context (NULL);
mono_interp_transform_init ();
}
cfailed = failed = run = 0;
transform_time = elapsed = 0.0;
-#if 0
- /* fixme: ugly hack - delete all previously compiled methods */
- if (domain_jit_info (domain)) {
- g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
- domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
- mono_internal_hash_table_destroy (&(domain->jit_code_hash));
- mono_jit_code_hash_init (&(domain->jit_code_hash));
- }
-#endif
-
g_timer_start (timer);
for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
MonoObject *exc = NULL;
*total += failed + cfailed;
*total_run += run;
}
+
static int
interp_regression (MonoImage *image, int verbose, int *total_run)
{
total_run = total = 0;
for (i = 0; i < count; ++i) {
- MonoAssembly *ass = mono_assembly_open (images [i], NULL);
+ MonoAssembly *ass = mono_assembly_open_predicate (images [i], FALSE, FALSE, NULL, NULL, NULL);
if (!ass) {
g_warning ("failed to load assembly: %s", images [i]);
continue;
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 (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
+{
+ ThreadContext *context;
+
+ g_assert (jit_tls);
+ context = jit_tls->interp_context;
+ g_assert (context);
+
+ context->has_resume_state = TRUE;
+ 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;
+}
+
+/*
+ * 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->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 = (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;
+}