From ef59fcf0ce7339a2054ae393cef5c3d81cb0591d Mon Sep 17 00:00:00 2001 From: BrzVlad Date: Wed, 6 Jan 2021 23:27:36 +0000 Subject: [PATCH] [interp] Move from stack based to fully local var based design Instead of having instructions that push and pop from the stack, every instruction has explicit dreg and sregs. While the purpose of this PR is mainly to make it easier to implement more advanced optimization in the future, it also has noticeable performance implications. The code is simplified because we no longer need to update and save the SP. However, the code for each instruction is bloated due to the addition of explicit source and destination offsets. This is counteracted by the reduction of the total number of instructions, since ldloc/stloc and moves become redundant and they are mostly optimized away, even in this implementation state. Here are the total number of executed opcodes as part of running the corlib test suite with the interp https://gist.github.com/BrzVlad/d62f504930b75cba4b870e6dbd947e90. --- src/mono/mono/mini/interp/interp-internals.h | 4 +- src/mono/mono/mini/interp/interp.c | 3476 +++++++++--------- src/mono/mono/mini/interp/mintops.c | 122 +- src/mono/mono/mini/interp/mintops.def | 1482 ++++---- src/mono/mono/mini/interp/mintops.h | 23 +- src/mono/mono/mini/interp/transform.c | 3459 +++++++++-------- src/mono/mono/mini/interp/transform.h | 46 +- src/mono/mono/mini/interp/whitebox.c | 4 - 8 files changed, 4265 insertions(+), 4351 deletions(-) diff --git a/src/mono/mono/mini/interp/interp-internals.h b/src/mono/mono/mini/interp/interp-internals.h index 69fcc403fb3401..6e240756a2ec51 100644 --- a/src/mono/mono/mini/interp/interp-internals.h +++ b/src/mono/mono/mini/interp/interp-internals.h @@ -127,7 +127,9 @@ struct InterpMethod { MonoJitInfo *jinfo; MonoDomain *domain; + // This doesn't include the size of stack locals guint32 total_locals_size; + // The size of locals that map to the execution stack guint32 stack_size; guint32 alloca_size; int num_clauses; // clauses @@ -185,8 +187,6 @@ typedef struct FrameClauseArgs FrameClauseArgs; /* State of the interpreter main loop */ typedef struct { - stackval *sp; - unsigned char *vt_sp; const unsigned short *ip; } InterpState; diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 24cc42c9d2ebc6..f4075f2a13b5ea 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -221,11 +221,11 @@ frame_data_allocator_pop (FrameDataAllocator *stack, InterpFrame *frame) * Reinitialize a frame. */ static void -reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, stackval *sp) +reinit_frame (InterpFrame *frame, InterpFrame *parent, InterpMethod *imethod, gpointer stack) { frame->parent = parent; frame->imethod = imethod; - frame->stack = sp; + frame->stack = (stackval*)stack; frame->state.ip = NULL; } @@ -1433,10 +1433,9 @@ interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig, InterpFrame *iframe = (InterpFrame*)frame; InterpMethod *imethod = iframe->imethod; - // If index == 1, we finished executing an InterpFrame, thus we always have imethod set, - // and the result is at the bottom of the execution stack. + // If index == -1, we finished executing an InterpFrame and the result is at the bottom of the stack. if (index == -1) - stackval_to_data (sig->ret, STACK_ADD_BYTES (iframe->stack, imethod->total_locals_size), data, TRUE); + stackval_to_data (sig->ret, iframe->stack, data, TRUE); else if (sig->hasthis && index == 0) *(gpointer*)data = iframe->stack->data.p; else @@ -1465,7 +1464,7 @@ interp_frame_arg_to_storage (MonoInterpFrameHandle frame, MonoMethodSignature *s InterpMethod *imethod = iframe->imethod; if (index == -1) - return STACK_ADD_BYTES (iframe->stack, imethod->total_locals_size); + return iframe->stack; else return STACK_ADD_BYTES (iframe->stack, get_arg_offset (imethod, sig, index)); } @@ -1498,7 +1497,7 @@ interp_to_native_trampoline (gpointer addr, gpointer ccontext) #ifdef _MSC_VER #pragma optimize ("", off) #endif -static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE void +static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE gpointer ves_pinvoke_method ( InterpMethod *imethod, MonoMethodSignature *sig, @@ -1596,7 +1595,7 @@ ves_pinvoke_method ( #endif goto exit_pinvoke; // prevent unused label warning in some configurations exit_pinvoke: - return; + return NULL; } #ifdef _MSC_VER #pragma optimize ("", on) @@ -1691,7 +1690,7 @@ interp_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpoint */ #ifndef ENABLE_NETCORE static MONO_NEVER_INLINE MonoException* -ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp, stackval *retval) +ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, stackval *sp) { const char *name = method->name; mono_class_init_internal (method->klass); @@ -1699,11 +1698,11 @@ ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, s if (method->klass == mono_defaults.array_class) { if (!strcmp (name, "UnsafeMov")) { /* TODO: layout checks */ - stackval_from_data (sig->ret, retval, (char*) sp, FALSE); + stackval_from_data (sig->ret, sp, (char*) sp, FALSE); return NULL; } if (!strcmp (name, "UnsafeLoad")) - return ves_array_get (frame, sp, retval, sig, FALSE); + return ves_array_get (frame, sp, sp, sig, FALSE); } g_error ("Don't know how to exec runtime method %s.%s::%s", @@ -1713,22 +1712,6 @@ ves_imethod (InterpFrame *frame, MonoMethod *method, MonoMethodSignature *sig, s #endif #if DEBUG_INTERP -static char* -dump_stack (stackval *stack, stackval *sp) -{ - stackval *s = stack; - GString *str = g_string_new (""); - - if (sp == stack) - return g_string_free (str, FALSE); - - while (s < sp) { - g_string_append_printf (str, "[%p (%" PRId64 ")] ", s->data.l, (gint64)s->data.l); - ++s; - } - return g_string_free (str, FALSE); -} - static void dump_stackval (GString *str, stackval *s, MonoType *type) { @@ -1785,7 +1768,7 @@ dump_retval (InterpFrame *inv) MonoType *ret = mono_method_signature_internal (inv->imethod->method)->ret; if (ret->type != MONO_TYPE_VOID) - dump_stackval (str, STACK_ADD_BYTES (inv->stack, inv->imethod->total_locals_size), ret); + dump_stackval (str, inv->stack, ret); return g_string_free (str, FALSE); } @@ -1937,8 +1920,8 @@ interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject */ return NULL; } - // The return value is at the bottom of the stack, after the locals - return STACK_ADD_BYTES (frame.stack, imethod->total_locals_size)->data.o; + // The return value is at the bottom of the stack + return frame.stack->data.o; } typedef struct { @@ -2026,10 +2009,10 @@ interp_entry (InterpEntryData *data) // The return value is at the bottom of the stack, after the locals space type = rmethod->rtype; if (type->type != MONO_TYPE_VOID) - stackval_to_data (type, STACK_ADD_BYTES (frame.stack, rmethod->total_locals_size), data->res, FALSE); + stackval_to_data (type, frame.stack, data->res, FALSE); } -static stackval * +static void do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error) { #ifdef ENABLE_NETCORE @@ -2047,91 +2030,79 @@ do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean case MINT_ICALL_V_P: { typedef gpointer (*T)(void); T func = (T)ptr; - sp++; - sp [-1].data.p = func (); + sp [0].data.p = func (); break; } case MINT_ICALL_P_V: { typedef void (*T)(gpointer); T func = (T)ptr; - func (sp [-1].data.p); - sp --; + func (sp [0].data.p); break; } case MINT_ICALL_P_P: { typedef gpointer (*T)(gpointer); T func = (T)ptr; - sp [-1].data.p = func (sp [-1].data.p); + sp [0].data.p = func (sp [0].data.p); break; } case MINT_ICALL_PP_V: { typedef void (*T)(gpointer,gpointer); T func = (T)ptr; - sp -= 2; func (sp [0].data.p, sp [1].data.p); break; } case MINT_ICALL_PP_P: { typedef gpointer (*T)(gpointer,gpointer); T func = (T)ptr; - --sp; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p); + sp [0].data.p = func (sp [0].data.p, sp [1].data.p); break; } case MINT_ICALL_PPP_V: { typedef void (*T)(gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 3; func (sp [0].data.p, sp [1].data.p, sp [2].data.p); break; } case MINT_ICALL_PPP_P: { typedef gpointer (*T)(gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 2; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p); + sp [0].data.p = func (sp [0].data.p, sp [1].data.p, sp [2].data.p); break; } case MINT_ICALL_PPPP_V: { typedef void (*T)(gpointer,gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 4; func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p); break; } case MINT_ICALL_PPPP_P: { typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 3; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p); + sp [0].data.p = func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p); break; } case MINT_ICALL_PPPPP_V: { typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 5; func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p); break; } case MINT_ICALL_PPPPP_P: { typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 4; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p); + sp [0].data.p = func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p); break; } case MINT_ICALL_PPPPPP_V: { typedef void (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 6; func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p, sp [5].data.p); break; } case MINT_ICALL_PPPPPP_P: { typedef gpointer (*T)(gpointer,gpointer,gpointer,gpointer,gpointer,gpointer); T func = (T)ptr; - sp -= 5; - sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p); + sp [0].data.p = func (sp [0].data.p, sp [1].data.p, sp [2].data.p, sp [3].data.p, sp [4].data.p, sp [5].data.p); break; } default: @@ -2143,9 +2114,7 @@ do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean /* convert the native representation to the stackval representation */ if (sig) - stackval_from_data (sig->ret, &sp [-1], (char*) &sp [-1].data.p, sig->pinvoke); - - return sp; + stackval_from_data (sig->ret, &sp [0], (char*) &sp [0].data.p, sig->pinvoke); } /* MONO_NO_OPTIMIZATION is needed due to usage of INTERP_PUSH_LMF_WITH_CTX. */ @@ -2153,19 +2122,19 @@ do_icall (MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean #pragma optimize ("", off) #endif // Do not inline in case order of frame addresses matters, and maybe other reasons. -static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE stackval * +static MONO_NO_OPTIMIZATION MONO_NEVER_INLINE gpointer do_icall_wrapper (InterpFrame *frame, MonoMethodSignature *sig, int op, stackval *sp, gpointer ptr, gboolean save_last_error) { MonoLMFExt ext; INTERP_PUSH_LMF_WITH_CTX (frame, ext, exit_icall); - sp = do_icall (sig, op, sp, ptr, save_last_error); + do_icall (sig, op, sp, ptr, save_last_error); interp_pop_lmf (&ext); goto exit_icall; // prevent unused label warning in some configurations exit_icall: - return sp; + return NULL; } #ifdef _MSC_VER #pragma optimize ("", on) @@ -3031,19 +3000,11 @@ static long opcode_counts[MINT_LASTOP]; #if DEBUG_INTERP #define DUMP_INSTR() \ if (tracing > 1) { \ - char *ins; \ - if (sp > frame->stack) { \ - ins = dump_stack (frame->stack, sp); \ - } else { \ - ins = g_strdup (""); \ - } \ - sp->data.l = 0; \ output_indent (); \ char *mn = mono_method_full_name (frame->imethod->method, FALSE); \ char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \ - g_print ("(%p) %s -> %s\t%s\n", mono_thread_internal_current (), mn, disasm, ins); \ + g_print ("(%p) %s -> %s\n", mono_thread_internal_current (), mn, disasm); \ g_free (mn); \ - g_free (ins); \ g_free (disasm); \ } #else @@ -3072,12 +3033,12 @@ mono_interp_load_remote_field ( InterpMethod* imethod, MonoObject* o, const guint16* ip, - stackval* sp) + gpointer result) { g_assert (o); // Caller checks and throws exception properly. void* addr; - MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]]; + MonoClassField *field = (MonoClassField*)imethod->data_items [ip [3]]; #ifndef DISABLE_REMOTING gpointer tmp; @@ -3089,20 +3050,20 @@ mono_interp_load_remote_field ( } else #endif addr = (char*)o + field->offset; - stackval_from_data (field->type, &sp [-1], addr, FALSE); + stackval_from_data (field->type, (stackval*)result, addr, FALSE); } -static stackval* +static void mono_interp_load_remote_field_vt ( InterpMethod* imethod, MonoObject* o, const guint16* ip, - stackval* sp) + gpointer result) { g_assert (o); // Caller checks and throws exception properly. void* addr; - MonoClassField* const field = (MonoClassField*)imethod->data_items[ip [1]]; + MonoClassField *field = (MonoClassField*)imethod->data_items [ip [3]]; MonoClass* klass = mono_class_from_mono_type_internal (field->type); int const i32 = mono_class_value_size (klass, NULL); @@ -3116,9 +3077,7 @@ mono_interp_load_remote_field_vt ( } else #endif addr = (char*)o + field->offset; - sp--; - memcpy ((char*)sp, addr, i32); - return STACK_ADD_BYTES (sp, i32); + memcpy (result, addr, i32); } static gboolean @@ -3176,14 +3135,14 @@ mono_interp_leave (InterpFrame* parent_frame) return (MonoException*)tmp_sp.data.p; } -static void -mono_interp_enum_hasflag (stackval* sp, MonoClass* klass) +static gint32 +mono_interp_enum_hasflag (stackval *sp1, stackval *sp2, MonoClass* klass) { guint64 a_val = 0, b_val = 0; - stackval_to_data (m_class_get_byval_arg (klass), --sp, &b_val, FALSE); - stackval_to_data (m_class_get_byval_arg (klass), --sp, &a_val, FALSE); - sp->data.i = (a_val & b_val) == b_val; + stackval_to_data (m_class_get_byval_arg (klass), sp1, &a_val, FALSE); + stackval_to_data (m_class_get_byval_arg (klass), sp2, &b_val, FALSE); + return (a_val & b_val) == b_val; } // varargs in wasm consumes extra linear stack per call-site. @@ -3240,13 +3199,11 @@ method_entry (ThreadContext *context, InterpFrame *frame, /* Save the state of the interpeter main loop into FRAME */ #define SAVE_INTERP_STATE(frame) do { \ frame->state.ip = ip; \ - frame->state.sp = sp; \ } while (0) /* Load and clear state from FRAME */ #define LOAD_INTERP_STATE(frame) do { \ ip = frame->state.ip; \ - sp = frame->state.sp; \ locals = (unsigned char *)frame->stack; \ frame->state.ip = NULL; \ } while (0) @@ -3255,13 +3212,14 @@ method_entry (ThreadContext *context, InterpFrame *frame, #define INIT_INTERP_STATE(frame, _clause_args) do { \ ip = _clause_args ? ((FrameClauseArgs *)_clause_args)->start_with_ip : (frame)->imethod->code; \ locals = (unsigned char *)(frame)->stack; \ - sp = (stackval*)(locals + (frame)->imethod->total_locals_size); \ } while (0) #if PROFILE_INTERP static long total_executed_opcodes; #endif +#define LOCAL_VAR(offset,type) (*(type*)(locals + (offset))) + /* * If CLAUSE_ARGS is non-null, start executing from it. * The ERROR argument is used to avoid declaring an error object for every interp frame, its not used @@ -3277,12 +3235,11 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs /* Interpreter main loop state (InterpState) */ const guint16 *ip = NULL; - stackval *sp; unsigned char *locals = NULL; + int call_args_offset; #if DEBUG_INTERP int tracing = global_tracing; - unsigned char *vtalloc; #endif #if USE_COMPUTED_GOTO static void * const in_labels[] = { @@ -3328,8 +3285,8 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs INIT_INTERP_STATE (frame, clause_args); if (clause_args && clause_args->filter_exception) { - sp->data.p = clause_args->filter_exception; - sp++; + // Write the exception on to the first slot on the excecution stack + LOCAL_VAR (frame->imethod->total_locals_size, MonoException*) = clause_args->filter_exception; } #ifdef ENABLE_EXPERIMENT_TIERED @@ -3351,13 +3308,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs total_executed_opcodes++; #endif MintOpcode opcode; -#ifdef ENABLE_CHECKED_BUILD - guchar *sp_start = (guchar*)frame->stack + frame->imethod->total_locals_size; - guchar *sp_end = sp_start + frame->imethod->stack_size; - g_assert (locals == (guchar*)frame->stack); - g_assert ((guchar*)sp >= sp_start); - g_assert ((guchar*)sp <= sp_end); -#endif DUMP_INSTR(); MINT_IN_SWITCH (*ip) { MINT_IN_CASE(MINT_INITLOCALS) @@ -3376,15 +3326,14 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ++ip; mono_break (); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDNULL) - sp->data.p = NULL; - ++ip; - ++sp; + MINT_IN_CASE(MINT_LDNULL) + LOCAL_VAR (ip [1], gpointer) = NULL; + ip += 2; MINT_IN_BREAK; MINT_IN_CASE(MINT_INIT_ARGLIST) { - const guint16 *call_ip = frame->parent->state.ip - 4; + const guint16 *call_ip = frame->parent->state.ip - 5; g_assert_checked (*call_ip == MINT_CALL_VARARG); - int params_stack_size = call_ip [2]; + int params_stack_size = call_ip [4]; MonoMethodSignature *sig = (MonoMethodSignature*)frame->parent->imethod->data_items [call_ip [3]]; // we are being overly conservative with the size here, for simplicity @@ -3393,13 +3342,13 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs init_arglist (frame, sig, STACK_ADD_BYTES (frame->stack, ip [2]), (char*)arglist); // save the arglist for future access with MINT_ARGLIST - *(gpointer*)(locals + ip [1]) = arglist; + LOCAL_VAR (ip [1], gpointer) = arglist; ip += 3; MINT_IN_BREAK; } -#define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0) +#define LDC(n) do { LOCAL_VAR (ip [1], gint32) = (n); ip += 2; } while (0) MINT_IN_CASE(MINT_LDC_I4_M1) LDC(-1); MINT_IN_BREAK; @@ -3431,73 +3380,31 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs LDC(8); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDC_I4_S) - sp->data.i = (short)ip [1]; - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gint32) = (short)ip [2]; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDC_I4) - ++ip; - sp->data.i = READ32 (ip); - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gint32) = READ32 (ip + 2); + ip += 4; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDC_I8) - ++ip; - sp->data.l = READ64 (ip); - ip += 4; - ++sp; + LOCAL_VAR (ip [1], gint64) = READ64 (ip + 2); + ip += 6; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDC_I8_S) - sp->data.l = (short)ip [1]; - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gint64) = (short)ip [2]; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDC_R4) { - guint32 val; - ++ip; - val = READ32(ip); - sp->data.f_r4 = * (float *)&val; - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gint32) = READ32(ip + 2); /* not union usage */ + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDC_R8) - sp->data.l = READ64 (ip + 1); /* note union usage */ - ip += 5; - ++sp; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DUP) - sp [0] = sp[-1]; - ++sp; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_DUP_VT) { - int i32 = READ32 (ip + 1); - memcpy (sp, STACK_SUB_BYTES (sp, i32), i32); - sp = STACK_ADD_BYTES (sp, i32); - ip += 3; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_POP) { - sp--; - ip++; - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_POP_VT) { - int i32 = READ32 (ip + 1); - i32 = ALIGN_TO (i32, MINT_STACK_SLOT_SIZE); - sp = STACK_SUB_BYTES (sp, i32); - ip += 3; + LOCAL_VAR (ip [1], gint64) = READ64 (ip + 2); /* note union usage */ + ip += 6; MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_POP1) { - sp [-2] = sp [-1]; - sp--; - ip++; - MINT_IN_BREAK; - } MINT_IN_CASE(MINT_JMP) { - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); InterpMethod *new_method = (InterpMethod*)frame->imethod->data_items [ip [1]]; if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL) @@ -3518,16 +3425,15 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs */ context->stack_pointer = (guchar*)frame->stack + new_method->alloca_size; frame->imethod = new_method; - sp = (stackval*)(locals + frame->imethod->total_locals_size); ip = frame->imethod->code; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CALL_DELEGATE) { // FIXME We don't need to encode the whole signature, just param_count - MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; + MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [3]]; int param_count = csignature->param_count; - sp = STACK_SUB_BYTES (sp, ip [2]); - MonoDelegate *del = (MonoDelegate*) sp [0].data.o; + call_args_offset = ip [1]; + MonoDelegate *del = LOCAL_VAR (call_args_offset, MonoDelegate*); gboolean is_multicast = del->method == NULL; InterpMethod *del_imethod = (InterpMethod*)del->interp_invoke_impl; @@ -3556,7 +3462,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } else if (del_imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL && !del->target) { // 'this' is passed dynamically, we need to recompute the target method // with each call - del_imethod = get_virtual_method (del_imethod, sp [1].data.o->vtable); + del_imethod = get_virtual_method (del_imethod, LOCAL_VAR (call_args_offset + MINT_STACK_SLOT_SIZE, MonoObject*)->vtable); } else { del->interp_invoke_impl = del_imethod; } @@ -3568,106 +3474,94 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs // Target method is static but the delegate has a target object. We handle // this separately from the case below, because, for these calls, the instance // is allowed to be null. - sp [0].data.o = del->target; + LOCAL_VAR (ip [1], MonoObject*) = del->target; } else if (del->target) { MonoObject *this_arg = del->target; // replace the MonoDelegate* on the stack with 'this' pointer if (m_class_is_valuetype (this_arg->vtable->klass)) { gpointer unboxed = mono_object_unbox_internal (this_arg); - sp [0].data.p = unboxed; + LOCAL_VAR (ip [1], gpointer) = unboxed; } else { - sp [0].data.o = this_arg; + LOCAL_VAR (ip [1], MonoObject*) = this_arg; } } else { // skip the delegate pointer for static calls // FIXME we could avoid memmove - memmove (sp, sp + 1, ip [2]); + memmove (locals + call_args_offset, locals + call_args_offset + MINT_STACK_SLOT_SIZE, ip [2]); } } - ip += 3; + ip += 4; goto call; } MINT_IN_CASE(MINT_CALLI) { MonoMethodSignature *csignature; - csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; - --sp; + csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [3]]; - cmethod = (InterpMethod*)sp->data.p; + cmethod = LOCAL_VAR (ip [2], InterpMethod*); if (cmethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { cmethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (cmethod->method, FALSE, FALSE), error); mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ } - /* decrement by the actual number of args */ - sp = STACK_SUB_BYTES (sp, ip [2]); + call_args_offset = ip [1]; if (csignature->hasthis) { - MonoObject *this_arg = (MonoObject*)sp->data.p; + MonoObject *this_arg = LOCAL_VAR (call_args_offset, MonoObject*); if (m_class_is_valuetype (this_arg->vtable->klass)) { gpointer unboxed = mono_object_unbox_internal (this_arg); - sp [0].data.p = unboxed; + LOCAL_VAR (call_args_offset, gpointer) = unboxed; } } - ip += 3; + ip += 4; goto call; } MINT_IN_CASE(MINT_CALLI_NAT_FAST) { - gpointer target_ip = sp [-1].data.p; - MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; - int opcode = ip [2]; - gboolean save_last_error = ip [3]; + MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [2]]; + int opcode = ip [3]; + gboolean save_last_error = ip [4]; - sp--; + stackval *args = (stackval*)(locals + ip [1]); + gpointer target_ip = args [csignature->param_count].data.p; /* for calls, have ip pointing at the start of next instruction */ - frame->state.ip = ip + 4; + frame->state.ip = ip + 5; - sp = do_icall_wrapper (frame, csignature, opcode, sp, target_ip, save_last_error); + do_icall_wrapper (frame, csignature, opcode, args, target_ip, save_last_error); EXCEPTION_CHECKPOINT_GC_UNSAFE; CHECK_RESUME_STATE (context); - ip += 4; + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CALLI_NAT_DYNAMIC) { - MonoMethodSignature* csignature; - - csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; - - --sp; - guchar* code = (guchar*)sp->data.p; + MonoMethodSignature* csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [3]]; - /* decrement by the actual number of args */ - sp = STACK_SUB_BYTES (sp, ip [2]); + call_args_offset = ip [1]; + guchar* code = LOCAL_VAR (ip [2], guchar*); cmethod = mono_interp_get_native_func_wrapper (frame->imethod, csignature, code); - ip += 3; + ip += 4; goto call; } MINT_IN_CASE(MINT_CALLI_NAT) { - MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]]; - InterpMethod *imethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; + MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [3]]; + InterpMethod *imethod = (InterpMethod*)frame->imethod->data_items [ip [4]]; - --sp; - guchar* const code = (guchar*)sp->data.p; - - sp = STACK_SUB_BYTES (sp, ip [3]); + guchar *code = LOCAL_VAR (ip [2], guchar*); gboolean save_last_error = ip [5]; gpointer *cache = (gpointer*)&frame->imethod->data_items [ip [6]]; /* for calls, have ip pointing at the start of next instruction */ - frame->state.ip = ip + 6; - ves_pinvoke_method (imethod, csignature, (MonoFuncV)code, context, frame, sp, save_last_error, cache); + frame->state.ip = ip + 7; + ves_pinvoke_method (imethod, csignature, (MonoFuncV)code, context, frame, (stackval*)(locals + ip [1]), save_last_error, cache); EXCEPTION_CHECKPOINT_GC_UNSAFE; CHECK_RESUME_STATE (context); - // Result was written directly at top of stack - sp = STACK_ADD_BYTES (sp, ip [4]); ip += 7; MINT_IN_BREAK; } @@ -3675,10 +3569,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MonoObject *this_arg; int slot; - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; + cmethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; + call_args_offset = ip [1]; - sp = STACK_SUB_BYTES (sp, ip [2]); - this_arg = (MonoObject*)sp->data.p; + this_arg = LOCAL_VAR (call_args_offset, MonoObject*); slot = (gint16)ip [3]; ip += 4; @@ -3686,7 +3580,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { /* unbox */ gpointer unboxed = mono_object_unbox_internal (this_arg); - sp [0].data.p = unboxed; + LOCAL_VAR (call_args_offset, gpointer) = unboxed; } InterpMethodCodeType code_type = cmethod->code_type; @@ -3711,16 +3605,13 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } else if (code_type == IMETHOD_CODE_COMPILED) { frame->state.ip = ip; error_init_reuse (error); - do_jit_call (sp, frame, cmethod, error); + do_jit_call ((stackval*)(locals + call_args_offset), frame, cmethod, error); if (!is_ok (error)) { MonoException *ex = mono_error_convert_to_exception (error); THROW_EX (ex, ip); } CHECK_RESUME_STATE (context); - - if (cmethod->rtype->type != MONO_TYPE_VOID) - sp = STACK_ADD_BYTES (sp, ((JitCallInfo*)cmethod->jit_call_info)->res_size); } MINT_IN_BREAK; @@ -3728,25 +3619,24 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_CALL_VARARG) { // Same as MINT_CALL, except at ip [3] we have the index for the csignature, // which is required by the called method to set up the arglist. - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; - sp = STACK_SUB_BYTES (sp, ip [2]); - ip += 4; + cmethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; + call_args_offset = ip [1]; + ip += 5; goto call; } MINT_IN_CASE(MINT_CALLVIRT) { // FIXME CALLVIRT opcodes are not used on netcore. We should kill them. - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; - - sp = STACK_SUB_BYTES (sp, ip [2]); + cmethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; + call_args_offset = ip [1]; - MonoObject *this_arg = (MonoObject*)sp->data.p; + MonoObject *this_arg = LOCAL_VAR (call_args_offset, MonoObject*); cmethod = get_virtual_method (cmethod, this_arg->vtable); if (m_class_is_valuetype (this_arg->vtable->klass) && m_class_is_valuetype (cmethod->method->klass)) { /* unbox */ gpointer unboxed = mono_object_unbox_internal (this_arg); - sp [0].data.p = unboxed; + LOCAL_VAR (call_args_offset, gpointer) = unboxed; } #ifdef ENABLE_EXPERIMENT_TIERED @@ -3757,8 +3647,8 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs goto call; } MINT_IN_CASE(MINT_CALL) { - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; - sp = STACK_SUB_BYTES (sp, ip [2]); + cmethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; + call_args_offset = ip [1]; #ifdef ENABLE_EXPERIMENT_TIERED ip += 5; @@ -3781,7 +3671,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs // Not free currently, but will be when allocation attempted. frame->next_free = child_frame; } - reinit_frame (child_frame, frame, cmethod, sp); + reinit_frame (child_frame, frame, cmethod, locals + call_args_offset); frame = child_frame; } if (method_entry (context, frame, @@ -3794,7 +3684,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs EXCEPTION_CHECKPOINT; } - context->stack_pointer = (guchar*)sp + cmethod->alloca_size; + context->stack_pointer = (guchar*)frame->stack + cmethod->alloca_size; /* Make sure the stack pointer is bumped before we store any references on the stack */ mono_compiler_barrier (); @@ -3803,34 +3693,29 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } MINT_IN_CASE(MINT_JIT_CALL) { - InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; + InterpMethod *rmethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; error_init_reuse (error); - sp = STACK_SUB_BYTES (sp, ip [2]); /* for calls, have ip pointing at the start of next instruction */ frame->state.ip = ip + 3; - do_jit_call (sp, frame, rmethod, error); + do_jit_call ((stackval*)(locals + ip [1]), frame, rmethod, error); if (!is_ok (error)) { MonoException *ex = mono_error_convert_to_exception (error); THROW_EX (ex, ip); } CHECK_RESUME_STATE (context); - - if (rmethod->rtype->type != MONO_TYPE_VOID) - sp = STACK_ADD_BYTES (sp, ((JitCallInfo*)rmethod->jit_call_info)->res_size); ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_JIT_CALL2) { #ifdef ENABLE_EXPERIMENT_TIERED - InterpMethod *rmethod = (InterpMethod *) READ64 (ip + 1); + InterpMethod *rmethod = (InterpMethod *) READ64 (ip + 2); error_init_reuse (error); - sp -= rmethod->param_count + rmethod->hasthis; - frame->state.ip = ip + 5; - do_jit_call (sp, frame, rmethod, error); + frame->state.ip = ip + 6; + do_jit_call ((stackval*)(locals + ip [1]), frame, rmethod, error); if (!is_ok (error)) { MonoException *ex = mono_error_convert_to_exception (error); THROW_EX (ex, ip); @@ -3838,9 +3723,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs CHECK_RESUME_STATE (context); - if (rmethod->rtype->type != MONO_TYPE_VOID) - sp++; - ip += 5; + ip += 6; #else g_error ("MINT_JIT_ICALL2 shouldn't be used"); #endif @@ -3848,73 +3731,38 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } MINT_IN_CASE(MINT_CALLRUN) { #ifndef ENABLE_NETCORE - MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [1]]; - MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [2]]; + MonoMethod *target_method = (MonoMethod*) frame->imethod->data_items [ip [2]]; + MonoMethodSignature *sig = (MonoMethodSignature*) frame->imethod->data_items [ip [3]]; - stackval *retval = sp; - - sp -= sig->param_count; - if (sig->hasthis) - sp--; - - MonoException *ex = ves_imethod (frame, target_method, sig, sp, retval); + MonoException *ex = ves_imethod (frame, target_method, sig, (stackval*)(locals + ip [1])); if (ex) THROW_EX (ex, ip); - if (sig->ret->type != MONO_TYPE_VOID) { - *sp = *retval; - sp++; - } - ip += 3; + ip += 4; #else g_assert_not_reached (); #endif MINT_IN_BREAK; } MINT_IN_CASE(MINT_RET) - --sp; - if (frame->parent) { - frame->parent->state.sp [0] = *sp; - frame->parent->state.sp++; - } - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); + frame->stack [0] = LOCAL_VAR (ip [1], stackval); goto exit_frame; MINT_IN_CASE(MINT_RET_VOID) - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT) { - int const i32 = READ32 (ip + 1); - - sp = STACK_SUB_BYTES (sp, i32); - if (frame->parent) { - memmove (frame->parent->state.sp, sp, i32); - frame->parent->state.sp = STACK_ADD_BYTES (frame->parent->state.sp, i32); - } - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); + memmove (frame->stack, locals + ip [1], ip [2]); goto exit_frame; } MINT_IN_CASE(MINT_RET_LOCALLOC) - --sp; - if (frame->parent) { - frame->parent->state.sp [0] = *sp; - frame->parent->state.sp++; - } + frame->stack [0] = LOCAL_VAR (ip [1], stackval); frame_data_allocator_pop (&context->data_stack, frame); - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); goto exit_frame; MINT_IN_CASE(MINT_RET_VOID_LOCALLOC) frame_data_allocator_pop (&context->data_stack, frame); - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); goto exit_frame; MINT_IN_CASE(MINT_RET_VT_LOCALLOC) { - int const i32 = READ32 (ip + 1); - sp = STACK_SUB_BYTES (sp, i32); - if (frame->parent) { - memmove (frame->parent->state.sp, sp, i32); - frame->parent->state.sp = STACK_ADD_BYTES (frame->parent->state.sp, i32); - } + memmove (frame->stack, locals + ip [1], ip [2]); frame_data_allocator_pop (&context->data_stack, frame); - g_assert_checked (sp == (stackval*)(locals + frame->imethod->total_locals_size)); goto exit_frame; } @@ -3940,752 +3788,868 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define ZEROP_S(datamem, op) \ - --sp; \ - if (sp->data.datamem op 0) { \ - gint16 br_offset = (gint16) ip [1]; \ +#define ZEROP_S(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op 0) { \ + gint16 br_offset = (gint16) ip [2]; \ BACK_BRANCH_PROFILE (br_offset); \ ip += br_offset; \ } else \ - ip += 2; + ip += 3; -#define ZEROP(datamem, op) \ - --sp; \ - if (sp->data.datamem op 0) { \ - gint32 br_offset = (gint32)READ32(ip + 1); \ +#define ZEROP(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op 0) { \ + gint32 br_offset = (gint32)READ32(ip + 2); \ BACK_BRANCH_PROFILE (br_offset); \ ip += br_offset; \ } else \ - ip += 3; + ip += 4; MINT_IN_CASE(MINT_BRFALSE_I4_S) - ZEROP_S(i, ==); + ZEROP_S(gint32, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_I8_S) - ZEROP_S(l, ==); + ZEROP_S(gint64, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_R4_S) - ZEROP_S(f_r4, ==); + ZEROP_S(float, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_R8_S) - ZEROP_S(f, ==); + ZEROP_S(double, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_I4) - ZEROP(i, ==); + ZEROP(gint32, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_I8) - ZEROP(l, ==); + ZEROP(gint64, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_R4) - ZEROP_S(f_r4, ==); + ZEROP_S(float, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRFALSE_R8) - ZEROP_S(f, ==); + ZEROP_S(double, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_I4_S) - ZEROP_S(i, !=); + ZEROP_S(gint32, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_I8_S) - ZEROP_S(l, !=); + ZEROP_S(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_R4_S) - ZEROP_S(f_r4, !=); + ZEROP_S(float, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_R8_S) - ZEROP_S(f, !=); + ZEROP_S(double, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_I4) - ZEROP(i, !=); + ZEROP(gint32, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_I8) - ZEROP(l, !=); + ZEROP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_R4) - ZEROP(f_r4, !=); + ZEROP(float, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BRTRUE_R8) - ZEROP(f, !=); - MINT_IN_BREAK; + ZEROP(double, !=); + MINT_IN_BREAK; #define CONDBR_S(cond) \ - sp -= 2; \ if (cond) { \ - gint16 br_offset = (gint16) ip [1]; \ + gint16 br_offset = (gint16) ip [3]; \ BACK_BRANCH_PROFILE (br_offset); \ ip += br_offset; \ } else \ - ip += 2; -#define BRELOP_S(datamem, op) \ - CONDBR_S(sp[0].data.datamem op sp[1].data.datamem) + ip += 4; +#define BRELOP_S(datatype, op) \ + CONDBR_S(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) #define CONDBR(cond) \ - sp -= 2; \ if (cond) { \ - gint32 br_offset = (gint32) READ32 (ip + 1); \ + gint32 br_offset = (gint32) READ32 (ip + 3); \ BACK_BRANCH_PROFILE (br_offset); \ ip += br_offset; \ } else \ - ip += 3; + ip += 5; -#define BRELOP(datamem, op) \ - CONDBR(sp[0].data.datamem op sp[1].data.datamem) +#define BRELOP(datatype, op) \ + CONDBR(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) MINT_IN_CASE(MINT_BEQ_I4_S) - BRELOP_S(i, ==) + BRELOP_S(gint32, ==) MINT_IN_BREAK; MINT_IN_CASE(MINT_BEQ_I8_S) - BRELOP_S(l, ==) + BRELOP_S(gint64, ==) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_R4_S) - CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4) + MINT_IN_CASE(MINT_BEQ_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 == f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_R8_S) - CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f) + } + MINT_IN_CASE(MINT_BEQ_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 == d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BEQ_I4) - BRELOP(i, ==) + BRELOP(gint32, ==) MINT_IN_BREAK; MINT_IN_CASE(MINT_BEQ_I8) - BRELOP(l, ==) + BRELOP(gint64, ==) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_R4) - CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4) + MINT_IN_CASE(MINT_BEQ_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(!isunordered (f1, f2) && f1 == f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BEQ_R8) - CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f) + } + MINT_IN_CASE(MINT_BEQ_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(!mono_isunordered (d1, d2) && d1 == d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGE_I4_S) - BRELOP_S(i, >=) + BRELOP_S(gint32, >=) MINT_IN_BREAK; MINT_IN_CASE(MINT_BGE_I8_S) - BRELOP_S(l, >=) + BRELOP_S(gint64, >=) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_R4_S) - CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGE_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 >= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_R8_S) - CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f) + } + MINT_IN_CASE(MINT_BGE_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 >= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGE_I4) - BRELOP(i, >=) + BRELOP(gint32, >=) MINT_IN_BREAK; MINT_IN_CASE(MINT_BGE_I8) - BRELOP(l, >=) + BRELOP(gint64, >=) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_R4) - CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGE_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(!isunordered (f1, f2) && f1 >= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_R8) - CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f) + } + MINT_IN_CASE(MINT_BGE_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(!mono_isunordered (d1, d2) && d1 >= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGT_I4_S) - BRELOP_S(i, >) + BRELOP_S(gint32, >) MINT_IN_BREAK; MINT_IN_CASE(MINT_BGT_I8_S) - BRELOP_S(l, >) + BRELOP_S(gint64, >) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_R4_S) - CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGT_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 > f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_R8_S) - CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f) + } + MINT_IN_CASE(MINT_BGT_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 > d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGT_I4) - BRELOP(i, >) + BRELOP(gint32, >) MINT_IN_BREAK; MINT_IN_CASE(MINT_BGT_I8) - BRELOP(l, >) + BRELOP(gint64, >) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_R4) - CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGT_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(!isunordered (f1, f2) && f1 > f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_R8) - CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f) + } + MINT_IN_CASE(MINT_BGT_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(!mono_isunordered (d1, d2) && d1 > d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLT_I4_S) - BRELOP_S(i, <) + BRELOP_S(gint32, <) MINT_IN_BREAK; MINT_IN_CASE(MINT_BLT_I8_S) - BRELOP_S(l, <) + BRELOP_S(gint64, <) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_R4_S) - CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLT_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 < f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_R8_S) - CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f) + } + MINT_IN_CASE(MINT_BLT_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 < d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLT_I4) - BRELOP(i, <) + BRELOP(gint32, <) MINT_IN_BREAK; MINT_IN_CASE(MINT_BLT_I8) - BRELOP(l, <) + BRELOP(gint64, <) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_R4) - CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLT_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(!isunordered (f1, f2) && f1 < f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_R8) - CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f) + } + MINT_IN_CASE(MINT_BLT_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(!mono_isunordered (d1, d2) && d1 < d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLE_I4_S) - BRELOP_S(i, <=) + BRELOP_S(gint32, <=) MINT_IN_BREAK; MINT_IN_CASE(MINT_BLE_I8_S) - BRELOP_S(l, <=) + BRELOP_S(gint64, <=) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_R4_S) - CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLE_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(!isunordered (f1, f2) && f1 <= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_R8_S) - CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f) + } + MINT_IN_CASE(MINT_BLE_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(!mono_isunordered (d1, d2) && d1 <= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLE_I4) - BRELOP(i, <=) + BRELOP(gint32, <=) MINT_IN_BREAK; MINT_IN_CASE(MINT_BLE_I8) - BRELOP(l, <=) + BRELOP(gint64, <=) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_R4) - CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLE_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(!isunordered (f1, f2) && f1 <= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_R8) - CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f) + } + MINT_IN_CASE(MINT_BLE_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(!mono_isunordered (d1, d2) && d1 <= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BNE_UN_I4_S) - BRELOP_S(i, !=) + BRELOP_S(gint32, !=) MINT_IN_BREAK; MINT_IN_CASE(MINT_BNE_UN_I8_S) - BRELOP_S(l, !=) + BRELOP_S(gint64, !=) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_R4_S) - CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4) + MINT_IN_CASE(MINT_BNE_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 != f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_R8_S) - CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f) + } + MINT_IN_CASE(MINT_BNE_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 != d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BNE_UN_I4) - BRELOP(i, !=) + BRELOP(gint32, !=) MINT_IN_BREAK; MINT_IN_CASE(MINT_BNE_UN_I8) - BRELOP(l, !=) + BRELOP(gint64, !=) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_R4) - CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4) + MINT_IN_CASE(MINT_BNE_UN_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(isunordered (f1, f2) || f1 != f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BNE_UN_R8) - CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f) + } + MINT_IN_CASE(MINT_BNE_UN_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(mono_isunordered (d1, d2) || d1 != d2) MINT_IN_BREAK; + } -#define BRELOP_S_CAST(datamem, op, type) \ - sp -= 2; \ - if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \ - gint16 br_offset = (gint16) ip [1]; \ +#define BRELOP_S_CAST(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) { \ + gint16 br_offset = (gint16) ip [3]; \ BACK_BRANCH_PROFILE (br_offset); \ ip += br_offset; \ } else \ - ip += 2; + ip += 4; -#define BRELOP_CAST(datamem, op, type) \ - sp -= 2; \ - if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) { \ +#define BRELOP_CAST(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) { \ gint32 br_offset = (gint32) ip [1]; \ BACK_BRANCH_PROFILE (br_offset); \ ip += br_offset; \ } else \ - ip += 3; + ip += 5; MINT_IN_CASE(MINT_BGE_UN_I4_S) - BRELOP_S_CAST(i, >=, guint32); + BRELOP_S_CAST(guint32, >=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BGE_UN_I8_S) - BRELOP_S_CAST(l, >=, guint64); + BRELOP_S_CAST(guint64, >=); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_R4_S) - CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGE_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 >= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_R8_S) - CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f) + } + MINT_IN_CASE(MINT_BGE_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 >= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGE_UN_I4) - BRELOP_CAST(i, >=, guint32); + BRELOP_CAST(guint32, >=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BGE_UN_I8) - BRELOP_CAST(l, >=, guint64); + BRELOP_CAST(guint64, >=); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_R4) - CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGE_UN_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(isunordered (f1, f2) || f1 >= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGE_UN_R8) - CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f) + } + MINT_IN_CASE(MINT_BGE_UN_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(mono_isunordered (d1, d2) || d1 >= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGT_UN_I4_S) - BRELOP_S_CAST(i, >, guint32); + BRELOP_S_CAST(guint32, >); MINT_IN_BREAK; MINT_IN_CASE(MINT_BGT_UN_I8_S) - BRELOP_S_CAST(l, >, guint64); + BRELOP_S_CAST(guint64, >); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_R4_S) - CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGT_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 > f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_R8_S) - CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f) + } + MINT_IN_CASE(MINT_BGT_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 > d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BGT_UN_I4) - BRELOP_CAST(i, >, guint32); + BRELOP_CAST(guint32, >); MINT_IN_BREAK; MINT_IN_CASE(MINT_BGT_UN_I8) - BRELOP_CAST(l, >, guint64); + BRELOP_CAST(guint64, >); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_R4) - CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4) + MINT_IN_CASE(MINT_BGT_UN_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(isunordered (f1, f2) || f1 > f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BGT_UN_R8) - CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f) + } + MINT_IN_CASE(MINT_BGT_UN_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(mono_isunordered (d1, d2) || d1 > d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLE_UN_I4_S) - BRELOP_S_CAST(i, <=, guint32); + BRELOP_S_CAST(guint32, <=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BLE_UN_I8_S) - BRELOP_S_CAST(l, <=, guint64); + BRELOP_S_CAST(guint64, <=); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_R4_S) - CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLE_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 <= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_R8_S) - CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f) + } + MINT_IN_CASE(MINT_BLE_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 <= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLE_UN_I4) - BRELOP_CAST(i, <=, guint32); + BRELOP_CAST(guint32, <=); MINT_IN_BREAK; MINT_IN_CASE(MINT_BLE_UN_I8) - BRELOP_CAST(l, <=, guint64); + BRELOP_CAST(guint64, <=); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_R4) - CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLE_UN_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(isunordered (f1, f2) || f1 <= f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLE_UN_R8) - CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f) + } + MINT_IN_CASE(MINT_BLE_UN_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(mono_isunordered (d1, d2) || d1 <= d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLT_UN_I4_S) - BRELOP_S_CAST(i, <, guint32); + BRELOP_S_CAST(guint32, <); MINT_IN_BREAK; MINT_IN_CASE(MINT_BLT_UN_I8_S) - BRELOP_S_CAST(l, <, guint64); + BRELOP_S_CAST(guint64, <); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_R4_S) - CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLT_UN_R4_S) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR_S(isunordered (f1, f2) || f1 < f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_R8_S) - CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f) + } + MINT_IN_CASE(MINT_BLT_UN_R8_S) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR_S(mono_isunordered (d1, d2) || d1 < d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_BLT_UN_I4) - BRELOP_CAST(i, <, guint32); + BRELOP_CAST(guint32, <); MINT_IN_BREAK; MINT_IN_CASE(MINT_BLT_UN_I8) - BRELOP_CAST(l, <, guint64); + BRELOP_CAST(guint64, <); MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_R4) - CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4) + MINT_IN_CASE(MINT_BLT_UN_R4) { + float f1 = LOCAL_VAR (ip [1], float); + float f2 = LOCAL_VAR (ip [2], float); + CONDBR(isunordered (f1, f2) || f1 < f2) MINT_IN_BREAK; - MINT_IN_CASE(MINT_BLT_UN_R8) - CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f) + } + MINT_IN_CASE(MINT_BLT_UN_R8) { + double d1 = LOCAL_VAR (ip [1], double); + double d2 = LOCAL_VAR (ip [2], double); + CONDBR(mono_isunordered (d1, d2) || d1 < d2) MINT_IN_BREAK; + } MINT_IN_CASE(MINT_SWITCH) { - guint32 n; - const unsigned short *st; - ++ip; - n = READ32 (ip); - ip += 2; - st = ip + 2 * n; - --sp; - if ((guint32)sp->data.i < n) { - gint offset; - ip += 2 * (guint32)sp->data.i; - offset = READ32 (ip); - ip = ip + offset; + guint32 val = LOCAL_VAR (ip [1], guint32); + guint32 n = READ32 (ip + 2); + ip += 4; + if (val < n) { + ip += 2 * val; + int offset = READ32 (ip); + ip += offset; } else { - ip = st; + ip += 2 * n; } MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDIND_I1_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; - sp[-1].data.i = *(gint8*)sp[-1].data.p; + MINT_IN_CASE(MINT_LDIND_I1_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], int) = *(gint8*)ptr; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_U1_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; - sp[-1].data.i = *(guint8*)sp[-1].data.p; + } + MINT_IN_CASE(MINT_LDIND_U1_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], int) = *(guint8*)ptr; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_I2_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; - sp[-1].data.i = *(gint16*)sp[-1].data.p; + } + MINT_IN_CASE(MINT_LDIND_I2_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], int) = *(gint16*)ptr; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_U2_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; - sp[-1].data.i = *(guint16*)sp[-1].data.p; + } + MINT_IN_CASE(MINT_LDIND_U2_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], int) = *(guint16*)ptr; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_LDIND_I4_CHECK) /* Fall through */ - MINT_IN_CASE(MINT_LDIND_U4_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; - sp[-1].data.i = *(gint32*)sp[-1].data.p; + MINT_IN_CASE(MINT_LDIND_U4_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], int) = *(gint32*)ptr; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_I8_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; + } + MINT_IN_CASE(MINT_LDIND_I8_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); #ifdef NO_UNALIGNED_ACCESS - if ((gsize)sp [-1].data.p % SIZEOF_VOID_P) - memcpy (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64)); + if ((gsize)ptr % SIZEOF_VOID_P) + memcpy (locals + ip [1], ptr, sizeof (gint64)); else #endif - sp[-1].data.l = *(gint64*)sp[-1].data.p; + LOCAL_VAR (ip [1], gint64) = *(gint64*)ptr; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_LDIND_I) { - guint16 offset = ip [1]; - // This doesn't follow the current stack based design, but we plan to switch to explicit offsets. - stackval *addr = (stackval*)(locals + frame->imethod->total_locals_size + offset); - addr->data.p = *(gpointer*)addr->data.p; - ip += 2; + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + LOCAL_VAR (ip [1], gpointer) = *(gpointer*)ptr; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDIND_I8) { - guint16 offset = ip [1]; - // This doesn't follow the current stack based design, but we plan to switch to explicit offsets. - stackval *addr = (stackval*)(locals + frame->imethod->total_locals_size + offset); + gpointer ptr = LOCAL_VAR (ip [2], gpointer); #ifdef NO_UNALIGNED_ACCESS - if ((gsize)addr->data.p % SIZEOF_VOID_P) - memcpy (&addr->data.l, addr->data.p, sizeof (gint64)); + if ((gsize)ptr % SIZEOF_VOID_P) + memcpy (locals + ip [1], ptr, sizeof (gint64)); else #endif - addr->data.l = *(gint64*)addr->data.p; - ip += 2; + LOCAL_VAR (ip [1], gint64) = *(gint64*)ptr; + ip += 3; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDIND_R4_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; - sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p; + MINT_IN_CASE(MINT_LDIND_R4_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], float) = *(gfloat*)ptr; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDIND_R8_CHECK) - NULL_CHECK (sp [-1].data.p); - ++ip; + } + MINT_IN_CASE(MINT_LDIND_R8_CHECK) { + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); #ifdef NO_UNALIGNED_ACCESS - if ((gsize)sp [-1].data.p % SIZEOF_VOID_P) - memcpy (&sp [-1].data.f, sp [-1].data.p, sizeof (gdouble)); + if ((gsize)ptr % SIZEOF_VOID_P) + memcpy (locals + ip [1], ptr, sizeof (gdouble)); else #endif - sp[-1].data.f = *(gdouble*)sp[-1].data.p; + LOCAL_VAR (ip [1], double) = *(gdouble*)ptr; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_LDIND_REF) - ++ip; - sp[-1].data.p = *(gpointer*)sp[-1].data.p; + LOCAL_VAR (ip [1], gpointer) = *(gpointer*)LOCAL_VAR (ip [2], gpointer); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDIND_REF_CHECK) { - NULL_CHECK (sp [-1].data.p); - ++ip; - sp [-1].data.p = *(gpointer*)sp [-1].data.p; + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + NULL_CHECK (ptr); + LOCAL_VAR (ip [1], gpointer) = *(gpointer*)LOCAL_VAR (ip [2], gpointer); + ip += 3; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_STIND_REF) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; - mono_gc_wbarrier_generic_store_internal (sp->data.p, sp [1].data.o); + MINT_IN_CASE(MINT_STIND_REF) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); + mono_gc_wbarrier_generic_store_internal (ptr, LOCAL_VAR (ip [2], MonoObject*)); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I1) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; - * (gint8 *) sp->data.p = (gint8)sp[1].data.i; + } + MINT_IN_CASE(MINT_STIND_I1) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); + *(gint8*)ptr = LOCAL_VAR (ip [2], gint8); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I2) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; - * (gint16 *) sp->data.p = (gint16)sp[1].data.i; + } + MINT_IN_CASE(MINT_STIND_I2) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); + *(gint16*)ptr = LOCAL_VAR (ip [2], gint16); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I4) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; - * (gint32 *) sp->data.p = sp[1].data.i; + } + MINT_IN_CASE(MINT_STIND_I4) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); + *(gint32*)ptr = LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; - * (mono_i *) sp->data.p = (mono_i)sp[1].data.p; + } + MINT_IN_CASE(MINT_STIND_I) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); + *(mono_i*)ptr = LOCAL_VAR (ip [2], mono_i); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_I8) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; + } + MINT_IN_CASE(MINT_STIND_I8) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); #ifdef NO_UNALIGNED_ACCESS - if ((gsize)sp->data.p % SIZEOF_VOID_P) - memcpy (sp->data.p, &sp [1].data.l, sizeof (gint64)); + if ((gsize)ptr % SIZEOF_VOID_P) + memcpy (ptr, locals + ip [2], sizeof (gint64)); else #endif - * (gint64 *) sp->data.p = sp[1].data.l; + *(gint64*)ptr = LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_R4) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; - * (float *) sp->data.p = sp[1].data.f_r4; + } + MINT_IN_CASE(MINT_STIND_R4) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); + *(float*)ptr = LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_STIND_R8) - NULL_CHECK (sp [-2].data.p); - ++ip; - sp -= 2; + } + MINT_IN_CASE(MINT_STIND_R8) { + gpointer ptr = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (ptr); #ifdef NO_UNALIGNED_ACCESS - if ((gsize)sp->data.p % SIZEOF_VOID_P) - memcpy (sp->data.p, &sp [1].data.f, sizeof (double)); + if ((gsize)ptr % SIZEOF_VOID_P) + memcpy (ptr, locals + ip [2], sizeof (double)); else #endif - * (double *) sp->data.p = sp[1].data.f; + *(double*)ptr = LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4) - ++ip; - sp -= 2; - mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i); + mono_atomic_store_i32 (LOCAL_VAR (ip [1], gint32*), LOCAL_VAR (ip [2], gint32)); + ip += 3; MINT_IN_BREAK; -#define BINOP(datamem, op) \ - --sp; \ - sp [-1].data.datamem op ## = sp [0].data.datamem; \ - ++ip; +#define BINOP(datatype, op) \ + LOCAL_VAR (ip [1], datatype) = LOCAL_VAR (ip [2], datatype) op LOCAL_VAR (ip [3], datatype); \ + ip += 4; MINT_IN_CASE(MINT_ADD_I4) - BINOP(i, +); + BINOP(gint32, +); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_I8) - BINOP(l, +); + BINOP(gint64, +); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_R4) - BINOP(f_r4, +); + BINOP(float, +); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD_R8) - BINOP(f, +); + BINOP(double, +); MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD1_I4) - ++sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = LOCAL_VAR (ip [2], gint32) + 1; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_ADD1_I8) - ++sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LOCADD1_I4) - *(gint32*)(locals + ip [1]) += 1; - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LOCADD1_I8) - *(gint64*)(locals + ip [1]) += 1; - ip += 2; + LOCAL_VAR (ip [1], gint64) = LOCAL_VAR (ip [2], gint64) + 1; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_I4) - BINOP(i, -); + BINOP(gint32, -); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_I8) - BINOP(l, -); + BINOP(gint64, -); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_R4) - BINOP(f_r4, -); + BINOP(float, -); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB_R8) - BINOP(f, -); + BINOP(double, -); MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB1_I4) - --sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = LOCAL_VAR (ip [2], gint32) - 1; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_SUB1_I8) - --sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LOCSUB1_I4) - *(gint32*)(locals + ip [1]) -= 1; - ip += 2; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_LOCSUB1_I8) - *(gint64*)(locals + ip [1]) -= 1; + LOCAL_VAR (ip [1], gint64) = LOCAL_VAR (ip [2], gint64) - 1; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_I4) - BINOP(i, *); + BINOP(gint32, *); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_I8) - BINOP(l, *); + BINOP(gint64, *); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_R4) - BINOP(f_r4, *); + BINOP(float, *); MINT_IN_BREAK; MINT_IN_CASE(MINT_MUL_R8) - BINOP(f, *); + BINOP(double, *); MINT_IN_BREAK; MINT_IN_CASE(MINT_DIV_I4) { - gint32 l1 = sp [-1].data.i; - gint32 l2 = sp [-2].data.i; - if (l1 == 0) + gint32 i1 = LOCAL_VAR (ip [2], gint32); + gint32 i2 = LOCAL_VAR (ip [3], gint32); + if (i2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - if (l1 == (-1) && l2 == G_MININT32) + if (i2 == (-1) && i1 == G_MININT32) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, /); + LOCAL_VAR (ip [1], gint32) = i1 / i2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_DIV_I8) { - gint64 l1 = sp [-1].data.l; - gint64 l2 = sp [-2].data.l; - if (l1 == 0) + gint64 l1 = LOCAL_VAR (ip [2], gint64); + gint64 l2 = LOCAL_VAR (ip [3], gint64); + if (l2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - if (l1 == (-1) && l2 == G_MININT64) + if (l2 == (-1) && l1 == G_MININT64) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, /); + LOCAL_VAR (ip [1], gint64) = l1 / l2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_DIV_R4) - BINOP(f_r4, /); + BINOP(float, /); MINT_IN_BREAK; MINT_IN_CASE(MINT_DIV_R8) - BINOP(f, /); + BINOP(double, /); MINT_IN_BREAK; - -#define BINOP_CAST(datamem, op, type) \ - --sp; \ - sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \ - ++ip; - MINT_IN_CASE(MINT_DIV_UN_I4) - if (sp [-1].data.i == 0) + MINT_IN_CASE(MINT_DIV_UN_I4) { + guint32 i2 = LOCAL_VAR (ip [3], guint32); + if (i2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(i, /, guint32); + LOCAL_VAR (ip [1], guint32) = LOCAL_VAR (ip [2], guint32) / i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_DIV_UN_I8) - if (sp [-1].data.l == 0) + } + MINT_IN_CASE(MINT_DIV_UN_I8) { + guint64 l2 = LOCAL_VAR (ip [3], guint64); + if (l2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(l, /, guint64); + LOCAL_VAR (ip [1], guint64) = LOCAL_VAR (ip [2], guint64) / l2; + ip += 4; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_REM_I4) { - int i1 = sp [-1].data.i; - int i2 = sp [-2].data.i; - if (i1 == 0) + gint32 i1 = LOCAL_VAR (ip [2], gint32); + gint32 i2 = LOCAL_VAR (ip [3], gint32); + if (i2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - if (i1 == (-1) && i2 == G_MININT32) + if (i2 == (-1) && i1 == G_MININT32) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, %); + LOCAL_VAR (ip [1], gint32) = i1 % i2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_REM_I8) { - gint64 l1 = sp [-1].data.l; - gint64 l2 = sp [-2].data.l; - if (l1 == 0) + gint64 l1 = LOCAL_VAR (ip [2], gint64); + gint64 l2 = LOCAL_VAR (ip [3], gint64); + if (l2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - if (l1 == (-1) && l2 == G_MININT64) + if (l2 == (-1) && l1 == G_MININT64) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, %); + LOCAL_VAR (ip [1], gint64) = l1 % l2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_REM_R4) - /* FIXME: what do we actually do here? */ - --sp; - sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4); - ++ip; + LOCAL_VAR (ip [1], float) = fmodf (LOCAL_VAR (ip [2], float), LOCAL_VAR (ip [3], float)); + ip += 4; MINT_IN_BREAK; MINT_IN_CASE(MINT_REM_R8) - /* FIXME: what do we actually do here? */ - --sp; - sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f); - ++ip; + LOCAL_VAR (ip [1], double) = fmod (LOCAL_VAR (ip [2], double), LOCAL_VAR (ip [3], double)); + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_UN_I4) - if (sp [-1].data.i == 0) + MINT_IN_CASE(MINT_REM_UN_I4) { + guint32 i2 = LOCAL_VAR (ip [3], guint32); + if (i2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(i, %, guint32); + LOCAL_VAR (ip [1], guint32) = LOCAL_VAR (ip [2], guint32) % i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_REM_UN_I8) - if (sp [-1].data.l == 0) + } + MINT_IN_CASE(MINT_REM_UN_I8) { + guint64 l2 = LOCAL_VAR (ip [3], guint64); + if (l2 == 0) THROW_EX (mono_get_exception_divide_by_zero (), ip); - BINOP_CAST(l, %, guint64); + LOCAL_VAR (ip [1], guint64) = LOCAL_VAR (ip [2], guint64) % l2; + ip += 4; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_AND_I4) - BINOP(i, &); + BINOP(gint32, &); MINT_IN_BREAK; MINT_IN_CASE(MINT_AND_I8) - BINOP(l, &); + BINOP(gint64, &); MINT_IN_BREAK; MINT_IN_CASE(MINT_OR_I4) - BINOP(i, |); + BINOP(gint32, |); MINT_IN_BREAK; MINT_IN_CASE(MINT_OR_I8) - BINOP(l, |); + BINOP(gint64, |); MINT_IN_BREAK; MINT_IN_CASE(MINT_XOR_I4) - BINOP(i, ^); + BINOP(gint32, ^); MINT_IN_BREAK; MINT_IN_CASE(MINT_XOR_I8) - BINOP(l, ^); + BINOP(gint64, ^); MINT_IN_BREAK; -#define SHIFTOP(datamem, op) \ - --sp; \ - sp [-1].data.datamem op ## = sp [0].data.i; \ - ++ip; +#define SHIFTOP(datatype, op) \ + LOCAL_VAR (ip [1], datatype) = LOCAL_VAR (ip [2], datatype) op LOCAL_VAR (ip [3], gint32); \ + ip += 4; MINT_IN_CASE(MINT_SHL_I4) - SHIFTOP(i, <<); + SHIFTOP(gint32, <<); MINT_IN_BREAK; MINT_IN_CASE(MINT_SHL_I8) - SHIFTOP(l, <<); + SHIFTOP(gint64, <<); MINT_IN_BREAK; MINT_IN_CASE(MINT_SHR_I4) - SHIFTOP(i, >>); + SHIFTOP(gint32, >>); MINT_IN_BREAK; MINT_IN_CASE(MINT_SHR_I8) - SHIFTOP(l, >>); + SHIFTOP(gint64, >>); MINT_IN_BREAK; MINT_IN_CASE(MINT_SHR_UN_I4) - --sp; - sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i; - ++ip; + SHIFTOP(guint32, >>); MINT_IN_BREAK; MINT_IN_CASE(MINT_SHR_UN_I8) - --sp; - sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i; - ++ip; + SHIFTOP(guint64, >>); MINT_IN_BREAK; MINT_IN_CASE(MINT_NEG_I4) - sp [-1].data.i = - sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = - LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_NEG_I8) - sp [-1].data.l = - sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint64) = - LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_NEG_R4) - sp [-1].data.f_r4 = - sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], float) = - LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_NEG_R8) - sp [-1].data.f = - sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], double) = - LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_NOT_I4) - sp [-1].data.i = ~ sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = ~ LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_NOT_I8) - sp [-1].data.l = ~ sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint64) = ~ LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I1_I4) - sp [-1].data.i = (gint8)sp [-1].data.i; - ++ip; + // FIXME read casted var directly and remove redundant conv opcodes + LOCAL_VAR (ip [1], gint32) = (gint8)LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I1_I8) - sp [-1].data.i = (gint8)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8)LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I1_R4) - sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) (gint32) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I1_R8) /* without gint32 cast, C compiler is allowed to use undefined @@ -4695,187 +4659,170 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs * > is discarded. The behavior is undefined if the truncated * > value cannot be represented in the destination type. * */ - sp [-1].data.i = (gint8) (gint32) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) (gint32) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U1_I4) - sp [-1].data.i = (guint8)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U1_I8) - sp [-1].data.i = (guint8)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U1_R4) - sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) (guint32) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U1_R8) - sp [-1].data.i = (guint8) (guint32) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) (guint32) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I2_I4) - sp [-1].data.i = (gint16)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I2_I8) - sp [-1].data.i = (gint16)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I2_R4) - sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) (gint32) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I2_R8) - sp [-1].data.i = (gint16) (gint32) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) (gint32) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U2_I4) - sp [-1].data.i = (guint16)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U2_I8) - sp [-1].data.i = (guint16)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U2_R4) - sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) (guint32) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U2_R8) - sp [-1].data.i = (guint16) (guint32) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) (guint32) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I4_R4) - sp [-1].data.i = (gint32) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I4_R8) - sp [-1].data.i = (gint32)sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U4_I8) MINT_IN_CASE(MINT_CONV_I4_I8) - sp [-1].data.i = (gint32)sp [-1].data.l; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I4_I8_SP) - sp [-2].data.i = (gint32)sp [-2].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32) LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U4_R4) #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4 - sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4); + LOCAL_VAR (ip [1], gint32) = mono_rconv_u4 (LOCAL_VAR (ip [2], float)); #else - sp [-1].data.i = (guint32) sp [-1].data.f_r4; + LOCAL_VAR (ip [1], gint32) = (guint32) LOCAL_VAR (ip [2], float); #endif - ++ip; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U4_R8) #ifdef MONO_ARCH_EMULATE_FCONV_TO_U4 - sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f); + LOCAL_VAR (ip [1], gint32) = mono_fconv_u4_2 (LOCAL_VAR (ip [2], double)); #else - sp [-1].data.i = (guint32) sp [-1].data.f; + LOCAL_VAR (ip [1], gint32) = (guint32) LOCAL_VAR (ip [2], double); #endif - ++ip; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I8_I4) - sp [-1].data.l = sp [-1].data.i; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_I8_I4_SP) - sp [-2].data.l = sp [-2].data.i; - ++ip; + LOCAL_VAR (ip [1], gint64) = LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I8_U4) - sp [-1].data.l = (guint32)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], gint64) = (guint32) LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I8_R4) - sp [-1].data.l = (gint64) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint64) = (gint64) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_I8_R8) - sp [-1].data.l = (gint64)sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint64) = (gint64) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R4_I4) - sp [-1].data.f_r4 = (float)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], float) = (float) LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R4_I8) - sp [-1].data.f_r4 = (float)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], float) = (float) LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R4_R8) - sp [-1].data.f_r4 = (float)sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], float) = (float) LOCAL_VAR (ip [2], double); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R8_I4) - sp [-1].data.f = (double)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], double) = (double) LOCAL_VAR (ip [2], gint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R8_I8) - sp [-1].data.f = (double)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], double) = (double) LOCAL_VAR (ip [2], gint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R8_R4) - sp [-1].data.f = (double) sp [-1].data.f_r4; - ++ip; - MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_R8_R4_SP) - sp [-2].data.f = (double) sp [-2].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], double) = (double) LOCAL_VAR (ip [2], float); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U8_R4) #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8 - sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4); + LOCAL_VAR (ip [1], gint64) = mono_rconv_u8 (LOCAL_VAR (ip [2], float)); #else - sp [-1].data.l = (guint64) sp [-1].data.f_r4; + LOCAL_VAR (ip [1], gint64) = (guint64) LOCAL_VAR (ip [2], float); #endif - ++ip; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_U8_R8) #ifdef MONO_ARCH_EMULATE_FCONV_TO_U8 - sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f); + LOCAL_VAR (ip [1], gint64) = mono_fconv_u8_2 (LOCAL_VAR (ip [2], double)); #else - sp [-1].data.l = (guint64)sp [-1].data.f; + LOCAL_VAR (ip [1], gint64) = (guint64) LOCAL_VAR (ip [2], double); #endif - ++ip; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CPOBJ) { - MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]]; + MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [3]]; g_assert (m_class_is_valuetype (c)); /* if this assertion fails, we need to add a write barrier */ g_assert (!MONO_TYPE_IS_REFERENCE (m_class_get_byval_arg (c))); - stackval_from_data (m_class_get_byval_arg (c), (stackval*)sp [-2].data.p, sp [-1].data.p, FALSE); - ip += 2; - sp -= 2; + stackval_from_data (m_class_get_byval_arg (c), (stackval*)LOCAL_VAR (ip [1], gpointer), LOCAL_VAR (ip [2], gpointer), FALSE); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CPOBJ_VT) { - MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]]; - mono_value_copy_internal (sp [-2].data.vt, sp [-1].data.vt, c); - ip += 2; - sp -= 2; + MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [3]]; + mono_value_copy_internal (LOCAL_VAR (ip [1], gpointer), LOCAL_VAR (ip [2], gpointer), c); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDOBJ_VT) { - int size = READ32(ip + 1); - sp--; - memcpy (sp, sp [0].data.p, size); - sp = STACK_ADD_BYTES (sp, size); - ip += 3; + guint16 size = ip [3]; + memcpy (locals + ip [1], LOCAL_VAR (ip [2], gpointer), size); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDSTR) - sp->data.p = frame->imethod->data_items [ip [1]]; - ++sp; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [2]]; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSTR_TOKEN) { MonoString *s = NULL; - guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [1]]; + guint32 strtoken = (guint32)(gsize)frame->imethod->data_items [ip [2]]; MonoMethod *method = frame->imethod->method; if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) { @@ -4885,53 +4832,48 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } else { g_assert_not_reached (); } - sp->data.p = s; - ++sp; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = s; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_NEWOBJ_ARRAY) { MonoClass *newobj_class; - guint32 token = ip [1]; - guint16 param_count = ip [2]; + guint32 token = ip [2]; + guint16 param_count = ip [3]; newobj_class = (MonoClass*) frame->imethod->data_items [token]; - sp -= param_count; - sp->data.o = ves_array_create (frame->imethod->domain, newobj_class, param_count, sp, error); + LOCAL_VAR (ip [1], MonoObject*) = ves_array_create (frame->imethod->domain, newobj_class, param_count, (stackval*)(locals + ip [1]), error); if (!is_ok (error)) THROW_EX (mono_error_convert_to_exception (error), ip); - - ++sp; - ip += 3; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_NEWOBJ_STRING) { - cmethod = (InterpMethod*)frame->imethod->data_items [ip [1]]; + cmethod = (InterpMethod*)frame->imethod->data_items [ip [2]]; + call_args_offset = ip [1]; + + int param_size = ip [3]; + if (param_size) + memmove (locals + call_args_offset + MINT_STACK_SLOT_SIZE, locals + call_args_offset, param_size); - int param_size = ip [2]; - if (param_size) { - sp = STACK_SUB_BYTES (sp, param_size); - memmove (sp + 1, sp, param_size); - } // `this` is implicit null. The created string will be returned // by the call, even though the call has void return (?!). - sp->data.p = NULL; - ip += 3; + LOCAL_VAR (call_args_offset, gpointer) = NULL; + ip += 4; goto call; } MINT_IN_CASE(MINT_NEWOBJ_FAST) { MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [3]]; INIT_VTABLE (vtable); - guint16 imethod_index = ip [1]; - guint16 param_size = ip [2]; + guint16 imethod_index = ip [2]; + guint16 param_size = ip [4]; + call_args_offset = ip [1]; const gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG; // Make room for two copies of o -- this parameter and return value. - if (param_size) { - sp = STACK_SUB_BYTES (sp, param_size); - memmove (sp + 2, sp, param_size); - } + if (param_size) + memmove (locals + call_args_offset + 2 * MINT_STACK_SLOT_SIZE, locals + call_args_offset, param_size); MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); if (G_UNLIKELY (!o)) { @@ -4939,55 +4881,52 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs THROW_EX (mono_error_convert_to_exception (error), ip); } - sp [0].data.o = o; - sp++; - sp [0].data.o = o; - ip += 5; + // This is return value + LOCAL_VAR (call_args_offset, MonoObject*) = o; + // Set `this` arg for ctor call + call_args_offset += MINT_STACK_SLOT_SIZE; + LOCAL_VAR (call_args_offset, MonoObject*) = o; + ip += 6; if (!is_inlined) { cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index]; goto call; } - sp = STACK_ADD_BYTES (sp, param_size + MINT_STACK_SLOT_SIZE); - MINT_IN_BREAK; } MINT_IN_CASE(MINT_NEWOBJ_VT_FAST) { - guint16 imethod_index = ip [1]; - guint16 param_size = ip [2]; + guint16 imethod_index = ip [2]; guint16 ret_size = ip [3]; + guint16 param_size = ip [4]; gboolean is_inlined = imethod_index == INLINED_METHOD_FLAG; + call_args_offset = ip [1]; + gpointer this_vt = locals + call_args_offset; - // Make room for extra parameter and result. - if (param_size) { - sp = STACK_SUB_BYTES (sp, param_size); - memmove (STACK_ADD_BYTES (sp, ret_size + MINT_STACK_SLOT_SIZE), sp, param_size); - } - // Allocate return value on stack - stackval *retvt = sp; - memset (retvt, 0, ret_size); - sp = STACK_ADD_BYTES (sp, ret_size); - sp [0].data.p = retvt; + if (param_size) + memmove (locals + call_args_offset + ret_size + MINT_STACK_SLOT_SIZE, locals + call_args_offset, param_size); - ip += 5; + // clear the valuetype + memset (this_vt, 0, ret_size); + call_args_offset += ret_size; + // pass the address of the valuetype + LOCAL_VAR (call_args_offset, gpointer) = this_vt; + + ip += 6; if (!is_inlined) { cmethod = (InterpMethod*)frame->imethod->data_items [imethod_index]; goto call; } - sp = STACK_ADD_BYTES (sp, param_size + MINT_STACK_SLOT_SIZE); MINT_IN_BREAK; } MINT_IN_CASE(MINT_NEWOBJ) { - guint32 const token = ip [1]; - guint16 param_size = ip [2]; + guint32 const token = ip [2]; + guint16 param_size = ip [3]; + call_args_offset = ip [1]; cmethod = (InterpMethod*)frame->imethod->data_items [token]; - // Make room for result and `this` - if (param_size) { - sp = STACK_SUB_BYTES (sp, param_size); - memmove (sp + 2, sp, param_size); - } + if (param_size) + memmove (locals + call_args_offset + 2 * MINT_STACK_SLOT_SIZE, locals + call_args_offset, param_size); MonoClass * const newobj_class = cmethod->method->klass; @@ -5007,8 +4946,9 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs } error_init_reuse (error); MonoObject* o = mono_object_new_checked (domain, newobj_class, error); - sp [0].data.o = o; // return value - sp [1].data.o = o; // first parameter + LOCAL_VAR (call_args_offset, MonoObject*) = o; // return value + call_args_offset += MINT_STACK_SLOT_SIZE; + LOCAL_VAR (call_args_offset, MonoObject*) = o; // first parameter mono_interp_error_cleanup (error); // FIXME: do not swallow the error EXCEPTION_CHECKPOINT; @@ -5020,112 +4960,92 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs mono_error_assert_ok (error); } #endif - ip += 3; - sp++; + ip += 4; goto call; } - MINT_IN_CASE(MINT_NEWOBJ_MAGIC) { - ip += 2; - - MINT_IN_BREAK; - } MINT_IN_CASE(MINT_INTRINS_SPAN_CTOR) { - sp -= 2; - gpointer ptr = sp [0].data.p; - int len = sp [1].data.i; + gpointer ptr = LOCAL_VAR (ip [2], gpointer); + int len = LOCAL_VAR (ip [3], gint32); if (len < 0) THROW_EX (mono_get_exception_argument_out_of_range ("length"), ip); - *(gpointer*)sp = ptr; - *(gint32*)((gpointer*)sp + 1) = len; -#if SIZEOF_VOID_P == 8 - sp = STACK_ADD_BYTES (sp, 12); -#else - sp = STACK_ADD_BYTES (sp, 8); -#endif - ip++; + gpointer span = locals + ip [1]; + *(gpointer*)span = ptr; + *(gint32*)((gpointer*)span + 1) = len; + ip += 4;; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_BYREFERENCE_GET_VALUE) { - sp [-1].data.p = *(gpointer*)sp [-1].data.p; - ++ip; + LOCAL_VAR (ip [1], gpointer) = *LOCAL_VAR (ip [2], gpointer*); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET) { - sp -= 2; - sp [0].data.p = (guint8*)sp [0].data.p + sp [1].data.nati; - sp ++; - ++ip; + LOCAL_VAR (ip [1], gpointer) = LOCAL_VAR (ip [2], guint8*) + LOCAL_VAR (ip [3], mono_u); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_CLEAR_WITH_REFERENCES) { - sp -= 2; - gpointer p = sp [0].data.p; - size_t size = sp [1].data.nati * sizeof (gpointer); + gpointer p = LOCAL_VAR (ip [1], gpointer); + size_t size = LOCAL_VAR (ip [2], mono_u) * sizeof (gpointer); mono_gc_bzero_aligned (p, size); - ++ip; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_MARVIN_BLOCK) { - sp -= 2; - interp_intrins_marvin_block ((guint32*)sp [0].data.p, (guint32*)sp [1].data.p); - ++ip; + interp_intrins_marvin_block (LOCAL_VAR (ip [1], guint32*), LOCAL_VAR (ip [2], guint32*)); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE) { - sp [-1].data.i = interp_intrins_ascii_chars_to_uppercase ((guint32)sp [-1].data.i); - ++ip; + LOCAL_VAR (ip [1], gint32) = interp_intrins_ascii_chars_to_uppercase (LOCAL_VAR (ip [2], guint32)); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp[-1].data.p = (guint8*)o + MONO_STRUCT_OFFSET (MonoArray, vector); - ++ip; + LOCAL_VAR (ip [1], gpointer) = (guint8*)o + MONO_STRUCT_OFFSET (MonoArray, vector); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII) { - sp--; - sp [-1].data.i = interp_intrins_ordinal_ignore_case_ascii ((guint32)sp [-1].data.i, (guint32)sp [0].data.i); - ++ip; + LOCAL_VAR (ip [1], gint32) = interp_intrins_ordinal_ignore_case_ascii (LOCAL_VAR (ip [2], guint32), LOCAL_VAR (ip [3], guint32)); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII) { - sp--; - sp [-1].data.i = interp_intrins_64ordinal_ignore_case_ascii ((guint64)sp [-1].data.l, (guint64)sp [0].data.l); - ++ip; + LOCAL_VAR (ip [1], gint32) = interp_intrins_64ordinal_ignore_case_ascii (LOCAL_VAR (ip [2], guint64), LOCAL_VAR (ip [3], guint64)); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_U32_TO_DECSTR) { - MonoArray **cache_addr = (MonoArray**)frame->imethod->data_items [ip [1]]; - MonoVTable *string_vtable = (MonoVTable*)frame->imethod->data_items [ip [2]]; - sp [-1].data.o = (MonoObject*)interp_intrins_u32_to_decstr ((guint32)sp [-1].data.i, *cache_addr, string_vtable); - ip += 3; + MonoArray **cache_addr = (MonoArray**)frame->imethod->data_items [ip [3]]; + MonoVTable *string_vtable = (MonoVTable*)frame->imethod->data_items [ip [4]]; + LOCAL_VAR (ip [1], MonoObject*) = (MonoObject*)interp_intrins_u32_to_decstr (LOCAL_VAR (ip [2], guint32), *cache_addr, string_vtable); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_WIDEN_ASCII_TO_UTF16) { - sp -= 2; - sp [-1].data.nati = interp_intrins_widen_ascii_to_utf16 ((guint8*)sp [-1].data.p, (mono_unichar2*)sp [0].data.p, sp [1].data.nati); - ip++; + LOCAL_VAR (ip [1], mono_u) = interp_intrins_widen_ascii_to_utf16 (LOCAL_VAR (ip [2], guint8*), LOCAL_VAR (ip [3], mono_unichar2*), LOCAL_VAR (ip [4], mono_u)); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_UNSAFE_BYTE_OFFSET) { - sp -= 2; - sp [0].data.nati = (guint8*)sp [1].data.p - (guint8*)sp [0].data.p; - sp ++; - ++ip; + LOCAL_VAR (ip [1], mono_u) = LOCAL_VAR (ip [3], guint8*) - LOCAL_VAR (ip [2], guint8*); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE) { - MonoObject *obj = sp [-1].data.o; - sp [-1].data.i = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0; - ++ip; + MonoObject *obj = LOCAL_VAR (ip [2], MonoObject*); + LOCAL_VAR (ip [1], gint32) = (obj->vtable->flags & MONO_VT_FLAG_ARRAY_OR_STRING) != 0; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CASTCLASS_INTERFACE) MINT_IN_CASE(MINT_ISINST_INTERFACE) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); if (o) { - MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]]; + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; gboolean isinst; if (MONO_VTABLE_IMPLEMENTS_INTERFACE (o->vtable, m_class_get_interface_id (c))) { isinst = TRUE; @@ -5139,75 +5059,88 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs if (!isinst) { gboolean const isinst_instr = *ip == MINT_ISINST_INTERFACE; if (isinst_instr) - sp [-1].data.p = NULL; + LOCAL_VAR (ip [1], MonoObject*) = NULL; else THROW_EX (mono_get_exception_invalid_cast (), ip); + } else { + LOCAL_VAR (ip [1], MonoObject*) = o; } + } else { + LOCAL_VAR (ip [1], MonoObject*) = NULL; } - ip += 2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CASTCLASS_COMMON) MINT_IN_CASE(MINT_ISINST_COMMON) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); if (o) { - MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]]; + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; gboolean isinst = mono_class_has_parent_fast (o->vtable->klass, c); if (!isinst) { gboolean const isinst_instr = *ip == MINT_ISINST_COMMON; if (isinst_instr) - sp [-1].data.p = NULL; + LOCAL_VAR (ip [1], MonoObject*) = NULL; else THROW_EX (mono_get_exception_invalid_cast (), ip); + } else { + LOCAL_VAR (ip [1], MonoObject*) = o; } + } else { + LOCAL_VAR (ip [1], MonoObject*) = NULL; } - ip += 2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CASTCLASS) MINT_IN_CASE(MINT_ISINST) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); if (o) { - MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]]; + MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [3]]; if (!mono_interp_isinst (o, c)) { // FIXME: do not swallow the error gboolean const isinst_instr = *ip == MINT_ISINST; if (isinst_instr) - sp [-1].data.p = NULL; + LOCAL_VAR (ip [1], MonoObject*) = NULL; else THROW_EX (mono_get_exception_invalid_cast (), ip); + } else { + LOCAL_VAR (ip [1], MonoObject*) = o; } + } else { + LOCAL_VAR (ip [1], MonoObject*) = NULL; } - ip += 2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_R_UN_I4) - sp [-1].data.f = (double)(guint32)sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], double) = (double)LOCAL_VAR (ip [2], guint32); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CONV_R_UN_I8) - sp [-1].data.f = (double)(guint64)sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], double) = (double)LOCAL_VAR (ip [2], guint64); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_UNBOX) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - MonoClass* const c = (MonoClass*)frame->imethod->data_items[ip [1]]; + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; if (!(m_class_get_rank (o->vtable->klass) == 0 && m_class_get_element_class (o->vtable->klass) == m_class_get_element_class (c))) THROW_EX (mono_get_exception_invalid_cast (), ip); - sp [-1].data.p = mono_object_unbox_internal (o); - ip += 2; + LOCAL_VAR (ip [1], gpointer) = mono_object_unbox_internal (o); + ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_THROW) - --sp; - if (!sp->data.p) - sp->data.p = mono_get_exception_null_reference (); + MINT_IN_CASE(MINT_THROW) { + MonoException *ex = LOCAL_VAR (ip [1], MonoException*); + if (!ex) + ex = mono_get_exception_null_reference (); - THROW_EX ((MonoException *)sp->data.p, ip); + THROW_EX (ex, ip); MINT_IN_BREAK; + } MINT_IN_CASE(MINT_CHECKPOINT) /* Do synchronous checking of abort requests */ EXCEPTION_CHECKPOINT; @@ -5221,554 +5154,462 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLDA_UNSAFE) { - sp[-1].data.p = (char*)sp [-1].data.o + ip [1]; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = (char*)LOCAL_VAR (ip [2], gpointer) + ip [3]; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDFLDA) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp[-1].data.p = (char *)o + ip [1]; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = (char *)o + ip [3]; + ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CKNULL_N) { - /* Same as CKNULL, but further down the stack */ - int offset = ip [1]; - // This doesn't follow the current stack based design, but we plan to switch to explicit offsets. - MonoObject *o = *(MonoObject**)(locals + frame->imethod->total_locals_size + offset); + MINT_IN_CASE(MINT_CKNULL) { + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - ip += 2; + LOCAL_VAR (ip [1], MonoObject*) = o; + ip += 3; MINT_IN_BREAK; } -#define LDFLD_VT_UNALIGNED(datamem, fieldtype, unaligned) do { \ - sp = STACK_SUB_BYTES (sp, ip [2]); \ +// FIXME squash to load directly field type, LDFLD_VT is just a LDLOC +#define LDFLD_VT_UNALIGNED(datatype, fieldtype, unaligned) do { \ if (unaligned) \ - memcpy (&sp [0].data.datamem, (char *)sp + ip [1], sizeof (fieldtype)); \ + memcpy (locals + ip [1], (char *)locals + ip [2] + ip [3], sizeof (fieldtype)); \ else \ - sp [0].data.datamem = * (fieldtype *)((char *)sp + ip [1]); \ - sp++; \ - ip += 3; \ + LOCAL_VAR (ip [1], datatype) = LOCAL_VAR (ip [2] + ip [3], fieldtype); \ + ip += 4; \ } while (0) -#define LDFLD_VT(datamem, fieldtype) LDFLD_VT_UNALIGNED(datamem, fieldtype, FALSE) +#define LDFLD_VT(datatype, fieldtype) LDFLD_VT_UNALIGNED(datatype, fieldtype, FALSE) - MINT_IN_CASE(MINT_LDFLD_VT_I1) LDFLD_VT(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_U1) LDFLD_VT(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I2) LDFLD_VT(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_U2) LDFLD_VT(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I4) LDFLD_VT(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I8) LDFLD_VT(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_R4) LDFLD_VT(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_R8) LDFLD_VT(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_O) LDFLD_VT(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_I8_UNALIGNED) LDFLD_VT_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_VT_R8_UNALIGNED) LDFLD_VT_UNALIGNED(f, double, TRUE); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_I1) LDFLD_VT(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_U1) LDFLD_VT(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_I2) LDFLD_VT(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_U2) LDFLD_VT(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_I4) LDFLD_VT(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_I8) LDFLD_VT(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_R4) LDFLD_VT(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_R8) LDFLD_VT(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_O) LDFLD_VT(gpointer, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_I8_UNALIGNED) LDFLD_VT_UNALIGNED(gint64, gint64, TRUE); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_VT_R8_UNALIGNED) LDFLD_VT_UNALIGNED(double, double, TRUE); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLD_VT_VT) { - sp = STACK_SUB_BYTES (sp, ip [2]); \ - memmove (sp, (char *)sp + ip [1], ip [3]); - sp = STACK_ADD_BYTES (sp, ip [3]); - ip += 4; + memmove (locals + ip [1], locals + ip [2] + ip [3], ip [4]); + ip += 5; MINT_IN_BREAK; } -#define LDFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \ - MonoObject* const o = sp [-1].data.o; \ +#define LDFLD_UNALIGNED(datatype, fieldtype, unaligned) do { \ + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); \ NULL_CHECK (o); \ if (unaligned) \ - memcpy (&sp[-1].data.datamem, (char *)o + ip [1], sizeof (fieldtype)); \ + memcpy (locals + ip [1], (char *)o + ip [3], sizeof (fieldtype)); \ else \ - sp[-1].data.datamem = * (fieldtype *)((char *)o + ip [1]) ; \ - ip += 2; \ + LOCAL_VAR (ip [1], datatype) = * (fieldtype *)((char *)o + ip [3]) ; \ + ip += 4; \ } while (0) #define LDFLD(datamem, fieldtype) LDFLD_UNALIGNED(datamem, fieldtype, FALSE) - MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_O) LDFLD(gpointer, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_I8_UNALIGNED) LDFLD_UNALIGNED(gint64, gint64, TRUE); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDFLD_R8_UNALIGNED) LDFLD_UNALIGNED(double, double, TRUE); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLD_VT) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - - int size = READ32(ip + 2); - sp--; - memcpy (sp, (char *)o + ip [1], size); - sp = STACK_ADD_BYTES (sp, size); - ip += 4; + memcpy (locals + ip [1], (char *)o + ip [3], ip [4]); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDRMFLD) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - mono_interp_load_remote_field (frame->imethod, o, ip, sp); - ip += 2; + mono_interp_load_remote_field (frame->imethod, o, ip, locals + ip [1]); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDRMFLD_VT) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp = mono_interp_load_remote_field_vt (frame->imethod, o, ip, sp); - ip += 2; + mono_interp_load_remote_field_vt (frame->imethod, o, ip, locals + ip [1]); + ip += 4; MINT_IN_BREAK; } -#define LDLOCFLD(datamem, fieldtype) do { \ - MonoObject *o = *(MonoObject**)(locals + ip [1]); \ - NULL_CHECK (o); \ - sp [0].data.datamem = * (fieldtype *)((char *)o + ip [2]) ; \ - sp++; \ - ip += 3; \ -} while (0) - MINT_IN_CASE(MINT_LDLOCFLD_I1) LDLOCFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_U1) LDLOCFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_I2) LDLOCFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_U2) LDLOCFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_I4) LDLOCFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_I8) LDLOCFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_R4) LDLOCFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_R8) LDLOCFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOCFLD_O) LDLOCFLD(p, gpointer); MINT_IN_BREAK; - -#define STFLD_UNALIGNED(datamem, fieldtype, unaligned) do { \ - MonoObject* const o = sp [-2].data.o; \ +#define STFLD_UNALIGNED(datatype, fieldtype, unaligned) do { \ + MonoObject *o = LOCAL_VAR (ip [1], MonoObject*); \ NULL_CHECK (o); \ - sp -= 2; \ if (unaligned) \ - memcpy ((char *)o + ip [1], &sp[1].data.datamem, sizeof (fieldtype)); \ + memcpy ((char *)o + ip [3], locals + ip [2], sizeof (fieldtype)); \ else \ - * (fieldtype *)((char *)o + ip [1]) = sp[1].data.datamem; \ - ip += 2; \ + * (fieldtype *)((char *)o + ip [3]) = LOCAL_VAR (ip [2], datatype); \ + ip += 4; \ } while (0) #define STFLD(datamem, fieldtype) STFLD_UNALIGNED(datamem, fieldtype, FALSE) - MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I1) STFLD(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_U1) STFLD(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I2) STFLD(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_U2) STFLD(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I4) STFLD(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I8) STFLD(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_R4) STFLD(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_R8) STFLD(double, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_STFLD_O) { - MonoObject* const o = sp [-2].data.o; + MonoObject *o = LOCAL_VAR (ip [1], MonoObject*); NULL_CHECK (o); - sp -= 2; - mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [1], sp [1].data.o); - ip += 2; + mono_gc_wbarrier_set_field_internal (o, (char*)o + ip [3], LOCAL_VAR (ip [2], MonoObject*)); + ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(l, gint64, TRUE); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(f, double, TRUE); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_I8_UNALIGNED) STFLD_UNALIGNED(gint64, gint64, TRUE); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STFLD_R8_UNALIGNED) STFLD_UNALIGNED(double, double, TRUE); MINT_IN_BREAK; MINT_IN_CASE(MINT_STFLD_VT_NOREF) { - guint16 offset = ip [1]; - guint16 vtsize = ip [2]; - - sp = STACK_SUB_BYTES (sp, MINT_STACK_SLOT_SIZE + vtsize); - MonoObject *o = sp [0].data.o; + MonoObject *o = LOCAL_VAR (ip [1], MonoObject*); NULL_CHECK (o); - - memcpy ((char *) o + offset, sp + 1, vtsize); - - ip += 3; + memcpy ((char*)o + ip [3], locals + ip [2], ip [4]); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STFLD_VT) { - MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [2]]; - int vtsize = mono_class_value_size (klass, NULL); - - sp = STACK_SUB_BYTES (sp, MINT_STACK_SLOT_SIZE + vtsize); - MonoObject *o = sp [0].data.o; + MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [4]]; + MonoObject *o = LOCAL_VAR (ip [1], MonoObject*); NULL_CHECK (o); - - guint16 offset = ip [1]; - mono_value_copy_internal ((char *) o + offset, sp + 1, klass); - - ip += 3; + mono_value_copy_internal ((char*)o + ip [3], locals + ip [2], klass); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STRMFLD) { MonoClassField *field; - MonoObject* const o = sp [-2].data.o; + MonoObject *o = LOCAL_VAR (ip [1], MonoObject*); NULL_CHECK (o); - field = (MonoClassField*)frame->imethod->data_items[ip [1]]; - ip += 2; - + field = (MonoClassField*)frame->imethod->data_items [ip [3]]; #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_store_remote_field_checked (o, klass, field, locals + ip [2], error); mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ } else #endif - stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE); + stackval_to_data (field->type, (stackval*)(locals + ip [2]), (char*)o + field->offset, FALSE); - sp -= 2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STRMFLD_VT) { - MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]]; + MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [3]]; MonoClass *klass = mono_class_from_mono_type_internal (field->type); - int vtsize = mono_class_value_size (klass, NULL); - sp = STACK_SUB_BYTES (sp, vtsize + MINT_STACK_SLOT_SIZE); - MonoObject *o = sp [0].data.o; + MonoObject *o = LOCAL_VAR (ip [1], MonoObject*); NULL_CHECK (o); #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, error); + mono_store_remote_field_checked (o, klass, field, locals + ip [2], error); mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ } else #endif - mono_value_copy_internal ((char *) o + field->offset, sp + 1, klass); + mono_value_copy_internal ((char *) o + field->offset, locals + ip [2], klass); - ip += 2; - MINT_IN_BREAK; - } - -#define STLOCFLD(datamem, fieldtype) do { \ - MonoObject *o = *(MonoObject**)(locals + ip [1]); \ - NULL_CHECK (o); \ - sp--; \ - * (fieldtype *)((char *)o + ip [2]) = sp [0].data.datamem; \ - ip += 3; \ -} while (0) - MINT_IN_CASE(MINT_STLOCFLD_I1) STLOCFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_U1) STLOCFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_I2) STLOCFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_U2) STLOCFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_I4) STLOCFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_I8) STLOCFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_R4) STLOCFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_R8) STLOCFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOCFLD_O) { - MonoObject *o = *(MonoObject**)(locals + ip [1]); - NULL_CHECK (o); - sp--; - mono_gc_wbarrier_set_field_internal (o, (char *) o + ip [2], sp [0].data.o); - ip += 3; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDSFLDA) { - MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; + MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; INIT_VTABLE (vtable); - sp->data.p = frame->imethod->data_items [ip [2]]; - ip += 3; - ++sp; + LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [3]]; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDSSFLDA) { - guint32 offset = READ32(ip + 1); - sp->data.p = mono_get_special_static_data (offset); - ip += 3; - ++sp; + guint32 offset = READ32(ip + 2); + LOCAL_VAR (ip [1], gpointer) = mono_get_special_static_data (offset); + ip += 4; MINT_IN_BREAK; } /* We init class here to preserve cctor order */ -#define LDSFLD(datamem, fieldtype) { \ - MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \ +#define LDSFLD(datatype, fieldtype) { \ + MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; \ INIT_VTABLE (vtable); \ - sp[0].data.datamem = * (fieldtype *)(frame->imethod->data_items [ip [2]]) ; \ - ip += 3; \ - sp++; \ + LOCAL_VAR (ip [1], datatype) = * (fieldtype *)(frame->imethod->data_items [ip [3]]) ; \ + ip += 4; \ } - MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_I1) LDSFLD(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_U1) LDSFLD(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_I2) LDSFLD(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_U2) LDSFLD(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_I4) LDSFLD(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_I8) LDSFLD(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_R4) LDSFLD(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_R8) LDSFLD(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDSFLD_O) LDSFLD(gpointer, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSFLD_VT) { - MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; + MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; INIT_VTABLE (vtable); - gpointer addr = frame->imethod->data_items [ip [2]]; - int const i32 = READ32 (ip + 3); + gpointer addr = frame->imethod->data_items [ip [3]]; + guint16 size = ip [4]; - memcpy (sp, addr, i32); - sp = STACK_ADD_BYTES (sp, i32); + memcpy (locals + ip [1], addr, size); ip += 5; MINT_IN_BREAK; } -#define LDTSFLD(datamem, fieldtype) { \ +#define LDTSFLD(datatype, fieldtype) { \ MonoInternalThread *thread = mono_thread_internal_current (); \ - guint32 offset = READ32 (ip + 1); \ + guint32 offset = READ32 (ip + 2); \ gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ - sp[0].data.datamem = *(fieldtype*)addr; \ - ip += 3; \ - ++sp; \ - } - MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(p, gpointer); MINT_IN_BREAK; + LOCAL_VAR (ip [1], datatype) = *(fieldtype*)addr; \ + ip += 4; \ + } + MINT_IN_CASE(MINT_LDTSFLD_I1) LDTSFLD(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_U1) LDTSFLD(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_I2) LDTSFLD(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_U2) LDTSFLD(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_I4) LDTSFLD(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_I8) LDTSFLD(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_R4) LDTSFLD(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_R8) LDTSFLD(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDTSFLD_O) LDTSFLD(gpointer, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDSSFLD) { - guint32 offset = READ32(ip + 2); + guint32 offset = READ32(ip + 3); gpointer addr = mono_get_special_static_data (offset); - MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]]; - stackval_from_data (field->type, sp, addr, FALSE); - ip += 4; - ++sp; + MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [2]]; + stackval_from_data (field->type, (stackval*)(locals + ip [1]), addr, FALSE); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDSSFLD_VT) { - guint32 offset = READ32(ip + 1); + guint32 offset = READ32(ip + 2); gpointer addr = mono_get_special_static_data (offset); - - int size = READ32 (ip + 3); - memcpy (sp, addr, size); - sp = STACK_ADD_BYTES (sp, size); + memcpy (locals + ip [1], addr, ip [4]); ip += 5; MINT_IN_BREAK; } -#define STSFLD(datamem, fieldtype) { \ - MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; \ +#define STSFLD(datatype, fieldtype) { \ + MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; \ INIT_VTABLE (vtable); \ - sp --; \ - * (fieldtype *)(frame->imethod->data_items [ip [2]]) = sp[0].data.datamem; \ - ip += 3; \ + * (fieldtype *)(frame->imethod->data_items [ip [3]]) = LOCAL_VAR (ip [1], datatype); \ + ip += 4; \ } - MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STSFLD_O) STSFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_I1) STSFLD(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_U1) STSFLD(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_I2) STSFLD(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_U2) STSFLD(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_I4) STSFLD(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_I8) STSFLD(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_R4) STSFLD(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_R8) STSFLD(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STSFLD_O) STSFLD(gpointer, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSFLD_VT) { - MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [1]]; + MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; INIT_VTABLE (vtable); - int const i32 = READ32 (ip + 3); - gpointer addr = frame->imethod->data_items [ip [2]]; - - sp = STACK_SUB_BYTES (sp, i32); - memcpy (addr, sp, i32); - + gpointer addr = frame->imethod->data_items [ip [3]]; + memcpy (addr, locals + ip [1], ip [4]); ip += 5; MINT_IN_BREAK; } -#define STTSFLD(datamem, fieldtype) { \ +#define STTSFLD(datatype, fieldtype) { \ MonoInternalThread *thread = mono_thread_internal_current (); \ - guint32 offset = READ32 (ip + 1); \ + guint32 offset = READ32 (ip + 2); \ gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ - sp--; \ - *(fieldtype*)addr = sp[0].data.datamem; \ - ip += 3; \ + *(fieldtype*)addr = LOCAL_VAR (ip [1], datatype); \ + ip += 4; \ } - MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I1) STTSFLD(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_U1) STTSFLD(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I2) STTSFLD(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_U2) STTSFLD(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I4) STTSFLD(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_I8) STTSFLD(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_R4) STTSFLD(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_R8) STTSFLD(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STTSFLD_O) STTSFLD(gpointer, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_STSSFLD) { - guint32 offset = READ32(ip + 2); + guint32 offset = READ32(ip + 3); gpointer addr = mono_get_special_static_data (offset); - MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [1]]; - --sp; - stackval_to_data (field->type, sp, addr, FALSE); - ip += 4; + MonoClassField *field = (MonoClassField*)frame->imethod->data_items [ip [2]]; + stackval_to_data (field->type, (stackval*)(locals + ip [1]), addr, FALSE); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STSSFLD_VT) { - guint32 offset = READ32(ip + 1); + guint32 offset = READ32(ip + 2); gpointer addr = mono_get_special_static_data (offset); - int size = READ32 (ip + 3); - - sp = STACK_SUB_BYTES (sp, size); - memcpy (addr, sp, size); - + memcpy (addr, locals + ip [1], ip [4]); ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STOBJ_VT) { - MonoClass *c = (MonoClass*)frame->imethod->data_items[ip [1]]; - int size = mono_class_value_size (c, NULL); - - sp = STACK_SUB_BYTES (sp, MINT_STACK_SLOT_SIZE + size); - mono_value_copy_internal (sp [0].data.p, sp + 1, c); - - ip += 2; + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; + mono_value_copy_internal (LOCAL_VAR (ip [1], gpointer), locals + ip [2], c); + ip += 4; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT32) + MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || val > G_MAXINT32) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint32)sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32)val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U8_I4) - if (sp [-1].data.i < 0) + } + MINT_IN_CASE(MINT_CONV_OVF_U8_I4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = sp [-1].data.i; - ++ip; + LOCAL_VAR (ip [1], guint64) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U8_I8) - if (sp [-1].data.l < 0) + } + MINT_IN_CASE(MINT_CONV_OVF_U8_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < 0) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], guint64) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I8_U8) - if ((guint64) sp [-1].data.l > G_MAXINT64) + } + MINT_IN_CASE(MINT_CONV_OVF_I8_U8) { + guint64 val = LOCAL_VAR (ip [2], guint64); + if (val > G_MAXINT64) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint64) = val; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_CONV_OVF_U8_R4) { - guint64 res = (guint64)sp [-1].data.f_r4; - if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) + float val = LOCAL_VAR (ip [2], float); + if (mono_isnan (val) || mono_trunc (val) != (guint64)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = res; - ++ip; + LOCAL_VAR (ip [1], guint64) = (guint64)val; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_U8_R8) { - guint64 res = (guint64)sp [-1].data.f; - if (mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res) + double val = LOCAL_VAR (ip [2], double); + if (mono_isnan (val) || mono_trunc (val) != (guint64)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = res; - ++ip; + LOCAL_VAR (ip [1], guint64) = (guint64)val; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8) { - gint64 res = (gint64)sp [-1].data.f; - if (res < 0 || mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res) + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || mono_isnan (val) || mono_trunc (val) != (gint64)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = res; - ++ip; + LOCAL_VAR (ip [1], gint64) = (gint64)val; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R4) { - gint64 res = (gint64)sp [-1].data.f_r4; - if (res < 0 || mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) + float val = LOCAL_VAR (ip [2], float); + if (val < 0 || mono_isnan (val) || mono_trunc (val) != (gint64)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = res; - ++ip; + LOCAL_VAR (ip [1], gint64) = (gint64)val; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_R4) { - gint64 res = (gint64)sp [-1].data.f_r4; - if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) + float val = LOCAL_VAR (ip [2], float); + if (mono_isnan (val) || mono_trunc (val) != (gint64)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = res; - ++ip; + LOCAL_VAR (ip [1], gint64) = (gint64)val; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_CONV_OVF_I8_R8) { - gint64 res = (gint64)sp [-1].data.f; - if (mono_isnan (sp [-1].data.f) || mono_trunc (sp [-1].data.f) != res) + double val = LOCAL_VAR (ip [2], double); + if (mono_isnan (val) || mono_trunc (val) != (gint64)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.l = res; - ++ip; + LOCAL_VAR (ip [1], gint64) = (gint64)val; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_BOX) { - MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [1]]; + MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; MonoObject *o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (vtable->klass)); MONO_HANDLE_ASSIGN_RAW (tmp_handle, o); - stackval_to_data (m_class_get_byval_arg (vtable->klass), &sp [-1], mono_object_get_data (o), FALSE); + stackval_to_data (m_class_get_byval_arg (vtable->klass), (stackval*)(locals + ip [2]), mono_object_get_data (o), FALSE); MONO_HANDLE_ASSIGN_RAW (tmp_handle, NULL); - sp [-1].data.o = o; - ip += 2; + LOCAL_VAR (ip [1], MonoObject*) = o; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_BOX_VT) { - MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [1]]; + MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; MonoClass *c = vtable->klass; - int size = mono_class_value_size (c, NULL); - MonoObject* o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (c)); MONO_HANDLE_ASSIGN_RAW (tmp_handle, o); - - sp = STACK_SUB_BYTES (sp, size); - mono_value_copy_internal (mono_object_get_data (o), sp, c); + mono_value_copy_internal (mono_object_get_data (o), locals + ip [2], c); MONO_HANDLE_ASSIGN_RAW (tmp_handle, NULL); - sp [0].data.o = o; - sp++; - - ip += 2; + LOCAL_VAR (ip [1], MonoObject*) = o; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_BOX_PTR) { - MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [1]]; + MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; MonoClass *c = vtable->klass; - // This doesn't follow the current stack based design, but we plan to switch to explicit offsets. - stackval *sp_ptr = (stackval*)(locals + frame->imethod->total_locals_size + ip [2]); MonoObject* o = mono_gc_alloc_obj (vtable, m_class_get_instance_size (c)); MONO_HANDLE_ASSIGN_RAW (tmp_handle, o); - mono_value_copy_internal (mono_object_get_data (o), sp_ptr->data.p, c); + mono_value_copy_internal (mono_object_get_data (o), LOCAL_VAR (ip [2], gpointer), c); MONO_HANDLE_ASSIGN_RAW (tmp_handle, NULL); - sp_ptr->data.o = o; - ip += 3; + LOCAL_VAR (ip [1], MonoObject*) = o; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_BOX_NULLABLE_PTR) { - MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [1]]; - // This doesn't follow the current stack based design, but we plan to switch to explicit offsets. - stackval *sp_ptr = (stackval*)(locals + frame->imethod->total_locals_size + ip [2]); + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; - sp_ptr->data.o = mono_nullable_box (sp_ptr->data.p, c, error); + LOCAL_VAR (ip [1], MonoObject*) = mono_nullable_box (LOCAL_VAR (ip [2], gpointer), c, error); mono_interp_error_cleanup (error); /* FIXME: don't swallow the error */ - ip += 3; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_NEWARR) { - MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items[ip [1]]; - sp [-1].data.o = (MonoObject*) mono_array_new_specific_checked (vtable, sp [-1].data.i, error); + MonoVTable *vtable = (MonoVTable*)frame->imethod->data_items [ip [3]]; + LOCAL_VAR (ip [1], MonoObject*) = (MonoObject*) mono_array_new_specific_checked (vtable, LOCAL_VAR (ip [2], gint32), error); if (!is_ok (error)) { THROW_EX (mono_error_convert_to_exception (error), ip); } - ip += 2; + ip += 4; /*if (profiling_classes) { guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass)); count++; @@ -5778,109 +5619,103 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDLEN) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp [-1].data.nati = mono_array_length_internal ((MonoArray *)o); - ++ip; + LOCAL_VAR (ip [1], mono_u) = mono_array_length_internal ((MonoArray *)o); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDLEN_SPAN) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - gsize offset_length = (gsize)(gint16)ip [1]; - sp [-1].data.nati = *(gint32 *) ((guint8 *) o + offset_length); - ip += 2; + // FIXME What's the point of this opcode ? It's just a LDFLD + gsize offset_length = (gsize)(gint16)ip [3]; + LOCAL_VAR (ip [1], mono_u) = *(gint32 *) ((guint8 *) o + offset_length); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_GETCHR) { - MonoString *s; - s = (MonoString*)sp [-2].data.p; + MonoString *s = LOCAL_VAR (ip [2], MonoString*); NULL_CHECK (s); - int const i32 = sp [-1].data.i; + int i32 = LOCAL_VAR (ip [3], int); if (i32 < 0 || i32 >= mono_string_length_internal (s)) THROW_EX (mono_get_exception_index_out_of_range (), ip); - --sp; - sp [-1].data.i = mono_string_chars_internal (s)[i32]; - ++ip; + LOCAL_VAR (ip [1], gint32) = mono_string_chars_internal (s)[i32]; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_GETITEM_SPAN) { - guint8 * const span = (guint8 *) sp [-2].data.p; - const int index = sp [-1].data.i; - sp--; - + guint8 *span = LOCAL_VAR (ip [2], guint8*); + int index = LOCAL_VAR (ip [3], int); NULL_CHECK (span); - const gsize offset_length = (gsize)(gint16)ip [2]; + gsize offset_length = (gsize)(gint16)ip [5]; const gint32 length = *(gint32 *) (span + offset_length); if (index < 0 || index >= length) THROW_EX (mono_get_exception_index_out_of_range (), ip); - const gsize element_size = (gsize)(gint16)ip [1]; - const gsize offset_pointer = (gsize)(gint16)ip [3]; + gsize element_size = (gsize)(gint16)ip [4]; + gsize offset_pointer = (gsize)(gint16)ip [6]; const gpointer pointer = *(gpointer *)(span + offset_pointer); - sp [-1].data.p = (guint8 *) pointer + index * element_size; + LOCAL_VAR (ip [1], gpointer) = (guint8 *) pointer + index * element_size; - ip += 4; + ip += 7; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STRLEN) { - ++ip; - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp [-1].data.i = mono_string_length_internal ((MonoString*) o); + LOCAL_VAR (ip [1], gint32) = mono_string_length_internal ((MonoString*) o); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ARRAY_RANK) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp [-1].data.i = m_class_get_rank (mono_object_class (o)); - ip++; + LOCAL_VAR (ip [1], gint32) = m_class_get_rank (mono_object_class (o)); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ARRAY_ELEMENT_SIZE) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp [-1].data.i = mono_array_element_size (mono_object_class (o)); - ip++; + LOCAL_VAR (ip [1], gint32) = mono_array_element_size (mono_object_class (o)); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE) { - MonoObject* const o = sp [-1].data.o; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); NULL_CHECK (o); - sp [-1].data.i = m_class_is_primitive (m_class_get_element_class (mono_object_class (o))); - ip++; + LOCAL_VAR (ip [1], gint32) = m_class_is_primitive (m_class_get_element_class (mono_object_class (o))); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDELEMA1) { /* No bounds, one direction */ - MonoArray *ao = (MonoArray*)sp [-2].data.o; + MonoArray *ao = LOCAL_VAR (ip [2], MonoArray*); NULL_CHECK (ao); - gint32 const index = sp [-1].data.i; + gint32 index = LOCAL_VAR (ip [3], gint32); if (index >= ao->max_length) THROW_EX (mono_get_exception_index_out_of_range (), ip); - gint32 const size = READ32 (ip + 1); - sp [-2].data.p = mono_array_addr_with_size_fast (ao, size, index); - ip += 3; - sp --; - + guint16 size = ip [4]; + LOCAL_VAR (ip [1], gpointer) = mono_array_addr_with_size_fast (ao, size, index); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDELEMA) { - guint16 rank = ip [1]; - gint32 const esize = READ32 (ip + 2); - ip += 4; - sp -= rank; + guint16 rank = ip [2]; + guint16 esize = ip [3]; + stackval *sp = (stackval*)(locals + ip [1]); - MonoArray* const ao = (MonoArray*) sp [-1].data.o; + MonoArray *ao = (MonoArray*) sp [0].data.o; NULL_CHECK (ao); g_assert (ao->bounds); guint32 pos = 0; for (int i = 0; i < rank; i++) { - gint32 idx = sp [i].data.i; + gint32 idx = sp [i + 1].data.i; gint32 lower = ao->bounds [i].lower_bound; guint32 len = ao->bounds [i].length; if (idx < lower || (guint32)(idx - lower) >= len) @@ -5888,420 +5723,527 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs pos = (pos * len) + (guint32)(idx - lower); } - sp [-1].data.p = mono_array_addr_with_size_fast (ao, esize, pos); + sp [0].data.p = mono_array_addr_with_size_fast (ao, esize, pos); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDELEMA_TC) { - guint16 rank = ip [1]; - ip += 3; - sp -= rank; + stackval *sp = (stackval*)(locals + ip [1]); - MonoObject* const o = sp [-1].data.o; + MonoObject *o = (MonoObject*) sp [0].data.o; NULL_CHECK (o); - MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [-3 + 2]]; - const gboolean needs_typecheck = ip [-3] == MINT_LDELEMA_TC; - MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, sp, needs_typecheck); + MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [2]]; + MonoException *ex = ves_array_element_address (frame, klass, (MonoArray *) o, sp + 1, TRUE); if (ex) THROW_EX (ex, ip); + ip += 3; MINT_IN_BREAK; } -#define LDELEM(datamem,elemtype) do { \ - sp--; \ - MonoArray *o = (MonoArray*)sp [-1].data.p; \ +#define LDELEM(datatype,elemtype) do { \ + MonoArray *o = LOCAL_VAR (ip [2], MonoArray*); \ NULL_CHECK (o); \ - gint32 aindex = sp [0].data.i; \ + gint32 aindex = LOCAL_VAR (ip [3], gint32); \ if (aindex >= mono_array_length_internal (o)) \ THROW_EX (mono_get_exception_index_out_of_range (), ip); \ - sp [-1].data.datamem = mono_array_get_fast (o, elemtype, aindex); \ - ip++; \ + LOCAL_VAR (ip [1], datatype) = mono_array_get_fast (o, elemtype, aindex); \ + ip += 4; \ } while (0) - MINT_IN_CASE(MINT_LDELEM_I1) LDELEM(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_U1) LDELEM(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_I2) LDELEM(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_U2) LDELEM(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_I4) LDELEM(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_U4) LDELEM(i, guint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_I8) LDELEM(l, guint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_I) LDELEM(nati, mono_i); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_R4) LDELEM(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_R8) LDELEM(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDELEM_REF) LDELEM(p, gpointer); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_I1) LDELEM(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_U1) LDELEM(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_I2) LDELEM(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_U2) LDELEM(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_I4) LDELEM(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_U4) LDELEM(gint32, guint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_I8) LDELEM(gint64, guint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_I) LDELEM(mono_u, mono_i); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_R4) LDELEM(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_R8) LDELEM(double, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_LDELEM_REF) LDELEM(gpointer, gpointer); MINT_IN_BREAK; MINT_IN_CASE(MINT_LDELEM_VT) { - sp -= 2; - MonoArray *o = (MonoArray*)sp [0].data.p; + MonoArray *o = LOCAL_VAR (ip [2], MonoArray*); NULL_CHECK (o); - mono_u aindex = sp [1].data.i; + mono_u aindex = LOCAL_VAR (ip [3], gint32); if (aindex >= mono_array_length_internal (o)) THROW_EX (mono_get_exception_index_out_of_range (), ip); - int i32 = READ32 (ip + 1); - char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex); - memcpy (sp, src_addr, i32); - sp = STACK_ADD_BYTES (sp, i32); + guint16 size = ip [4]; + char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, size, aindex); + memcpy (locals + ip [1], src_addr, size); - ip += 3; + ip += 5; MINT_IN_BREAK; } #define STELEM_PROLOG(o, aindex) do { \ - sp -= 3; \ - o = (MonoArray*)sp [0].data.p; \ + o = LOCAL_VAR (ip [1], MonoArray*); \ NULL_CHECK (o); \ - aindex = sp [1].data.i; \ + aindex = LOCAL_VAR (ip [2], gint32); \ if (aindex >= mono_array_length_internal (o)) \ THROW_EX (mono_get_exception_index_out_of_range (), ip); \ } while (0) -#define STELEM(datamem,elemtype) do { \ +#define STELEM(datatype, elemtype) do { \ MonoArray *o; \ gint32 aindex; \ STELEM_PROLOG(o, aindex); \ - mono_array_set_fast (o, elemtype, aindex, sp [2].data.datamem); \ - ip++; \ + mono_array_set_fast (o, elemtype, aindex, LOCAL_VAR (ip [3], datatype)); \ + ip += 4; \ } while (0) - MINT_IN_CASE(MINT_STELEM_I1) STELEM(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_U1) STELEM(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_I2) STELEM(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_U2) STELEM(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_I4) STELEM(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_I8) STELEM(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_I) STELEM(nati, mono_i); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_R4) STELEM(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STELEM_R8) STELEM(f, double); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_I1) STELEM(gint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_U1) STELEM(gint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_I2) STELEM(gint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_U2) STELEM(gint32, guint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_I4) STELEM(gint32, gint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_I8) STELEM(gint64, gint64); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_I) STELEM(mono_u, mono_i); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_R4) STELEM(float, float); MINT_IN_BREAK; + MINT_IN_CASE(MINT_STELEM_R8) STELEM(double, double); MINT_IN_BREAK; MINT_IN_CASE(MINT_STELEM_REF) { MonoArray *o; gint32 aindex; STELEM_PROLOG(o, aindex); + MonoObject *ref = LOCAL_VAR (ip [3], MonoObject*); - if (sp [2].data.o) { - gboolean isinst = mono_interp_isinst (sp [2].data.o, m_class_get_element_class (mono_object_class (o))); + if (ref) { + gboolean isinst = mono_interp_isinst (ref, m_class_get_element_class (mono_object_class (o))); if (!isinst) THROW_EX (mono_get_exception_array_type_mismatch (), ip); } - mono_array_setref_fast ((MonoArray *) o, aindex, sp [2].data.p); - ip++; + mono_array_setref_fast ((MonoArray *) o, aindex, ref); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_STELEM_VT) { - int i32 = READ32 (ip + 2); - sp = STACK_SUB_BYTES (sp, 2 * MINT_STACK_SLOT_SIZE + i32); - MonoArray *o = (MonoArray*)sp [0].data.p; + MonoArray *o = LOCAL_VAR (ip [1], MonoArray*); NULL_CHECK (o); - gint32 aindex = sp [1].data.i; + gint32 aindex = LOCAL_VAR (ip [2], gint32); if (aindex >= mono_array_length_internal (o)) THROW_EX (mono_get_exception_index_out_of_range (), ip); - char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, i32, aindex); - MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [1]]; - mono_value_copy_internal (dst_addr, sp + 2, klass_vt); - ip += 4; + guint16 size = ip [5]; + char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, size, aindex); + MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [4]]; + mono_value_copy_internal (dst_addr, locals + ip [3], klass_vt); + ip += 6; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CONV_OVF_I4_U4) - if (sp [-1].data.i < 0) + MINT_IN_CASE(MINT_CONV_OVF_I4_U4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I4_I8) - if (sp [-1].data.l < G_MININT32 || sp [-1].data.l > G_MAXINT32) + } + MINT_IN_CASE(MINT_CONV_OVF_I4_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < G_MININT32 || val > G_MAXINT32) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint32) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I4_U8) - if ((guint64)sp [-1].data.l > G_MAXINT32) + } + MINT_IN_CASE(MINT_CONV_OVF_I4_U8) { + guint64 val = LOCAL_VAR (ip [2], guint64); + if (val > G_MAXINT32) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint32) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32) val; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_CONV_OVF_I4_R4) { - gint32 res = (gint32)sp [-1].data.f_r4; - if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) + float val = LOCAL_VAR (ip [2], float); + if (mono_isnan (val) || mono_trunc (val) != (gint32)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = res; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32) val; + ip += 3; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CONV_OVF_I4_R8) - if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32 || isnan (sp [-1].data.f)) + MINT_IN_CASE(MINT_CONV_OVF_I4_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < G_MININT32 || val > G_MAXINT32 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint32) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint32)val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U4_I4) - if (sp [-1].data.i < 0) + } + MINT_IN_CASE(MINT_CONV_OVF_U4_I4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U4_I8) - if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT32) + } + MINT_IN_CASE(MINT_CONV_OVF_U4_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < 0 || val > G_MAXUINT32) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint32) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint32) val; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_CONV_OVF_U4_R4) { - guint32 res = (guint32)sp [-1].data.f_r4; - if (mono_isnan (sp [-1].data.f_r4) || mono_trunc (sp [-1].data.f_r4) != res) + float val = LOCAL_VAR (ip [2], float); + if (mono_isnan (val) || mono_trunc (val) != (guint32)val) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = res; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint32)val; + ip += 3; MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CONV_OVF_U4_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32 || isnan (sp [-1].data.f)) + MINT_IN_CASE(MINT_CONV_OVF_U4_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || val > G_MAXUINT32 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint32) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint32) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_I4) - if (sp [-1].data.i < G_MININT16 || sp [-1].data.i > G_MAXINT16) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_I4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < G_MININT16 || val > G_MAXINT16) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16)val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_U4) - if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT16) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_U4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0 || val > G_MAXINT16) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16)val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_I8) - if (sp [-1].data.l < G_MININT16 || sp [-1].data.l > G_MAXINT16) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < G_MININT16 || val > G_MAXINT16) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_U8) - if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT16) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_U8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < 0 || val > G_MAXINT16) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_R4) - if (sp [-1].data.f_r4 < G_MININT16 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4)) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_R4) { + float val = LOCAL_VAR (ip [2], float); + if (val < G_MININT16 || val > G_MAXINT16 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_R8) - if (sp [-1].data.f < G_MININT16 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < G_MININT16 || val > G_MAXINT16 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4) - if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT16 || isnan (sp [-1].data.f_r4)) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R4) { + float val = LOCAL_VAR (ip [2], float); + if (val < 0 || val > G_MAXINT16 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT16 || isnan (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CONV_OVF_I2_UN_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || val > G_MAXINT16 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint16) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint16) val; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_I4) - if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT16) + } + MINT_IN_CASE(MINT_CONV_OVF_U2_I4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0 || val > G_MAXUINT16) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_I8) - if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT16) + } + MINT_IN_CASE(MINT_CONV_OVF_U2_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < 0 || val > G_MAXUINT16) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint16) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_R4) - if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT16 || isnan (sp [-1].data.f_r4)) + } + MINT_IN_CASE(MINT_CONV_OVF_U2_R4) { + float val = LOCAL_VAR (ip [2], float); + if (val < 0 || val > G_MAXUINT16 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint16) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U2_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT16 || isnan (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CONV_OVF_U2_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || val > G_MAXUINT16 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint16) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint16) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_I4) - if (sp [-1].data.i < G_MININT8 || sp [-1].data.i > G_MAXINT8) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_I4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < G_MININT8 || val > G_MAXINT8) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_U4) - if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXINT8) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_U4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0 || val > G_MAXINT8) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_I8) - if (sp [-1].data.l < G_MININT8 || sp [-1].data.l > G_MAXINT8) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < G_MININT8 || val > G_MAXINT8) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_U8) - if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXINT8) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_U8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < 0 || val > G_MAXINT8) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_R4) - if (sp [-1].data.f_r4 < G_MININT8 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4)) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_R4) { + float val = LOCAL_VAR (ip [2], float); + if (val < G_MININT8 || val > G_MAXINT8 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_R8) - if (sp [-1].data.f < G_MININT8 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < G_MININT8 || val > G_MAXINT8 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4) - if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXINT8 || isnan (sp [-1].data.f_r4)) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R4) { + float val = LOCAL_VAR (ip [2], float); + if (val < 0 || val > G_MAXINT8 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXINT8 || isnan (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CONV_OVF_I1_UN_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || val > G_MAXINT8 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (gint8) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (gint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_I4) - if (sp [-1].data.i < 0 || sp [-1].data.i > G_MAXUINT8) + } + MINT_IN_CASE(MINT_CONV_OVF_U1_I4) { + gint32 val = LOCAL_VAR (ip [2], gint32); + if (val < 0 || val > G_MAXUINT8) THROW_EX (mono_get_exception_overflow (), ip); - ++ip; + LOCAL_VAR (ip [1], gint32) = val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_I8) - if (sp [-1].data.l < 0 || sp [-1].data.l > G_MAXUINT8) + } + MINT_IN_CASE(MINT_CONV_OVF_U1_I8) { + gint64 val = LOCAL_VAR (ip [2], gint64); + if (val < 0 || val > G_MAXUINT8) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint8) sp [-1].data.l; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_R4) - if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT8 || isnan (sp [-1].data.f_r4)) + } + MINT_IN_CASE(MINT_CONV_OVF_U1_R4) { + float val = LOCAL_VAR (ip [2], float); + if (val < 0 || val > G_MAXUINT8 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint8) sp [-1].data.f_r4; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CONV_OVF_U1_R8) - if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT8 || isnan (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CONV_OVF_U1_R8) { + double val = LOCAL_VAR (ip [2], double); + if (val < 0 || val > G_MAXUINT8 || isnan (val)) THROW_EX (mono_get_exception_overflow (), ip); - sp [-1].data.i = (guint8) sp [-1].data.f; - ++ip; + LOCAL_VAR (ip [1], gint32) = (guint8) val; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CKFINITE) - if (!mono_isfinite (sp [-1].data.f)) + } + MINT_IN_CASE(MINT_CKFINITE) { + double val = LOCAL_VAR (ip [2], double); + if (!mono_isfinite (val)) THROW_EX (mono_get_exception_arithmetic (), ip); - ++ip; + LOCAL_VAR (ip [1], double) = val; + ip += 3; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_MKREFANY) { - MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]]; + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; - sp--; - /* The value address is on the stack */ - gpointer addr = sp [0].data.p; - /* Push the typedref value on the stack */ - MonoTypedRef *tref = (MonoTypedRef*)sp; + gpointer addr = LOCAL_VAR (ip [2], gpointer); + /* Write the typedref value */ + MonoTypedRef *tref = (MonoTypedRef*)(locals + ip [1]); tref->klass = c; tref->type = m_class_get_byval_arg (c); tref->value = addr; - sp = STACK_ADD_BYTES (sp, sizeof (MonoTypedRef)); - ip += 2; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_REFANYTYPE) { - sp = STACK_SUB_BYTES (sp, sizeof (MonoTypedRef)); - MonoTypedRef *tref = (MonoTypedRef*)sp; + MonoTypedRef *tref = (MonoTypedRef*)(locals + ip [2]); - sp [0].data.p = tref->type; - sp++; - ip++; + LOCAL_VAR (ip [1], gpointer) = tref->type; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_REFANYVAL) { - sp = STACK_SUB_BYTES (sp, sizeof (MonoTypedRef)); - MonoTypedRef *tref = (MonoTypedRef*)sp; + MonoTypedRef *tref = (MonoTypedRef*)(locals + ip [2]); - MonoClass* const c = (MonoClass*)frame->imethod->data_items [ip [1]]; + MonoClass *c = (MonoClass*)frame->imethod->data_items [ip [3]]; if (c != tref->klass) THROW_EX (mono_get_exception_invalid_cast (), ip); - sp [0].data.p = tref->value; - sp++; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = tref->value; + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDTOKEN) // FIXME same as MINT_MONO_LDPTR - sp->data.p = frame->imethod->data_items [ip [1]]; - sp++; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [2]]; + ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_I4) - if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) + MINT_IN_CASE(MINT_ADD_OVF_I4) { + gint32 i1 = LOCAL_VAR (ip [2], gint32); + gint32 i2 = LOCAL_VAR (ip [3], gint32); + if (CHECK_ADD_OVERFLOW (i1, i2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, +); + LOCAL_VAR (ip [1], gint32) = i1 + i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_I8) - if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) + } + MINT_IN_CASE(MINT_ADD_OVF_I8) { + gint64 l1 = LOCAL_VAR (ip [2], gint64); + gint64 l2 = LOCAL_VAR (ip [3], gint64); + if (CHECK_ADD_OVERFLOW64 (l1, l2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, +); + LOCAL_VAR (ip [1], gint64) = l1 + l2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_UN_I4) - if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) + } + MINT_IN_CASE(MINT_ADD_OVF_UN_I4) { + guint32 i1 = LOCAL_VAR (ip [2], guint32); + guint32 i2 = LOCAL_VAR (ip [3], guint32); + if (CHECK_ADD_OVERFLOW_UN (i1, i2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(i, +, guint32); + LOCAL_VAR (ip [1], guint32) = i1 + i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_ADD_OVF_UN_I8) - if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) + } + MINT_IN_CASE(MINT_ADD_OVF_UN_I8) { + guint64 l1 = LOCAL_VAR (ip [2], guint64); + guint64 l2 = LOCAL_VAR (ip [3], guint64); + if (CHECK_ADD_OVERFLOW64_UN (l1, l2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(l, +, guint64); + LOCAL_VAR (ip [1], guint64) = l1 + l2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_I4) - if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) + } + MINT_IN_CASE(MINT_MUL_OVF_I4) { + gint32 i1 = LOCAL_VAR (ip [2], gint32); + gint32 i2 = LOCAL_VAR (ip [3], gint32); + if (CHECK_MUL_OVERFLOW (i1, i2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, *); + LOCAL_VAR (ip [1], gint32) = i1 * i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_I8) - if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) + } + MINT_IN_CASE(MINT_MUL_OVF_I8) { + gint64 l1 = LOCAL_VAR (ip [2], gint64); + gint64 l2 = LOCAL_VAR (ip [3], gint64); + if (CHECK_MUL_OVERFLOW64 (l1, l2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, *); + LOCAL_VAR (ip [1], gint64) = l1 * l2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_UN_I4) - if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) + } + MINT_IN_CASE(MINT_MUL_OVF_UN_I4) { + guint32 i1 = LOCAL_VAR (ip [2], guint32); + guint32 i2 = LOCAL_VAR (ip [3], guint32); + if (CHECK_MUL_OVERFLOW_UN (i1, i2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(i, *, guint32); + LOCAL_VAR (ip [1], guint32) = i1 * i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_MUL_OVF_UN_I8) - if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) + } + MINT_IN_CASE(MINT_MUL_OVF_UN_I8) { + guint64 l1 = LOCAL_VAR (ip [2], guint64); + guint64 l2 = LOCAL_VAR (ip [3], guint64); + if (CHECK_MUL_OVERFLOW64_UN (l1, l2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(l, *, guint64); + LOCAL_VAR (ip [1], guint64) = l1 * l2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_I4) - if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i)) + } + MINT_IN_CASE(MINT_SUB_OVF_I4) { + gint32 i1 = LOCAL_VAR (ip [2], gint32); + gint32 i2 = LOCAL_VAR (ip [3], gint32); + if (CHECK_SUB_OVERFLOW (i1, i2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(i, -); + LOCAL_VAR (ip [1], gint32) = i1 - i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_I8) - if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l)) + } + MINT_IN_CASE(MINT_SUB_OVF_I8) { + gint64 l1 = LOCAL_VAR (ip [2], gint64); + gint64 l2 = LOCAL_VAR (ip [3], gint64); + if (CHECK_SUB_OVERFLOW64 (l1, l2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP(l, -); + LOCAL_VAR (ip [1], gint64) = l1 - l2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_UN_I4) - if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i)) + } + MINT_IN_CASE(MINT_SUB_OVF_UN_I4) { + guint32 i1 = LOCAL_VAR (ip [2], guint32); + guint32 i2 = LOCAL_VAR (ip [3], guint32); + if (CHECK_SUB_OVERFLOW_UN (i1, i2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(i, -, guint32); + LOCAL_VAR (ip [1], guint32) = i1 - i2; + ip += 4; MINT_IN_BREAK; - MINT_IN_CASE(MINT_SUB_OVF_UN_I8) - if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l)) + } + MINT_IN_CASE(MINT_SUB_OVF_UN_I8) { + guint64 l1 = LOCAL_VAR (ip [2], guint64); + guint64 l2 = LOCAL_VAR (ip [3], guint64); + if (CHECK_SUB_OVERFLOW64_UN (l1, l2)) THROW_EX (mono_get_exception_overflow (), ip); - BINOP_CAST(l, -, guint64); + LOCAL_VAR (ip [1], gint64) = l1 - l2; + ip += 4; MINT_IN_BREAK; + } MINT_IN_CASE(MINT_START_ABORT_PROT) mono_threads_begin_abort_protected_block (); ip ++; @@ -6310,9 +6252,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs mono_threads_end_abort_protected_block (); guint16 clause_index = *(ip + 1); - // endfinally empties the stack - sp = (stackval*)(locals + frame->imethod->total_locals_size); - guint16 *ret_ip = *(guint16**)(locals + frame->imethod->clause_data_offsets [clause_index]); if (!ret_ip) { // this clause was called from EH, return to eh @@ -6339,9 +6278,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_LEAVE_S) MINT_IN_CASE(MINT_LEAVE_CHECK) MINT_IN_CASE(MINT_LEAVE_S_CHECK) { - // leave empties the stack - sp = (stackval*)(locals + frame->imethod->total_locals_size); - int opcode = *ip; gboolean const check = opcode == MINT_LEAVE_CHECK || opcode == MINT_LEAVE_S_CHECK; @@ -6372,36 +6308,28 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_ICALL_PPPPP_P) MINT_IN_CASE(MINT_ICALL_PPPPPP_V) MINT_IN_CASE(MINT_ICALL_PPPPPP_P) - frame->state.ip = ip + 2; - sp = do_icall_wrapper (frame, NULL, *ip, sp, frame->imethod->data_items [ip [1]], FALSE); + frame->state.ip = ip + 3; + do_icall_wrapper (frame, NULL, *ip, (stackval*)(locals + ip [1]), frame->imethod->data_items [ip [2]], FALSE); EXCEPTION_CHECKPOINT_GC_UNSAFE; CHECK_RESUME_STATE (context); - ip += 2; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_LDPTR) - sp->data.p = frame->imethod->data_items [ip [1]]; - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [2]]; + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_NEWOBJ) - sp->data.o = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [1]]); // FIXME: do not swallow the error - ip += 2; - sp++; + LOCAL_VAR (ip [1], MonoObject*) = mono_interp_new (frame->imethod->domain, (MonoClass*)frame->imethod->data_items [ip [2]]); // FIXME: do not swallow the error + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_RETOBJ) - ++ip; - sp--; - g_assert_not_reached (); - stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->retval, sp->data.p, + stackval_from_data (mono_method_signature_internal (frame->imethod->method)->ret, frame->stack, LOCAL_VAR (ip [1], gpointer), mono_method_signature_internal (frame->imethod->method)->pinvoke); - if (sp > frame->stack) - g_warning_d ("retobj: more values on stack: %d", sp - frame->stack); frame_data_allocator_pop (&context->data_stack, frame); goto exit_frame; MINT_IN_CASE(MINT_MONO_SGEN_THREAD_INFO) - sp->data.p = mono_tls_get_sgen_thread_info (); - sp++; - ++ip; + LOCAL_VAR (ip [1], gpointer) = mono_tls_get_sgen_thread_info (); + ip += 2; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) { ++ip; @@ -6409,33 +6337,32 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } MINT_IN_CASE(MINT_MONO_EXCHANGE_I8) { - sp--; gboolean flag = FALSE; + gint64 *dest = LOCAL_VAR (ip [2], gint64*); + gint64 exch = LOCAL_VAR (ip [3], gint64); #if SIZEOF_VOID_P == 4 - if (G_UNLIKELY ((size_t) ((gint64*) sp [-1].data.p) & 0x7)) { + if (G_UNLIKELY (((size_t)dest) & 0x7)) { gint64 result; mono_interlocked_lock (); - result = *((gint64*) sp [-1].data.p); - *((gint64*) sp [-1].data.p) = sp [0].data.l; + result = *dest; + *dest = exch; mono_interlocked_unlock (); - sp [-1].data.l = result; + LOCAL_VAR (ip [1], gint64) = result; flag = TRUE; } #endif if (!flag) - sp [-1].data.l = mono_atomic_xchg_i64 ((gint64*) sp [-1].data.p, sp [0].data.l); - ++ip; + LOCAL_VAR (ip [1], gint64) = mono_atomic_xchg_i64 (dest, exch); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_MONO_LDDOMAIN) - sp->data.p = mono_domain_get (); - ++sp; - ++ip; + LOCAL_VAR (ip [1], gpointer) = mono_domain_get (); + ip += 2; MINT_IN_BREAK; MINT_IN_CASE(MINT_MONO_GET_SP) - sp->data.p = frame; - ++sp; - ++ip; + LOCAL_VAR (ip [1], gpointer) = frame; + ip += 2; MINT_IN_BREAK; MINT_IN_CASE(MINT_SDB_INTR_LOC) if (G_UNLIKELY (ss_enabled)) { @@ -6491,137 +6418,136 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define RELOP(datamem, op) \ - --sp; \ - sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \ - ++ip; +#define RELOP(datatype, op) \ + LOCAL_VAR (ip [1], gint32) = LOCAL_VAR (ip [2], datatype) op LOCAL_VAR (ip [3], datatype); \ + ip += 4; -#define RELOP_FP(datamem, op, noorder) \ - --sp; \ - if (mono_isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \ - sp [-1].data.i = noorder; \ +#define RELOP_FP(datatype, op, noorder) do { \ + datatype a1 = LOCAL_VAR (ip [2], datatype); \ + datatype a2 = LOCAL_VAR (ip [3], datatype); \ + if (mono_isunordered (a1, a2)) \ + LOCAL_VAR (ip [1], gint32) = noorder; \ else \ - sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \ - ++ip; + LOCAL_VAR (ip [1], gint32) = a1 op a2; \ + ip += 4; \ +} while (0) MINT_IN_CASE(MINT_CEQ_I4) - RELOP(i, ==); + RELOP(gint32, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_CEQ0_I4) - sp [-1].data.i = (sp [-1].data.i == 0); - ++ip; + LOCAL_VAR (ip [1], gint32) = (LOCAL_VAR (ip [2], gint32) == 0); + ip += 3; MINT_IN_BREAK; MINT_IN_CASE(MINT_CEQ_I8) - RELOP(l, ==); + RELOP(gint64, ==); MINT_IN_BREAK; MINT_IN_CASE(MINT_CEQ_R4) - RELOP_FP(f_r4, ==, 0); + RELOP_FP(float, ==, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CEQ_R8) - RELOP_FP(f, ==, 0); + RELOP_FP(double, ==, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CNE_I4) - RELOP(i, !=); + RELOP(gint32, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CNE_I8) - RELOP(l, !=); + RELOP(gint64, !=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CNE_R4) - RELOP_FP(f_r4, !=, 1); + RELOP_FP(float, !=, 1); MINT_IN_BREAK; MINT_IN_CASE(MINT_CNE_R8) - RELOP_FP(f, !=, 1); + RELOP_FP(double, !=, 1); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_I4) - RELOP(i, >); + RELOP(gint32, >); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_I8) - RELOP(l, >); + RELOP(gint64, >); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_R4) - RELOP_FP(f_r4, >, 0); + RELOP_FP(float, >, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_R8) - RELOP_FP(f, >, 0); + RELOP_FP(double, >, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGE_I4) - RELOP(i, >=); + RELOP(gint32, >=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGE_I8) - RELOP(l, >=); + RELOP(gint64, >=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGE_R4) - RELOP_FP(f_r4, >=, 0); + RELOP_FP(float, >=, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGE_R8) - RELOP_FP(f, >=, 0); + RELOP_FP(double, >=, 0); MINT_IN_BREAK; -#define RELOP_CAST(datamem, op, type) \ - --sp; \ - sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \ - ++ip; +#define RELOP_CAST(datatype, op) \ + LOCAL_VAR (ip [1], gint32) = LOCAL_VAR (ip [2], datatype) op LOCAL_VAR (ip [3], datatype); \ + ip += 4; MINT_IN_CASE(MINT_CGE_UN_I4) - RELOP_CAST(l, >=, guint32); + RELOP_CAST(guint32, >=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGE_UN_I8) - RELOP_CAST(l, >=, guint64); + RELOP_CAST(guint64, >=); MINT_IN_BREAK; - MINT_IN_CASE(MINT_CGT_UN_I4) - RELOP_CAST(i, >, guint32); + RELOP_CAST(guint32, >); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_UN_I8) - RELOP_CAST(l, >, guint64); + RELOP_CAST(guint64, >); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_UN_R4) - RELOP_FP(f_r4, >, 1); + RELOP_FP(float, >, 1); MINT_IN_BREAK; MINT_IN_CASE(MINT_CGT_UN_R8) - RELOP_FP(f, >, 1); + RELOP_FP(double, >, 1); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_I4) - RELOP(i, <); + RELOP(gint32, <); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_I8) - RELOP(l, <); + RELOP(gint64, <); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_R4) - RELOP_FP(f_r4, <, 0); + RELOP_FP(float, <, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_R8) - RELOP_FP(f, <, 0); + RELOP_FP(double, <, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_UN_I4) - RELOP_CAST(i, <, guint32); + RELOP_CAST(guint32, <); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_UN_I8) - RELOP_CAST(l, <, guint64); + RELOP_CAST(guint64, <); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_UN_R4) - RELOP_FP(f_r4, <, 1); + RELOP_FP(float, <, 1); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLT_UN_R8) - RELOP_FP(f, <, 1); + RELOP_FP(double, <, 1); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLE_I4) - RELOP(i, <=); + RELOP(gint32, <=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLE_I8) - RELOP(l, <=); + RELOP(gint64, <=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLE_UN_I4) - RELOP_CAST(l, <=, guint32); + RELOP_CAST(guint32, <=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLE_UN_I8) - RELOP_CAST(l, <=, guint64); + RELOP_CAST(guint64, <=); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLE_R4) - RELOP_FP(f_r4, <=, 0); + RELOP_FP(float, <=, 0); MINT_IN_BREAK; MINT_IN_CASE(MINT_CLE_R8) - RELOP_FP(f, <=, 0); + RELOP_FP(double, <=, 0); MINT_IN_BREAK; #undef RELOP @@ -6629,27 +6555,25 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs #undef RELOP_CAST MINT_IN_CASE(MINT_LDFTN) { - sp->data.p = frame->imethod->data_items [ip [1]]; - ++sp; - ip += 2; + LOCAL_VAR (ip [1], gpointer) = frame->imethod->data_items [ip [2]]; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDVIRTFTN) { - InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [1]]; - --sp; - NULL_CHECK (sp->data.p); + InterpMethod *m = (InterpMethod*)frame->imethod->data_items [ip [3]]; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); + NULL_CHECK (o); - sp->data.p = get_virtual_method (m, sp->data.o->vtable); - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gpointer) = get_virtual_method (m, o->vtable); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LDFTN_DYNAMIC) { error_init_reuse (error); - InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), (MonoMethod*) sp [-1].data.p, error); + InterpMethod *m = mono_interp_get_imethod (mono_domain_get (), LOCAL_VAR (ip [2], MonoMethod*), error); mono_error_assert_ok (error); - sp [-1].data.p = m; - ip++; + LOCAL_VAR (ip [1], gpointer) = m; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_PROF_ENTER) { @@ -6672,24 +6596,15 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } - MINT_IN_CASE(MINT_PROF_EXIT) - MINT_IN_CASE(MINT_PROF_EXIT_VOID) { - guint16 flag = ip [1]; + MINT_IN_CASE(MINT_PROF_EXIT) { + guint16 flag = ip [2]; // Set retval - int const i32 = READ32 (ip + 2); + int i32 = READ32 (ip + 3); if (i32 == -1) { } else if (i32) { - sp = STACK_SUB_BYTES (sp, i32); - if (frame->parent) { - memmove (frame->parent->state.sp, sp, i32); - frame->parent->state.sp = STACK_ADD_BYTES (frame->parent->state.sp, i32); - } + memmove (frame->stack, locals + ip [1], i32); } else { - sp--; - if (frame->parent) { - frame->parent->state.sp [0] = *sp; - frame->parent->state.sp++; - } + frame->stack [0] = LOCAL_VAR (ip [1], stackval); } if ((flag & TRACING_FLAG) || ((flag & PROFILING_FLAG) && MONO_PROFILER_ENABLED (method_leave) && @@ -6698,7 +6613,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs prof_ctx->interp_frame = frame; prof_ctx->method = frame->imethod->method; if (i32 != -1) - prof_ctx->return_value = sp; + prof_ctx->return_value = frame->stack; if (flag & TRACING_FLAG) mono_trace_leave_method (frame->imethod->method, frame->imethod->jinfo, prof_ctx); if (flag & PROFILING_FLAG) @@ -6708,7 +6623,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, NULL)); } - ip += 4; frame_data_allocator_pop (&context->data_stack, frame); goto exit_frame; } @@ -6720,143 +6634,76 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define LDLOC(datamem, argtype) \ - sp->data.datamem = * (argtype *)(locals + ip [1]); \ - ip += 2; \ - ++sp; - - MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_LDLOC_VT) { - int const i32 = READ32 (ip + 2); - memcpy (sp, locals + ip [1], i32); - sp = STACK_ADD_BYTES (sp, i32); - ip += 4; - MINT_IN_BREAK; - } MINT_IN_CASE(MINT_LDLOCA_S) - sp->data.p = locals + ip [1]; - ip += 2; - ++sp; + LOCAL_VAR (ip [1], gpointer) = locals + ip [2]; + ip += 3; MINT_IN_BREAK; -#define STLOC(datamem, argtype) \ - --sp; \ - * (argtype *)(locals + ip [1]) = sp->data.datamem; \ - ip += 2; - - MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK; - -#define STLOC_NP(datamem, argtype) \ - * (argtype *)(locals + ip [1]) = sp [-1].data.datamem; \ - ip += 2; - - MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_NP_I8) STLOC_NP(l, gint64); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_NP_R4) STLOC_NP(f_r4, float); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_NP_R8) STLOC_NP(f, double); MINT_IN_BREAK; - MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_STLOC_VT) { - int const i32 = READ32 (ip + 2); - sp = STACK_SUB_BYTES (sp, i32); - memcpy (locals + ip [1], sp, i32); - ip += 4; - MINT_IN_BREAK; - } -#define MOVLOC(argtype) \ - * (argtype *)(locals + ip [2]) = * (argtype *)(locals + ip [1]); \ +#define MOV(argtype1,argtype2) \ + LOCAL_VAR (ip [1], argtype1) = LOCAL_VAR (ip [2], argtype2); \ ip += 3; - - MINT_IN_CASE(MINT_MOVLOC_1) MOVLOC(guint8); MINT_IN_BREAK; - MINT_IN_CASE(MINT_MOVLOC_2) MOVLOC(guint16); MINT_IN_BREAK; - MINT_IN_CASE(MINT_MOVLOC_4) MOVLOC(guint32); MINT_IN_BREAK; - MINT_IN_CASE(MINT_MOVLOC_8) MOVLOC(guint64); MINT_IN_BREAK; - - MINT_IN_CASE(MINT_MOVLOC_VT) { - int const i32 = READ32(ip + 3); - memcpy (locals + ip [2], locals + ip [1], i32); - ip += 5; + // When loading from a local, we might need to sign / zero extend to 4 bytes + // which is our minimum "register" size in interp. They are only needed when + // the address of the local is taken and we should try to optimize them out + // because the local can't be propagated. + MINT_IN_CASE(MINT_MOV_I1) MOV(guint32, gint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_MOV_U1) MOV(guint32, guint8); MINT_IN_BREAK; + MINT_IN_CASE(MINT_MOV_I2) MOV(guint32, gint16); MINT_IN_BREAK; + MINT_IN_CASE(MINT_MOV_U2) MOV(guint32, guint16); MINT_IN_BREAK; + // Normal moves between locals + MINT_IN_CASE(MINT_MOV_4) MOV(guint32, guint32); MINT_IN_BREAK; + MINT_IN_CASE(MINT_MOV_8) MOV(guint64, guint64); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_MOV_VT) { + guint16 size = ip [3]; + memmove (locals + ip [1], locals + ip [2], size); + ip += 4; MINT_IN_BREAK; } MINT_IN_CASE(MINT_LOCALLOC) { - stackval *sp_start = (stackval*)(locals + frame->imethod->total_locals_size); - if (sp != sp_start + 1) /*FIX?*/ - THROW_EX (mono_get_exception_execution_engine (NULL), ip); - - int len = sp [-1].data.i; - // FIXME we need a separate allocator for localloc sections - sp [-1].data.p = frame_data_allocator_alloc (&context->data_stack, frame, ALIGN_TO (len, MINT_VT_ALIGNMENT)); + int len = LOCAL_VAR (ip [2], gint32); + gpointer mem = frame_data_allocator_alloc (&context->data_stack, frame, ALIGN_TO (len, MINT_VT_ALIGNMENT)); if (frame->imethod->init_locals) - memset (sp [-1].data.p, 0, len); - ++ip; + memset (mem, 0, len); + LOCAL_VAR (ip [1], gpointer) = mem; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ENDFILTER) /* top of stack is result of filter */ - frame->retval->data.i = sp [-1].data.i; + frame->retval->data.i = LOCAL_VAR (ip [1], gint32); goto exit_clause; MINT_IN_CASE(MINT_INITOBJ) - --sp; - memset (sp->data.vt, 0, READ32(ip + 1)); + memset (LOCAL_VAR (ip [1], gpointer), 0, ip [2]); ip += 3; MINT_IN_BREAK; - MINT_IN_CASE(MINT_CPBLK) - sp -= 3; - if (!sp [0].data.p || !sp [1].data.p) - THROW_EX (mono_get_exception_null_reference(), ip - 1); - ++ip; + MINT_IN_CASE(MINT_CPBLK) { + gpointer dest = LOCAL_VAR (ip [1], gpointer); + gpointer src = LOCAL_VAR (ip [2], gpointer); + if (!dest || !src) + THROW_EX (mono_get_exception_null_reference(), ip); /* FIXME: value and size may be int64... */ - memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i); - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_CONSTRAINED_) { - guint32 token; - /* FIXME: implement */ - ++ip; - token = READ32 (ip); - ip += 2; + memcpy (dest, src, LOCAL_VAR (ip [3], gint32)); + ip += 4; MINT_IN_BREAK; } -#endif - MINT_IN_CASE(MINT_INITBLK) - sp -= 3; - NULL_CHECK (sp [0].data.p); - ++ip; + MINT_IN_CASE(MINT_INITBLK) { + gpointer dest = LOCAL_VAR (ip [1], gpointer); + NULL_CHECK (dest); /* FIXME: value and size may be int64... */ - memset (sp [0].data.p, sp [1].data.i, sp [2].data.i); - MINT_IN_BREAK; -#if 0 - MINT_IN_CASE(MINT_NO_) - /* FIXME: implement */ - ip += 2; + memset (dest, LOCAL_VAR (ip [2], gint32), LOCAL_VAR (ip [3], gint32)); + ip += 4; MINT_IN_BREAK; -#endif - MINT_IN_CASE(MINT_RETHROW) { + } + MINT_IN_CASE(MINT_RETHROW) { int exvar_offset = ip [1]; THROW_EX_GENERAL (*(MonoException**)(frame_locals (frame) + exvar_offset), ip, TRUE); MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_MONO_RETHROW) { + } + MINT_IN_CASE(MINT_MONO_RETHROW) { /* * need to clarify what this should actually do: * @@ -6865,40 +6712,35 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs * use CEE_THROW and lose the exception stacktrace. */ - --sp; - if (!sp->data.p) - sp->data.p = mono_get_exception_null_reference (); - - THROW_EX_GENERAL ((MonoException *)sp->data.p, ip, TRUE); - MINT_IN_BREAK; - } - MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) { - MonoDelegate *del; - - --sp; - del = (MonoDelegate*)sp->data.p; - if (!del->interp_method) { - /* Not created from interpreted code */ - error_init_reuse (error); - g_assert (del->method); - del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error); - mono_error_assert_ok (error); - } - g_assert (del->interp_method); - sp->data.p = del->interp_method; - ++sp; - ip += 1; - MINT_IN_BREAK; - } + MonoException *exc = LOCAL_VAR (ip [1], MonoException*); + if (!exc) + exc = mono_get_exception_null_reference (); + + THROW_EX_GENERAL (exc, ip, TRUE); + MINT_IN_BREAK; + } + MINT_IN_CASE(MINT_LD_DELEGATE_METHOD_PTR) { + MonoDelegate *del = LOCAL_VAR (ip [2], MonoDelegate*); + if (!del->interp_method) { + /* Not created from interpreted code */ + error_init_reuse (error); + g_assert (del->method); + del->interp_method = mono_interp_get_imethod (del->object.vtable->domain, del->method, error); + mono_error_assert_ok (error); + } + g_assert (del->interp_method); + LOCAL_VAR (ip [1], gpointer) = del->interp_method; + ip += 3; + MINT_IN_BREAK; + } #define MATH_UNOP(mathfunc) \ - sp [-1].data.f = mathfunc (sp [-1].data.f); \ - ++ip; + LOCAL_VAR (ip [1], double) = mathfunc (LOCAL_VAR (ip [2], double)); \ + ip += 3; #define MATH_BINOP(mathfunc) \ - sp--; \ - sp [-1].data.f = mathfunc (sp [-1].data.f, sp [0].data.f); \ - ++ip; + LOCAL_VAR (ip [1], double) = mathfunc (LOCAL_VAR (ip [2], double), LOCAL_VAR (ip [3], double)); \ + ip += 4; MINT_IN_CASE(MINT_ABS) MATH_UNOP(fabs); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASIN) MATH_UNOP(asin); MINT_IN_BREAK; @@ -6925,37 +6767,34 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_ATAN2) MATH_BINOP(atan2); MINT_IN_BREAK; MINT_IN_CASE(MINT_POW) MATH_BINOP(pow); MINT_IN_BREAK; MINT_IN_CASE(MINT_FMA) - sp -= 2; - sp [-1].data.f = fma (sp [-1].data.f, sp [0].data.f, sp [1].data.f); - ip++; + LOCAL_VAR (ip [1], double) = fma (LOCAL_VAR (ip [2], double), LOCAL_VAR (ip [3], double), LOCAL_VAR (ip [4], double)); + ip += 5; MINT_IN_BREAK; MINT_IN_CASE(MINT_SCALEB) - sp--; - sp [-1].data.f = scalbn (sp [-1].data.f, sp [0].data.i); - ip++; + LOCAL_VAR (ip [1], double) = scalbn (LOCAL_VAR (ip [2], double), LOCAL_VAR (ip [3], gint32)); + ip += 4; MINT_IN_BREAK; MINT_IN_CASE(MINT_ILOGB) { int result; - double x = sp [-1].data.f; + double x = LOCAL_VAR (ip [2], double); if (FP_ILOGB0 != INT_MIN && x == 0.0) result = INT_MIN; else if (FP_ILOGBNAN != INT_MAX && isnan(x)) result = INT_MAX; else result = ilogb (x); - sp [-1].data.i = result; - ip++; + LOCAL_VAR (ip [1], gint32) = result; + ip += 3; MINT_IN_BREAK; } #define MATH_UNOPF(mathfunc) \ - sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4); \ - ++ip; + LOCAL_VAR (ip [1], float) = mathfunc (LOCAL_VAR (ip [2], float)); \ + ip += 3; #define MATH_BINOPF(mathfunc) \ - sp--; \ - sp [-1].data.f_r4 = mathfunc (sp [-1].data.f_r4, sp [0].data.f_r4); \ - ++ip; + LOCAL_VAR (ip [1], float) = mathfunc (LOCAL_VAR (ip [2], float), LOCAL_VAR (ip [3], float)); \ + ip += 4; MINT_IN_CASE(MINT_ABSF) MATH_UNOPF(fabsf); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASINF) MATH_UNOPF(asinf); MINT_IN_BREAK; MINT_IN_CASE(MINT_ASINHF) MATH_UNOPF(asinhf); MINT_IN_BREAK; @@ -6981,45 +6820,43 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_CASE(MINT_ATAN2F) MATH_BINOPF(atan2f); MINT_IN_BREAK; MINT_IN_CASE(MINT_POWF) MATH_BINOPF(powf); MINT_IN_BREAK; MINT_IN_CASE(MINT_FMAF) - sp -= 2; - sp [-1].data.f_r4 = fmaf (sp [-1].data.f_r4, sp [0].data.f_r4, sp [1].data.f_r4); - ip++; + LOCAL_VAR (ip [1], float) = fmaf (LOCAL_VAR (ip [2], float), LOCAL_VAR (ip [3], float), LOCAL_VAR (ip [4], float)); + ip += 5; MINT_IN_BREAK; MINT_IN_CASE(MINT_SCALEBF) - sp--; - sp [-1].data.f_r4 = scalbnf (sp [-1].data.f_r4, sp [0].data.i); - ip++; + LOCAL_VAR (ip [1], float) = scalbnf (LOCAL_VAR (ip [2], float), LOCAL_VAR (ip [3], gint32)); + ip += 4; MINT_IN_BREAK; MINT_IN_CASE(MINT_ILOGBF) { int result; - float x = sp [-1].data.f_r4; + float x = LOCAL_VAR (ip [2], float); if (FP_ILOGB0 != INT_MIN && x == 0.0) result = INT_MIN; else if (FP_ILOGBNAN != INT_MAX && isnan(x)) result = INT_MAX; else result = ilogbf (x); - sp [-1].data.i = result; - ip++; + LOCAL_VAR (ip [1], gint32) = result; + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_ENUM_HASFLAG) { - MonoClass *klass = (MonoClass*)frame->imethod->data_items[ip [1]]; - mono_interp_enum_hasflag (sp, klass); - sp--; - ip += 2; + MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [4]]; + LOCAL_VAR (ip [1], gint32) = mono_interp_enum_hasflag ((stackval*)(locals + ip [2]), (stackval*)(locals + ip [3]), klass); + ip += 5; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_GET_HASHCODE) { - sp [-1].data.i = mono_object_hash_internal (sp [-1].data.o); - ip++; + LOCAL_VAR (ip [1], gint32) = mono_object_hash_internal (LOCAL_VAR (ip [2], MonoObject*)); + ip += 3; MINT_IN_BREAK; } MINT_IN_CASE(MINT_INTRINS_GET_TYPE) { - NULL_CHECK (sp [-1].data.p); - sp [-1].data.o = (MonoObject*) sp [-1].data.o->vtable->type; - ip++; + MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); + NULL_CHECK (o); + LOCAL_VAR (ip [1], MonoObject*) = (MonoObject*) o->vtable->type; + ip += 3; MINT_IN_BREAK; } @@ -7049,10 +6886,9 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip = context->handler_ip; /* spec says stack should be empty at endfinally so it should be at the start too */ locals = (guchar*)frame->stack; - sp = (stackval*)(locals + frame->imethod->total_locals_size); g_assert (context->exc_gchandle); - sp->data.p = mono_gchandle_get_target_internal (context->exc_gchandle); - ++sp; + // Write the exception on to the first slot on the excecution stack + LOCAL_VAR (frame->imethod->total_locals_size, MonoObject*) = mono_gchandle_get_target_internal (context->exc_gchandle); clear_resume_state (context); // goto main_loop instead of MINT_IN_DISPATCH helps the compiler and therefore conserves stack. diff --git a/src/mono/mono/mini/interp/mintops.c b/src/mono/mono/mini/interp/mintops.c index 4d50657e13deb9..86cb256d6df22f 100644 --- a/src/mono/mono/mini/interp/mintops.c +++ b/src/mono/mono/mini/interp/mintops.c @@ -35,28 +35,16 @@ unsigned char const mono_interp_oplen [] = { }; #undef OPDEF -#define Push0 0 -#define Push1 1 -#define Push2 2 -#define Pop0 0 -#define Pop1 1 -#define Pop2 2 -#define Pop3 3 -#define Pop4 4 -#define Pop5 5 -#define Pop6 6 -#define PopAll MINT_POP_ALL -#define VarPush MINT_VAR_PUSH -#define VarPop MINT_VAR_POP +#define CallArgs MINT_CALL_ARGS -#define OPDEF(a,b,c,d,e,f) d, -int const mono_interp_oppop[] = { +#define OPDEF(a,b,c,d,e,f) e, +int const mono_interp_op_sregs[] = { #include "mintops.def" }; #undef OPDEF -#define OPDEF(a,b,c,d,e,f) e, -int const mono_interp_oppush[] = { +#define OPDEF(a,b,c,d,e,f) d, +int const mono_interp_op_dregs[] = { #include "mintops.def" }; #undef OPDEF @@ -76,111 +64,13 @@ mono_interp_dis_mintop_len (const guint16 *ip) g_print ("op %d len %d\n", *ip, len); g_assert_not_reached (); } else if (len == 0) { /* SWITCH */ - int n = READ32 (ip + 1); + int n = READ32 (ip + 2); len = MINT_SWITCH_LEN (n); } return ip + len; } -/* - * ins_offset is the associated offset of this instruction - * native_offset indicates whether this instruction is part of the compacted - * instruction stream or is part of an InterpInst - * ip is the address where the arguments of the instruction are located - */ -char * -mono_interp_dis_mintop (gint32 ins_offset, gboolean native_offset, const guint16 *ip, guint16 opcode) -{ - GString *str = g_string_new (""); - guint32 token; - int target; - - if (native_offset) - g_string_append_printf (str, "IR_%04x: %-10s", ins_offset, mono_interp_opname (opcode)); - else - g_string_append_printf (str, "IL_%04x: %-10s", ins_offset, mono_interp_opname (opcode)); - - switch (mono_interp_opargtype [opcode]) { - case MintOpNoArgs: - break; - case MintOpUShortInt: - g_string_append_printf (str, " %u", *(guint16*)ip); - break; - case MintOpTwoShorts: - g_string_append_printf (str, " %u,%u", *(guint16*)ip, *(guint16 *)(ip + 1)); - break; - case MintOpShortAndInt: - g_string_append_printf (str, " %u,%u", *(guint16*)ip, (guint32)READ32(ip + 1)); - break; - case MintOpShortInt: - g_string_append_printf (str, " %d", *(gint16*)ip); - break; - case MintOpClassToken: - case MintOpMethodToken: - case MintOpFieldToken: - token = * (guint16 *) ip; - g_string_append_printf (str, " %u", token); - break; - case MintOpInt: - g_string_append_printf (str, " %d", (gint32)READ32 (ip)); - break; - case MintOpLongInt: - g_string_append_printf (str, " %" PRId64, (gint64)READ64 (ip)); - break; - case MintOpFloat: { - gint32 tmp = READ32 (ip); - g_string_append_printf (str, " %g", * (float *)&tmp); - break; - } - case MintOpDouble: { - gint64 tmp = READ64 (ip); - g_string_append_printf (str, " %g", * (double *)&tmp); - break; - } - case MintOpShortBranch: - if (native_offset) { - target = ins_offset + *(gint16*)ip; - g_string_append_printf (str, " IR_%04x", target); - } else { - /* the target IL is already embedded in the instruction */ - g_string_append_printf (str, " IL_%04x", *(gint16*)ip); - } - break; - case MintOpBranch: - if (native_offset) { - target = ins_offset + (gint32)READ32 (ip); - g_string_append_printf (str, " IR_%04x", target); - } else { - g_string_append_printf (str, " IL_%04x", (gint32)READ32 (ip)); - } - break; - case MintOpSwitch: { - int sval = (gint32)READ32 (ip); - int i; - g_string_append_printf (str, "("); - gint32 p = 2; - for (i = 0; i < sval; ++i) { - if (i > 0) - g_string_append_printf (str, ", "); - if (native_offset) { - int offset = (gint32)READ32 (ip + p); - g_string_append_printf (str, "IR_%04x", ins_offset + 1 + p + offset); - } else { - g_string_append_printf (str, "IL_%04x", (gint32)READ32 (ip + p)); - } - p += 2; - } - g_string_append_printf (str, ")"); - break; - } - default: - g_string_append_printf (str, "unknown arg type\n"); - } - - return g_string_free (str, FALSE); -} - const char* mono_interp_opname (int op) { diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index 3ec3cd4150f4cf..d94d90ead77c6f 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -4,793 +4,733 @@ * Authors: * Bernie Solomon (bernard@ugsolutions.com) * + * OPDEF (opsymbol, opstring, oplength (in uint16s), num_dregs (0 or 1), num_sregs, optype) + * optype describes the contents of the instruction, following the dreg/sreg offsets. */ -/* OPDEF (opsymbol, opstring, oplength (in uint16s), pop_n, push_n, optype) */ - -OPDEF(MINT_NOP, "nop", 0, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_NIY, "niy", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_BREAK, "break", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_BREAKPOINT, "breakpoint", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_LDNULL, "ldnull", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_DUP, "dup", 1, Pop1, Push2, MintOpNoArgs) -OPDEF(MINT_DUP_VT, "dup.vt", 3, Pop1, Push2, MintOpInt) -OPDEF(MINT_POP, "pop", 1, Pop1, Push0, MintOpNoArgs) -OPDEF(MINT_POP_VT, "pop.vt", 3, Pop1, Push0, MintOpNoArgs) -OPDEF(MINT_POP1, "pop1", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_RET, "ret", 1, Pop1, Push0, MintOpNoArgs) -OPDEF(MINT_RET_VOID, "ret.void", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_RET_VT, "ret.vt", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_RET_LOCALLOC, "ret.localloc", 1, Pop1, Push0, MintOpNoArgs) -OPDEF(MINT_RET_VOID_LOCALLOC, "ret.void.localloc", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_RET_VT_LOCALLOC, "ret.vt.localloc", 3, Pop1, Push0, MintOpInt) - -OPDEF(MINT_LDC_I4_M1, "ldc.i4.m1", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_0, "ldc.i4.0", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_1, "ldc.i4.1", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_2, "ldc.i4.2", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_3, "ldc.i4.3", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_4, "ldc.i4.4", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_5, "ldc.i4.5", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_6, "ldc.i4.6", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_7, "ldc.i4.7", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_LDC_I4_8, "ldc.i4.8", 1, Pop0, Push1, MintOpNoArgs) - -OPDEF(MINT_LDC_I4_S, "ldc.i4.s", 2, Pop0, Push1, MintOpShortInt) -OPDEF(MINT_LDC_I4, "ldc.i4", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDC_I8, "ldc.i8", 5, Pop0, Push1, MintOpLongInt) -OPDEF(MINT_LDC_I8_S, "ldc.i8.s", 2, Pop0, Push1, MintOpShortInt) - -OPDEF(MINT_LDC_R4, "ldc.r4", 3, Pop0, Push1, MintOpFloat) -OPDEF(MINT_LDC_R8, "ldc.r8", 5, Pop0, Push1, MintOpDouble) - -OPDEF(MINT_INIT_ARGLIST, "init_arglist", 3, Pop0, Push0, MintOpNoArgs) - -OPDEF(MINT_LDFLD_VT_I1, "ldfld.vt.i1", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_U1, "ldfld.vt.u1", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_I2, "ldfld.vt.i2", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_U2, "ldfld.vt.u2", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_I4, "ldfld.vt.i4", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_I8, "ldfld.vt.i8", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_R4, "ldfld.vt.r4", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_R8, "ldfld.vt.r8", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_O, "ldfld.vt.o", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_VT, "ldfld.vt.vt", 4, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_I8_UNALIGNED, "ldfld.vt.i8.unaligned", 3, Pop1, Push1, MintOpTwoShorts) -OPDEF(MINT_LDFLD_VT_R8_UNALIGNED, "ldfld.vt.r8.unaligned", 3, Pop1, Push1, MintOpTwoShorts) - -OPDEF(MINT_LDFLD_I1, "ldfld.i1", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_U1, "ldfld.u1", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_I2, "ldfld.i2", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_U2, "ldfld.u2", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_I4, "ldfld.i4", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_I8, "ldfld.i8", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_R4, "ldfld.r4", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_R8, "ldfld.r8", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_O, "ldfld.o", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_VT, "ldfld.vt", 4, Pop1, Push1, MintOpShortAndInt) -OPDEF(MINT_LDFLD_I8_UNALIGNED, "ldfld.i8.unaligned", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLD_R8_UNALIGNED, "ldfld.r8.unaligned", 2, Pop1, Push1, MintOpUShortInt) - -OPDEF(MINT_LDRMFLD, "ldrmfld", 2, Pop1, Push1, MintOpFieldToken) -OPDEF(MINT_LDRMFLD_VT, "ldrmfld.vt", 2, Pop1, Push1, MintOpUShortInt) - -OPDEF(MINT_LDFLDA, "ldflda", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDFLDA_UNSAFE, "ldflda.unsafe", 2, Pop1, Push1, MintOpUShortInt) - -OPDEF(MINT_LDLOCFLD_I1, "ldlocfld.i1", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_U1, "ldlocfld.u1", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_I2, "ldlocfld.i2", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_U2, "ldlocfld.u2", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_I4, "ldlocfld.i4", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_I8, "ldlocfld.i8", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_R4, "ldlocfld.r4", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_R8, "ldlocfld.r8", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDLOCFLD_O, "ldlocfld.o", 3, Pop0, Push1, MintOpTwoShorts) - -OPDEF(MINT_STFLD_I1, "stfld.i1", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_U1, "stfld.u1", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_I2, "stfld.i2", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_U2, "stfld.u2", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_I4, "stfld.i4", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_I8, "stfld.i8", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_R4, "stfld.r4", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_R8, "stfld.r8", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_O, "stfld.o", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_VT, "stfld.vt", 3, Pop2, Push0, MintOpTwoShorts) -OPDEF(MINT_STFLD_VT_NOREF, "stfld.vt.noref", 3, Pop2, Push0, MintOpTwoShorts) -OPDEF(MINT_STFLD_I8_UNALIGNED, "stfld.i8.unaligned", 2, Pop2, Push0, MintOpUShortInt) -OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 2, Pop2, Push0, MintOpUShortInt) - -OPDEF(MINT_STRMFLD, "strmfld", 2, Pop2, Push0, MintOpFieldToken) -OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 2, Pop2, Push0, MintOpUShortInt) - -OPDEF(MINT_STLOCFLD_I1, "stlocfld.i1", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_U1, "stlocfld.u1", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_I2, "stlocfld.i2", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_U2, "stlocfld.u2", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_I4, "stlocfld.i4", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_I8, "stlocfld.i8", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_R4, "stlocfld.r4", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_R8, "stlocfld.r8", 3, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_STLOCFLD_O, "stlocfld.o", 3, Pop1, Push0, MintOpTwoShorts) - -OPDEF(MINT_LDTSFLD_I1, "ldtsfld.i1", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_U1, "ldtsfld.u1", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_I2, "ldtsfld.i2", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_U2, "ldtsfld.u2", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_I4, "ldtsfld.i4", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_I8, "ldtsfld.i8", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_R4, "ldtsfld.r4", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_R8, "ldtsfld.r8", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDTSFLD_O, "ldtsfld.o", 3, Pop0, Push1, MintOpInt) -OPDEF(MINT_LDSSFLD, "ldssfld", 4, Pop0, Push1, MintOpFieldToken) -OPDEF(MINT_LDSSFLD_VT, "ldssfld.vt", 5, Pop0, Push1, MintOpInt) - -OPDEF(MINT_LDSFLD_I1, "ldsfld.i1", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_U1, "ldsfld.u1", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_I2, "ldsfld.i2", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_U2, "ldsfld.u2", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_I4, "ldsfld.i4", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_I8, "ldsfld.i8", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_R4, "ldsfld.r4", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_R8, "ldsfld.r8", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_O, "ldsfld.o", 3, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 5, Pop0, Push1, MintOpTwoShorts) - -OPDEF(MINT_STTSFLD_I1, "sttsfld.i1", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_U1, "sttsfld.u1", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_I2, "sttsfld.i2", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_U2, "sttsfld.u2", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_I4, "sttsfld.i4", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_I8, "sttsfld.i8", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_R4, "sttsfld.r4", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_R8, "sttsfld.r8", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STTSFLD_O, "sttsfld.o", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_STSSFLD, "stssfld", 4, Pop1, Push0, MintOpFieldToken) -OPDEF(MINT_STSSFLD_VT, "stssfld.vt", 5, Pop1, Push0, MintOpInt) -OPDEF(MINT_STSFLD_I1, "stsfld.i1", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_U1, "stsfld.u1", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_I2, "stsfld.i2", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_U2, "stsfld.u2", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_I4, "stsfld.i4", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_I8, "stsfld.i8", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_R4, "stsfld.r4", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_R8, "stsfld.r8", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_O, "stsfld.o", 3, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STSFLD_VT, "stsfld.vt", 5, Pop1, Push0, MintOpTwoShorts) -OPDEF(MINT_LDSFLDA, "ldsflda", 3, Pop0, Push1, MintOpTwoShorts) -OPDEF(MINT_LDSSFLDA, "ldssflda", 3, Pop0, Push1, MintOpInt) - -OPDEF(MINT_LDLOC_I1, "ldloc.i1", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_U1, "ldloc.u1", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_I2, "ldloc.i2", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_U2, "ldloc.u2", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_I4, "ldloc.i4", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_I8, "ldloc.i8", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_R4, "ldloc.r4", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_R8, "ldloc.r8", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_O, "ldloc.o", 2, Pop0, Push1, MintOpUShortInt) -OPDEF(MINT_LDLOC_VT, "ldloc.vt", 4, Pop0, Push1, MintOpShortAndInt) - -OPDEF(MINT_STLOC_I1, "stloc.i1", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_U1, "stloc.u1", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_I2, "stloc.i2", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_U2, "stloc.u2", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_I4, "stloc.i4", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_I8, "stloc.i8", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_R4, "stloc.r4", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_R8, "stloc.r8", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_O, "stloc.o", 2, Pop1, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_VT, "stloc.vt", 4, Pop1, Push0, MintOpShortAndInt) - -OPDEF(MINT_STLOC_NP_I4, "stloc.np.i4", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_NP_I8, "stloc.np.i8", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_NP_R4, "stloc.np.R4", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_NP_R8, "stloc.np.R8", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_STLOC_NP_O, "stloc.np.o", 2, Pop0, Push0, MintOpUShortInt) - -OPDEF(MINT_MOVLOC_1, "movloc.1", 3, Pop0, Push0, MintOpTwoShorts) -OPDEF(MINT_MOVLOC_2, "movloc.2", 3, Pop0, Push0, MintOpTwoShorts) -OPDEF(MINT_MOVLOC_4, "movloc.4", 3, Pop0, Push0, MintOpTwoShorts) -OPDEF(MINT_MOVLOC_8, "movloc.8", 3, Pop0, Push0, MintOpTwoShorts) -OPDEF(MINT_MOVLOC_VT, "movloc.vt", 5, Pop0, Push0, MintOpTwoShorts) - -OPDEF(MINT_LDLOCA_S, "ldloca.s", 2, Pop0, Push1, MintOpUShortInt) - -OPDEF(MINT_LDIND_I1_CHECK, "ldind.i1.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_U1_CHECK, "ldind.u1.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_I2_CHECK, "ldind.i2.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_U2_CHECK, "ldind.u2.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_I4_CHECK, "ldind.i4.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_U4_CHECK, "ldind.u4.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_I8_CHECK, "ldind.i8.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_I, "ldind.i", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDIND_I8, "ldind.i8", 2, Pop1, Push1, MintOpUShortInt) -OPDEF(MINT_LDIND_R4_CHECK, "ldind.r4.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_R8_CHECK, "ldind.r8.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_REF, "ldind.ref", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDIND_REF_CHECK, "ldind.ref.check", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_STIND_I1, "stind.i1", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_I2, "stind.i2", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_I4, "stind.i4", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_I8, "stind.i8", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_I, "stind.i", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_R4, "stind.r4", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_R8, "stind.r8", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_STIND_REF, "stind.ref", 1, Pop2, Push0, MintOpNoArgs) - -OPDEF(MINT_BR, "br", 3, Pop0, Push0, MintOpBranch) -OPDEF(MINT_LEAVE, "leave", 3, PopAll, Push0, MintOpBranch) -OPDEF(MINT_LEAVE_CHECK, "leave.check", 3, PopAll, Push0, MintOpBranch) -OPDEF(MINT_BR_S, "br.s", 2, Pop0, Push0, MintOpShortBranch) -OPDEF(MINT_LEAVE_S, "leave.s", 2, PopAll, Push0, MintOpShortBranch) -OPDEF(MINT_LEAVE_S_CHECK, "leave.s.check", 2, PopAll, Push0, MintOpShortBranch) -OPDEF(MINT_CALL_HANDLER, "call_handler", 4, Pop0, Push0, MintOpBranch) -OPDEF(MINT_CALL_HANDLER_S, "call_handler.s", 3, Pop0, Push0, MintOpShortBranch) - -OPDEF(MINT_THROW, "throw", 1, Pop1, Push0, MintOpNoArgs) -OPDEF(MINT_RETHROW, "rethrow", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_ENDFINALLY, "endfinally", 2, PopAll, Push0, MintOpShortInt) -OPDEF(MINT_MONO_RETHROW, "mono_rethrow", 1, Pop1, Push0, MintOpNoArgs) - -OPDEF(MINT_CHECKPOINT, "checkpoint", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_SAFEPOINT, "safepoint", 1, Pop0, Push0, MintOpNoArgs) - -OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRFALSE_R4, "brfalse.r4", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRFALSE_R8, "brfalse.r8", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRTRUE_I4, "brtrue.i4", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRTRUE_I8, "brtrue.i8", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRTRUE_R4, "brtrue.r4", 3, Pop1, Push0, MintOpBranch) -OPDEF(MINT_BRTRUE_R8, "brtrue.r8", 3, Pop1, Push0, MintOpBranch) - -OPDEF(MINT_BRFALSE_I4_S, "brfalse.i4.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRFALSE_I8_S, "brfalse.i8.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRFALSE_R4_S, "brfalse.r4.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRFALSE_R8_S, "brfalse.r8.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRTRUE_I4_S, "brtrue.i4.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRTRUE_I8_S, "brtrue.i8.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRTRUE_R4_S, "brtrue.r4.s", 2, Pop1, Push0, MintOpShortBranch) -OPDEF(MINT_BRTRUE_R8_S, "brtrue.r8.s", 2, Pop1, Push0, MintOpShortBranch) - -OPDEF(MINT_BEQ_I4, "beq.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BEQ_I8, "beq.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BEQ_R4, "beq.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BEQ_R8, "beq.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_I4, "bge.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_I8, "bge.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_R4, "bge.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_R8, "bge.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_I4, "bgt.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_I8, "bgt.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_R4, "bgt.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_R8, "bgt.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_I4, "blt.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_I8, "blt.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_R4, "blt.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_R8, "blt.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_I4, "ble.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_I8, "ble.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_R4, "ble.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_R8, "ble.r8", 3, Pop2, Push0, MintOpBranch) - -OPDEF(MINT_BNE_UN_I4, "bne.un.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BNE_UN_I8, "bne.un.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BNE_UN_R4, "bne.un.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BNE_UN_R8, "bne.un.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_UN_I4, "bge.un.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_UN_I8, "bge.un.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_UN_R4, "bge.un.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGE_UN_R8, "bge.un.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_UN_I4, "bgt.un.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_UN_I8, "bgt.un.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_UN_R4, "bgt.un.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BGT_UN_R8, "bgt.un.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_UN_I4, "ble.un.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_UN_I8, "ble.un.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_UN_R4, "ble.un.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLE_UN_R8, "ble.un.r8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_UN_I4, "blt.un.i4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_UN_I8, "blt.un.i8", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_UN_R4, "blt.un.r4", 3, Pop2, Push0, MintOpBranch) -OPDEF(MINT_BLT_UN_R8, "blt.un.r8", 3, Pop2, Push0, MintOpBranch) - -OPDEF(MINT_BEQ_I4_S, "beq.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BEQ_I8_S, "beq.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BEQ_R4_S, "beq.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BEQ_R8_S, "beq.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_I4_S, "bge.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_I8_S, "bge.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_R4_S, "bge.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_R8_S, "bge.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_I4_S, "bgt.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_I8_S, "bgt.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_R4_S, "bgt.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_R8_S, "bgt.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_I4_S, "blt.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_I8_S, "blt.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_R4_S, "blt.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_R8_S, "blt.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_I4_S, "ble.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_I8_S, "ble.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_R4_S, "ble.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_R8_S, "ble.r8.s", 2, Pop2, Push0, MintOpShortBranch) - -OPDEF(MINT_BNE_UN_I4_S, "bne.un.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BNE_UN_I8_S, "bne.un.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BNE_UN_R4_S, "bne.un.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BNE_UN_R8_S, "bne.un.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_UN_I4_S, "bge.un.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_UN_I8_S, "bge.un.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_UN_R4_S, "bge.un.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGE_UN_R8_S, "bge.un.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_UN_I4_S, "bgt.un.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_UN_I8_S, "bgt.un.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_UN_R4_S, "bgt.un.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BGT_UN_R8_S, "bgt.un.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_UN_I4_S, "ble.un.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_UN_I8_S, "ble.un.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_UN_R4_S, "ble.un.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLE_UN_R8_S, "ble.un.r8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_UN_I4_S, "blt.un.i4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_UN_R4_S, "blt.un.r4.s", 2, Pop2, Push0, MintOpShortBranch) -OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 2, Pop2, Push0, MintOpShortBranch) - -OPDEF(MINT_SWITCH, "switch", 0, Pop1, Push0, MintOpSwitch) - -OPDEF(MINT_LDSTR, "ldstr", 2, Pop0, Push1, MintOpMethodToken) /* not really */ -OPDEF(MINT_LDSTR_TOKEN, "ldstr.token", 2, Pop0, Push1, MintOpMethodToken) /* not really */ - -OPDEF(MINT_JMP, "jmp", 2, Pop0, Push0, MintOpMethodToken) - -OPDEF(MINT_ENDFILTER, "endfilter", 1, Pop0, Push0, MintOpNoArgs) - -OPDEF(MINT_NEWOBJ, "newobj", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_NEWOBJ_ARRAY, "newobj_array", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_NEWOBJ_STRING, "newobj_string", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_NEWOBJ_FAST, "newobj_fast", 5, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_NEWOBJ_VT_FAST, "newobj_vt_fast", 5, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_NEWOBJ_MAGIC, "newobj_magic", 2, Pop0, Push0, MintOpMethodToken) -OPDEF(MINT_INITOBJ, "initobj", 3, Pop1, Push0, MintOpInt) -OPDEF(MINT_CASTCLASS, "castclass", 2, Pop0, Push0, MintOpClassToken) -OPDEF(MINT_ISINST, "isinst", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_CASTCLASS_INTERFACE, "castclass.interface", 2, Pop0, Push0, MintOpClassToken) -OPDEF(MINT_ISINST_INTERFACE, "isinst.interface", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_CASTCLASS_COMMON, "castclass.common", 2, Pop0, Push0, MintOpClassToken) -OPDEF(MINT_ISINST_COMMON, "isinst.common", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_NEWARR, "newarr", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_BOX, "box", 2, Pop1, Push1, MintOpShortInt) -OPDEF(MINT_BOX_VT, "box.vt", 2, Pop1, Push1, MintOpShortInt) -OPDEF(MINT_BOX_PTR, "box.ptr", 3, Pop0, Push0, MintOpTwoShorts) -OPDEF(MINT_BOX_NULLABLE_PTR, "box.nullable.ptr", 3, Pop0, Push0, MintOpTwoShorts) -OPDEF(MINT_UNBOX, "unbox", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_LDTOKEN, "ldtoken", 2, Pop0, Push1, MintOpClassToken) /* not really */ -OPDEF(MINT_LDFTN, "ldftn", 2, Pop0, Push1, MintOpMethodToken) -OPDEF(MINT_LDFTN_DYNAMIC, "ldftn.dynamic", 1, Pop1, Push1, MintOpMethodToken) -OPDEF(MINT_LDVIRTFTN, "ldvirtftn", 2, Pop1, Push1, MintOpMethodToken) -OPDEF(MINT_CPOBJ, "cpobj", 2, Pop2, Push0, MintOpClassToken) -OPDEF(MINT_CPOBJ_VT, "cpobj.vt", 2, Pop2, Push0, MintOpClassToken) -OPDEF(MINT_LDOBJ_VT, "ldobj.vt", 3, Pop1, Push1, MintOpInt) -OPDEF(MINT_STOBJ_VT, "stobj.vt", 2, Pop2, Push0, MintOpClassToken) -OPDEF(MINT_CPBLK, "cpblk", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_INITBLK, "initblk", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_LOCALLOC, "localloc", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INITLOCALS, "initlocals", 3, Pop0, Push0, MintOpTwoShorts) - -OPDEF(MINT_LDELEM_I, "ldelem.i", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I1, "ldelem.i1", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_U1, "ldelem.u1", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I2, "ldelem.i2", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_U2, "ldelem.u2", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I4, "ldelem.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_U4, "ldelem.u4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_I8, "ldelem.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_R4, "ldelem.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_R8, "ldelem.r8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_REF, "ldelem.ref", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_LDELEM_VT, "ldelem.vt", 3, Pop2, Push1, MintOpInt) - -OPDEF(MINT_LDELEMA1, "ldelema1", 3, Pop2, Push1, MintOpInt) -OPDEF(MINT_LDELEMA, "ldelema", 4, VarPop, Push1, MintOpTwoShorts) -OPDEF(MINT_LDELEMA_TC, "ldelema.tc", 3, VarPop, Push1, MintOpTwoShorts) - -OPDEF(MINT_STELEM_I, "stelem.i", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_I1, "stelem.i1", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_U1, "stelem.u1", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_I2, "stelem.i2", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_U2, "stelem.u2", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_I4, "stelem.i4", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_I8, "stelem.i8", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_R4, "stelem.r4", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_R8, "stelem.r8", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_REF, "stelem.ref", 1, Pop3, Push0, MintOpNoArgs) -OPDEF(MINT_STELEM_VT, "stelem.vt", 4, Pop3, Push0, MintOpShortAndInt) - -OPDEF(MINT_LDLEN, "ldlen", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LDLEN_SPAN, "ldlen.span", 2, Pop1, Push1, MintOpShortInt) - -OPDEF(MINT_GETITEM_SPAN, "getitem.span", 4, Pop2, Push1, MintOpShortAndInt) +OPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_NIY, "niy", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_BREAK, "break", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_BREAKPOINT, "breakpoint", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_LDNULL, "ldnull", 2, 1, 0, MintOpNoArgs) + +OPDEF(MINT_RET, "ret", 2, 0, 1, MintOpNoArgs) +OPDEF(MINT_RET_VOID, "ret.void", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_RET_VT, "ret.vt", 3, 0, 1, MintOpShortInt) +OPDEF(MINT_RET_LOCALLOC, "ret.localloc", 2, 0, 1, MintOpNoArgs) +OPDEF(MINT_RET_VOID_LOCALLOC, "ret.void.localloc", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_RET_VT_LOCALLOC, "ret.vt.localloc", 3, 0, 1, MintOpShortInt) + +OPDEF(MINT_LDC_I4_M1, "ldc.i4.m1", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_0, "ldc.i4.0", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_1, "ldc.i4.1", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_2, "ldc.i4.2", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_3, "ldc.i4.3", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_4, "ldc.i4.4", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_5, "ldc.i4.5", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_6, "ldc.i4.6", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_7, "ldc.i4.7", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_LDC_I4_8, "ldc.i4.8", 2, 1, 0, MintOpNoArgs) + +OPDEF(MINT_LDC_I4_S, "ldc.i4.s", 3, 1, 0, MintOpShortInt) +OPDEF(MINT_LDC_I4, "ldc.i4", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDC_I8, "ldc.i8", 6, 1, 0, MintOpLongInt) +OPDEF(MINT_LDC_I8_S, "ldc.i8.s", 3, 1, 0, MintOpShortInt) + +OPDEF(MINT_LDC_R4, "ldc.r4", 4, 1, 0, MintOpFloat) +OPDEF(MINT_LDC_R8, "ldc.r8", 6, 1, 0, MintOpDouble) + +OPDEF(MINT_INIT_ARGLIST, "init_arglist", 3, 1, 0, MintOpNoArgs) + +OPDEF(MINT_LDFLD_VT_I1, "ldfld.vt.i1", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_U1, "ldfld.vt.u1", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_I2, "ldfld.vt.i2", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_U2, "ldfld.vt.u2", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_I4, "ldfld.vt.i4", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_I8, "ldfld.vt.i8", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_R4, "ldfld.vt.r4", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_R8, "ldfld.vt.r8", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_O, "ldfld.vt.o", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_VT, "ldfld.vt.vt", 5, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_I8_UNALIGNED, "ldfld.vt.i8.unaligned", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_VT_R8_UNALIGNED, "ldfld.vt.r8.unaligned", 4, 1, 1, MintOpShortInt) + +OPDEF(MINT_LDFLD_I1, "ldfld.i1", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_U1, "ldfld.u1", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_I2, "ldfld.i2", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_U2, "ldfld.u2", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_I4, "ldfld.i4", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_I8, "ldfld.i8", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_R4, "ldfld.r4", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_R8, "ldfld.r8", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_O, "ldfld.o", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_VT, "ldfld.vt", 5, 1, 1, MintOpShortInt) +OPDEF(MINT_LDFLD_I8_UNALIGNED, "ldfld.i8.unaligned", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLD_R8_UNALIGNED, "ldfld.r8.unaligned", 4, 1, 1, MintOpUShortInt) + +OPDEF(MINT_LDRMFLD, "ldrmfld", 4, 1, 1, MintOpFieldToken) +OPDEF(MINT_LDRMFLD_VT, "ldrmfld.vt", 4, 1, 1, MintOpUShortInt) + +OPDEF(MINT_LDFLDA, "ldflda", 4, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDFLDA_UNSAFE, "ldflda.unsafe", 4, 1, 1, MintOpUShortInt) + +OPDEF(MINT_STFLD_I1, "stfld.i1", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_U1, "stfld.u1", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_I2, "stfld.i2", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_U2, "stfld.u2", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_I4, "stfld.i4", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_I8, "stfld.i8", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_R4, "stfld.r4", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_R8, "stfld.r8", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_O, "stfld.o", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_VT, "stfld.vt", 5, 0, 2, MintOpTwoShorts) +OPDEF(MINT_STFLD_VT_NOREF, "stfld.vt.noref", 5, 0, 2, MintOpTwoShorts) +OPDEF(MINT_STFLD_I8_UNALIGNED, "stfld.i8.unaligned", 4, 0, 2, MintOpUShortInt) +OPDEF(MINT_STFLD_R8_UNALIGNED, "stfld.r8.unaligned", 4, 0, 2, MintOpUShortInt) + +OPDEF(MINT_STRMFLD, "strmfld", 4, 0, 2, MintOpFieldToken) +OPDEF(MINT_STRMFLD_VT, "strmfld.vt", 4, 0, 2, MintOpUShortInt) + +OPDEF(MINT_LDTSFLD_I1, "ldtsfld.i1", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_U1, "ldtsfld.u1", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_I2, "ldtsfld.i2", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_U2, "ldtsfld.u2", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_I4, "ldtsfld.i4", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_I8, "ldtsfld.i8", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_R4, "ldtsfld.r4", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_R8, "ldtsfld.r8", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDTSFLD_O, "ldtsfld.o", 4, 1, 0, MintOpInt) +OPDEF(MINT_LDSSFLD, "ldssfld", 5, 1, 0, MintOpFieldToken) +OPDEF(MINT_LDSSFLD_VT, "ldssfld.vt", 5, 1, 0, MintOpInt) + +OPDEF(MINT_LDSFLD_I1, "ldsfld.i1", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_U1, "ldsfld.u1", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_I2, "ldsfld.i2", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_U2, "ldsfld.u2", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_I4, "ldsfld.i4", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_I8, "ldsfld.i8", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_R4, "ldsfld.r4", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_R8, "ldsfld.r8", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_O, "ldsfld.o", 4, 1, 0, MintOpUShortInt) +OPDEF(MINT_LDSFLD_VT, "ldsfld.vt", 5, 1, 0, MintOpTwoShorts) + +OPDEF(MINT_STTSFLD_I1, "sttsfld.i1", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_U1, "sttsfld.u1", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_I2, "sttsfld.i2", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_U2, "sttsfld.u2", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_I4, "sttsfld.i4", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_I8, "sttsfld.i8", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_R4, "sttsfld.r4", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_R8, "sttsfld.r8", 4, 0, 1, MintOpInt) +OPDEF(MINT_STTSFLD_O, "sttsfld.o", 4, 0, 1, MintOpInt) +OPDEF(MINT_STSSFLD, "stssfld", 5, 0, 1, MintOpFieldToken) +OPDEF(MINT_STSSFLD_VT, "stssfld.vt", 5, 0, 1, MintOpInt) + +OPDEF(MINT_STSFLD_I1, "stsfld.i1", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_U1, "stsfld.u1", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_I2, "stsfld.i2", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_U2, "stsfld.u2", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_I4, "stsfld.i4", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_I8, "stsfld.i8", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_R4, "stsfld.r4", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_R8, "stsfld.r8", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_O, "stsfld.o", 4, 0, 1, MintOpUShortInt) +OPDEF(MINT_STSFLD_VT, "stsfld.vt", 5, 0, 1, MintOpTwoShorts) +OPDEF(MINT_LDSFLDA, "ldsflda", 4, 1, 0, MintOpTwoShorts) +OPDEF(MINT_LDSSFLDA, "ldssflda", 4, 1, 0, MintOpInt) + +OPDEF(MINT_MOV_I1, "mov.i1", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MOV_U1, "mov.u1", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MOV_I2, "mov.i2", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MOV_U2, "mov.u2", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MOV_4, "mov.4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MOV_8, "mov.8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MOV_VT, "mov.vt", 4, 1, 1, MintOpShortInt) + +OPDEF(MINT_LDLOCA_S, "ldloca.s", 3, 1, 0, MintOpUShortInt) + +OPDEF(MINT_LDIND_I1_CHECK, "ldind.i1.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U1_CHECK, "ldind.u1.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I2_CHECK, "ldind.i2.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U2_CHECK, "ldind.u2.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I4_CHECK, "ldind.i4.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_U4_CHECK, "ldind.u4.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I8_CHECK, "ldind.i8.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_I, "ldind.i", 3, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDIND_I8, "ldind.i8", 3, 1, 1, MintOpUShortInt) +OPDEF(MINT_LDIND_R4_CHECK, "ldind.r4.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_R8_CHECK, "ldind.r8.check", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_REF, "ldind.ref", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDIND_REF_CHECK, "ldind.ref.check", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_STIND_I1, "stind.i1", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_I2, "stind.i2", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_I4, "stind.i4", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_I8, "stind.i8", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_I, "stind.i", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_R4, "stind.r4", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_R8, "stind.r8", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_STIND_REF, "stind.ref", 3, 0, 2, MintOpNoArgs) + +OPDEF(MINT_BR, "br", 3, 0, 0, MintOpBranch) +OPDEF(MINT_LEAVE, "leave", 3, 0, 0, MintOpBranch) +OPDEF(MINT_LEAVE_CHECK, "leave.check", 3, 0, 0, MintOpBranch) +OPDEF(MINT_BR_S, "br.s", 2, 0, 0, MintOpShortBranch) +OPDEF(MINT_LEAVE_S, "leave.s", 2, 0, 0, MintOpShortBranch) +OPDEF(MINT_LEAVE_S_CHECK, "leave.s.check", 2, 0, 0, MintOpShortBranch) +OPDEF(MINT_CALL_HANDLER, "call_handler", 4, 0, 0, MintOpBranch) +OPDEF(MINT_CALL_HANDLER_S, "call_handler.s", 3, 0, 0, MintOpShortBranch) + +OPDEF(MINT_THROW, "throw", 2, 0, 1, MintOpNoArgs) +OPDEF(MINT_RETHROW, "rethrow", 2, 0, 0, MintOpUShortInt) +OPDEF(MINT_ENDFINALLY, "endfinally", 2, 0, 0, MintOpShortInt) +OPDEF(MINT_MONO_RETHROW, "mono_rethrow", 2, 0, 1, MintOpNoArgs) + +OPDEF(MINT_CHECKPOINT, "checkpoint", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_SAFEPOINT, "safepoint", 1, 0, 0, MintOpNoArgs) + +OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRFALSE_R4, "brfalse.r4", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRFALSE_R8, "brfalse.r8", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRTRUE_I4, "brtrue.i4", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRTRUE_I8, "brtrue.i8", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRTRUE_R4, "brtrue.r4", 4, 0, 1, MintOpBranch) +OPDEF(MINT_BRTRUE_R8, "brtrue.r8", 4, 0, 1, MintOpBranch) + +OPDEF(MINT_BRFALSE_I4_S, "brfalse.i4.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I8_S, "brfalse.i8.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_R4_S, "brfalse.r4.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_R8_S, "brfalse.r8.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I4_S, "brtrue.i4.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I8_S, "brtrue.i8.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_R4_S, "brtrue.r4.s", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_R8_S, "brtrue.r8.s", 3, 0, 1, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4, "beq.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BEQ_I8, "beq.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BEQ_R4, "beq.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BEQ_R8, "beq.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_I4, "bge.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_I8, "bge.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_R4, "bge.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_R8, "bge.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_I4, "bgt.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_I8, "bgt.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_R4, "bgt.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_R8, "bgt.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_I4, "blt.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_I8, "blt.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_R4, "blt.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_R8, "blt.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_I4, "ble.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_I8, "ble.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_R4, "ble.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_R8, "ble.r8", 5, 0, 2, MintOpBranch) + +OPDEF(MINT_BNE_UN_I4, "bne.un.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BNE_UN_I8, "bne.un.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BNE_UN_R4, "bne.un.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BNE_UN_R8, "bne.un.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_UN_I4, "bge.un.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_UN_I8, "bge.un.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_UN_R4, "bge.un.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGE_UN_R8, "bge.un.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_UN_I4, "bgt.un.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_UN_I8, "bgt.un.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_UN_R4, "bgt.un.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BGT_UN_R8, "bgt.un.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_UN_I4, "ble.un.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_UN_I8, "ble.un.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_UN_R4, "ble.un.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLE_UN_R8, "ble.un.r8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_UN_I4, "blt.un.i4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_UN_I8, "blt.un.i8", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_UN_R4, "blt.un.r4", 5, 0, 2, MintOpBranch) +OPDEF(MINT_BLT_UN_R8, "blt.un.r8", 5, 0, 2, MintOpBranch) + +OPDEF(MINT_BEQ_I4_S, "beq.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_I8_S, "beq.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_R4_S, "beq.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_R8_S, "beq.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I4_S, "bge.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I8_S, "bge.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_R4_S, "bge.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_R8_S, "bge.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I4_S, "bgt.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I8_S, "bgt.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_R4_S, "bgt.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_R8_S, "bgt.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I4_S, "blt.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I8_S, "blt.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_R4_S, "blt.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_R8_S, "blt.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I4_S, "ble.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I8_S, "ble.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_R4_S, "ble.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_R8_S, "ble.r8.s", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BNE_UN_I4_S, "bne.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_I8_S, "bne.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_R4_S, "bne.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_R8_S, "bne.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I4_S, "bge.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I8_S, "bge.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_R4_S, "bge.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_R8_S, "bge.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I4_S, "bgt.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I8_S, "bgt.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_R4_S, "bgt.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_R8_S, "bgt.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I4_S, "ble.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I8_S, "ble.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_R4_S, "ble.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_R8_S, "ble.un.r8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I4_S, "blt.un.i4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_R4_S, "blt.un.r4.s", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_SWITCH, "switch", 0, 0, 1, MintOpSwitch) + +OPDEF(MINT_LDSTR, "ldstr", 3, 1, 0, MintOpShortInt) +OPDEF(MINT_LDSTR_TOKEN, "ldstr.token", 3, 1, 0, MintOpShortInt) + +OPDEF(MINT_JMP, "jmp", 2, 0, 0, MintOpMethodToken) + +OPDEF(MINT_ENDFILTER, "endfilter", 2, 0, 1, MintOpNoArgs) + +OPDEF(MINT_NEWOBJ, "newobj", 4, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_NEWOBJ_ARRAY, "newobj_array", 4, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_NEWOBJ_STRING, "newobj_string", 4, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_NEWOBJ_FAST, "newobj_fast", 6, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_NEWOBJ_VT_FAST, "newobj_vt_fast", 6, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_INITOBJ, "initobj", 3, 0, 1, MintOpShortInt) +OPDEF(MINT_CASTCLASS, "castclass", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_ISINST, "isinst", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_CASTCLASS_INTERFACE, "castclass.interface", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_ISINST_INTERFACE, "isinst.interface", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_CASTCLASS_COMMON, "castclass.common", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_ISINST_COMMON, "isinst.common", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_NEWARR, "newarr", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_BOX, "box", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_BOX_VT, "box.vt", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_BOX_PTR, "box.ptr", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_BOX_NULLABLE_PTR, "box.nullable.ptr", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_UNBOX, "unbox", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_LDTOKEN, "ldtoken", 3, 1, 0, MintOpShortInt) +OPDEF(MINT_LDFTN, "ldftn", 3, 1, 0, MintOpMethodToken) +OPDEF(MINT_LDFTN_DYNAMIC, "ldftn.dynamic", 3, 1, 1, MintOpMethodToken) +OPDEF(MINT_LDVIRTFTN, "ldvirtftn", 4, 1, 1, MintOpMethodToken) +OPDEF(MINT_CPOBJ, "cpobj", 4, 0, 2, MintOpClassToken) +OPDEF(MINT_CPOBJ_VT, "cpobj.vt", 4, 0, 2, MintOpClassToken) +OPDEF(MINT_LDOBJ_VT, "ldobj.vt", 4, 1, 1, MintOpShortInt) +OPDEF(MINT_STOBJ_VT, "stobj.vt", 4, 0, 2, MintOpClassToken) +OPDEF(MINT_CPBLK, "cpblk", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_INITBLK, "initblk", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_LOCALLOC, "localloc", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INITLOCALS, "initlocals", 3, 0, 0, MintOpTwoShorts) + +OPDEF(MINT_LDELEM_I, "ldelem.i", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_I1, "ldelem.i1", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_U1, "ldelem.u1", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_I2, "ldelem.i2", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_U2, "ldelem.u2", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_I4, "ldelem.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_U4, "ldelem.u4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_I8, "ldelem.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_R4, "ldelem.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_R8, "ldelem.r8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_REF, "ldelem.ref", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_LDELEM_VT, "ldelem.vt", 5, 1, 2, MintOpShortInt) + +OPDEF(MINT_LDELEMA1, "ldelema1", 5, 1, 2, MintOpShortInt) +OPDEF(MINT_LDELEMA, "ldelema", 4, CallArgs, 0, MintOpTwoShorts) +OPDEF(MINT_LDELEMA_TC, "ldelema.tc", 3, CallArgs, 0, MintOpTwoShorts) + +OPDEF(MINT_STELEM_I, "stelem.i", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_I1, "stelem.i1", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_U1, "stelem.u1", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_I2, "stelem.i2", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_U2, "stelem.u2", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_I4, "stelem.i4", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_I8, "stelem.i8", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_R4, "stelem.r4", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_R8, "stelem.r8", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_REF, "stelem.ref", 4, 0, 3, MintOpNoArgs) +OPDEF(MINT_STELEM_VT, "stelem.vt", 6, 0, 3, MintOpTwoShorts) + +OPDEF(MINT_LDLEN, "ldlen", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LDLEN_SPAN, "ldlen.span", 4, 1, 1, MintOpShortInt) + +OPDEF(MINT_GETITEM_SPAN, "getitem.span", 7, 1, 2, MintOpTwoShorts) /* binops */ -OPDEF(MINT_ADD_I4, "add.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_ADD_I8, "add.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_ADD_R4, "add.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_ADD_R8, "add.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_SUB_I4, "sub.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SUB_I8, "sub.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SUB_R4, "sub.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SUB_R8, "sub.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_MUL_I4, "mul.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_MUL_I8, "mul.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_MUL_R4, "mul.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_MUL_R8, "mul.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_DIV_I4, "div.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_DIV_I8, "div.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_DIV_R4, "div.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_DIV_R8, "div.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_DIV_UN_I4, "div.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_DIV_UN_I8, "div.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_ADD_OVF_I4, "add.ovf.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_ADD_OVF_I8, "add.ovf.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_ADD_OVF_UN_I4, "add.ovf.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_ADD_OVF_UN_I8, "add.ovf.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_MUL_OVF_I4, "mul.ovf.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_MUL_OVF_I8, "mul.ovf.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_MUL_OVF_UN_I4, "mul.ovf.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_MUL_OVF_UN_I8, "mul.ovf.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_SUB_OVF_I4, "sub.ovf.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SUB_OVF_I8, "sub.ovf.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_SUB_OVF_UN_I4, "sub.ovf.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SUB_OVF_UN_I8, "sub.ovf.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_AND_I4, "and.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_AND_I8, "and.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_OR_I4, "or.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_OR_I8, "or.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_XOR_I4, "xor.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_XOR_I8, "xor.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_REM_I4, "rem.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_REM_I8, "rem.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_REM_R4, "rem.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_REM_R8, "rem.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_REM_UN_I4, "rem.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_REM_UN_I8, "rem.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_SHR_UN_I4, "shr.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SHR_UN_I8, "shr.un.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SHL_I4, "shl.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SHL_I8, "shl.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SHR_I4, "shr.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SHR_I8, "shr.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CEQ_I4, "ceq.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CEQ_I8, "ceq.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CEQ_R4, "ceq.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CEQ_R8, "ceq.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CNE_I4, "cne.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CNE_I8, "cne.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CNE_R4, "cne.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CNE_R8, "cne.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CGT_I4, "cgt.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGT_I8, "cgt.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGT_R4, "cgt.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGT_R8, "cgt.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CGE_I4, "cge.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGE_I8, "cge.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGE_R4, "cge.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGE_R8, "cge.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CGE_UN_I4, "cge.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGE_UN_I8, "cge.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CGT_UN_I4, "cgt.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGT_UN_I8, "cgt.un.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGT_UN_R4, "cgt.un.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CGT_UN_R8, "cgt.un.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CLT_I4, "clt.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLT_I8, "clt.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLT_R4, "clt.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLT_R8, "clt.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CLE_I4, "cle.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLE_I8, "cle.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLE_R4, "cle.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLE_R8, "cle.r8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CLE_UN_I4, "cle.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLE_UN_I8, "cle.un.i8", 1, Pop2, Push1, MintOpNoArgs) - -OPDEF(MINT_CLT_UN_I4, "clt.un.i4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLT_UN_I8, "clt.un.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLT_UN_R4, "clt.un.r4", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CLT_UN_R8, "clt.un.r8", 1, Pop2, Push1, MintOpNoArgs) +OPDEF(MINT_ADD_I4, "add.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_ADD_I8, "add.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_ADD_R4, "add.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_ADD_R8, "add.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_SUB_I4, "sub.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SUB_I8, "sub.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SUB_R4, "sub.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SUB_R8, "sub.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_MUL_I4, "mul.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_MUL_I8, "mul.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_MUL_R4, "mul.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_MUL_R8, "mul.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_DIV_I4, "div.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_DIV_I8, "div.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_DIV_R4, "div.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_DIV_R8, "div.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_DIV_UN_I4, "div.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_DIV_UN_I8, "div.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_ADD_OVF_I4, "add.ovf.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_ADD_OVF_I8, "add.ovf.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_ADD_OVF_UN_I4, "add.ovf.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_ADD_OVF_UN_I8, "add.ovf.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_MUL_OVF_I4, "mul.ovf.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_MUL_OVF_I8, "mul.ovf.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_MUL_OVF_UN_I4, "mul.ovf.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_MUL_OVF_UN_I8, "mul.ovf.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_SUB_OVF_I4, "sub.ovf.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SUB_OVF_I8, "sub.ovf.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_SUB_OVF_UN_I4, "sub.ovf.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SUB_OVF_UN_I8, "sub.ovf.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_AND_I4, "and.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_AND_I8, "and.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_OR_I4, "or.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_OR_I8, "or.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_XOR_I4, "xor.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_XOR_I8, "xor.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_REM_I4, "rem.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_REM_I8, "rem.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_REM_R4, "rem.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_REM_R8, "rem.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_REM_UN_I4, "rem.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_REM_UN_I8, "rem.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_SHR_UN_I4, "shr.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SHR_UN_I8, "shr.un.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SHL_I4, "shl.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SHL_I8, "shl.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SHR_I4, "shr.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SHR_I8, "shr.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CEQ_I4, "ceq.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CEQ_I8, "ceq.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CEQ_R4, "ceq.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CEQ_R8, "ceq.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CNE_I4, "cne.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CNE_I8, "cne.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CNE_R4, "cne.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CNE_R8, "cne.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CGT_I4, "cgt.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGT_I8, "cgt.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGT_R4, "cgt.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGT_R8, "cgt.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CGE_I4, "cge.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGE_I8, "cge.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGE_R4, "cge.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGE_R8, "cge.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CGE_UN_I4, "cge.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGE_UN_I8, "cge.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CGT_UN_I4, "cgt.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGT_UN_I8, "cgt.un.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGT_UN_R4, "cgt.un.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CGT_UN_R8, "cgt.un.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CLT_I4, "clt.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLT_I8, "clt.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLT_R4, "clt.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLT_R8, "clt.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CLE_I4, "cle.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLE_I8, "cle.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLE_R4, "cle.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLE_R8, "cle.r8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CLE_UN_I4, "cle.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLE_UN_I8, "cle.un.i8", 4, 1, 2, MintOpNoArgs) + +OPDEF(MINT_CLT_UN_I4, "clt.un.i4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLT_UN_I8, "clt.un.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLT_UN_R4, "clt.un.r4", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CLT_UN_R8, "clt.un.r8", 4, 1, 2, MintOpNoArgs) /* binops end */ -OPDEF(MINT_LOCADD1_I4, "locadd1.i4", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_LOCADD1_I8, "locadd1.i8", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_LOCSUB1_I4, "locsub1.i4", 2, Pop0, Push0, MintOpUShortInt) -OPDEF(MINT_LOCSUB1_I8, "locsub1.i8", 2, Pop0, Push0, MintOpUShortInt) - /* unops */ -OPDEF(MINT_ADD1_I4, "add1.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ADD1_I8, "add1.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_SUB1_I4, "sub1.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_SUB1_I8, "sub1.i8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_NEG_I4, "neg.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_NEG_I8, "neg.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_NEG_R4, "neg.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_NEG_R8, "neg.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_NOT_I4, "not.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_NOT_I8, "not.i8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_R_UN_I4, "conv.r.un.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_R_UN_I8, "conv.r.un.i8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_I1_I4, "conv.i1.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I1_I8, "conv.i1.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I1_R4, "conv.i1.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I1_R8, "conv.i1.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_U1_I4, "conv.u1.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U1_I8, "conv.u1.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U1_R4, "conv.u1.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U1_R8, "conv.u1.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_I2_I4, "conv.i2.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I2_I8, "conv.i2.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I2_R4, "conv.i2.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I2_R8, "conv.i2.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_U2_I4, "conv.u2.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U2_I8, "conv.u2.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U2_R4, "conv.u2.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U2_R8, "conv.u2.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_I4_I8, "conv.i4.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I4_R4, "conv.i4.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I4_R8, "conv.i4.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_U4_I8, "conv.u4.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U4_R4, "conv.u4.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U4_R8, "conv.u4.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_I8_I4, "conv.i8.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I8_U4, "conv.i8.u4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I8_R4, "conv.i8.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_I8_R8, "conv.i8.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_R4_I4, "conv.r4.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_R4_I8, "conv.r4.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_R4_R8, "conv.r4.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_R8_I4, "conv.r8.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_R8_I8, "conv.r8.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_R8_R4, "conv.r8.r4", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_U8_R4, "conv.u8.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_U8_R8, "conv.u8.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I1_I4, "conv.ovf.i1.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_I8, "conv.ovf.i1.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_R4, "conv.ovf.i1.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_R8, "conv.ovf.i1.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I1_U4, "conv.ovf.i1.u4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_U8, "conv.ovf.i1.u8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_UN_R4, "conv.ovf.i1.un.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I1_UN_R8, "conv.ovf.i1.un.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U1_I4, "conv.ovf.u1.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U1_I8, "conv.ovf.u1.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U1_R4, "conv.ovf.u1.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U1_R8, "conv.ovf.u1.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I2_I4, "conv.ovf.i2.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_I8, "conv.ovf.i2.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_R4, "conv.ovf.i2.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_R8, "conv.ovf.i2.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I2_U4, "conv.ovf.i2.u4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_U8, "conv.ovf.i2.u8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_UN_R4, "conv.ovf.i2.un.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I2_UN_R8, "conv.ovf.i2.un.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U2_I4, "conv.ovf.u2.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U2_I8, "conv.ovf.u2.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U2_R4, "conv.ovf.u2.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U2_R8, "conv.ovf.u2.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I4_U4, "conv.ovf.i4.u4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_I8, "conv.ovf.i4.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_U8, "conv.ovf.i4.u8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_R4, "conv.ovf.i4.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I4_R8, "conv.ovf.i4.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I4_UN_R8, "conv.ovf.i4.un.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U4_I4, "conv.ovf.u4.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U4_I8, "conv.ovf.u4.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U4_R4, "conv.ovf.u4.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U4_R8, "conv.ovf.u4.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I8_U8, "conv.ovf.i8.u8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I8_R4, "conv.ovf.i8.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I8_R8, "conv.ovf.i8.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_I8_UN_R8, "conv.ovf.i8.un.r8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_I8_UN_R4, "conv.ovf.i8.un.r4", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_OVF_U8_I4, "conv.ovf.u8.i4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U8_I8, "conv.ovf.u8.i8", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U8_R4, "conv.ovf.u8.r4", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CONV_OVF_U8_R8, "conv.ovf.u8.r8", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CEQ0_I4, "ceq0.i4", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_CONV_I4_I8_SP, "conv.i4.i8.sp", 1, Pop2, Push2, MintOpNoArgs) /* special for narrowing sp[-2] on 64 bits */ -OPDEF(MINT_CONV_I8_I4_SP, "conv.i8.i4.sp", 1, Pop2, Push2, MintOpNoArgs) /* special for widening sp[-2] on 64 bits */ -OPDEF(MINT_CONV_R8_R4_SP, "conv.r8.r4.sp", 1, Pop2, Push2, MintOpNoArgs) +OPDEF(MINT_ADD1_I4, "add1.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ADD1_I8, "add1.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_SUB1_I4, "sub1.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_SUB1_I8, "sub1.i8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_NEG_I4, "neg.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_NEG_I8, "neg.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_NEG_R4, "neg.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_NEG_R8, "neg.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_NOT_I4, "not.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_NOT_I8, "not.i8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_R_UN_I4, "conv.r.un.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_R_UN_I8, "conv.r.un.i8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I1_I4, "conv.i1.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I1_I8, "conv.i1.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I1_R4, "conv.i1.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I1_R8, "conv.i1.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U1_I4, "conv.u1.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U1_I8, "conv.u1.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U1_R4, "conv.u1.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U1_R8, "conv.u1.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I2_I4, "conv.i2.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I2_I8, "conv.i2.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I2_R4, "conv.i2.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I2_R8, "conv.i2.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U2_I4, "conv.u2.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U2_I8, "conv.u2.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U2_R4, "conv.u2.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U2_R8, "conv.u2.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I4_I8, "conv.i4.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I4_R4, "conv.i4.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I4_R8, "conv.i4.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U4_I8, "conv.u4.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U4_R4, "conv.u4.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U4_R8, "conv.u4.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_I8_I4, "conv.i8.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I8_U4, "conv.i8.u4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I8_R4, "conv.i8.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_I8_R8, "conv.i8.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_R4_I4, "conv.r4.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_R4_I8, "conv.r4.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_R4_R8, "conv.r4.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_R8_I4, "conv.r8.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_R8_I8, "conv.r8.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_R8_R4, "conv.r8.r4", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_U8_R4, "conv.u8.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_U8_R8, "conv.u8.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I1_I4, "conv.ovf.i1.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_I8, "conv.ovf.i1.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_R4, "conv.ovf.i1.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_R8, "conv.ovf.i1.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I1_U4, "conv.ovf.i1.u4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_U8, "conv.ovf.i1.u8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_UN_R4, "conv.ovf.i1.un.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I1_UN_R8, "conv.ovf.i1.un.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U1_I4, "conv.ovf.u1.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U1_I8, "conv.ovf.u1.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U1_R4, "conv.ovf.u1.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U1_R8, "conv.ovf.u1.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I2_I4, "conv.ovf.i2.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_I8, "conv.ovf.i2.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_R4, "conv.ovf.i2.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_R8, "conv.ovf.i2.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I2_U4, "conv.ovf.i2.u4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_U8, "conv.ovf.i2.u8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_UN_R4, "conv.ovf.i2.un.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I2_UN_R8, "conv.ovf.i2.un.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U2_I4, "conv.ovf.u2.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U2_I8, "conv.ovf.u2.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U2_R4, "conv.ovf.u2.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U2_R8, "conv.ovf.u2.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I4_U4, "conv.ovf.i4.u4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_I8, "conv.ovf.i4.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_U8, "conv.ovf.i4.u8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_R4, "conv.ovf.i4.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I4_R8, "conv.ovf.i4.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I4_UN_R8, "conv.ovf.i4.un.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U4_I4, "conv.ovf.u4.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U4_I8, "conv.ovf.u4.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U4_R4, "conv.ovf.u4.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U4_R8, "conv.ovf.u4.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I8_U8, "conv.ovf.i8.u8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I8_R4, "conv.ovf.i8.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I8_R8, "conv.ovf.i8.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_I8_UN_R8, "conv.ovf.i8.un.r8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_I8_UN_R4, "conv.ovf.i8.un.r4", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CONV_OVF_U8_I4, "conv.ovf.u8.i4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U8_I8, "conv.ovf.u8.i8", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U8_R4, "conv.ovf.u8.r4", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CONV_OVF_U8_R8, "conv.ovf.u8.r8", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_CEQ0_I4, "ceq0.i4", 3, 1, 1, MintOpNoArgs) /* unops end */ -OPDEF(MINT_CKFINITE, "ckfinite", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_MKREFANY, "mkrefany", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_REFANYTYPE, "refanytype", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_REFANYVAL, "refanyval", 2, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_CKFINITE, "ckfinite", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_MKREFANY, "mkrefany", 4, 1, 1, MintOpClassToken) +OPDEF(MINT_REFANYTYPE, "refanytype", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_REFANYVAL, "refanyval", 4, 1, 1, MintOpNoArgs) -OPDEF(MINT_CKNULL_N, "cknull_n", 2, Pop0, Push0, MintOpUShortInt) +OPDEF(MINT_CKNULL, "cknull", 3, 1, 1, MintOpNoArgs) -OPDEF(MINT_GETCHR, "getchr", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_STRLEN, "strlen", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ARRAY_RANK, "array_rank", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ARRAY_ELEMENT_SIZE, "array_element_size", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ARRAY_IS_PRIMITIVE, "array_is_primitive", 1, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_GETCHR, "getchr", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_STRLEN, "strlen", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ARRAY_RANK, "array_rank", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ARRAY_ELEMENT_SIZE, "array_element_size", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ARRAY_IS_PRIMITIVE, "array_is_primitive", 3, 1, 1, MintOpNoArgs) /* Calls */ -OPDEF(MINT_CALL, "call", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_CALLVIRT, "callvirt", 3, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 4, VarPop, Push1, MintOpMethodToken) -OPDEF(MINT_CALL_DELEGATE, "call.delegate", 3, VarPop, VarPush, MintOpTwoShorts) -OPDEF(MINT_CALLI, "calli", 3, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT, "calli.nat", 7, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT_DYNAMIC, "calli.nat.dynamic", 3, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALLI_NAT_FAST, "calli.nat.fast", 4, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALL_VARARG, "call.vararg", 4, VarPop, VarPush, MintOpMethodToken) -OPDEF(MINT_CALLRUN, "callrun", 3, VarPop, VarPush, MintOpNoArgs) - -OPDEF(MINT_ICALL_V_V, "mono_icall_v_v", 2, Pop0, Push0, MintOpClassToken) /* not really */ -OPDEF(MINT_ICALL_V_P, "mono_icall_v_p", 2, Pop0, Push1, MintOpClassToken) -OPDEF(MINT_ICALL_P_V, "mono_icall_p_v", 2, Pop1, Push0, MintOpClassToken) -OPDEF(MINT_ICALL_P_P, "mono_icall_p_p", 2, Pop1, Push1, MintOpClassToken) -OPDEF(MINT_ICALL_PP_V, "mono_icall_pp_v", 2, Pop2, Push0, MintOpClassToken) -OPDEF(MINT_ICALL_PP_P, "mono_icall_pp_p", 2, Pop2, Push1, MintOpClassToken) -OPDEF(MINT_ICALL_PPP_V, "mono_icall_ppp_v", 2, Pop3, Push0, MintOpClassToken) -OPDEF(MINT_ICALL_PPP_P, "mono_icall_ppp_p", 2, Pop3, Push1, MintOpClassToken) -OPDEF(MINT_ICALL_PPPP_V, "mono_icall_pppp_v", 2, Pop4, Push0, MintOpClassToken) -OPDEF(MINT_ICALL_PPPP_P, "mono_icall_pppp_p", 2, Pop4, Push1, MintOpClassToken) -OPDEF(MINT_ICALL_PPPPP_V, "mono_icall_ppppp_v", 2, Pop5, Push0, MintOpClassToken) -OPDEF(MINT_ICALL_PPPPP_P, "mono_icall_ppppp_p", 2, Pop5, Push1, MintOpClassToken) -OPDEF(MINT_ICALL_PPPPPP_V, "mono_icall_pppppp_v", 2, Pop6, Push0, MintOpClassToken) -OPDEF(MINT_ICALL_PPPPPP_P, "mono_icall_pppppp_p", 2, Pop6, Push1, MintOpClassToken) +OPDEF(MINT_CALL, "call", 3, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_CALLVIRT, "callvirt", 3, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 4, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_CALL_DELEGATE, "call.delegate", 4, CallArgs, 0, MintOpTwoShorts) +OPDEF(MINT_CALLI, "calli", 4, CallArgs, 1, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT, "calli.nat", 7, CallArgs, 1, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT_DYNAMIC, "calli.nat.dynamic", 4, CallArgs, 1, MintOpMethodToken) +OPDEF(MINT_CALLI_NAT_FAST, "calli.nat.fast", 5, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_CALL_VARARG, "call.vararg", 5, CallArgs, 0, MintOpMethodToken) +OPDEF(MINT_CALLRUN, "callrun", 4, CallArgs, 0, MintOpNoArgs) + +OPDEF(MINT_ICALL_V_V, "mono_icall_v_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_V_P, "mono_icall_v_p", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_P_V, "mono_icall_p_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_P_P, "mono_icall_p_p", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PP_V, "mono_icall_pp_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PP_P, "mono_icall_pp_p", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPP_V, "mono_icall_ppp_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPP_P, "mono_icall_ppp_p", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPPP_V, "mono_icall_pppp_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPPP_P, "mono_icall_pppp_p", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPPPP_V, "mono_icall_ppppp_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPPPP_P, "mono_icall_ppppp_p", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPPPPP_V, "mono_icall_pppppp_v", 3, CallArgs, 0, MintOpShortInt) +OPDEF(MINT_ICALL_PPPPPP_P, "mono_icall_pppppp_p", 3, CallArgs, 0, MintOpShortInt) // FIXME: MintOp -OPDEF(MINT_JIT_CALL, "mono_jit_call", 3, VarPop, VarPush, MintOpNoArgs) -OPDEF(MINT_JIT_CALL2, "mono_jit_call2", 5, VarPop, VarPush, MintOpNoArgs) - -OPDEF(MINT_MONO_LDPTR, "mono_ldptr", 2, Pop0, Push1, MintOpClassToken) -OPDEF(MINT_MONO_SGEN_THREAD_INFO, "mono_sgen_thread_info", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_MONO_NEWOBJ, "mono_newobj", 2, Pop0, Push1, MintOpClassToken) -OPDEF(MINT_MONO_RETOBJ, "mono_retobj", 1, Pop1, Push0, MintOpNoArgs) -OPDEF(MINT_MONO_ATOMIC_STORE_I4, "mono_atomic.store.i4", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_MONO_MEMORY_BARRIER, "mono_memory_barrier", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_MONO_EXCHANGE_I8, "mono_interlocked.xchg.i8", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_MONO_LDDOMAIN, "mono_lddomain", 1, Pop0, Push1, MintOpNoArgs) -OPDEF(MINT_MONO_GET_SP, "mono_get_sp", 1, Pop0, Push1, MintOpNoArgs) - -OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_LD_DELEGATE_METHOD_PTR, "ld_delegate_method_ptr", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_START_ABORT_PROT, "start_abort_protected", 1, Pop0, Push0, MintOpNoArgs) +OPDEF(MINT_JIT_CALL, "mono_jit_call", 3, CallArgs, 0, MintOpNoArgs) +OPDEF(MINT_JIT_CALL2, "mono_jit_call2", 6, CallArgs, 0, MintOpNoArgs) + +OPDEF(MINT_MONO_LDPTR, "mono_ldptr", 3, 1, 0, MintOpShortInt) +OPDEF(MINT_MONO_SGEN_THREAD_INFO, "mono_sgen_thread_info", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_MONO_NEWOBJ, "mono_newobj", 3, 1, 0, MintOpClassToken) +OPDEF(MINT_MONO_RETOBJ, "mono_retobj", 2, 0, 1, MintOpNoArgs) +OPDEF(MINT_MONO_ATOMIC_STORE_I4, "mono_atomic.store.i4", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_MONO_MEMORY_BARRIER, "mono_memory_barrier", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_MONO_EXCHANGE_I8, "mono_interlocked.xchg.i8", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_MONO_LDDOMAIN, "mono_lddomain", 2, 1, 0, MintOpNoArgs) +OPDEF(MINT_MONO_GET_SP, "mono_get_sp", 2, 1, 0, MintOpNoArgs) + +OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, 0, 0, MintOpNoArgs) +OPDEF(MINT_LD_DELEGATE_METHOD_PTR, "ld_delegate_method_ptr", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_START_ABORT_PROT, "start_abort_protected", 1, 0, 0, MintOpNoArgs) // Math intrinsics // double -OPDEF(MINT_ABS, "abs", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ASIN, "asin", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ASINH, "asinh", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ACOS, "acos", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ACOSH, "acosh", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ATAN, "atan", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ATANH, "atanh", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ATAN2, "atan2", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CEILING, "ceiling", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_COS, "cos", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CBRT, "cbrt", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_COSH, "cosh", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_EXP, "exp", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_FMA, "fma", 1, Pop3, Push1, MintOpNoArgs) -OPDEF(MINT_FLOOR, "floor", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ILOGB, "ilogb", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LOG, "log", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LOG2, "log2", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LOG10, "log10", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_POW, "pow", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SCALEB, "scaleb", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SIN, "sin", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_SQRT, "sqrt", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_SINH, "sinh", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_TAN, "tan", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_TANH, "tanh", 1, Pop1, Push1, MintOpNoArgs) +OPDEF(MINT_ABS, "abs", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ASIN, "asin", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ASINH, "asinh", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ACOS, "acos", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ACOSH, "acosh", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ATAN, "atan", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ATANH, "atanh", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ATAN2, "atan2", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CEILING, "ceiling", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_COS, "cos", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CBRT, "cbrt", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_COSH, "cosh", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_EXP, "exp", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_FMA, "fma", 5, 1, 3, MintOpNoArgs) +OPDEF(MINT_FLOOR, "floor", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ILOGB, "ilogb", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LOG, "log", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LOG2, "log2", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LOG10, "log10", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_POW, "pow", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SCALEB, "scaleb", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SIN, "sin", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_SQRT, "sqrt", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_SINH, "sinh", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_TAN, "tan", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_TANH, "tanh", 3, 1, 1, MintOpNoArgs) // float. These must be kept in the same order as their double counterpart -OPDEF(MINT_ABSF, "absf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ASINF, "asinf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ASINHF, "asinhf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ACOSF, "acosf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ACOSHF, "acoshf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ATANF, "atanf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ATANHF, "atanhf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ATAN2F, "atan2f", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_CEILINGF, "ceilingf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_COSF, "cosf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_CBRTF, "cbrtf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_COSHF, "coshf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_EXPF, "expf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_FMAF, "fmaf", 1, Pop3, Push1, MintOpNoArgs) -OPDEF(MINT_FLOORF, "floorf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_ILOGBF, "ilogbf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LOGF, "logf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LOG2F, "log2f", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_LOG10F, "log10f", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_POWF, "powf", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SCALEBF, "scalebf", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_SINF, "sinf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_SQRTF, "sqrtf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_SINHF, "sinhf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_TANF, "tanf", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_TANHF, "tanhf", 1, Pop1, Push1, MintOpNoArgs) - -OPDEF(MINT_PROF_ENTER, "prof_enter", 2, Pop0, Push0, MintOpNoArgs) -OPDEF(MINT_PROF_EXIT, "prof_exit", 4, Pop1, Push0, MintOpShortAndInt) -OPDEF(MINT_PROF_EXIT_VOID, "prof_exit_void", 4, Pop0, Push0, MintOpShortAndInt) -OPDEF(MINT_PROF_COVERAGE_STORE, "prof_coverage_store", 5, Pop0, Push0, MintOpLongInt) - -OPDEF(MINT_INTRINS_ENUM_HASFLAG, "intrins_enum_hasflag", 2, Pop2, Push1, MintOpClassToken) -OPDEF(MINT_INTRINS_GET_HASHCODE, "intrins_get_hashcode", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_GET_TYPE, "intrins_get_type", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_SPAN_CTOR, "intrins_span_ctor", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_BYREFERENCE_GET_VALUE, "intrins_byreference_get_value", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET, "intrins_unsafe_add_byte_offset", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_UNSAFE_BYTE_OFFSET, "intrins_unsafe_byte_offset", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE, "intrins_runtimehelpers_object_has_component_size", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_CLEAR_WITH_REFERENCES, "intrin_clear_with_references", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_INTRINS_MARVIN_BLOCK, "intrins_marvin_block", 1, Pop2, Push0, MintOpNoArgs) -OPDEF(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE, "intrins_ascii_chars_to_uppercase", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF, "intrins_memorymarshal_getarraydataref", 1, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII, "intrins_ordinal_ignore_case_ascii", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII, "intrins_64ordinal_ignore_case_ascii", 1, Pop2, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_U32_TO_DECSTR, "intrins_u32_to_decstr", 3, Pop1, Push1, MintOpNoArgs) -OPDEF(MINT_INTRINS_WIDEN_ASCII_TO_UTF16, "intrins_widen_ascii_to_utf16", 1, Pop3, Push1, MintOpNoArgs) +OPDEF(MINT_ABSF, "absf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ASINF, "asinf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ASINHF, "asinhf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ACOSF, "acosf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ACOSHF, "acoshf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ATANF, "atanf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ATANHF, "atanhf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ATAN2F, "atan2f", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_CEILINGF, "ceilingf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_COSF, "cosf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_CBRTF, "cbrtf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_COSHF, "coshf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_EXPF, "expf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_FMAF, "fmaf", 5, 1, 3, MintOpNoArgs) +OPDEF(MINT_FLOORF, "floorf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_ILOGBF, "ilogbf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LOGF, "logf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LOG2F, "log2f", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_LOG10F, "log10f", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_POWF, "powf", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SCALEBF, "scalebf", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_SINF, "sinf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_SQRTF, "sqrtf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_SINHF, "sinhf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_TANF, "tanf", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_TANHF, "tanhf", 3, 1, 1, MintOpNoArgs) + +OPDEF(MINT_PROF_ENTER, "prof_enter", 2, 0, 0, MintOpShortInt) +OPDEF(MINT_PROF_EXIT, "prof_exit", 5, 0, 1, MintOpShortAndInt) +OPDEF(MINT_PROF_COVERAGE_STORE, "prof_coverage_store", 5, 0, 0, MintOpLongInt) + +OPDEF(MINT_INTRINS_ENUM_HASFLAG, "intrins_enum_hasflag", 5, 1, 2, MintOpClassToken) +OPDEF(MINT_INTRINS_GET_HASHCODE, "intrins_get_hashcode", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INTRINS_GET_TYPE, "intrins_get_type", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INTRINS_SPAN_CTOR, "intrins_span_ctor", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_BYREFERENCE_GET_VALUE, "intrins_byreference_get_value", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INTRINS_UNSAFE_ADD_BYTE_OFFSET, "intrins_unsafe_add_byte_offset", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_UNSAFE_BYTE_OFFSET, "intrins_unsafe_byte_offset", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE, "intrins_runtimehelpers_object_has_component_size", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INTRINS_CLEAR_WITH_REFERENCES, "intrin_clear_with_references", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_MARVIN_BLOCK, "intrins_marvin_block", 3, 0, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE, "intrins_ascii_chars_to_uppercase", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF, "intrins_memorymarshal_getarraydataref", 3, 1, 1, MintOpNoArgs) +OPDEF(MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII, "intrins_ordinal_ignore_case_ascii", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII, "intrins_64ordinal_ignore_case_ascii", 4, 1, 2, MintOpNoArgs) +OPDEF(MINT_INTRINS_U32_TO_DECSTR, "intrins_u32_to_decstr", 5, 1, 1, MintOpTwoShorts) +OPDEF(MINT_INTRINS_WIDEN_ASCII_TO_UTF16, "intrins_widen_ascii_to_utf16", 5, 1, 3, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index fe264b58ff6f01..262062ee12ab58 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -52,12 +52,9 @@ typedef enum { #define READ64(x) (*(guint64 *)(x)) #endif -#define MINT_SWITCH_LEN(n) (3 + (n) * 2) +#define MINT_SWITCH_LEN(n) (4 + (n) * 2) -#define MINT_IS_LDLOC(op) ((op) >= MINT_LDLOC_I1 && (op) <= MINT_LDLOC_VT) -#define MINT_IS_STLOC(op) ((op) >= MINT_STLOC_I1 && (op) <= MINT_STLOC_VT) -#define MINT_IS_MOVLOC(op) ((op) >= MINT_MOVLOC_1 && (op) <= MINT_MOVLOC_VT) -#define MINT_IS_STLOC_NP(op) ((op) >= MINT_STLOC_NP_I4 && (op) <= MINT_STLOC_NP_O) +#define MINT_IS_MOV(op) ((op) >= MINT_MOV_I1 && (op) <= MINT_MOV_VT) #define MINT_IS_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BLT_UN_R8_S) #define MINT_IS_UNOP_CONDITIONAL_BRANCH(op) ((op) >= MINT_BRFALSE_I4 && (op) <= MINT_BRTRUE_R8_S) #define MINT_IS_BINOP_CONDITIONAL_BRANCH(op) ((op) >= MINT_BEQ_I4 && (op) <= MINT_BLT_UN_R8_S) @@ -65,23 +62,17 @@ typedef enum { #define MINT_IS_PATCHABLE_CALL(op) ((op) >= MINT_CALL && (op) <= MINT_VCALL) #define MINT_IS_NEWOBJ(op) ((op) >= MINT_NEWOBJ && (op) <= MINT_NEWOBJ_MAGIC) #define MINT_IS_LDC_I4(op) ((op) >= MINT_LDC_I4_M1 && (op) <= MINT_LDC_I4) -#define MINT_IS_UNOP(op) ((op) >= MINT_ADD1_I4 && (op) <= MINT_CONV_R8_R4_SP) +#define MINT_IS_UNOP(op) ((op) >= MINT_ADD1_I4 && (op) <= MINT_CEQ0_I4) #define MINT_IS_BINOP(op) ((op) >= MINT_ADD_I4 && (op) <= MINT_CLT_UN_R8) -#define MINT_IS_LDLOCFLD(op) ((op) >= MINT_LDLOCFLD_I1 && (op) <= MINT_LDLOCFLD_O) -#define MINT_IS_STLOCFLD(op) ((op) >= MINT_STLOCFLD_I1 && (op) <= MINT_STLOCFLD_O) -#define MINT_IS_LOCUNOP(op) ((op) >= MINT_LOCADD1_I4 && (op) <= MINT_LOCSUB1_I8) #define MINT_IS_LDFLD(op) ((op) >= MINT_LDFLD_I1 && (op) <= MINT_LDFLD_O) +#define MINT_IS_STFLD(op) ((op) >= MINT_STFLD_I1 && (op) <= MINT_STFLD_O) - -#define MINT_POP_ALL -2 -#define MINT_VAR_PUSH -1 -#define MINT_VAR_POP -1 +#define MINT_CALL_ARGS 2 extern unsigned char const mono_interp_oplen[]; -extern int const mono_interp_oppop[]; -extern int const mono_interp_oppush[]; +extern int const mono_interp_op_dregs []; +extern int const mono_interp_op_sregs []; extern MintOpArgType const mono_interp_opargtype[]; -extern char* mono_interp_dis_mintop (gint32 ins_offset, gboolean native_offset, const guint16 *ip, guint16 opcode); extern const guint16* mono_interp_dis_mintop_len (const guint16 *ip); // This, instead of an array of pointers, to optimize away a pointer and a relocation per string. diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index ae59aff6bbb471..1994437f0da093 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -129,6 +129,12 @@ MonoInterpStats mono_interp_stats; #define MINT_CONV_OVF_U4_P MINT_CONV_OVF_U4_I4 #endif +#if SIZEOF_VOID_P == 8 +#define MINT_MOV_P MINT_MOV_8 +#else +#define MINT_MOV_P MINT_MOV_4 +#endif + typedef struct { const gchar *op_name; guint16 insn [3]; @@ -137,7 +143,7 @@ typedef struct { // static const MagicIntrinsic int_binop[] = { static const MagicIntrinsic int_unnop[] = { - { "op_UnaryPlus", {MINT_NOP, MINT_NOP, MINT_NOP}}, + { "op_UnaryPlus", {MINT_MOV_P, MINT_MOV_P, MINT_MOV_4}}, { "op_UnaryNegation", {MINT_NEG_P, MINT_NEG_P, MINT_NEG_FP}}, { "op_OnesComplement", {MINT_NOT_P, MINT_NOT_P, MINT_NIY}} }; @@ -181,6 +187,25 @@ static int stack_type [] = { static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error); +#define interp_ins_set_dreg(ins,dr) do { \ + ins->dreg = dr; \ +} while (0) + +#define interp_ins_set_sreg(ins,s1) do { \ + ins->sregs [0] = s1; \ +} while (0) + +#define interp_ins_set_sregs2(ins,s1,s2) do { \ + ins->sregs [0] = s1; \ + ins->sregs [1] = s2; \ +} while (0) + +#define interp_ins_set_sregs3(ins,s1,s2,s3) do { \ + ins->sregs [0] = s1; \ + ins->sregs [1] = s2; \ + ins->sregs [2] = s3; \ +} while (0) + static InterpInst* interp_new_ins (TransformData *td, guint16 opcode, int len) { @@ -274,8 +299,10 @@ interp_prev_ins (InterpInst *ins) #define ENSURE_I4(td, sp_off) \ do { \ - if ((td)->sp [-sp_off].type == STACK_TYPE_I8) \ - interp_add_ins (td, sp_off == 1 ? MINT_CONV_I4_I8 : MINT_CONV_I4_I8_SP); \ + if ((td)->sp [-sp_off].type == STACK_TYPE_I8) { \ + /* Same representation in memory, nothing to do */ \ + (td)->sp [-sp_off].type = STACK_TYPE_I4; \ + } \ } while (0) #define CHECK_TYPELOAD(klass) \ @@ -338,26 +365,6 @@ interp_prev_ins (InterpInst *ins) #endif -// This does not handle the size/offset of the entry. For those cases -// we need to manually pop the top of the stack and push a new entry. -#define SET_SIMPLE_TYPE(s, ty) \ - do { \ - g_assert (ty != STACK_TYPE_VT); \ - g_assert ((s)->type != STACK_TYPE_VT); \ - (s)->type = (ty); \ - (s)->flags = 0; \ - (s)->klass = NULL; \ - } while (0) - -#define SET_TYPE(s, ty, k) \ - do { \ - g_assert (ty != STACK_TYPE_VT); \ - g_assert ((s)->type != STACK_TYPE_VT); \ - (s)->type = (ty); \ - (s)->flags = 0; \ - (s)->klass = k; \ - } while (0) - static void realloc_stack (TransformData *td) { @@ -377,6 +384,59 @@ get_tos_offset (TransformData *td) return td->sp [-1].offset + td->sp [-1].size; } +static MonoType* +get_type_from_stack (int type, MonoClass *klass) +{ + switch (type) { + case STACK_TYPE_I4: return m_class_get_byval_arg (mono_defaults.int32_class); + case STACK_TYPE_I8: return m_class_get_byval_arg (mono_defaults.int64_class); + case STACK_TYPE_R4: return m_class_get_byval_arg (mono_defaults.single_class); + case STACK_TYPE_R8: return m_class_get_byval_arg (mono_defaults.double_class); + case STACK_TYPE_O: return (klass && !m_class_is_valuetype (klass)) ? m_class_get_byval_arg (klass) : m_class_get_byval_arg (mono_defaults.object_class); + case STACK_TYPE_VT: return m_class_get_byval_arg (klass); + case STACK_TYPE_MP: + case STACK_TYPE_F: + return m_class_get_byval_arg (mono_defaults.int_class); + default: + g_assert_not_reached (); + } +} + +/* + * These are additional locals that can be allocated as we transform the code. + * They are allocated past the method locals so they are accessed in the same + * way, with an offset relative to the frame->locals. + */ +static int +create_interp_local_explicit (TransformData *td, MonoType *type, int size) +{ + if (td->locals_size == td->locals_capacity) { + td->locals_capacity *= 2; + if (td->locals_capacity == 0) + td->locals_capacity = 2; + td->locals = (InterpLocal*) g_realloc (td->locals, td->locals_capacity * sizeof (InterpLocal)); + } + td->locals [td->locals_size].type = type; + td->locals [td->locals_size].mt = mint_type (type); + td->locals [td->locals_size].flags = 0; + td->locals [td->locals_size].indirects = 0; + td->locals [td->locals_size].offset = -1; + td->locals [td->locals_size].size = size; + td->locals_size++; + return td->locals_size - 1; + +} + +static int +create_interp_stack_local (TransformData *td, int type, MonoClass *k, int type_size, int offset) +{ + int local = create_interp_local_explicit (td, get_type_from_stack (type, k), type_size); + + td->locals [local].flags |= INTERP_LOCAL_FLAG_EXECUTION_STACK; + td->locals [local].stack_offset = offset; + return local; +} + static void push_type_explicit (TransformData *td, int type, MonoClass *k, int type_size) { @@ -390,15 +450,50 @@ push_type_explicit (TransformData *td, int type, MonoClass *k, int type_size) td->sp->klass = k; td->sp->flags = 0; td->sp->offset = get_tos_offset (td); + td->sp->local = create_interp_stack_local (td, type, k, type_size, td->sp->offset); td->sp->size = ALIGN_TO (type_size, MINT_STACK_SLOT_SIZE); if ((td->sp->size + td->sp->offset) > td->max_stack_size) td->max_stack_size = td->sp->size + td->sp->offset; td->sp++; } +// This does not handle the size/offset of the entry. For those cases +// we need to manually pop the top of the stack and push a new entry. +#define SET_SIMPLE_TYPE(s, ty) \ + do { \ + g_assert (ty != STACK_TYPE_VT); \ + g_assert ((s)->type != STACK_TYPE_VT); \ + (s)->type = (ty); \ + (s)->flags = 0; \ + (s)->klass = NULL; \ + } while (0) + +#define SET_TYPE(s, ty, k) \ + do { \ + g_assert (ty != STACK_TYPE_VT); \ + g_assert ((s)->type != STACK_TYPE_VT); \ + (s)->type = (ty); \ + (s)->flags = 0; \ + (s)->klass = k; \ + } while (0) + +static void +set_type_and_local (TransformData *td, StackInfo *sp, MonoClass *klass, int type) +{ + SET_TYPE (sp, type, klass); + sp->local = create_interp_stack_local (td, type, NULL, MINT_STACK_SLOT_SIZE, sp->offset); +} + +static void +set_simple_type_and_local (TransformData *td, StackInfo *sp, int type) +{ + set_type_and_local (td, sp, NULL, type); +} + static void push_type (TransformData *td, int type, MonoClass *k) { + // We don't really care about the exact size for non-valuetypes push_type_explicit (td, type, k, MINT_STACK_SLOT_SIZE); } @@ -458,12 +553,15 @@ interp_merge_bblocks (TransformData *td, InterpBasicBlock *bb, InterpBasicBlock // Remove the branch instruction to the invalid bblock if (bb->last_ins) { - if (bb->last_ins->opcode == MINT_BR || bb->last_ins->opcode == MINT_BR_S) { - g_assert (bb->last_ins->info.target_bb == bbadd); - interp_clear_ins (bb->last_ins); - } else if (bb->last_ins->opcode == MINT_SWITCH) { - // Weird corner case where empty switch can branch by default to next instruction - bb->last_ins->opcode = MINT_POP; + InterpInst *last_ins = (bb->last_ins->opcode != MINT_NOP) ? bb->last_ins : interp_prev_ins (bb->last_ins); + if (last_ins) { + if (last_ins->opcode == MINT_BR || last_ins->opcode == MINT_BR_S) { + g_assert (last_ins->info.target_bb == bbadd); + interp_clear_ins (last_ins); + } else if (last_ins->opcode == MINT_SWITCH) { + // Weird corner case where empty switch can branch by default to next instruction + last_ins->opcode = MINT_NOP; + } } } @@ -564,10 +662,70 @@ interp_link_bblocks (TransformData *td, InterpBasicBlock *from, InterpBasicBlock } } +static int +get_mov_for_type (int mt, gboolean needs_sext) +{ + switch (mt) { + case MINT_TYPE_I1: + case MINT_TYPE_U1: + case MINT_TYPE_I2: + case MINT_TYPE_U2: + if (needs_sext) + return MINT_MOV_I1 + mt; + else + return MINT_MOV_4; + case MINT_TYPE_I4: + case MINT_TYPE_R4: + return MINT_MOV_4; + case MINT_TYPE_I8: + case MINT_TYPE_R8: + return MINT_MOV_8; + case MINT_TYPE_O: +#if SIZEOF_VOID_P == 8 + return MINT_MOV_8; +#else + return MINT_MOV_4; +#endif + case MINT_TYPE_VT: + return MINT_MOV_VT; + } + g_assert_not_reached (); +} + +// Should be called when td->cbb branches to newbb and newbb can have a stack state +static void +fixup_newbb_stack_locals (TransformData *td, InterpBasicBlock *newbb) +{ + if (newbb->stack_height <= 0) + return; + + for (int i = 0; i < newbb->stack_height; i++) { + int sloc = td->stack [i].local; + int dloc = newbb->stack_state [i].local; + if (sloc != dloc) { + int mt = td->locals [sloc].mt; + int mov_op = get_mov_for_type (mt, FALSE); + + // FIXME can be hit in some IL cases. Should we merge the stack states ? (b41002.il) + // g_assert (mov_op == get_mov_for_type (td->locals [dloc].mt, FALSE)); + + interp_add_ins (td, mov_op); + interp_ins_set_sreg (td->last_ins, td->stack [i].local); + interp_ins_set_dreg (td->last_ins, newbb->stack_state [i].local); + + if (mt == MINT_TYPE_VT) { + g_assert (td->locals [sloc].size == td->locals [dloc].size); + td->last_ins->data [0] = td->locals [sloc].size; + } + } + } +} + // Initializes stack state at entry to bb, based on the current stack state static void init_bb_stack_state (TransformData *td, InterpBasicBlock *bb) { + // FIXME If already initialized, then we need to generate mov to the registers in the state. // Check if already initialized if (bb->stack_height >= 0) return; @@ -601,6 +759,7 @@ handle_branch (TransformData *td, int short_op, int long_op, int offset) if (short_op == MINT_LEAVE_S || short_op == MINT_LEAVE_S_CHECK) target_bb->eh_block = TRUE; + fixup_newbb_stack_locals (td, target_bb); if (offset > 0) init_bb_stack_state (td, target_bb); @@ -626,10 +785,26 @@ one_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) int short_op = long_op + MINT_BRFALSE_I4_S - MINT_BRFALSE_I4; CHECK_STACK(td, 1); --td->sp; - if (offset) + if (offset) { handle_branch (td, short_op, long_op, offset + inst_size); + interp_ins_set_sreg (td->last_ins, td->sp->local); + } else { + interp_add_ins (td, MINT_NOP); + } +} + +static void +interp_add_conv (TransformData *td, StackInfo *sp, InterpInst *prev_ins, int type, int conv_op) +{ + InterpInst *new_inst; + if (prev_ins) + new_inst = interp_insert_ins (td, prev_ins, conv_op); else - interp_add_ins (td, MINT_POP); + new_inst = interp_add_ins (td, conv_op); + + interp_ins_set_sreg (new_inst, sp->local); + set_simple_type_and_local (td, sp, type); + interp_ins_set_dreg (new_inst, sp->local); } static void @@ -641,19 +816,15 @@ two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) { // The il instruction starts with the actual branch, and not with the conversion opcodes - interp_insert_ins (td, td->last_ins, MINT_CONV_I8_I4); - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8); + interp_add_conv (td, td->sp - 1, td->last_ins, STACK_TYPE_I8, MINT_CONV_I8_I4); type1 = STACK_TYPE_I8; } else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) { - interp_insert_ins (td, td->last_ins, MINT_CONV_I8_I4_SP); - SET_SIMPLE_TYPE (td->sp - 2, STACK_TYPE_I8); + interp_add_conv (td, td->sp - 2, td->last_ins, STACK_TYPE_I8, MINT_CONV_I8_I4); } else if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) { - interp_insert_ins (td, td->last_ins, MINT_CONV_R8_R4); - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_R8); + interp_add_conv (td, td->sp - 1, td->last_ins, STACK_TYPE_R8, MINT_CONV_R8_R4); type1 = STACK_TYPE_R8; } else if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) { - interp_insert_ins (td, td->last_ins, MINT_CONV_R8_R4_SP); - SET_SIMPLE_TYPE (td->sp - 2, STACK_TYPE_R8); + interp_add_conv (td, td->sp - 2, td->last_ins, STACK_TYPE_R8, MINT_CONV_R8_R4); } else if (type1 != type2) { g_warning("%s.%s: branch type mismatch %d %d", m_class_get_name (td->method->klass), td->method->name, @@ -665,9 +836,9 @@ two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) td->sp -= 2; if (offset) { handle_branch (td, short_op, long_op, offset + inst_size); + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); } else { - interp_add_ins (td, MINT_POP); - interp_add_ins (td, MINT_POP); + interp_add_ins (td, MINT_NOP); } } @@ -676,7 +847,11 @@ unary_arith_op(TransformData *td, int mint_op) { int op = mint_op + td->sp [-1].type - STACK_TYPE_I4; CHECK_STACK(td, 1); + td->sp--; interp_add_ins (td, op); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, td->sp [0].type); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } static void @@ -687,23 +862,21 @@ binary_arith_op(TransformData *td, int mint_op) int op; #if SIZEOF_VOID_P == 8 if ((type1 == STACK_TYPE_MP || type1 == STACK_TYPE_I8) && type2 == STACK_TYPE_I4) { - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); type2 = STACK_TYPE_I8; } if (type1 == STACK_TYPE_I4 && (type2 == STACK_TYPE_MP || type2 == STACK_TYPE_I8)) { - interp_add_ins (td, MINT_CONV_I8_I4_SP); + interp_add_conv (td, td->sp - 2, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); type1 = STACK_TYPE_I8; - td->sp [-2].type = STACK_TYPE_I8; } #endif if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) { - interp_add_ins (td, MINT_CONV_R8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); type2 = STACK_TYPE_R8; } if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) { - interp_add_ins (td, MINT_CONV_R8_R4_SP); + interp_add_conv (td, td->sp - 2, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); type1 = STACK_TYPE_R8; - td->sp [-2].type = STACK_TYPE_R8; } if (type1 == STACK_TYPE_MP) type1 = STACK_TYPE_I; @@ -716,8 +889,11 @@ binary_arith_op(TransformData *td, int mint_op) } op = mint_op + type1 - STACK_TYPE_I4; CHECK_STACK(td, 2); + td->sp -= 2; interp_add_ins (td, op); - --td->sp; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, type1); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } static void @@ -730,8 +906,11 @@ shift_op(TransformData *td, int mint_op) m_class_get_name (td->method->klass), td->method->name, td->sp [-2].type); } + td->sp -= 2; interp_add_ins (td, op); - --td->sp; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, td->sp [0].type); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } static int @@ -764,6 +943,7 @@ get_arg_type_exact (TransformData *td, int n, int *mt) static void load_arg(TransformData *td, int n) { + gint32 size = 0; int mt; MonoClass *klass = NULL; MonoType *type; @@ -772,7 +952,6 @@ load_arg(TransformData *td, int n) type = get_arg_type_exact (td, n, &mt); if (mt == MINT_TYPE_VT) { - gint32 size; klass = mono_class_from_mono_type_internal (type); if (mono_method_signature_internal (td->method)->pinvoke) size = mono_class_native_size (klass, NULL); @@ -781,14 +960,10 @@ load_arg(TransformData *td, int n) if (hasthis && n == 0) { mt = MINT_TYPE_I; - interp_add_ins (td, MINT_LDLOC_O); - td->last_ins->data [0] = 0; klass = NULL; push_type (td, stack_type [mt], klass); } else { - interp_add_ins (td, MINT_LDLOC_VT); - td->last_ins->data [0] = n; - WRITE32_INS (td->last_ins, 1, &size); + g_assert (size < G_MAXUINT16); push_type_vt (td, klass, size); } } else { @@ -796,21 +971,23 @@ load_arg(TransformData *td, int n) // Special case loading of the first ptr sized argument if (mt != MINT_TYPE_O) mt = MINT_TYPE_I; - interp_add_ins (td, MINT_LDLOC_O); - td->last_ins->data [0] = 0; } else { - interp_add_ins (td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1)); - td->last_ins->data [0] = n; if (mt == MINT_TYPE_O) klass = mono_class_from_mono_type_internal (type); } push_type (td, stack_type [mt], klass); } + interp_add_ins (td, get_mov_for_type (mt, TRUE)); + interp_ins_set_sreg (td->last_ins, n); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = size; } static void store_arg(TransformData *td, int n) { + gint32 size = 0; int mt; CHECK_STACK (td, 1); MonoType *type; @@ -818,82 +995,66 @@ store_arg(TransformData *td, int n) type = get_arg_type_exact (td, n, &mt); if (mt == MINT_TYPE_VT) { - gint32 size; MonoClass *klass = mono_class_from_mono_type_internal (type); if (mono_method_signature_internal (td->method)->pinvoke) size = mono_class_native_size (klass, NULL); else size = mono_class_value_size (klass, NULL); - interp_add_ins (td, MINT_STLOC_VT); - td->last_ins->data [0] = n; - WRITE32_INS (td->last_ins, 1, &size); - } else { - interp_add_ins (td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1)); - td->last_ins->data [0] = n; + g_assert (size < G_MAXUINT16); } --td->sp; + interp_add_ins (td, get_mov_for_type (mt, FALSE)); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + interp_ins_set_dreg (td->last_ins, n); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = size; } static void load_local (TransformData *td, int local) { - MonoType *type = td->locals [local].type; int mt = td->locals [local].mt; - MonoClass *klass = NULL; + gint32 size = td->locals [local].size; + MonoType *type = td->locals [local].type; + if (mt == MINT_TYPE_VT) { - klass = mono_class_from_mono_type_internal (type); - gint32 size = mono_class_value_size (klass, NULL); - interp_add_ins (td, MINT_LDLOC_VT); - td->last_ins->data [0] = local; - WRITE32_INS (td->last_ins, 1, &size); + MonoClass *klass = mono_class_from_mono_type_internal (type); push_type_vt (td, klass, size); } else { - g_assert (mt < MINT_TYPE_VT); - interp_add_ins (td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1)); - td->last_ins->data [0] = local; + MonoClass *klass = NULL; if (mt == MINT_TYPE_O) klass = mono_class_from_mono_type_internal (type); push_type (td, stack_type [mt], klass); } + interp_add_ins (td, get_mov_for_type (mt, TRUE)); + interp_ins_set_sreg (td->last_ins, local); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = size; } static void store_local (TransformData *td, int local) { - MonoType *type = td->locals [local].type; int mt = td->locals [local].mt; CHECK_STACK (td, 1); #if SIZEOF_VOID_P == 8 - if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) { - interp_add_ins (td, MINT_CONV_I8_I4); - td->sp [-1].type = STACK_TYPE_I8; - } + if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); #endif if (!can_store(td->sp [-1].type, stack_type [mt])) { g_warning("%s.%s: Store local stack type mismatch %d %d", m_class_get_name (td->method->klass), td->method->name, stack_type [mt], td->sp [-1].type); } - if (mt == MINT_TYPE_VT) { - MonoClass *klass = mono_class_from_mono_type_internal (type); - gint32 size = mono_class_value_size (klass, NULL); - interp_add_ins (td, MINT_STLOC_VT); - td->last_ins->data [0] = local; - WRITE32_INS (td->last_ins, 1, &size); - } else { - g_assert (mt < MINT_TYPE_VT); - interp_add_ins (td, MINT_STLOC_I1 + (mt - MINT_TYPE_I1)); - td->last_ins->data [0] = local; - } --td->sp; + interp_add_ins (td, get_mov_for_type (mt, FALSE)); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + interp_ins_set_dreg (td->last_ins, local); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = td->locals [local].size; } -#define SIMPLE_OP(td, op) \ - do { \ - interp_add_ins (td, op); \ - ++td->ip; \ - } while (0) - static guint16 get_data_item_index (TransformData *td, void *ptr) { @@ -1003,17 +1164,22 @@ interp_generate_mae_throw (TransformData *td, MonoMethod *method, MonoMethod *ta /* Inject code throwing MethodAccessException */ interp_add_ins (td, MINT_MONO_LDPTR); - td->last_ins->data [0] = get_data_item_index (td, method); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, method); + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; interp_add_ins (td, MINT_MONO_LDPTR); - td->last_ins->data [0] = get_data_item_index (td, target_method); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, target_method); + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + td->sp -= 2; interp_add_ins (td, MINT_ICALL_PP_V); + interp_ins_set_dreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); - td->sp -= 2; } static void @@ -1022,6 +1188,10 @@ interp_generate_bie_throw (TransformData *td) MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_bad_image; interp_add_ins (td, MINT_ICALL_V_V); + // Allocate a dummy local to serve as dreg for this instruction + push_simple_type (td, STACK_TYPE_I4); + td->sp--; + interp_ins_set_dreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); } @@ -1031,6 +1201,10 @@ interp_generate_not_supported_throw (TransformData *td) MonoJitICallInfo *info = &mono_get_jit_icall_info ()->mono_throw_not_supported; interp_add_ins (td, MINT_ICALL_V_V); + // Allocate a dummy local to serve as dreg for this instruction + push_simple_type (td, STACK_TYPE_I4); + td->sp--; + interp_ins_set_dreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); } @@ -1042,38 +1216,15 @@ interp_generate_ipe_throw_with_msg (TransformData *td, MonoError *error_msg) char *msg = mono_mem_manager_strdup (td->mem_manager, mono_error_get_message (error_msg)); interp_add_ins (td, MINT_MONO_LDPTR); - td->last_ins->data [0] = get_data_item_index (td, msg); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + td->last_ins->data [0] = get_data_item_index (td, msg); + td->sp -= 1; interp_add_ins (td, MINT_ICALL_P_V); + interp_ins_set_dreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); - - td->sp -= 1; -} - -/* - * These are additional locals that can be allocated as we transform the code. - * They are allocated past the method locals so they are accessed in the same - * way, with an offset relative to the frame->locals. - */ -static int -create_interp_local_explicit (TransformData *td, MonoType *type, int size) -{ - if (td->locals_size == td->locals_capacity) { - td->locals_capacity *= 2; - if (td->locals_capacity == 0) - td->locals_capacity = 2; - td->locals = (InterpLocal*) g_realloc (td->locals, td->locals_capacity * sizeof (InterpLocal)); - } - td->locals [td->locals_size].type = type; - td->locals [td->locals_size].mt = mint_type (type); - td->locals [td->locals_size].flags = 0; - td->locals [td->locals_size].indirects = 0; - td->locals [td->locals_size].offset = -1; - td->locals [td->locals_size].size = size; - td->locals_size++; - return td->locals_size - 1; - } static int @@ -1088,32 +1239,162 @@ create_interp_local (TransformData *td, MonoType *type) } static int -get_interp_local_offset (TransformData *td, int local) +get_interp_local_offset (TransformData *td, int local, gboolean resolve_stack_locals) { - int size, offset; + // FIXME MINT_PROF_EXIT when void + if (local == -1) + return -1; + + if ((td->locals [local].flags & INTERP_LOCAL_FLAG_EXECUTION_STACK) && !resolve_stack_locals) + return -1; if (td->locals [local].offset != -1) return td->locals [local].offset; - offset = td->total_locals_size; - size = td->locals [local].size; + if (td->locals [local].flags & INTERP_LOCAL_FLAG_EXECUTION_STACK) { + td->locals [local].offset = td->total_locals_size + td->locals [local].stack_offset; + } else { + int size, offset; + + offset = td->total_locals_size; + size = td->locals [local].size; - td->locals [local].offset = offset; + td->locals [local].offset = offset; + + td->total_locals_size = ALIGN_TO (offset + size, MINT_STACK_SLOT_SIZE); + } - td->total_locals_size = ALIGN_TO (offset + size, MINT_STACK_SLOT_SIZE); //g_assert (td->total_locals_size < G_MAXUINT16); - return offset; + return td->locals [local].offset; +} + +/* + * ins_offset is the associated offset of this instruction + * if ins is null, it means the data belongs to an instruction that was + * emitted in the final code + * ip is the address where the arguments of the instruction are located + */ +static char* +dump_interp_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, guint16 opcode) +{ + GString *str = g_string_new (""); + guint32 token; + int target; + + switch (mono_interp_opargtype [opcode]) { + case MintOpNoArgs: + break; + case MintOpUShortInt: + g_string_append_printf (str, " %u", *(guint16*)data); + break; + case MintOpTwoShorts: + g_string_append_printf (str, " %u,%u", *(guint16*)data, *(guint16 *)(data + 1)); + break; + case MintOpShortAndInt: + g_string_append_printf (str, " %u,%u", *(guint16*)data, (guint32)READ32(data + 1)); + break; + case MintOpShortInt: + g_string_append_printf (str, " %d", *(gint16*)data); + break; + case MintOpClassToken: + case MintOpMethodToken: + case MintOpFieldToken: + token = * (guint16 *) data; + g_string_append_printf (str, " %u", token); + break; + case MintOpInt: + g_string_append_printf (str, " %d", (gint32)READ32 (data)); + break; + case MintOpLongInt: + g_string_append_printf (str, " %" PRId64, (gint64)READ64 (data)); + break; + case MintOpFloat: { + gint32 tmp = READ32 (data); + g_string_append_printf (str, " %g", * (float *)&tmp); + break; + } + case MintOpDouble: { + gint64 tmp = READ64 (data); + g_string_append_printf (str, " %g", * (double *)&tmp); + break; + } + case MintOpShortBranch: + if (ins) { + /* the target IL is already embedded in the instruction */ + g_string_append_printf (str, " BB%d", ins->info.target_bb->index); + } else { + target = ins_offset + *(gint16*)data; + g_string_append_printf (str, " IR_%04x", target); + } + break; + case MintOpBranch: + if (ins) { + g_string_append_printf (str, " BB%d", ins->info.target_bb->index); + } else { + target = ins_offset + (gint32)READ32 (data); + g_string_append_printf (str, " IR_%04x", target); + } + break; + case MintOpSwitch: { + int sval = (gint32)READ32 (data); + int i; + g_string_append_printf (str, "("); + gint32 p = 2; + for (i = 0; i < sval; ++i) { + if (i > 0) + g_string_append_printf (str, ", "); + if (ins) { + g_string_append_printf (str, "BB%d", ins->info.target_bb_table [i]->index); + } else { + g_string_append_printf (str, "IR_%04x", (gint32)READ32 (data + p)); + } + p += 2; + } + g_string_append_printf (str, ")"); + break; + } + default: + g_string_append_printf (str, "unknown arg type\n"); + } + + return g_string_free (str, FALSE); +} + +static void +dump_interp_compacted_ins (const guint16 *ip, const guint16 *start) +{ + int opcode = *ip; + int ins_offset = ip - start; + + g_print ("IR_%04x: %-14s", ins_offset, mono_interp_opname (opcode)); + ip++; + + if (mono_interp_op_dregs [opcode] == MINT_CALL_ARGS) + g_print (" [call_args %d <-", *ip++); + else if (mono_interp_op_dregs [opcode] > 0) + g_print (" [%d <-", *ip++); + else + g_print (" [nil <-"); + + if (mono_interp_op_sregs [opcode] > 0) { + for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) + g_print (" %d", *ip++); + g_print ("],"); + } else { + g_print (" nil],"); + } + char *ins = dump_interp_ins_data (NULL, ins_offset, ip, opcode); + g_print ("%s\n", ins); + g_free (ins); } static void -dump_mint_code (const guint16 *start, const guint16* end) +dump_interp_code (const guint16 *start, const guint16* end) { const guint16 *p = start; while (p < end) { - char *ins = mono_interp_dis_mintop ((gint32)(p - start), TRUE, p + 1, *p); - g_print ("%s\n", ins); - g_free (ins); + dump_interp_compacted_ins (p, start); p = mono_interp_dis_mintop_len (p); } } @@ -1121,9 +1402,32 @@ dump_mint_code (const guint16 *start, const guint16* end) static void dump_interp_inst_no_newline (InterpInst *ins) { - char *descr = mono_interp_dis_mintop (ins->il_offset, FALSE, &ins->data [0], ins->opcode); - g_print ("%s", descr); - g_free (descr); + int opcode = ins->opcode; + g_print ("IL_%04x: %-14s", ins->il_offset, mono_interp_opname (opcode)); + + if (mono_interp_op_dregs [opcode] == MINT_CALL_ARGS) + g_print (" [call_args %d <-", ins->dreg); + else if (mono_interp_op_dregs [opcode] > 0) + g_print (" [%d <-", ins->dreg); + else + g_print (" [nil <-"); + + if (mono_interp_op_sregs [opcode] > 0) { + for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) + g_print (" %d", ins->sregs [i]); + g_print ("],"); + } else { + g_print (" nil],"); + } + + if (opcode == MINT_LDLOCA_S) { + // LDLOCA has special semantics, it has data in sregs [0], but it doesn't have any sregs + g_print (" %d", ins->sregs [0]); + } else { + char *descr = dump_interp_ins_data (ins, ins->il_offset, &ins->data [0], ins->opcode); + g_print ("%s", descr); + g_free (descr); + } } static void @@ -1157,7 +1461,7 @@ mono_interp_print_code (InterpMethod *imethod) g_free (name); start = (guint8*) jinfo->code_start; - dump_mint_code ((const guint16*)start, (const guint16*)(start + jinfo->code_size)); + dump_interp_code ((const guint16*)start, (const guint16*)(start + jinfo->code_size)); } /* For debug use */ @@ -1198,10 +1502,10 @@ emit_store_value_as_local (TransformData *td, MonoType *src) store_local (td, local); interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = local; - td->locals [local].indirects++; - push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_ins_set_sreg (td->last_ins, local); + td->locals [local].indirects++; } static gboolean @@ -1241,7 +1545,7 @@ interp_get_const_from_ldc_i4 (InterpInst *ins) /* If ins is not null, it will replace it with the ldc */ static InterpInst* -interp_get_ldc_i4_from_const (TransformData *td, InterpInst *ins, gint32 ct) +interp_get_ldc_i4_from_const (TransformData *td, InterpInst *ins, gint32 ct, int dreg) { int opcode; switch (ct) { @@ -1276,10 +1580,11 @@ interp_get_ldc_i4_from_const (TransformData *td, InterpInst *ins, gint32 ct) } else { ins->opcode = opcode; } + interp_ins_set_dreg (ins, dreg); - if (new_size == 2) + if (new_size == 3) ins->data [0] = (gint8)ct; - else if (new_size == 3) + else if (new_size == 4) WRITE32_INS (ins, 0, &ct); return ins; @@ -1289,6 +1594,7 @@ static InterpInst* interp_inst_replace_with_i8_const (TransformData *td, InterpInst *ins, gint64 ct) { int size = mono_interp_oplen [ins->opcode]; + int dreg = ins->dreg; if (size < 5) { ins = interp_insert_ins (td, ins, MINT_LDC_I8); @@ -1297,6 +1603,7 @@ interp_inst_replace_with_i8_const (TransformData *td, InterpInst *ins, gint64 ct ins->opcode = MINT_LDC_I8; } WRITE64_INS (ins, 0, &ct); + ins->dreg = dreg; return ins; } @@ -1324,19 +1631,24 @@ static void interp_emit_ldobj (TransformData *td, MonoClass *klass) { int mt = mint_type (m_class_get_byval_arg (klass)); - int size; + gint32 size; td->sp--; if (mt == MINT_TYPE_VT) { interp_add_ins (td, MINT_LDOBJ_VT); size = mono_class_value_size (klass, NULL); - WRITE32_INS (td->last_ins, 0, &size); + g_assert (size < G_MAXUINT16); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_type_vt (td, klass, size); } else { int opcode = interp_get_ldind_for_mt (mt); interp_add_ins (td, opcode); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_type (td, stack_type [mt], klass); } + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = size; } static void @@ -1378,6 +1690,7 @@ interp_emit_stobj (TransformData *td, MonoClass *klass) interp_add_ins (td, opcode); } td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); } static void @@ -1386,27 +1699,39 @@ interp_emit_ldelema (TransformData *td, MonoClass *array_class, MonoClass *check MonoClass *element_class = m_class_get_element_class (array_class); int rank = m_class_get_rank (array_class); int size = mono_class_array_element_size (element_class); + gboolean call_args = FALSE; gboolean bounded = m_class_get_byval_arg (array_class) ? m_class_get_byval_arg (array_class)->type == MONO_TYPE_ARRAY : FALSE; + td->sp -= rank + 1; // We only need type checks when writing to array of references if (!check_class || m_class_is_valuetype (element_class)) { if (rank == 1 && !bounded) { interp_add_ins (td, MINT_LDELEMA1); - WRITE32_INS (td->last_ins, 0, &size); + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + g_assert (size < G_MAXUINT16); + td->last_ins->data [0] = size; } else { interp_add_ins (td, MINT_LDELEMA); + for (int i = 0; i < rank + 1; i++) + td->locals [td->sp [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; td->last_ins->data [0] = rank; - WRITE32_INS (td->last_ins, 1, &size); + g_assert (size < G_MAXUINT16); + td->last_ins->data [1] = size; + call_args = TRUE; } } else { interp_add_ins (td, MINT_LDELEMA_TC); - td->last_ins->data [0] = rank; - td->last_ins->data [1] = get_data_item_index (td, check_class); + for (int i = 0; i < rank + 1; i++) + td->locals [td->sp [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + td->last_ins->data [0] = get_data_item_index (td, check_class); + call_args = TRUE; } - td->sp -= rank; - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + if (call_args) + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; } static gboolean @@ -1425,10 +1750,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (arg_size > SIZEOF_VOID_P) { // 8 -> 4 switch (type_index) { case 0: case 1: - interp_add_ins (td, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); break; case 2: - interp_add_ins (td, MINT_CONV_R4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_R4_R8); break; } } @@ -1436,13 +1761,13 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (arg_size < SIZEOF_VOID_P) { // 4 -> 8 switch (type_index) { case 0: - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); break; case 1: - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_U4); break; case 2: - interp_add_ins (td, MINT_CONV_R8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); break; } } @@ -1463,8 +1788,8 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho #endif break; } - td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); td->ip += 5; return TRUE; } else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) { @@ -1509,10 +1834,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (src_size > dst_size) { // 8 -> 4 switch (type_index) { case 0: case 1: - interp_add_ins (td, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); break; case 2: - interp_add_ins (td, MINT_CONV_R4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_R8); break; } } @@ -1520,13 +1845,13 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (src_size < dst_size) { // 4 -> 8 switch (type_index) { case 0: - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); break; case 1: - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_U4); break; case 2: - interp_add_ins (td, MINT_CONV_R8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); break; } } @@ -1541,7 +1866,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho #else interp_add_ins (td, MINT_ADD1_I4); #endif - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type (td, stack_type [mt], magic_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } else if (!strcmp ("op_Decrement", tm)) { @@ -1551,7 +1879,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho #else interp_add_ins (td, MINT_SUB1_I4); #endif - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type (td, stack_type [mt], magic_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } else if (!strcmp ("CompareTo", tm) || !strcmp ("Equals", tm)) { @@ -1581,7 +1912,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho for (i = 0; i < sizeof (int_unnop) / sizeof (MagicIntrinsic); ++i) { if (!strcmp (int_unnop [i].op_name, tm)) { interp_add_ins (td, int_unnop [i].insn [type_index]); - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type (td, stack_type [mt], magic_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -1590,8 +1924,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho for (i = 0; i < sizeof (int_binop) / sizeof (MagicIntrinsic); ++i) { if (!strcmp (int_binop [i].op_name, tm)) { interp_add_ins (td, int_binop [i].insn [type_index]); - td->sp -= 1; - SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_type (td, stack_type [mt], magic_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -1601,8 +1937,10 @@ interp_handle_magic_type_intrinsics (TransformData *td, MonoMethod *target_metho if (!strcmp (int_cmpop [i].op_name, tm)) { MonoClass *k = mono_defaults.boolean_class; interp_add_ins (td, int_cmpop [i].insn [type_index]); - td->sp -= 1; - SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_type (td, stack_type [mint_type (m_class_get_byval_arg (k))], k); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -1725,7 +2063,10 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_add_ins (td, MINT_INTRINS_U32_TO_DECSTR); td->last_ins->data [0] = get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset); td->last_ins->data [1] = get_data_item_index (td, mono_class_vtable_checked (td->rtm->domain, mono_defaults.string_class, error)); - SET_TYPE (td->sp - 1, STACK_TYPE_O, mono_defaults.string_class); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type (td, STACK_TYPE_O, mono_defaults.string_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -1826,8 +2167,10 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas td->last_ins->data [1] = offset_length; td->last_ins->data [2] = offset_pointer; - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); - td->sp -= 1; + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -1837,7 +2180,10 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas int offset_length = length_field->offset - sizeof (MonoObject); interp_add_ins (td, MINT_LDLEN_SPAN); td->last_ins->data [0] = offset_length; - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -1850,7 +2196,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas else if (!strcmp (tm, "ByteOffset")) *op = MINT_INTRINS_UNSAFE_BYTE_OFFSET; else if (!strcmp (tm, "As") || !strcmp (tm, "AsRef")) - *op = MINT_NOP; + *op = MINT_MOV_P; else if (!strcmp (tm, "AsPointer")) { /* NOP */ SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); @@ -1864,8 +2210,10 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoClass *k = mono_defaults.boolean_class; interp_add_ins (td, MINT_CLT_UN_P); - td->sp -= 1; - SET_TYPE (td->sp - 1, stack_type [mint_type (m_class_get_byval_arg (k))], k); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_type (td, stack_type [mint_type (m_class_get_byval_arg (k))], k); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } else if (!strcmp (tm, "SizeOf")) { @@ -1879,12 +2227,13 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &esize); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } else if (!strcmp (tm, "AreSame")) { *op = MINT_CEQ_P; } else if (!strcmp (tm, "SkipInit")) { - *op = MINT_POP; + *op = MINT_NOP; } else if (!strcmp (tm, "InitBlockUnaligned")) { *op = MINT_INITBLK; } @@ -1897,13 +2246,17 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &offset); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } else if (!strcmp (tm, "GetRawData")) { interp_add_ins (td, MINT_LDFLDA_UNSAFE); td->last_ins->data [0] = (gint16) MONO_ABI_SIZEOF (MonoObject); - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; @@ -1972,9 +2325,9 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoType *base_type = mono_type_get_underlying_type (m_class_get_byval_arg (td->sp [-2].klass)); base_klass = mono_class_from_mono_type_internal (base_type); - // Remove the boxing of valuetypes - interp_clear_ins (td->last_ins->prev->prev); - interp_clear_ins (td->last_ins); + // Remove the boxing of valuetypes, by replacing them with moves + td->last_ins->prev->prev->opcode = get_mov_for_type (mint_type (base_type), FALSE); + td->last_ins->opcode = get_mov_for_type (mint_type (base_type), FALSE); intrinsify = TRUE; } else if (td->last_ins && td->last_ins->opcode == MINT_BOX && @@ -1988,16 +2341,19 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas int mt = mint_type (m_class_get_byval_arg (base_klass)); // Remove boxing and load the value of this - interp_clear_ins (td->last_ins); - interp_insert_ins (td, td->last_ins->prev->prev, interp_get_ldind_for_mt (mt)); - + td->last_ins->opcode = get_mov_for_type (mt, FALSE); + InterpInst *ins = interp_insert_ins (td, td->last_ins->prev->prev, interp_get_ldind_for_mt (mt)); + interp_ins_set_sreg (ins, td->sp [-2].local); + interp_ins_set_dreg (ins, td->sp [-2].local); intrinsify = TRUE; } if (intrinsify) { interp_add_ins (td, MINT_INTRINS_ENUM_HASFLAG); td->last_ins->data [0] = get_data_item_index (td, base_klass); td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } @@ -2041,8 +2397,10 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_add_ins (td, is_i8 ? MINT_CGT_UN_I8 : MINT_CGT_UN_I4); else interp_add_ins (td, is_i8 ? MINT_CGT_I8 : MINT_CGT_I4); - td->sp --; - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); // (a < b) load_local (td, locala); load_local (td, localb); @@ -2050,11 +2408,16 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas interp_add_ins (td, is_i8 ? MINT_CLT_UN_I8 : MINT_CLT_UN_I4); else interp_add_ins (td, is_i8 ? MINT_CLT_I8 : MINT_CLT_I4); - td->sp --; - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); // (a > b) - (a < b) interp_add_ins (td, MINT_SUB_I4); - td->sp --; + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; return TRUE; } else { @@ -2394,20 +2757,21 @@ static void interp_constrained_box (TransformData *td, MonoDomain *domain, MonoClass *constrained_class, MonoMethodSignature *csignature, MonoError *error) { int mt = mint_type (m_class_get_byval_arg (constrained_class)); - int ptr_offset = td->sp [-1 - csignature->param_count].offset; + StackInfo *sp = td->sp - 1 - csignature->param_count; if (mono_class_is_nullable (constrained_class)) { g_assert (mt == MINT_TYPE_VT); interp_add_ins (td, MINT_BOX_NULLABLE_PTR); td->last_ins->data [0] = get_data_item_index (td, constrained_class); - td->last_ins->data [1] = ptr_offset; } else { MonoVTable *vtable = mono_class_vtable_checked (domain, constrained_class, error); return_if_nok (error); interp_add_ins (td, MINT_BOX_PTR); td->last_ins->data [0] = get_data_item_index (td, vtable); - td->last_ins->data [1] = ptr_offset; } + interp_ins_set_sreg (td->last_ins, sp->local); + set_simple_type_and_local (td, sp, STACK_TYPE_O); + interp_ins_set_dreg (td->last_ins, sp->local); } static MonoMethod* @@ -2432,6 +2796,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target int op = -1; int native = 0; int need_null_check = is_virtual; + int fp_sreg = -1, first_sreg = -1, dreg = -1; gboolean is_delegate_invoke = FALSE; guint32 token = read32 (td->ip + 1); @@ -2523,9 +2888,12 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target // Follow the rules for constrained calls from ECMA spec if (!m_class_is_valuetype (constrained_class)) { + StackInfo *sp = td->sp - 1 - csignature->param_count; /* managed pointer on the stack, we need to deref that puppy */ interp_add_ins (td, MINT_LDIND_I); - td->last_ins->data [0] = td->sp [-1 - csignature->param_count].offset; + interp_ins_set_sreg (td->last_ins, sp->local); + set_simple_type_and_local (td, sp, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, sp->local); } else if (target_method->klass != constrained_class) { /* * The type parameter is instantiated as a valuetype, @@ -2595,8 +2963,11 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target csignature = mono_method_get_signature_checked (target_method, image, token, generic_context, error); if (need_null_check) { - interp_add_ins (td, MINT_CKNULL_N); - td->last_ins->data [0] = td->sp [-1 - csignature->param_count].offset; + StackInfo *sp = td->sp - 1 - csignature->param_count; + interp_add_ins (td, MINT_CKNULL); + interp_ins_set_sreg (td->last_ins, sp->local); + set_simple_type_and_local (td, sp, sp->type); + interp_ins_set_dreg (td->last_ins, sp->local); } g_assert (csignature->call_convention != MONO_CALL_FASTCALL); @@ -2622,37 +2993,78 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target } /* Pop the function pointer */ - if (calli) + if (calli) { --td->sp; + fp_sreg = td->sp [0].local; + td->locals [fp_sreg].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + } guint32 tos_offset = get_tos_offset (td); td->sp -= csignature->param_count + !!csignature->hasthis; guint32 params_stack_size = tos_offset - get_tos_offset (td); + if (op == -1 || mono_interp_op_dregs [op] == MINT_CALL_ARGS) { + // We must not optimize out these locals, storing to them is part of the interp call convention + // unless we already intrinsified this call + for (int i = 0; i < (csignature->param_count + !!csignature->hasthis); i++) + td->locals [td->sp [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + } + + // We overwrite it with the return local, save it for future use + if (csignature->param_count || csignature->hasthis) + first_sreg = td->sp [0].local; + /* need to handle typedbyref ... */ if (csignature->ret->type != MONO_TYPE_VOID) { int mt = mint_type(csignature->ret); MonoClass *klass = mono_class_from_mono_type_internal (csignature->ret); + if (mt == MINT_TYPE_VT) { if (csignature->pinvoke && method->wrapper_type != MONO_WRAPPER_NONE) res_size = mono_class_native_size (klass, NULL); else res_size = mono_class_value_size (klass, NULL); + push_type_vt (td, klass, res_size); res_size = ALIGN_TO (res_size, MINT_VT_ALIGNMENT); if (mono_class_has_failure (klass)) { mono_error_set_for_class_failure (error, klass); return FALSE; } - push_type_vt (td, klass, res_size); } else { push_type (td, stack_type[mt], klass); res_size = MINT_STACK_SLOT_SIZE; } + dreg = td->sp [-1].local; + if (op == -1 || mono_interp_op_dregs [op] == MINT_CALL_ARGS) { + // This dreg needs to be at the same offset as the call args + td->locals [dreg].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + } + } else { + // Create a new dummy local to serve as the dreg of the call + // This dreg is only used to resolve the call args offset + push_simple_type (td, STACK_TYPE_I4); + td->sp--; + dreg = td->sp [0].local; } if (op >= 0) { interp_add_ins (td, op); + int has_dreg = mono_interp_op_dregs [op]; + int num_sregs = mono_interp_op_sregs [op]; + if (has_dreg) + interp_ins_set_dreg (td->last_ins, dreg); + if (num_sregs > 0) { + if (num_sregs == 1) + interp_ins_set_sreg (td->last_ins, first_sreg); + else if (num_sregs == 2) + interp_ins_set_sregs2 (td->last_ins, first_sreg, td->sp [!has_dreg].local); + else if (num_sregs == 3) + interp_ins_set_sregs3 (td->last_ins, first_sreg, td->sp [!has_dreg].local, td->sp [!has_dreg + 1].local); + else + g_error ("Unsupported opcode"); + } + if (op == MINT_LDLEN) { #ifdef MONO_BIG_ARRAYS SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8); @@ -2663,35 +3075,42 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target #ifndef ENABLE_NETCORE if (op == MINT_CALLRUN) { + interp_ins_set_dreg (td->last_ins, dreg); td->last_ins->data [0] = get_data_item_index (td, target_method); td->last_ins->data [1] = get_data_item_index (td, mono_method_signature_internal (target_method)); } #endif } else if (!calli && !is_delegate_invoke && !is_virtual && mono_interp_jit_call_supported (target_method, csignature)) { interp_add_ins (td, MINT_JIT_CALL); + interp_ins_set_dreg (td->last_ins, dreg); td->last_ins->data [0] = get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error)); mono_error_assert_ok (error); - td->last_ins->data [1] = params_stack_size; } else { if (is_delegate_invoke) { interp_add_ins (td, MINT_CALL_DELEGATE); - td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); - td->last_ins->data [1] = params_stack_size; + interp_ins_set_dreg (td->last_ins, dreg); + td->last_ins->data [0] = params_stack_size; + td->last_ins->data [1] = get_data_item_index (td, (void *)csignature); } else if (calli) { #ifndef MONO_ARCH_HAS_NO_PROPER_MONOCTX /* Try using fast icall path for simple signatures */ if (native && !method->dynamic) op = interp_icall_op_for_sig (csignature); #endif + // FIXME calli receives both the args offset and sometimes another arg for the frame pointer, + // therefore some args are in the param area, while the fp is not. We should differentiate for + // this, probably once we will have an explicit param area where we copy arguments. if (op != -1) { interp_add_ins (td, MINT_CALLI_NAT_FAST); + interp_ins_set_dreg (td->last_ins, dreg); td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); td->last_ins->data [1] = op; td->last_ins->data [2] = save_last_error; } else if (native && method->dynamic && csignature->pinvoke) { interp_add_ins (td, MINT_CALLI_NAT_DYNAMIC); + interp_ins_set_dreg (td->last_ins, dreg); + interp_ins_set_sreg (td->last_ins, fp_sreg); td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); - td->last_ins->data [1] = params_stack_size; } else if (native) { interp_add_ins (td, MINT_CALLI_NAT); #ifdef TARGET_X86 @@ -2714,17 +3133,18 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target } } + interp_ins_set_dreg (td->last_ins, dreg); + interp_ins_set_sreg (td->last_ins, fp_sreg); td->last_ins->data [0] = get_data_item_index (td, csignature); td->last_ins->data [1] = get_data_item_index (td, imethod); - td->last_ins->data [2] = params_stack_size; - td->last_ins->data [3] = res_size; - td->last_ins->data [4] = save_last_error; + td->last_ins->data [2] = save_last_error; /* Cache slot */ - td->last_ins->data [5] = get_data_item_index_nonshared (td, NULL); + td->last_ins->data [3] = get_data_item_index_nonshared (td, NULL); } else { interp_add_ins (td, MINT_CALLI); + interp_ins_set_dreg (td->last_ins, dreg); + interp_ins_set_sreg (td->last_ins, fp_sreg); td->last_ins->data [0] = get_data_item_index (td, (void *)csignature); - td->last_ins->data [1] = params_stack_size; } } else { InterpMethod *imethod = mono_interp_get_imethod (domain, target_method, error); @@ -2732,20 +3152,21 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (csignature->call_convention == MONO_CALL_VARARG) { interp_add_ins (td, MINT_CALL_VARARG); - td->last_ins->data [2] = get_data_item_index (td, (void *)csignature); + td->last_ins->data [1] = get_data_item_index (td, (void *)csignature); + td->last_ins->data [2] = params_stack_size; } else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass)) { interp_add_ins (td, MINT_CALLVIRT_FAST); if (mono_class_is_interface (target_method->klass)) - td->last_ins->data [2] = -2 * MONO_IMT_SIZE + mono_method_get_imt_slot (target_method); + td->last_ins->data [1] = -2 * MONO_IMT_SIZE + mono_method_get_imt_slot (target_method); else - td->last_ins->data [2] = mono_method_get_vtable_slot (target_method); + td->last_ins->data [1] = mono_method_get_vtable_slot (target_method); } else if (is_virtual) { interp_add_ins (td, MINT_CALLVIRT); } else { interp_add_ins (td, MINT_CALL); } + interp_ins_set_dreg (td->last_ins, dreg); td->last_ins->data [0] = get_data_item_index (td, (void *)imethod); - td->last_ins->data [1] = params_stack_size; #ifdef ENABLE_EXPERIMENT_TIERED if (MINT_IS_PATCHABLE_CALL (td->last_ins->opcode)) { @@ -3168,15 +3589,17 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet else type = mono_method_signature_internal (td->method)->params [i - sig->hasthis]; int mt = mint_type (type); + td->locals [i].type = type; td->locals [i].offset = offset; td->locals [i].flags = 0; td->locals [i].indirects = 0; - td->locals [i].type = type; td->locals [i].mt = mt; if (mt == MINT_TYPE_VT && (!sig->hasthis || i != 0)) { size = mono_type_size (type, &align); + td->locals [i].size = size; offset += ALIGN_TO (size, MINT_STACK_SLOT_SIZE); } else { + td->locals [i].size = MINT_STACK_SLOT_SIZE; // not really offset += MINT_STACK_SLOT_SIZE; } } @@ -3194,12 +3617,17 @@ interp_method_compute_offsets (TransformData *td, InterpMethod *imethod, MonoMet offset += align - 1; offset &= ~(align - 1); imethod->local_offsets [i] = offset; + td->locals [index].type = header->locals [i]; td->locals [index].offset = offset; td->locals [index].flags = 0; td->locals [index].indirects = 0; - td->locals [index].type = header->locals [i]; td->locals [index].mt = mint_type (header->locals [i]); - offset += size; + if (td->locals [index].mt == MINT_TYPE_VT) + td->locals [index].size = size; + else + td->locals [index].size = MINT_STACK_SLOT_SIZE; // not really + // Every local takes a MINT_STACK_SLOT_SIZE so IL locals have same behavior as execution locals + offset += ALIGN_TO (size, MINT_STACK_SLOT_SIZE); } offset = ALIGN_TO (offset, MINT_VT_ALIGNMENT); td->il_locals_size = offset - td->il_locals_offset; @@ -3270,7 +3698,15 @@ interp_handle_isinst (TransformData *td, MonoClass *klass, gboolean isinst_instr } else { interp_add_ins (td, isinst_instr ? MINT_ISINST : MINT_CASTCLASS); } + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + if (isinst_instr) + push_type (td, td->sp [0].type, td->sp [0].klass); + else + push_type (td, STACK_TYPE_O, klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, klass); + td->ip += 5; } @@ -3282,6 +3718,7 @@ interp_emit_ldsflda (TransformData *td, MonoClassField *field, MonoError *error) MonoVTable *vtable = mono_class_vtable_checked (domain, field->parent, error); return_if_nok (error); + push_simple_type (td, STACK_TYPE_MP); if (mono_class_field_is_special_static (field)) { guint32 offset; @@ -3292,9 +3729,11 @@ interp_emit_ldsflda (TransformData *td, MonoClassField *field, MonoError *error) g_assert (offset); interp_add_ins (td, MINT_LDSSFLDA); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE32_INS(td->last_ins, 0, &offset); } else { interp_add_ins (td, MINT_LDSFLDA); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, vtable); td->last_ins->data [1] = get_data_item_index (td, (char*)mono_vtable_get_static_field_data (vtable) + field->offset); } @@ -3303,6 +3742,10 @@ interp_emit_ldsflda (TransformData *td, MonoClassField *field, MonoError *error) static gboolean interp_emit_load_const (TransformData *td, gpointer field_addr, int mt) { + if (mt == MINT_TYPE_VT) + return FALSE; + + push_simple_type (td, stack_type [mt]); if ((mt >= MINT_TYPE_I1 && mt <= MINT_TYPE_I4)) { gint32 val; switch (mt) { @@ -3321,20 +3764,25 @@ interp_emit_load_const (TransformData *td, gpointer field_addr, int mt) default: val = *(gint32*)field_addr; } - interp_get_ldc_i4_from_const (td, NULL, val); + interp_get_ldc_i4_from_const (td, NULL, val, td->sp [-1].local); } else if (mt == MINT_TYPE_I8) { gint64 val = *(gint64*)field_addr; interp_add_ins (td, MINT_LDC_I8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE64_INS (td->last_ins, 0, &val); } else if (mt == MINT_TYPE_R4) { float val = *(float*)field_addr; interp_add_ins (td, MINT_LDC_R4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE32_INS (td->last_ins, 0, &val); } else if (mt == MINT_TYPE_R8) { double val = *(double*)field_addr; interp_add_ins (td, MINT_LDC_R8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE64_INS (td->last_ins, 0, &val); } else { + // Revert stack + td->sp--; return FALSE; } return TRUE; @@ -3355,7 +3803,11 @@ emit_convert (TransformData *td, int stype, MonoType *ftype) case MONO_TYPE_I8: { switch (stype) { case STACK_TYPE_I4: + td->sp--; interp_add_ins (td, MINT_CONV_I8_I4); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_I8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); break; default: break; @@ -3387,41 +3839,76 @@ interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *fi // Offset is SpecialStaticOffset if ((offset & 0x80000000) == 0 && mt != MINT_TYPE_VT) { // This field is thread static - interp_add_ins (td, (is_load ? MINT_LDTSFLD_I1 : MINT_STTSFLD_I1) + mt); - WRITE32_INS(td->last_ins, 0, &offset); + if (is_load) { + interp_add_ins (td, MINT_LDTSFLD_I1 + mt); + WRITE32_INS(td->last_ins, 0, &offset); + push_type (td, stack_type [mt], field_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + } else { + interp_add_ins (td, MINT_STTSFLD_I1 + mt); + WRITE32_INS(td->last_ins, 0, &offset); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + } } else { if (mt == MINT_TYPE_VT) { - interp_add_ins (td, is_load ? MINT_LDSSFLD_VT : MINT_STSSFLD_VT); - WRITE32_INS(td->last_ins, 0, &offset); - int size = mono_class_value_size (field_class, NULL); - WRITE32_INS(td->last_ins, 2, &size); + g_assert (size < G_MAXUINT16); + if (is_load) { + interp_add_ins (td, MINT_LDSSFLD_VT); + push_type_vt (td, field_class, size); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + } else { + interp_add_ins (td, MINT_STSSFLD_VT); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + } + WRITE32_INS(td->last_ins, 0, &offset); + td->last_ins->data [2] = size; } else { - interp_add_ins (td, is_load ? MINT_LDSSFLD : MINT_STSSFLD); + if (is_load) { + interp_add_ins (td, MINT_LDSSFLD); + push_type (td, stack_type [mt], field_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + } else { + interp_add_ins (td, MINT_STSSFLD); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + } td->last_ins->data [0] = get_data_item_index (td, field); WRITE32_INS(td->last_ins, 1, &offset); } } } else { gpointer field_addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset; + int size = 0; + if (mt == MINT_TYPE_VT) + size = mono_class_value_size (field_class, NULL); if (is_load) { MonoType *ftype = mono_field_get_type_internal (field); if (ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY && vtable->initialized) { if (interp_emit_load_const (td, field_addr, mt)) return; } - interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_LDSFLD_VT : (MINT_LDSFLD_I1 + mt - MINT_TYPE_I1)); + if (mt == MINT_TYPE_VT) { + interp_add_ins (td, MINT_LDSFLD_VT); + push_type_vt (td, field_class, size); + } else { + interp_add_ins (td, MINT_LDSFLD_I1 + mt - MINT_TYPE_I1); + push_type (td, stack_type [mt], field_class); + } + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else { interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_STSFLD_VT : (MINT_STSFLD_I1 + mt - MINT_TYPE_I1)); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); } td->last_ins->data [0] = get_data_item_index (td, vtable); td->last_ins->data [1] = get_data_item_index (td, (char*)field_addr); + if (mt == MINT_TYPE_VT) + td->last_ins->data [2] = size; - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (field_class, NULL); - WRITE32_INS(td->last_ins, 2, &size); - } } } @@ -3460,6 +3947,8 @@ initialize_clause_bblocks (TransformData *td) bb->stack_state [0].type = STACK_TYPE_O; bb->stack_state [0].klass = NULL; /*FIX*/ bb->stack_state [0].size = MINT_STACK_SLOT_SIZE; + bb->stack_state [0].offset = 0; + bb->stack_state [0].local = create_interp_stack_local (td, STACK_TYPE_O, NULL, MINT_STACK_SLOT_SIZE, 0); } if (c->flags == MONO_EXCEPTION_CLAUSE_FILTER) { @@ -3471,6 +3960,8 @@ initialize_clause_bblocks (TransformData *td) bb->stack_state [0].type = STACK_TYPE_O; bb->stack_state [0].klass = NULL; /*FIX*/ bb->stack_state [0].size = MINT_STACK_SLOT_SIZE; + bb->stack_state [0].offset = 0; + bb->stack_state [0].local = create_interp_stack_local (td, STACK_TYPE_O, NULL, MINT_STACK_SLOT_SIZE, 0); } else if (c->flags == MONO_EXCEPTION_CLAUSE_NONE) { /* * JIT doesn't emit sdb seq intr point at the start of catch clause, probably @@ -3483,6 +3974,62 @@ initialize_clause_bblocks (TransformData *td) } +static void +handle_ldind (TransformData *td, int op, int type, gboolean *volatile_) +{ + CHECK_STACK (td, 1); + interp_add_ins (td, op); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, type); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + + if (*volatile_) { + interp_emit_memory_barrier (td, MONO_MEMORY_BARRIER_ACQ); + *volatile_ = FALSE; + } + ++td->ip; +} + +static void +handle_stind (TransformData *td, int op, gboolean *volatile_) +{ + CHECK_STACK (td, 2); + if (*volatile_) { + interp_emit_memory_barrier (td, MONO_MEMORY_BARRIER_REL); + *volatile_ = FALSE; + } + interp_add_ins (td, op); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + + ++td->ip; +} + +static void +handle_ldelem (TransformData *td, int op, int type) +{ + CHECK_STACK (td, 2); + ENSURE_I4 (td, 1); + interp_add_ins (td, op); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, type); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; +} + +static void +handle_stelem (TransformData *td, int op) +{ + CHECK_STACK (td, 3); + ENSURE_I4 (td, 2); + interp_add_ins (td, op); + td->sp -= 3; + interp_ins_set_sregs3 (td->last_ins, td->sp [0].local, td->sp [1].local, td->sp [2].local); + ++td->ip; +} + static gboolean generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoGenericContext *generic_context, MonoError *error) { @@ -3581,8 +4128,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, last_seq_point->flags |= INTERP_INST_FLAG_SEQ_POINT_METHOD_ENTRY; } - if (mono_debugger_method_has_breakpoint (method)) + if (mono_debugger_method_has_breakpoint (method)) { interp_add_ins (td, MINT_BREAKPOINT); + } if (!inlining) { if (td->verbose_level) { @@ -3601,11 +4149,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, // is localloc'ed so we have compile time static offsets for all locals/stack. arglist_local = create_interp_local (td, m_class_get_byval_arg (mono_defaults.int_class)); interp_add_ins (td, MINT_INIT_ARGLIST); - td->last_ins->data [0] = arglist_local; + interp_ins_set_dreg (td->last_ins, arglist_local); // This is the offset where the variable args are on stack. After this instruction // which copies them to localloc'ed memory, this space will be overwritten by normal // locals - td->last_ins->data [1] = td->il_locals_offset; + td->last_ins->data [0] = td->il_locals_offset; td->has_localloc = TRUE; } @@ -3693,6 +4241,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, * instruction is an unconditional branch (BR, LEAVE, ENDFINALLY) */ interp_link_bblocks (td, td->cbb, new_bb); + fixup_newbb_stack_locals (td, new_bb); } td->cbb->next_bb = new_bb; td->cbb = new_bb; @@ -3730,7 +4279,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (td->verbose_level > 1) g_print ("SKIPPING DEAD OP at %x\n", in_offset); - + link_bblocks = FALSE; td->ip += op_size; continue; } @@ -3765,7 +4314,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, ++td->ip; break; case CEE_BREAK: - SIMPLE_OP(td, MINT_BREAK); + interp_add_ins (td, MINT_BREAK); + ++td->ip; break; case CEE_LDARG_0: case CEE_LDARG_1: @@ -3818,15 +4368,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (!inlining) { interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = n; + interp_ins_set_sreg (td->last_ins, n); td->locals [n].indirects++; } else { int loc_n = arg_locals [n]; interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = loc_n; + interp_ins_set_sreg (td->last_ins, loc_n); td->locals [loc_n].indirects++; } push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 2; break; } @@ -3855,9 +4406,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, loc_n += num_args; else loc_n = local_locals [loc_n]; - td->last_ins->data [0] = loc_n; + interp_ins_set_sreg (td->last_ins, loc_n); td->locals [loc_n].indirects++; push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 2; break; } @@ -3871,31 +4423,47 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; } case CEE_LDNULL: - SIMPLE_OP(td, MINT_LDNULL); + interp_add_ins (td, MINT_LDNULL); push_type (td, STACK_TYPE_O, NULL); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; break; case CEE_LDC_I4_M1: - SIMPLE_OP(td, MINT_LDC_I4_M1); + interp_add_ins (td, MINT_LDC_I4_M1); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; break; case CEE_LDC_I4_0: if (in_offset + 2 < td->code_size && interp_ip_in_cbb (td, in_offset + 1) && td->ip [1] == 0xfe && td->ip [2] == CEE_CEQ && td->sp > td->stack && td->sp [-1].type == STACK_TYPE_I4) { - SIMPLE_OP(td, MINT_CEQ0_I4); - td->ip += 2; + interp_add_ins (td, MINT_CEQ0_I4); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 3; } else { - SIMPLE_OP(td, MINT_LDC_I4_0); + interp_add_ins (td, MINT_LDC_I4_0); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; } break; case CEE_LDC_I4_1: if (in_offset + 1 < td->code_size && interp_ip_in_cbb (td, in_offset + 1) && (td->ip [1] == CEE_ADD || td->ip [1] == CEE_SUB) && td->sp [-1].type == STACK_TYPE_I4) { interp_add_ins (td, td->ip [1] == CEE_ADD ? MINT_ADD1_I4 : MINT_SUB1_I4); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 2; } else { - SIMPLE_OP(td, MINT_LDC_I4_1); + interp_add_ins (td, MINT_LDC_I4_1); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; } break; case CEE_LDC_I4_2: @@ -3905,28 +4473,33 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_LDC_I4_6: case CEE_LDC_I4_7: case CEE_LDC_I4_8: - SIMPLE_OP(td, (*td->ip - CEE_LDC_I4_0) + MINT_LDC_I4_0); + interp_add_ins (td, (*td->ip - CEE_LDC_I4_0) + MINT_LDC_I4_0); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; break; case CEE_LDC_I4_S: interp_add_ins (td, MINT_LDC_I4_S); td->last_ins->data [0] = ((gint8 *) td->ip) [1]; - td->ip += 2; push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 2; break; case CEE_LDC_I4: i32 = read32 (td->ip + 1); interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &i32); - td->ip += 5; push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 5; break; case CEE_LDC_I8: { gint64 val = read64 (td->ip + 1); interp_add_ins (td, MINT_LDC_I8); WRITE64_INS (td->last_ins, 0, &val); - td->ip += 9; push_simple_type (td, STACK_TYPE_I8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 9; break; } case CEE_LDC_R4: { @@ -3934,8 +4507,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, readr4 (td->ip + 1, &val); interp_add_ins (td, MINT_LDC_R4); WRITE32_INS (td->last_ins, 0, &val); - td->ip += 5; push_simple_type (td, STACK_TYPE_R4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 5; break; } case CEE_LDC_R8: { @@ -3943,37 +4517,38 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, readr8 (td->ip + 1, &val); interp_add_ins (td, MINT_LDC_R8); WRITE64_INS (td->last_ins, 0, &val); - td->ip += 9; push_simple_type (td, STACK_TYPE_R8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 9; break; } case CEE_DUP: { int type = td->sp [-1].type; MonoClass *klass = td->sp [-1].klass; - if (td->sp [-1].type == STACK_TYPE_VT) { + int mt = td->locals [td->sp [-1].local].mt; + if (mt == MINT_TYPE_VT) { gint32 size = mono_class_value_size (klass, NULL); - interp_add_ins (td, MINT_DUP_VT); - WRITE32_INS (td->last_ins, 0, &size); - td->ip ++; + g_assert (size < G_MAXUINT16); + + interp_add_ins (td, MINT_MOV_VT); + interp_ins_set_sreg (td->last_ins, td->sp [-1].local); push_type_vt (td, klass, size); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = size; } else { - SIMPLE_OP(td, MINT_DUP); + interp_add_ins (td, get_mov_for_type (mt, FALSE)); + interp_ins_set_sreg (td->last_ins, td->sp [-1].local); push_type (td, type, klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } + td->ip++; break; } case CEE_POP: CHECK_STACK(td, 1); - if (td->sp [-1].type == STACK_TYPE_VT) { - int size = mono_class_value_size (td->sp [-1].klass, NULL); - size = ALIGN_TO (size, MINT_VT_ALIGNMENT); - interp_add_ins (td, MINT_POP_VT); - WRITE32_INS (td->last_ins, 0, &size); - td->ip++; - } else { - SIMPLE_OP(td, MINT_POP); - } + interp_add_ins (td, MINT_NOP); --td->sp; + ++td->ip; break; case CEE_JMP: { MonoMethod *m; @@ -4027,6 +4602,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, /* Return from inlined method, return value is on top of stack */ if (inlining) { td->ip++; + fixup_newbb_stack_locals (td, exit_bb); interp_add_ins (td, MINT_BR_S); td->last_ins->info.target_bb = exit_bb; init_bb_stack_state (td, exit_bb); @@ -4061,24 +4637,32 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, exit_profiling |= PROFILING_FLAG; if (exit_profiling) { /* This does the return as well */ + interp_add_ins (td, MINT_PROF_EXIT); if (ult->type == MONO_TYPE_VOID) { - interp_add_ins (td, MINT_PROF_EXIT_VOID); vt_size = -1; + interp_ins_set_sreg (td->last_ins, -1); } else { - interp_add_ins (td, MINT_PROF_EXIT); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); } + td->last_ins->data [0] = exit_profiling; WRITE32_INS (td->last_ins, 1, &vt_size); - ++td->ip; } else { - if (vt_size == 0) - SIMPLE_OP(td, ult->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET); - else { + if (vt_size == 0) { + if (ult->type == MONO_TYPE_VOID) { + interp_add_ins (td, MINT_RET_VOID); + } else { + interp_add_ins (td, MINT_RET); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + } + } else { interp_add_ins (td, MINT_RET_VT); - WRITE32_INS (td->last_ins, 0, &vt_size); - ++td->ip; + g_assert (vt_size < G_MAXUINT16); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + td->last_ins->data [0] = vt_size; } } + ++td->ip; break; } case CEE_BR: { @@ -4205,6 +4789,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->ip += 4; next_ip = td->ip + n * 4; --td->sp; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); InterpBasicBlock **target_bb_table = (InterpBasicBlock**)mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock*) * n); for (i = 0; i < n; i++) { offset = read32 (td->ip); @@ -4227,118 +4812,61 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; } case CEE_LDIND_I1: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_I1_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_I1_CHECK, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_U1: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_U1_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_U1_CHECK, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_I2: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_I2_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_I2_CHECK, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_U2: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_U2_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_U2_CHECK, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_I4: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_I4_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_I4_CHECK, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_U4: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_U4_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_U4_CHECK, STACK_TYPE_I4, &volatile_); break; case CEE_LDIND_I8: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_I8_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_I8_CHECK, STACK_TYPE_I8, &volatile_); break; case CEE_LDIND_I: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_REF_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_REF_CHECK, STACK_TYPE_I, &volatile_); break; case CEE_LDIND_R4: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_R4_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_R4_CHECK, STACK_TYPE_R4, &volatile_); break; case CEE_LDIND_R8: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_R8_CHECK); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); + handle_ldind (td, MINT_LDIND_R8_CHECK, STACK_TYPE_R8, &volatile_); break; case CEE_LDIND_REF: - CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDIND_REF_CHECK); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O); + handle_ldind (td, MINT_LDIND_REF_CHECK, STACK_TYPE_O, &volatile_); break; case CEE_STIND_REF: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_REF); - td->sp -= 2; + handle_stind (td, MINT_STIND_REF, &volatile_); break; case CEE_STIND_I1: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_I1); - td->sp -= 2; + handle_stind (td, MINT_STIND_I1, &volatile_); break; case CEE_STIND_I2: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_I2); - td->sp -= 2; + handle_stind (td, MINT_STIND_I2, &volatile_); break; case CEE_STIND_I4: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_I4); - td->sp -= 2; + handle_stind (td, MINT_STIND_I4, &volatile_); break; case CEE_STIND_I: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_I); - td->sp -= 2; + handle_stind (td, MINT_STIND_I, &volatile_); break; case CEE_STIND_I8: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_I8); - td->sp -= 2; + handle_stind (td, MINT_STIND_I8, &volatile_); break; case CEE_STIND_R4: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_R4); - td->sp -= 2; + handle_stind (td, MINT_STIND_R4, &volatile_); break; case CEE_STIND_R8: - CHECK_STACK (td, 2); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); - SIMPLE_OP (td, MINT_STIND_R8); - td->sp -= 2; + handle_stind (td, MINT_STIND_R8, &volatile_); break; case CEE_ADD: binary_arith_op(td, MINT_ADD_I4); @@ -4404,203 +4932,200 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_U1_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U1_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_U1_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U1_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_U1_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U1_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_U1_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U1_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_I1: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_I1_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I1_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_I1_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I1_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_I1_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I1_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_I1_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I1_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_U2: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_U2_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U2_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_U2_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U2_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_U2_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U2_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_U2_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U2_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_I2: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_I2_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I2_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_I2_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I2_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_I2_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I2_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_I2_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I2_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_U: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R8: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_CONV_U4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_U4_R8); #else - interp_add_ins (td, MINT_CONV_U8_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_U8_R8); #endif break; case STACK_TYPE_I4: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I8_U4); #endif break; case STACK_TYPE_I8: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_CONV_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_U4_I8); #endif break; case STACK_TYPE_MP: case STACK_TYPE_O: + SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); break; case CEE_CONV_I: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R8: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_I8_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I8_R8); #else - interp_add_ins (td, MINT_CONV_I4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I4_R8); #endif break; case STACK_TYPE_I4: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I8_I4); #endif break; case STACK_TYPE_O: - break; case STACK_TYPE_MP: + SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); break; case STACK_TYPE_I8: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I4_I8); #endif break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); break; case CEE_CONV_U4: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_U4_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U4_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_U4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U4_R8); break; case STACK_TYPE_I4: break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U4_I8); break; case STACK_TYPE_MP: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_U4_I8); +#else + SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); #endif break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_I4: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_I4_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_I4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_R8); break; case STACK_TYPE_I4: break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); break; case STACK_TYPE_MP: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); +#else + SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); #endif break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_I8: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_I8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_I8_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_R8); break; case STACK_TYPE_I4: { if (interp_ins_is_ldc (td->last_ins) && td->last_ins == td->cbb->last_ins) { @@ -4608,9 +5133,12 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_clear_ins (td->last_ins); interp_add_ins (td, MINT_LDC_I8); + td->sp--; + push_simple_type (td, STACK_TYPE_I8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE64_INS (td->last_ins, 0, &ct); } else { - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); } break; } @@ -4619,25 +5147,26 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case STACK_TYPE_MP: #if SIZEOF_VOID_P == 4 interp_add_ins (td, MINT_CONV_I8_I4); +#else + SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); #endif break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); break; case CEE_CONV_R4: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_R4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_R8); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_R4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_I8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_R4_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_I4); break; case STACK_TYPE_R4: /* no-op */ @@ -4646,19 +5175,18 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4); break; case CEE_CONV_R8: CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_R8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_R8_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_I8); break; case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_R8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); break; case STACK_TYPE_R8: break; @@ -4666,7 +5194,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8); break; case CEE_CONV_U8: CHECK_STACK (td, 1); @@ -4677,29 +5204,33 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_clear_ins (td->last_ins); interp_add_ins (td, MINT_LDC_I8); + td->sp--; + push_simple_type (td, STACK_TYPE_I8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE64_INS (td->last_ins, 0, &ct); } else { - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_U4); } break; case STACK_TYPE_I8: break; case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_U8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_U8_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_U8_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_U8_R8); break; case STACK_TYPE_MP: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_U4); +#else + SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); #endif break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); break; case CEE_CPOBJ: { CHECK_STACK (td, 2); @@ -4710,14 +5241,22 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (m_class_is_valuetype (klass)) { int mt = mint_type (m_class_get_byval_arg (klass)); + td->sp -= 2; interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_CPOBJ_VT : MINT_CPOBJ); + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); td->last_ins->data [0] = get_data_item_index(td, klass); } else { + td->sp--; interp_add_ins (td, MINT_LDIND_REF); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + + td->sp -= 2; interp_add_ins (td, MINT_STIND_REF); + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); } td->ip += 5; - td->sp -= 2; break; } case CEE_LDOBJ: { @@ -4740,20 +5279,22 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } case CEE_LDSTR: { token = mono_metadata_token_index (read32 (td->ip + 1)); - td->ip += 5; + push_type (td, STACK_TYPE_O, mono_defaults.string_class); if (method->wrapper_type == MONO_WRAPPER_NONE) { MonoString *s = mono_ldstr_checked (domain, image, token, error); goto_if_nok (error, exit); /* GC won't scan code stream, but reference is held by metadata * machinery so we are good here */ interp_add_ins (td, MINT_LDSTR); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, s); } else { /* defer allocation to execution-time */ interp_add_ins (td, MINT_LDSTR_TOKEN); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, GUINT_TO_POINTER (token)); } - push_type (td, STACK_TYPE_O, mono_defaults.string_class); + td->ip += 5; break; } case CEE_NEWOBJ: { @@ -4784,53 +5325,57 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, int ret_mt = mint_type (m_class_get_byval_arg (klass)); if (mono_class_is_magic_int (klass) || mono_class_is_magic_float (klass)) { - td->sp -= csignature->param_count; + g_assert (csignature->param_count == 1); #if SIZEOF_VOID_P == 8 - if (mono_class_is_magic_int (klass) && td->sp [0].type == STACK_TYPE_I4) - interp_add_ins (td, MINT_CONV_I8_I4); - else if (mono_class_is_magic_float (klass) && td->sp [0].type == STACK_TYPE_R4) - interp_add_ins (td, MINT_CONV_R8_R4); + if (mono_class_is_magic_int (klass) && td->sp [-1].type == STACK_TYPE_I4) + interp_add_conv (td, td->sp - 1, NULL, stack_type [ret_mt], MINT_CONV_I8_I4); + else if (mono_class_is_magic_float (klass) && td->sp [-1].type == STACK_TYPE_R4) + interp_add_conv (td, td->sp - 1, NULL, stack_type [ret_mt], MINT_CONV_R8_R4); #endif - interp_add_ins (td, MINT_NEWOBJ_MAGIC); - td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); - goto_if_nok (error, exit); - - push_type (td, stack_type [ret_mt], klass); } else if (klass == mono_defaults.int_class && csignature->param_count == 1) { - td->sp--; #if SIZEOF_VOID_P == 8 - if (td->sp [0].type == STACK_TYPE_I4) - interp_add_ins (td, MINT_CONV_I8_I4); + if (td->sp [-1].type == STACK_TYPE_I4) + interp_add_conv (td, td->sp - 1, NULL, stack_type [ret_mt], MINT_CONV_I8_I4); #else - if (td->sp [0].type == STACK_TYPE_I8) - interp_add_ins (td, MINT_CONV_OVF_I4_I8); + if (td->sp [-1].type == STACK_TYPE_I8) + interp_add_conv (td, td->sp - 1, NULL, stack_type [ret_mt], MINT_CONV_OVF_I4_I8); #endif - - push_type (td, stack_type [ret_mt], klass); } else if (m_class_get_parent (klass) == mono_defaults.array_class) { + td->sp -= csignature->param_count; + for (int i = 0; i < csignature->param_count; i++) + td->locals [td->sp [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + interp_add_ins (td, MINT_NEWOBJ_ARRAY); td->last_ins->data [0] = get_data_item_index (td, m->klass); td->last_ins->data [1] = csignature->param_count; - td->sp -= csignature->param_count; push_type (td, stack_type [ret_mt], klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; } else if (klass == mono_defaults.string_class) { guint32 tos_offset = get_tos_offset (td); td->sp -= csignature->param_count; guint32 params_stack_size = tos_offset - get_tos_offset (td); + for (int i = 0; i < csignature->param_count; i++) + td->locals [td->sp [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + interp_add_ins (td, MINT_NEWOBJ_STRING); td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); td->last_ins->data [1] = params_stack_size; push_type (td, stack_type [ret_mt], klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; } else if (m_class_get_image (klass) == mono_defaults.corlib && !strcmp (m_class_get_name (m->klass), "ByReference`1") && !strcmp (m->name, ".ctor")) { /* public ByReference(ref T value) */ g_assert (csignature->hasthis && csignature->param_count == 1); - /* We already have the vt on top of the stack */ - interp_add_ins (td, MINT_NOP); td->sp--; + /* We already have the vt on top of the stack. Just do a dummy mov that should be optimized out */ + interp_add_ins (td, MINT_MOV_P); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_type_vt (td, klass, mono_class_value_size (klass, NULL)); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else if (m_class_get_image (klass) == mono_defaults.corlib && (!strcmp (m_class_get_name (m->klass), "Span`1") || !strcmp (m_class_get_name (m->klass), "ReadOnlySpan`1")) && @@ -4840,16 +5385,24 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, /* ctor frequently used with ReadOnlySpan over static arrays */ interp_add_ins (td, MINT_INTRINS_SPAN_CTOR); td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); push_type_vt (td, klass, mono_class_value_size (klass, NULL)); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else { guint32 tos_offset = get_tos_offset (td); td->sp -= csignature->param_count; guint32 params_stack_size = tos_offset - get_tos_offset (td); // Move params types in temporary buffer + // FIXME stop leaking sp_params StackInfo *sp_params = (StackInfo*) g_malloc (sizeof (StackInfo) * csignature->param_count); memcpy (sp_params, td->sp, sizeof (StackInfo) * csignature->param_count); + // We must not optimize out these locals, storing to them is part of the interp call convention + // FIXME this affects inlining efficiency. We need to first remove the param moving by NEWOBJ + for (int i = 0; i < csignature->param_count; i++) + td->locals [sp_params [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + // Push the return value and `this` argument to the ctor gboolean is_vt = m_class_is_valuetype (klass); int vtsize = 0; @@ -4864,6 +5417,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, push_type (td, stack_type [ret_mt], klass); push_type (td, stack_type [ret_mt], klass); } + int dreg = td->sp [-2].local; + td->locals [dreg].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; // Push back the params to top of stack push_types (td, sp_params, csignature->param_count); @@ -4875,28 +5430,34 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (is_vt) { newobj_fast = interp_add_ins (td, MINT_NEWOBJ_VT_FAST); - newobj_fast->data [2] = vtsize; - // FIXME Remove this once we dump stack based design. It is here only to inform cprop - // how many args this instruction receives in inlined case and it is a bad pattern. - newobj_fast->data [3] = csignature->param_count; + interp_ins_set_dreg (newobj_fast, dreg); + newobj_fast->data [1] = ALIGN_TO (vtsize, MINT_STACK_SLOT_SIZE); } else { MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error); goto_if_nok (error, exit); newobj_fast = interp_add_ins (td, MINT_NEWOBJ_FAST); - newobj_fast->data [2] = get_data_item_index (td, vtable); - newobj_fast->data [3] = csignature->param_count; + interp_ins_set_dreg (newobj_fast, dreg); + newobj_fast->data [1] = get_data_item_index (td, vtable); } - newobj_fast->data [1] = params_stack_size; + // FIXME remove these once we have our own local offset allocator, even for execution stack locals + newobj_fast->data [2] = params_stack_size; + newobj_fast->data [3] = csignature->param_count; - // We don't support inlining ctors of MINT_TYPE_VT which also receive a MINT_TYPE_VT - // as an argument. The reason is that we would need to push this on the vtstack before - // the argument, which is very awkward for uncommon scenario. if ((mono_interp_opt & INTERP_OPT_INLINE) && interp_method_check_inlining (td, m, csignature)) { MonoMethodHeader *mheader = interp_method_get_header (m, error); goto_if_nok (error, exit); + // Add local mapping information for cprop to use, in case we inline + int param_count = csignature->param_count; + int *newobj_reg_map = (int*)mono_mempool_alloc (td->mempool, sizeof (int) * param_count * 2); + for (int i = 0; i < param_count; i++) { + newobj_reg_map [2 * i] = sp_params [i].local; + newobj_reg_map [2 * i + 1] = td->sp [-param_count + i].local; + } + if (interp_inline_method (td, m, mheader, error)) { newobj_fast->data [0] = INLINED_METHOD_FLAG; + newobj_fast->info.newobj_reg_map = newobj_reg_map; break; } } @@ -4907,6 +5468,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } else { interp_add_ins (td, MINT_NEWOBJ); g_assert (!m_class_is_valuetype (klass)); + interp_ins_set_dreg (td->last_ins, dreg); td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); td->last_ins->data [1] = params_stack_size; } @@ -4924,8 +5486,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, klass = mini_get_class (method, token, generic_context); CHECK_TYPELOAD (klass); interp_handle_isinst (td, klass, isinst_instr); - if (!isinst_instr) - td->sp [-1].klass = klass; break; } case CEE_CONV_R_UN: @@ -4933,15 +5493,14 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case STACK_TYPE_R8: break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_R_UN_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R_UN_I8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_R_UN_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R_UN_I4); break; default: g_assert_not_reached (); } - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8); ++td->ip; break; case CEE_UNBOX: @@ -4971,14 +5530,19 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, */ int local = create_interp_local (td, m_class_get_byval_arg (klass)); store_local (td, local); + interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = local; - td->locals [local].indirects++; push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_ins_set_sreg (td->last_ins, local); + td->locals [local].indirects++; } else { interp_add_ins (td, MINT_UNBOX); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, klass); - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); td->ip += 5; } break; @@ -5001,14 +5565,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, push_type_vt (td, klass, mono_class_value_size (klass, NULL)); else push_type (td, stack_type [mt], klass); + // FIXME do this somewhere else, maybe in super instruction pass, where we would check + // instruction patterns + // Restore the local that is on top of the stack + td->sp [-1].local = td->last_ins->sregs [0]; td->ip += 5; break; } if (mini_type_is_reference (m_class_get_byval_arg (klass))) { - int mt = mint_type (m_class_get_byval_arg (klass)); interp_handle_isinst (td, klass, FALSE); - SET_TYPE (td->sp - 1, stack_type [mt], klass); } else if (mono_class_is_nullable (klass)) { MonoMethod *target_method; if (m_class_is_enumtype (mono_class_get_nullable_param_internal (klass))) @@ -5021,6 +5587,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, goto exit; } else { interp_add_ins (td, MINT_UNBOX); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, klass); interp_emit_ldobj (td, klass); @@ -5032,9 +5602,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_THROW: INLINE_FAILURE; CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_THROW); + interp_add_ins (td, MINT_THROW); + interp_ins_set_sreg (td->last_ins, td->sp [-1].local); link_bblocks = FALSE; td->sp = td->stack; + ++td->ip; break; case CEE_LDFLDA: { CHECK_STACK (td, 1); @@ -5052,14 +5624,19 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_MONO_LDPTR); td->last_ins->data [0] = get_data_item_index (td, klass); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_add_ins (td, MINT_MONO_LDPTR); td->last_ins->data [0] = get_data_item_index (td, field); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &offset); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); #endif MonoMethod *wrapper = mono_marshal_get_ldflda_wrapper (field->type); @@ -5070,22 +5647,25 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, #endif { if (is_static) { - interp_add_ins (td, MINT_POP); + td->sp--; interp_emit_ldsflda (td, field, error); goto_if_nok (error, exit); } else { - if ((td->sp - 1)->type == STACK_TYPE_O) { + td->sp--; + if (td->sp->type == STACK_TYPE_O) { interp_add_ins (td, MINT_LDFLDA); } else { - int sp_type = (td->sp - 1)->type; + int sp_type = td->sp->type; g_assert (sp_type == STACK_TYPE_MP || sp_type == STACK_TYPE_I); interp_add_ins (td, MINT_LDFLDA_UNSAFE); } td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } td->ip += 5; } - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP); break; } case CEE_LDFLD: { @@ -5100,22 +5680,28 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, MonoClass *field_klass = mono_class_from_mono_type_internal (ftype); mt = mint_type (m_class_get_byval_arg (field_klass)); int field_size = mono_class_value_size (field_klass, NULL); - field_size = ALIGN_TO (field_size, MINT_VT_ALIGNMENT); int obj_size = mono_class_value_size (klass, NULL); obj_size = ALIGN_TO (obj_size, MINT_VT_ALIGNMENT); #ifndef DISABLE_REMOTING - if ((m_class_get_marshalbyref (klass) && !(signature->hasthis && td->last_ins->opcode == MINT_LDLOC_O && td->last_ins->data [0] == 0)) || + if (m_class_get_marshalbyref (klass) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) { g_assert (!is_static); interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_LDRMFLD_VT : MINT_LDRMFLD); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = get_data_item_index (td, field); + if (mt == MINT_TYPE_VT) + push_type_vt (td, field_klass, field_size); + else + push_type (td, stack_type [mt], field_klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else #endif { if (is_static) { - interp_add_ins (td, MINT_POP); + td->sp--; interp_emit_sfld_access (td, field, field_klass, mt, TRUE, error); goto_if_nok (error, exit); } else if (td->sp [-1].type == STACK_TYPE_VT) { @@ -5131,10 +5717,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, #endif interp_add_ins (td, opcode); g_assert (m_class_is_valuetype (klass)); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = field->offset - MONO_ABI_SIZEOF (MonoObject); - td->last_ins->data [1] = obj_size; if (mt == MINT_TYPE_VT) - td->last_ins->data [2] = field_size; + td->last_ins->data [1] = field_size; + if (mt == MINT_TYPE_VT) + push_type_vt (td, field_klass, field_size); + else + push_type (td, stack_type [mt], field_klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else { int opcode = MINT_LDFLD_I1 + mt - MINT_TYPE_I1; #ifdef NO_UNALIGNED_ACCESS @@ -5142,18 +5734,21 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, opcode = get_unaligned_opcode (opcode); #endif interp_add_ins (td, opcode); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset; if (mt == MINT_TYPE_VT) { int size = mono_class_value_size (field_klass, NULL); - WRITE32_INS (td->last_ins, 1, &size); + g_assert (size < G_MAXUINT16); + td->last_ins->data [1] = size; } + if (mt == MINT_TYPE_VT) + push_type_vt (td, field_klass, field_size); + else + push_type (td, stack_type [mt], field_klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } } - td->sp--; - if (mt == MINT_TYPE_VT) - push_type_vt (td, field_klass, field_size); - else - push_type (td, stack_type [mt], field_klass); td->ip += 5; BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_ACQ); break; @@ -5175,6 +5770,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (m_class_get_marshalbyref (klass)) { g_assert (!is_static); interp_add_ins (td, mt == MINT_TYPE_VT ? MINT_STRMFLD_VT : MINT_STRMFLD); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); td->last_ins->data [0] = get_data_item_index (td, field); } else #endif @@ -5184,7 +5781,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, goto_if_nok (error, exit); /* pop the unused object reference */ - interp_add_ins (td, MINT_POP); + td->sp--; /* the vtable of the field might not be initialized at this point */ mono_class_vtable_checked (domain, field_klass, error); @@ -5196,6 +5793,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, opcode = get_unaligned_opcode (opcode); #endif interp_add_ins (td, opcode); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); td->last_ins->data [0] = m_class_is_valuetype (klass) ? field->offset - MONO_ABI_SIZEOF (MonoObject) : field->offset; if (mt == MINT_TYPE_VT) { /* the vtable of the field might not be initialized at this point */ @@ -5211,7 +5810,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } } td->ip += 5; - td->sp -= 2; break; } case CEE_LDSFLDA: { @@ -5221,7 +5819,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_emit_ldsflda (td, field, error); goto_if_nok (error, exit); td->ip += 5; - push_simple_type (td, STACK_TYPE_MP); break; } case CEE_LDSFLD: { @@ -5239,6 +5836,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, { interp_add_ins (td, (TARGET_BYTE_ORDER == G_LITTLE_ENDIAN) ? MINT_LDC_I4_1 : MINT_LDC_I4_0); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; break; } @@ -5246,12 +5844,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_emit_sfld_access (td, field, klass, mt, TRUE, error); goto_if_nok (error, exit); - if (mt == MINT_TYPE_VT) { - int size = mono_class_value_size (klass, NULL); - push_type_vt (td, klass, size); - } else { - push_type (td, stack_type [mt], klass); - } td->ip += 5; break; } @@ -5274,7 +5866,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, goto_if_nok (error, exit); td->ip += 5; - --td->sp; break; } case CEE_STOBJ: { @@ -5299,29 +5890,28 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, switch (td->sp [-1].type) { case STACK_TYPE_R8: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_OVF_I8_UN_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_OVF_I8_UN_R8); #else - interp_add_ins (td, MINT_CONV_OVF_I4_UN_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_OVF_I4_UN_R8); #endif break; case STACK_TYPE_I8: #if SIZEOF_VOID_P == 4 - interp_add_ins (td, MINT_CONV_OVF_I4_U8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_OVF_I4_U8); #endif break; case STACK_TYPE_I4: #if SIZEOF_VOID_P == 8 - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_I8_U4); #elif SIZEOF_VOID_P == 4 if (*td->ip == CEE_CONV_OVF_I_UN) - interp_add_ins (td, MINT_CONV_OVF_I4_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I, MINT_CONV_OVF_I4_U4); #endif break; default: g_assert_not_reached (); break; } - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); ++td->ip; break; case CEE_CONV_OVF_I8_UN: @@ -5329,23 +5919,22 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_I8_UN_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_I8_UN_R8); break; case STACK_TYPE_I8: if (*td->ip == CEE_CONV_OVF_I8_UN) - interp_add_ins (td, MINT_CONV_OVF_I8_U8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_I8_U8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_I8_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_U4); break; case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_I8_UN_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_I8_UN_R4); break; default: g_assert_not_reached (); break; } - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); ++td->ip; break; case CEE_BOX: { @@ -5375,15 +5964,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, const gboolean vt = mint_type (m_class_get_byval_arg (klass)) == MINT_TYPE_VT; if (td->sp [-1].type == STACK_TYPE_R8 && m_class_get_byval_arg (klass)->type == MONO_TYPE_R4) - interp_add_ins (td, MINT_CONV_R4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R4, MINT_CONV_R4_R8); MonoVTable *vtable = mono_class_vtable_checked (domain, klass, error); goto_if_nok (error, exit); td->sp--; interp_add_ins (td, vt ? MINT_BOX_VT : MINT_BOX); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); td->last_ins->data [0] = get_data_item_index (td, vtable); - td->last_ins->data [1] = 0; push_type (td, STACK_TYPE_O, klass); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 5; } @@ -5406,26 +5996,32 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, unsigned char lentype = (td->sp - 1)->type; if (lentype == STACK_TYPE_I8) { /* mimic mini behaviour */ - interp_add_ins (td, MINT_CONV_OVF_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_I8); } else { g_assert (lentype == STACK_TYPE_I4); - interp_add_ins (td, MINT_CONV_OVF_U4_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_I4); } - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); + td->sp--; interp_add_ins (td, MINT_NEWARR); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type (td, STACK_TYPE_O, array_class); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, vtable); - SET_TYPE (td->sp - 1, STACK_TYPE_O, array_class); td->ip += 5; break; } case CEE_LDLEN: CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_LDLEN); + td->sp--; + interp_add_ins (td, MINT_LDLEN); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); #ifdef MONO_BIG_ARRAYS - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I8); + push_simple_type (td, STACK_TYPE_I8); #else - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_I4); + push_simple_type (td, STACK_TYPE_I4); #endif + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; break; case CEE_LDELEMA: { gint32 size; @@ -5448,166 +6044,107 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, mono_class_setup_vtable (klass); CHECK_TYPELOAD (klass); interp_add_ins (td, MINT_LDELEMA_TC); - td->last_ins->data [0] = 1; - td->last_ins->data [1] = get_data_item_index (td, klass); + td->sp -= 2; + td->locals [td->sp [0].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + td->locals [td->sp [1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->locals [td->sp [-1].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + td->last_ins->data [0] = get_data_item_index (td, klass); } else { interp_add_ins (td, MINT_LDELEMA1); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); mono_class_init_internal (klass); size = mono_class_array_element_size (klass); - WRITE32_INS (td->last_ins, 0, &size); + td->last_ins->data [0] = size; } readonly = FALSE; td->ip += 5; - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP); break; } case CEE_LDELEM_I1: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I1); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_I1, STACK_TYPE_I4); break; case CEE_LDELEM_U1: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_U1); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_U1, STACK_TYPE_I4); break; case CEE_LDELEM_I2: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I2); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_I2, STACK_TYPE_I4); break; case CEE_LDELEM_U2: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_U2); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_U2, STACK_TYPE_I4); break; case CEE_LDELEM_I4: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_I4, STACK_TYPE_I4); break; case CEE_LDELEM_U4: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_U4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_U4, STACK_TYPE_I4); break; case CEE_LDELEM_I8: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I8); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); + handle_ldelem (td, MINT_LDELEM_I8, STACK_TYPE_I8); break; case CEE_LDELEM_I: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I); + handle_ldelem (td, MINT_LDELEM_I, STACK_TYPE_I); break; case CEE_LDELEM_R4: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_R4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4); + handle_ldelem (td, MINT_LDELEM_R4, STACK_TYPE_R4); break; case CEE_LDELEM_R8: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_R8); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8); + handle_ldelem (td, MINT_LDELEM_R8, STACK_TYPE_R8); break; case CEE_LDELEM_REF: - CHECK_STACK (td, 2); - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_REF); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O); + handle_ldelem (td, MINT_LDELEM_REF, STACK_TYPE_O); break; case CEE_LDELEM: - CHECK_STACK (td, 2); token = read32 (td->ip + 1); klass = mini_get_class (method, token, generic_context); CHECK_TYPELOAD (klass); switch (mint_type (m_class_get_byval_arg (klass))) { case MINT_TYPE_I1: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I1); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_I1, STACK_TYPE_I4); break; case MINT_TYPE_U1: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_U1); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_U1, STACK_TYPE_I4); break; case MINT_TYPE_U2: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_U2); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_U2, STACK_TYPE_I4); break; case MINT_TYPE_I2: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I2); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_I2, STACK_TYPE_I4); break; case MINT_TYPE_I4: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + handle_ldelem (td, MINT_LDELEM_I4, STACK_TYPE_I4); break; case MINT_TYPE_I8: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_I8); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); + handle_ldelem (td, MINT_LDELEM_I8, STACK_TYPE_I8); break; case MINT_TYPE_R4: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_R4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4); + handle_ldelem (td, MINT_LDELEM_R4, STACK_TYPE_R4); break; case MINT_TYPE_R8: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_R8); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8); + handle_ldelem (td, MINT_LDELEM_R8, STACK_TYPE_R8); break; case MINT_TYPE_O: - ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_REF); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_O); + handle_ldelem (td, MINT_LDELEM_REF, STACK_TYPE_O); break; case MINT_TYPE_VT: { int size = mono_class_value_size (klass, NULL); + g_assert (size < G_MAXUINT16); + + CHECK_STACK (td, 2); ENSURE_I4 (td, 1); - SIMPLE_OP (td, MINT_LDELEM_VT); - WRITE32_INS (td->last_ins, 0, &size); + interp_add_ins (td, MINT_LDELEM_VT); td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); push_type_vt (td, klass, size); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = size; + ++td->ip; break; } default: { @@ -5622,92 +6159,68 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->ip += 4; break; case CEE_STELEM_I: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_I); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_I); break; case CEE_STELEM_I1: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_I1); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_I1); break; case CEE_STELEM_I2: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_I2); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_I2); break; case CEE_STELEM_I4: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_I4); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_I4); break; case CEE_STELEM_I8: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_I8); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_I8); break; case CEE_STELEM_R4: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_R4); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_R4); break; case CEE_STELEM_R8: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_R8); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_R8); break; case CEE_STELEM_REF: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); - SIMPLE_OP (td, MINT_STELEM_REF); - td->sp -= 3; + handle_stelem (td, MINT_STELEM_REF); break; case CEE_STELEM: - CHECK_STACK (td, 3); - ENSURE_I4 (td, 2); token = read32 (td->ip + 1); klass = mini_get_class (method, token, generic_context); CHECK_TYPELOAD (klass); switch (mint_type (m_class_get_byval_arg (klass))) { case MINT_TYPE_I1: - SIMPLE_OP (td, MINT_STELEM_I1); + handle_stelem (td, MINT_STELEM_I1); break; case MINT_TYPE_U1: - SIMPLE_OP (td, MINT_STELEM_U1); + handle_stelem (td, MINT_STELEM_U1); break; case MINT_TYPE_I2: - SIMPLE_OP (td, MINT_STELEM_I2); + handle_stelem (td, MINT_STELEM_I2); break; case MINT_TYPE_U2: - SIMPLE_OP (td, MINT_STELEM_U2); + handle_stelem (td, MINT_STELEM_U2); break; case MINT_TYPE_I4: - SIMPLE_OP (td, MINT_STELEM_I4); + handle_stelem (td, MINT_STELEM_I4); break; case MINT_TYPE_I8: - SIMPLE_OP (td, MINT_STELEM_I8); + handle_stelem (td, MINT_STELEM_I8); break; case MINT_TYPE_R4: - SIMPLE_OP (td, MINT_STELEM_R4); + handle_stelem (td, MINT_STELEM_R4); break; case MINT_TYPE_R8: - SIMPLE_OP (td, MINT_STELEM_R8); + handle_stelem (td, MINT_STELEM_R8); break; case MINT_TYPE_O: - SIMPLE_OP (td, MINT_STELEM_REF); + handle_stelem (td, MINT_STELEM_REF); break; case MINT_TYPE_VT: { int size = mono_class_value_size (klass, NULL); - SIMPLE_OP (td, MINT_STELEM_VT); + g_assert (size < G_MAXUINT16); + + handle_stelem (td, MINT_STELEM_VT); td->last_ins->data [0] = get_data_item_index (td, klass); - WRITE32_INS (td->last_ins, 1, &size); + td->last_ins->data [1] = size; break; } default: { @@ -5720,20 +6233,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, } } td->ip += 4; - td->sp -= 3; break; -#if 0 - case CEE_CONV_OVF_U1: - - case CEE_CONV_OVF_I8: - -#if SIZEOF_VOID_P == 8 - case CEE_CONV_OVF_U: -#endif -#endif case CEE_CKFINITE: CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_CKFINITE); + interp_add_ins (td, MINT_CKFINITE); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_R8); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; break; case CEE_MKREFANY: CHECK_STACK (td, 1); @@ -5743,11 +6251,13 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_TYPELOAD (klass); interp_add_ins (td, MINT_MKREFANY); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type_vt (td, mono_defaults.typed_reference_class, sizeof (MonoTypedRef)); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->last_ins->data [0] = get_data_item_index (td, klass); td->ip += 5; - td->sp--; - push_type_vt (td, mono_defaults.typed_reference_class, sizeof (MonoTypedRef)); break; case CEE_REFANYVAL: { CHECK_STACK (td, 1); @@ -5757,11 +6267,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_TYPELOAD (klass); interp_add_ins (td, MINT_REFANYVAL); - td->last_ins->data [0] = get_data_item_index (td, klass); - td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_simple_type (td, STACK_TYPE_MP); - SET_SIMPLE_TYPE (td->sp - 1, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, klass); td->ip += 5; break; @@ -5772,22 +6282,21 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_UN_R4 : MINT_CONV_OVF_I1_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I1_UN_R4 : MINT_CONV_OVF_I1_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_UN_R8 : MINT_CONV_OVF_I1_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I1_UN_R8 : MINT_CONV_OVF_I1_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_U4 : MINT_CONV_OVF_I1_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I1_U4 : MINT_CONV_OVF_I1_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I1_U8 : MINT_CONV_OVF_I1_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I1_U8 : MINT_CONV_OVF_I1_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; } case CEE_CONV_OVF_U1: @@ -5795,22 +6304,21 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_U1_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U1_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_U1_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U1_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_OVF_U1_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U1_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_OVF_U1_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U1_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; case CEE_CONV_OVF_I2: case CEE_CONV_OVF_I2_UN: { @@ -5818,22 +6326,21 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_UN_R4 : MINT_CONV_OVF_I2_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I2_UN_R4 : MINT_CONV_OVF_I2_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_UN_R8 : MINT_CONV_OVF_I2_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I2_UN_R8 : MINT_CONV_OVF_I2_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_U4 : MINT_CONV_OVF_I2_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I2_U4 : MINT_CONV_OVF_I2_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, is_un ? MINT_CONV_OVF_I2_U8 : MINT_CONV_OVF_I2_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, is_un ? MINT_CONV_OVF_I2_U8 : MINT_CONV_OVF_I2_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; } case CEE_CONV_OVF_U2_UN: @@ -5841,22 +6348,21 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_U2_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U2_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_U2_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U2_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_OVF_U2_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U2_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_OVF_U2_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U2_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; #if SIZEOF_VOID_P == 4 case CEE_CONV_OVF_I: @@ -5866,26 +6372,25 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_I4_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_I4_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_I4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_I4_R8); break; case STACK_TYPE_I4: if (*td->ip == CEE_CONV_OVF_I4_UN) - interp_add_ins (td, MINT_CONV_OVF_I4_U4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_I4_U4); break; case STACK_TYPE_I8: if (*td->ip == CEE_CONV_OVF_I4_UN) - interp_add_ins (td, MINT_CONV_OVF_I4_U8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_I4_U8); else - interp_add_ins (td, MINT_CONV_OVF_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_I4_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; #if SIZEOF_VOID_P == 4 case CEE_CONV_OVF_U: @@ -5895,26 +6400,25 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_U4_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_U4_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_R8); break; case STACK_TYPE_I4: if (*td->ip != CEE_CONV_OVF_U4_UN) - interp_add_ins (td, MINT_CONV_OVF_U4_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_OVF_U4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_I8); break; case STACK_TYPE_MP: - interp_add_ins (td, MINT_CONV_OVF_U4_P); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_OVF_U4_P); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); break; #if SIZEOF_VOID_P == 8 case CEE_CONV_OVF_I: @@ -5923,13 +6427,13 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_I8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_I8_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_I8_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_I8_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_I8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_I8_I4); break; case STACK_TYPE_I8: break; @@ -5937,7 +6441,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); break; #if SIZEOF_VOID_P == 8 case CEE_CONV_OVF_U: @@ -5946,22 +6449,21 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); switch (td->sp [-1].type) { case STACK_TYPE_R4: - interp_add_ins (td, MINT_CONV_OVF_U8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_U8_R4); break; case STACK_TYPE_R8: - interp_add_ins (td, MINT_CONV_OVF_U8_R8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_U8_R8); break; case STACK_TYPE_I4: - interp_add_ins (td, MINT_CONV_OVF_U8_I4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_U8_I4); break; case STACK_TYPE_I8: - interp_add_ins (td, MINT_CONV_OVF_U8_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I8, MINT_CONV_OVF_U8_I8); break; default: g_assert_not_reached (); } ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I8); break; case CEE_LDTOKEN: { int size; @@ -6011,6 +6513,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, else interp_add_ins (td, MINT_LDC_I4_0); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip = next_next_ip + 5; break; } @@ -6018,13 +6521,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_MONO_LDPTR); gpointer systype = mono_type_get_object_checked (domain, (MonoType*)handle, error); goto_if_nok (error, exit); - td->last_ins->data [0] = get_data_item_index (td, systype); push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, systype); td->ip = next_ip + 5; } else { interp_add_ins (td, MINT_LDTOKEN); - td->last_ins->data [0] = get_data_item_index (td, handle); push_type_vt (td, klass, sizeof (gpointer)); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, handle); td->ip += 5; } @@ -6057,9 +6562,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_ENDFINALLY: { g_assert (td->clause_indexes [in_offset] != -1); td->sp = td->stack; - SIMPLE_OP (td, MINT_ENDFINALLY); + interp_add_ins (td, MINT_ENDFINALLY); td->last_ins->data [0] = td->clause_indexes [in_offset]; link_bblocks = FALSE; + ++td->ip; break; } case CEE_LEAVE: @@ -6107,64 +6613,82 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, switch (*td->ip) { case CEE_MONO_RETHROW: CHECK_STACK (td, 1); - SIMPLE_OP (td, MINT_MONO_RETHROW); + interp_add_ins (td, MINT_MONO_RETHROW); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); td->sp = td->stack; + ++td->ip; break; case CEE_MONO_LD_DELEGATE_METHOD_PTR: --td->sp; td->ip += 1; interp_add_ins (td, MINT_LD_DELEGATE_METHOD_PTR); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); break; - case CEE_MONO_CALLI_EXTRA_ARG: + case CEE_MONO_CALLI_EXTRA_ARG: { + int saved_local = td->sp [-1].local; /* Same as CEE_CALLI, except that we drop the extra arg required for llvm specific behaviour */ - interp_add_ins (td, MINT_POP1); - --td->sp; + td->sp -= 2; + StackInfo tos = td->sp [1]; + + // Push back to top of stack and fixup the local offset + push_types (td, &tos, 1); + td->sp [-1].local = saved_local; + td->locals [saved_local].stack_offset = td->sp [-1].offset; + if (!interp_transform_call (td, method, NULL, domain, generic_context, NULL, FALSE, error, FALSE, FALSE, FALSE)) goto exit; break; + } case CEE_MONO_JIT_ICALL_ADDR: { const guint32 token = read32 (td->ip + 1); td->ip += 5; const gconstpointer func = mono_find_jit_icall_info ((MonoJitICallId)token)->func; interp_add_ins (td, MINT_LDFTN); - td->last_ins->data [0] = get_data_item_index (td, (gpointer)func); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, (gpointer)func); break; } case CEE_MONO_ICALL: { + int dreg; MonoJitICallId const jit_icall_id = (MonoJitICallId)read32 (td->ip + 1); MonoJitICallInfo const * const info = mono_find_jit_icall_info (jit_icall_id); td->ip += 5; CHECK_STACK (td, info->sig->param_count); + td->sp -= info->sig->param_count; + for (int i = 0; i < info->sig->param_count; i++) + td->locals [td->sp [i].local].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + if (!MONO_TYPE_IS_VOID (info->sig->ret)) { + int mt = mint_type (info->sig->ret); + push_simple_type (td, stack_type [mt]); + dreg = td->sp [-1].local; + td->locals [dreg].flags |= INTERP_LOCAL_FLAG_CALL_ARGS; + } else { + // Create a new dummy local to serve as the dreg of the call + // This dreg is only used to resolve the call args offset + push_simple_type (td, STACK_TYPE_I4); + td->sp--; + dreg = td->sp [0].local; + } if (jit_icall_id == MONO_JIT_ICALL_mono_threads_attach_coop) { rtm->needs_thread_attach = 1; - - /* attach needs two arguments, and has one return value: leave one element on the stack */ - interp_add_ins (td, MINT_POP); } else if (jit_icall_id == MONO_JIT_ICALL_mono_threads_detach_coop) { g_assert (rtm->needs_thread_attach); - - /* detach consumes two arguments, and no return value: drop both of them */ - interp_add_ins (td, MINT_POP); - interp_add_ins (td, MINT_POP); } else { int const icall_op = interp_icall_op_for_sig (info->sig); g_assert (icall_op != -1); interp_add_ins (td, icall_op); // hash here is overkill + interp_ins_set_dreg (td->last_ins, dreg); td->last_ins->data [0] = get_data_item_index (td, (gpointer)info->func); } - td->sp -= info->sig->param_count; - - if (!MONO_TYPE_IS_VOID (info->sig->ret)) { - int mt = mint_type (info->sig->ret); - push_simple_type (td, stack_type [mt]); - } break; } case CEE_MONO_VTADDR: { @@ -6177,14 +6701,17 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, size = mono_class_value_size (klass, NULL); int local = create_interp_local_explicit (td, m_class_get_byval_arg (klass), size); - interp_add_ins (td, MINT_STLOC_VT); - td->last_ins->data [0] = local; - WRITE32_INS (td->last_ins, 1, &size); + interp_add_ins (td, MINT_MOV_VT); td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + interp_ins_set_dreg (td->last_ins, local); + td->last_ins->data [0] = size; interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = local; push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_ins_set_sreg (td->last_ins, local); + td->locals [local].indirects++; ++td->ip; break; @@ -6195,18 +6722,20 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, token = read32 (td->ip + 1); td->ip += 5; interp_add_ins (td, MINT_MONO_LDPTR); - td->last_ins->data [0] = get_data_item_index (td, mono_method_get_wrapper_data (method, token)); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, mono_method_get_wrapper_data (method, token)); break; case CEE_MONO_PINVOKE_ADDR_CACHE: { token = read32 (td->ip + 1); td->ip += 5; interp_add_ins (td, MINT_MONO_LDPTR); g_assert (method->wrapper_type != MONO_WRAPPER_NONE); + push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); /* This is a memory slot used by the wrapper */ gpointer addr = mono_mem_manager_alloc0 (td->mem_manager, sizeof (gpointer)); td->last_ins->data [0] = get_data_item_index (td, addr); - push_simple_type (td, STACK_TYPE_I); break; } case CEE_MONO_OBJADDR: @@ -6219,8 +6748,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, token = read32 (td->ip + 1); td->ip += 5; interp_add_ins (td, MINT_MONO_NEWOBJ); - td->last_ins->data [0] = get_data_item_index (td, mono_method_get_wrapper_data (method, token)); push_simple_type (td, STACK_TYPE_O); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, mono_method_get_wrapper_data (method, token)); break; case CEE_MONO_RETOBJ: CHECK_STACK (td, 1); @@ -6228,7 +6758,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->ip += 5; interp_add_ins (td, MINT_MONO_RETOBJ); td->sp--; - + interp_ins_set_sreg (td->last_ins, td->sp [0].local); klass = (MonoClass *)mono_method_get_wrapper_data (method, token); /*stackval_from_data (signature->ret, frame->retval, sp->data.vt, signature->pinvoke);*/ @@ -6245,8 +6775,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, int size = mono_class_native_size (klass, NULL); interp_add_ins (td, MINT_LDOBJ_VT); - WRITE32_INS (td->last_ins, 0, &size); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); push_type_vt (td, klass, size); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = size; break; } case CEE_MONO_TLS: { @@ -6255,13 +6787,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, g_assertf (key == TLS_KEY_SGEN_THREAD_INFO, "%d", key); interp_add_ins (td, MINT_MONO_SGEN_THREAD_INFO); push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); break; } case CEE_MONO_ATOMIC_STORE_I4: CHECK_STACK (td, 2); - SIMPLE_OP (td, MINT_MONO_ATOMIC_STORE_I4); + interp_add_ins (td, MINT_MONO_ATOMIC_STORE_I4); td->sp -= 2; - td->ip++; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + td->ip += 2; break; case CEE_MONO_SAVE_LMF: case CEE_MONO_RESTORE_LMF: @@ -6270,8 +6804,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, break; case CEE_MONO_LDPTR_INT_REQ_FLAG: interp_add_ins (td, MINT_MONO_LDPTR); - td->last_ins->data [0] = get_data_item_index (td, &mono_thread_interruption_request_flag); push_type (td, STACK_TYPE_MP, NULL); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->last_ins->data [0] = get_data_item_index (td, &mono_thread_interruption_request_flag); ++td->ip; break; case CEE_MONO_MEMORY_BARRIER: @@ -6281,6 +6816,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_MONO_LDDOMAIN: interp_add_ins (td, MINT_MONO_LDDOMAIN); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; case CEE_MONO_SAVE_LAST_ERROR: @@ -6290,6 +6826,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_MONO_GET_SP: interp_add_ins (td, MINT_MONO_GET_SP); push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; default: @@ -6323,13 +6860,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4); } else { if (td->sp [-1].type == STACK_TYPE_R4 && td->sp [-2].type == STACK_TYPE_R8) - interp_add_ins (td, MINT_CONV_R8_R4); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); if (td->sp [-1].type == STACK_TYPE_R8 && td->sp [-2].type == STACK_TYPE_R4) - interp_add_ins (td, MINT_CONV_R8_R4_SP); + interp_add_conv (td, td->sp - 2, NULL, STACK_TYPE_R8, MINT_CONV_R8_R4); interp_add_ins (td, MINT_CEQ_I4 + td->sp [-1].type - STACK_TYPE_I4); } - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; case CEE_CGT: @@ -6338,8 +6877,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_CGT_I4 + STACK_TYPE_I - STACK_TYPE_I4); else interp_add_ins (td, MINT_CGT_I4 + td->sp [-1].type - STACK_TYPE_I4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; case CEE_CGT_UN: @@ -6348,8 +6889,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_CGT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4); else interp_add_ins (td, MINT_CGT_UN_I4 + td->sp [-1].type - STACK_TYPE_I4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; case CEE_CLT: @@ -6358,8 +6901,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_CLT_I4 + STACK_TYPE_I - STACK_TYPE_I4); else interp_add_ins (td, MINT_CLT_I4 + td->sp [-1].type - STACK_TYPE_I4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; case CEE_CLT_UN: @@ -6368,17 +6913,15 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_CLT_UN_I4 + STACK_TYPE_I - STACK_TYPE_I4); else interp_add_ins (td, MINT_CLT_UN_I4 + td->sp [-1].type - STACK_TYPE_I4); - --td->sp; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); + push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); ++td->ip; break; case CEE_LDVIRTFTN: /* fallthrough */ case CEE_LDFTN: { MonoMethod *m; - if (*td->ip == CEE_LDVIRTFTN) { - CHECK_STACK (td, 1); - --td->sp; - } token = read32 (td->ip + 1); m = interp_get_method (method, token, image, generic_context, error); goto_if_nok (error, exit); @@ -6396,8 +6939,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (m->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) { interp_generate_not_supported_throw (td); interp_add_ins (td, MINT_LDNULL); - td->ip += 5; push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + td->ip += 5; break; } @@ -6428,6 +6972,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_generate_ipe_throw_with_msg (td, wrapper_error); mono_interp_error_cleanup (wrapper_error); interp_add_ins (td, MINT_LDNULL); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else { /* push a pointer to a trampoline that calls m */ gpointer entry = mini_get_interp_callbacks ()->create_method_pointer (m, TRUE, error); @@ -6438,17 +6984,29 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &entry); #endif + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } td->ip += 5; - push_simple_type (td, STACK_TYPE_MP); break; } - - interp_add_ins (td, *td->ip == CEE_LDFTN ? MINT_LDFTN : MINT_LDVIRTFTN); - td->last_ins->data [0] = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); + + int index = get_data_item_index (td, mono_interp_get_imethod (domain, m, error)); goto_if_nok (error, exit); - td->ip += 5; + if (*td->ip == CEE_LDVIRTFTN) { + CHECK_STACK (td, 1); + --td->sp; + interp_add_ins (td, MINT_LDVIRTFTN); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + td->last_ins->data [0] = index; + } else { + interp_add_ins (td, MINT_LDFTN); + td->last_ins->data [0] = index; + } push_simple_type (td, STACK_TYPE_F); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + + td->ip += 5; break; } case CEE_LDARG: { @@ -6465,15 +7023,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (!inlining) { interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = n; + interp_ins_set_sreg (td->last_ins, n); td->locals [n].indirects++; } else { int loc_n = arg_locals [n]; interp_add_ins (td, MINT_LDLOCA_S); - td->last_ins->data [0] = loc_n; + interp_ins_set_sreg (td->last_ins, n); td->locals [loc_n].indirects++; } push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 3; break; } @@ -6502,9 +7061,10 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, loc_n += num_args; else loc_n = local_locals [loc_n]; - td->last_ins->data [0] = loc_n; + interp_ins_set_sreg (td->last_ins, loc_n); td->locals [loc_n].indirects++; push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->ip += 3; break; } @@ -6522,21 +7082,26 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, CHECK_STACK (td, 1); #if SIZEOF_VOID_P == 8 if (td->sp [-1].type == STACK_TYPE_I8) - interp_add_ins (td, MINT_CONV_I4_I8); + interp_add_conv (td, td->sp - 1, NULL, STACK_TYPE_I4, MINT_CONV_I4_I8); #endif interp_add_ins (td, MINT_LOCALLOC); if (td->sp != td->stack + 1) g_warning("CEE_LOCALLOC: stack not empty"); - ++td->ip; - SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_MP); + td->sp--; + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_MP); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); td->has_localloc = TRUE; + ++td->ip; break; #if 0 case CEE_UNUSED57: ves_abort(); break; #endif case CEE_ENDFILTER: interp_add_ins (td, MINT_ENDFILTER); + interp_ins_set_sreg (td->last_ins, td->sp [-1].local); ++td->ip; + link_bblocks = FALSE; break; case CEE_UNALIGNED_: td->ip += 2; @@ -6556,15 +7121,20 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, klass = mini_get_class (method, token, generic_context); CHECK_TYPELOAD (klass); if (m_class_is_valuetype (klass)) { + --td->sp; interp_add_ins (td, MINT_INITOBJ); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); i32 = mono_class_value_size (klass, NULL); - WRITE32_INS (td->last_ins, 0, &i32); - --td->sp; + g_assert (i32 < G_MAXUINT16); + td->last_ins->data [0] = i32; } else { interp_add_ins (td, MINT_LDNULL); push_type (td, STACK_TYPE_O, NULL); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + interp_add_ins (td, MINT_STIND_REF); td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); } td->ip += 5; break; @@ -6574,8 +7144,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, if (volatile_) interp_add_ins (td, MINT_MONO_MEMORY_BARRIER); interp_add_ins (td, MINT_CPBLK); - BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_SEQ); td->sp -= 3; + interp_ins_set_sregs3 (td->last_ins, td->sp [0].local, td->sp [1].local, td->sp [2].local); + BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_SEQ); ++td->ip; break; case CEE_READONLY_: @@ -6593,6 +7164,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, BARRIER_IF_VOLATILE (td, MONO_MEMORY_BARRIER_REL); interp_add_ins (td, MINT_INITBLK); td->sp -= 3; + interp_ins_set_sregs3 (td->last_ins, td->sp [0].local, td->sp [1].local, td->sp [2].local); td->ip += 1; break; case CEE_NO_: @@ -6602,10 +7174,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, case CEE_RETHROW: { int clause_index = td->clause_indexes [in_offset]; g_assert (clause_index != -1); - SIMPLE_OP (td, MINT_RETHROW); + interp_add_ins (td, MINT_RETHROW); td->last_ins->data [0] = rtm->clause_data_offsets [clause_index]; td->sp = td->stack; link_bblocks = FALSE; + ++td->ip; break; } case CEE_SIZEOF: { @@ -6630,13 +7203,16 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_add_ins (td, MINT_LDC_I4); WRITE32_INS (td->last_ins, 0, &size); push_simple_type (td, STACK_TYPE_I4); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); break; } case CEE_REFANYTYPE: interp_add_ins (td, MINT_REFANYTYPE); - td->ip += 1; td->sp--; - push_type_vt (td, NULL, sizeof (gpointer)); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_simple_type (td, STACK_TYPE_I); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + ++td->ip; break; default: g_error ("transform.c: Unimplemented opcode: 0xFE %02x (%s) at 0x%x\n", *td->ip, mono_opcode_name (256 + *td->ip), td->ip-header->code); @@ -6696,15 +7272,15 @@ handle_relocations (TransformData *td) switch (reloc->type) { case RELOC_SHORT_BRANCH: - g_assert (td->new_code [reloc->offset + 1] == 0xdead); - td->new_code [reloc->offset + 1] = offset; + g_assert (td->new_code [reloc->offset + reloc->skip + 1] == 0xdead); + td->new_code [reloc->offset + reloc->skip + 1] = offset; break; case RELOC_LONG_BRANCH: { guint16 *v = (guint16 *) &offset; - g_assert (td->new_code [reloc->offset + 1] == 0xdead); - g_assert (td->new_code [reloc->offset + 2] == 0xbeef); - td->new_code [reloc->offset + 1] = *(guint16 *) v; - td->new_code [reloc->offset + 2] = *(guint16 *) (v + 1); + g_assert (td->new_code [reloc->offset + reloc->skip + 1] == 0xdead); + g_assert (td->new_code [reloc->offset + reloc->skip + 2] == 0xbeef); + td->new_code [reloc->offset + reloc->skip + 1] = *(guint16 *) v; + td->new_code [reloc->offset + reloc->skip + 2] = *(guint16 *) (v + 1); break; } case RELOC_SWITCH: { @@ -6722,7 +7298,6 @@ handle_relocations (TransformData *td) } } - static int get_inst_length (InterpInst *ins) { @@ -6736,96 +7311,6 @@ get_inst_length (InterpInst *ins) return mono_interp_oplen [ins->opcode]; } -static void -get_inst_stack_usage (TransformData *td, InterpInst *ins, int *pop, int *push) -{ - guint16 opcode = ins->opcode; - if (mono_interp_oppop [opcode] == MINT_VAR_POP || - mono_interp_oppush [opcode] == MINT_VAR_PUSH) { - switch (opcode) { - case MINT_JIT_CALL: - case MINT_CALL: - case MINT_CALLVIRT: - case MINT_CALLVIRT_FAST: { - InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; - *pop = imethod->param_count + imethod->hasthis; - *push = imethod->rtype->type != MONO_TYPE_VOID; - break; - } -#ifndef ENABLE_NETCORE - case MINT_CALLRUN: { - MonoMethodSignature *csignature = (MonoMethodSignature*) td->data_items [ins->data [1]]; - *pop = csignature->param_count + csignature->hasthis; - *push = csignature->ret->type != MONO_TYPE_VOID; - break; - } -#endif - case MINT_CALL_DELEGATE: { - MonoMethodSignature *csignature = (MonoMethodSignature*) td->data_items [ins->data [0]]; - *pop = csignature->param_count + 1; - *push = csignature->ret->type != MONO_TYPE_VOID; - break; - } - case MINT_CALLI: - case MINT_CALLI_NAT: - case MINT_CALLI_NAT_DYNAMIC: - case MINT_CALLI_NAT_FAST: { - MonoMethodSignature *csignature = (MonoMethodSignature*) td->data_items [ins->data [0]]; - *pop = csignature->param_count + csignature->hasthis + 1; - *push = csignature->ret->type != MONO_TYPE_VOID; - break; - } - case MINT_CALL_VARARG: { - InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; - MonoMethodSignature *csignature = (MonoMethodSignature*) td->data_items [ins->data [2]]; - *pop = imethod->param_count + imethod->hasthis + csignature->param_count - csignature->sentinelpos; - *push = imethod->rtype->type != MONO_TYPE_VOID; - break; - } - case MINT_NEWOBJ_VT_FAST: - case MINT_NEWOBJ_FAST: { - gboolean is_inlined = ins->data [0] == INLINED_METHOD_FLAG; - if (is_inlined) { - // This needs to be handled explictly during cprop, in order to properly - // keep track of stack contents - *pop = 0; - *push = 2; - } else { - InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; - *pop = imethod->param_count; - *push = 1; - } - break; - } - case MINT_NEWOBJ_ARRAY: - *pop = ins->data [1]; - *push = 1; - break; - case MINT_NEWOBJ_STRING: { - InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; - *pop = imethod->param_count; - *push = 1; - break; - } - case MINT_LDELEMA: - case MINT_LDELEMA_TC: - *pop = ins->data [0] + 1; - *push = 1; - break; - case MINT_NEWOBJ: { - InterpMethod *imethod = (InterpMethod*) td->data_items [ins->data [0]]; - *pop = imethod->param_count; - *push = 1; - break; - } - default: - g_assert_not_reached (); - } - } else { - *pop = mono_interp_oppop [opcode]; - *push = mono_interp_oppush [opcode]; - } -} static guint16* emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *ins) @@ -6851,6 +7336,7 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in *ip++ = opcode; if (opcode == MINT_SWITCH) { int labels = READ32 (&ins->data [0]); + *ip++ = get_interp_local_offset (td, ins->sregs [0], TRUE); // Write number of switch labels *ip++ = ins->data [0]; *ip++ = ins->data [1]; @@ -6868,6 +7354,8 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in (opcode >= MINT_BEQ_I4_S && opcode <= MINT_BLT_UN_R8_S) || opcode == MINT_BR_S || opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK || opcode == MINT_CALL_HANDLER_S) { const int br_offset = start_ip - td->new_code; + for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) + *ip++ = get_interp_local_offset (td, ins->sregs [i], TRUE); if (ins->info.target_bb->native_offset >= 0) { // Backwards branch. We can already patch it. *ip++ = ins->info.target_bb->native_offset - br_offset; @@ -6875,6 +7363,7 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in // We don't know the in_offset of the target, add a reloc Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc)); reloc->type = RELOC_SHORT_BRANCH; + reloc->skip = mono_interp_op_sregs [opcode]; reloc->offset = br_offset; reloc->target_bb = ins->info.target_bb; g_ptr_array_add (td->relocs, reloc); @@ -6886,6 +7375,8 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in (opcode >= MINT_BEQ_I4 && opcode <= MINT_BLT_UN_R8) || opcode == MINT_BR || opcode == MINT_LEAVE || opcode == MINT_LEAVE_CHECK || opcode == MINT_CALL_HANDLER) { const int br_offset = start_ip - td->new_code; + for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) + *ip++ = get_interp_local_offset (td, ins->sregs [i], TRUE); if (ins->info.target_bb->native_offset >= 0) { // Backwards branch. We can already patch it int target_offset = ins->info.target_bb->native_offset - br_offset; @@ -6893,6 +7384,7 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in } else { Reloc *reloc = (Reloc*)mono_mempool_alloc0 (td->mempool, sizeof (Reloc)); reloc->type = RELOC_LONG_BRANCH; + reloc->skip = mono_interp_op_sregs [opcode]; reloc->offset = br_offset; reloc->target_bb = ins->info.target_bb; g_ptr_array_add (td->relocs, reloc); @@ -6949,25 +7441,42 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in *ip++ = MINT_NIY; #endif } else { - if (MINT_IS_LDLOC (opcode) || MINT_IS_STLOC (opcode) || MINT_IS_STLOC_NP (opcode) || opcode == MINT_LDLOCA_S || - MINT_IS_LDLOCFLD (opcode) || MINT_IS_LOCUNOP (opcode) || MINT_IS_STLOCFLD (opcode)) { - ins->data [0] = get_interp_local_offset (td, ins->data [0]); - } else if (MINT_IS_MOVLOC (opcode)) { - ins->data [0] = get_interp_local_offset (td, ins->data [0]); - ins->data [1] = get_interp_local_offset (td, ins->data [1]); - } else if (opcode == MINT_INIT_ARGLIST) { - ins->data [0] = get_interp_local_offset (td, ins->data [0]); + if (mono_interp_op_dregs [opcode]) + *ip++ = get_interp_local_offset (td, ins->dreg, TRUE); + + if (mono_interp_op_sregs [opcode]) { + for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) + *ip++ = get_interp_local_offset (td, ins->sregs [i], TRUE); + } else if (opcode == MINT_LDLOCA_S) { + // This opcode receives a local but it is not viewed as a sreg since we don't load the value + *ip++ = get_interp_local_offset (td, ins->sregs [0], TRUE); } - int size = get_inst_length (ins) - 1; + int left = get_inst_length (ins) - (ip - start_ip); // Emit the rest of the data - for (int i = 0; i < size; i++) + for (int i = 0; i < left; i++) *ip++ = ins->data [i]; } mono_interp_stats.emitted_instructions++; return ip; } +static void +alloc_ins_locals (TransformData *td, InterpInst *ins) +{ + int opcode = ins->opcode; + if (mono_interp_op_sregs [opcode]) { + for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) + get_interp_local_offset (td, ins->sregs [i], FALSE); + } else if (opcode == MINT_LDLOCA_S) { + // This opcode receives a local but it is not viewed as a sreg since we don't load the value + get_interp_local_offset (td, ins->sregs [0], FALSE); + } + + if (mono_interp_op_dregs [opcode]) + get_interp_local_offset (td, ins->dreg, FALSE); +} + // Generates the final code, after we are done with all the passes static void generate_compacted_code (TransformData *td) @@ -6977,11 +7486,12 @@ generate_compacted_code (TransformData *td) td->relocs = g_ptr_array_new (); InterpBasicBlock *bb; - // Iterate once to compute the exact size of the compacted code + // Iterate once for preliminary computations for (bb = td->entry_bb; bb != NULL; bb = bb->next_bb) { InterpInst *ins = bb->first_ins; while (ins) { size += get_inst_length (ins); + alloc_ins_locals (td, ins); ins = ins->next; } } @@ -7007,58 +7517,6 @@ generate_compacted_code (TransformData *td) g_ptr_array_free (td->relocs, TRUE); } -static int -get_movloc_for_type (int mt) -{ - switch (mt) { - case MINT_TYPE_I1: - case MINT_TYPE_U1: - return MINT_MOVLOC_1; - case MINT_TYPE_I2: - case MINT_TYPE_U2: - return MINT_MOVLOC_2; - case MINT_TYPE_I4: - case MINT_TYPE_R4: - return MINT_MOVLOC_4; - case MINT_TYPE_I8: - case MINT_TYPE_R8: - return MINT_MOVLOC_8; - case MINT_TYPE_O: -#if SIZEOF_VOID_P == 8 - return MINT_MOVLOC_8; -#else - return MINT_MOVLOC_4; -#endif - case MINT_TYPE_VT: - return MINT_MOVLOC_VT; - } - g_assert_not_reached (); -} - -// The value of local has changed. This means the contents of the stack where the -// local was loaded, no longer contain the value of the local. Clear them. -static void -clear_stack_content_info_for_local (StackContentInfo *start, StackContentInfo *end, int local) -{ - StackContentInfo *si; - for (si = start; si < end; si++) { - if (si->val.type == STACK_VALUE_LOCAL && si->val.local == local) - si->val.type = STACK_VALUE_NONE; - } -} - -// The value of local has changed. This means we can no longer assume that any other local -// is a copy of this local. -static void -clear_local_content_info_for_local (StackValue *start, StackValue *end, int local) -{ - StackValue *sval; - for (sval = start; sval < end; sval++) { - if (sval->type == STACK_VALUE_LOCAL && sval->local == local) - sval->type = STACK_VALUE_NONE; - } -} - // Traverse the list of basic blocks and merge adjacent blocks static gboolean interp_optimize_bblocks (TransformData *td) @@ -7100,13 +7558,10 @@ interp_local_deadce (TransformData *td, int *local_ref_count) g_assert (td->locals [i].indirects >= 0); if (!local_ref_count [i] && !td->locals [i].indirects && + !(td->locals [i].flags & INTERP_LOCAL_FLAG_CALL_ARGS) && (td->locals [i].flags & INTERP_LOCAL_FLAG_DEAD) == 0) { needs_dce = TRUE; - // If we do another deadce iteration over the code, make sure we don't try - // to kill instructions accessing locals that have already been handled in - // a previous iteration. td->locals [i].flags |= INTERP_LOCAL_FLAG_DEAD; - break; } } @@ -7117,24 +7572,29 @@ interp_local_deadce (TransformData *td, int *local_ref_count) // Kill instructions that don't use stack and are storing into dead locals for (InterpBasicBlock *bb = td->entry_bb; bb != NULL; bb = bb->next_bb) { for (InterpInst *ins = bb->first_ins; ins != NULL; ins = ins->next) { - if (MINT_IS_STLOC_NP (ins->opcode)) { - if (!local_ref_count [ins->data [0]] && !td->locals [ins->data [0]].indirects) { - interp_clear_ins (ins); - mono_interp_stats.killed_instructions++; - // We killed an instruction that makes use of the stack. This might uncover new optimizations - needs_cprop = TRUE; - } - } else if (MINT_IS_MOVLOC (ins->opcode)) { - if (!local_ref_count [ins->data [1]] && !td->locals [ins->data [1]].indirects) { + if (MINT_IS_MOV (ins->opcode) || + MINT_IS_LDC_I4 (ins->opcode) || + ins->opcode == MINT_LDC_I8 || + ins->opcode == MINT_MONO_LDPTR || + ins->opcode == MINT_LDLOCA_S) { + int dreg = ins->dreg; + if (td->locals [dreg].flags & INTERP_LOCAL_FLAG_DEAD) { + if (td->verbose_level) { + g_print ("kill dead ins:\n\t"); + dump_interp_inst (ins); + } + + if (ins->opcode == MINT_LDLOCA_S) { + mono_interp_stats.ldlocas_removed++; + td->locals [ins->sregs [0]].indirects--; + if (!td->locals [ins->sregs [0]].indirects) { + // We can do cprop now through this local. Run cprop again. + needs_cprop = TRUE; + } + } interp_clear_ins (ins); mono_interp_stats.killed_instructions++; - } - } else if (MINT_IS_STLOC (ins->opcode) && ins->opcode != MINT_STLOC_VT) { - if (!local_ref_count [ins->data [0]] && !td->locals [ins->data [0]].indirects) { - // We store to a dead stloc, we can replace it with a POP to save local space - ins->opcode = MINT_POP; - mono_interp_stats.added_pop_count++; - // We might to be able to kill both the pop and the instruction pushing the value + // FIXME This is lazy. We should update the ref count for the sregs and redo deadce. needs_cprop = TRUE; } } @@ -7143,144 +7603,134 @@ interp_local_deadce (TransformData *td, int *local_ref_count) return needs_cprop; } -#define INTERP_FOLD_UNOP(opcode,stack_type,field,op) \ +#define INTERP_FOLD_UNOP(opcode,val_type,field,op) \ case opcode: \ - g_assert (sp->val.type == stack_type); \ - result.type = stack_type; \ - result.field = op sp->val.field; \ + g_assert (val->type == val_type); \ + result.type = val_type; \ + result.field = op val->field; \ break; -#define INTERP_FOLD_CONV(opcode,stack_type_dst,field_dst,stack_type_src,field_src,cast_type) \ +#define INTERP_FOLD_CONV(opcode,val_type_dst,field_dst,val_type_src,field_src,cast_type) \ case opcode: \ - g_assert (sp->val.type == stack_type_src); \ - result.type = stack_type_dst; \ - result.field_dst = (cast_type)sp->val.field_src; \ + g_assert (val->type == val_type_src); \ + result.type = val_type_dst; \ + result.field_dst = (cast_type)val->field_src; \ break; -#define INTERP_FOLD_CONV_FULL(opcode,stack_type_dst,field_dst,stack_type_src,field_src,cast_type,cond) \ +#define INTERP_FOLD_CONV_FULL(opcode,val_type_dst,field_dst,val_type_src,field_src,cast_type,cond) \ case opcode: \ - g_assert (sp->val.type == stack_type_src); \ - if (!(cond)) goto cfold_failed; \ - result.type = stack_type_dst; \ - result.field_dst = (cast_type)sp->val.field_src; \ + g_assert (val->type == val_type_src); \ + if (!(cond)) return ins; \ + result.type = val_type_dst; \ + result.field_dst = (cast_type)val->field_src; \ break; static InterpInst* -interp_fold_unop (TransformData *td, StackContentInfo *sp, InterpInst *ins) +interp_fold_unop (TransformData *td, LocalValue *local_defs, int *local_ref_count, InterpInst *ins) { - StackValue result; - - if (ins->opcode >= MINT_CONV_I4_I8_SP && - ins->opcode <= MINT_CONV_R8_R4_SP) { - // Decrement sp so it's easier to access top of the stack - sp -= 2; - if (sp->val.type != STACK_VALUE_I4 && sp->val.type != STACK_VALUE_I8) - goto cfold_failed; - - switch (ins->opcode) { - INTERP_FOLD_CONV (MINT_CONV_I4_I8_SP, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); - INTERP_FOLD_CONV (MINT_CONV_I8_I4_SP, STACK_VALUE_I8, l, STACK_VALUE_I4, i, gint64); - default: - goto cfold_failed; - } - } else { - // Decrement sp so it's easier to access top of the stack - sp--; - if (sp->val.type != STACK_VALUE_I4 && sp->val.type != STACK_VALUE_I8) - goto cfold_failed; - - // Top of the stack is a constant - switch (ins->opcode) { - INTERP_FOLD_UNOP (MINT_ADD1_I4, STACK_VALUE_I4, i, 1+); - INTERP_FOLD_UNOP (MINT_ADD1_I8, STACK_VALUE_I8, l, 1+); - INTERP_FOLD_UNOP (MINT_SUB1_I4, STACK_VALUE_I4, i, -1+); - INTERP_FOLD_UNOP (MINT_SUB1_I8, STACK_VALUE_I8, l, -1+); - INTERP_FOLD_UNOP (MINT_NEG_I4, STACK_VALUE_I4, i, -); - INTERP_FOLD_UNOP (MINT_NEG_I8, STACK_VALUE_I8, l, -); - INTERP_FOLD_UNOP (MINT_NOT_I4, STACK_VALUE_I4, i, ~); - INTERP_FOLD_UNOP (MINT_NOT_I8, STACK_VALUE_I8, l, ~); - INTERP_FOLD_UNOP (MINT_CEQ0_I4, STACK_VALUE_I4, i, 0 ==); - - INTERP_FOLD_CONV (MINT_CONV_I1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint8); - INTERP_FOLD_CONV (MINT_CONV_I1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint8); - INTERP_FOLD_CONV (MINT_CONV_U1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint8); - INTERP_FOLD_CONV (MINT_CONV_U1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint8); - - INTERP_FOLD_CONV (MINT_CONV_I2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint16); - INTERP_FOLD_CONV (MINT_CONV_I2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint16); - INTERP_FOLD_CONV (MINT_CONV_U2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint16); - INTERP_FOLD_CONV (MINT_CONV_U2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint16); - - INTERP_FOLD_CONV (MINT_CONV_I4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); - INTERP_FOLD_CONV (MINT_CONV_U4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32); - - INTERP_FOLD_CONV (MINT_CONV_I8_I4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, gint32); - INTERP_FOLD_CONV (MINT_CONV_I8_U4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, guint32); - - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint8, sp [0].val.i >= G_MININT8 && sp [0].val.i <= G_MAXINT8); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint8, sp [0].val.l >= G_MININT8 && sp [0].val.l <= G_MAXINT8); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_U4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint8, sp [0].val.i >= 0 && sp [0].val.i <= G_MAXINT8); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_U8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint8, sp [0].val.l >= 0 && sp [0].val.l <= G_MAXINT8); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U1_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint8, sp [0].val.i >= 0 && sp [0].val.i <= G_MAXUINT8); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U1_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint8, sp [0].val.l >= 0 && sp [0].val.l <= G_MAXUINT8); - - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint16, sp [0].val.i >= G_MININT16 && sp [0].val.i <= G_MAXINT16); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, i, gint16, sp [0].val.l >= G_MININT16 && sp [0].val.l <= G_MAXINT16); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_U4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint16, sp [0].val.i >= 0 && sp [0].val.i <= G_MAXINT16); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_U8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint16, sp [0].val.l >= 0 && sp [0].val.l <= G_MAXINT16); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U2_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint16, sp [0].val.i >= 0 && sp [0].val.i <= G_MAXUINT16); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U2_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint16, sp [0].val.l >= 0 && sp [0].val.l <= G_MAXUINT16); - - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I4_U4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, gint32, sp [0].val.i >= 0); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32, sp [0].val.l >= G_MININT32 && sp [0].val.l <= G_MAXINT32); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I4_U8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, gint32, sp [0].val.l >= 0 && sp [0].val.l <= G_MAXINT32); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U4_I4, STACK_VALUE_I4, i, STACK_VALUE_I4, i, guint32, sp [0].val.i >= 0); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U4_I8, STACK_VALUE_I4, i, STACK_VALUE_I8, l, guint32, sp [0].val.l >= 0 && sp [0].val.l <= G_MAXINT32); - - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I8_U8, STACK_VALUE_I8, l, STACK_VALUE_I8, l, gint64, sp [0].val.l >= 0); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U8_I4, STACK_VALUE_I8, l, STACK_VALUE_I4, i, guint64, sp [0].val.i >= 0); - INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U8_I8, STACK_VALUE_I8, l, STACK_VALUE_I8, l, guint64, sp [0].val.l >= 0); + // ins should be an unop, therefore it should have a single dreg and a single sreg + int dreg = ins->dreg; + int sreg = ins->sregs [0]; + LocalValue *val = &local_defs [sreg]; + LocalValue result; - default: - goto cfold_failed; - } + if (val->type != LOCAL_VALUE_I4 && val->type != LOCAL_VALUE_I8) + return ins; + + // Top of the stack is a constant + switch (ins->opcode) { + INTERP_FOLD_UNOP (MINT_ADD1_I4, LOCAL_VALUE_I4, i, 1+); + INTERP_FOLD_UNOP (MINT_ADD1_I8, LOCAL_VALUE_I8, l, 1+); + INTERP_FOLD_UNOP (MINT_SUB1_I4, LOCAL_VALUE_I4, i, -1+); + INTERP_FOLD_UNOP (MINT_SUB1_I8, LOCAL_VALUE_I8, l, -1+); + INTERP_FOLD_UNOP (MINT_NEG_I4, LOCAL_VALUE_I4, i, -); + INTERP_FOLD_UNOP (MINT_NEG_I8, LOCAL_VALUE_I8, l, -); + INTERP_FOLD_UNOP (MINT_NOT_I4, LOCAL_VALUE_I4, i, ~); + INTERP_FOLD_UNOP (MINT_NOT_I8, LOCAL_VALUE_I8, l, ~); + INTERP_FOLD_UNOP (MINT_CEQ0_I4, LOCAL_VALUE_I4, i, 0 ==); + + // MOV's are just a copy, if the contents of sreg are known + INTERP_FOLD_CONV (MINT_MOV_I1, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint32); + INTERP_FOLD_CONV (MINT_MOV_U1, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint32); + INTERP_FOLD_CONV (MINT_MOV_I2, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint32); + INTERP_FOLD_CONV (MINT_MOV_U2, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint32); + + INTERP_FOLD_CONV (MINT_CONV_I1_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint8); + INTERP_FOLD_CONV (MINT_CONV_I1_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint8); + INTERP_FOLD_CONV (MINT_CONV_U1_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, guint8); + INTERP_FOLD_CONV (MINT_CONV_U1_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, guint8); + + INTERP_FOLD_CONV (MINT_CONV_I2_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint16); + INTERP_FOLD_CONV (MINT_CONV_I2_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint16); + INTERP_FOLD_CONV (MINT_CONV_U2_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, guint16); + INTERP_FOLD_CONV (MINT_CONV_U2_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, guint16); + + INTERP_FOLD_CONV (MINT_CONV_I4_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint32); + INTERP_FOLD_CONV (MINT_CONV_U4_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint32); + + INTERP_FOLD_CONV (MINT_CONV_I8_I4, LOCAL_VALUE_I8, l, LOCAL_VALUE_I4, i, gint32); + INTERP_FOLD_CONV (MINT_CONV_I8_U4, LOCAL_VALUE_I8, l, LOCAL_VALUE_I4, i, guint32); + + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint8, val->i >= G_MININT8 && val->i <= G_MAXINT8); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint8, val->l >= G_MININT8 && val->l <= G_MAXINT8); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_U4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint8, val->i >= 0 && val->i <= G_MAXINT8); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I1_U8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint8, val->l >= 0 && val->l <= G_MAXINT8); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U1_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, guint8, val->i >= 0 && val->i <= G_MAXUINT8); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U1_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, guint8, val->l >= 0 && val->l <= G_MAXUINT8); + + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint16, val->i >= G_MININT16 && val->i <= G_MAXINT16); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, i, gint16, val->l >= G_MININT16 && val->l <= G_MAXINT16); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_U4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint16, val->i >= 0 && val->i <= G_MAXINT16); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I2_U8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint16, val->l >= 0 && val->l <= G_MAXINT16); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U2_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, guint16, val->i >= 0 && val->i <= G_MAXUINT16); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U2_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, guint16, val->l >= 0 && val->l <= G_MAXUINT16); + + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I4_U4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, gint32, val->i >= 0); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I4_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint32, val->l >= G_MININT32 && val->l <= G_MAXINT32); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I4_U8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, gint32, val->l >= 0 && val->l <= G_MAXINT32); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U4_I4, LOCAL_VALUE_I4, i, LOCAL_VALUE_I4, i, guint32, val->i >= 0); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U4_I8, LOCAL_VALUE_I4, i, LOCAL_VALUE_I8, l, guint32, val->l >= 0 && val->l <= G_MAXINT32); + + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_I8_U8, LOCAL_VALUE_I8, l, LOCAL_VALUE_I8, l, gint64, val->l >= 0); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U8_I4, LOCAL_VALUE_I8, l, LOCAL_VALUE_I4, i, guint64, val->i >= 0); + INTERP_FOLD_CONV_FULL (MINT_CONV_OVF_U8_I8, LOCAL_VALUE_I8, l, LOCAL_VALUE_I8, l, guint64, val->l >= 0); + + default: + return ins; } - // We were able to compute the result of the ins instruction. We store the - // current value for the top of the stack and, if possible, try to replace the - // instructions that are part of this unary operation with a single LDC. + // We were able to compute the result of the ins instruction. We replace the unop + // with a LDC of the constant. We leave alone the sregs of this instruction, for + // deadce to kill the instructions initializing them. mono_interp_stats.constant_folds++; - if (sp->ins != NULL) { - // The instruction that pushed the top of stack can be replaced with the new constant result - if (result.type == STACK_VALUE_I4) - sp->ins = interp_get_ldc_i4_from_const (td, sp->ins, result.i); - else if (result.type == STACK_VALUE_I8) - sp->ins = interp_inst_replace_with_i8_const (td, sp->ins, result.l); - else - g_assert_not_reached (); - if (td->verbose_level) { - g_print ("Fold unop :\n\t"); - dump_interp_inst (sp->ins); - } - mono_interp_stats.killed_instructions++; - interp_clear_ins (ins); + + if (result.type == LOCAL_VALUE_I4) + ins = interp_get_ldc_i4_from_const (td, ins, result.i, dreg); + else if (result.type == LOCAL_VALUE_I8) + ins = interp_inst_replace_with_i8_const (td, ins, result.l); + else + g_assert_not_reached (); + + if (td->verbose_level) { + g_print ("Fold unop :\n\t"); + dump_interp_inst (ins); } - sp->val = result; - return ins; -cfold_failed: - sp->ins = NULL; - sp->val.type = STACK_VALUE_NONE; + local_ref_count [sreg]--; + local_defs [dreg] = result; + return ins; } -#define INTERP_FOLD_UNOP_BR(_opcode,_stack_type,_cond) \ +#define INTERP_FOLD_UNOP_BR(_opcode,_local_type,_cond) \ case _opcode: \ - g_assert (sp->val.type == _stack_type); \ + g_assert (val->type == _local_type); \ if (_cond) { \ ins->opcode = MINT_BR_S; \ if (cbb->next_bb != ins->info.target_bb) \ interp_unlink_bblocks (cbb, cbb->next_bb); \ + for (InterpInst *it = ins->next; it != NULL; it = it->next) \ + interp_clear_ins (it); \ } else { \ interp_clear_ins (ins); \ interp_unlink_bblocks (cbb, ins->info.target_bb); \ @@ -7288,174 +7738,181 @@ interp_fold_unop (TransformData *td, StackContentInfo *sp, InterpInst *ins) break; static InterpInst* -interp_fold_unop_cond_br (TransformData *td, InterpBasicBlock *cbb, StackContentInfo *sp, InterpInst *ins) +interp_fold_unop_cond_br (TransformData *td, InterpBasicBlock *cbb, LocalValue *local_defs, int *local_ref_count, InterpInst *ins) { - sp--; - // If we can't remove the instruction pushing the constant, don't bother - if (sp->ins == NULL) - return ins; - if (sp->val.type != STACK_VALUE_I4 && sp->val.type != STACK_VALUE_I8) + // ins should be an unop conditional branch, therefore it should have a single sreg + int sreg = ins->sregs [0]; + LocalValue *val = &local_defs [sreg]; + + if (val->type != LOCAL_VALUE_I4 && val->type != LOCAL_VALUE_I8) return ins; + // Top of the stack is a constant switch (ins->opcode) { - INTERP_FOLD_UNOP_BR (MINT_BRFALSE_I4_S, STACK_VALUE_I4, sp [0].val.i == 0); - INTERP_FOLD_UNOP_BR (MINT_BRFALSE_I8_S, STACK_VALUE_I8, sp [0].val.l == 0); - INTERP_FOLD_UNOP_BR (MINT_BRTRUE_I4_S, STACK_VALUE_I4, sp [0].val.i != 0); - INTERP_FOLD_UNOP_BR (MINT_BRTRUE_I8_S, STACK_VALUE_I8, sp [0].val.l != 0); + INTERP_FOLD_UNOP_BR (MINT_BRFALSE_I4_S, LOCAL_VALUE_I4, val->i == 0); + INTERP_FOLD_UNOP_BR (MINT_BRFALSE_I8_S, LOCAL_VALUE_I8, val->l == 0); + INTERP_FOLD_UNOP_BR (MINT_BRTRUE_I4_S, LOCAL_VALUE_I4, val->i != 0); + INTERP_FOLD_UNOP_BR (MINT_BRTRUE_I8_S, LOCAL_VALUE_I8, val->l != 0); default: return ins; } + if (td->verbose_level) { + g_print ("Fold unop cond br :\n\t"); + dump_interp_inst (ins); + } + mono_interp_stats.constant_folds++; - mono_interp_stats.killed_instructions++; - interp_clear_ins (sp->ins); - sp->val.type = STACK_VALUE_NONE; + local_ref_count [sreg]--; return ins; } -#define INTERP_FOLD_BINOP(opcode,stack_type,field,op) \ +#define INTERP_FOLD_BINOP(opcode,local_type,field,op) \ case opcode: \ - g_assert (sp [0].val.type == stack_type && sp [1].val.type == stack_type); \ - result.type = stack_type; \ - result.field = sp [0].val.field op sp [1].val.field; \ + g_assert (val1->type == local_type && val2->type == local_type); \ + result.type = local_type; \ + result.field = val1->field op val2->field; \ break; -#define INTERP_FOLD_BINOP_FULL(opcode,stack_type,field,op,cast_type,cond) \ +#define INTERP_FOLD_BINOP_FULL(opcode,local_type,field,op,cast_type,cond) \ case opcode: \ - g_assert (sp [0].val.type == stack_type && sp [1].val.type == stack_type); \ - if (!(cond)) goto cfold_failed; \ - result.type = stack_type; \ - result.field = (cast_type)sp [0].val.field op (cast_type)sp [1].val.field; \ + g_assert (val1->type == local_type && val2->type == local_type); \ + if (!(cond)) return ins; \ + result.type = local_type; \ + result.field = (cast_type)val1->field op (cast_type)val2->field; \ break; -#define INTERP_FOLD_SHIFTOP(opcode,stack_type,field,shift_op,cast_type) \ +#define INTERP_FOLD_SHIFTOP(opcode,local_type,field,shift_op,cast_type) \ case opcode: \ - g_assert (sp [1].val.type == STACK_VALUE_I4); \ - result.type = stack_type; \ - result.field = (cast_type)sp [0].val.field shift_op sp [1].val.i; \ + g_assert (val2->type == LOCAL_VALUE_I4); \ + result.type = local_type; \ + result.field = (cast_type)val1->field shift_op val2->i; \ break; -#define INTERP_FOLD_RELOP(opcode,stack_type,field,relop,cast_type) \ +#define INTERP_FOLD_RELOP(opcode,local_type,field,relop,cast_type) \ case opcode: \ - g_assert (sp [0].val.type == stack_type && sp [1].val.type == stack_type); \ - result.type = STACK_VALUE_I4; \ - result.i = (cast_type) sp [0].val.field relop (cast_type) sp [1].val.field; \ + g_assert (val1->type == local_type && val2->type == local_type); \ + result.type = LOCAL_VALUE_I4; \ + result.i = (cast_type) val1->field relop (cast_type) val2->field; \ break; static InterpInst* -interp_fold_binop (TransformData *td, StackContentInfo *sp, InterpInst *ins) +interp_fold_binop (TransformData *td, LocalValue *local_defs, int *local_ref_count, InterpInst *ins) { - StackValue result; - // Decrement sp so it's easier to access top of the stack - sp -= 2; - if (sp [0].val.type != STACK_VALUE_I4 && sp [0].val.type != STACK_VALUE_I8) - goto cfold_failed; - if (sp [1].val.type != STACK_VALUE_I4 && sp [1].val.type != STACK_VALUE_I8) - goto cfold_failed; + // ins should be a binop, therefore it should have a single dreg and two sregs + int dreg = ins->dreg; + int sreg1 = ins->sregs [0]; + int sreg2 = ins->sregs [1]; + LocalValue *val1 = &local_defs [sreg1]; + LocalValue *val2 = &local_defs [sreg2]; + LocalValue result; + + if (val1->type != LOCAL_VALUE_I4 && val1->type != LOCAL_VALUE_I8) + return ins; + if (val2->type != LOCAL_VALUE_I4 && val2->type != LOCAL_VALUE_I8) + return ins; // Top two values of the stack are constants switch (ins->opcode) { - INTERP_FOLD_BINOP (MINT_ADD_I4, STACK_VALUE_I4, i, +); - INTERP_FOLD_BINOP (MINT_ADD_I8, STACK_VALUE_I8, l, +); - INTERP_FOLD_BINOP (MINT_SUB_I4, STACK_VALUE_I4, i, -); - INTERP_FOLD_BINOP (MINT_SUB_I8, STACK_VALUE_I8, l, -); - INTERP_FOLD_BINOP (MINT_MUL_I4, STACK_VALUE_I4, i, *); - INTERP_FOLD_BINOP (MINT_MUL_I8, STACK_VALUE_I8, l, *); - - INTERP_FOLD_BINOP (MINT_AND_I4, STACK_VALUE_I4, i, &); - INTERP_FOLD_BINOP (MINT_AND_I8, STACK_VALUE_I8, l, &); - INTERP_FOLD_BINOP (MINT_OR_I4, STACK_VALUE_I4, i, |); - INTERP_FOLD_BINOP (MINT_OR_I8, STACK_VALUE_I8, l, |); - INTERP_FOLD_BINOP (MINT_XOR_I4, STACK_VALUE_I4, i, ^); - INTERP_FOLD_BINOP (MINT_XOR_I8, STACK_VALUE_I8, l, ^); - - INTERP_FOLD_SHIFTOP (MINT_SHL_I4, STACK_VALUE_I4, i, <<, gint32); - INTERP_FOLD_SHIFTOP (MINT_SHL_I8, STACK_VALUE_I8, l, <<, gint64); - INTERP_FOLD_SHIFTOP (MINT_SHR_I4, STACK_VALUE_I4, i, >>, gint32); - INTERP_FOLD_SHIFTOP (MINT_SHR_I8, STACK_VALUE_I8, l, >>, gint64); - INTERP_FOLD_SHIFTOP (MINT_SHR_UN_I4, STACK_VALUE_I4, i, >>, guint32); - INTERP_FOLD_SHIFTOP (MINT_SHR_UN_I8, STACK_VALUE_I8, l, >>, guint64); - - INTERP_FOLD_RELOP (MINT_CEQ_I4, STACK_VALUE_I4, i, ==, gint32); - INTERP_FOLD_RELOP (MINT_CEQ_I8, STACK_VALUE_I8, l, ==, gint64); - INTERP_FOLD_RELOP (MINT_CNE_I4, STACK_VALUE_I4, i, !=, gint32); - INTERP_FOLD_RELOP (MINT_CNE_I8, STACK_VALUE_I8, l, !=, gint64); - - INTERP_FOLD_RELOP (MINT_CGT_I4, STACK_VALUE_I4, i, >, gint32); - INTERP_FOLD_RELOP (MINT_CGT_I8, STACK_VALUE_I8, l, >, gint64); - INTERP_FOLD_RELOP (MINT_CGT_UN_I4, STACK_VALUE_I4, i, >, guint32); - INTERP_FOLD_RELOP (MINT_CGT_UN_I8, STACK_VALUE_I8, l, >, guint64); - - INTERP_FOLD_RELOP (MINT_CGE_I4, STACK_VALUE_I4, i, >=, gint32); - INTERP_FOLD_RELOP (MINT_CGE_I8, STACK_VALUE_I8, l, >=, gint64); - INTERP_FOLD_RELOP (MINT_CGE_UN_I4, STACK_VALUE_I4, i, >=, guint32); - INTERP_FOLD_RELOP (MINT_CGE_UN_I8, STACK_VALUE_I8, l, >=, guint64); - - INTERP_FOLD_RELOP (MINT_CLT_I4, STACK_VALUE_I4, i, <, gint32); - INTERP_FOLD_RELOP (MINT_CLT_I8, STACK_VALUE_I8, l, <, gint64); - INTERP_FOLD_RELOP (MINT_CLT_UN_I4, STACK_VALUE_I4, i, <, guint32); - INTERP_FOLD_RELOP (MINT_CLT_UN_I8, STACK_VALUE_I8, l, <, guint64); - - INTERP_FOLD_RELOP (MINT_CLE_I4, STACK_VALUE_I4, i, <=, gint32); - INTERP_FOLD_RELOP (MINT_CLE_I8, STACK_VALUE_I8, l, <=, gint64); - INTERP_FOLD_RELOP (MINT_CLE_UN_I4, STACK_VALUE_I4, i, <=, guint32); - INTERP_FOLD_RELOP (MINT_CLE_UN_I8, STACK_VALUE_I8, l, <=, guint64); - - INTERP_FOLD_BINOP_FULL (MINT_DIV_I4, STACK_VALUE_I4, i, /, gint32, sp [1].val.i != 0 && (sp [0].val.i != G_MININT32 || sp [1].val.i != -1)); - INTERP_FOLD_BINOP_FULL (MINT_DIV_I8, STACK_VALUE_I8, l, /, gint64, sp [1].val.l != 0 && (sp [0].val.l != G_MININT64 || sp [1].val.l != -1)); - INTERP_FOLD_BINOP_FULL (MINT_DIV_UN_I4, STACK_VALUE_I4, i, /, guint32, sp [1].val.i != 0); - INTERP_FOLD_BINOP_FULL (MINT_DIV_UN_I8, STACK_VALUE_I8, l, /, guint64, sp [1].val.l != 0); - - INTERP_FOLD_BINOP_FULL (MINT_REM_I4, STACK_VALUE_I4, i, %, gint32, sp [1].val.i != 0 && (sp [0].val.i != G_MININT32 || sp [1].val.i != -1)); - INTERP_FOLD_BINOP_FULL (MINT_REM_I8, STACK_VALUE_I8, l, %, gint64, sp [1].val.l != 0 && (sp [0].val.l != G_MININT64 || sp [1].val.l != -1)); - INTERP_FOLD_BINOP_FULL (MINT_REM_UN_I4, STACK_VALUE_I4, i, %, guint32, sp [1].val.i != 0); - INTERP_FOLD_BINOP_FULL (MINT_REM_UN_I8, STACK_VALUE_I8, l, %, guint64, sp [1].val.l != 0); + INTERP_FOLD_BINOP (MINT_ADD_I4, LOCAL_VALUE_I4, i, +); + INTERP_FOLD_BINOP (MINT_ADD_I8, LOCAL_VALUE_I8, l, +); + INTERP_FOLD_BINOP (MINT_SUB_I4, LOCAL_VALUE_I4, i, -); + INTERP_FOLD_BINOP (MINT_SUB_I8, LOCAL_VALUE_I8, l, -); + INTERP_FOLD_BINOP (MINT_MUL_I4, LOCAL_VALUE_I4, i, *); + INTERP_FOLD_BINOP (MINT_MUL_I8, LOCAL_VALUE_I8, l, *); + + INTERP_FOLD_BINOP (MINT_AND_I4, LOCAL_VALUE_I4, i, &); + INTERP_FOLD_BINOP (MINT_AND_I8, LOCAL_VALUE_I8, l, &); + INTERP_FOLD_BINOP (MINT_OR_I4, LOCAL_VALUE_I4, i, |); + INTERP_FOLD_BINOP (MINT_OR_I8, LOCAL_VALUE_I8, l, |); + INTERP_FOLD_BINOP (MINT_XOR_I4, LOCAL_VALUE_I4, i, ^); + INTERP_FOLD_BINOP (MINT_XOR_I8, LOCAL_VALUE_I8, l, ^); + + INTERP_FOLD_SHIFTOP (MINT_SHL_I4, LOCAL_VALUE_I4, i, <<, gint32); + INTERP_FOLD_SHIFTOP (MINT_SHL_I8, LOCAL_VALUE_I8, l, <<, gint64); + INTERP_FOLD_SHIFTOP (MINT_SHR_I4, LOCAL_VALUE_I4, i, >>, gint32); + INTERP_FOLD_SHIFTOP (MINT_SHR_I8, LOCAL_VALUE_I8, l, >>, gint64); + INTERP_FOLD_SHIFTOP (MINT_SHR_UN_I4, LOCAL_VALUE_I4, i, >>, guint32); + INTERP_FOLD_SHIFTOP (MINT_SHR_UN_I8, LOCAL_VALUE_I8, l, >>, guint64); + + INTERP_FOLD_RELOP (MINT_CEQ_I4, LOCAL_VALUE_I4, i, ==, gint32); + INTERP_FOLD_RELOP (MINT_CEQ_I8, LOCAL_VALUE_I8, l, ==, gint64); + INTERP_FOLD_RELOP (MINT_CNE_I4, LOCAL_VALUE_I4, i, !=, gint32); + INTERP_FOLD_RELOP (MINT_CNE_I8, LOCAL_VALUE_I8, l, !=, gint64); + + INTERP_FOLD_RELOP (MINT_CGT_I4, LOCAL_VALUE_I4, i, >, gint32); + INTERP_FOLD_RELOP (MINT_CGT_I8, LOCAL_VALUE_I8, l, >, gint64); + INTERP_FOLD_RELOP (MINT_CGT_UN_I4, LOCAL_VALUE_I4, i, >, guint32); + INTERP_FOLD_RELOP (MINT_CGT_UN_I8, LOCAL_VALUE_I8, l, >, guint64); + + INTERP_FOLD_RELOP (MINT_CGE_I4, LOCAL_VALUE_I4, i, >=, gint32); + INTERP_FOLD_RELOP (MINT_CGE_I8, LOCAL_VALUE_I8, l, >=, gint64); + INTERP_FOLD_RELOP (MINT_CGE_UN_I4, LOCAL_VALUE_I4, i, >=, guint32); + INTERP_FOLD_RELOP (MINT_CGE_UN_I8, LOCAL_VALUE_I8, l, >=, guint64); + + INTERP_FOLD_RELOP (MINT_CLT_I4, LOCAL_VALUE_I4, i, <, gint32); + INTERP_FOLD_RELOP (MINT_CLT_I8, LOCAL_VALUE_I8, l, <, gint64); + INTERP_FOLD_RELOP (MINT_CLT_UN_I4, LOCAL_VALUE_I4, i, <, guint32); + INTERP_FOLD_RELOP (MINT_CLT_UN_I8, LOCAL_VALUE_I8, l, <, guint64); + + INTERP_FOLD_RELOP (MINT_CLE_I4, LOCAL_VALUE_I4, i, <=, gint32); + INTERP_FOLD_RELOP (MINT_CLE_I8, LOCAL_VALUE_I8, l, <=, gint64); + INTERP_FOLD_RELOP (MINT_CLE_UN_I4, LOCAL_VALUE_I4, i, <=, guint32); + INTERP_FOLD_RELOP (MINT_CLE_UN_I8, LOCAL_VALUE_I8, l, <=, guint64); + + INTERP_FOLD_BINOP_FULL (MINT_DIV_I4, LOCAL_VALUE_I4, i, /, gint32, val2->i != 0 && (val1->i != G_MININT32 || val2->i != -1)); + INTERP_FOLD_BINOP_FULL (MINT_DIV_I8, LOCAL_VALUE_I8, l, /, gint64, val2->l != 0 && (val1->l != G_MININT64 || val2->l != -1)); + INTERP_FOLD_BINOP_FULL (MINT_DIV_UN_I4, LOCAL_VALUE_I4, i, /, guint32, val2->i != 0); + INTERP_FOLD_BINOP_FULL (MINT_DIV_UN_I8, LOCAL_VALUE_I8, l, /, guint64, val2->l != 0); + + INTERP_FOLD_BINOP_FULL (MINT_REM_I4, LOCAL_VALUE_I4, i, %, gint32, val2->i != 0 && (val1->i != G_MININT32 || val2->i != -1)); + INTERP_FOLD_BINOP_FULL (MINT_REM_I8, LOCAL_VALUE_I8, l, %, gint64, val2->l != 0 && (val1->l != G_MININT64 || val2->l != -1)); + INTERP_FOLD_BINOP_FULL (MINT_REM_UN_I4, LOCAL_VALUE_I4, i, %, guint32, val2->i != 0); + INTERP_FOLD_BINOP_FULL (MINT_REM_UN_I8, LOCAL_VALUE_I8, l, %, guint64, val2->l != 0); default: - goto cfold_failed; + return ins; } - // We were able to compute the result of the ins instruction. We store the - // current value for the top of the stack and, if possible, try to replace the - // instructions that are part of this unary operation with a single LDC. + // We were able to compute the result of the ins instruction. We replace the binop + // with a LDC of the constant. We leave alone the sregs of this instruction, for + // deadce to kill the instructions initializing them. mono_interp_stats.constant_folds++; - if (sp [0].ins != NULL && sp [1].ins != NULL) { - interp_clear_ins (sp [0].ins); - interp_clear_ins (sp [1].ins); - mono_interp_stats.killed_instructions += 2; - if (result.type == STACK_VALUE_I4) - ins = interp_get_ldc_i4_from_const (td, ins, result.i); - else if (result.type == STACK_VALUE_I8) - ins = interp_inst_replace_with_i8_const (td, ins, result.l); - else - g_assert_not_reached (); - if (td->verbose_level) { - g_print ("Fold binop :\n\t"); - dump_interp_inst (ins); - } - sp [0].ins = ins; - } else { - sp [0].ins = NULL; + + if (result.type == LOCAL_VALUE_I4) + ins = interp_get_ldc_i4_from_const (td, ins, result.i, dreg); + else if (result.type == LOCAL_VALUE_I8) + ins = interp_inst_replace_with_i8_const (td, ins, result.l); + else + g_assert_not_reached (); + + if (td->verbose_level) { + g_print ("Fold binop :\n\t"); + dump_interp_inst (ins); } - sp [0].val = result; - return ins; -cfold_failed: - sp->ins = NULL; - sp->val.type = STACK_VALUE_NONE; + local_ref_count [sreg1]--; + local_ref_count [sreg2]--; + local_defs [dreg] = result; return ins; } -#define INTERP_FOLD_BINOP_BR(_opcode,_stack_type,_cond) \ +// Due to poor current design, the branch op might not be the last instruction in the bblock +// (in case we fallthrough and need to have the stack locals match the ones from next_bb, done +// in fixup_newbb_stack_locals). If that's the case, clear all these mov's. This helps bblock +// merging quickly find the MINT_BR_S opcode. +#define INTERP_FOLD_BINOP_BR(_opcode,_local_type,_cond) \ case _opcode: \ - g_assert (sp [0].val.type == _stack_type); \ - g_assert (sp [1].val.type == _stack_type); \ + g_assert (val1->type == _local_type); \ + g_assert (val2->type == _local_type); \ if (_cond) { \ ins->opcode = MINT_BR_S; \ if (cbb->next_bb != ins->info.target_bb) \ interp_unlink_bblocks (cbb, cbb->next_bb); \ + for (InterpInst *it = ins->next; it != NULL; it = it->next) \ + interp_clear_ins (it); \ } else { \ interp_clear_ins (ins); \ interp_unlink_bblocks (cbb, ins->info.target_bb); \ @@ -7463,87 +7920,66 @@ interp_fold_binop (TransformData *td, StackContentInfo *sp, InterpInst *ins) break; static InterpInst* -interp_fold_binop_cond_br (TransformData *td, InterpBasicBlock *cbb, StackContentInfo *sp, InterpInst *ins) +interp_fold_binop_cond_br (TransformData *td, InterpBasicBlock *cbb, LocalValue *local_defs, int *local_ref_count, InterpInst *ins) { - sp -= 2; - // If we can't remove the instructions pushing the constants, don't bother - if (sp [0].ins == NULL || sp [1].ins == NULL) - return ins; - if (sp [0].val.type != STACK_VALUE_I4 && sp [0].val.type != STACK_VALUE_I8) + // ins should be a conditional binop, therefore it should have only two sregs + int sreg1 = ins->sregs [0]; + int sreg2 = ins->sregs [1]; + LocalValue *val1 = &local_defs [sreg1]; + LocalValue *val2 = &local_defs [sreg2]; + + if (val1->type != LOCAL_VALUE_I4 && val1->type != LOCAL_VALUE_I8) return ins; - if (sp [1].val.type != STACK_VALUE_I4 && sp [1].val.type != STACK_VALUE_I8) + if (val2->type != LOCAL_VALUE_I4 && val2->type != LOCAL_VALUE_I8) return ins; switch (ins->opcode) { - INTERP_FOLD_BINOP_BR (MINT_BEQ_I4_S, STACK_VALUE_I4, sp [0].val.i == sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BEQ_I8_S, STACK_VALUE_I8, sp [0].val.l == sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BGE_I4_S, STACK_VALUE_I4, sp [0].val.i >= sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BGE_I8_S, STACK_VALUE_I8, sp [0].val.l >= sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BGT_I4_S, STACK_VALUE_I4, sp [0].val.i > sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BGT_I8_S, STACK_VALUE_I8, sp [0].val.l > sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BLT_I4_S, STACK_VALUE_I4, sp [0].val.i < sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BLT_I8_S, STACK_VALUE_I8, sp [0].val.l < sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BLE_I4_S, STACK_VALUE_I4, sp [0].val.i <= sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BLE_I8_S, STACK_VALUE_I8, sp [0].val.l <= sp [1].val.l); - - INTERP_FOLD_BINOP_BR (MINT_BNE_UN_I4_S, STACK_VALUE_I4, sp [0].val.i != sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BNE_UN_I8_S, STACK_VALUE_I8, sp [0].val.l != sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BGE_UN_I4_S, STACK_VALUE_I4, (guint32)sp [0].val.i >= (guint32)sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BGE_UN_I8_S, STACK_VALUE_I8, (guint64)sp [0].val.l >= (guint64)sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BGT_UN_I4_S, STACK_VALUE_I4, (guint32)sp [0].val.i > (guint32)sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BGT_UN_I8_S, STACK_VALUE_I8, (guint64)sp [0].val.l > (guint64)sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BLE_UN_I4_S, STACK_VALUE_I4, (guint32)sp [0].val.i <= (guint32)sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BLE_UN_I8_S, STACK_VALUE_I8, (guint64)sp [0].val.l <= (guint64)sp [1].val.l); - INTERP_FOLD_BINOP_BR (MINT_BLT_UN_I4_S, STACK_VALUE_I4, (guint32)sp [0].val.i < (guint32)sp [1].val.i); - INTERP_FOLD_BINOP_BR (MINT_BLT_UN_I8_S, STACK_VALUE_I8, (guint64)sp [0].val.l < (guint64)sp [1].val.l); + INTERP_FOLD_BINOP_BR (MINT_BEQ_I4_S, LOCAL_VALUE_I4, val1->i == val2->i); + INTERP_FOLD_BINOP_BR (MINT_BEQ_I8_S, LOCAL_VALUE_I8, val1->l == val2->l); + INTERP_FOLD_BINOP_BR (MINT_BGE_I4_S, LOCAL_VALUE_I4, val1->i >= val2->i); + INTERP_FOLD_BINOP_BR (MINT_BGE_I8_S, LOCAL_VALUE_I8, val1->l >= val2->l); + INTERP_FOLD_BINOP_BR (MINT_BGT_I4_S, LOCAL_VALUE_I4, val1->i > val2->i); + INTERP_FOLD_BINOP_BR (MINT_BGT_I8_S, LOCAL_VALUE_I8, val1->l > val2->l); + INTERP_FOLD_BINOP_BR (MINT_BLT_I4_S, LOCAL_VALUE_I4, val1->i < val2->i); + INTERP_FOLD_BINOP_BR (MINT_BLT_I8_S, LOCAL_VALUE_I8, val1->l < val2->l); + INTERP_FOLD_BINOP_BR (MINT_BLE_I4_S, LOCAL_VALUE_I4, val1->i <= val2->i); + INTERP_FOLD_BINOP_BR (MINT_BLE_I8_S, LOCAL_VALUE_I8, val1->l <= val2->l); + + INTERP_FOLD_BINOP_BR (MINT_BNE_UN_I4_S, LOCAL_VALUE_I4, val1->i != val2->i); + INTERP_FOLD_BINOP_BR (MINT_BNE_UN_I8_S, LOCAL_VALUE_I8, val1->l != val2->l); + INTERP_FOLD_BINOP_BR (MINT_BGE_UN_I4_S, LOCAL_VALUE_I4, (guint32)val1->i >= (guint32)val2->i); + INTERP_FOLD_BINOP_BR (MINT_BGE_UN_I8_S, LOCAL_VALUE_I8, (guint64)val1->l >= (guint64)val2->l); + INTERP_FOLD_BINOP_BR (MINT_BGT_UN_I4_S, LOCAL_VALUE_I4, (guint32)val1->i > (guint32)val2->i); + INTERP_FOLD_BINOP_BR (MINT_BGT_UN_I8_S, LOCAL_VALUE_I8, (guint64)val1->l > (guint64)val2->l); + INTERP_FOLD_BINOP_BR (MINT_BLE_UN_I4_S, LOCAL_VALUE_I4, (guint32)val1->i <= (guint32)val2->i); + INTERP_FOLD_BINOP_BR (MINT_BLE_UN_I8_S, LOCAL_VALUE_I8, (guint64)val1->l <= (guint64)val2->l); + INTERP_FOLD_BINOP_BR (MINT_BLT_UN_I4_S, LOCAL_VALUE_I4, (guint32)val1->i < (guint32)val2->i); + INTERP_FOLD_BINOP_BR (MINT_BLT_UN_I8_S, LOCAL_VALUE_I8, (guint64)val1->l < (guint64)val2->l); default: return ins; } + if (td->verbose_level) { + g_print ("Fold binop cond br :\n\t"); + dump_interp_inst (ins); + } + mono_interp_stats.constant_folds++; - mono_interp_stats.killed_instructions += 2; - interp_clear_ins (sp [0].ins); - interp_clear_ins (sp [1].ins); - sp [0].val.type = STACK_VALUE_NONE; - sp [1].val.type = STACK_VALUE_NONE; + local_ref_count [sreg1]--; + local_ref_count [sreg2]--; return ins; } -static gboolean -interp_local_equal (StackValue *locals, int local1, int local2) -{ - if (local1 == local2) - return TRUE; - if (locals [local1].type == STACK_VALUE_LOCAL && locals [local1].local == local2) { - // local1 is a copy of local2 - return TRUE; - } - if (locals [local2].type == STACK_VALUE_LOCAL && locals [local2].local == local1) { - // local2 is a copy of local1 - return TRUE; - } - if (locals [local1].type == STACK_VALUE_I4 && locals [local2].type == STACK_VALUE_I4) - return locals [local1].i == locals [local2].i; - if (locals [local1].type == STACK_VALUE_I8 && locals [local2].type == STACK_VALUE_I8) - return locals [local1].l == locals [local2].l; - return FALSE; -} - static void interp_cprop (TransformData *td) { - if (!td->max_stack_height) - return; - StackContentInfo *stack = (StackContentInfo*) g_malloc (td->max_stack_height * sizeof (StackContentInfo)); - StackContentInfo *stack_end = stack + td->max_stack_height; - StackContentInfo *sp; - StackValue *locals = (StackValue*) g_malloc (td->locals_size * sizeof (StackValue)); + LocalValue *local_defs = (LocalValue*) g_malloc (td->locals_size * sizeof (LocalValue)); int *local_ref_count = (int*) g_malloc (td->locals_size * sizeof (int)); InterpBasicBlock *bb; gboolean needs_retry; + int ins_index; retry: - sp = stack; memset (local_ref_count, 0, td->locals_size * sizeof (int)); if (td->verbose_level) @@ -7551,347 +7987,207 @@ interp_cprop (TransformData *td) for (bb = td->entry_bb; bb != NULL; bb = bb->next_bb) { InterpInst *ins; - // Optimizations take place only inside a single basic block - if (bb->stack_height >= 0) { - sp = stack + bb->stack_height; - g_assert (sp <= stack_end); - memset (stack, 0, (sp - stack) * sizeof (StackContentInfo)); - } - memset (locals, 0, td->locals_size * sizeof (StackValue)); + ins_index = 0; + + // Set cbb since we do some instruction inserting below + td->cbb = bb; + + // FIXME This is excessive. Remove this once we have SSA + memset (local_defs, 0, td->locals_size * sizeof (LocalValue)); if (td->verbose_level) g_print ("BB%d\n", bb->index); for (ins = bb->first_ins; ins != NULL; ins = ins->next) { - int pop, push; - // The instruction pops some values then pushes some other - get_inst_stack_usage (td, ins, &pop, &push); - if (td->verbose_level && ins->opcode != MINT_NOP) { - dump_interp_inst_no_newline (ins); - g_print (", sp %d, (pop %d, push %d)\n", sp - stack, pop, push); - } - if (MINT_IS_LDLOC (ins->opcode)) { - int replace_op = 0; - int loaded_local = ins->data [0]; - local_ref_count [loaded_local]++; - InterpInst *prev_ins = interp_prev_ins (ins); - if (prev_ins && MINT_IS_STLOC (prev_ins->opcode) && interp_local_equal (locals, prev_ins->data [0], loaded_local)) { - int mt = prev_ins->opcode - MINT_STLOC_I1; - if (ins->opcode - MINT_LDLOC_I1 == mt) { - if (mt == MINT_TYPE_I4) - replace_op = MINT_STLOC_NP_I4; - else if (mt == MINT_TYPE_I8) - replace_op = MINT_STLOC_NP_I8; - else if (mt == MINT_TYPE_R4) - replace_op = MINT_STLOC_NP_R4; - else if (mt == MINT_TYPE_R8) - replace_op = MINT_STLOC_NP_R8; - else if (mt == MINT_TYPE_O) - replace_op = MINT_STLOC_NP_O; - if (replace_op) { - int stored_local = prev_ins->data [0]; - sp->ins = NULL; - if (sp->val.type == STACK_VALUE_NONE && !td->locals [stored_local].indirects) { - // We know what local is on the stack now. Track it - sp->val.type = STACK_VALUE_LOCAL; - sp->val.local = stored_local; - } + int opcode = ins->opcode; - // Clear the previous stloc instruction - interp_clear_ins (prev_ins); - ins->opcode = replace_op; - ins->data [0] = stored_local; - local_ref_count [loaded_local]--; - if (td->verbose_level) { - g_print ("Add stloc.np :\n\t"); - dump_interp_inst (ins); - } - mono_interp_stats.stloc_nps++; - mono_interp_stats.killed_instructions++; - } + if (opcode == MINT_NOP) + continue; + + int num_sregs = mono_interp_op_sregs [opcode]; + int num_dregs = mono_interp_op_dregs [opcode]; + gint32 *sregs = &ins->sregs [0]; + gint32 dreg = ins->dreg; + + if (td->verbose_level && ins->opcode != MINT_NOP) + dump_interp_inst (ins); + + for (int i = 0; i < num_sregs; i++) { + // FIXME MINT_PROF_EXIT when void + if (sregs [i] == -1) + continue; + local_ref_count [sregs [i]]++; + if (local_defs [sregs [i]].type == LOCAL_VALUE_LOCAL) { + int cprop_local = local_defs [sregs [i]].local; + // We are not allowed to extend the liveness of execution stack locals because + // it can end up conflicting with another such local. Once we will have our + // own offset allocator for these locals, this restriction can be lifted. + if (td->locals [cprop_local].flags & INTERP_LOCAL_FLAG_EXECUTION_STACK) + continue; + + // We are trying to replace sregs [i] with its def local (cprop_local), but cprop_local has since been + // modified, so we can't use it. + if (local_defs [cprop_local].ins != NULL && local_defs [cprop_local].def_index > local_defs [sregs [i]].def_index) + continue; + + if (td->verbose_level) + g_print ("cprop %d -> %d:\n\t", sregs [i], cprop_local); + local_ref_count [sregs [i]]--; + sregs [i] = cprop_local; + local_ref_count [cprop_local]++; + if (td->verbose_level) + dump_interp_inst (ins); } } - /* If we didn't replace this ldloc with a stloc.np, try other optimizations */ - if (!replace_op) { - if (locals [loaded_local].type == STACK_VALUE_LOCAL) { - g_assert (!td->locals [loaded_local].indirects); - // do copy propagation of the original source - mono_interp_stats.copy_propagations++; - local_ref_count [loaded_local]--; - // We can't propagate a local that has its address taken - g_assert (!td->locals [locals [loaded_local].local].indirects); - ins->data [0] = locals [loaded_local].local; - local_ref_count [ins->data [0]]++; - if (td->verbose_level) { - g_print ("cprop loc %d -> loc %d :\n\t", loaded_local, locals [loaded_local].local); - dump_interp_inst (ins); + + if (num_dregs) { + local_defs [dreg].type = LOCAL_VALUE_NONE; + local_defs [dreg].ins = ins; + local_defs [dreg].def_index = ins_index; + } + + if (opcode == MINT_MOV_4 || opcode == MINT_MOV_8 || opcode == MINT_MOV_VT) { + int sreg = sregs [0]; + if (dreg == sreg) { + if (td->verbose_level) + g_print ("clear redundant mov\n"); + interp_clear_ins (ins); + local_ref_count [sreg]--; + } else if (td->locals [sreg].indirects || td->locals [dreg].indirects) { + // Don't bother with indirect locals + } else if (local_defs [sreg].type == LOCAL_VALUE_I4 || local_defs [sreg].type == LOCAL_VALUE_I8) { + // Replace mov with ldc + gboolean is_i4 = local_defs [sreg].type == LOCAL_VALUE_I4; + g_assert (!td->locals [sreg].indirects); + local_defs [dreg].type = local_defs [sreg].type; + if (is_i4) { + int ct = local_defs [sreg].i; + ins = interp_get_ldc_i4_from_const (td, ins, ct, dreg); + local_defs [dreg].i = ct; + } else { + gint64 ct = local_defs [sreg].l; + ins = interp_inst_replace_with_i8_const (td, ins, ct); + local_defs [dreg].l = ct; } - } else if (locals [loaded_local].type == STACK_VALUE_I4 || locals [loaded_local].type == STACK_VALUE_I8) { - gboolean is_i4 = locals [loaded_local].type == STACK_VALUE_I4; - g_assert (!td->locals [loaded_local].indirects); - if (is_i4) - ins = interp_get_ldc_i4_from_const (td, ins, locals [loaded_local].i); - else - ins = interp_inst_replace_with_i8_const (td, ins, locals [loaded_local].l); - sp->ins = ins; - sp->val = locals [loaded_local]; - local_ref_count [loaded_local]--; + local_defs [dreg].ins = ins; + local_ref_count [sreg]--; mono_interp_stats.copy_propagations++; if (td->verbose_level) { - g_print ("cprop loc %d -> ct :\n\t", loaded_local); + g_print ("cprop loc %d -> ct :\n\t", sreg); dump_interp_inst (ins); } - // FIXME this replace_op got ugly - replace_op = ins->opcode; - } - } - if (!replace_op) { - // Save the ldloc on the stack if it wasn't optimized away - // For simplicity we don't track locals that have their address taken - // since it is hard to detect instructions that change the local value. - if (td->locals [loaded_local].indirects) { - sp->val.type = STACK_VALUE_NONE; - } else { - sp->val.type = STACK_VALUE_LOCAL; - sp->val.local = ins->data [0]; - } - sp->ins = ins; - } - sp++; - } else if (MINT_IS_STLOC (ins->opcode)) { - int dest_local = ins->data [0]; - sp--; - if (sp->val.type == STACK_VALUE_LOCAL) { - int src_local = sp->val.local; - if (td->locals [src_local].mt == td->locals [dest_local].mt) { - // The locals have the same type. We can propagate the value - int vtsize = (ins->opcode == MINT_STLOC_VT) ? ins->data [1] : 0; - - if (!td->locals [dest_local].indirects) { - // Track what exactly is stored into local - locals [dest_local].type = STACK_VALUE_LOCAL; - locals [dest_local].local = src_local; - } + } else if (local_defs [sreg].ins != NULL && + (td->locals [sreg].flags & INTERP_LOCAL_FLAG_EXECUTION_STACK) && + !(td->locals [sreg].flags & INTERP_LOCAL_FLAG_CALL_ARGS) && + !(td->locals [dreg].flags & INTERP_LOCAL_FLAG_EXECUTION_STACK) && + interp_prev_ins (ins) == local_defs [sreg].ins) { + // hackish temporary optimization that won't be necessary in the future + // We replace `local1 <- ?, local2 <- local1` with `local2 <- ?, local1 <- local2` + // if local1 is execution stack local and local2 is normal global local. This makes + // it more likely for `local1 <- local2` to be killed, while before we always needed + // to store to the global local, which is likely accessed by other instructions. + InterpInst *def = local_defs [sreg].ins; + int original_dreg = def->dreg; + + def->dreg = dreg; + ins->dreg = original_dreg; + sregs [0] = dreg; + + local_defs [dreg].type = LOCAL_VALUE_NONE; + local_defs [dreg].ins = def; + local_defs [original_dreg].type = LOCAL_VALUE_LOCAL; + local_defs [original_dreg].ins = ins; + local_defs [original_dreg].local = dreg; + + local_ref_count [original_dreg]--; + local_ref_count [dreg]++; - if (sp->ins) { - // If the top of stack is not pushed by a ldloc, we are introducing a - // new dependency on the src_local since we are adding a movloc from it. - if (!MINT_IS_LDLOC (sp->ins->opcode)) - local_ref_count [src_local]++; - interp_clear_ins (sp->ins); - interp_clear_ins (ins); - - ins = interp_insert_ins_bb (td, bb, ins, get_movloc_for_type (td->locals [src_local].mt)); - ins->data [0] = src_local; - ins->data [1] = dest_local; - if (vtsize) - ins->data [2] = vtsize; - // Clear ldloc / stloc pair and replace it with movloc superinstruction - if (td->verbose_level) { - g_print ("Add movloc (ldloc off %d) :\n\t", sp->ins->il_offset); - dump_interp_inst (ins); - } - mono_interp_stats.movlocs++; - mono_interp_stats.killed_instructions++; + if (td->verbose_level) { + g_print ("cprop dreg:\n\t"); + dump_interp_inst (def); + g_print ("\t"); + dump_interp_inst (ins); } } else { - locals [dest_local].type = STACK_VALUE_NONE; + if (td->verbose_level) + g_print ("local copy %d <- %d\n", dreg, sreg); + local_defs [dreg].type = LOCAL_VALUE_LOCAL; + local_defs [dreg].local = sreg; } - } else if (sp->val.type == STACK_VALUE_NONE) { - locals [dest_local].type = STACK_VALUE_NONE; - } else { - g_assert (sp->val.type == STACK_VALUE_I4 || sp->val.type == STACK_VALUE_I8); - if (!td->locals [dest_local].indirects) - locals [dest_local] = sp->val; - } - clear_stack_content_info_for_local (stack, sp, dest_local); - clear_local_content_info_for_local (locals, locals + td->locals_size, dest_local); - } else if (MINT_IS_LDC_I4 (ins->opcode) || ins->opcode == MINT_LDC_I8) { - StackValue val; - gboolean is_i8 = ins->opcode == MINT_LDC_I8; - InterpInst *prev_ins = interp_prev_ins (ins); - - if (is_i8) { - val.type = STACK_VALUE_I8; - val.l = READ64 (&ins->data [0]); - } else { - val.type = STACK_VALUE_I4; - val.i = interp_get_const_from_ldc_i4 (ins); - } - - if (prev_ins && prev_ins->opcode == MINT_POP && - ((is_i8 && sp->val.type == STACK_VALUE_I8 && sp->val.l == val.l) || - (!is_i8 && sp->val.type == STACK_VALUE_I4 && sp->val.i == val.i))) { - // The previous instruction pops the stack of the value we are pushing - // right now. We can kill both instructions - if (td->verbose_level) - g_print ("Kill redundant pop/ldc pair: pop (off %p), ldc (off %p)\n", prev_ins->il_offset, ins->il_offset); - interp_clear_ins (prev_ins); - interp_clear_ins (ins); - mono_interp_stats.killed_instructions += 2; - } else { - sp->ins = ins; - sp->val = val; - } - sp++; - } else if (ins->opcode == MINT_MONO_LDPTR) { - StackValue val; + } else if (opcode == MINT_LDLOCA_S) { + // The local that we are taking the address of is not a sreg but still referenced + local_ref_count [ins->sregs [0]]++; + } else if (MINT_IS_LDC_I4 (opcode)) { + local_defs [dreg].type = LOCAL_VALUE_I4; + local_defs [dreg].i = interp_get_const_from_ldc_i4 (ins); + } else if (opcode == MINT_LDC_I8) { + local_defs [dreg].type = LOCAL_VALUE_I8; + local_defs [dreg].l = READ64 (&ins->data [0]); + } else if (ins->opcode == MINT_MONO_LDPTR) { #if SIZEOF_VOID_P == 8 - val.type = STACK_VALUE_I8; - val.l = (gint64)td->data_items [ins->data [0]]; + local_defs [dreg].type = LOCAL_VALUE_I8; + local_defs [dreg].l = (gint64)td->data_items [ins->data [0]]; #else - val.type = STACK_VALUE_I4; - val.i = (gint32)td->data_items [ins->data [0]]; + local_defs [dreg].type = LOCAL_VALUE_I4; + local_defs [dreg].i = (gint32)td->data_items [ins->data [0]]; #endif - sp->ins = ins; - sp->val = val; - sp++; - } else if (MINT_IS_MOVLOC (ins->opcode)) { - int src_local = ins->data [0]; - int dest_local = ins->data [1]; - local_ref_count [src_local]++; - if (!td->locals [dest_local].indirects) { - if (locals [src_local].type != STACK_VALUE_NONE) { - locals [dest_local] = locals [src_local]; - } else { - locals [dest_local].type = STACK_VALUE_LOCAL; - locals [dest_local].local = src_local; + } else if (MINT_IS_UNOP (opcode) || (opcode >= MINT_MOV_I1 && opcode <= MINT_MOV_U2)) { + ins = interp_fold_unop (td, local_defs, local_ref_count, ins); + } else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (opcode)) { + ins = interp_fold_unop_cond_br (td, bb, local_defs, local_ref_count, ins); + } else if (MINT_IS_BINOP (opcode)) { + ins = interp_fold_binop (td, local_defs, local_ref_count, ins); + } else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (opcode)) { + ins = interp_fold_binop_cond_br (td, bb, local_defs, local_ref_count, ins); + } else if ((ins->opcode == MINT_NEWOBJ_FAST || ins->opcode == MINT_NEWOBJ_VT_FAST) && ins->data [0] == INLINED_METHOD_FLAG) { + // FIXME Drop the CALL_ARGS flag on the params so this will no longer be necessary + int param_count = ins->data [3]; + int *newobj_reg_map = ins->info.newobj_reg_map; + for (int i = 0; i < param_count; i++) { + int src = newobj_reg_map [2 * i]; + int dst = newobj_reg_map [2 * i + 1]; + local_defs [dst] = local_defs [src]; + local_defs [dst].ins = NULL; } - clear_stack_content_info_for_local (stack, sp, dest_local); - clear_local_content_info_for_local (locals, locals + td->locals_size, dest_local); - } - } else if (MINT_IS_STLOC_NP (ins->opcode)) { - int dest_local = ins->data [0]; - // Prevent optimizing away the instruction that pushed the value on the stack - sp [-1].ins = NULL; - // The local contains the value of the top of stack - if (!td->locals [dest_local].indirects) { - locals [dest_local] = sp [-1].val; - clear_stack_content_info_for_local (stack, sp, dest_local); - clear_local_content_info_for_local (locals, locals + td->locals_size, dest_local); - } - } else if (ins->opcode == MINT_DUP || ins->opcode == MINT_DUP_VT) { - sp [0].val = sp [-1].val; - sp [0].ins = ins; - // If top of stack is known, we could also replace dup with an explicit - // propagated instruction, so we remove the top of stack dependency - sp [-1].ins = NULL; - sp++; - } else if (ins->opcode == MINT_BOX_PTR || ins->opcode == MINT_BOX_NULLABLE_PTR) { - // These opcodes violate the stack based design, just clear the whole stack - // for now since we will get rid of the stack design anyway. - memset (stack, 0, (sp - stack) * sizeof (StackContentInfo)); - } else if (ins->opcode == MINT_CKNULL_N) { - // This opcode violates the stack based design, just clear the whole stack - // for now since we will get rid of the stack design anyway. - for (StackContentInfo *spit = stack; spit < sp; spit++) - spit->ins = NULL; - } else if (ins->opcode == MINT_POP || ins->opcode == MINT_POP_VT) { - sp--; - if (sp->ins) { - // The top of the stack is not used by any instructions. Kill both the - // instruction that pushed it and the pop. - interp_clear_ins (sp->ins); - interp_clear_ins (ins); - mono_interp_stats.killed_instructions += 2; - // The value pop-ed by this instruction can still be accessed. If we also - // kill the instruction pushing the value, then we need to empty the - // value of the stack, so it is not considered for further optimizations. - sp->val.type = STACK_VALUE_NONE; - } - } else if ((ins->opcode == MINT_NEWOBJ_FAST || ins->opcode == MINT_NEWOBJ_VT_FAST) && ins->data [0] == INLINED_METHOD_FLAG) { - int param_count = ins->data [3]; - // memmove the stack values while clearing ins, to prevent instruction removal - for (int i = 1; i <= param_count; i++) { - sp [-i + 2] = sp [-i]; - sp [-i + 2].ins = NULL; - } - // clear stack information for the slots where the allocated object resides - memset (&sp [-param_count], 0, 2 * sizeof (StackContentInfo)); - sp += 2; - } else if (ins->opcode == MINT_CASTCLASS || ins->opcode == MINT_CASTCLASS_COMMON || ins->opcode == MINT_CASTCLASS_INTERFACE) { - // Keep the value on the stack, but prevent optimizing away - sp [-1].ins = NULL; - } else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (ins->opcode)) { - ins = interp_fold_unop_cond_br (td, bb, sp, ins); - sp--; - } else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (ins->opcode)) { - ins = interp_fold_binop_cond_br (td, bb, sp, ins); - sp -= 2; - } else if (MINT_IS_UNOP (ins->opcode)) { - ins = interp_fold_unop (td, sp, ins); - } else if (MINT_IS_BINOP (ins->opcode)) { - ins = interp_fold_binop (td, sp, ins); - sp--; - } else if (ins->opcode == MINT_LDLOCA_S && ins->next && MINT_IS_LDFLD (ins->next->opcode) && - td->locals [ins->data [0]].mt == (ins->next->opcode - MINT_LDFLD_I1) && - ins->next->data [0] == 0) { - int mt = ins->next->opcode - MINT_LDFLD_I1; - int local = ins->data [0]; - // Replace LDLOCA + LDFLD with LDLOC, when the storing field represents - // the entire local. This is the case with storing to the only field of - // an IntPtr. We don't handle value type loads. - ins->next->opcode = MINT_LDLOC_I1 + mt; - ins->next->data [0] = local; - td->locals [local].indirects--; - interp_clear_ins (ins); - mono_interp_stats.killed_instructions++; - mono_interp_stats.ldlocas_removed++; - if (td->verbose_level) { - g_print ("Replace ldloca/ldfld pair :\n\t"); - dump_interp_inst (ins->next); - } - } else if (ins->opcode >= MINT_STFLD_I1 && ins->opcode <= MINT_STFLD_O) { - StackContentInfo *src = &sp [-2]; - if (src->ins) { - if (src->ins->opcode == MINT_LDLOCA_S && td->locals [src->ins->data [0]].mt == (ins->opcode - MINT_STFLD_I1) && - ins->data [0] == 0) { + } else if (MINT_IS_LDFLD (opcode) && ins->data [0] == 0) { + InterpInst *ldloca = local_defs [sregs [0]].ins; + if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S && + td->locals [ldloca->sregs [0]].mt == (ins->opcode - MINT_LDFLD_I1)) { + int mt = ins->opcode - MINT_LDFLD_I1; + int local = ldloca->sregs [0]; + // Replace LDLOCA + LDFLD with LDLOC, when the loading field represents + // the entire local. This is the case with loading the only field of an + // IntPtr. We don't handle value type loads. + ins->opcode = get_mov_for_type (mt, TRUE); + // The dreg of the MOV is the same as the dreg of the LDFLD + local_ref_count [sregs [0]]--; + sregs [0] = local; + + if (td->verbose_level) { + g_print ("Replace ldloca/ldfld pair :\n\t"); + dump_interp_inst (ins->next); + } + } + } else if (MINT_IS_STFLD (opcode) && ins->data [0] == 0) { + InterpInst *ldloca = local_defs [sregs [0]].ins; + if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S && + td->locals [ldloca->sregs [0]].mt == (ins->opcode - MINT_STFLD_I1)) { int mt = ins->opcode - MINT_STFLD_I1; - int local = src->ins->data [0]; - interp_clear_ins (src->ins); - ins->opcode = MINT_STLOC_I1 + mt; - ins->data [0] = local; - td->locals [local].indirects--; - mono_interp_stats.killed_instructions++; - mono_interp_stats.ldlocas_removed++; - // FIXME Update stack contents for stloc, we currently rely on cprop running again. - clear_stack_content_info_for_local (stack, sp, local); - clear_local_content_info_for_local (locals, locals + td->locals_size, local); + int local = ldloca->sregs [0]; + + ins->opcode = get_mov_for_type (mt, FALSE); + // The sreg of the MOV is the same as the second sreg of the STFLD + local_ref_count [sregs [0]]--; + ins->dreg = local; + sregs [0] = sregs [1]; if (td->verbose_level) { - g_print ("Replace ldloca/stfld pair (off %p) :\n\t", src->ins->il_offset); + g_print ("Replace ldloca/stfld pair (off %p) :\n\t", ldloca->il_offset); dump_interp_inst (ins); } - } else if (src->val.type == STACK_VALUE_LOCAL && (mono_interp_opt & INTERP_OPT_SUPER_INSTRUCTIONS)) { - int loc_index = src->val.local; - int fld_offset = ins->data [0]; - int mt = ins->opcode - MINT_STFLD_I1; - ins = interp_insert_ins_bb (td, bb, ins, MINT_STLOCFLD_I1 + mt); - ins->data [0] = loc_index; - ins->data [1] = fld_offset; - local_ref_count [loc_index]++; - interp_clear_ins (ins->prev); - interp_clear_ins (src->ins); - mono_interp_stats.super_instructions++; - mono_interp_stats.killed_instructions++; } } - sp -= 2; - } else if (MINT_IS_STLOCFLD (ins->opcode)) { - local_ref_count [ins->data [0]]++; - sp--; - } else { - if (pop == MINT_POP_ALL) - pop = sp - stack; - sp += push - pop; - g_assert (sp >= stack && sp <= stack_end); - g_assert ((sp - push) >= stack && (sp - push) <= stack_end); - memset (sp - push, 0, push * sizeof (StackContentInfo)); - // If this instruction only pushes a single value, make it a candidate for - // removal, if its value is not used anywhere. - if (push == 1 && pop == 0 && !MINT_IS_CALL (ins->opcode) && !MINT_IS_NEWOBJ (ins->opcode)) - sp [-1].ins = ins; - } + ins_index++; } } @@ -7902,8 +8198,7 @@ interp_cprop (TransformData *td) if (needs_retry) goto retry; - g_free (stack); - g_free (locals); + g_free (local_defs); g_free (local_ref_count); } @@ -7916,53 +8211,7 @@ mono_test_interp_cprop (TransformData *td) static void interp_super_instructions (TransformData *td) { - InterpBasicBlock *bb; - for (bb = td->entry_bb; bb != NULL; bb = bb->next_bb) { - InterpInst *ins; - InterpInst *prev1_ins = NULL; - InterpInst *prev2_ins = NULL; - for (ins = bb->first_ins; ins != NULL; ins = ins->next) { - if (ins->opcode == MINT_NOP) - continue; - if (ins->opcode >= MINT_LDFLD_I1 && ins->opcode <= MINT_LDFLD_O && prev1_ins) { - if (prev1_ins->opcode == MINT_LDLOC_O) { - int loc_index = prev1_ins->data [0]; - int fld_offset = ins->data [0]; - int mt = ins->opcode - MINT_LDFLD_I1; - ins = interp_insert_ins_bb (td, bb, ins, MINT_LDLOCFLD_I1 + mt); - ins->data [0] = loc_index; - ins->data [1] = fld_offset; - interp_clear_ins (ins->prev); - interp_clear_ins (prev1_ins); - prev1_ins = NULL; - mono_interp_stats.super_instructions++; - mono_interp_stats.killed_instructions++; - } - } else if (MINT_IS_STLOC (ins->opcode) && prev1_ins && prev2_ins) { - if (prev1_ins->opcode == MINT_ADD1_I4 || prev1_ins->opcode == MINT_ADD1_I8 || - prev1_ins->opcode == MINT_SUB1_I4 || prev1_ins->opcode == MINT_SUB1_I8) { - if (MINT_IS_LDLOC (prev2_ins->opcode) && prev2_ins->data [0] == ins->data [0]) { - if (prev1_ins->opcode == MINT_ADD1_I4) - ins->opcode = MINT_LOCADD1_I4; - else if (prev1_ins->opcode == MINT_ADD1_I8) - ins->opcode = MINT_LOCADD1_I8; - else if (prev1_ins->opcode == MINT_SUB1_I4) - ins->opcode = MINT_LOCSUB1_I4; - else - ins->opcode = MINT_LOCSUB1_I8; - // the local index is already set inside the replaced STLOC instruction - interp_clear_ins (prev1_ins); - interp_clear_ins (prev2_ins); - prev1_ins = NULL; - mono_interp_stats.super_instructions++; - mono_interp_stats.killed_instructions += 2; - } - } - } - prev2_ins = prev1_ins; - prev1_ins = ins; - } - } + // Add some actual super instructions } static void @@ -8105,7 +8354,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, MonoG g_print ("Runtime method: %s %p\n", mono_method_full_name (method, TRUE), rtm); g_print ("Locals size %d, stack size: %d\n", td->total_locals_size, td->max_stack_size); g_print ("Calculated stack height: %d, stated height: %d\n", td->max_stack_height, header->max_stack); - dump_mint_code (td->new_code, td->new_code_end); + dump_interp_code (td->new_code, td->new_code_end); } /* Check if we use excessive stack space */ diff --git a/src/mono/mono/mini/interp/transform.h b/src/mono/mono/mini/interp/transform.h index bd8ec7b1940826..2e3f631d8b188d 100644 --- a/src/mono/mono/mini/interp/transform.h +++ b/src/mono/mono/mini/interp/transform.h @@ -11,6 +11,8 @@ #define INTERP_INST_FLAG_RECORD_CALL_PATCH 16 #define INTERP_LOCAL_FLAG_DEAD 1 +#define INTERP_LOCAL_FLAG_EXECUTION_STACK 2 +#define INTERP_LOCAL_FLAG_CALL_ARGS 4 typedef struct _InterpInst InterpInst; typedef struct _InterpBasicBlock InterpBasicBlock; @@ -20,40 +22,37 @@ typedef struct MonoClass *klass; unsigned char type; unsigned char flags; + /* + * The local associated with the value of this stack entry. Every time we push on + * the stack a new local is created. + */ + int local; /* The offset from the execution stack start where this is stored */ int offset; /* Saves how much stack this is using. It is a multiple of MINT_VT_ALIGNMENT */ int size; } StackInfo; -#define STACK_VALUE_NONE 0 -#define STACK_VALUE_LOCAL 1 -#define STACK_VALUE_I4 2 -#define STACK_VALUE_I8 3 +#define LOCAL_VALUE_NONE 0 +#define LOCAL_VALUE_LOCAL 1 +#define LOCAL_VALUE_I4 2 +#define LOCAL_VALUE_I8 3 -// StackValue contains data to construct an InterpInst that is equivalent with the contents +// LocalValue contains data to construct an InterpInst that is equivalent with the contents // of the stack slot / local / argument. typedef struct { - // Indicates the type of the stored information. It can be a local, argument or a constant + // Indicates the type of the stored information. It can be another local or a constant int type; // Holds the local index or the actual constant value union { int local; - int arg; gint32 i; gint64 l; }; -} StackValue; - -typedef struct -{ - // This indicates what is currently stored in this stack slot. This can be a constant - // or the copy of a local / argument. - StackValue val; - // The instruction that pushed this stack slot. If ins is null, we can't remove the usage - // of the stack slot, because we can't clear the instruction that set it. + // The instruction that writes this local. InterpInst *ins; -} StackContentInfo; + int def_index; +} LocalValue; struct _InterpInst { guint16 opcode; @@ -62,6 +61,8 @@ struct _InterpInst { // part of the IL instruction associated with the previous interp instruction. int il_offset; guint32 flags; + gint32 dreg; + gint32 sregs [3]; // Currently all instructions have at most 3 sregs // This union serves the same purpose as the data array. The difference is that // the data array maps exactly to the final representation of the instruction. // FIXME We should consider using a separate higher level IR, that is also easier @@ -69,7 +70,12 @@ struct _InterpInst { union { InterpBasicBlock *target_bb; InterpBasicBlock **target_bb_table; + // We handle newobj poorly due to not having our own local offset allocator. + // We temporarily use this array to let cprop know the values of the newobj args. + int *newobj_reg_map; } info; + // Variable data immediately following the dreg/sreg information. This is represented exactly + // in the final code stream as in this array. guint16 data [MONO_ZERO_LEN_ARRAY]; }; @@ -115,6 +121,8 @@ typedef enum { typedef struct { RelocType type; + /* For branch relocation, how many sreg slots to skip */ + int skip; /* In the interpreter IR */ int offset; InterpBasicBlock *target_bb; @@ -127,6 +135,10 @@ typedef struct { int indirects; int offset; int size; + union { + // the offset from the start of the execution stack locals space + int stack_offset; + }; } InterpLocal; typedef struct diff --git a/src/mono/mono/mini/interp/whitebox.c b/src/mono/mono/mini/interp/whitebox.c index c9496334194224..7dcadf905abe83 100644 --- a/src/mono/mono/mini/interp/whitebox.c +++ b/src/mono/mono/mini/interp/whitebox.c @@ -78,10 +78,6 @@ verify_cprop_ldloc_stloc (TransformData *td) return 1; if (expect (&ins, NULL, MINT_CALL)) return 2; - if (expect (&ins, NULL, MINT_STLOC_NP_I4)) - return 3; - if (expect (&ins, NULL, MINT_LDLOC_I4)) - return 4; if (expect (&ins, NULL, MINT_ADD_I4)) return 5; if (expect (&ins, NULL, MINT_RET))