diff options
author | Mike Pall <mike> | 2010-02-08 05:28:57 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-02-08 05:28:57 +0100 |
commit | 4424027844bdcdb76e90e0994efafeee7ea5cc1f (patch) | |
tree | c23e3595ae292e669cb39b8d377e790df57c9591 /src | |
parent | 48d93d8c84eb72e720d90ed7861f353a2c417470 (diff) | |
download | luajit-4424027844bdcdb76e90e0994efafeee7ea5cc1f.tar.gz luajit-4424027844bdcdb76e90e0994efafeee7ea5cc1f.tar.bz2 luajit-4424027844bdcdb76e90e0994efafeee7ea5cc1f.zip |
Redesign of prototype generation, part 3: bc and lineinfo.
Use a growable, per-chunk bytecode instruction/line stack.
Collect bc/lineinfo for prototype at the end.
Diffstat (limited to 'src')
-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); |