diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index fe813407e2d65b..ec422ef1a7771a 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1022,6 +1022,22 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con } \ } while (0) +// Reduce duplicate code in interp_exec_method +static void +do_safepoint (InterpFrame *frame, ThreadContext *context) +{ + context_set_safepoint_frame (context, frame); + /* Poll safepoint */ + mono_threads_safepoint (); + context_clear_safepoint_frame (context); +} + +#define SAFEPOINT \ + do { \ + if (G_UNLIKELY (mono_polling_required)) \ + do_safepoint (frame, context); \ + } while (0) + static MonoObject* ves_array_create (MonoClass *klass, int param_count, stackval *values, MonoError *error) { @@ -4136,6 +4152,79 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs CONDBR(mono_isunordered (d1, d2) || d1 < d2) MINT_IN_BREAK; } + +#define ZEROP_SP(datatype, op) \ + if (LOCAL_VAR (ip [1], datatype) op 0) { \ + gint16 br_offset = (gint16) ip [2]; \ + BACK_BRANCH_PROFILE (br_offset); \ + SAFEPOINT; \ + ip += br_offset; \ + } else \ + ip += 3; + +MINT_IN_CASE(MINT_BRFALSE_I4_SP) ZEROP_SP(gint32, ==); MINT_IN_BREAK; +MINT_IN_CASE(MINT_BRFALSE_I8_SP) ZEROP_SP(gint64, ==); MINT_IN_BREAK; +MINT_IN_CASE(MINT_BRTRUE_I4_SP) ZEROP_SP(gint32, !=); MINT_IN_BREAK; +MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK; + +#define CONDBR_SP(cond) \ + if (cond) { \ + gint16 br_offset = (gint16) ip [3]; \ + BACK_BRANCH_PROFILE (br_offset); \ + SAFEPOINT; \ + ip += br_offset; \ + } else \ + ip += 4; +#define BRELOP_SP(datatype, op) \ + CONDBR_SP(LOCAL_VAR (ip [1], datatype) op LOCAL_VAR (ip [2], datatype)) + + MINT_IN_CASE(MINT_BEQ_I4_SP) BRELOP_SP(gint32, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8_SP) BRELOP_SP(gint64, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I4_SP) BRELOP_SP(gint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8_SP) BRELOP_SP(gint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I4_SP) BRELOP_SP(gint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8_SP) BRELOP_SP(gint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I4_SP) BRELOP_SP(gint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8_SP) BRELOP_SP(gint64, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I4_SP) BRELOP_SP(gint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8_SP) BRELOP_SP(gint64, <=); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_BNE_UN_I4_SP) BRELOP_SP(guint32, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8_SP) BRELOP_SP(guint64, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I4_SP) BRELOP_SP(guint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8_SP) BRELOP_SP(guint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I4_SP) BRELOP_SP(guint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8_SP) BRELOP_SP(guint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I4_SP) BRELOP_SP(guint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8_SP) BRELOP_SP(guint64, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I4_SP) BRELOP_SP(guint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8_SP) BRELOP_SP(guint64, <); MINT_IN_BREAK; + +#define BRELOP_IMM_SP(datatype, op) \ + CONDBR_SP(LOCAL_VAR (ip [1], datatype) op (datatype)(gint16)ip [2]) + + MINT_IN_CASE(MINT_BEQ_I4_IMM_SP) BRELOP_IMM_SP(gint32, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BEQ_I8_IMM_SP) BRELOP_IMM_SP(gint64, ==); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I4_IMM_SP) BRELOP_IMM_SP(gint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_I8_IMM_SP) BRELOP_IMM_SP(gint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I4_IMM_SP) BRELOP_IMM_SP(gint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_I8_IMM_SP) BRELOP_IMM_SP(gint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I4_IMM_SP) BRELOP_IMM_SP(gint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_I8_IMM_SP) BRELOP_IMM_SP(gint64, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I4_IMM_SP) BRELOP_IMM_SP(gint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_I8_IMM_SP) BRELOP_IMM_SP(gint64, <=); MINT_IN_BREAK; + + MINT_IN_CASE(MINT_BNE_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BNE_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, !=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGE_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, >=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BGT_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, >); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLE_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, <=); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I4_IMM_SP) BRELOP_IMM_SP(guint32, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_BLT_UN_I8_IMM_SP) BRELOP_IMM_SP(guint64, <); MINT_IN_BREAK; + MINT_IN_CASE(MINT_SWITCH) { guint32 val = LOCAL_VAR (ip [1], guint32); guint32 n = READ32 (ip + 2); @@ -5089,20 +5178,8 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs THROW_EX (ex, ip); MINT_IN_BREAK; } - MINT_IN_CASE(MINT_CHECKPOINT) - /* Do synchronous checking of abort requests */ - EXCEPTION_CHECKPOINT; - ++ip; - MINT_IN_BREAK; MINT_IN_CASE(MINT_SAFEPOINT) - /* Do synchronous checking of abort requests */ - EXCEPTION_CHECKPOINT; - if (G_UNLIKELY (mono_polling_required)) { - context_set_safepoint_frame (context, frame); - /* Poll safepoint */ - mono_threads_safepoint (); - context_clear_safepoint_frame (context); - } + SAFEPOINT; ++ip; MINT_IN_BREAK; MINT_IN_CASE(MINT_LDFLDA_UNSAFE) { @@ -5125,35 +5202,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -// FIXME squash to load directly field type, LDFLD_VT is just a LDLOC -#define LDFLD_VT_UNALIGNED(datatype, fieldtype, unaligned) do { \ - if (unaligned) \ - memcpy (locals + ip [1], (char *)locals + ip [2] + ip [3], sizeof (fieldtype)); \ - else \ - LOCAL_VAR (ip [1], datatype) = LOCAL_VAR (ip [2] + ip [3], fieldtype); \ - ip += 4; \ -} while (0) - -#define LDFLD_VT(datatype, fieldtype) LDFLD_VT_UNALIGNED(datatype, fieldtype, FALSE) - - 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) { - memmove (locals + ip [1], locals + ip [2] + ip [3], ip [4]); - ip += 5; - MINT_IN_BREAK; - } - #define LDFLD_UNALIGNED(datatype, fieldtype, unaligned) do { \ MonoObject *o = LOCAL_VAR (ip [2], MonoObject*); \ NULL_CHECK (o); \ @@ -5241,9 +5289,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } - MINT_IN_CASE(MINT_LDSSFLDA) { - guint32 offset = READ32(ip + 2); - LOCAL_VAR (ip [1], gpointer) = mono_get_special_static_data (offset); + MINT_IN_CASE(MINT_LDTSFLDA) { + MonoInternalThread *thread = mono_thread_internal_current (); + guint32 offset = READ32 (ip + 2); + LOCAL_VAR (ip [1], gpointer) = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); ip += 4; MINT_IN_BREAK; } @@ -5278,38 +5327,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define LDTSFLD(datatype, fieldtype) { \ - MonoInternalThread *thread = mono_thread_internal_current (); \ - guint32 offset = READ32 (ip + 2); \ - gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ - 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 + 3); - gpointer addr = mono_get_special_static_data (offset); - 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 + 2); - gpointer addr = mono_get_special_static_data (offset); - memcpy (locals + ip [1], addr, ip [4]); - ip += 5; - MINT_IN_BREAK; - } #define STSFLD(datatype, fieldtype) { \ MonoVTable *vtable = (MonoVTable*) frame->imethod->data_items [ip [2]]; \ INIT_VTABLE (vtable); \ @@ -5336,40 +5353,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs MINT_IN_BREAK; } -#define STTSFLD(datatype, fieldtype) { \ - MonoInternalThread *thread = mono_thread_internal_current (); \ - guint32 offset = READ32 (ip + 2); \ - gpointer addr = ((char*)thread->static_data [offset & 0x3f]) + (offset >> 6); \ - *(fieldtype*)addr = LOCAL_VAR (ip [1], datatype); \ - ip += 4; \ - } - - 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 + 3); - gpointer addr = mono_get_special_static_data (offset); - 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 + 2); - gpointer addr = mono_get_special_static_data (offset); - 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 [3]]; mono_value_copy_internal (LOCAL_VAR (ip [1], gpointer), locals + ip [2], c); @@ -6188,9 +6171,6 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs gboolean const short_offset = opcode == MINT_LEAVE_S || opcode == MINT_LEAVE_S_CHECK; ip += short_offset ? (gint16)*(ip + 1) : (gint32)READ32 (ip + 1); - // Check for any abort requests, once all finally blocks were invoked - if (!check) - EXCEPTION_CHECKPOINT; MINT_IN_BREAK; } MINT_IN_CASE(MINT_ICALL_V_V) @@ -6546,6 +6526,10 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs ip += 3; MINT_IN_BREAK; + MINT_IN_CASE(MINT_MOV_OFF) + // This opcode is resolved to a normal MINT_MOV when emitting compacted instructions + g_assert_not_reached (); + MINT_IN_BREAK; #define MOV(argtype1,argtype2) \ LOCAL_VAR (ip [1], argtype1) = LOCAL_VAR (ip [2], argtype2); \ diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index b3076e7b426acb..aeb5f034e2b9db 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -44,19 +44,6 @@ 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) @@ -87,18 +74,6 @@ 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_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) @@ -110,18 +85,6 @@ 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) @@ -133,7 +96,9 @@ 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_LDTSFLDA, "ldtsflda", 4, 1, 0, MintOpInt) + +OPDEF(MINT_MOV_OFF, "mov.off", 6, 1, 1, MintOpTwoShorts) OPDEF(MINT_MOV_I1, "mov.i1", 3, 1, 1, MintOpNoArgs) OPDEF(MINT_MOV_U1, "mov.u1", 3, 1, 1, MintOpNoArgs) @@ -200,7 +165,6 @@ 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) @@ -305,6 +269,56 @@ 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_BRFALSE_I4_SP, "brfalse.i4.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRFALSE_I8_SP, "brfalse.i8.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I4_SP, "brtrue.i4.sp", 3, 0, 1, MintOpShortBranch) +OPDEF(MINT_BRTRUE_I8_SP, "brtrue.i8.sp", 3, 0, 1, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4_SP, "beq.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BEQ_I8_SP, "beq.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I4_SP, "bge.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_I8_SP, "bge.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I4_SP, "bgt.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_I8_SP, "bgt.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I4_SP, "blt.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_I8_SP, "blt.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I4_SP, "ble.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_I8_SP, "ble.i8.sp", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BNE_UN_I4_SP, "bne.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BNE_UN_I8_SP, "bne.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I4_SP, "bge.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGE_UN_I8_SP, "bge.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I4_SP, "bgt.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BGT_UN_I8_SP, "bgt.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I4_SP, "ble.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLE_UN_I8_SP, "ble.un.i8.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I4_SP, "blt.un.i4.sp", 4, 0, 2, MintOpShortBranch) +OPDEF(MINT_BLT_UN_I8_SP, "blt.un.i8.sp", 4, 0, 2, MintOpShortBranch) + +OPDEF(MINT_BEQ_I4_IMM_SP, "beq.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BEQ_I8_IMM_SP, "beq.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_I4_IMM_SP, "bge.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_I8_IMM_SP, "bge.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_I4_IMM_SP, "bgt.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_I8_IMM_SP, "bgt.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_I4_IMM_SP, "blt.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_I8_IMM_SP, "blt.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_I4_IMM_SP, "ble.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_I8_IMM_SP, "ble.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) + +OPDEF(MINT_BNE_UN_I4_IMM_SP, "bne.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BNE_UN_I8_IMM_SP, "bne.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_UN_I4_IMM_SP, "bge.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGE_UN_I8_IMM_SP, "bge.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_UN_I4_IMM_SP, "bgt.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BGT_UN_I8_IMM_SP, "bgt.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_UN_I4_IMM_SP, "ble.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLE_UN_I8_IMM_SP, "ble.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_UN_I4_IMM_SP, "blt.un.i4.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) +OPDEF(MINT_BLT_UN_I8_IMM_SP, "blt.un.i8.imm.sp", 4, 0, 1, MintOpShortAndShortBranch) + + OPDEF(MINT_SWITCH, "switch", 0, 0, 1, MintOpSwitch) OPDEF(MINT_LDSTR, "ldstr", 3, 1, 0, MintOpShortInt) diff --git a/src/mono/mono/mini/interp/mintops.h b/src/mono/mono/mini/interp/mintops.h index 621fa930119e12..ec5c95298c0467 100644 --- a/src/mono/mono/mini/interp/mintops.h +++ b/src/mono/mono/mini/interp/mintops.h @@ -23,7 +23,8 @@ typedef enum MintOpFieldToken, MintOpClassToken, MintOpTwoShorts, - MintOpShortAndInt + MintOpShortAndInt, + MintOpShortAndShortBranch } MintOpArgType; #define OPDEF(a,b,c,d,e,f) a, diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 90f8a056bc35e6..ac95364038ed7e 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -789,8 +789,6 @@ handle_branch (TransformData *td, int short_op, int long_op, int offset) if (offset < 0) { if (mono_threads_are_safepoints_enabled ()) interp_add_ins (td, MINT_SAFEPOINT); - else - interp_add_ins (td, MINT_CHECKPOINT); } InterpBasicBlock *target_bb = td->offset_to_bb [target]; @@ -1405,6 +1403,15 @@ dump_interp_ins_data (InterpInst *ins, gint32 ins_offset, const guint16 *data, g g_string_append_printf (str, ")"); break; } + case MintOpShortAndShortBranch: + if (ins) { + /* the target IL is already embedded in the instruction */ + g_string_append_printf (str, " %u, BB%d", *(guint16*)data, ins->info.target_bb->index); + } else { + target = ins_offset + *(gint16*)(data + 1); + g_string_append_printf (str, " %u, IR_%04x", *(guint16*)data, target); + } + break; default: g_string_append_printf (str, "unknown arg type\n"); } @@ -1698,6 +1705,32 @@ interp_get_ldind_for_mt (int mt) return -1; } +static int +interp_get_stind_for_mt (int mt) +{ + switch (mt) { + case MINT_TYPE_I1: + case MINT_TYPE_U1: + return MINT_STIND_I1; + case MINT_TYPE_I2: + case MINT_TYPE_U2: + return MINT_STIND_I2; + case MINT_TYPE_I4: + return MINT_STIND_I4; + case MINT_TYPE_I8: + return MINT_STIND_I8; + case MINT_TYPE_R4: + return MINT_STIND_R4; + case MINT_TYPE_R8: + return MINT_STIND_R8; + case MINT_TYPE_O: + return MINT_STIND_REF; + default: + g_assert_not_reached (); + } + return -1; +} + static void interp_emit_ldobj (TransformData *td, MonoClass *klass) { @@ -1731,33 +1764,7 @@ interp_emit_stobj (TransformData *td, MonoClass *klass) interp_add_ins (td, MINT_STOBJ_VT); td->last_ins->data [0] = get_data_item_index (td, klass); } else { - int opcode; - switch (mt) { - case MINT_TYPE_I1: - case MINT_TYPE_U1: - opcode = MINT_STIND_I1; - break; - case MINT_TYPE_I2: - case MINT_TYPE_U2: - opcode = MINT_STIND_I2; - break; - case MINT_TYPE_I4: - opcode = MINT_STIND_I4; - break; - case MINT_TYPE_I8: - opcode = MINT_STIND_I8; - break; - case MINT_TYPE_R4: - opcode = MINT_STIND_R4; - break; - case MINT_TYPE_R8: - opcode = MINT_STIND_R8; - break; - case MINT_TYPE_O: - opcode = MINT_STIND_REF; - break; - default: g_assert_not_reached (); break; - } + int opcode = interp_get_stind_for_mt (mt); interp_add_ins (td, opcode); } td->sp -= 2; @@ -3995,7 +4002,7 @@ interp_emit_ldsflda (TransformData *td, MonoClassField *field, MonoError *error) mono_error_assert_ok (error); g_assert (offset); - interp_add_ins (td, MINT_LDSSFLDA); + interp_add_ins (td, MINT_LDTSFLDA); interp_ins_set_dreg (td->last_ins, td->sp [-1].local); WRITE32_INS(td->last_ins, 0, &offset); } else { @@ -4065,49 +4072,33 @@ interp_emit_sfld_access (TransformData *td, MonoClassField *field, MonoClass *fi if (mono_class_field_is_special_static (field)) { guint32 offset = GPOINTER_TO_UINT (mono_special_static_field_get_offset (field, error)); mono_error_assert_ok (error); - g_assert (offset); + g_assert (offset && (offset & 0x80000000) == 0); - // Offset is SpecialStaticOffset - if ((offset & 0x80000000) == 0 && mt != MINT_TYPE_VT) { - // This field is thread static - 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); - } + // Load address of thread static field + push_simple_type (td, STACK_TYPE_MP); + interp_add_ins (td, MINT_LDTSFLDA); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + WRITE32_INS (td->last_ins, 0, &offset); + + // Do a load/store to this address + if (is_load) { + int opcode = (mt == MINT_TYPE_VT) ? MINT_LDOBJ_VT : interp_get_ldind_for_mt (mt); + interp_add_ins (td, opcode); + interp_ins_set_sreg (td->last_ins, td->sp [-1].local); + td->sp--; + push_simple_type (td, stack_type [mt]); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); + if (mt == MINT_TYPE_VT) + td->last_ins->data [0] = get_data_item_index (td, field_class); } else { + int opcode = (mt == MINT_TYPE_VT) ? MINT_STOBJ_VT : interp_get_stind_for_mt (mt); + interp_add_ins (td, opcode); + td->sp -= 2; + interp_ins_set_sregs2 (td->last_ins, td->sp [1].local, td->sp [0].local); if (mt == MINT_TYPE_VT) { int size = mono_class_value_size (field_class, NULL); 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 { - 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); + td->last_ins->data [0] = size; } } } else { @@ -5912,23 +5903,24 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, 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) { + int size = 0; /* First we pop the vt object from the stack. Then we push the field */ - int opcode = MINT_LDFLD_VT_I1 + mt - MINT_TYPE_I1; #ifdef NO_UNALIGNED_ACCESS if (field->offset % SIZEOF_VOID_P != 0) { - if (mt == MINT_TYPE_I8) - opcode = MINT_LDFLD_VT_I8_UNALIGNED; - else if (mt == MINT_TYPE_R8) - opcode = MINT_LDFLD_VT_R8_UNALIGNED; + if (mt == MINT_TYPE_I8 || mt == MINT_TYPE_R8) + size = 8; } #endif - interp_add_ins (td, opcode); + interp_add_ins (td, MINT_MOV_OFF); 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] = mt; if (mt == MINT_TYPE_VT) - td->last_ins->data [1] = field_size; + size = field_size; + td->last_ins->data [2] = size; + if (mt == MINT_TYPE_VT) push_type_vt (td, field_klass, field_size); else @@ -7557,10 +7549,14 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in } } else if ((opcode >= MINT_BRFALSE_I4_S && opcode <= MINT_BRTRUE_R8_S) || (opcode >= MINT_BEQ_I4_S && opcode <= MINT_BLT_UN_R8_S) || + (opcode >= MINT_BRFALSE_I4_SP && opcode <= MINT_BLT_UN_I8_IMM_SP) || 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; + gboolean has_imm = opcode >= MINT_BEQ_I4_IMM_SP && opcode <= MINT_BLT_UN_I8_IMM_SP; for (int i = 0; i < mono_interp_op_sregs [opcode]; i++) *ip++ = td->locals [ins->sregs [i]].offset; + if (has_imm) + *ip++ = ins->data [0]; if (ins->info.target_bb->native_offset >= 0) { // Backwards branch. We can already patch it. *ip++ = ins->info.target_bb->native_offset - br_offset; @@ -7568,7 +7564,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->skip = mono_interp_op_sregs [opcode] + has_imm; reloc->offset = br_offset; reloc->target_bb = ins->info.target_bb; g_ptr_array_add (td->relocs, reloc); @@ -7621,6 +7617,23 @@ emit_compacted_instruction (TransformData *td, guint16* start_ip, InterpInst *in cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp); cbb->last_seq_point = seqp; + } else if (opcode == MINT_MOV_OFF) { + int foff = ins->data [0]; + int mt = ins->data [1]; + int fsize = ins->data [2]; + + int dest_off = td->locals [ins->dreg].offset; + int src_off = td->locals [ins->sregs [0]].offset + foff; + if (mt == MINT_TYPE_VT || fsize) + opcode = MINT_MOV_VT; + else + opcode = get_mov_for_type (mt, TRUE); + // Replace MINT_MOV_OFF with the real instruction + ip [-1] = opcode; + *ip++ = dest_off; + *ip++ = src_off; + if (opcode == MINT_MOV_VT) + *ip++ = fsize; #ifdef ENABLE_EXPERIMENT_TIERED } else if (ins->flags & INTERP_INST_FLAG_RECORD_CALL_PATCH) { g_assert (MINT_IS_PATCHABLE_CALL (opcode)); @@ -8189,6 +8202,7 @@ interp_cprop (TransformData *td) td->local_ref_count = local_ref_count; retry: + needs_retry = FALSE; memset (local_ref_count, 0, td->locals_size * sizeof (int)); if (td->verbose_level) @@ -8295,9 +8309,11 @@ interp_cprop (TransformData *td) local_defs [dreg].type = LOCAL_VALUE_NONE; local_defs [dreg].ins = def; + local_defs [dreg].def_index = local_defs [original_dreg].def_index; local_defs [original_dreg].type = LOCAL_VALUE_LOCAL; local_defs [original_dreg].ins = ins; local_defs [original_dreg].local = dreg; + local_defs [original_dreg].def_index = ins_index; local_ref_count [original_dreg]--; local_ref_count [dreg]++; @@ -8357,13 +8373,20 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/ldfld pair :\n\t"); dump_interp_inst (ins); } + needs_retry = TRUE; } } else if (opcode == MINT_INITOBJ) { InterpInst *ldloca = local_defs [sregs [0]].ins; if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int size = ins->data [0]; int local = ldloca->sregs [0]; - // Replace LDLOCA + INITOBJ with INITLOCAL - ins->opcode = MINT_INITLOCAL; + // Replace LDLOCA + INITOBJ with or LDC + if (size <= 4) + ins->opcode = MINT_LDC_I4_0; + else if (size <= 8) + ins->opcode = MINT_LDC_I8_0; + else + ins->opcode = MINT_INITLOCAL; local_ref_count [sregs [0]]--; ins->dreg = local; @@ -8371,6 +8394,7 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/initobj pair :\n\t"); dump_interp_inst (ins); } + needs_retry = TRUE; } } else if (opcode == MINT_LDOBJ_VT) { InterpInst *ldloca = local_defs [sregs [0]].ins; @@ -8385,6 +8409,7 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/ldobj_vt pair :\n\t"); dump_interp_inst (ins); } + needs_retry = TRUE; } } else if (MINT_IS_STFLD (opcode) && ins->data [0] == 0) { InterpInst *ldloca = local_defs [sregs [0]].ins; @@ -8403,13 +8428,14 @@ interp_cprop (TransformData *td) g_print ("Replace ldloca/stfld pair (off %p) :\n\t", ldloca->il_offset); dump_interp_inst (ins); } + needs_retry = TRUE; } } ins_index++; } } - needs_retry = interp_local_deadce (td); + needs_retry |= interp_local_deadce (td); if (mono_interp_opt & INTERP_OPT_BBLOCKS) needs_retry |= interp_optimize_bblocks (td); @@ -8446,6 +8472,74 @@ get_sreg_imm (TransformData *td, int sreg, gint16 *imm) return FALSE; } +static int +get_binop_condbr_imm_sp (int opcode) +{ + switch (opcode) { + case MINT_BEQ_I4_S: return MINT_BEQ_I4_IMM_SP; + case MINT_BEQ_I8_S: return MINT_BEQ_I8_IMM_SP; + case MINT_BGE_I4_S: return MINT_BGE_I4_IMM_SP; + case MINT_BGE_I8_S: return MINT_BGE_I8_IMM_SP; + case MINT_BGT_I4_S: return MINT_BGT_I4_IMM_SP; + case MINT_BGT_I8_S: return MINT_BGT_I8_IMM_SP; + case MINT_BLT_I4_S: return MINT_BLT_I4_IMM_SP; + case MINT_BLT_I8_S: return MINT_BLT_I8_IMM_SP; + case MINT_BLE_I4_S: return MINT_BLE_I4_IMM_SP; + case MINT_BLE_I8_S: return MINT_BLE_I8_IMM_SP; + case MINT_BNE_UN_I4_S: return MINT_BNE_UN_I4_IMM_SP; + case MINT_BNE_UN_I8_S: return MINT_BNE_UN_I8_IMM_SP; + case MINT_BGE_UN_I4_S: return MINT_BGE_UN_I4_IMM_SP; + case MINT_BGE_UN_I8_S: return MINT_BGE_UN_I8_IMM_SP; + case MINT_BGT_UN_I4_S: return MINT_BGT_UN_I4_IMM_SP; + case MINT_BGT_UN_I8_S: return MINT_BGT_UN_I8_IMM_SP; + case MINT_BLE_UN_I4_S: return MINT_BLE_UN_I4_IMM_SP; + case MINT_BLE_UN_I8_S: return MINT_BLE_UN_I8_IMM_SP; + case MINT_BLT_UN_I4_S: return MINT_BLT_UN_I4_IMM_SP; + case MINT_BLT_UN_I8_S: return MINT_BLT_UN_I8_IMM_SP; + default: return MINT_NOP; + } +} + +static int +get_binop_condbr_sp (int opcode) +{ + switch (opcode) { + case MINT_BEQ_I4_S: return MINT_BEQ_I4_SP; + case MINT_BEQ_I8_S: return MINT_BEQ_I8_SP; + case MINT_BGE_I4_S: return MINT_BGE_I4_SP; + case MINT_BGE_I8_S: return MINT_BGE_I8_SP; + case MINT_BGT_I4_S: return MINT_BGT_I4_SP; + case MINT_BGT_I8_S: return MINT_BGT_I8_SP; + case MINT_BLT_I4_S: return MINT_BLT_I4_SP; + case MINT_BLT_I8_S: return MINT_BLT_I8_SP; + case MINT_BLE_I4_S: return MINT_BLE_I4_SP; + case MINT_BLE_I8_S: return MINT_BLE_I8_SP; + case MINT_BNE_UN_I4_S: return MINT_BNE_UN_I4_SP; + case MINT_BNE_UN_I8_S: return MINT_BNE_UN_I8_SP; + case MINT_BGE_UN_I4_S: return MINT_BGE_UN_I4_SP; + case MINT_BGE_UN_I8_S: return MINT_BGE_UN_I8_SP; + case MINT_BGT_UN_I4_S: return MINT_BGT_UN_I4_SP; + case MINT_BGT_UN_I8_S: return MINT_BGT_UN_I8_SP; + case MINT_BLE_UN_I4_S: return MINT_BLE_UN_I4_SP; + case MINT_BLE_UN_I8_S: return MINT_BLE_UN_I8_SP; + case MINT_BLT_UN_I4_S: return MINT_BLT_UN_I4_SP; + case MINT_BLT_UN_I8_S: return MINT_BLT_UN_I8_SP; + default: return MINT_NOP; + } +} + +static int +get_unop_condbr_sp (int opcode) +{ + switch (opcode) { + case MINT_BRFALSE_I4_S: return MINT_BRFALSE_I4_SP; + case MINT_BRFALSE_I8_S: return MINT_BRFALSE_I8_SP; + case MINT_BRTRUE_I4_S: return MINT_BRTRUE_I4_SP; + case MINT_BRTRUE_I8_S: return MINT_BRTRUE_I8_SP; + default: return MINT_NOP; + } +} + static void interp_super_instructions (TransformData *td) { @@ -8628,6 +8722,56 @@ interp_super_instructions (TransformData *td) local_ref_count [obj_sreg]--; mono_interp_stats.super_instructions++; } + } else if (MINT_IS_BINOP_CONDITIONAL_BRANCH (opcode)) { + gint16 imm; + int sreg_imm = ins->sregs [1]; + if (get_sreg_imm (td, sreg_imm, &imm)) { + int condbr_op = get_binop_condbr_imm_sp (opcode); + if (condbr_op != MINT_NOP) { + InterpInst *prev_ins = interp_prev_ins (ins); + // The new instruction does a safepoint + if (prev_ins && prev_ins->opcode == MINT_SAFEPOINT) + interp_clear_ins (prev_ins); + InterpInst *new_ins = interp_insert_ins (td, ins, condbr_op); + new_ins->sregs [0] = ins->sregs [0]; + new_ins->data [0] = imm; + new_ins->info.target_bb = ins->info.target_bb; + interp_clear_ins (td->locals [sreg_imm].def); + interp_clear_ins (ins); + local_ref_count [sreg_imm]--; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (new_ins); + } + } + } else { + InterpInst *prev_ins = interp_prev_ins (ins); + if (prev_ins && prev_ins->opcode == MINT_SAFEPOINT) { + int condbr_op = get_binop_condbr_sp (opcode); + if (condbr_op != MINT_NOP) { + interp_clear_ins (prev_ins); + ins->opcode = condbr_op; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (ins); + } + } + } + } + } else if (MINT_IS_UNOP_CONDITIONAL_BRANCH (opcode)) { + InterpInst *prev_ins = interp_prev_ins (ins); + if (prev_ins && prev_ins->opcode == MINT_SAFEPOINT) { + int condbr_op = get_unop_condbr_sp (opcode); + if (condbr_op != MINT_NOP) { + interp_clear_ins (prev_ins); + ins->opcode = condbr_op; + if (td->verbose_level) { + g_print ("superins: "); + dump_interp_inst (ins); + } + } + + } } } }