diff --git a/src/lj_lex.c b/src/lj_lex.c index 6cb785b5..95adb212 100644 --- a/src/lj_lex.c +++ b/src/lj_lex.c @@ -311,6 +311,8 @@ void lj_lex_setup(lua_State *L, LexState *ls) ls->vstack = NULL; ls->sizevstack = 0; ls->vtop = 0; + ls->bcstack = NULL; + ls->sizebcstack = 0; ls->lookahead = TK_eof; /* No look-ahead token. */ ls->linenumber = 1; ls->lastline = 1; @@ -339,6 +341,7 @@ void lj_lex_setup(lua_State *L, LexState *ls) void lj_lex_cleanup(lua_State *L, LexState *ls) { global_State *g = G(L); + lj_mem_freevec(g, ls->bcstack, ls->sizebcstack, BCInsLine); lj_mem_freevec(g, ls->vstack, ls->sizevstack, VarInfo); lj_str_freebuf(g, &ls->sb); } diff --git a/src/lj_lex.h b/src/lj_lex.h index ee183b40..9bcd3cdb 100644 --- a/src/lj_lex.h +++ b/src/lj_lex.h @@ -32,6 +32,12 @@ TKDEF(TKENUM1, TKENUM2) typedef int LexToken; +/* Combined bytecode ins/line. Only used during bytecode generation. */ +typedef struct BCInsLine { + BCIns ins; /* Bytecode instruction. */ + BCLine line; /* Line number for this bytecode. */ +} BCInsLine; + /* Lua lexer state. */ typedef struct LexState { struct FuncState *fs; /* Current FuncState. Defined in lj_parse.c. */ @@ -53,6 +59,8 @@ typedef struct LexState { VarInfo *vstack; /* Stack for names and extents of local variables. */ MSize sizevstack; /* Size of variable stack. */ MSize vtop; /* Top of variable stack. */ + BCInsLine *bcstack; /* Stack for bytecode instructions/line numbers. */ + MSize sizebcstack; /* Size of bytecode stack. */ uint32_t level; /* Syntactical nesting level. */ } LexState; diff --git a/src/lj_parse.c b/src/lj_parse.c index c1fc5dd6..54ff6974 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c @@ -110,11 +110,14 @@ typedef struct FuncState { BCPos lasttarget; /* Bytecode position of last jump target. */ BCPos jpc; /* Pending jump list to next bytecode. */ BCReg freereg; /* First free register. */ + BCReg nactvar; /* Number of active local variables. */ BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */ BCLine linedefined; /* First line of the function definition. */ + BCInsLine *bcbase; /* Base of bytecode stack. */ + BCPos bclim; /* Limit of bytecode stack. */ MSize vbase; /* Base of variable stack for this function. */ - uint8_t nactvar; /* Number of active local variables. */ uint8_t flags; /* Prototype flags. */ + uint8_t numparams; /* Number of active local variables. */ uint8_t framesize; /* Fixed frame size. */ uint8_t nuv; /* Number of upvalues */ VarIndex varmap[LJ_MAX_LOCVAR]; /* Map from register to variable idx. */ @@ -217,7 +220,7 @@ GCstr *lj_parse_keepstr(LexState *ls, const char *str, size_t len) /* Get next element in jump list. */ static BCPos jmp_next(FuncState *fs, BCPos pc) { - ptrdiff_t delta = bc_j(proto_ins(fs->pt, pc)); + ptrdiff_t delta = bc_j(fs->bcbase[pc].ins); if ((BCPos)delta == NO_JMP) return NO_JMP; else @@ -228,7 +231,7 @@ static BCPos jmp_next(FuncState *fs, BCPos pc) static int jmp_novalue(FuncState *fs, BCPos list) { for (; list != NO_JMP; list = jmp_next(fs, list)) { - BCOp op = bc_op(proto_ins(fs->pt, list >= 1 ? list-1 : list)); + BCOp op = bc_op(fs->bcbase[list >= 1 ? list-1 : list].ins); if (!(op == BC_ISTC || op == BC_ISFC)) return 1; } return 0; @@ -237,15 +240,15 @@ static int jmp_novalue(FuncState *fs, BCPos list) /* Patch register of test instructions. */ static int jmp_patchtestreg(FuncState *fs, BCPos pc, BCReg reg) { - BCIns *i = proto_insptr(fs->pt, pc >= 1 ? pc-1 : pc); - BCOp op = bc_op(*i); + BCIns *ip = &fs->bcbase[pc >= 1 ? pc-1 : pc].ins; + BCOp op = bc_op(*ip); if (!(op == BC_ISTC || op == BC_ISFC)) return 0; /* Cannot patch other instructions. */ - if (reg != NO_REG && reg != bc_d(*i)) { - setbc_a(i, reg); + if (reg != NO_REG && reg != bc_d(*ip)) { + setbc_a(ip, reg); } else { /* Nothing to store or already in the right register. */ - setbc_op(i, op+(BC_IST-BC_ISTC)); - setbc_a(i, 0); + setbc_op(ip, op+(BC_IST-BC_ISTC)); + setbc_a(ip, 0); } return 1; } @@ -260,7 +263,7 @@ static void jmp_dropval(FuncState *fs, BCPos list) /* Patch jump instruction to target. */ static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest) { - BCIns *jmp = proto_insptr(fs->pt, pc); + BCIns *jmp = &fs->bcbase[pc].ins; BCPos offset = dest-(pc+1)+BCBIAS_J; lua_assert(dest != NO_JMP); if (offset > BCMAX_D) @@ -355,33 +358,30 @@ static void expr_free(FuncState *fs, ExpDesc *e) /* -- Bytecode emitter ---------------------------------------------------- */ /* Emit bytecode instruction. */ -static BCPos bcemit_INS(FuncState *fs, BCIns i) +static BCPos bcemit_INS(FuncState *fs, BCIns ins) { - GCproto *pt; - BCIns *bc; - BCLine *lineinfo; - jmp_patchval(fs, fs->jpc, fs->pc, NO_REG, fs->pc); + BCPos pc = fs->pc; + LexState *ls = fs->ls; + jmp_patchval(fs, fs->jpc, pc, NO_REG, pc); fs->jpc = NO_JMP; - pt = fs->pt; - bc = proto_bc(pt); - lineinfo = proto_lineinfo(pt); - if (LJ_UNLIKELY(fs->pc >= pt->sizebc)) { - checklimit(fs, fs->pc, LJ_MAX_BCINS, "bytecode instructions"); - lj_mem_growvec(fs->L, bc, pt->sizebc, LJ_MAX_BCINS, BCIns); - setmref(pt->bc, bc); - lj_mem_growvec(fs->L, lineinfo, pt->sizelineinfo, LJ_MAX_BCINS, BCLine); - setmref(pt->lineinfo, lineinfo); + if (LJ_UNLIKELY(pc >= fs->bclim)) { + ptrdiff_t base = fs->bcbase - ls->bcstack; + checklimit(fs, ls->sizebcstack, LJ_MAX_BCINS, "bytecode instructions"); + lj_mem_growvec(fs->L, ls->bcstack, ls->sizebcstack, LJ_MAX_BCINS,BCInsLine); + fs->bclim = (BCPos)(ls->sizebcstack - base); + fs->bcbase = ls->bcstack + base; } - bc[fs->pc] = i; - lineinfo[fs->pc] = fs->ls->lastline; - return fs->pc++; + fs->bcbase[pc].ins = ins; + fs->bcbase[pc].line = ls->lastline; + fs->pc = pc+1; + return pc; } #define bcemit_ABC(fs, o, a, b, c) bcemit_INS(fs, BCINS_ABC(o, a, b, c)) #define bcemit_AD(fs, o, a, d) bcemit_INS(fs, BCINS_AD(o, a, d)) #define bcemit_AJ(fs, o, a, j) bcemit_INS(fs, BCINS_AJ(o, a, j)) -#define bcptr(fs, e) (proto_insptr((fs)->pt, (e)->u.s.info)) +#define bcptr(fs, e) (&(fs)->bcbase[(e)->u.s.info].ins) /* -- Bytecode emitter for expressions ------------------------------------ */ @@ -579,14 +579,12 @@ static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key) /* Emit bytecode to set a range of registers to nil. */ static void bcemit_nil(FuncState *fs, BCReg from, BCReg n) { - BCIns *pr; if (fs->pc > fs->lasttarget) { /* No jumps to current position? */ - BCReg pfrom, pto; - pr = proto_insptr(fs->pt, fs->pc-1); - pfrom = bc_a(*pr); - switch (bc_op(*pr)) { /* Try to merge with the previous instruction. */ + BCIns *ip = &fs->bcbase[fs->pc-1].ins; + BCReg pto, pfrom = bc_a(*ip); + switch (bc_op(*ip)) { /* Try to merge with the previous instruction. */ case BC_KPRI: - if (bc_d(*pr) != ~LJ_TNIL) break; + if (bc_d(*ip) != ~LJ_TNIL) break; if (from == pfrom) { if (n == 1) return; } else if (from == pfrom+1) { @@ -598,10 +596,10 @@ static void bcemit_nil(FuncState *fs, BCReg from, BCReg n) fs->pc--; /* Drop KPRI. */ break; case BC_KNIL: - pto = bc_d(*pr); + pto = bc_d(*ip); if (pfrom <= from && from <= pto+1) { /* Can we connect both ranges? */ if (from+n-1 > pto) - setbc_d(pr, from+n-1); /* Patch previous instruction range. */ + setbc_d(ip, from+n-1); /* Patch previous instruction range. */ return; } break; @@ -623,8 +621,8 @@ static BCPos bcemit_jmp(FuncState *fs) BCPos j = fs->pc - 1; fs->jpc = NO_JMP; if ((int32_t)j >= (int32_t)fs->lasttarget && - bc_op(proto_ins(fs->pt, j)) == BC_UCLO) - setbc_j(proto_insptr(fs->pt, j), NO_JMP); + bc_op(fs->bcbase[j].ins) == BC_UCLO) + setbc_j(&fs->bcbase[j].ins, NO_JMP); else j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP); jmp_append(fs, &j, jpc); @@ -634,8 +632,8 @@ static BCPos bcemit_jmp(FuncState *fs) /* Invert branch condition of bytecode instruction. */ static void invertcond(FuncState *fs, ExpDesc *e) { - BCIns *i = bcptr(fs, e) - 1; - setbc_op(i, bc_op(*i)^1); + BCIns *ip = &fs->bcbase[e->u.s.info - 1].ins; + setbc_op(ip, bc_op(*ip)^1); } /* Emit conditional branch. */ @@ -643,9 +641,9 @@ static BCPos bcemit_branch(FuncState *fs, ExpDesc *e, int cond) { BCPos pc; if (e->k == VRELOCABLE) { - BCIns *i = bcptr(fs, e); - if (bc_op(*i) == BC_NOT) { - *i = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*i)); + BCIns *ip = bcptr(fs, e); + if (bc_op(*ip) == BC_NOT) { + *ip = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*ip)); return bcemit_jmp(fs); } } @@ -1094,10 +1092,10 @@ static int bcopisret(BCOp op) } /* Fixup return instruction for prototype. */ -static void fs_fixup_ret(FuncState *fs, GCproto *pt) +static void fs_fixup_ret(FuncState *fs) { BCPos lastpc = fs->pc; - if (lastpc <= fs->lasttarget || !bcopisret(bc_op(proto_ins(pt, lastpc-1)))) { + if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) { if (fs->flags & PROTO_HAS_FNEW) bcemit_AJ(fs, BC_UCLO, 0, 0); bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ @@ -1106,16 +1104,16 @@ static void fs_fixup_ret(FuncState *fs, GCproto *pt) if (fs->flags & PROTO_FIXUP_RETURN) { BCPos pc; for (pc = 0; pc < lastpc; pc++) { - BCIns i = proto_ins(pt, pc); + BCIns ins = fs->bcbase[pc].ins; BCPos offset; - switch (bc_op(i)) { + switch (bc_op(ins)) { case BC_CALLMT: case BC_CALLT: case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1: - offset = bcemit_INS(fs, i)-(pc+1)+BCBIAS_J; /* Copy return ins. */ + offset = bcemit_INS(fs, ins)-(pc+1)+BCBIAS_J; /* Copy return ins. */ if (offset > BCMAX_D) err_syntax(fs->ls, LJ_ERR_XFIXUP); /* Replace with UCLO plus branch. */ - *proto_insptr(pt, pc) = BCINS_AD(BC_UCLO, 0, offset); + fs->bcbase[pc].ins = BCINS_AD(BC_UCLO, 0, offset); break; case BC_UCLO: return; /* We're done. */ @@ -1132,26 +1130,29 @@ static GCproto *fs_finish(LexState *ls, BCLine line) lua_State *L = ls->L; FuncState *fs = ls->fs; GCproto *pt = fs->pt; - BCIns *bc; - BCLine *lineinfo; /* Apply final fixups. */ var_remove(ls, 0); - fs_fixup_ret(fs, pt); - - /* Reallocate arrays. */ - bc = proto_bc(pt); - lj_mem_reallocvec(L, bc, pt->sizebc, fs->pc, BCIns); - setmref(pt->bc, bc); - pt->sizebc = fs->pc; + fs_fixup_ret(fs); fs_fixup_k(fs, pt); fs_fixup_uv(fs, pt); - lineinfo = proto_lineinfo(pt); - lj_mem_reallocvec(L, lineinfo, pt->sizelineinfo, fs->pc, BCLine); - setmref(pt->lineinfo, lineinfo); - pt->sizelineinfo = fs->pc; + { + MSize i, n = fs->pc; + BCInsLine *base = fs->bcbase; + BCLine *lineinfo; + BCIns *bc = lj_mem_newvec(L, n, BCIns); + setmref(pt->bc, bc); + pt->sizebc = fs->pc; + lineinfo = lj_mem_newvec(L, n, BCLine); + setmref(pt->lineinfo, lineinfo); + pt->sizelineinfo = n; + for (i = 0; i < n; i++) { + bc[i] = base[i].ins; + lineinfo[i] = base[i].line; + } + } { MSize n = ls->vtop - fs->vbase; @@ -1173,6 +1174,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line) /* Initialize prototype fields. */ setgcref(pt->chunkname, obj2gco(ls->chunkname)); pt->flags = fs->flags; + pt->numparams = fs->numparams; pt->framesize = fs->framesize; pt->linedefined = fs->linedefined; pt->lastlinedefined = line; @@ -1196,7 +1198,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line) } /* Initialize a new FuncState. */ -static void fs_init(LexState *ls, FuncState *fs, BCLine line) +static void fs_init(LexState *ls, FuncState *fs) { lua_State *L = ls->L; GCproto *pt = lj_func_newproto(L); @@ -1216,7 +1218,6 @@ static void fs_init(LexState *ls, FuncState *fs, BCLine line) fs->bl = NULL; fs->flags = 0; fs->framesize = 2; /* Minimum frame size. */ - fs->linedefined = line; fs->kt = lj_tab_new(L, 0, 0); /* Anchor table of constants and prototype (to avoid being collected). */ settabV(L, L->top, fs->kt); @@ -1333,7 +1334,7 @@ static void expr_table(LexState *ls, ExpDesc *e) BCReg kidx; t = lj_tab_new(fs->L, 0, 0); kidx = const_gc(fs, obj2gco(t), LJ_TTAB); - *proto_insptr(fs->pt, pc) = BCINS_AD(BC_TDUP, freg-1, kidx); + fs->bcbase[pc].ins = BCINS_AD(BC_TDUP, freg-1, kidx); } vcall = 0; expr_kvalue(&k, &key); @@ -1350,14 +1351,15 @@ static void expr_table(LexState *ls, ExpDesc *e) } lex_match(ls, '}', '{', line); if (vcall) { - BCIns *i = proto_insptr(fs->pt, fs->pc-1); + BCInsLine *ilp = &fs->bcbase[fs->pc-1]; ExpDesc en; - lua_assert(bc_a(*i)==freg && bc_op(*i) == (narr>256?BC_TSETV:BC_TSETB)); + lua_assert(bc_a(ilp->ins) == freg && + bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB)); expr_init(&en, VKNUM, 0); setintV(&en.u.nval, narr-1); - if (narr > 256) { fs->pc--; i--; } - *i = BCINS_AD(BC_TSETM, freg, const_num(fs, &en)); - setbc_b(i-1, 0); + if (narr > 256) { fs->pc--; ilp--; } + ilp->ins = BCINS_AD(BC_TSETM, freg, const_num(fs, &en)); + setbc_b(&ilp[-1].ins, 0); } if (pc == fs->pc-1) { /* Make expr relocable if possible. */ e->u.s.info = pc; @@ -1370,15 +1372,14 @@ static void expr_table(LexState *ls, ExpDesc *e) if (!needarr) narr = 0; else if (narr < 3) narr = 3; else if (narr > 0x7ff) narr = 0x7ff; - setbc_d(proto_insptr(fs->pt, pc), (uint32_t)narr|(hsize2hbits(nhash)<<11)); + setbc_d(&fs->bcbase[pc].ins, (uint32_t)narr|(hsize2hbits(nhash)<<11)); } } /* Parse function parameters. */ -static void parse_params(LexState *ls, int needself) +static BCReg parse_params(LexState *ls, int needself) { FuncState *fs = ls->fs; - GCproto *pt = fs->pt; BCReg nparams = 0; lex_check(ls, '('); if (needself) { @@ -1399,9 +1400,9 @@ static void parse_params(LexState *ls, int needself) } while (lex_opt(ls, ',')); } var_add(ls, nparams); - pt->numparams = cast_byte(fs->nactvar); bcreg_reserve(fs, fs->nactvar); lex_check(ls, ')'); + return fs->nactvar; } /* Forward declaration. */ @@ -1410,18 +1411,23 @@ static void parse_chunk(LexState *ls); /* Parse body of a function. */ static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) { - FuncState *fs, cfs; + FuncState cfs, *fs = ls->fs; BCReg kidx; BCLine lastline; GCproto *pt; - fs_init(ls, &cfs, line); - parse_params(ls, needself); + ptrdiff_t oldbase = fs->bcbase - ls->bcstack; + fs_init(ls, &cfs); + cfs.linedefined = line; + cfs.numparams = (uint8_t)parse_params(ls, needself); + cfs.bcbase = fs->bcbase + fs->pc; + cfs.bclim = fs->bclim - fs->pc; parse_chunk(ls); lastline = ls->linenumber; lex_match(ls, TK_end, TK_function, line); pt = fs_finish(ls, lastline); + fs->bcbase = ls->bcstack + oldbase; /* May have been reallocated. */ + fs->bclim = ls->sizebcstack - oldbase; /* Store new prototype in the constant array of the parent. */ - fs = ls->fs; kidx = const_gc(fs, obj2gco(pt), LJ_TPROTO); expr_init(e, VRELOCABLE, bcemit_AD(fs, BC_FNEW, 0, kidx)); if (!(fs->flags & PROTO_HAS_FNEW)) { @@ -1485,7 +1491,7 @@ static void parse_args(LexState *ls, ExpDesc *e) } expr_init(e, VCALL, bcemit_INS(fs, ins)); e->u.s.aux = base; - proto_lineinfo(fs->pt)[fs->pc - 1] = line; + fs->bcbase[fs->pc - 1].line = line; fs->freereg = base+1; /* Leave one result by default. */ } @@ -1693,7 +1699,7 @@ static void scope_begin(FuncState *fs, FuncScope *bl, int isbreakable) { bl->breaklist = NO_JMP; bl->isbreakable = (uint8_t)isbreakable; - bl->nactvar = fs->nactvar; + bl->nactvar = (uint8_t)fs->nactvar; bl->upval = 0; bl->prev = fs->bl; fs->bl = bl; @@ -1766,11 +1772,11 @@ static void parse_return(LexState *ls) BCReg nret = expr_list(ls, &e); if (nret == 1) { /* Return one result. */ if (e.k == VCALL) { /* Check for tail call. */ - BCIns *i = bcptr(fs, &e); + BCIns *ip = bcptr(fs, &e); /* It doesn't pay off to add BC_VARGT just for 'return ...'. */ - if (bc_op(*i) == BC_VARG) goto notailcall; + if (bc_op(*ip) == BC_VARG) goto notailcall; fs->pc--; - ins = BCINS_AD(bc_op(*i)-BC_CALL+BC_CALLT, bc_a(*i), bc_c(*i)); + ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT, bc_a(*ip), bc_c(*ip)); } else { /* Can return the result from any register. */ ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); } @@ -1957,7 +1963,7 @@ static void parse_func(LexState *ls, BCLine line) parse_body(ls, &b, needself, line); fs = ls->fs; bcemit_store(fs, &v, &b); - proto_lineinfo(fs->pt)[fs->pc - 1] = line; /* Set line for the store. */ + fs->bcbase[fs->pc - 1].line = line; /* Set line for the store. */ } /* -- Loop and conditional statements ------------------------------------- */ @@ -2033,9 +2039,9 @@ static void parse_for_body(LexState *ls, BCReg base, BCLine line, jmp_patchins(fs, loop, fs->pc); bcemit_ABC(fs, BC_ITERC, base+3, nvars+1, 2+1); loopend = bcemit_AJ(fs, BC_ITERL, base+3, NO_JMP); - proto_lineinfo(fs->pt)[loopend-1] = line; + fs->bcbase[loopend-1].line = line; } - proto_lineinfo(fs->pt)[loopend] = line; /* Fix line for control ins. */ + fs->bcbase[loopend].line = line; /* Fix line for control ins. */ jmp_patchins(fs, loopend, loop+1); } @@ -2210,7 +2216,11 @@ GCproto *lj_parse(LexState *ls) setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */ incr_top(L); ls->level = 0; - fs_init(ls, &fs, 0); + fs_init(ls, &fs); + fs.linedefined = 0; + fs.numparams = 0; + fs.bcbase = NULL; + fs.bclim = 0; fs.flags |= PROTO_IS_VARARG; /* Main chunk is always a vararg func. */ lj_lex_next(ls); /* Read-ahead first token. */ parse_chunk(ls);