X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Finterp%2Finterp.c;h=fdbbe262ba4f2bb6d3e0fb1b6617b0a84511abdf;hb=f9ae98ab88f522219cd6be6fd282ef30adbc5365;hp=be96452e8e577658999871b4186947c971439dce;hpb=2811e6d98478df221bb6b6695372963c1e2ddb5d;p=mono.git diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index be96452e8e5..fdbbe262ba4 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -1,4 +1,5 @@ -/* +/** + * \file * PLEASE NOTE: This is a research prototype. * * @@ -56,6 +57,7 @@ #include #include #include +#include #include "interp.h" #include "interp-internals.h" @@ -64,7 +66,11 @@ #include #include +#include +#ifdef TARGET_ARM +#include +#endif /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */ #ifdef _WIN32 @@ -77,30 +83,43 @@ #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 (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval) +{ + frame->parent = parent_frame; + frame->stack_args = method_args; + frame->retval = method_retval; + frame->imethod = 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 { \ + InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \ + init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \ } while (0) -void ves_exec_method (MonoInvocation *frame); +/* + * 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 (InterpFrame *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 char* dump_frame (InterpFrame *inv); +static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top); +static void ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally); -typedef void (*ICallMethod) (MonoInvocation *frame); +typedef void (*ICallMethod) (InterpFrame *frame); static guint32 die_on_exception = 0; static MonoNativeTlsKey thread_context_id; -static char* dump_args (MonoInvocation *inv); +static char* dump_args (InterpFrame *inv); #define DEBUG_INTERP 0 #define COUNT_OPS 0 @@ -134,16 +153,17 @@ db_match_method (gpointer data, gpointer user_data) break_on_method = 1; } -static void debug_enter (MonoInvocation *frame, int *tracing) +static void +debug_enter (InterpFrame *frame, int *tracing) { if (db_methods) { - g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method); + g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->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; + MonoMethod *method = frame->imethod->method; char *mn, *args = dump_args (frame); debug_indent_level++; output_indent (); @@ -153,8 +173,6 @@ static void debug_enter (MonoInvocation *frame, int *tracing) g_print ("%s)\n", args); g_free (args); } - if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) - mono_profiler_method_enter (frame->runtime_method->method); } @@ -163,72 +181,47 @@ static void debug_enter (MonoInvocation *frame, int *tracing) char *mn, *args; \ args = dump_retval (frame); \ output_indent (); \ - mn = mono_method_full_name (frame->runtime_method->method, FALSE); \ + mn = mono_method_full_name (frame->imethod->method, FALSE); \ g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \ g_free (mn); \ g_print (" => %s\n", args); \ g_free (args); \ debug_indent_level--; \ if (tracing == 3) global_tracing = 0; \ - } \ - if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \ - mono_profiler_method_leave (frame->runtime_method->method); + } #else int mono_interp_traceopt = 0; -static void debug_enter (MonoInvocation *frame, int *tracing) +static void debug_enter (InterpFrame *frame, int *tracing) { } #define DEBUG_LEAVE() #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 @@ -249,28 +242,59 @@ ves_real_abort (int line, MonoMethod *mh, #define ves_abort() \ do {\ - ves_real_abort(__LINE__, frame->runtime_method->method, ip, frame->stack, sp); \ + ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \ THROW_EX (mono_get_exception_execution_engine (NULL), ip); \ } while (0); -RuntimeMethod* -mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error) +static InterpMethod* +lookup_imethod (MonoDomain *domain, MonoMethod *method) +{ + InterpMethod *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; +} + +InterpMethod* +mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error) { - RuntimeMethod *rtm; + InterpMethod *rtm; + MonoJitDomainInfo *info; + MonoMethodSignature *sig; + int i; + error_init (error); + info = domain_jit_info (domain); mono_domain_jit_code_hash_lock (domain); - if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) { - mono_domain_jit_code_hash_unlock (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_domain_alloc0 (domain, sizeof (RuntimeMethod)); + + sig = mono_method_signature (method); + + rtm = mono_domain_alloc0 (domain, sizeof (InterpMethod)); 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); + 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); + rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method); + return rtm; } @@ -279,25 +303,55 @@ mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError { if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) method = mono_marshal_get_synchronized_wrapper (method); - return mono_interp_get_runtime_method (domain, method, error); + return mono_interp_get_imethod (domain, method, error); } -static inline RuntimeMethod* -get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj) +/* + * 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, InterpFrame *frame) { - MonoMethod *m = runtime_method->method; + 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 InterpMethod* +get_virtual_method (InterpMethod *imethod, MonoObject *obj) +{ + MonoMethod *m = imethod->method; + MonoDomain *domain = imethod->domain; + InterpMethod *ret = NULL; MonoError error; +#ifndef DISABLE_REMOTING + if (mono_object_is_transparent_proxy (obj)) { + ret = mono_interp_get_imethod (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) { - ret = mono_interp_get_runtime_method (domain, mono_marshal_get_synchronized_wrapper (m), &error); + if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) { + ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ } else { - ret = runtime_method; + ret = imethod; } return ret; } @@ -330,9 +384,9 @@ get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObjec virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method); } - RuntimeMethod *virtual_runtime_method = mono_interp_get_runtime_method (domain, virtual_method, &error); + InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - return virtual_runtime_method; + return virtual_imethod; } static void inline @@ -382,15 +436,19 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo 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: @@ -406,9 +464,14 @@ stackval_from_data (MonoType *type, stackval *result, char *data, gboolean pinvo } 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 (); @@ -484,9 +547,13 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke) 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; } @@ -497,9 +564,16 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke) } 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 (); @@ -507,27 +581,34 @@ stackval_to_data (MonoType *type, stackval *val, char *data, gboolean pinvoke) } static void -fill_in_trace (MonoException *exception, MonoInvocation *frame) +fill_in_trace (MonoException *exception, InterpFrame *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->imethod->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); \ + } \ + MONO_PROFILER_RAISE (exception_throw, ((MonoObject *) exception)); \ goto handle_exception; \ } while (0) +#define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE) + static MonoObject* -ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values) +ves_array_create (InterpFrame *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values) { uintptr_t *lengths; intptr_t *lower_bounds; @@ -558,7 +639,7 @@ ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, M } static gint32 -ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame) +ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe) { g_assert (!frame->ex); MonoClass *ac = ((MonoObject *) ao)->vtable->klass; @@ -569,7 +650,7 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame) 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; @@ -578,7 +659,7 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame) } } 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; @@ -588,7 +669,7 @@ ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame) } static void -ves_array_set (MonoInvocation *frame) +ves_array_set (InterpFrame *frame) { stackval *sp = frame->stack_args + 1; @@ -598,7 +679,7 @@ ves_array_set (MonoInvocation *frame) 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; @@ -616,12 +697,12 @@ ves_array_set (MonoInvocation *frame) gint32 esize = mono_array_element_size (ac); gpointer ea = mono_array_addr_with_size (ao, esize, pos); - MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank]; + MonoType *mt = mono_method_signature (frame->imethod->method)->params [ac->rank]; stackval_to_data (mt, &sp [ac->rank], ea, FALSE); } static void -ves_array_get (MonoInvocation *frame) +ves_array_get (InterpFrame *frame, gboolean safe) { stackval *sp = frame->stack_args + 1; @@ -631,25 +712,25 @@ ves_array_get (MonoInvocation *frame) 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; gint32 esize = mono_array_element_size (ac); gpointer ea = mono_array_addr_with_size (ao, esize, pos); - MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret; + MonoType *mt = mono_method_signature (frame->imethod->method)->ret; stackval_from_data (mt, frame->retval, ea, FALSE); } static gpointer -ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck) +ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck) { MonoClass *ac = ((MonoObject *) ao)->vtable->klass; 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; @@ -668,17 +749,20 @@ interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUn MonoError error; ThreadContext *context = mono_native_tls_get_value (thread_context_id); - MonoInvocation *frame = context->current_frame; + if (!context) + return; + + InterpFrame *frame = context->current_frame; while (frame) { MonoStackFrameInfo fi; memset (&fi, 0, sizeof (MonoStackFrameInfo)); /* TODO: hack to make some asserts happy. */ - fi.ji = (MonoJitInfo *) frame->runtime_method; + fi.ji = (MonoJitInfo *) frame->imethod; - if (frame->runtime_method) - fi.method = fi.actual_method = frame->runtime_method->method; + if (frame->imethod) + fi.method = fi.actual_method = frame->imethod->method; if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) { fi.il_offset = -1; @@ -700,22 +784,14 @@ interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUn 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, InterpFrame *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++; @@ -738,15 +814,34 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc 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); } @@ -758,10 +853,10 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc 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); @@ -791,15 +886,35 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc 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); #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: if (ptype == MONO_TYPE_R4) @@ -809,7 +924,11 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc #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); @@ -836,6 +955,7 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc 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: @@ -853,12 +973,13 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc } static void -ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context) +ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context) { jmp_buf env; - MonoInvocation *old_frame = context->current_frame; - MonoInvocation *old_env_frame = context->env_frame; + InterpFrame *old_frame = context->current_frame; + InterpFrame *old_env_frame = context->env_frame; jmp_buf *old_env = context->current_env; + MonoLMFExt ext; if (setjmp (env)) { context->current_frame = old_frame; @@ -872,15 +993,19 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a context->env_frame = frame; context->current_env = &env; - g_assert (!frame->runtime_method); + g_assert (!frame->imethod); 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); @@ -889,11 +1014,13 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a 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 (); @@ -918,8 +1045,10 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a 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 = ((InterpMethod *) del->method_ptr)->method; } /* @@ -928,9 +1057,9 @@ mono_interp_init_delegate (MonoDelegate *del) * provided by the runtime and is primarily used for the methods of delegates. */ static void -ves_runtime_method (MonoInvocation *frame, ThreadContext *context) +ves_imethod (InterpFrame *frame, ThreadContext *context) { - MonoMethod *method = frame->runtime_method->method; + MonoMethod *method = frame->imethod->method; const char *name = method->name; MonoObject *obj = (MonoObject*) frame->stack_args->data.p; MonoObject *isinst_obj; @@ -945,6 +1074,10 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context) 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); @@ -955,7 +1088,7 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context) return; } if (*name == 'G' && (strcmp (name, "Get") == 0)) { - ves_array_get (frame); + ves_array_get (frame, TRUE); return; } } @@ -965,6 +1098,7 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context) method->name); } +#if DEBUG_INTERP static char* dump_stack (stackval *stack, stackval *sp) { @@ -980,6 +1114,7 @@ dump_stack (stackval *stack, stackval *sp) } return g_string_free (str, FALSE); } +#endif static void dump_stackval (GString *str, stackval *s, MonoType *type) @@ -1027,18 +1162,32 @@ dump_stackval (GString *str, stackval *s, MonoType *type) } } +#if DEBUG_INTERP +static char* +dump_retval (InterpFrame *inv) +{ + GString *str = g_string_new (""); + MonoType *ret = mono_method_signature (inv->imethod->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) +dump_args (InterpFrame *inv) { GString *str = g_string_new (""); int i; - MonoMethodSignature *signature = mono_method_signature (inv->runtime_method->method); + MonoMethodSignature *signature = mono_method_signature (inv->imethod->method); if (signature->param_count == 0 && !signature->hasthis) return g_string_free (str, FALSE); if (signature->hasthis) { - MonoMethod *method = inv->runtime_method->method; + MonoMethod *method = inv->imethod->method; dump_stackval (str, inv->stack_args, &method->klass->byval_arg); } @@ -1047,21 +1196,9 @@ 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) +dump_frame (InterpFrame *inv) { GString *str = g_string_new (""); int i; @@ -1069,8 +1206,8 @@ dump_frame (MonoInvocation *inv) MonoError error; for (i = 0; inv; inv = inv->parent) { - if (inv->runtime_method != NULL) { - MonoMethod *method = inv->runtime_method->method; + if (inv->imethod != NULL) { + MonoMethod *method = inv->imethod->method; MonoClass *k; int codep = 0; @@ -1088,7 +1225,7 @@ dump_frame (MonoInvocation *inv) if (hd != NULL) { if (inv->ip) { opname = mono_interp_opname [*inv->ip]; - codep = inv->ip - inv->runtime_method->code; + codep = inv->ip - inv->imethod->code; source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep); } else opname = ""; @@ -1115,23 +1252,23 @@ dump_frame (MonoInvocation *inv) } static MonoArray * -get_trace_ips (MonoDomain *domain, MonoInvocation *top) +get_trace_ips (MonoDomain *domain, InterpFrame *top) { int i; MonoArray *res; - MonoInvocation *inv; + InterpFrame *inv; MonoError error; for (i = 0, inv = top; inv; inv = inv->parent) - if (inv->runtime_method != NULL) + if (inv->imethod != NULL) ++i; res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ for (i = 0, inv = top; inv; inv = inv->parent) - if (inv->runtime_method != NULL) { - mono_array_set (res, gpointer, i, inv->runtime_method); + if (inv->imethod != NULL) { + mono_array_set (res, gpointer, i, inv->imethod); ++i; mono_array_set (res, gpointer, i, (gpointer)inv->ip); ++i; @@ -1223,17 +1360,15 @@ get_trace_ips (MonoDomain *domain, MonoInvocation *top) MonoObject* mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error) { - MonoInvocation frame; + InterpFrame frame; ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id); MonoObject *retval = NULL; MonoMethodSignature *sig = mono_method_signature (method); MonoClass *klass = mono_class_from_mono_type (sig->ret); - int i, type, isobject = 0; - void *ret = NULL; stackval result; - stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis)); + stackval *args; ThreadContext context_struct; - MonoInvocation *old_frame = NULL; + InterpFrame *old_frame = NULL; jmp_buf env; error_init (error); @@ -1244,11 +1379,10 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb 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; @@ -1256,157 +1390,265 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb 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: - break; - case MONO_TYPE_STRING: - case MONO_TYPE_OBJECT: - case MONO_TYPE_CLASS: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: - isobject = 1; - break; - case MONO_TYPE_VALUETYPE: - retval = mono_object_new_checked (context->domain, klass, error); - ret = mono_object_unbox (retval); - if (!sig->ret->data.klass->enumtype) - result.data.vt = ret; - else - result.data.vt = alloca (mono_class_instance_size (klass)); - break; - case MONO_TYPE_GENERICINST: - if (!MONO_TYPE_IS_REFERENCE (sig->ret)) { - retval = mono_object_new_checked (context->domain, klass, error); - ret = mono_object_unbox (retval); - if (!sig->ret->data.klass->enumtype) - result.data.vt = ret; - else - result.data.vt = alloca (mono_class_instance_size (klass)); - } else { - isobject = 1; + MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE); + + //* MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method) + + result.data.vt = alloca (mono_class_instance_size (klass)); + args = alloca (sizeof (stackval) * 4); + + if (sig->hasthis) + args [0].data.p = obj; + else + args [0].data.p = NULL; + args [1].data.p = params; + args [2].data.p = exc; + args [3].data.p = method; + + INIT_FRAME (&frame, context->current_frame, args, &result, domain, invoke_wrapper, error); + + if (exc) + frame.invoke_trap = 1; + context->managed_code = 1; + ves_exec_method_with_context (&frame, context, NULL, NULL, -1); + context->managed_code = 0; + if (context == &context_struct) + set_context (NULL); + else + context->current_frame = old_frame; + if (frame.ex != NULL) { + if (exc != NULL) { + *exc = (MonoObject*) frame.ex; + return NULL; } - break; + if (context->current_env != NULL) { + context->env_frame->ex = frame.ex; + longjmp(*context->current_env, 1); + } + else + printf("dropped exception...\n"); + } + return result.data.p; +} - case MONO_TYPE_PTR: - retval = mono_object_new_checked (context->domain, mono_defaults.int_class, error); - ret = mono_object_unbox (retval); - break; - default: - retval = mono_object_new_checked (context->domain, klass, error); - ret = mono_object_unbox (retval); - break; +typedef struct { + InterpMethod *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) +{ + InterpFrame frame; + InterpMethod *rmethod = data->rmethod; + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + ThreadContext context_struct; + InterpFrame *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 = obj; + 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; + int a_index = i + (sig->hasthis ? 1 : 0); if (sig->params [i]->byref) { args [a_index].data.p = params [i]; continue; } - type = sig->params [i]->type; -handle_enum: - switch (type) { + type = rmethod->param_types [i]; + switch (type->type) { case MONO_TYPE_U1: case MONO_TYPE_I1: - case MONO_TYPE_BOOLEAN: args [a_index].data.i = *(MonoBoolean*)params [i]; break; case MONO_TYPE_U2: case MONO_TYPE_I2: - case MONO_TYPE_CHAR: args [a_index].data.i = *(gint16*)params [i]; break; + case MONO_TYPE_U: #if SIZEOF_VOID_P == 4 - case MONO_TYPE_U: /* use VAL_POINTER? */ + 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; -#if SIZEOF_VOID_P == 8 - case MONO_TYPE_U: - case MONO_TYPE_I: -#endif 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_VALUETYPE: - if (sig->params [i]->data.klass->enumtype) { - type = mono_class_enum_basetype (sig->params [i]->data.klass)->type; - goto handle_enum; - } else { - args [a_index].data.p = params [i]; - } - break; - case MONO_TYPE_STRING: case MONO_TYPE_PTR: - case MONO_TYPE_CLASS: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: case MONO_TYPE_OBJECT: - case MONO_TYPE_GENERICINST: + args [a_index].data.p = *(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: - g_error ("type 0x%x not handled in runtime invoke", sig->params [i]->type); + printf ("%s\n", mono_type_full_name (sig->params [i])); + NOT_IMPLEMENTED; + break; } } - if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) - method = mono_marshal_get_native_wrapper (method, FALSE, FALSE); - INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error); - if (exc) - frame.invoke_trap = 1; + init_frame (&frame, NULL, data->rmethod, args, &result); context->managed_code = 1; - ves_exec_method_with_context (&frame, context); - context->managed_code = 0; - if (context == &context_struct) - mono_native_tls_set_value (thread_context_id, NULL); - else - context->current_frame = old_frame; - if (frame.ex != NULL) { - if (exc != NULL) { - *exc = (MonoObject*) frame.ex; - return NULL; - } - if (context->current_env != NULL) { - context->env_frame->ex = frame.ex; - longjmp(*context->current_env, 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 */ } - else - printf("dropped exception...\n"); + 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 * do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) { - MonoInvocation *old_frame = context->current_frame; - MonoInvocation *old_env_frame = context->env_frame; + InterpFrame *old_frame = context->current_frame; + InterpFrame *old_env_frame = context->env_frame; jmp_buf *old_env = context->current_env; jmp_buf env; @@ -1424,12 +1666,12 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) 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; @@ -1491,84 +1733,455 @@ do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr) return sp; } -static mono_mutex_t create_method_pointer_mutex; +static stackval * +do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod) +{ + MonoMethodSignature *sig; + MonoFtnDesc ftndesc; + guint8 res_buf [256]; + MonoType *type; + MonoLMFExt ext; + + //printf ("%s\n", mono_method_full_name (rmethod->method, 1)); + + /* + * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument + * by ref and return a return value using an explicit return value argument. + */ + if (!rmethod->jit_wrapper) { + MonoMethod *method = rmethod->method; + MonoError error; + + sig = mono_method_signature (method); + g_assert (sig); + + MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig); + //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1)); + + gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error); + mono_error_assert_ok (&error); + + gpointer addr = mono_jit_compile_method_jit_only (method, &error); + g_assert (addr); + mono_error_assert_ok (&error); + + rmethod->jit_addr = addr; + rmethod->jit_sig = sig; + mono_memory_barrier (); + rmethod->jit_wrapper = jit_wrapper; + + } else { + sig = rmethod->jit_sig; + } + + sp -= sig->param_count; + if (sig->hasthis) + --sp; + + ftndesc.addr = rmethod->jit_addr; + ftndesc.arg = NULL; + + // FIXME: Optimize this + + gpointer args [32]; + int pindex = 0; + int stack_index = 0; + if (rmethod->hasthis) { + args [pindex ++] = sp [0].data.p; + stack_index ++; + } + type = rmethod->rtype; + if (type->type != MONO_TYPE_VOID) { + if (MONO_TYPE_ISSTRUCT (type)) + args [pindex ++] = vt_sp; + else + args [pindex ++] = res_buf; + } + for (int i = 0; i < rmethod->param_count; ++i) { + MonoType *t = rmethod->param_types [i]; + stackval *sval = &sp [stack_index + i]; + if (sig->params [i]->byref) { + args [pindex ++] = sval->data.p; + } else if (MONO_TYPE_ISSTRUCT (t)) { + args [pindex ++] = sval->data.p; + } else if (MONO_TYPE_IS_REFERENCE (t)) { + args [pindex ++] = &sval->data.p; + } else { + switch (t->type) { + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_VALUETYPE: + args [pindex ++] = &sval->data.i; + break; + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_OBJECT: + args [pindex ++] = &sval->data.p; + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + args [pindex ++] = &sval->data.l; + break; + default: + printf ("%s\n", mono_type_full_name (t)); + g_assert_not_reached (); + } + } + } + + interp_push_lmf (&ext, frame); + + switch (pindex) { + case 0: { + void (*func)(gpointer) = rmethod->jit_wrapper; + + func (&ftndesc); + break; + } + case 1: { + void (*func)(gpointer, gpointer) = rmethod->jit_wrapper; + + func (args [0], &ftndesc); + break; + } + case 2: { + void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper; + + func (args [0], args [1], &ftndesc); + break; + } + case 3: { + void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper; + + func (args [0], args [1], args [2], &ftndesc); + break; + } + case 4: { + void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper; + + func (args [0], args [1], args [2], args [3], &ftndesc); + break; + } + case 5: { + void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper; + + func (args [0], args [1], args [2], args [3], args [4], &ftndesc); + break; + } + case 6: { + void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper; -static GHashTable *method_pointer_hash = NULL; + 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; -#define TRAMPS_USED 8 + func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc); + break; + } + default: + g_assert_not_reached (); + break; + } -static MonoMethod *method_pointers [TRAMPS_USED] = {0}; + interp_pop_lmf (&ext); -#define GEN_METHOD_PTR_TRAMP(num) \ - static MonoObject * mp_tramp_ ## num (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 [num], NULL, params_real, NULL, &error); \ - mono_error_cleanup (&error); \ - return ret; \ + MonoType *rtype = rmethod->rtype; + switch (rtype->type) { + case MONO_TYPE_VOID: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_I: + case MONO_TYPE_U: + sp->data.p = *(gpointer*)res_buf; + break; + case MONO_TYPE_I1: + sp->data.i = *(gint8*)res_buf; + break; + case MONO_TYPE_U1: + sp->data.i = *(guint8*)res_buf; + break; + case MONO_TYPE_I2: + sp->data.i = *(gint16*)res_buf; + break; + case MONO_TYPE_U2: + sp->data.i = *(guint16*)res_buf; + break; + case MONO_TYPE_I4: + sp->data.i = *(gint32*)res_buf; + break; + case MONO_TYPE_U4: + sp->data.i = *(guint32*)res_buf; + break; + case MONO_TYPE_VALUETYPE: + /* The result was written to vt_sp */ + sp->data.p = vt_sp; + break; + case MONO_TYPE_GENERICINST: + if (MONO_TYPE_IS_REFERENCE (rtype)) { + sp->data.p = *(gpointer*)res_buf; + } else { + /* The result was written to vt_sp */ + sp->data.p = vt_sp; } + break; + default: + printf ("%s\n", mono_type_full_name (rtype)); + g_assert_not_reached (); + break; + } + + return sp; +} + +static void +do_debugger_tramp (void (*tramp) (void), InterpFrame *frame) +{ + MonoLMFExt ext; + interp_push_lmf (&ext, frame); + tramp (); + interp_pop_lmf (&ext); +} + +static void +do_transform_method (InterpFrame *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->imethod, context); + context->managed_code = 1; + + interp_pop_lmf (&ext); +} +/* + * These functions are the entry points into the interpreter from compiled code. + * They are called by the interp_in wrappers. They have the following signature: + * void (, , , ..., , ) + * 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. + */ -GEN_METHOD_PTR_TRAMP (0); -GEN_METHOD_PTR_TRAMP (1); -GEN_METHOD_PTR_TRAMP (2); -GEN_METHOD_PTR_TRAMP (3); -GEN_METHOD_PTR_TRAMP (4); -GEN_METHOD_PTR_TRAMP (5); -GEN_METHOD_PTR_TRAMP (6); -GEN_METHOD_PTR_TRAMP (7); +#define MAX_INTERP_ENTRY_ARGS 8 -#undef GEN_METHOD_PTR_TRAMP +#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; -gpointer *mp_tramps[TRAMPS_USED] = { - (gpointer) mp_tramp_0, (gpointer) mp_tramp_1, (gpointer) mp_tramp_2, (gpointer) mp_tramp_3, - (gpointer) mp_tramp_4, (gpointer) mp_tramp_5, (gpointer) mp_tramp_6, (gpointer) mp_tramp_7 -}; +#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 InterpMethod *rmethod +#define ARGLIST1 gpointer arg1, InterpMethod *rmethod +#define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod +#define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod +#define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod +#define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod +#define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod +#define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod +#define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *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; + InterpMethod *rmethod = mono_interp_get_imethod (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 < TRAMPS_USED); - - /* 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; } @@ -1592,7 +2205,7 @@ static int opcode_counts[512]; } \ sp->data.l = 0; \ output_indent (); \ - char *mn = mono_method_full_name (frame->runtime_method->method, FALSE); \ + char *mn = mono_method_full_name (frame->imethod->method, FALSE); \ g_print ("(%p) %s -> ", mono_thread_internal_current (), mn); \ g_free (mn); \ mono_interp_dis_mintop(rtm->code, ip); \ @@ -1622,18 +2235,23 @@ static int opcode_counts[512]; #define MINT_IN_DEFAULT default: #endif +/* + * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index. + */ static void -ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) +ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally) { - MonoInvocation child_frame; + InterpFrame child_frame; GSList *finally_ips = NULL; const unsigned short *endfinally_ip = NULL; const unsigned short *ip = NULL; register stackval *sp; - RuntimeMethod *rtm; + InterpMethod *rtm; #if DEBUG_INTERP gint tracing = global_tracing; unsigned char *vtalloc; +#else + gint tracing = 0; #endif int i32; unsigned char *vt_sp; @@ -1654,19 +2272,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) frame->ip = NULL; context->current_frame = frame; -#if DEBUG_INTERP debug_enter (frame, &tracing); -#endif - if (!frame->runtime_method->transformed) { + if (!frame->imethod->transformed) { context->managed_code = 0; #if DEBUG_INTERP - char *mn = mono_method_full_name (frame->runtime_method->method, TRUE); + char *mn = mono_method_full_name (frame->imethod->method, TRUE); 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; @@ -1674,26 +2290,28 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) } } - 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); + rtm = frame->imethod; + 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, @@ -1714,7 +2332,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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; @@ -1817,7 +2435,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) MINT_IN_BREAK; } MINT_IN_CASE(MINT_JMP) { - RuntimeMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)]; + InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)]; if (!new_method->transformed) { frame->ip = ip; frame->ex = mono_interp_transform_method (new_method, context); @@ -1827,12 +2445,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) ip += 2; if (new_method->alloca_size > rtm->alloca_size) g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size); - rtm = frame->runtime_method = new_method; + rtm = frame->imethod = new_method; vt_sp = (unsigned char *) sp + rtm->stack_size; #if DEBUG_INTERP 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; } @@ -1846,7 +2465,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) ip += 2; --sp; --endsp; - child_frame.runtime_method = sp->data.p; + child_frame.imethod = sp->data.p; sp->data.p = vt_sp; child_frame.retval = sp; @@ -1856,12 +2475,15 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) --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.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.imethod->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.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { + child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ } @@ -1874,10 +2496,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) } } - 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.. @@ -1905,7 +2534,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) --sp; --endsp; code = sp->data.p; - child_frame.runtime_method = NULL; + child_frame.imethod = NULL; sp->data.p = vt_sp; child_frame.retval = sp; @@ -1918,6 +2547,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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.. @@ -1942,25 +2578,35 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) frame->ip = ip; - child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)]; + child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)]; ip += 2; sp->data.p = vt_sp; child_frame.retval = sp; /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count; - if (child_frame.runtime_method->hasthis) + sp -= child_frame.imethod->param_count; + if (child_frame.imethod->hasthis) --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); + if (child_frame.imethod->hasthis && !child_frame.imethod->method->klass->valuetype && sp->data.p && mono_object_is_transparent_proxy (sp->data.p)) { + child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.imethod->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.. @@ -1977,14 +2623,14 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) MINT_IN_CASE(MINT_VCALL) { frame->ip = ip; - child_frame.runtime_method = rtm->data_items [* (guint16 *)(ip + 1)]; + child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)]; ip += 2; sp->data.p = vt_sp; child_frame.retval = sp; /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count; - if (child_frame.runtime_method->hasthis) { + sp -= child_frame.imethod->param_count; + if (child_frame.imethod->hasthis) { --sp; MonoObject *this_arg = sp->data.p; if (!this_arg) @@ -1992,15 +2638,24 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) } child_frame.stack_args = sp; - 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); +#ifndef DISABLE_REMOTING + if (child_frame.imethod->hasthis && !child_frame.imethod->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) { + child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke (child_frame.imethod->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.. @@ -2010,6 +2665,31 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) } MINT_IN_BREAK; } + + MINT_IN_CASE(MINT_JIT_CALL) { + InterpMethod *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; @@ -2019,29 +2699,36 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) token = * (unsigned short *)(ip + 1); ip += 2; - child_frame.runtime_method = rtm->data_items [token]; + child_frame.imethod = rtm->data_items [token]; sp->data.p = vt_sp; child_frame.retval = sp; /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count + 1; + sp -= child_frame.imethod->param_count + 1; child_frame.stack_args = sp; 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.imethod = get_virtual_method (child_frame.imethod, this_arg); MonoClass *this_class = this_arg->vtable->klass; - if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) { + if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) { /* unbox */ gpointer *unboxed = mono_object_unbox (this_arg); 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.. @@ -2067,28 +2754,35 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) token = * (unsigned short *)(ip + 1); ip += 2; - child_frame.runtime_method = rtm->data_items [token]; + child_frame.imethod = rtm->data_items [token]; sp->data.p = vt_sp; child_frame.retval = sp; /* decrement by the actual number of args */ - sp -= child_frame.runtime_method->param_count + 1; + sp -= child_frame.imethod->param_count + 1; child_frame.stack_args = sp; 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.imethod = get_virtual_method (child_frame.imethod, this_arg); MonoClass *this_class = this_arg->vtable->klass; - if (this_class->valuetype && child_frame.runtime_method->method->klass->valuetype) { + if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) { gpointer *unboxed = mono_object_unbox (this_arg); 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.. @@ -2103,7 +2797,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) MINT_IN_BREAK; } MINT_IN_CASE(MINT_CALLRUN) - ves_runtime_method (frame, context); + ves_imethod (frame, context); if (frame->ex) { rtm = NULL; goto handle_exception; @@ -2117,7 +2811,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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->imethod->method, TRUE)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT) i32 = READ32(ip + 1); @@ -2408,7 +3102,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) gint offset; ip += 2 * (guint32)sp->data.i; offset = READ32 (ip); - ip = st + offset; + ip = ip + offset; } else { ip = st; } @@ -2437,7 +3131,8 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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); @@ -2460,7 +3155,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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; @@ -2497,6 +3192,11 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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; \ @@ -2726,7 +3426,11 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) ++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) @@ -2775,8 +3479,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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; @@ -2814,9 +3523,9 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) 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; + child_frame.imethod = rtm->data_items [token]; + csig = mono_method_signature (child_frame.imethod->method); + newobj_class = child_frame.imethod->method->klass; /*if (profiling_classes) { guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class)); count++; @@ -2826,7 +3535,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) if (newobj_class->parent == mono_defaults.array_class) { sp -= csig->param_count; child_frame.stack_args = sp; - o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp); + o = ves_array_create (&child_frame, rtm->domain, newobj_class, csig, sp); if (child_frame.ex) THROW_EX (child_frame.ex, ip); goto array_constructed; @@ -2854,7 +3563,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) } 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 ()) @@ -2868,10 +3577,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context) g_assert (csig->call_convention == MONO_CALL_DEFAULT); - 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.. @@ -2941,6 +3657,7 @@ array_constructed: 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) @@ -3001,14 +3718,15 @@ array_constructed: 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; @@ -3025,13 +3743,14 @@ array_constructed: 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); @@ -3056,8 +3775,15 @@ array_constructed: 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; @@ -3080,11 +3806,13 @@ array_constructed: 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; @@ -3100,11 +3828,13 @@ array_constructed: 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; @@ -3113,14 +3843,14 @@ array_constructed: } 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; @@ -3128,7 +3858,7 @@ array_constructed: } 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; @@ -3140,7 +3870,7 @@ array_constructed: } 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); @@ -3148,7 +3878,7 @@ array_constructed: } 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; @@ -3168,11 +3898,14 @@ array_constructed: 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; } @@ -3223,20 +3956,20 @@ array_constructed: 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); } @@ -3271,7 +4004,10 @@ array_constructed: } 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; @@ -3381,6 +4117,7 @@ array_constructed: 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 */ @@ -3412,6 +4149,9 @@ array_constructed: 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; @@ -3429,7 +4169,7 @@ array_constructed: 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: { @@ -3561,17 +4301,50 @@ array_constructed: 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; @@ -3640,13 +4413,20 @@ array_constructed: 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); goto main_loop; } if (frame->ex) - goto handle_fault; + goto handle_catch; ves_abort(); MINT_IN_BREAK; MINT_IN_CASE(MINT_LEAVE) /* Fall through */ @@ -3678,6 +4458,13 @@ array_constructed: 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; @@ -3688,7 +4475,7 @@ array_constructed: ++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++; @@ -3702,11 +4489,102 @@ array_constructed: MINT_IN_CASE(MINT_MONO_RETOBJ) ++ip; sp--; - stackval_from_data (mono_method_signature (frame->runtime_method->method)->ret, frame->retval, sp->data.p, - mono_method_signature (frame->runtime_method->method)->pinvoke); + stackval_from_data (mono_method_signature (frame->imethod->method)->ret, frame->retval, sp->data.p, + mono_method_signature (frame->imethod->method)->pinvoke); 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_MEMORY_BARRIER) { + ++ip; + mono_memory_barrier (); + 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_MONO_LDDOMAIN) + sp->data.p = mono_domain_get (); + ++sp; + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SDB_INTR_LOC) + if (G_UNLIKELY (ss_enabled)) { + static void (*ss_tramp) (void); + + if (!ss_tramp) { + void *tramp = mini_get_single_step_trampoline (); + mono_memory_barrier (); + ss_tramp = tramp; + } + + /* + * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since + * the address of that instruction is stored as the seq point address. + */ + frame->ip = ip + 1; + + /* + * Use the same trampoline as the JIT. This ensures that + * the debugger has the context for the last interpreter + * native frame. + */ + do_debugger_tramp (ss_tramp, frame); + + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + } + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SDB_SEQ_POINT) + /* Just a placeholder for a breakpoint */ + ++ip; + MINT_IN_BREAK; + MINT_IN_CASE(MINT_SDB_BREAKPOINT) { + static void (*bp_tramp) (void); + if (!bp_tramp) { + void *tramp = mini_get_breakpoint_trampoline (); + mono_memory_barrier (); + bp_tramp = tramp; + } + + frame->ip = ip; + + /* Use the same trampoline as the JIT */ + do_debugger_tramp (bp_tramp, frame); + + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + + ++ip; + MINT_IN_BREAK; + } #define RELOP(datamem, op) \ --sp; \ @@ -3799,13 +4677,13 @@ array_constructed: MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDVIRTFTN) { - RuntimeMethod *m = rtm->data_items [* (guint16 *)(ip + 1)]; + InterpMethod *m = rtm->data_items [* (guint16 *)(ip + 1)]; ip += 2; --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; } @@ -3885,6 +4763,26 @@ array_constructed: MINT_IN_BREAK; } + MINT_IN_CASE(MINT_PROF_ENTER) { + ip += 1; + + if (MONO_PROFILER_ENABLED (method_enter)) { + MonoProfilerCallContext *prof_ctx = NULL; + + if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT) { + prof_ctx = g_new0 (MonoProfilerCallContext, 1); + prof_ctx->interp_frame = frame; + prof_ctx->method = frame->imethod->method; + } + + MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx)); + + g_free (prof_ctx); + } + + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LDARGA) sp->data.p = frame->args + * (guint16 *)(ip + 1); ip += 2; @@ -3959,16 +4857,17 @@ array_constructed: int len = sp [-1].data.i; sp [-1].data.p = alloca (len); - MonoMethodHeader *header = mono_method_get_header_checked (frame->runtime_method->method, &error); + MonoMethodHeader *header = mono_method_get_header_checked (frame->imethod->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)); @@ -4006,7 +4905,7 @@ array_constructed: 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 @@ -4017,9 +4916,11 @@ array_constructed: * 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); @@ -4036,7 +4937,7 @@ array_constructed: { int i; guint32 ip_offset; - MonoInvocation *inv; + InterpFrame *inv; MonoExceptionClause *clause; /*char *message;*/ MonoObject *ex_obj; @@ -4052,37 +4953,59 @@ array_constructed: for (inv = frame; inv; inv = inv->parent) { MonoMethod *method; - if (inv->runtime_method == NULL) + if (inv->imethod == NULL) continue; - method = inv->runtime_method->method; + method = inv->imethod->method; if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) continue; if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) continue; if (inv->ip == NULL) continue; - ip_offset = inv->ip - inv->runtime_method->code; + ip_offset = inv->ip - inv->imethod->code; 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; + for (i = 0; i < inv->imethod->num_clauses; ++i) { + clause = &inv->imethod->clauses [i]; +#if DEBUG_INTERP + 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 + InterpFrame dup_frame; + stackval retval; + memcpy (&dup_frame, inv, sizeof (InterpFrame)); + dup_frame.retval = &retval; + ves_exec_method_with_context (&dup_frame, context, inv->imethod->code + clause->data.filter_offset, frame->ex, -1); + if (dup_frame.retval->data.i) { #if DEBUG_INTERP - if (tracing) - g_print ("* Found handler at '%s'\n", method->name); + if (tracing) + g_print ("* Matched Filter at '%s'\n", method->name); #endif - goto handle_finally; - } - } else { - g_error ("FIXME: handle filter clause"); + inv->ex_handler = clause; + *(MonoException**)(inv->locals + inv->imethod->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 + inv->ex_handler = clause; + *(MonoException**)(inv->locals + inv->imethod->exvar_offsets [i]) = frame->ex; + goto handle_finally; } } } @@ -4095,7 +5018,8 @@ array_constructed: goto handle_finally; } die_on_ex: - ex_obj = (MonoObject*)frame->ex; + ex_obj = (MonoObject *) frame->ex; + mono_unhandled_exception (ex_obj); MonoJitTlsData *jit_tls = (MonoJitTlsData *) mono_tls_get_jit_tls (); jit_tls->abort_func (ex_obj); g_assert_not_reached (); @@ -4106,7 +5030,7 @@ die_on_ex: guint32 ip_offset; MonoExceptionClause *clause; GSList *old_list = finally_ips; - MonoMethod *method = frame->runtime_method->method; + MonoMethod *method = frame->imethod->method; MonoMethodHeader *header = mono_method_get_header_checked (method, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ @@ -4162,7 +5086,8 @@ die_on_ex: int i; guint32 ip_offset; MonoExceptionClause *clause; - MonoMethod *method = frame->runtime_method->method; + GSList *old_list = finally_ips; + MonoMethod *method = frame->imethod->method; MonoMethodHeader *header = mono_method_get_header_checked (method, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ @@ -4175,13 +5100,23 @@ die_on_ex: clause = &rtm->clauses [i]; if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) { ip = rtm->code + clause->handler_offset; + finally_ips = g_slist_prepend (finally_ips, (gpointer) ip); #if DEBUG_INTERP if (tracing) g_print ("* Executing handler at IL_%04x\n", clause->handler_offset); #endif - goto main_loop; } } + + if (old_list != finally_ips && finally_ips) { + ip = finally_ips->data; + finally_ips = g_slist_remove (finally_ips, ip); + sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */ + goto main_loop; + } + } + handle_catch: + { /* * If the handler for the exception was found in this method, we jump * to it right away, otherwise we return and let the caller run @@ -4204,14 +5139,46 @@ die_on_ex: goto exit_frame; } exit_frame: + + if (!frame->ex) { + if (MONO_PROFILER_ENABLED (method_leave) && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE) { + MonoProfilerCallContext *prof_ctx = NULL; + + if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT) { + prof_ctx = g_new0 (MonoProfilerCallContext, 1); + prof_ctx->interp_frame = frame; + prof_ctx->method = frame->imethod->method; + + MonoType *rtype = mono_method_signature (frame->imethod->method)->ret; + + switch (rtype->type) { + case MONO_TYPE_VOID: + break; + case MONO_TYPE_VALUETYPE: + prof_ctx->return_value = frame->retval->data.p; + break; + default: + prof_ctx->return_value = frame->retval; + break; + } + } + + MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx)); + + g_free (prof_ctx); + } + } else + MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, (MonoObject *) frame->ex)); + DEBUG_LEAVE (); } void -ves_exec_method (MonoInvocation *frame) +ves_exec_method (InterpFrame *frame) { ThreadContext *context = mono_native_tls_get_value (thread_context_id); ThreadContext context_struct; + MonoDomain *domain = frame->imethod->domain; MonoError error; jmp_buf env; @@ -4223,21 +5190,20 @@ ves_exec_method (MonoInvocation *frame) } 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->imethod = mono_interp_get_imethod (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) { @@ -4248,160 +5214,30 @@ ves_exec_method (MonoInvocation *frame) 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 */ + char **args, **ptr; - 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); + args = g_strsplit (options, ",", -1); + for (ptr = args; ptr && *ptr; ptr ++) { + char *arg = *ptr; - sf->filename = filename? mono_string_new (domain, filename): NULL; - sf->column = 0; - - g_free (filename); - } -#endif - - 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 (&create_method_pointer_mutex); + set_context (NULL); mono_interp_transform_init (); } @@ -4518,6 +5354,7 @@ interp_regression_step (MonoImage *image, int verbose, int *total_run, int *tota *total += failed + cfailed; *total_run += run; } + static int interp_regression (MonoImage *image, int verbose, int *total_run) { @@ -4570,3 +5407,176 @@ mono_interp_regression_list (int verbose, int count, char *images []) 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) +{ + InterpFrame *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 { + InterpFrame *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 = (InterpFrame*)interp_exit_data; +} + +gboolean +mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) +{ + StackIter *stack_iter = (StackIter*)iter; + InterpFrame *iframe = stack_iter->current; + + memset (frame, 0, sizeof (StackFrameInfo)); + /* pinvoke frames doesn't have imethod set */ + while (iframe && !(iframe->imethod && iframe->imethod->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->imethod->method; + frame->actual_method = frame->method; + /* This is the offset in the interpreter IR */ + frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code; + frame->ji = iframe->imethod->jinfo; + + stack_iter->current = iframe->parent; + + return TRUE; +} + +MonoJitInfo* +mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method) +{ + InterpMethod* rtm; + + rtm = lookup_imethod (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) +{ + InterpFrame *iframe = (InterpFrame*)frame; + + g_assert (iframe->imethod); + return iframe->imethod->jinfo; +} + +gpointer +mono_interp_frame_get_ip (MonoInterpFrameHandle frame) +{ + InterpFrame *iframe = (InterpFrame*)frame; + + g_assert (iframe->imethod); + return (gpointer)iframe->ip; +} + +gpointer +mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos) +{ + InterpFrame *iframe = (InterpFrame*)frame; + + g_assert (iframe->imethod); + + int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)]; + + return iframe->args + arg_offset; +} + +gpointer +mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos) +{ + InterpFrame *iframe = (InterpFrame*)frame; + + g_assert (iframe->imethod); + + return iframe->locals + iframe->imethod->local_offsets [pos]; +} + +gpointer +mono_interp_frame_get_this (MonoInterpFrameHandle frame) +{ + InterpFrame *iframe = (InterpFrame*)frame; + + g_assert (iframe->imethod); + g_assert (iframe->imethod->hasthis); + + int arg_offset = iframe->imethod->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; +}