diff --git a/src/lj_bc.h b/src/lj_bc.h index 02356e5b..af532716 100644 --- a/src/lj_bc.h +++ b/src/lj_bc.h @@ -144,6 +144,7 @@ _(GSET, var, ___, str, newindex) \ _(TGETV, dst, var, var, index) \ _(TGETS, dst, var, str, index) \ + _(TGETSS, dst, var, str, index) \ _(TGETB, dst, var, lit, index) \ _(TGETR, dst, var, var, index) \ _(TSETV, var, var, var, newindex) \ @@ -259,6 +260,8 @@ static LJ_AINLINE int bc_isret(BCOp op) return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1); } +#define bc_isalias(op) ((op) == BC_TGETSS) + LJ_DATA const uint16_t lj_bc_mode[]; LJ_DATA const uint16_t lj_bc_ofs[]; diff --git a/src/lj_debug.c b/src/lj_debug.c index 112f5358..65e7fac2 100644 --- a/src/lj_debug.c +++ b/src/lj_debug.c @@ -271,13 +271,10 @@ restart: return "global"; case BC_TGETS: *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); - if (ip > proto_bc(pt)) { - BCIns insp = ip[-1]; - if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 && - bc_d(insp) == bc_b(ins)) - return "method"; - } return "field"; + case BC_TGETSS: + *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); + return "method"; case BC_UGET: *name = lj_debug_uvname(pt, bc_d(ins)); return "upvalue"; diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 022de1aa..c8625a7e 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -225,6 +225,7 @@ static void LJ_FASTCALL recff_getmetatable(jit_State *J, RecordFFData *rd) RecordIndex ix; ix.tab = tr; copyTV(J->L, &ix.tabv, &rd->argv[0]); + ix.mtspec = 0; if (lj_record_mm_lookup(J, &ix, MM_metatable)) J->base[0] = ix.mobj; else @@ -241,6 +242,7 @@ static void LJ_FASTCALL recff_setmetatable(jit_State *J, RecordFFData *rd) RecordIndex ix; ix.tab = tr; copyTV(J->L, &ix.tabv, &rd->argv[0]); + ix.mtspec = 0; lj_record_mm_lookup(J, &ix, MM_metatable); /* Guard for no __metatable. */ fref = emitir(IRT(IR_FREF, IRT_PGC), tr, IRFL_TAB_META); mtref = tref_isnil(mt) ? lj_ir_knull(J, IRT_TAB) : mt; @@ -389,6 +391,7 @@ static int recff_metacall(jit_State *J, RecordFFData *rd, MMS mm) RecordIndex ix; ix.tab = J->base[0]; copyTV(J->L, &ix.tabv, &rd->argv[0]); + ix.mtspec = 1; if (lj_record_mm_lookup(J, &ix, mm)) { /* Has metamethod? */ int errcode; TValue argv0; @@ -548,6 +551,7 @@ static void LJ_FASTCALL recff_next(jit_State *J, RecordFFData *rd) ix.idxchain = (J->framedepth && frame_islua(J->L->base-1) && bc_b(frame_pc(J->L->base-1)[-1])-1 < 2); ix.mobj = 0; /* We don't need the next index. */ + ix.mtspec = 0; rd->nres = lj_record_next(J, &ix); J->base[0] = ix.key; J->base[1] = ix.val; diff --git a/src/lj_parse.c b/src/lj_parse.c index 9ddf60ed..42006483 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c @@ -675,7 +675,7 @@ static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key) idx = const_str(fs, key); if (idx <= BCMAX_C) { bcreg_reserve(fs, 2+LJ_FR2); - bcemit_ABC(fs, BC_TGETS, func, obj, idx); + bcemit_ABC(fs, BC_TGETSS, func, obj, idx); } else { bcreg_reserve(fs, 3+LJ_FR2); bcemit_AD(fs, BC_KSTR, func+2+LJ_FR2, idx); diff --git a/src/lj_record.c b/src/lj_record.c index bfd41236..f6c4f8a6 100644 --- a/src/lj_record.c +++ b/src/lj_record.c @@ -686,6 +686,7 @@ static LoopEvent rec_itern(jit_State *J, BCReg ra, BCReg rb) copyTV(J->L, &ix.keyv, &J->L->base[ra-1]); ix.idxchain = (rb < 3); /* Omit value type check, if unused. */ ix.mobj = 1; /* We need the next index, too. */ + ix.mtspec = 0; J->maxslot = ra + lj_record_next(J, &ix); J->needsnap = 1; if (!tref_isnil(ix.key)) { /* Looping back? */ @@ -818,6 +819,7 @@ static void rec_call_setup(jit_State *J, BCReg func, ptrdiff_t nargs) if (!tref_isfunc(fbase[0])) { /* Resolve __call metamethod. */ ix.tab = fbase[0]; copyTV(J->L, &ix.tabv, functv); + ix.mtspec = 1; if (!lj_record_mm_lookup(J, &ix, MM_call) || !tref_isfunc(ix.mobj)) lj_trace_err(J, LJ_TRERR_NOMM); for (i = ++nargs; i > LJ_FR2; i--) /* Shift arguments up. */ @@ -1103,7 +1105,14 @@ int lj_record_mm_lookup(jit_State *J, RecordIndex *ix, MMS mm) goto nocheck; } ix->mt = mt ? mix.tab : TREF_NIL; - emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mix.tab, lj_ir_knull(J, IRT_TAB)); + if (ix->mtspec && mt) { + TRef kmt = lj_ir_ktab(J, mt); + emitir(IRTG(IR_EQ, IRT_TAB), mix.tab, kmt); + mix.tab = kmt; + ix->mt = kmt; + } else { + emitir(IRTG(mt ? IR_NE : IR_EQ, IRT_TAB), mix.tab, lj_ir_knull(J, IRT_TAB)); + } nocheck: if (mt) { GCstr *mmstr = mmname_str(J2G(J), mm); @@ -1157,6 +1166,7 @@ static TRef rec_mm_len(jit_State *J, TRef tr, TValue *tv) RecordIndex ix; ix.tab = tr; copyTV(J->L, &ix.tabv, tv); + ix.mtspec = 1; if (lj_record_mm_lookup(J, &ix, MM_len)) { BCReg func = rec_mm_prep(J, lj_cont_ra); TRef *base = J->base + func; @@ -2086,6 +2096,7 @@ static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot) ix.tab = top[-1]; ix.key = top[0]; memcpy(savetv, &J->L->base[topslot-1], sizeof(savetv)); /* Save slots. */ + ix.mtspec = 1; rec_mm_arith(J, &ix, MM_concat); /* Call __concat metamethod. */ memcpy(&J->L->base[topslot-1], savetv, sizeof(savetv)); /* Restore slots. */ return 0; /* No result yet. */ @@ -2290,6 +2301,7 @@ void lj_record_ins(jit_State *J) rc = lj_ir_kint(J, 0); ta = IRT_INT; } else { + ix.mtspec = 1; rec_mm_comp(J, &ix, (int)op); break; } @@ -2313,10 +2325,12 @@ void lj_record_ins(jit_State *J) int diff; rec_comp_prep(J); diff = lj_record_objcmp(J, ra, rc, rav, rcv); - if (diff == 2 || !(tref_istab(ra) || tref_isudata(ra))) + if (diff == 2 || !(tref_istab(ra) || tref_isudata(ra))) { rec_comp_fixup(J, J->pc, ((int)op & 1) == !diff); - else if (diff == 1) /* Only check __eq if different, but same type. */ + } else if (diff == 1) { /* Only check __eq if different, but same type. */ + ix.mtspec = 1; rec_mm_equal(J, &ix, (int)op); + } } break; @@ -2367,6 +2381,7 @@ void lj_record_ins(jit_State *J) } else { ix.tab = rc; copyTV(J->L, &ix.tabv, rcv); + ix.mtspec = 1; rc = rec_mm_arith(J, &ix, MM_unm); } break; @@ -2383,27 +2398,33 @@ void lj_record_ins(jit_State *J) case BC_ADDVN: case BC_SUBVN: case BC_MULVN: case BC_DIVVN: case BC_ADDVV: case BC_SUBVV: case BC_MULVV: case BC_DIVVV: { MMS mm = bcmode_mm(op); - if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) + if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) { rc = lj_opt_narrow_arith(J, rb, rc, rbv, rcv, (int)mm - (int)MM_add + (int)IR_ADD); - else + } else { + ix.mtspec = 1; rc = rec_mm_arith(J, &ix, mm); + } break; } case BC_MODVN: case BC_MODVV: recmod: - if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) + if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) { rc = lj_opt_narrow_mod(J, rb, rc, rbv, rcv); - else + } else { + ix.mtspec = 1; rc = rec_mm_arith(J, &ix, MM_mod); + } break; case BC_POW: - if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) + if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) { rc = lj_opt_narrow_arith(J, rb, rc, rbv, rcv, IR_POW); - else + } else { + ix.mtspec = 1; rc = rec_mm_arith(J, &ix, MM_pow); + } break; /* -- Miscellaneous ops ------------------------------------------------- */ @@ -2457,6 +2478,7 @@ void lj_record_ins(jit_State *J) settabV(J->L, &ix.tabv, tabref(J->fn->l.env)); ix.tab = emitir(IRT(IR_FLOAD, IRT_TAB), getcurrf(J), IRFL_FUNC_ENV); ix.idxchain = LJ_MAX_IDXCHAIN; + ix.mtspec = 0; rc = lj_record_idx(J, &ix); break; @@ -2466,6 +2488,12 @@ void lj_record_ins(jit_State *J) /* fallthrough */ case BC_TGETV: case BC_TGETS: case BC_TSETV: case BC_TSETS: ix.idxchain = LJ_MAX_IDXCHAIN; + ix.mtspec = 0; + rc = lj_record_idx(J, &ix); + break; + case BC_TGETSS: + ix.idxchain = LJ_MAX_IDXCHAIN; + ix.mtspec = 1; rc = lj_record_idx(J, &ix); break; case BC_TGETR: case BC_TSETR: diff --git a/src/lj_record.h b/src/lj_record.h index ab2f4c8d..259d7362 100644 --- a/src/lj_record.h +++ b/src/lj_record.h @@ -23,7 +23,8 @@ typedef struct RecordIndex { TRef val; /* Value reference for a store or 0 for a load. */ TRef mt; /* Metatable reference. */ TRef mobj; /* Metamethod object reference. */ - int idxchain; /* Index indirections left or 0 for raw lookup. */ + short idxchain; /* Index indirections left or 0 for raw lookup. */ + short mtspec; /* Specialize to metatable. */ } RecordIndex; LJ_FUNC int lj_record_objcmp(jit_State *J, TRef a, TRef b, diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc index 770c1602..41419336 100644 --- a/src/vm_arm.dasc +++ b/src/vm_arm.dasc @@ -2592,6 +2592,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |=>defop: switch (op) { @@ -3542,6 +3546,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | b ->vmeta_tgetv break; case BC_TGETS: + |=>BC_TGETSS: | decode_RB8 RB, INS | and RC, RC, #255 | // RA = dst*8, RB = table*8, RC = str_const (~) diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc index 3448d0d2..b03f0171 100644 --- a/src/vm_arm64.dasc +++ b/src/vm_arm64.dasc @@ -2226,6 +2226,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |=>defop: switch (op) { @@ -2992,6 +2996,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | b ->BC_TGETS_Z break; case BC_TGETS: + |=>BC_TGETSS: | decode_RB RB, INS | and RC, RC, #255 | // RA = dst, RB = table, RC = str_const (~) diff --git a/src/vm_mips.dasc b/src/vm_mips.dasc index 34645bf1..d863ddf8 100644 --- a/src/vm_mips.dasc +++ b/src/vm_mips.dasc @@ -2981,6 +2981,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |=>defop: switch (op) { @@ -4076,6 +4080,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |. nop break; case BC_TGETS: + |=>BC_TGETSS: | // RA = dst*8, RB = table*8, RC = str_const*4 (~) | decode_RB8a RB, INS | decode_RB8b RB diff --git a/src/vm_mips64.dasc b/src/vm_mips64.dasc index 651bc42e..bb13b0a0 100644 --- a/src/vm_mips64.dasc +++ b/src/vm_mips64.dasc @@ -3104,6 +3104,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |=>defop: switch (op) { @@ -4290,6 +4294,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) |. nop break; case BC_TGETS: + |=>BC_TGETSS: | // RA = dst*8, RB = table*8, RC = str_const*8 (~) | decode_RB8a RB, INS | decode_RB8b RB diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc index 3cad37d2..2976cc39 100644 --- a/src/vm_ppc.dasc +++ b/src/vm_ppc.dasc @@ -3310,6 +3310,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |=>defop: switch (op) { @@ -4563,6 +4567,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | b ->BC_TGETS_Z // String key? break; case BC_TGETS: + |=>BC_TGETSS: | // RA = dst*8, RB = table*8, RC = str_const*8 (~) | lwzux CARG1, RB, BASE | srwi TMP1, RC, 1 diff --git a/src/vm_x64.dasc b/src/vm_x64.dasc index 03d96557..a5313bae 100644 --- a/src/vm_x64.dasc +++ b/src/vm_x64.dasc @@ -2796,6 +2796,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |// Note: aligning all instructions does not pay off. |=>defop: @@ -3678,6 +3682,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | jmp ->BC_TGETS_Z break; case BC_TGETS: + |=>BC_TGETSS: | ins_ABC // RA = dst, RB = table, RC = str const (~) | mov TAB:RB, [BASE+RB*8] | not RC diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index 18ca87b5..c3277fd3 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc @@ -3381,6 +3381,10 @@ static void build_subroutines(BuildCtx *ctx) static void build_ins(BuildCtx *ctx, BCOp op, int defop) { int vk = 0; + + if (bc_isalias(op)) + return; + |// Note: aligning all instructions does not pay off. |=>defop: @@ -4309,6 +4313,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | jmp ->BC_TGETS_Z break; case BC_TGETS: + |=>BC_TGETSS: | ins_ABC // RA = dst, RB = table, RC = str const (~) | not RCa | mov STR:RC, [KBASE+RC*4]