} else if (rd->data == 0 && tvistab(tv) && tref_isstr(J->base[1])) {
/* Specialize to result of __index lookup. */
cTValue *o = lj_tab_get(J->L, tabV(tv), &rd->argv[1]);
- IRType t = itype2irt(o);
- if (tvisgcv(o))
- J->base[0] = lj_ir_kgc(J, gcV(o), t);
- else if (tvisint(o))
- J->base[0] = lj_ir_kint(J, intV(o));
- else if (tvisnum(o))
- J->base[0] = lj_ir_knumint(J, numV(o));
- else if (tvisbool(o))
- J->base[0] = TREF_PRI(t);
- else
+ J->base[0] = lj_record_constify(J, o);
+ if (!J->base[0])
lj_trace_err(J, LJ_TRERR_BADTYPE);
/* Always specialize to the key. */
emitir(IRTG(IR_EQ, IRT_STR), J->base[1], lj_ir_kstr(J, strV(&rd->argv[1])));
VKLAST = VKNUM,
VKCDATA, /* nval = cdata value, not treated as a constant expression */
/* Non-constant expressions follow: */
- VLOCAL, /* info = local register */
- VUPVAL, /* info = upvalue index */
+ VLOCAL, /* info = local register, aux = vstack index */
+ VUPVAL, /* info = upvalue index, aux = vstack index */
VGLOBAL, /* sval = string value */
VINDEXED, /* info = table register, aux = index reg/byte/string const */
VJMP, /* info = instruction PC */
typedef uint16_t VarIndex;
#define LJ_MAX_VSTACK 65536
+#define VSTACK_VAR_RW 0x80000000 /* In endpc: R/W variable. */
+
/* Upvalue map. */
typedef struct UVMap {
VarIndex vidx; /* Varinfo index. */
{
BCIns ins;
if (var->k == VLOCAL) {
+ fs->ls->vstack[var->u.s.aux].endpc |= VSTACK_VAR_RW;
expr_free(fs, e);
expr_toreg(fs, e, var->u.s.info);
return;
} else if (var->k == VUPVAL) {
+ fs->ls->vstack[var->u.s.aux].endpc |= VSTACK_VAR_RW;
expr_toval(fs, e);
if (e->k <= VKTRUE)
ins = BCINS_AD(BC_USETP, var->u.s.info, const_pri(e));
{
FuncState *fs = ls->fs;
fs->nactvar = (uint8_t)(fs->nactvar + nvars);
- for (; nvars; nvars--)
- var_get(ls, fs, fs->nactvar - nvars).startpc = fs->pc;
+ for (; nvars; nvars--) {
+ VarInfo *v = &var_get(ls, fs, fs->nactvar - nvars);
+ v->startpc = fs->pc;
+ v->endpc = 0;
+ }
}
/* Remove local variables. */
{
FuncState *fs = ls->fs;
while (fs->nactvar > tolevel)
- var_get(ls, fs, --fs->nactvar).endpc = fs->pc;
+ var_get(ls, fs, --fs->nactvar).endpc |= fs->pc;
}
/* Lookup local variable name. */
checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues");
lua_assert(e->k == VLOCAL || e->k == VUPVAL);
fs->uvloc[n].vidx = (uint16_t)vidx;
- fs->uvloc[n].slot = (uint16_t)(e->u.s.info | (e->k == VLOCAL ? 0x8000 : 0));
+ fs->uvloc[n].slot = (uint16_t)(e->u.s.info |
+ (e->k == VLOCAL ? PROTO_UV_LOCAL : 0));
fs->nuv = n+1;
return n;
}
expr_init(e, VLOCAL, reg);
if (!first)
scope_uvmark(fs, reg); /* Scope now has an upvalue. */
- return (MSize)fs->varmap[reg];
+ return (MSize)(e->u.s.aux = (uint32_t)fs->varmap[reg]);
} else {
MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */
if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */
/* Fixup upvalues for prototype. */
static void fs_fixup_uv(FuncState *fs, GCproto *pt, uint16_t *uv)
{
+ VarInfo *vstack;
+ UVMap *uvloc;
MSize i, n = fs->nuv;
setmref(pt->uv, uv);
pt->sizeuv = n;
- for (i = 0; i < n; i++)
- uv[i] = fs->uvloc[i].slot;
+ vstack = fs->ls->vstack;
+ uvloc = fs->uvloc;
+ for (i = 0; i < n; i++) {
+ uint16_t slot = uvloc[i].slot;
+ uint16_t vidx = uvloc[i].vidx;
+ if ((slot & PROTO_UV_LOCAL) && !(vstack[vidx].endpc & VSTACK_VAR_RW))
+ slot |= PROTO_UV_IMMUTABLE;
+ uv[i] = slot;
+ }
}
#ifndef LUAJIT_DISABLE_DEBUGINFO
/* Store local variable names and compressed ranges. */
for (i = 0, n = ls->vtop - fs->vbase; i < n; i++) {
GCstr *s = strref(vstack[i].name);
- BCPos startpc = vstack[i].startpc, endpc = vstack[i].endpc;
+ BCPos startpc = vstack[i].startpc;
+ BCPos endpc = vstack[i].endpc & ~VSTACK_VAR_RW;
if ((uintptr_t)s < VARNAME__MAX) {
fs_buf_need(ls, 1 + 2*5);
ls->sb.buf[ls->sb.n++] = (uint8_t)(uintptr_t)s;
FuncState *fs = ls->fs;
var_new(ls, 0, lex_str(ls));
expr_init(&v, VLOCAL, fs->freereg);
+ v.u.s.aux = fs->varmap[fs->freereg];
bcreg_reserve(fs, 1);
var_add(ls, 1);
parse_body(ls, &b, 0, ls->linenumber);
return diff;
}
+/* Constify a value. Returns 0 for non-representable object types. */
+TRef lj_record_constify(jit_State *J, cTValue *o)
+{
+ if (tvisgcv(o))
+ return lj_ir_kgc(J, gcV(o), itype2irt(o));
+ else if (tvisint(o))
+ return lj_ir_kint(J, intV(o));
+ else if (tvisnum(o))
+ return lj_ir_knumint(J, numV(o));
+ else if (tvisbool(o))
+ return TREF_PRI(itype2irt(o));
+ else
+ return 0; /* Can't represent lightuserdata (pointless). */
+}
+
/* -- Record loop ops ----------------------------------------------------- */
/* Loop event. */
TRef kfunc;
if (isluafunc(fn)) {
GCproto *pt = funcproto(fn);
- /* 3 or more closures created? Probably not a monomorphic function. */
- if (pt->flags >= 3*PROTO_CLCOUNT) { /* Specialize to prototype instead. */
+ /* Too many closures created? Probably not a monomorphic function. */
+ if (pt->flags >= PROTO_CLC_POLY) { /* Specialize to prototype instead. */
TRef trpt = emitir(IRT(IR_FLOAD, IRT_P32), tr, IRFL_FUNC_PC);
emitir(IRTG(IR_EQ, IRT_P32), trpt, lj_ir_kptr(J, proto_bc(pt)));
(void)lj_ir_kgc(J, obj2gco(pt), IRT_PROTO); /* Prevent GC of proto. */
TRef fn = getcurrf(J);
IRRef uref;
int needbarrier = 0;
+ if (uvp->immutable) { /* Try to constify immutable upvalue. */
+ TRef tr, kfunc;
+ lua_assert(val == 0);
+ if (!tref_isk(fn)) { /* Late specialization of current function. */
+ if (J->pt->flags >= PROTO_CLC_POLY)
+ goto noconstify;
+ kfunc = lj_ir_kfunc(J, J->fn);
+ emitir(IRTG(IR_EQ, IRT_FUNC), fn, kfunc);
+ J->base[-1] = TREF_FRAME | kfunc;
+ fn = kfunc;
+ }
+ tr = lj_record_constify(J, uvval(uvp));
+ if (tr)
+ return tr;
+ }
+noconstify:
/* Note: this effectively limits LJ_MAX_UPVAL to 127. */
uv = (uv << 8) | (hashrot(uvp->dhash, uvp->dhash + HASH_BIAS) & 0xff);
if (!uvp->closed) {