diff options
| -rw-r--r-- | src/lj_lex.c | 3 | ||||
| -rw-r--r-- | src/lj_lex.h | 8 | ||||
| -rw-r--r-- | src/lj_parse.c | 186 |
3 files changed, 109 insertions, 88 deletions
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) | |||
| 311 | ls->vstack = NULL; | 311 | ls->vstack = NULL; |
| 312 | ls->sizevstack = 0; | 312 | ls->sizevstack = 0; |
| 313 | ls->vtop = 0; | 313 | ls->vtop = 0; |
| 314 | ls->bcstack = NULL; | ||
| 315 | ls->sizebcstack = 0; | ||
| 314 | ls->lookahead = TK_eof; /* No look-ahead token. */ | 316 | ls->lookahead = TK_eof; /* No look-ahead token. */ |
| 315 | ls->linenumber = 1; | 317 | ls->linenumber = 1; |
| 316 | ls->lastline = 1; | 318 | ls->lastline = 1; |
| @@ -339,6 +341,7 @@ void lj_lex_setup(lua_State *L, LexState *ls) | |||
| 339 | void lj_lex_cleanup(lua_State *L, LexState *ls) | 341 | void lj_lex_cleanup(lua_State *L, LexState *ls) |
| 340 | { | 342 | { |
| 341 | global_State *g = G(L); | 343 | global_State *g = G(L); |
| 344 | lj_mem_freevec(g, ls->bcstack, ls->sizebcstack, BCInsLine); | ||
| 342 | lj_mem_freevec(g, ls->vstack, ls->sizevstack, VarInfo); | 345 | lj_mem_freevec(g, ls->vstack, ls->sizevstack, VarInfo); |
| 343 | lj_str_freebuf(g, &ls->sb); | 346 | lj_str_freebuf(g, &ls->sb); |
| 344 | } | 347 | } |
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) | |||
| 32 | 32 | ||
| 33 | typedef int LexToken; | 33 | typedef int LexToken; |
| 34 | 34 | ||
| 35 | /* Combined bytecode ins/line. Only used during bytecode generation. */ | ||
| 36 | typedef struct BCInsLine { | ||
| 37 | BCIns ins; /* Bytecode instruction. */ | ||
| 38 | BCLine line; /* Line number for this bytecode. */ | ||
| 39 | } BCInsLine; | ||
| 40 | |||
| 35 | /* Lua lexer state. */ | 41 | /* Lua lexer state. */ |
| 36 | typedef struct LexState { | 42 | typedef struct LexState { |
| 37 | struct FuncState *fs; /* Current FuncState. Defined in lj_parse.c. */ | 43 | struct FuncState *fs; /* Current FuncState. Defined in lj_parse.c. */ |
| @@ -53,6 +59,8 @@ typedef struct LexState { | |||
| 53 | VarInfo *vstack; /* Stack for names and extents of local variables. */ | 59 | VarInfo *vstack; /* Stack for names and extents of local variables. */ |
| 54 | MSize sizevstack; /* Size of variable stack. */ | 60 | MSize sizevstack; /* Size of variable stack. */ |
| 55 | MSize vtop; /* Top of variable stack. */ | 61 | MSize vtop; /* Top of variable stack. */ |
| 62 | BCInsLine *bcstack; /* Stack for bytecode instructions/line numbers. */ | ||
| 63 | MSize sizebcstack; /* Size of bytecode stack. */ | ||
| 56 | uint32_t level; /* Syntactical nesting level. */ | 64 | uint32_t level; /* Syntactical nesting level. */ |
| 57 | } LexState; | 65 | } LexState; |
| 58 | 66 | ||
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 { | |||
| 110 | BCPos lasttarget; /* Bytecode position of last jump target. */ | 110 | BCPos lasttarget; /* Bytecode position of last jump target. */ |
| 111 | BCPos jpc; /* Pending jump list to next bytecode. */ | 111 | BCPos jpc; /* Pending jump list to next bytecode. */ |
| 112 | BCReg freereg; /* First free register. */ | 112 | BCReg freereg; /* First free register. */ |
| 113 | BCReg nactvar; /* Number of active local variables. */ | ||
| 113 | BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */ | 114 | BCReg nkn, nkgc; /* Number of lua_Number/GCobj constants */ |
| 114 | BCLine linedefined; /* First line of the function definition. */ | 115 | BCLine linedefined; /* First line of the function definition. */ |
| 116 | BCInsLine *bcbase; /* Base of bytecode stack. */ | ||
| 117 | BCPos bclim; /* Limit of bytecode stack. */ | ||
| 115 | MSize vbase; /* Base of variable stack for this function. */ | 118 | MSize vbase; /* Base of variable stack for this function. */ |
| 116 | uint8_t nactvar; /* Number of active local variables. */ | ||
| 117 | uint8_t flags; /* Prototype flags. */ | 119 | uint8_t flags; /* Prototype flags. */ |
| 120 | uint8_t numparams; /* Number of active local variables. */ | ||
| 118 | uint8_t framesize; /* Fixed frame size. */ | 121 | uint8_t framesize; /* Fixed frame size. */ |
| 119 | uint8_t nuv; /* Number of upvalues */ | 122 | uint8_t nuv; /* Number of upvalues */ |
| 120 | VarIndex varmap[LJ_MAX_LOCVAR]; /* Map from register to variable idx. */ | 123 | 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) | |||
| 217 | /* Get next element in jump list. */ | 220 | /* Get next element in jump list. */ |
| 218 | static BCPos jmp_next(FuncState *fs, BCPos pc) | 221 | static BCPos jmp_next(FuncState *fs, BCPos pc) |
| 219 | { | 222 | { |
| 220 | ptrdiff_t delta = bc_j(proto_ins(fs->pt, pc)); | 223 | ptrdiff_t delta = bc_j(fs->bcbase[pc].ins); |
| 221 | if ((BCPos)delta == NO_JMP) | 224 | if ((BCPos)delta == NO_JMP) |
| 222 | return NO_JMP; | 225 | return NO_JMP; |
| 223 | else | 226 | else |
| @@ -228,7 +231,7 @@ static BCPos jmp_next(FuncState *fs, BCPos pc) | |||
| 228 | static int jmp_novalue(FuncState *fs, BCPos list) | 231 | static int jmp_novalue(FuncState *fs, BCPos list) |
| 229 | { | 232 | { |
| 230 | for (; list != NO_JMP; list = jmp_next(fs, list)) { | 233 | for (; list != NO_JMP; list = jmp_next(fs, list)) { |
| 231 | BCOp op = bc_op(proto_ins(fs->pt, list >= 1 ? list-1 : list)); | 234 | BCOp op = bc_op(fs->bcbase[list >= 1 ? list-1 : list].ins); |
| 232 | if (!(op == BC_ISTC || op == BC_ISFC)) return 1; | 235 | if (!(op == BC_ISTC || op == BC_ISFC)) return 1; |
| 233 | } | 236 | } |
| 234 | return 0; | 237 | return 0; |
| @@ -237,15 +240,15 @@ static int jmp_novalue(FuncState *fs, BCPos list) | |||
| 237 | /* Patch register of test instructions. */ | 240 | /* Patch register of test instructions. */ |
| 238 | static int jmp_patchtestreg(FuncState *fs, BCPos pc, BCReg reg) | 241 | static int jmp_patchtestreg(FuncState *fs, BCPos pc, BCReg reg) |
| 239 | { | 242 | { |
| 240 | BCIns *i = proto_insptr(fs->pt, pc >= 1 ? pc-1 : pc); | 243 | BCIns *ip = &fs->bcbase[pc >= 1 ? pc-1 : pc].ins; |
| 241 | BCOp op = bc_op(*i); | 244 | BCOp op = bc_op(*ip); |
| 242 | if (!(op == BC_ISTC || op == BC_ISFC)) | 245 | if (!(op == BC_ISTC || op == BC_ISFC)) |
| 243 | return 0; /* Cannot patch other instructions. */ | 246 | return 0; /* Cannot patch other instructions. */ |
| 244 | if (reg != NO_REG && reg != bc_d(*i)) { | 247 | if (reg != NO_REG && reg != bc_d(*ip)) { |
| 245 | setbc_a(i, reg); | 248 | setbc_a(ip, reg); |
| 246 | } else { /* Nothing to store or already in the right register. */ | 249 | } else { /* Nothing to store or already in the right register. */ |
| 247 | setbc_op(i, op+(BC_IST-BC_ISTC)); | 250 | setbc_op(ip, op+(BC_IST-BC_ISTC)); |
| 248 | setbc_a(i, 0); | 251 | setbc_a(ip, 0); |
| 249 | } | 252 | } |
| 250 | return 1; | 253 | return 1; |
| 251 | } | 254 | } |
| @@ -260,7 +263,7 @@ static void jmp_dropval(FuncState *fs, BCPos list) | |||
| 260 | /* Patch jump instruction to target. */ | 263 | /* Patch jump instruction to target. */ |
| 261 | static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest) | 264 | static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest) |
| 262 | { | 265 | { |
| 263 | BCIns *jmp = proto_insptr(fs->pt, pc); | 266 | BCIns *jmp = &fs->bcbase[pc].ins; |
| 264 | BCPos offset = dest-(pc+1)+BCBIAS_J; | 267 | BCPos offset = dest-(pc+1)+BCBIAS_J; |
| 265 | lua_assert(dest != NO_JMP); | 268 | lua_assert(dest != NO_JMP); |
| 266 | if (offset > BCMAX_D) | 269 | if (offset > BCMAX_D) |
| @@ -355,33 +358,30 @@ static void expr_free(FuncState *fs, ExpDesc *e) | |||
| 355 | /* -- Bytecode emitter ---------------------------------------------------- */ | 358 | /* -- Bytecode emitter ---------------------------------------------------- */ |
| 356 | 359 | ||
| 357 | /* Emit bytecode instruction. */ | 360 | /* Emit bytecode instruction. */ |
| 358 | static BCPos bcemit_INS(FuncState *fs, BCIns i) | 361 | static BCPos bcemit_INS(FuncState *fs, BCIns ins) |
| 359 | { | 362 | { |
| 360 | GCproto *pt; | 363 | BCPos pc = fs->pc; |
| 361 | BCIns *bc; | 364 | LexState *ls = fs->ls; |
| 362 | BCLine *lineinfo; | 365 | jmp_patchval(fs, fs->jpc, pc, NO_REG, pc); |
| 363 | jmp_patchval(fs, fs->jpc, fs->pc, NO_REG, fs->pc); | ||
| 364 | fs->jpc = NO_JMP; | 366 | fs->jpc = NO_JMP; |
| 365 | pt = fs->pt; | 367 | if (LJ_UNLIKELY(pc >= fs->bclim)) { |
| 366 | bc = proto_bc(pt); | 368 | ptrdiff_t base = fs->bcbase - ls->bcstack; |
| 367 | lineinfo = proto_lineinfo(pt); | 369 | checklimit(fs, ls->sizebcstack, LJ_MAX_BCINS, "bytecode instructions"); |
| 368 | if (LJ_UNLIKELY(fs->pc >= pt->sizebc)) { | 370 | lj_mem_growvec(fs->L, ls->bcstack, ls->sizebcstack, LJ_MAX_BCINS,BCInsLine); |
| 369 | checklimit(fs, fs->pc, LJ_MAX_BCINS, "bytecode instructions"); | 371 | fs->bclim = (BCPos)(ls->sizebcstack - base); |
| 370 | lj_mem_growvec(fs->L, bc, pt->sizebc, LJ_MAX_BCINS, BCIns); | 372 | fs->bcbase = ls->bcstack + base; |
| 371 | setmref(pt->bc, bc); | 373 | } |
| 372 | lj_mem_growvec(fs->L, lineinfo, pt->sizelineinfo, LJ_MAX_BCINS, BCLine); | 374 | fs->bcbase[pc].ins = ins; |
| 373 | setmref(pt->lineinfo, lineinfo); | 375 | fs->bcbase[pc].line = ls->lastline; |
| 374 | } | 376 | fs->pc = pc+1; |
| 375 | bc[fs->pc] = i; | 377 | return pc; |
| 376 | lineinfo[fs->pc] = fs->ls->lastline; | ||
| 377 | return fs->pc++; | ||
| 378 | } | 378 | } |
| 379 | 379 | ||
| 380 | #define bcemit_ABC(fs, o, a, b, c) bcemit_INS(fs, BCINS_ABC(o, a, b, c)) | 380 | #define bcemit_ABC(fs, o, a, b, c) bcemit_INS(fs, BCINS_ABC(o, a, b, c)) |
| 381 | #define bcemit_AD(fs, o, a, d) bcemit_INS(fs, BCINS_AD(o, a, d)) | 381 | #define bcemit_AD(fs, o, a, d) bcemit_INS(fs, BCINS_AD(o, a, d)) |
| 382 | #define bcemit_AJ(fs, o, a, j) bcemit_INS(fs, BCINS_AJ(o, a, j)) | 382 | #define bcemit_AJ(fs, o, a, j) bcemit_INS(fs, BCINS_AJ(o, a, j)) |
| 383 | 383 | ||
| 384 | #define bcptr(fs, e) (proto_insptr((fs)->pt, (e)->u.s.info)) | 384 | #define bcptr(fs, e) (&(fs)->bcbase[(e)->u.s.info].ins) |
| 385 | 385 | ||
| 386 | /* -- Bytecode emitter for expressions ------------------------------------ */ | 386 | /* -- Bytecode emitter for expressions ------------------------------------ */ |
| 387 | 387 | ||
| @@ -579,14 +579,12 @@ static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key) | |||
| 579 | /* Emit bytecode to set a range of registers to nil. */ | 579 | /* Emit bytecode to set a range of registers to nil. */ |
| 580 | static void bcemit_nil(FuncState *fs, BCReg from, BCReg n) | 580 | static void bcemit_nil(FuncState *fs, BCReg from, BCReg n) |
| 581 | { | 581 | { |
| 582 | BCIns *pr; | ||
| 583 | if (fs->pc > fs->lasttarget) { /* No jumps to current position? */ | 582 | if (fs->pc > fs->lasttarget) { /* No jumps to current position? */ |
| 584 | BCReg pfrom, pto; | 583 | BCIns *ip = &fs->bcbase[fs->pc-1].ins; |
| 585 | pr = proto_insptr(fs->pt, fs->pc-1); | 584 | BCReg pto, pfrom = bc_a(*ip); |
| 586 | pfrom = bc_a(*pr); | 585 | switch (bc_op(*ip)) { /* Try to merge with the previous instruction. */ |
| 587 | switch (bc_op(*pr)) { /* Try to merge with the previous instruction. */ | ||
| 588 | case BC_KPRI: | 586 | case BC_KPRI: |
| 589 | if (bc_d(*pr) != ~LJ_TNIL) break; | 587 | if (bc_d(*ip) != ~LJ_TNIL) break; |
| 590 | if (from == pfrom) { | 588 | if (from == pfrom) { |
| 591 | if (n == 1) return; | 589 | if (n == 1) return; |
| 592 | } else if (from == pfrom+1) { | 590 | } else if (from == pfrom+1) { |
| @@ -598,10 +596,10 @@ static void bcemit_nil(FuncState *fs, BCReg from, BCReg n) | |||
| 598 | fs->pc--; /* Drop KPRI. */ | 596 | fs->pc--; /* Drop KPRI. */ |
| 599 | break; | 597 | break; |
| 600 | case BC_KNIL: | 598 | case BC_KNIL: |
| 601 | pto = bc_d(*pr); | 599 | pto = bc_d(*ip); |
| 602 | if (pfrom <= from && from <= pto+1) { /* Can we connect both ranges? */ | 600 | if (pfrom <= from && from <= pto+1) { /* Can we connect both ranges? */ |
| 603 | if (from+n-1 > pto) | 601 | if (from+n-1 > pto) |
| 604 | setbc_d(pr, from+n-1); /* Patch previous instruction range. */ | 602 | setbc_d(ip, from+n-1); /* Patch previous instruction range. */ |
| 605 | return; | 603 | return; |
| 606 | } | 604 | } |
| 607 | break; | 605 | break; |
| @@ -623,8 +621,8 @@ static BCPos bcemit_jmp(FuncState *fs) | |||
| 623 | BCPos j = fs->pc - 1; | 621 | BCPos j = fs->pc - 1; |
| 624 | fs->jpc = NO_JMP; | 622 | fs->jpc = NO_JMP; |
| 625 | if ((int32_t)j >= (int32_t)fs->lasttarget && | 623 | if ((int32_t)j >= (int32_t)fs->lasttarget && |
| 626 | bc_op(proto_ins(fs->pt, j)) == BC_UCLO) | 624 | bc_op(fs->bcbase[j].ins) == BC_UCLO) |
| 627 | setbc_j(proto_insptr(fs->pt, j), NO_JMP); | 625 | setbc_j(&fs->bcbase[j].ins, NO_JMP); |
| 628 | else | 626 | else |
| 629 | j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP); | 627 | j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP); |
| 630 | jmp_append(fs, &j, jpc); | 628 | jmp_append(fs, &j, jpc); |
| @@ -634,8 +632,8 @@ static BCPos bcemit_jmp(FuncState *fs) | |||
| 634 | /* Invert branch condition of bytecode instruction. */ | 632 | /* Invert branch condition of bytecode instruction. */ |
| 635 | static void invertcond(FuncState *fs, ExpDesc *e) | 633 | static void invertcond(FuncState *fs, ExpDesc *e) |
| 636 | { | 634 | { |
| 637 | BCIns *i = bcptr(fs, e) - 1; | 635 | BCIns *ip = &fs->bcbase[e->u.s.info - 1].ins; |
| 638 | setbc_op(i, bc_op(*i)^1); | 636 | setbc_op(ip, bc_op(*ip)^1); |
| 639 | } | 637 | } |
| 640 | 638 | ||
| 641 | /* Emit conditional branch. */ | 639 | /* Emit conditional branch. */ |
| @@ -643,9 +641,9 @@ static BCPos bcemit_branch(FuncState *fs, ExpDesc *e, int cond) | |||
| 643 | { | 641 | { |
| 644 | BCPos pc; | 642 | BCPos pc; |
| 645 | if (e->k == VRELOCABLE) { | 643 | if (e->k == VRELOCABLE) { |
| 646 | BCIns *i = bcptr(fs, e); | 644 | BCIns *ip = bcptr(fs, e); |
| 647 | if (bc_op(*i) == BC_NOT) { | 645 | if (bc_op(*ip) == BC_NOT) { |
| 648 | *i = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*i)); | 646 | *ip = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*ip)); |
| 649 | return bcemit_jmp(fs); | 647 | return bcemit_jmp(fs); |
| 650 | } | 648 | } |
| 651 | } | 649 | } |
| @@ -1094,10 +1092,10 @@ static int bcopisret(BCOp op) | |||
| 1094 | } | 1092 | } |
| 1095 | 1093 | ||
| 1096 | /* Fixup return instruction for prototype. */ | 1094 | /* Fixup return instruction for prototype. */ |
| 1097 | static void fs_fixup_ret(FuncState *fs, GCproto *pt) | 1095 | static void fs_fixup_ret(FuncState *fs) |
| 1098 | { | 1096 | { |
| 1099 | BCPos lastpc = fs->pc; | 1097 | BCPos lastpc = fs->pc; |
| 1100 | if (lastpc <= fs->lasttarget || !bcopisret(bc_op(proto_ins(pt, lastpc-1)))) { | 1098 | if (lastpc <= fs->lasttarget || !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) { |
| 1101 | if (fs->flags & PROTO_HAS_FNEW) | 1099 | if (fs->flags & PROTO_HAS_FNEW) |
| 1102 | bcemit_AJ(fs, BC_UCLO, 0, 0); | 1100 | bcemit_AJ(fs, BC_UCLO, 0, 0); |
| 1103 | bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ | 1101 | bcemit_AD(fs, BC_RET0, 0, 1); /* Need final return. */ |
| @@ -1106,16 +1104,16 @@ static void fs_fixup_ret(FuncState *fs, GCproto *pt) | |||
| 1106 | if (fs->flags & PROTO_FIXUP_RETURN) { | 1104 | if (fs->flags & PROTO_FIXUP_RETURN) { |
| 1107 | BCPos pc; | 1105 | BCPos pc; |
| 1108 | for (pc = 0; pc < lastpc; pc++) { | 1106 | for (pc = 0; pc < lastpc; pc++) { |
| 1109 | BCIns i = proto_ins(pt, pc); | 1107 | BCIns ins = fs->bcbase[pc].ins; |
| 1110 | BCPos offset; | 1108 | BCPos offset; |
| 1111 | switch (bc_op(i)) { | 1109 | switch (bc_op(ins)) { |
| 1112 | case BC_CALLMT: case BC_CALLT: | 1110 | case BC_CALLMT: case BC_CALLT: |
| 1113 | case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1: | 1111 | case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1: |
| 1114 | offset = bcemit_INS(fs, i)-(pc+1)+BCBIAS_J; /* Copy return ins. */ | 1112 | offset = bcemit_INS(fs, ins)-(pc+1)+BCBIAS_J; /* Copy return ins. */ |
| 1115 | if (offset > BCMAX_D) | 1113 | if (offset > BCMAX_D) |
| 1116 | err_syntax(fs->ls, LJ_ERR_XFIXUP); | 1114 | err_syntax(fs->ls, LJ_ERR_XFIXUP); |
| 1117 | /* Replace with UCLO plus branch. */ | 1115 | /* Replace with UCLO plus branch. */ |
| 1118 | *proto_insptr(pt, pc) = BCINS_AD(BC_UCLO, 0, offset); | 1116 | fs->bcbase[pc].ins = BCINS_AD(BC_UCLO, 0, offset); |
| 1119 | break; | 1117 | break; |
| 1120 | case BC_UCLO: | 1118 | case BC_UCLO: |
| 1121 | return; /* We're done. */ | 1119 | return; /* We're done. */ |
| @@ -1132,26 +1130,29 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
| 1132 | lua_State *L = ls->L; | 1130 | lua_State *L = ls->L; |
| 1133 | FuncState *fs = ls->fs; | 1131 | FuncState *fs = ls->fs; |
| 1134 | GCproto *pt = fs->pt; | 1132 | GCproto *pt = fs->pt; |
| 1135 | BCIns *bc; | ||
| 1136 | BCLine *lineinfo; | ||
| 1137 | 1133 | ||
| 1138 | /* Apply final fixups. */ | 1134 | /* Apply final fixups. */ |
| 1139 | var_remove(ls, 0); | 1135 | var_remove(ls, 0); |
| 1140 | fs_fixup_ret(fs, pt); | 1136 | fs_fixup_ret(fs); |
| 1141 | |||
| 1142 | /* Reallocate arrays. */ | ||
| 1143 | bc = proto_bc(pt); | ||
| 1144 | lj_mem_reallocvec(L, bc, pt->sizebc, fs->pc, BCIns); | ||
| 1145 | setmref(pt->bc, bc); | ||
| 1146 | pt->sizebc = fs->pc; | ||
| 1147 | 1137 | ||
| 1148 | fs_fixup_k(fs, pt); | 1138 | fs_fixup_k(fs, pt); |
| 1149 | fs_fixup_uv(fs, pt); | 1139 | fs_fixup_uv(fs, pt); |
| 1150 | 1140 | ||
| 1151 | lineinfo = proto_lineinfo(pt); | 1141 | { |
| 1152 | lj_mem_reallocvec(L, lineinfo, pt->sizelineinfo, fs->pc, BCLine); | 1142 | MSize i, n = fs->pc; |
| 1153 | setmref(pt->lineinfo, lineinfo); | 1143 | BCInsLine *base = fs->bcbase; |
| 1154 | pt->sizelineinfo = fs->pc; | 1144 | BCLine *lineinfo; |
| 1145 | BCIns *bc = lj_mem_newvec(L, n, BCIns); | ||
| 1146 | setmref(pt->bc, bc); | ||
| 1147 | pt->sizebc = fs->pc; | ||
| 1148 | lineinfo = lj_mem_newvec(L, n, BCLine); | ||
| 1149 | setmref(pt->lineinfo, lineinfo); | ||
| 1150 | pt->sizelineinfo = n; | ||
| 1151 | for (i = 0; i < n; i++) { | ||
| 1152 | bc[i] = base[i].ins; | ||
| 1153 | lineinfo[i] = base[i].line; | ||
| 1154 | } | ||
| 1155 | } | ||
| 1155 | 1156 | ||
| 1156 | { | 1157 | { |
| 1157 | MSize n = ls->vtop - fs->vbase; | 1158 | MSize n = ls->vtop - fs->vbase; |
| @@ -1173,6 +1174,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
| 1173 | /* Initialize prototype fields. */ | 1174 | /* Initialize prototype fields. */ |
| 1174 | setgcref(pt->chunkname, obj2gco(ls->chunkname)); | 1175 | setgcref(pt->chunkname, obj2gco(ls->chunkname)); |
| 1175 | pt->flags = fs->flags; | 1176 | pt->flags = fs->flags; |
| 1177 | pt->numparams = fs->numparams; | ||
| 1176 | pt->framesize = fs->framesize; | 1178 | pt->framesize = fs->framesize; |
| 1177 | pt->linedefined = fs->linedefined; | 1179 | pt->linedefined = fs->linedefined; |
| 1178 | pt->lastlinedefined = line; | 1180 | pt->lastlinedefined = line; |
| @@ -1196,7 +1198,7 @@ static GCproto *fs_finish(LexState *ls, BCLine line) | |||
| 1196 | } | 1198 | } |
| 1197 | 1199 | ||
| 1198 | /* Initialize a new FuncState. */ | 1200 | /* Initialize a new FuncState. */ |
| 1199 | static void fs_init(LexState *ls, FuncState *fs, BCLine line) | 1201 | static void fs_init(LexState *ls, FuncState *fs) |
| 1200 | { | 1202 | { |
| 1201 | lua_State *L = ls->L; | 1203 | lua_State *L = ls->L; |
| 1202 | GCproto *pt = lj_func_newproto(L); | 1204 | GCproto *pt = lj_func_newproto(L); |
| @@ -1216,7 +1218,6 @@ static void fs_init(LexState *ls, FuncState *fs, BCLine line) | |||
| 1216 | fs->bl = NULL; | 1218 | fs->bl = NULL; |
| 1217 | fs->flags = 0; | 1219 | fs->flags = 0; |
| 1218 | fs->framesize = 2; /* Minimum frame size. */ | 1220 | fs->framesize = 2; /* Minimum frame size. */ |
| 1219 | fs->linedefined = line; | ||
| 1220 | fs->kt = lj_tab_new(L, 0, 0); | 1221 | fs->kt = lj_tab_new(L, 0, 0); |
| 1221 | /* Anchor table of constants and prototype (to avoid being collected). */ | 1222 | /* Anchor table of constants and prototype (to avoid being collected). */ |
| 1222 | settabV(L, L->top, fs->kt); | 1223 | settabV(L, L->top, fs->kt); |
| @@ -1333,7 +1334,7 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1333 | BCReg kidx; | 1334 | BCReg kidx; |
| 1334 | t = lj_tab_new(fs->L, 0, 0); | 1335 | t = lj_tab_new(fs->L, 0, 0); |
| 1335 | kidx = const_gc(fs, obj2gco(t), LJ_TTAB); | 1336 | kidx = const_gc(fs, obj2gco(t), LJ_TTAB); |
| 1336 | *proto_insptr(fs->pt, pc) = BCINS_AD(BC_TDUP, freg-1, kidx); | 1337 | fs->bcbase[pc].ins = BCINS_AD(BC_TDUP, freg-1, kidx); |
| 1337 | } | 1338 | } |
| 1338 | vcall = 0; | 1339 | vcall = 0; |
| 1339 | expr_kvalue(&k, &key); | 1340 | expr_kvalue(&k, &key); |
| @@ -1350,14 +1351,15 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1350 | } | 1351 | } |
| 1351 | lex_match(ls, '}', '{', line); | 1352 | lex_match(ls, '}', '{', line); |
| 1352 | if (vcall) { | 1353 | if (vcall) { |
| 1353 | BCIns *i = proto_insptr(fs->pt, fs->pc-1); | 1354 | BCInsLine *ilp = &fs->bcbase[fs->pc-1]; |
| 1354 | ExpDesc en; | 1355 | ExpDesc en; |
| 1355 | lua_assert(bc_a(*i)==freg && bc_op(*i) == (narr>256?BC_TSETV:BC_TSETB)); | 1356 | lua_assert(bc_a(ilp->ins) == freg && |
| 1357 | bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB)); | ||
| 1356 | expr_init(&en, VKNUM, 0); | 1358 | expr_init(&en, VKNUM, 0); |
| 1357 | setintV(&en.u.nval, narr-1); | 1359 | setintV(&en.u.nval, narr-1); |
| 1358 | if (narr > 256) { fs->pc--; i--; } | 1360 | if (narr > 256) { fs->pc--; ilp--; } |
| 1359 | *i = BCINS_AD(BC_TSETM, freg, const_num(fs, &en)); | 1361 | ilp->ins = BCINS_AD(BC_TSETM, freg, const_num(fs, &en)); |
| 1360 | setbc_b(i-1, 0); | 1362 | setbc_b(&ilp[-1].ins, 0); |
| 1361 | } | 1363 | } |
| 1362 | if (pc == fs->pc-1) { /* Make expr relocable if possible. */ | 1364 | if (pc == fs->pc-1) { /* Make expr relocable if possible. */ |
| 1363 | e->u.s.info = pc; | 1365 | e->u.s.info = pc; |
| @@ -1370,15 +1372,14 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1370 | if (!needarr) narr = 0; | 1372 | if (!needarr) narr = 0; |
| 1371 | else if (narr < 3) narr = 3; | 1373 | else if (narr < 3) narr = 3; |
| 1372 | else if (narr > 0x7ff) narr = 0x7ff; | 1374 | else if (narr > 0x7ff) narr = 0x7ff; |
| 1373 | setbc_d(proto_insptr(fs->pt, pc), (uint32_t)narr|(hsize2hbits(nhash)<<11)); | 1375 | setbc_d(&fs->bcbase[pc].ins, (uint32_t)narr|(hsize2hbits(nhash)<<11)); |
| 1374 | } | 1376 | } |
| 1375 | } | 1377 | } |
| 1376 | 1378 | ||
| 1377 | /* Parse function parameters. */ | 1379 | /* Parse function parameters. */ |
| 1378 | static void parse_params(LexState *ls, int needself) | 1380 | static BCReg parse_params(LexState *ls, int needself) |
| 1379 | { | 1381 | { |
| 1380 | FuncState *fs = ls->fs; | 1382 | FuncState *fs = ls->fs; |
| 1381 | GCproto *pt = fs->pt; | ||
| 1382 | BCReg nparams = 0; | 1383 | BCReg nparams = 0; |
| 1383 | lex_check(ls, '('); | 1384 | lex_check(ls, '('); |
| 1384 | if (needself) { | 1385 | if (needself) { |
| @@ -1399,9 +1400,9 @@ static void parse_params(LexState *ls, int needself) | |||
| 1399 | } while (lex_opt(ls, ',')); | 1400 | } while (lex_opt(ls, ',')); |
| 1400 | } | 1401 | } |
| 1401 | var_add(ls, nparams); | 1402 | var_add(ls, nparams); |
| 1402 | pt->numparams = cast_byte(fs->nactvar); | ||
| 1403 | bcreg_reserve(fs, fs->nactvar); | 1403 | bcreg_reserve(fs, fs->nactvar); |
| 1404 | lex_check(ls, ')'); | 1404 | lex_check(ls, ')'); |
| 1405 | return fs->nactvar; | ||
| 1405 | } | 1406 | } |
| 1406 | 1407 | ||
| 1407 | /* Forward declaration. */ | 1408 | /* Forward declaration. */ |
| @@ -1410,18 +1411,23 @@ static void parse_chunk(LexState *ls); | |||
| 1410 | /* Parse body of a function. */ | 1411 | /* Parse body of a function. */ |
| 1411 | static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) | 1412 | static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) |
| 1412 | { | 1413 | { |
| 1413 | FuncState *fs, cfs; | 1414 | FuncState cfs, *fs = ls->fs; |
| 1414 | BCReg kidx; | 1415 | BCReg kidx; |
| 1415 | BCLine lastline; | 1416 | BCLine lastline; |
| 1416 | GCproto *pt; | 1417 | GCproto *pt; |
| 1417 | fs_init(ls, &cfs, line); | 1418 | ptrdiff_t oldbase = fs->bcbase - ls->bcstack; |
| 1418 | parse_params(ls, needself); | 1419 | fs_init(ls, &cfs); |
| 1420 | cfs.linedefined = line; | ||
| 1421 | cfs.numparams = (uint8_t)parse_params(ls, needself); | ||
| 1422 | cfs.bcbase = fs->bcbase + fs->pc; | ||
| 1423 | cfs.bclim = fs->bclim - fs->pc; | ||
| 1419 | parse_chunk(ls); | 1424 | parse_chunk(ls); |
| 1420 | lastline = ls->linenumber; | 1425 | lastline = ls->linenumber; |
| 1421 | lex_match(ls, TK_end, TK_function, line); | 1426 | lex_match(ls, TK_end, TK_function, line); |
| 1422 | pt = fs_finish(ls, lastline); | 1427 | pt = fs_finish(ls, lastline); |
| 1428 | fs->bcbase = ls->bcstack + oldbase; /* May have been reallocated. */ | ||
| 1429 | fs->bclim = ls->sizebcstack - oldbase; | ||
| 1423 | /* Store new prototype in the constant array of the parent. */ | 1430 | /* Store new prototype in the constant array of the parent. */ |
| 1424 | fs = ls->fs; | ||
| 1425 | kidx = const_gc(fs, obj2gco(pt), LJ_TPROTO); | 1431 | kidx = const_gc(fs, obj2gco(pt), LJ_TPROTO); |
| 1426 | expr_init(e, VRELOCABLE, bcemit_AD(fs, BC_FNEW, 0, kidx)); | 1432 | expr_init(e, VRELOCABLE, bcemit_AD(fs, BC_FNEW, 0, kidx)); |
| 1427 | if (!(fs->flags & PROTO_HAS_FNEW)) { | 1433 | if (!(fs->flags & PROTO_HAS_FNEW)) { |
| @@ -1485,7 +1491,7 @@ static void parse_args(LexState *ls, ExpDesc *e) | |||
| 1485 | } | 1491 | } |
| 1486 | expr_init(e, VCALL, bcemit_INS(fs, ins)); | 1492 | expr_init(e, VCALL, bcemit_INS(fs, ins)); |
| 1487 | e->u.s.aux = base; | 1493 | e->u.s.aux = base; |
| 1488 | proto_lineinfo(fs->pt)[fs->pc - 1] = line; | 1494 | fs->bcbase[fs->pc - 1].line = line; |
| 1489 | fs->freereg = base+1; /* Leave one result by default. */ | 1495 | fs->freereg = base+1; /* Leave one result by default. */ |
| 1490 | } | 1496 | } |
| 1491 | 1497 | ||
| @@ -1693,7 +1699,7 @@ static void scope_begin(FuncState *fs, FuncScope *bl, int isbreakable) | |||
| 1693 | { | 1699 | { |
| 1694 | bl->breaklist = NO_JMP; | 1700 | bl->breaklist = NO_JMP; |
| 1695 | bl->isbreakable = (uint8_t)isbreakable; | 1701 | bl->isbreakable = (uint8_t)isbreakable; |
| 1696 | bl->nactvar = fs->nactvar; | 1702 | bl->nactvar = (uint8_t)fs->nactvar; |
| 1697 | bl->upval = 0; | 1703 | bl->upval = 0; |
| 1698 | bl->prev = fs->bl; | 1704 | bl->prev = fs->bl; |
| 1699 | fs->bl = bl; | 1705 | fs->bl = bl; |
| @@ -1766,11 +1772,11 @@ static void parse_return(LexState *ls) | |||
| 1766 | BCReg nret = expr_list(ls, &e); | 1772 | BCReg nret = expr_list(ls, &e); |
| 1767 | if (nret == 1) { /* Return one result. */ | 1773 | if (nret == 1) { /* Return one result. */ |
| 1768 | if (e.k == VCALL) { /* Check for tail call. */ | 1774 | if (e.k == VCALL) { /* Check for tail call. */ |
| 1769 | BCIns *i = bcptr(fs, &e); | 1775 | BCIns *ip = bcptr(fs, &e); |
| 1770 | /* It doesn't pay off to add BC_VARGT just for 'return ...'. */ | 1776 | /* It doesn't pay off to add BC_VARGT just for 'return ...'. */ |
| 1771 | if (bc_op(*i) == BC_VARG) goto notailcall; | 1777 | if (bc_op(*ip) == BC_VARG) goto notailcall; |
| 1772 | fs->pc--; | 1778 | fs->pc--; |
| 1773 | ins = BCINS_AD(bc_op(*i)-BC_CALL+BC_CALLT, bc_a(*i), bc_c(*i)); | 1779 | ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT, bc_a(*ip), bc_c(*ip)); |
| 1774 | } else { /* Can return the result from any register. */ | 1780 | } else { /* Can return the result from any register. */ |
| 1775 | ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); | 1781 | ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); |
| 1776 | } | 1782 | } |
| @@ -1957,7 +1963,7 @@ static void parse_func(LexState *ls, BCLine line) | |||
| 1957 | parse_body(ls, &b, needself, line); | 1963 | parse_body(ls, &b, needself, line); |
| 1958 | fs = ls->fs; | 1964 | fs = ls->fs; |
| 1959 | bcemit_store(fs, &v, &b); | 1965 | bcemit_store(fs, &v, &b); |
| 1960 | proto_lineinfo(fs->pt)[fs->pc - 1] = line; /* Set line for the store. */ | 1966 | fs->bcbase[fs->pc - 1].line = line; /* Set line for the store. */ |
| 1961 | } | 1967 | } |
| 1962 | 1968 | ||
| 1963 | /* -- Loop and conditional statements ------------------------------------- */ | 1969 | /* -- Loop and conditional statements ------------------------------------- */ |
| @@ -2033,9 +2039,9 @@ static void parse_for_body(LexState *ls, BCReg base, BCLine line, | |||
| 2033 | jmp_patchins(fs, loop, fs->pc); | 2039 | jmp_patchins(fs, loop, fs->pc); |
| 2034 | bcemit_ABC(fs, BC_ITERC, base+3, nvars+1, 2+1); | 2040 | bcemit_ABC(fs, BC_ITERC, base+3, nvars+1, 2+1); |
| 2035 | loopend = bcemit_AJ(fs, BC_ITERL, base+3, NO_JMP); | 2041 | loopend = bcemit_AJ(fs, BC_ITERL, base+3, NO_JMP); |
| 2036 | proto_lineinfo(fs->pt)[loopend-1] = line; | 2042 | fs->bcbase[loopend-1].line = line; |
| 2037 | } | 2043 | } |
| 2038 | proto_lineinfo(fs->pt)[loopend] = line; /* Fix line for control ins. */ | 2044 | fs->bcbase[loopend].line = line; /* Fix line for control ins. */ |
| 2039 | jmp_patchins(fs, loopend, loop+1); | 2045 | jmp_patchins(fs, loopend, loop+1); |
| 2040 | } | 2046 | } |
| 2041 | 2047 | ||
| @@ -2210,7 +2216,11 @@ GCproto *lj_parse(LexState *ls) | |||
| 2210 | setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */ | 2216 | setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */ |
| 2211 | incr_top(L); | 2217 | incr_top(L); |
| 2212 | ls->level = 0; | 2218 | ls->level = 0; |
| 2213 | fs_init(ls, &fs, 0); | 2219 | fs_init(ls, &fs); |
| 2220 | fs.linedefined = 0; | ||
| 2221 | fs.numparams = 0; | ||
| 2222 | fs.bcbase = NULL; | ||
| 2223 | fs.bclim = 0; | ||
| 2214 | fs.flags |= PROTO_IS_VARARG; /* Main chunk is always a vararg func. */ | 2224 | fs.flags |= PROTO_IS_VARARG; /* Main chunk is always a vararg func. */ |
| 2215 | lj_lex_next(ls); /* Read-ahead first token. */ | 2225 | lj_lex_next(ls); /* Read-ahead first token. */ |
| 2216 | parse_chunk(ls); | 2226 | parse_chunk(ls); |
