mirror of
https://github.com/love2d/megasource.git
synced 2026-08-17 11:11:35 +02:00
Update LuaJIT to the latest 2.1.0 source (f3c8569)
This commit is contained in:
+163
-19
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Trace recorder (bytecode -> SSA IR).
|
||||
** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
|
||||
** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
|
||||
*/
|
||||
|
||||
#define lj_record_c
|
||||
@@ -156,6 +156,9 @@ static void rec_check_slots(jit_State *J)
|
||||
lj_assertJ((J->slot[s+1+LJ_FR2] & TREF_FRAME),
|
||||
"cont slot %d not followed by frame", s);
|
||||
depth++;
|
||||
} else if ((tr & TREF_KEYINDEX)) {
|
||||
lj_assertJ(tref_isint(tr), "keyindex slot %d bad type %d",
|
||||
s, tref_type(tr));
|
||||
} else {
|
||||
/* Number repr. may differ, but other types must be the same. */
|
||||
lj_assertJ(tvisnumber(tv) ? tref_isnumber(tr) :
|
||||
@@ -259,6 +262,14 @@ TRef lj_record_constify(jit_State *J, cTValue *o)
|
||||
return 0; /* Can't represent lightuserdata (pointless). */
|
||||
}
|
||||
|
||||
/* Emit a VLOAD with the correct type. */
|
||||
TRef lj_record_vload(jit_State *J, TRef ref, MSize idx, IRType t)
|
||||
{
|
||||
TRef tr = emitir(IRTG(IR_VLOAD, t), ref, idx);
|
||||
if (irtype_ispri(t)) tr = TREF_PRI(t); /* Canonicalize primitives. */
|
||||
return tr;
|
||||
}
|
||||
|
||||
/* -- Record loop ops ----------------------------------------------------- */
|
||||
|
||||
/* Loop event. */
|
||||
@@ -275,9 +286,9 @@ static void canonicalize_slots(jit_State *J)
|
||||
if (LJ_DUALNUM) return;
|
||||
for (s = J->baseslot+J->maxslot-1; s >= 1; s--) {
|
||||
TRef tr = J->slot[s];
|
||||
if (tref_isinteger(tr)) {
|
||||
if (tref_isinteger(tr) && !(tr & TREF_KEYINDEX)) {
|
||||
IRIns *ir = IR(tref_ref(tr));
|
||||
if (!(ir->o == IR_SLOAD && (ir->op2 & IRSLOAD_READONLY)))
|
||||
if (!(ir->o == IR_SLOAD && (ir->op2 & (IRSLOAD_READONLY))))
|
||||
J->slot[s] = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT);
|
||||
}
|
||||
}
|
||||
@@ -598,6 +609,7 @@ static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev)
|
||||
{
|
||||
if (J->parent == 0 && J->exitno == 0) {
|
||||
if (pc == J->startpc && J->framedepth + J->retdepth == 0) {
|
||||
if (bc_op(J->cur.startins) == BC_ITERN) return; /* See rec_itern(). */
|
||||
/* Same loop? */
|
||||
if (ev == LOOPEV_LEAVE) /* Must loop back to form a root trace. */
|
||||
lj_trace_err(J, LJ_TRERR_LLEAVE);
|
||||
@@ -638,6 +650,70 @@ static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev)
|
||||
} /* Side trace continues across a loop that's left or not entered. */
|
||||
}
|
||||
|
||||
/* Record ITERN. */
|
||||
static LoopEvent rec_itern(jit_State *J, BCReg ra, BCReg rb)
|
||||
{
|
||||
#if LJ_BE
|
||||
/* YAGNI: Disabled on big-endian due to issues with lj_vm_next,
|
||||
** IR_HIOP, RID_RETLO/RID_RETHI and ra_destpair.
|
||||
*/
|
||||
UNUSED(ra); UNUSED(rb);
|
||||
setintV(&J->errinfo, (int32_t)BC_ITERN);
|
||||
lj_trace_err_info(J, LJ_TRERR_NYIBC);
|
||||
#else
|
||||
RecordIndex ix;
|
||||
/* Since ITERN is recorded at the start, we need our own loop detection. */
|
||||
if (J->pc == J->startpc &&
|
||||
(J->cur.nins > REF_FIRST+1 ||
|
||||
(J->cur.nins == REF_FIRST+1 && J->cur.ir[REF_FIRST].o != IR_PROF)) &&
|
||||
J->framedepth + J->retdepth == 0 && J->parent == 0 && J->exitno == 0) {
|
||||
lj_record_stop(J, LJ_TRLINK_LOOP, J->cur.traceno); /* Looping trace. */
|
||||
return LOOPEV_ENTER;
|
||||
}
|
||||
J->maxslot = ra;
|
||||
lj_snap_add(J); /* Required to make JLOOP the first ins in a side-trace. */
|
||||
ix.tab = getslot(J, ra-2);
|
||||
ix.key = J->base[ra-1] ? J->base[ra-1] :
|
||||
sloadt(J, (int32_t)(ra-1), IRT_INT, IRSLOAD_KEYINDEX);
|
||||
copyTV(J->L, &ix.tabv, &J->L->base[ra-2]);
|
||||
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. */
|
||||
J->maxslot = ra + lj_record_next(J, &ix);
|
||||
J->needsnap = 1;
|
||||
if (!tref_isnil(ix.key)) { /* Looping back? */
|
||||
J->base[ra-1] = ix.mobj | TREF_KEYINDEX; /* Control var has next index. */
|
||||
J->base[ra] = ix.key;
|
||||
J->base[ra+1] = ix.val;
|
||||
J->pc += bc_j(J->pc[1])+2;
|
||||
return LOOPEV_ENTER;
|
||||
} else {
|
||||
J->maxslot = ra-3;
|
||||
J->pc += 2;
|
||||
return LOOPEV_LEAVE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Record ISNEXT. */
|
||||
static void rec_isnext(jit_State *J, BCReg ra)
|
||||
{
|
||||
cTValue *b = &J->L->base[ra-3];
|
||||
if (tvisfunc(b) && funcV(b)->c.ffid == FF_next &&
|
||||
tvistab(b+1) && tvisnil(b+2)) {
|
||||
/* These checks are folded away for a compiled pairs(). */
|
||||
TRef func = getslot(J, ra-3);
|
||||
TRef trid = emitir(IRT(IR_FLOAD, IRT_U8), func, IRFL_FUNC_FFID);
|
||||
emitir(IRTGI(IR_EQ), trid, lj_ir_kint(J, FF_next));
|
||||
(void)getslot(J, ra-2); /* Type check for table. */
|
||||
(void)getslot(J, ra-1); /* Type check for nil key. */
|
||||
J->base[ra-1] = lj_ir_kint(J, 0) | TREF_KEYINDEX;
|
||||
J->maxslot = ra;
|
||||
} else { /* Abort trace. Interpreter will despecialize bytecode. */
|
||||
lj_trace_err(J, LJ_TRERR_RECERR);
|
||||
}
|
||||
}
|
||||
|
||||
/* -- Record profiler hook checks ----------------------------------------- */
|
||||
|
||||
#if LJ_HASPROFILE
|
||||
@@ -708,7 +784,7 @@ static TRef rec_call_specialize(jit_State *J, GCfunc *fn, TRef tr)
|
||||
/* NYI: io_file_iter doesn't have an ffid, yet. */
|
||||
{ /* Specialize to the ffid. */
|
||||
TRef trid = emitir(IRT(IR_FLOAD, IRT_U8), tr, IRFL_FUNC_FFID);
|
||||
emitir(IRTG(IR_EQ, IRT_INT), trid, lj_ir_kint(J, fn->c.ffid));
|
||||
emitir(IRTGI(IR_EQ), trid, lj_ir_kint(J, fn->c.ffid));
|
||||
}
|
||||
return tr;
|
||||
default:
|
||||
@@ -832,6 +908,7 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
||||
J->base -= cbase;
|
||||
J->base[--rbase] = TREF_TRUE; /* Prepend true to results. */
|
||||
frame = frame_prevd(frame);
|
||||
J->needsnap = 1; /* Stop catching on-trace errors. */
|
||||
}
|
||||
/* Return to lower frame via interpreter for unhandled cases. */
|
||||
if (J->framedepth == 0 && J->pt && bc_isret(bc_op(*J->pc)) &&
|
||||
@@ -918,6 +995,9 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
|
||||
TRef tr = gotresults ? J->base[cbase+rbase] : TREF_NIL;
|
||||
if (bslot != J->maxslot) { /* Concatenate the remainder. */
|
||||
TValue *b = J->L->base, save; /* Simulate lower frame and result. */
|
||||
/* Can't handle MM_concat + CALLT + fast func side-effects. */
|
||||
if (J->postproc != LJ_POST_NONE)
|
||||
lj_trace_err(J, LJ_TRERR_NYIRETL);
|
||||
J->base[J->maxslot] = tr;
|
||||
copyTV(J->L, &save, b-(2<<LJ_FR2));
|
||||
if (gotresults)
|
||||
@@ -1433,6 +1513,16 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix)
|
||||
return 0; /* No result yet. */
|
||||
}
|
||||
}
|
||||
#if LJ_HASBUFFER
|
||||
/* The index table of buffer objects is treated as immutable. */
|
||||
if (ix->mt == TREF_NIL && !ix->val &&
|
||||
tref_isudata(ix->tab) && udataV(&ix->tabv)->udtype == UDTYPE_BUFFER &&
|
||||
tref_istab(ix->mobj) && tref_isstr(ix->key) && tref_isk(ix->key)) {
|
||||
cTValue *val = lj_tab_getstr(tabV(&ix->mobjv), strV(&ix->keyv));
|
||||
TRef tr = lj_record_constify(J, val);
|
||||
if (tr) return tr; /* Specialize to the value, i.e. a method. */
|
||||
}
|
||||
#endif
|
||||
/* Otherwise retry lookup with metaobject. */
|
||||
ix->tab = ix->mobj;
|
||||
copyTV(J->L, &ix->tabv, &ix->mobjv);
|
||||
@@ -1543,6 +1633,47 @@ TRef lj_record_idx(jit_State *J, RecordIndex *ix)
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine result type of table traversal. */
|
||||
static IRType rec_next_types(GCtab *t, uint32_t idx)
|
||||
{
|
||||
for (; idx < t->asize; idx++) {
|
||||
cTValue *a = arrayslot(t, idx);
|
||||
if (LJ_LIKELY(!tvisnil(a)))
|
||||
return (LJ_DUALNUM ? IRT_INT : IRT_NUM) + (itype2irt(a) << 8);
|
||||
}
|
||||
idx -= t->asize;
|
||||
for (; idx <= t->hmask; idx++) {
|
||||
Node *n = &noderef(t->node)[idx];
|
||||
if (!tvisnil(&n->val))
|
||||
return itype2irt(&n->key) + (itype2irt(&n->val) << 8);
|
||||
}
|
||||
return IRT_NIL + (IRT_NIL << 8);
|
||||
}
|
||||
|
||||
/* Record a table traversal step aka next(). */
|
||||
int lj_record_next(jit_State *J, RecordIndex *ix)
|
||||
{
|
||||
IRType t, tkey, tval;
|
||||
TRef trvk;
|
||||
t = rec_next_types(tabV(&ix->tabv), ix->keyv.u32.lo);
|
||||
tkey = (t & 0xff); tval = (t >> 8);
|
||||
trvk = lj_ir_call(J, IRCALL_lj_vm_next, ix->tab, ix->key);
|
||||
if (ix->mobj || tkey == IRT_NIL) {
|
||||
TRef idx = emitir(IRTI(IR_HIOP), trvk, trvk);
|
||||
/* Always check for invalid key from next() for nil result. */
|
||||
if (!ix->mobj) emitir(IRTGI(IR_NE), idx, lj_ir_kint(J, -1));
|
||||
ix->mobj = idx;
|
||||
}
|
||||
ix->key = lj_record_vload(J, trvk, 1, tkey);
|
||||
if (tkey == IRT_NIL || ix->idxchain) { /* Omit value type check. */
|
||||
ix->val = TREF_NIL;
|
||||
return 1;
|
||||
} else { /* Need value. */
|
||||
ix->val = lj_record_vload(J, trvk, 0, tval);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void rec_tsetm(jit_State *J, BCReg ra, BCReg rn, int32_t i)
|
||||
{
|
||||
RecordIndex ix;
|
||||
@@ -1826,11 +1957,7 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults)
|
||||
vbase = emitir(IRT(IR_ADD, IRT_PGC), vbase, lj_ir_kint(J, frofs-8));
|
||||
for (i = 0; i < nload; i++) {
|
||||
IRType t = itype2irt(&J->L->base[i-1-LJ_FR2-nvararg]);
|
||||
TRef aref = emitir(IRT(IR_AREF, IRT_PGC),
|
||||
vbase, lj_ir_kint(J, (int32_t)i));
|
||||
TRef tr = emitir(IRTG(IR_VLOAD, t), aref, 0);
|
||||
if (irtype_ispri(t)) tr = TREF_PRI(t); /* Canonicalize primitives. */
|
||||
J->base[dst+i] = tr;
|
||||
J->base[dst+i] = lj_record_vload(J, vbase, i, t);
|
||||
}
|
||||
} else {
|
||||
emitir(IRTGI(IR_LE), fr, lj_ir_kint(J, frofs));
|
||||
@@ -1877,8 +2004,7 @@ static void rec_varg(jit_State *J, BCReg dst, ptrdiff_t nresults)
|
||||
lj_ir_kint(J, frofs-(8<<LJ_FR2)));
|
||||
t = itype2irt(&J->L->base[idx-2-LJ_FR2-nvararg]);
|
||||
aref = emitir(IRT(IR_AREF, IRT_PGC), vbase, tridx);
|
||||
tr = emitir(IRTG(IR_VLOAD, t), aref, 0);
|
||||
if (irtype_ispri(t)) tr = TREF_PRI(t); /* Canonicalize primitives. */
|
||||
tr = lj_record_vload(J, aref, 0, t);
|
||||
}
|
||||
J->base[dst-2-LJ_FR2] = tr;
|
||||
J->maxslot = dst-1-LJ_FR2;
|
||||
@@ -1935,9 +2061,9 @@ static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
|
||||
tr = hdr = emitir(IRT(IR_BUFHDR, IRT_PGC),
|
||||
lj_ir_kptr(J, &J2G(J)->tmpbuf), IRBUFHDR_RESET);
|
||||
do {
|
||||
tr = emitir(IRT(IR_BUFPUT, IRT_PGC), tr, *trp++);
|
||||
tr = emitir(IRTG(IR_BUFPUT, IRT_PGC), tr, *trp++);
|
||||
} while (trp <= top);
|
||||
tr = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
|
||||
tr = emitir(IRTG(IR_BUFSTR, IRT_STR), tr, hdr);
|
||||
J->maxslot = (BCReg)(xbase - J->base);
|
||||
if (xbase == base) return tr; /* Return simple concatenation result. */
|
||||
/* Pass partial result. */
|
||||
@@ -2050,7 +2176,7 @@ void lj_record_ins(jit_State *J)
|
||||
/* Need snapshot before recording next bytecode (e.g. after a store). */
|
||||
if (J->needsnap) {
|
||||
J->needsnap = 0;
|
||||
lj_snap_purge(J);
|
||||
if (J->pt) lj_snap_purge(J);
|
||||
lj_snap_add(J);
|
||||
J->mergesnap = 1;
|
||||
}
|
||||
@@ -2423,6 +2549,9 @@ void lj_record_ins(jit_State *J)
|
||||
case BC_ITERL:
|
||||
rec_loop_interp(J, pc, rec_iterl(J, *pc));
|
||||
break;
|
||||
case BC_ITERN:
|
||||
rec_loop_interp(J, pc, rec_itern(J, ra, rb));
|
||||
break;
|
||||
case BC_LOOP:
|
||||
rec_loop_interp(J, pc, rec_loop(J, ra, 1));
|
||||
break;
|
||||
@@ -2451,6 +2580,10 @@ void lj_record_ins(jit_State *J)
|
||||
J->maxslot = ra; /* Shrink used slots. */
|
||||
break;
|
||||
|
||||
case BC_ISNEXT:
|
||||
rec_isnext(J, ra);
|
||||
break;
|
||||
|
||||
/* -- Function headers -------------------------------------------------- */
|
||||
|
||||
case BC_FUNCF:
|
||||
@@ -2480,8 +2613,6 @@ void lj_record_ins(jit_State *J)
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case BC_ITERN:
|
||||
case BC_ISNEXT:
|
||||
case BC_UCLO:
|
||||
case BC_FNEW:
|
||||
setintV(&J->errinfo, (int32_t)op);
|
||||
@@ -2533,6 +2664,13 @@ static const BCIns *rec_setup_root(jit_State *J)
|
||||
lj_assertJ(bc_op(pc[-1]) == BC_JMP, "ITERL does not point to JMP+1");
|
||||
J->bc_min = pc;
|
||||
break;
|
||||
case BC_ITERN:
|
||||
lj_assertJ(bc_op(pc[1]) == BC_ITERL, "no ITERL after ITERN");
|
||||
J->maxslot = ra;
|
||||
J->bc_extent = (MSize)(-bc_j(pc[1]))*sizeof(BCIns);
|
||||
J->bc_min = pc+2 + bc_j(pc[1]);
|
||||
J->state = LJ_TRACE_RECORD_1ST; /* Record the first ITERN, too. */
|
||||
break;
|
||||
case BC_LOOP:
|
||||
/* Only check BC range for real loops, but not for "repeat until true". */
|
||||
pcj = pc + bc_j(ins);
|
||||
@@ -2629,9 +2767,14 @@ void lj_record_setup(jit_State *J)
|
||||
}
|
||||
lj_snap_replay(J, T);
|
||||
sidecheck:
|
||||
if (traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] ||
|
||||
T->snap[J->exitno].count >= J->param[JIT_P_hotexit] +
|
||||
J->param[JIT_P_tryside]) {
|
||||
if ((traceref(J, J->cur.root)->nchild >= J->param[JIT_P_maxside] ||
|
||||
T->snap[J->exitno].count >= J->param[JIT_P_hotexit] +
|
||||
J->param[JIT_P_tryside])) {
|
||||
if (bc_op(*J->pc) == BC_JLOOP) {
|
||||
BCIns startins = traceref(J, bc_d(*J->pc))->startins;
|
||||
if (bc_op(startins) == BC_ITERN)
|
||||
rec_itern(J, bc_a(startins), bc_b(startins));
|
||||
}
|
||||
lj_record_stop(J, LJ_TRLINK_INTERP, 0);
|
||||
}
|
||||
} else { /* Root trace. */
|
||||
@@ -2640,6 +2783,7 @@ void lj_record_setup(jit_State *J)
|
||||
J->pc = rec_setup_root(J);
|
||||
/* Note: the loop instruction itself is recorded at the end and not
|
||||
** at the start! So snapshot #0 needs to point to the *next* instruction.
|
||||
** The one exception is BC_ITERN, which sets LJ_TRACE_RECORD_1ST.
|
||||
*/
|
||||
lj_snap_add(J);
|
||||
if (bc_op(J->cur.startins) == BC_FORL)
|
||||
|
||||
Reference in New Issue
Block a user