Inline-Lua
view release on metacpan or search on metacpan
ffi/target/release/build/mlua-sys-6a99a2ae50f12319/out/luajit-build/build/src/lj_record.c view on Meta::CPAN
for (mm = 0; mm <= MM_FAST; mm++)
if (mmname_str(J2G(J), mm) == str)
return 0; /* MUST be one the fast metamethod names. */
} else {
return 0; /* Variable string key MAY be a metamethod name. */
}
}
return 1; /* CANNOT be a metamethod name. */
}
/* Record indexed load/store. */
TRef lj_record_idx(jit_State *J, RecordIndex *ix)
{
TRef xref;
IROp xrefop, loadop;
IRRef rbref;
IRType1 rbguard;
cTValue *oldv;
while (!tref_istab(ix->tab)) { /* Handle non-table lookup. */
/* Never call raw lj_record_idx() on non-table. */
lj_assertJ(ix->idxchain != 0, "bad usage");
if (!lj_record_mm_lookup(J, ix, ix->val ? MM_newindex : MM_index))
lj_trace_err(J, LJ_TRERR_NOMM);
handlemm:
if (tref_isfunc(ix->mobj)) { /* Handle metamethod call. */
BCReg func = rec_mm_prep(J, ix->val ? lj_cont_nop : lj_cont_ra);
TRef *base = J->base + func + LJ_FR2;
TValue *tv = J->L->base + func + LJ_FR2;
base[-LJ_FR2] = ix->mobj; base[1] = ix->tab; base[2] = ix->key;
setfuncV(J->L, tv-LJ_FR2, funcV(&ix->mobjv));
copyTV(J->L, tv+1, &ix->tabv);
copyTV(J->L, tv+2, &ix->keyv);
if (ix->val) {
base[3] = ix->val;
copyTV(J->L, tv+3, &ix->valv);
lj_record_call(J, func, 3); /* mobj(tab, key, val) */
return 0;
} else {
lj_record_call(J, func, 2); /* res = mobj(tab, key) */
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);
if (--ix->idxchain == 0)
lj_trace_err(J, LJ_TRERR_IDXLOOP);
}
/* First catch nil and NaN keys for tables. */
if (tvisnil(&ix->keyv) || (tvisnum(&ix->keyv) && tvisnan(&ix->keyv))) {
if (ix->val) /* Better fail early. */
lj_trace_err(J, LJ_TRERR_STORENN);
if (tref_isk(ix->key)) {
if (ix->idxchain && lj_record_mm_lookup(J, ix, MM_index))
goto handlemm;
return TREF_NIL;
}
}
/* Record the key lookup. */
xref = rec_idx_key(J, ix, &rbref, &rbguard);
xrefop = IR(tref_ref(xref))->o;
loadop = xrefop == IR_AREF ? IR_ALOAD : IR_HLOAD;
/* The lj_meta_tset() inconsistency is gone, but better play safe. */
oldv = xrefop == IR_KKPTR ? (cTValue *)ir_kptr(IR(tref_ref(xref))) : ix->oldv;
if (ix->val == 0) { /* Indexed load */
IRType t = itype2irt(oldv);
TRef res;
if (oldv == niltvg(J2G(J))) {
emitir(IRTG(IR_EQ, IRT_PGC), xref, lj_ir_kkptr(J, niltvg(J2G(J))));
res = TREF_NIL;
} else {
res = emitir(IRTG(loadop, t), xref, 0);
}
if (tref_ref(res) < rbref) { /* HREFK + load forwarded? */
lj_ir_rollback(J, rbref); /* Rollback to eliminate hmask guard. */
J->guardemit = rbguard;
}
if (t == IRT_NIL && ix->idxchain && lj_record_mm_lookup(J, ix, MM_index))
goto handlemm;
if (irtype_ispri(t)) res = TREF_PRI(t); /* Canonicalize primitives. */
return res;
} else { /* Indexed store. */
GCtab *mt = tabref(tabV(&ix->tabv)->metatable);
int keybarrier = tref_isgcv(ix->key) && !tref_isnil(ix->val);
if (tref_ref(xref) < rbref) { /* HREFK forwarded? */
lj_ir_rollback(J, rbref); /* Rollback to eliminate hmask guard. */
J->guardemit = rbguard;
}
if (tvisnil(oldv)) { /* Previous value was nil? */
/* Need to duplicate the hasmm check for the early guards. */
int hasmm = 0;
if (ix->idxchain && mt) {
cTValue *mo = lj_tab_getstr(mt, mmname_str(J2G(J), MM_newindex));
hasmm = mo && !tvisnil(mo);
}
if (hasmm)
emitir(IRTG(loadop, IRT_NIL), xref, 0); /* Guard for nil value. */
else if (xrefop == IR_HREF)
emitir(IRTG(oldv == niltvg(J2G(J)) ? IR_EQ : IR_NE, IRT_PGC),
xref, lj_ir_kkptr(J, niltvg(J2G(J))));
if (ix->idxchain && lj_record_mm_lookup(J, ix, MM_newindex)) {
lj_assertJ(hasmm, "inconsistent metamethod handling");
goto handlemm;
}
lj_assertJ(!hasmm, "inconsistent metamethod handling");
if (oldv == niltvg(J2G(J))) { /* Need to insert a new key. */
TRef key = ix->key;
if (tref_isinteger(key)) { /* NEWREF needs a TValue as a key. */
key = emitir(IRTN(IR_CONV), key, IRCONV_NUM_INT);
} else if (tref_isnum(key)) {
if (tref_isk(key)) {
if (tvismzero(&ix->keyv))
key = lj_ir_knum_zero(J); /* Canonicalize -0.0 to +0.0. */
} else {
emitir(IRTG(IR_EQ, IRT_NUM), key, key); /* Check for !NaN. */
}
}
xref = emitir(IRT(IR_NEWREF, IRT_PGC), ix->tab, key);
keybarrier = 0; /* NEWREF already takes care of the key barrier. */
#ifdef LUAJIT_ENABLE_TABLE_BUMP
if ((J->flags & JIT_F_OPT_SINK)) /* Avoid a separate flag. */
rec_idx_bump(J, ix);
#endif
}
} else if (!lj_opt_fwd_wasnonnil(J, loadop, tref_ref(xref))) {
/* Cannot derive that the previous value was non-nil, must do checks. */
if (xrefop == IR_HREF) /* Guard against store to niltv. */
emitir(IRTG(IR_NE, IRT_PGC), xref, lj_ir_kkptr(J, niltvg(J2G(J))));
if (ix->idxchain) { /* Metamethod lookup required? */
/* A check for NULL metatable is cheaper (hoistable) than a load. */
if (!mt) {
TRef mtref = emitir(IRT(IR_FLOAD, IRT_TAB), ix->tab, IRFL_TAB_META);
emitir(IRTG(IR_EQ, IRT_TAB), mtref, lj_ir_knull(J, IRT_TAB));
} else {
IRType t = itype2irt(oldv);
emitir(IRTG(loadop, t), xref, 0); /* Guard for non-nil value. */
}
}
} else {
keybarrier = 0; /* Previous non-nil value kept the key alive. */
}
/* Convert int to number before storing. */
if (!LJ_DUALNUM && tref_isinteger(ix->val))
ix->val = emitir(IRTN(IR_CONV), ix->val, IRCONV_NUM_INT);
emitir(IRT(loadop+IRDELTA_L2S, tref_type(ix->val)), xref, ix->val);
if (keybarrier || tref_isgcv(ix->val))
emitir(IRT(IR_TBAR, IRT_NIL), ix->tab, 0);
/* Invalidate neg. metamethod cache for stores with certain string keys. */
if (!nommstr(J, ix->key)) {
TRef fref = emitir(IRT(IR_FREF, IRT_PGC), ix->tab, IRFL_TAB_NOMM);
emitir(IRT(IR_FSTORE, IRT_U8), fref, lj_ir_kint(J, 0));
}
J->needsnap = 1;
return 0;
}
}
/* 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(). */
( run in 2.861 seconds using v1.01-cache-2.11-cpan-98e64b0badf )