#include <mono/metadata/tokentype.h>
#include <mono/metadata/loader.h>
#include <mono/metadata/threads.h>
-#include <mono/metadata/threadpool-ms.h>
+#include <mono/metadata/threadpool.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/reflection.h>
#include "interp.h"
#include "mintops.h"
-#include "embed.h"
#include "hacks.h"
-#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
- a = i,
+#include <mono/mini/mini.h>
-enum {
-#include "mono/cil/opcode.def"
- CEE_LASTOP
-};
-#undef OPDEF
/* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
#ifdef _WIN32
#endif
#endif
-static gint *abort_requested;
-
-/* If true, then we output the opcodes as we interpret them */
-static int global_tracing = 0;
-static int global_no_pointers = 0;
-
int mono_interp_traceopt = 0;
-static int debug_indent_level = 0;
-
#define INIT_FRAME(frame,parent_frame,obj_this,method_args,method_retval,domain,mono_method,error) \
do { \
(frame)->parent = (parent_frame); \
static guint32 die_on_exception = 0;
static MonoNativeTlsKey thread_context_id;
-#define DEBUG_INTERP 1
+static char* dump_args (MonoInvocation *inv);
+
+#define DEBUG_INTERP 0
#define COUNT_OPS 0
#if DEBUG_INTERP
+/* If true, then we output the opcodes as we interpret them */
+static int global_tracing = 1;
+
+static int debug_indent_level = 0;
static int break_on_method = 0;
static int nested_trace = 0;
break_on_method = 1;
}
-#define DEBUG_ENTER() \
- if (db_methods) { \
- g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method); \
- if (break_on_method) tracing=nested_trace ? (global_tracing = 2, 3) : 2; \
- break_on_method = 0; \
- } \
- if (tracing) { \
- MonoMethod *method = frame->runtime_method->method ;\
- char *mn, *args = dump_args (frame); \
- debug_indent_level++; \
- output_indent (); \
- mn = mono_method_full_name (method, FALSE); \
- g_printerr ("(0x%08x) Entering %s (", mono_thread_internal_current (), mn); \
- g_free (mn); \
- g_printerr ("%s)\n", args); \
- g_free (args); \
- } \
- if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \
+static void debug_enter (MonoInvocation *frame, int *tracing)
+{
+ if (db_methods) {
+ g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method);
+ if (break_on_method)
+ *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
+ break_on_method = 0;
+ }
+ if (*tracing) {
+ MonoMethod *method = frame->runtime_method->method;
+ char *mn, *args = dump_args (frame);
+ debug_indent_level++;
+ output_indent ();
+ mn = mono_method_full_name (method, FALSE);
+ g_printerr ("(0x%08x) Entering %s (", mono_thread_internal_current (), mn);
+ g_free (mn);
+ g_printerr ("%s)\n", args);
+ g_free (args);
+ }
+ if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE)
mono_profiler_method_enter (frame->runtime_method->method);
+}
+
#define DEBUG_LEAVE() \
if (tracing) { \
#else
-#define DEBUG_ENTER()
+static void debug_enter (MonoInvocation *frame, int *tracing)
+{
+}
#define DEBUG_LEAVE()
#endif
THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
} while (0);
-static gpointer
-interp_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
-{
- g_error ("FIXME: use domain and error");
- // return mono_interp_get_runtime_method (mono_marshal_get_remoting_invoke_for_target (method, target));
-}
-
static mono_mutex_t runtime_method_lookup_section;
RuntimeMethod*
if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
RuntimeMethod *ret = NULL;
- if (obj->vtable->klass == mono_defaults.transparent_proxy_class)
+ if (mono_object_is_transparent_proxy (obj)) {
ret = mono_interp_get_runtime_method (domain, mono_marshal_get_remoting_invoke (m), &error);
- else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ } else if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error);
- else
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ } else {
ret = runtime_method;
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ }
return ret;
}
- if (m->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
- // return ((RuntimeMethod **)obj->vtable->interface_offsets [m->klass->interface_id]) [m->slot];
- g_error ("FIXME: interface method lookup");
- return NULL;
- } else {
- return ((RuntimeMethod **)obj->vtable->vtable) [m->slot];
+ int slot = mono_method_get_vtable_slot (m);
+ if (mono_class_is_interface (m->klass)) {
+ g_assert (obj->vtable->klass != m->klass);
+ /* TODO: interface offset lookup is slow, go through IMT instead */
+ slot += mono_class_interface_offset (obj->vtable->klass, m->klass);
}
+ MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
+ 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;
}
static void inline
return;
}
-#if 0 /* FIX */
- if (sp [ac->rank].data.p && !mono_object_isinst (sp [ac->rank].data.p, mono_object_class (o)->element_class)) {
- frame->ex = mono_get_exception_array_type_mismatch ();
- FILL_IN_TRACE (frame->ex, frame);
- return;
+ if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
+ MonoError error;
+ MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
+ mono_error_cleanup (&error);
+ if (!isinst) {
+ frame->ex = mono_get_exception_array_type_mismatch ();
+ FILL_IN_TRACE (frame->ex, frame);
+ return;
+ }
}
-#endif
esize = mono_array_element_size (ac);
ea = mono_array_addr_with_size (ao, esize, pos);
}
}
+static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
+
+struct _MethodArguments {
+ size_t ilen;
+ gpointer *iargs;
+ size_t flen;
+ gpointer *fargs;
+ gpointer *retval;
+};
+
+typedef struct _MethodArguments MethodArguments;
+
+// TODO: this function is also arch dependent (register width).
+static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvocation *frame)
+{
+ // TODO: don't malloc this data structure.
+ MethodArguments *margs = g_malloc0 (sizeof (MethodArguments));
+
+ if (sig->hasthis)
+ margs->ilen++;
+
+ for (int i = 0; i < sig->param_count; i++) {
+ guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
+ switch (ptype) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ 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_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_I8:
+ margs->ilen++;
+ break;
+ default:
+ g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
+ }
+ }
+
+ if (margs->ilen > 0)
+ margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
+
+ if (margs->ilen > 3)
+ g_error ("build_args_from_sig: TODO, more than two iregs: %d\n", margs->ilen);
+
+ if (margs->flen > 0)
+ g_error ("build_args_from_sig: TODO, allocate floats: %d\n", margs->flen);
+
+
+ size_t int_i = 0;
+
+ if (sig->hasthis) {
+ margs->iargs [0] = frame->obj;
+ int_i++;
+ }
+
+ for (int i = 0; i < sig->param_count; i++) {
+ guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
+ switch (ptype) {
+ case MONO_TYPE_BOOLEAN:
+ case MONO_TYPE_CHAR:
+ 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_I:
+ case MONO_TYPE_U:
+ case MONO_TYPE_PTR:
+ case MONO_TYPE_SZARRAY:
+ case MONO_TYPE_CLASS:
+ case MONO_TYPE_OBJECT:
+ case MONO_TYPE_STRING:
+ case MONO_TYPE_I8:
+ margs->iargs [int_i] = frame->stack_args [i].data.p;
+#if DEBUG_INTERP
+ g_printerr ("build_args_from_sig: margs->iargs[%d]: %p (frame @ %d)\n", int_i, margs->iargs[int_i], i);
+#endif
+ int_i++;
+ break;
+ default:
+ g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
+ }
+ }
+
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ margs->retval = &(frame->retval->data.p);
+ } else {
+ margs->retval = NULL;
+ }
+
+ return margs;
+}
+
static void
ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
{
jmp_buf env;
- MonoPIFunc func;
MonoInvocation *old_frame = context->current_frame;
MonoInvocation *old_env_frame = context->env_frame;
jmp_buf *old_env = context->current_env;
context->env_frame = frame;
context->current_env = &env;
- if (frame->runtime_method) {
- func = frame->runtime_method->func;
- } else {
- g_error ("FIXME: not available?");
-#if 0
- func = mono_arch_create_trampoline (sig, string_ctor);
-#endif
+ 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);
}
+ MethodArguments *margs = build_args_from_sig (sig, frame);
+#if DEBUG_INTERP
+ g_printerr ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
+ g_printerr ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
+#endif
+
context->current_frame = frame;
context->managed_code = 0;
- func (addr, &frame->retval->data.p, frame->obj, frame->stack_args);
+ mono_interp_enter_icall_trampoline (addr, margs);
context->managed_code = 1;
/* domain can only be changed by native code */
context->domain = mono_domain_get ();
- if (*abort_requested)
+ if (*mono_thread_interruption_request_flag ())
mono_thread_interruption_checkpoint ();
- if (string_ctor) {
- stackval_from_data (&mono_defaults.string_class->byval_arg, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
- } else if (!MONO_TYPE_ISSTRUCT (sig->ret))
+ if (!MONO_TYPE_ISSTRUCT (sig->ret))
stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
context->current_frame = old_frame;
context->env_frame = old_env_frame;
context->current_env = old_env;
+
+ g_free (margs->iargs);
+ g_free (margs->fargs);
+ g_free (margs);
}
static void
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
delegate->target = target;
- if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
+ if (target && mono_object_is_transparent_proxy (target)) {
MonoMethod *method = mono_marshal_get_remoting_invoke (runtime_method->method);
delegate->method_ptr = mono_interp_get_runtime_method (domain, method, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
if (inv->ip) {
opname = mono_interp_opname [*inv->ip];
codep = inv->ip - inv->runtime_method->code;
+ source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
} else
opname = "";
-
- g_error ("FIXME: proper source location");
- // source = mono_debug_source_location_from_il_offset (method, codep, NULL);
+
+#if 0
+ MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
+ source = mono_debug_method_lookup_location (minfo, codep);
+#endif
}
}
args = dump_args (inv);
name = mono_method_full_name (method, TRUE);
if (source)
- g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname,
- name, args, source);
+ g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
else
- g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname,
- name, args);
+ g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
g_free (name);
g_free (args);
g_free (source);
#define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
#endif
-static MonoObject*
+MonoObject*
interp_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
{
MonoInvocation frame;
}
}
- if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
+ if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
INIT_FRAME(&frame,context->current_frame,obj,args,&result,mono_get_root_domain (),method,error);
if (exc)
func ();
break;
}
+ case MINT_ICALL_V_P: {
+ gpointer (*func)() = ptr;
+ sp++;
+ sp [-1].data.p = func ();
+ break;
+ }
case MINT_ICALL_P_V: {
void (*func)(gpointer) = ptr;
func (sp [-1].data.p);
static GHashTable *method_pointer_hash = NULL;
gpointer
-mono_create_method_pointer (MonoMethod *method, MonoError *error)
+interp_create_method_pointer (MonoMethod *method, MonoError *error)
{
gpointer addr;
MonoJitInfo *ji;
- mono_error_init (error);
mono_os_mutex_lock (&create_method_pointer_mutex);
if (!method_pointer_hash) {
frame->ip = NULL;
context->current_frame = frame;
- DEBUG_ENTER ();
+#if DEBUG_INTERP
+ debug_enter (frame, &tracing);
+#endif
if (!frame->runtime_method->transformed) {
context->managed_code = 0;
+#if DEBUG_INTERP
+ char *mn = mono_method_full_name (frame->runtime_method->method, FALSE);
+ g_printerr ("(0x%08x) 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;
if (frame->ex) {
MINT_IN_BREAK;
MINT_IN_CASE(MINT_POP)
++ip;
- fprintf (stderr, "POP: 0x%08x\n", (sp-1)->data.i);
--sp;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_JMP) {
} else {
child_frame.obj = NULL;
}
- if (csignature->hasthis && ((MonoObject *)child_frame.obj)->vtable->klass == mono_defaults.transparent_proxy_class) {
+ if (csignature->hasthis && mono_object_is_transparent_proxy (child_frame.obj)) {
child_frame.runtime_method = mono_interp_get_runtime_method (context->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) {
} else {
child_frame.obj = NULL;
}
- if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->valuetype && ((MonoObject *)child_frame.obj)->vtable->klass == mono_defaults.transparent_proxy_class) {
+ if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->valuetype && mono_object_is_transparent_proxy (child_frame.obj)) {
child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
child_frame.obj = NULL;
}
- if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->valuetype && ((MonoObject *)child_frame.obj)->vtable->klass == mono_defaults.transparent_proxy_class) {
+ if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->valuetype && mono_object_is_transparent_proxy (child_frame.obj)) {
child_frame.runtime_method = mono_interp_get_runtime_method (context->domain, mono_marshal_get_remoting_invoke (child_frame.runtime_method->method), &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
}
}
MINT_IN_BREAK;
}
- MINT_IN_CASE(MINT_CALLINT)
- ves_pinvoke_method (frame, mono_method_signature (frame->runtime_method->method), ((MonoMethodPInvoke*) frame->runtime_method->method)->addr,
- frame->runtime_method->method->string_ctor, context);
- if (frame->ex) {
- rtm = NULL;
- goto handle_exception;
- }
- goto exit_frame;
MINT_IN_CASE(MINT_CALLRUN)
ves_runtime_method (frame, context);
if (frame->ex) {
MINT_IN_CASE(MINT_DIV_I4)
if (sp [-1].data.i == 0)
THROW_EX (mono_get_exception_divide_by_zero (), ip);
+ if (sp [-1].data.i == (-1))
+ THROW_EX (mono_get_exception_overflow (), ip);
BINOP(i, /);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_DIV_I8)
if (sp [-1].data.l == 0)
THROW_EX (mono_get_exception_divide_by_zero (), ip);
+ if (sp [-1].data.l == (-1))
+ THROW_EX (mono_get_exception_overflow (), ip);
BINOP(l, /);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_DIV_R8)
o = mono_object_new_checked (context->domain, newobj_class, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
context->managed_code = 1;
- if (*abort_requested)
+ if (*mono_thread_interruption_request_flag ())
mono_thread_interruption_checkpoint ();
child_frame.obj = o;
} else {
MINT_IN_CASE(MINT_CASTCLASS)
c = rtm->data_items [*(guint16 *)(ip + 1)];
if ((o = sp [-1].data.p)) {
- if (c->marshalbyref) {
- MonoObject *isinst_obj = mono_object_isinst_mbyref_checked (o, c, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (!isinst_obj)
- THROW_EX (mono_get_exception_invalid_cast (), ip);
- } else {
- MonoVTable *vt = o->vtable;
- MonoClass *oklass = vt->klass;
- if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
- g_error ("FIXME: interface method lookup");
- if (c->interface_id > vt->max_interface_id /* || vt->interface_offsets [c->interface_id] == 0 */) {
- THROW_EX (mono_get_exception_invalid_cast (), ip);
- }
- } else if (c->rank) {
- MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (!isinst_obj)
- THROW_EX (mono_get_exception_invalid_cast (), ip);
- } else if (!mono_class_has_parent (oklass, c)) {
- THROW_EX (mono_get_exception_invalid_cast (), ip);
- }
- }
+ MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ if (!isinst_obj)
+ THROW_EX (mono_get_exception_invalid_cast (), ip);
}
ip += 2;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_ISINST)
c = rtm->data_items [*(guint16 *)(ip + 1)];
if ((o = sp [-1].data.p)) {
- if (c->marshalbyref) {
- MonoObject *isinst_obj = mono_object_isinst_mbyref_checked (o, c, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (!isinst_obj)
- sp [-1].data.p = NULL;
- } else {
- MonoVTable *vt = o->vtable;
- MonoClass *oklass = vt->klass;
- if (c->flags & TYPE_ATTRIBUTE_INTERFACE) {
- g_error ("FIXME: interface method lookup");
- if (c->interface_id > vt->max_interface_id /* || vt->interface_offsets [c->interface_id] == 0 */) {
- sp [-1].data.p = NULL;
- }
- } else if (c->rank) {
- MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (!isinst_obj)
- sp [-1].data.p = NULL;
- } else if (!mono_class_has_parent (oklass, c)) {
- sp [-1].data.p = NULL;
- }
- }
+ MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ if (!isinst_obj)
+ sp [-1].data.p = NULL;
}
ip += 2;
MINT_IN_BREAK;
o = sp [-1].data.p;
if (!o)
- THROW_EX (mono_get_exception_null_reference(), ip);
+ THROW_EX (mono_get_exception_null_reference (), ip);
MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
- if (!(isinst_obj ||
- ((o->vtable->klass->rank == 0) &&
- (o->vtable->klass->element_class == c->element_class))))
+ if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
THROW_EX (mono_get_exception_invalid_cast (), ip);
- sp [-1].data.p = (char *)o + sizeof (MonoObject);
+ if (c->byval_arg.type == MONO_TYPE_VALUETYPE && !c->enumtype) {
+ g_error ("unbox: implement vt");
+ } else {
+ stackval_from_data (&c->byval_arg, &sp [-1], mono_object_unbox (o), FALSE);
+ }
ip += 2;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_THROW)
THROW_EX (mono_get_exception_null_reference (), ip);
field = rtm->data_items[* (guint16 *)(ip + 1)];
ip += 2;
- if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+ 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);
field = rtm->data_items[* (guint16 *)(ip + 1)];
i32 = READ32(ip + 2);
ip += 4;
- if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+ 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 */
field = rtm->data_items[* (guint16 *)(ip + 1)];
ip += 2;
- if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+ 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 */
i32 = READ32(ip + 2);
ip += 4;
- if (o->vtable->klass == mono_defaults.transparent_proxy_class) {
+ 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 */
goto handle_finally;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_ICALL_V_V)
+ MINT_IN_CASE(MINT_ICALL_V_P)
MINT_IN_CASE(MINT_ICALL_P_V)
MINT_IN_CASE(MINT_ICALL_P_P)
MINT_IN_CASE(MINT_ICALL_PP_V)
MINT_IN_CASE(MINT_MONO_FREE)
++ip;
--sp;
+ g_error ("that doesn't seem right");
g_free (sp->data.p);
MINT_IN_BREAK;
MINT_IN_CASE(MINT_MONO_RETOBJ)
frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error);
mono_error_cleanup (&error); /* FIXME: don't swallow the error */
context->managed_code = 1;
- ves_exec_method_with_context(frame, context);
+ ves_exec_method_with_context (frame, context);
context->managed_code = 0;
if (frame->ex) {
if (context != &context_struct && context->current_env) {
g_error ("No entry point method found in %s", mono_image_get_filename (image));
rval = mono_runtime_run_main_checked (method, argc, argv, &error);
- return_val_and_set_pending_if_nok (&error, rval);
+ mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ return rval;
}
static void
" --profile\n"
" --trace\n"
" --traceops\n"
+ " --regression\n"
"\n"
"Runtime:\n"
" --config filename load the specified config file instead of the default\n"
exit (1);
}
-#ifdef RUN_TEST
-static void
-test_load_class (MonoImage* image)
-{
- MonoTableInfo *t = &image->tables [MONO_TABLE_TYPEDEF];
- MonoClass *klass;
- int i;
-
- for (i = 1; i <= t->rows; ++i) {
- klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i);
- mono_class_init (klass);
- }
-}
-#endif
-
-static void
-add_signal_handler (int signo, void (*handler)(int))
-{
-#ifdef HOST_WIN32
- signal (signo, handler);
-#else
- struct sigaction sa;
-
- sa.sa_handler = handler;
- sigemptyset (&sa.sa_mask);
- sa.sa_flags = 0;
-
- g_assert (sigaction (signo, &sa, NULL) != -1);
-#endif
-}
-
-static void
-segv_handler (int signum)
-{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
- MonoException *segv_exception;
-
- if (context == NULL)
- return;
- segv_exception = mono_get_exception_null_reference ();
- segv_exception->message = mono_string_new (mono_domain_get (), "Null Reference (SIGSEGV)");
- mono_raise_exception (segv_exception);
-}
-
-
-static void
-quit_handler (int signum)
-{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
- MonoException *quit_exception;
-
- if (context == NULL)
- return;
- quit_exception = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
- mono_raise_exception (quit_exception);
-}
-
-static void
-abrt_handler (int signum)
-{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
- MonoException *abrt_exception;
-
- if (context == NULL)
- return;
- abrt_exception = mono_get_exception_execution_engine ("Abort (SIGABRT).");
- mono_raise_exception (abrt_exception);
-}
-
-#if 0
-static void
-thread_abort_handler (int signum)
-{
- ThreadContext *context = mono_native_tls_get_value (thread_context_id);
- MonoException *exc;
-
- if (context == NULL)
- return;
-
- exc = mono_thread_request_interruption (context->managed_code);
- if (exc) mono_raise_exception (exc);
-}
-#endif
-
static MonoBoolean
-ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
+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)
}
static MonoArray *
-ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
+interp_ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
{
MonoDomain *domain = mono_domain_get ();
MonoArray *res;
return delegate;
}
-
-typedef struct
-{
- MonoDomain *domain;
- int enable_debugging;
- char *file;
- int argc;
- char **argv;
-} MainThreadArgs;
-
-static void main_thread_handler (gpointer user_data)
-{
- MainThreadArgs *main_args=(MainThreadArgs *)user_data;
- MonoAssembly *assembly;
-
- if (main_args->enable_debugging) {
- mono_debug_init (MONO_DEBUG_FORMAT_MONO);
- }
-
- assembly = mono_domain_assembly_open (main_args->domain, main_args->file);
-
- if (!assembly){
- fprintf (stderr, "Can not open image %s\n", main_args->file);
- exit (1);
- }
-
-#ifdef RUN_TEST
- test_load_class (assembly->image);
-#else
-
- ves_exec (main_args->domain, assembly, main_args->argc, main_args->argv);
-#endif
-}
-
-static void
-mono_runtime_install_handlers (void)
-{
- add_signal_handler (SIGSEGV, segv_handler);
- add_signal_handler (SIGINT, quit_handler);
- add_signal_handler (SIGABRT, abrt_handler);
-#if 0
- add_signal_handler (mono_thread_get_abort_signal (), thread_abort_handler);
-#endif
-}
-
-static void
-quit_function (MonoDomain *domain, gpointer user_data)
-{
- mono_profiler_shutdown ();
-
- mono_runtime_cleanup (domain);
- mono_domain_free (domain, TRUE);
-
-}
-
void
-mono_interp_cleanup(MonoDomain *domain)
-{
- quit_function (domain, NULL);
-}
-
-int
-mono_interp_exec(MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
-{
- return ves_exec (domain, assembly, argc, argv);
-}
-
-gpointer*
-interp_get_imt_trampoline (MonoVTable *vtable, int imt_slot_index)
-{
- // FIXME: implement me
- return NULL;
-}
-
-MonoDomain *
-mono_interp_init(const char *file)
+mono_interp_init ()
{
- MonoDomain *domain;
- MonoRuntimeCallbacks callbacks;
- MonoRuntimeExceptionHandlingCallbacks ecallbacks;
- MonoError error;
-
- g_set_prgname (file);
- mono_set_rootdir ();
-
- g_log_set_always_fatal (G_LOG_LEVEL_ERROR);
- g_log_set_fatal_mask (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR);
-
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);
- // TODO: use callbacks?
- mono_runtime_install_handlers ();
mono_interp_transform_init ();
+}
- memset (&callbacks, 0, sizeof (callbacks));
- // TODO: replace with `mono_install_callbacks`
- callbacks.compile_method = mono_create_method_pointer;
- callbacks.runtime_invoke = interp_mono_runtime_invoke;
- callbacks.get_imt_trampoline = interp_get_imt_trampoline;
-#ifndef DISABLE_REMOTING
- mono_install_remoting_trampoline (interp_create_remoting_trampoline);
-#endif
- callbacks.create_jit_trampoline = interp_create_trampoline;
- mono_install_callbacks (&callbacks);
+typedef int (*TestMethod) (void);
+
+static void
+interp_regression_step (MonoImage *image, int verbose, int *total_run, int *total, GTimer *timer, MonoDomain *domain)
+{
+ int result, expected, failed, cfailed, run;
+ double elapsed, transform_time;
+ int i;
+ MonoObject *result_obj;
+ static gboolean filter_method_init = FALSE;
+ static const char *filter_method = NULL;
+ g_print ("Test run: image=%s\n", mono_image_get_filename (image));
+ cfailed = failed = run = 0;
+ transform_time = elapsed = 0.0;
- memset (&ecallbacks, 0, sizeof (ecallbacks));
- ecallbacks.mono_raise_exception = interp_ex_handler;
#if 0
- // FIXME: ...
- mono_install_stack_walk (interp_walk_stack);
+ /* 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
- mono_install_eh_callbacks (&ecallbacks);
-
- mono_install_runtime_cleanup (quit_function);
-
- abort_requested = mono_thread_interruption_request_flag ();
- domain = mono_init_from_assembly (file, file);
-#ifdef __hpux /* generates very big stack frames */
- mono_threads_set_default_stacksize(32*1024*1024);
-#endif
- mono_icall_init ();
- mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", ves_icall_get_frame_info);
- mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace", ves_icall_get_trace);
- mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers);
- mono_add_internal_call ("System.Delegate::CreateDelegate_internal", ves_icall_System_Delegate_CreateDelegate_internal);
+ g_timer_start (timer);
+ for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
+ MonoError error;
+ MonoMethod *method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+ if (!method) {
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ continue;
+ }
- mono_register_jit_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", mono_create_icall_signature ("void"), FALSE);
+ if (!filter_method_init) {
+ filter_method = g_getenv ("INTERP_FILTER_METHOD");
+ filter_method_init = TRUE;
+ }
+ gboolean filter = FALSE;
+ if (filter_method) {
+ const char *name = filter_method;
+
+ if ((strchr (name, '.') > name) || strchr (name, ':')) {
+ MonoMethodDesc *desc = mono_method_desc_new (name, TRUE);
+ filter = mono_method_desc_full_match (desc, method);
+ mono_method_desc_free (desc);
+ } else {
+ filter = strcmp (method->name, name) == 0;
+ }
+ } else { // no filter
+ filter = TRUE;
+ }
+ if (strncmp (method->name, "test_", 5) == 0 && filter) {
+ MonoError interp_error;
+ MonoObject *exc = NULL;
+
+ result_obj = interp_mono_runtime_invoke (method, NULL, NULL, &exc, &interp_error);
+ if (!mono_error_ok (&interp_error)) {
+ cfailed++;
+ g_print ("Test '%s' execution failed.\n", method->name);
+ } else if (exc != NULL) {
+ g_print ("Exception in Test '%s' occured:\n", method->name);
+ mono_object_describe (exc);
+ run++;
+ failed++;
+ } else {
+ result = *(gint32 *) mono_object_unbox (result_obj);
+ expected = atoi (method->name + 5); // FIXME: oh no.
+ run++;
- mono_runtime_init_checked (domain, NULL, NULL, &error);
- mono_error_cleanup (&error); /* FIXME: don't swallow the error */
+ if (result != expected) {
+ failed++;
+ g_print ("Test '%s' failed result (got %d, expected %d).\n", method->name, result, expected);
+ }
+ }
+ }
+ }
+ g_timer_stop (timer);
+ elapsed = g_timer_elapsed (timer, NULL);
+ if (failed > 0 || cfailed > 0){
+ g_print ("Results: total tests: %d, failed: %d, cfailed: %d (pass: %.2f%%)\n",
+ run, failed, cfailed, 100.0*(run-failed-cfailed)/run);
+ } else {
+ g_print ("Results: total tests: %d, all pass \n", run);
+ }
- mono_thread_attach (domain);
- fprintf (stderr, "INTERPRETER: INIT DONE\n");
- return domain;
+ g_print ("Elapsed time: %f secs (%f, %f)\n\n", elapsed,
+ elapsed - transform_time, transform_time);
+ *total += failed + cfailed;
+ *total_run += run;
}
-
-int
-mono_main (int argc, char *argv [])
+static int
+interp_regression (MonoImage *image, int verbose, int *total_run)
{
- MonoDomain *domain;
- int retval = 0, i;
- char *file, *config_file = NULL;
- int enable_debugging = FALSE;
- MainThreadArgs main_args;
- const char *error;
-
- setlocale (LC_ALL, "");
- if (argc < 2)
- usage ();
-
- for (i = 1; i < argc && argv [i][0] == '-'; i++){
- if (strcmp (argv [i], "--trace") == 0)
- global_tracing = 1;
- if (strcmp (argv [i], "--noptr") == 0)
- global_no_pointers = 1;
- if (strcmp (argv [i], "--traceops") == 0)
- global_tracing = 2;
- if (strcmp (argv [i], "--traceopt") == 0)
- ++mono_interp_traceopt;
- if (strcmp (argv [i], "--dieonex") == 0) {
- die_on_exception = 1;
- enable_debugging = 1;
- }
- if (strcmp (argv [i], "--print-vtable") == 0)
- mono_print_vtable = TRUE;
- if (strcmp (argv [i], "--profile") == 0)
- mono_profiler_load (NULL);
- if (strcmp (argv [i], "--config") == 0)
- config_file = argv [++i];
- if (strcmp (argv [i], "--help") == 0)
- usage ();
-#if DEBUG_INTERP
- if (strcmp (argv [i], "--debug") == 0) {
- MonoMethodDesc *desc = mono_method_desc_new (argv [++i], FALSE);
- if (!desc)
- g_error ("Invalid method name '%s'", argv [i]);
- db_methods = g_list_append (db_methods, desc);
+ MonoMethod *method;
+ GTimer *timer = g_timer_new ();
+ MonoDomain *domain = mono_domain_get ();
+ guint32 i;
+ int total;
+
+ /* load the metadata */
+ for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
+ MonoError error;
+ method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+ if (!method) {
+ mono_error_cleanup (&error);
+ continue;
}
- if (strcmp (argv [i], "--nested") == 0)
- nested_trace = 1;
-#endif
+ mono_class_init (method->klass);
}
-
- file = argv [i];
- if (!file)
- usage ();
+ total = 0;
+ *total_run = 0;
+ interp_regression_step (image, verbose, total_run, &total, timer, domain);
- domain = mono_interp_init (file);
- mono_config_parse (config_file);
+ g_timer_destroy (timer);
+ return total;
+}
- error = mono_check_corlib_version ();
- if (error) {
- fprintf (stderr, "Corlib not in sync with this runtime: %s\n", error);
- fprintf (stderr, "Download a newer corlib at http://www.go-mono.com/daily.\n");
- exit (1);
+int
+interp_regression_list (int verbose, int count, char *images [])
+{
+ int i, total, total_run, run;
+
+ total_run = total = 0;
+ for (i = 0; i < count; ++i) {
+ MonoAssembly *ass = mono_assembly_open (images [i], NULL);
+ if (!ass) {
+ g_warning ("failed to load assembly: %s", images [i]);
+ continue;
+ }
+ total += interp_regression (mono_assembly_get_image (ass), verbose, &run);
+ total_run += run;
+ }
+ if (total > 0) {
+ g_print ("Overall results: tests: %d, failed: %d (pass: %.2f%%)\n", total_run, total, 100.0*(total_run-total)/total_run);
+ } else {
+ g_print ("Overall results: tests: %d, 100%% pass\n", total_run);
}
-
- main_args.domain=domain;
- main_args.file=file;
- main_args.argc=argc-i;
- main_args.argv=argv+i;
- main_args.enable_debugging=enable_debugging;
- fprintf (stderr, "INTERPRETER: INIT DONE\n");
- mono_runtime_exec_managed_code (domain, main_thread_handler,
- &main_args);
-
- quit_function (domain, NULL);
-
- /* Get the return value from System.Environment.ExitCode */
- retval=mono_environment_exitcode_get ();
-
-#if COUNT_OPS
- for (i = 0; i < 512; i++)
- if (opcode_counts[i] != 0)
- printf("%s %d\n", mono_interp_opname[i], opcode_counts[i]);
-#endif
- return retval;
+ return total;
}
+