Improve assertions.

This commit is contained in:
Mike Pall
2020-06-13 00:52:54 +02:00
parent 8b55054473
commit 8ae5170cdc
71 changed files with 1363 additions and 927 deletions

View File

@@ -163,6 +163,12 @@ LJ_STATIC_ASSERT((int)BC_MULVV-(int)BC_ADDVV == (int)OPR_MUL-(int)OPR_ADD);
LJ_STATIC_ASSERT((int)BC_DIVVV-(int)BC_ADDVV == (int)OPR_DIV-(int)OPR_ADD);
LJ_STATIC_ASSERT((int)BC_MODVV-(int)BC_ADDVV == (int)OPR_MOD-(int)OPR_ADD);
#ifdef LUA_USE_ASSERT
#define lj_assertFS(c, ...) (lj_assertG_(G(fs->L), (c), __VA_ARGS__))
#else
#define lj_assertFS(c, ...) ((void)fs)
#endif
/* -- Error handling ------------------------------------------------------ */
LJ_NORET LJ_NOINLINE static void err_syntax(LexState *ls, ErrMsg em)
@@ -200,7 +206,7 @@ static BCReg const_num(FuncState *fs, ExpDesc *e)
{
lua_State *L = fs->L;
TValue *o;
lua_assert(expr_isnumk(e));
lj_assertFS(expr_isnumk(e), "bad usage");
o = lj_tab_set(L, fs->kt, &e->u.nval);
if (tvhaskslot(o))
return tvkslot(o);
@@ -225,7 +231,7 @@ static BCReg const_gc(FuncState *fs, GCobj *gc, uint32_t itype)
/* Add a string constant. */
static BCReg const_str(FuncState *fs, ExpDesc *e)
{
lua_assert(expr_isstrk(e) || e->k == VGLOBAL);
lj_assertFS(expr_isstrk(e) || e->k == VGLOBAL, "bad usage");
return const_gc(fs, obj2gco(e->u.sval), LJ_TSTR);
}
@@ -313,7 +319,7 @@ static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest)
{
BCIns *jmp = &fs->bcbase[pc].ins;
BCPos offset = dest-(pc+1)+BCBIAS_J;
lua_assert(dest != NO_JMP);
lj_assertFS(dest != NO_JMP, "uninitialized jump target");
if (offset > BCMAX_D)
err_syntax(fs->ls, LJ_ERR_XJUMP);
setbc_d(jmp, offset);
@@ -362,7 +368,7 @@ static void jmp_patch(FuncState *fs, BCPos list, BCPos target)
if (target == fs->pc) {
jmp_tohere(fs, list);
} else {
lua_assert(target < fs->pc);
lj_assertFS(target < fs->pc, "bad jump target");
jmp_patchval(fs, list, target, NO_REG, target);
}
}
@@ -392,7 +398,7 @@ static void bcreg_free(FuncState *fs, BCReg reg)
{
if (reg >= fs->nactvar) {
fs->freereg--;
lua_assert(reg == fs->freereg);
lj_assertFS(reg == fs->freereg, "bad regfree");
}
}
@@ -542,7 +548,7 @@ static void expr_toreg_nobranch(FuncState *fs, ExpDesc *e, BCReg reg)
} else if (e->k <= VKTRUE) {
ins = BCINS_AD(BC_KPRI, reg, const_pri(e));
} else {
lua_assert(e->k == VVOID || e->k == VJMP);
lj_assertFS(e->k == VVOID || e->k == VJMP, "bad expr type %d", e->k);
return;
}
bcemit_INS(fs, ins);
@@ -637,7 +643,7 @@ static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
ins = BCINS_AD(BC_GSET, ra, const_str(fs, var));
} else {
BCReg ra, rc;
lua_assert(var->k == VINDEXED);
lj_assertFS(var->k == VINDEXED, "bad expr type %d", var->k);
ra = expr_toanyreg(fs, e);
rc = var->u.s.aux;
if ((int32_t)rc < 0) {
@@ -645,10 +651,12 @@ static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
} else if (rc > BCMAX_C) {
ins = BCINS_ABC(BC_TSETB, ra, var->u.s.info, rc-(BCMAX_C+1));
} else {
#ifdef LUA_USE_ASSERT
/* Free late alloced key reg to avoid assert on free of value reg. */
/* This can only happen when called from expr_table(). */
lua_assert(e->k != VNONRELOC || ra < fs->nactvar ||
rc < ra || (bcreg_free(fs, rc),1));
if (e->k == VNONRELOC && ra >= fs->nactvar && rc >= ra)
bcreg_free(fs, rc);
#endif
ins = BCINS_ABC(BC_TSETV, ra, var->u.s.info, rc);
}
}
@@ -663,7 +671,7 @@ static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key)
expr_free(fs, e);
func = fs->freereg;
bcemit_AD(fs, BC_MOV, func+1+LJ_FR2, obj); /* Copy object to 1st argument. */
lua_assert(expr_isstrk(key));
lj_assertFS(expr_isstrk(key), "bad usage");
idx = const_str(fs, key);
if (idx <= BCMAX_C) {
bcreg_reserve(fs, 2+LJ_FR2);
@@ -803,7 +811,8 @@ static void bcemit_arith(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2)
else
rc = expr_toanyreg(fs, e2);
/* 1st operand discharged by bcemit_binop_left, but need KNUM/KSHORT. */
lua_assert(expr_isnumk(e1) || e1->k == VNONRELOC);
lj_assertFS(expr_isnumk(e1) || e1->k == VNONRELOC,
"bad expr type %d", e1->k);
expr_toval(fs, e1);
/* Avoid two consts to satisfy bytecode constraints. */
if (expr_isnumk(e1) && !expr_isnumk(e2) &&
@@ -891,19 +900,20 @@ static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2)
if (op <= OPR_POW) {
bcemit_arith(fs, op, e1, e2);
} else if (op == OPR_AND) {
lua_assert(e1->t == NO_JMP); /* List must be closed. */
lj_assertFS(e1->t == NO_JMP, "jump list not closed");
expr_discharge(fs, e2);
jmp_append(fs, &e2->f, e1->f);
*e1 = *e2;
} else if (op == OPR_OR) {
lua_assert(e1->f == NO_JMP); /* List must be closed. */
lj_assertFS(e1->f == NO_JMP, "jump list not closed");
expr_discharge(fs, e2);
jmp_append(fs, &e2->t, e1->t);
*e1 = *e2;
} else if (op == OPR_CONCAT) {
expr_toval(fs, e2);
if (e2->k == VRELOCABLE && bc_op(*bcptr(fs, e2)) == BC_CAT) {
lua_assert(e1->u.s.info == bc_b(*bcptr(fs, e2))-1);
lj_assertFS(e1->u.s.info == bc_b(*bcptr(fs, e2))-1,
"bad CAT stack layout");
expr_free(fs, e1);
setbc_b(bcptr(fs, e2), e1->u.s.info);
e1->u.s.info = e2->u.s.info;
@@ -915,8 +925,9 @@ static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2)
}
e1->k = VRELOCABLE;
} else {
lua_assert(op == OPR_NE || op == OPR_EQ ||
op == OPR_LT || op == OPR_GE || op == OPR_LE || op == OPR_GT);
lj_assertFS(op == OPR_NE || op == OPR_EQ ||
op == OPR_LT || op == OPR_GE || op == OPR_LE || op == OPR_GT,
"bad binop %d", op);
bcemit_comp(fs, op, e1, e2);
}
}
@@ -945,10 +956,10 @@ static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e)
e->u.s.info = fs->freereg-1;
e->k = VNONRELOC;
} else {
lua_assert(e->k == VNONRELOC);
lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k);
}
} else {
lua_assert(op == BC_UNM || op == BC_LEN);
lj_assertFS(op == BC_UNM || op == BC_LEN, "bad unop %d", op);
if (op == BC_UNM && !expr_hasjump(e)) { /* Constant-fold negations. */
#if LJ_HASFFI
if (e->k == VKCDATA) { /* Fold in-place since cdata is not interned. */
@@ -1043,8 +1054,9 @@ static void var_new(LexState *ls, BCReg n, GCstr *name)
lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK);
lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo);
}
lua_assert((uintptr_t)name < VARNAME__MAX ||
lj_tab_getstr(fs->kt, name) != NULL);
lj_assertFS((uintptr_t)name < VARNAME__MAX ||
lj_tab_getstr(fs->kt, name) != NULL,
"unanchored variable name");
/* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */
setgcref(ls->vstack[vtop].name, obj2gco(name));
fs->varmap[fs->nactvar+n] = (uint16_t)vtop;
@@ -1099,7 +1111,7 @@ static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e)
return i; /* Already exists. */
/* Otherwise create a new one. */
checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues");
lua_assert(e->k == VLOCAL || e->k == VUPVAL);
lj_assertFS(e->k == VLOCAL || e->k == VUPVAL, "bad expr type %d", e->k);
fs->uvmap[n] = (uint16_t)vidx;
fs->uvtmp[n] = (uint16_t)(e->k == VLOCAL ? vidx : LJ_MAX_VSTACK+e->u.s.info);
fs->nuv = n+1;
@@ -1150,7 +1162,8 @@ static MSize gola_new(LexState *ls, GCstr *name, uint8_t info, BCPos pc)
lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK);
lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo);
}
lua_assert(name == NAME_BREAK || lj_tab_getstr(fs->kt, name) != NULL);
lj_assertFS(name == NAME_BREAK || lj_tab_getstr(fs->kt, name) != NULL,
"unanchored label name");
/* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */
setgcref(ls->vstack[vtop].name, obj2gco(name));
ls->vstack[vtop].startpc = pc;
@@ -1180,8 +1193,9 @@ static void gola_close(LexState *ls, VarInfo *vg)
FuncState *fs = ls->fs;
BCPos pc = vg->startpc;
BCIns *ip = &fs->bcbase[pc].ins;
lua_assert(gola_isgoto(vg));
lua_assert(bc_op(*ip) == BC_JMP || bc_op(*ip) == BC_UCLO);
lj_assertFS(gola_isgoto(vg), "expected goto");
lj_assertFS(bc_op(*ip) == BC_JMP || bc_op(*ip) == BC_UCLO,
"bad bytecode op %d", bc_op(*ip));
setbc_a(ip, vg->slot);
if (bc_op(*ip) == BC_JMP) {
BCPos next = jmp_next(fs, pc);
@@ -1200,9 +1214,9 @@ static void gola_resolve(LexState *ls, FuncScope *bl, MSize idx)
if (gcrefeq(vg->name, vl->name) && gola_isgoto(vg)) {
if (vg->slot < vl->slot) {
GCstr *name = strref(var_get(ls, ls->fs, vg->slot).name);
lua_assert((uintptr_t)name >= VARNAME__MAX);
lj_assertLS((uintptr_t)name >= VARNAME__MAX, "expected goto name");
ls->linenumber = ls->fs->bcbase[vg->startpc].line;
lua_assert(strref(vg->name) != NAME_BREAK);
lj_assertLS(strref(vg->name) != NAME_BREAK, "unexpected break");
lj_lex_error(ls, 0, LJ_ERR_XGSCOPE,
strdata(strref(vg->name)), strdata(name));
}
@@ -1266,7 +1280,7 @@ static void fscope_begin(FuncState *fs, FuncScope *bl, int flags)
bl->vstart = fs->ls->vtop;
bl->prev = fs->bl;
fs->bl = bl;
lua_assert(fs->freereg == fs->nactvar);
lj_assertFS(fs->freereg == fs->nactvar, "bad regalloc");
}
/* End a scope. */
@@ -1277,7 +1291,7 @@ static void fscope_end(FuncState *fs)
fs->bl = bl->prev;
var_remove(ls, bl->nactvar);
fs->freereg = fs->nactvar;
lua_assert(bl->nactvar == fs->nactvar);
lj_assertFS(bl->nactvar == fs->nactvar, "bad regalloc");
if ((bl->flags & (FSCOPE_UPVAL|FSCOPE_NOCLOSE)) == FSCOPE_UPVAL)
bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0);
if ((bl->flags & FSCOPE_BREAK)) {
@@ -1364,13 +1378,13 @@ static void fs_fixup_k(FuncState *fs, GCproto *pt, void *kptr)
Node *n = &node[i];
if (tvhaskslot(&n->val)) {
ptrdiff_t kidx = (ptrdiff_t)tvkslot(&n->val);
lua_assert(!tvisint(&n->key));
lj_assertFS(!tvisint(&n->key), "unexpected integer key");
if (tvisnum(&n->key)) {
TValue *tv = &((TValue *)kptr)[kidx];
if (LJ_DUALNUM) {
lua_Number nn = numV(&n->key);
int32_t k = lj_num2int(nn);
lua_assert(!tvismzero(&n->key));
lj_assertFS(!tvismzero(&n->key), "unexpected -0 key");
if ((lua_Number)k == nn)
setintV(tv, k);
else
@@ -1418,21 +1432,21 @@ static void fs_fixup_line(FuncState *fs, GCproto *pt,
uint8_t *li = (uint8_t *)lineinfo;
do {
BCLine delta = base[i].line - first;
lua_assert(delta >= 0 && delta < 256);
lj_assertFS(delta >= 0 && delta < 256, "bad line delta");
li[i] = (uint8_t)delta;
} while (++i < n);
} else if (LJ_LIKELY(numline < 65536)) {
uint16_t *li = (uint16_t *)lineinfo;
do {
BCLine delta = base[i].line - first;
lua_assert(delta >= 0 && delta < 65536);
lj_assertFS(delta >= 0 && delta < 65536, "bad line delta");
li[i] = (uint16_t)delta;
} while (++i < n);
} else {
uint32_t *li = (uint32_t *)lineinfo;
do {
BCLine delta = base[i].line - first;
lua_assert(delta >= 0);
lj_assertFS(delta >= 0, "bad line delta");
li[i] = (uint32_t)delta;
} while (++i < n);
}
@@ -1522,7 +1536,7 @@ static void fs_fixup_ret(FuncState *fs)
}
fs->bl->flags |= FSCOPE_NOCLOSE; /* Handled above. */
fscope_end(fs);
lua_assert(fs->bl == NULL);
lj_assertFS(fs->bl == NULL, "bad scope nesting");
/* May need to fixup returns encoded before first function was created. */
if (fs->flags & PROTO_FIXUP_RETURN) {
BCPos pc;
@@ -1594,7 +1608,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line)
L->top--; /* Pop table of constants. */
ls->vtop = fs->vbase; /* Reset variable stack. */
ls->fs = fs->prev;
lua_assert(ls->fs != NULL || ls->tok == TK_eof);
lj_assertL(ls->fs != NULL || ls->tok == TK_eof, "bad parser state");
return pt;
}
@@ -1688,14 +1702,15 @@ static void expr_bracket(LexState *ls, ExpDesc *v)
}
/* Get value of constant expression. */
static void expr_kvalue(TValue *v, ExpDesc *e)
static void expr_kvalue(FuncState *fs, TValue *v, ExpDesc *e)
{
UNUSED(fs);
if (e->k <= VKTRUE) {
setpriV(v, ~(uint32_t)e->k);
} else if (e->k == VKSTR) {
setgcVraw(v, obj2gco(e->u.sval), LJ_TSTR);
} else {
lua_assert(tvisnumber(expr_numtv(e)));
lj_assertFS(tvisnumber(expr_numtv(e)), "bad number constant");
*v = *expr_numtv(e);
}
}
@@ -1745,11 +1760,11 @@ static void expr_table(LexState *ls, ExpDesc *e)
fs->bcbase[pc].ins = BCINS_AD(BC_TDUP, freg-1, kidx);
}
vcall = 0;
expr_kvalue(&k, &key);
expr_kvalue(fs, &k, &key);
v = lj_tab_set(fs->L, t, &k);
lj_gc_anybarriert(fs->L, t);
if (expr_isk_nojump(&val)) { /* Add const key/value to template table. */
expr_kvalue(v, &val);
expr_kvalue(fs, v, &val);
} else { /* Otherwise create dummy string key (avoids lj_tab_newkey). */
settabV(fs->L, v, t); /* Preserve key with table itself as value. */
fixt = 1; /* Fix this later, after all resizes. */
@@ -1768,8 +1783,9 @@ static void expr_table(LexState *ls, ExpDesc *e)
if (vcall) {
BCInsLine *ilp = &fs->bcbase[fs->pc-1];
ExpDesc en;
lua_assert(bc_a(ilp->ins) == freg &&
bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB));
lj_assertFS(bc_a(ilp->ins) == freg &&
bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB),
"bad CALL code generation");
expr_init(&en, VKNUM, 0);
en.u.nval.u32.lo = narr-1;
en.u.nval.u32.hi = 0x43300000; /* Biased integer to avoid denormals. */
@@ -1799,7 +1815,7 @@ static void expr_table(LexState *ls, ExpDesc *e)
for (i = 0; i <= hmask; i++) {
Node *n = &node[i];
if (tvistab(&n->val)) {
lua_assert(tabV(&n->val) == t);
lj_assertFS(tabV(&n->val) == t, "bad dummy key in template table");
setnilV(&n->val); /* Turn value into nil. */
}
}
@@ -1830,7 +1846,7 @@ static BCReg parse_params(LexState *ls, int needself)
} while (lex_opt(ls, ','));
}
var_add(ls, nparams);
lua_assert(fs->nactvar == nparams);
lj_assertFS(fs->nactvar == nparams, "bad regalloc");
bcreg_reserve(fs, nparams);
lex_check(ls, ')');
return nparams;
@@ -1917,7 +1933,7 @@ static void parse_args(LexState *ls, ExpDesc *e)
err_syntax(ls, LJ_ERR_XFUNARG);
return; /* Silence compiler. */
}
lua_assert(e->k == VNONRELOC);
lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k);
base = e->u.s.info; /* Base register for call. */
if (args.k == VCALL) {
ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1 - LJ_FR2);
@@ -2687,8 +2703,9 @@ static void parse_chunk(LexState *ls)
while (!islast && !parse_isend(ls->tok)) {
islast = parse_stmt(ls);
lex_opt(ls, ';');
lua_assert(ls->fs->framesize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
lj_assertLS(ls->fs->framesize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar,
"bad regalloc");
ls->fs->freereg = ls->fs->nactvar; /* Free registers after each stmt. */
}
synlevel_end(ls);
@@ -2723,9 +2740,8 @@ GCproto *lj_parse(LexState *ls)
err_token(ls, TK_eof);
pt = fs_finish(ls, ls->linenumber);
L->top--; /* Drop chunkname. */
lua_assert(fs.prev == NULL);
lua_assert(ls->fs == NULL);
lua_assert(pt->sizeuv == 0);
lj_assertL(fs.prev == NULL && ls->fs == NULL, "mismatched frame nesting");
lj_assertL(pt->sizeuv == 0, "toplevel proto has upvalues");
return pt;
}