diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-05-10 16:22:11 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-05-10 16:22:11 -0300 |
commit | 2dadc8182282afa4b1fe6e6287704a54cd8e5123 (patch) | |
tree | 933eef764dba4636de1e8afcde10e0dc9a052f33 | |
parent | b487975344ee90c0410e79e1af08461bdbc0f3da (diff) | |
download | lua-2dadc8182282afa4b1fe6e6287704a54cd8e5123.tar.gz lua-2dadc8182282afa4b1fe6e6287704a54cd8e5123.tar.bz2 lua-2dadc8182282afa4b1fe6e6287704a54cd8e5123.zip |
cleaner implementation of code generation for jumps
-rw-r--r-- | lcode.c | 65 | ||||
-rw-r--r-- | lcode.h | 4 | ||||
-rw-r--r-- | lparser.c | 26 | ||||
-rw-r--r-- | lparser.h | 4 |
4 files changed, 46 insertions, 53 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.c,v 1.100 2002/05/09 14:14:34 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 1.101 2002/05/10 17:02:32 roberto Exp roberto $ |
3 | ** Code generator for Lua | 3 | ** Code generator for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -39,58 +39,48 @@ void luaK_nil (FuncState *fs, int from, int n) { | |||
39 | } | 39 | } |
40 | 40 | ||
41 | 41 | ||
42 | void luaK_moveexp (expdesc *e, int offset) { | ||
43 | if (e->t != NO_JUMP) e->t += offset; | ||
44 | if (e->f != NO_JUMP) e->f += offset; | ||
45 | if (e->k == VRELOCABLE || e->k == VJMP) e->info += offset; | ||
46 | } | ||
47 | |||
48 | |||
49 | int luaK_jump (FuncState *fs) { | 42 | int luaK_jump (FuncState *fs) { |
50 | int j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); | 43 | int jpc = fs->jpc; /* save list of jumps to here */ |
51 | if (j == fs->lasttarget) { /* possible jumps to this jump? */ | 44 | int j; |
52 | luaK_concat(fs, &j, fs->jlt); /* keep them on hold */ | 45 | fs->jpc = NO_JUMP; |
53 | fs->jlt = NO_JUMP; | 46 | j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); |
54 | } | 47 | luaK_concat(fs, &j, jpc); /* keep them on hold */ |
55 | return j; | 48 | return j; |
56 | } | 49 | } |
57 | 50 | ||
58 | 51 | ||
59 | static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { | 52 | static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) { |
60 | luaK_codeABC(fs, op, A, B, C); | 53 | luaK_codeABC(fs, op, A, B, C); |
61 | return luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); | 54 | return luaK_jump(fs); |
62 | } | 55 | } |
63 | 56 | ||
64 | 57 | ||
65 | static void luaK_fixjump (FuncState *fs, int pc, int dest) { | 58 | static void luaK_fixjump (FuncState *fs, int pc, int dest) { |
66 | Instruction *jmp = &fs->f->code[pc]; | 59 | Instruction *jmp = &fs->f->code[pc]; |
67 | if (dest == NO_JUMP) | 60 | int offset = dest-(pc+1); |
68 | SETARG_sBx(*jmp, NO_JUMP); /* point to itself to represent end of list */ | 61 | lua_assert(dest != NO_JUMP); |
69 | else { /* jump is relative to position following jump instruction */ | 62 | if (abs(offset) > MAXARG_sBx) |
70 | int offset = dest-(pc+1); | 63 | luaX_syntaxerror(fs->ls, "control structure too long"); |
71 | if (abs(offset) > MAXARG_sBx) | 64 | SETARG_sBx(*jmp, offset); |
72 | luaX_syntaxerror(fs->ls, "control structure too long"); | ||
73 | SETARG_sBx(*jmp, offset); | ||
74 | } | ||
75 | } | 65 | } |
76 | 66 | ||
77 | 67 | ||
78 | /* | 68 | /* |
79 | ** returns current `pc' and marks it as a jump target (to avoid wrong | 69 | ** returns current `pc' and marks it as a jump target (to avoid wrong |
80 | ** optimizations with consecutive instructions not in the same basic block). | 70 | ** optimizations with consecutive instructions not in the same basic block). |
81 | ** discharge list of jumps to last target. | ||
82 | */ | 71 | */ |
83 | int luaK_getlabel (FuncState *fs) { | 72 | int luaK_getlabel (FuncState *fs) { |
84 | if (fs->pc != fs->lasttarget) { | 73 | fs->lasttarget = fs->pc; |
85 | int lasttarget = fs->lasttarget; | ||
86 | fs->lasttarget = fs->pc; | ||
87 | luaK_patchlist(fs, fs->jlt, lasttarget); /* discharge old list `jlt' */ | ||
88 | fs->jlt = NO_JUMP; /* nobody jumps to this new label (yet) */ | ||
89 | } | ||
90 | return fs->pc; | 74 | return fs->pc; |
91 | } | 75 | } |
92 | 76 | ||
93 | 77 | ||
78 | void luaK_dischargejpc (FuncState *fs) { | ||
79 | luaK_patchlist(fs, fs->jpc, fs->pc); /* discharge old list `jpc' */ | ||
80 | fs->jpc = NO_JUMP; | ||
81 | } | ||
82 | |||
83 | |||
94 | static int luaK_getjump (FuncState *fs, int pc) { | 84 | static int luaK_getjump (FuncState *fs, int pc) { |
95 | int offset = GETARG_sBx(fs->f->code[pc]); | 85 | int offset = GETARG_sBx(fs->f->code[pc]); |
96 | if (offset == NO_JUMP) /* point to itself represents end of list */ | 86 | if (offset == NO_JUMP) /* point to itself represents end of list */ |
@@ -155,20 +145,20 @@ static void luaK_patchlistaux (FuncState *fs, int list, | |||
155 | 145 | ||
156 | 146 | ||
157 | void luaK_patchlist (FuncState *fs, int list, int target) { | 147 | void luaK_patchlist (FuncState *fs, int list, int target) { |
158 | if (target == fs->lasttarget) /* same target that list `jlt'? */ | 148 | lua_assert(target <= fs->pc); |
159 | luaK_concat(fs, &fs->jlt, list); /* delay fixing */ | 149 | luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); |
160 | else | ||
161 | luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); | ||
162 | } | 150 | } |
163 | 151 | ||
164 | 152 | ||
165 | void luaK_patchtohere (FuncState *fs, int list) { | 153 | void luaK_patchtohere (FuncState *fs, int list) { |
166 | luaK_patchlist(fs, list, luaK_getlabel(fs)); | 154 | luaK_getlabel(fs); |
155 | luaK_concat(fs, &fs->jpc, list); | ||
167 | } | 156 | } |
168 | 157 | ||
169 | 158 | ||
170 | void luaK_concat (FuncState *fs, int *l1, int l2) { | 159 | void luaK_concat (FuncState *fs, int *l1, int l2) { |
171 | if (*l1 == NO_JUMP) | 160 | if (l2 == NO_JUMP) return; |
161 | else if (*l1 == NO_JUMP) | ||
172 | *l1 = l2; | 162 | *l1 = l2; |
173 | else { | 163 | else { |
174 | int list = *l1; | 164 | int list = *l1; |
@@ -508,7 +498,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { | |||
508 | break; | 498 | break; |
509 | } | 499 | } |
510 | case VFALSE: { | 500 | case VFALSE: { |
511 | pc = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); /* always jump */ | 501 | pc = luaK_jump(fs); /* always jump */ |
512 | break; | 502 | break; |
513 | } | 503 | } |
514 | case VJMP: { | 504 | case VJMP: { |
@@ -534,7 +524,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) { | |||
534 | break; | 524 | break; |
535 | } | 525 | } |
536 | case VTRUE: { | 526 | case VTRUE: { |
537 | pc = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); /* always jump */ | 527 | pc = luaK_jump(fs); /* always jump */ |
538 | break; | 528 | break; |
539 | } | 529 | } |
540 | case VJMP: { | 530 | case VJMP: { |
@@ -737,6 +727,7 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { | |||
737 | int luaK_code (FuncState *fs, Instruction i, int line) { | 727 | int luaK_code (FuncState *fs, Instruction i, int line) { |
738 | Proto *f = fs->f; | 728 | Proto *f = fs->f; |
739 | int oldsize = f->sizecode; | 729 | int oldsize = f->sizecode; |
730 | luaK_dischargejpc(fs); /* `pc' will change */ | ||
740 | /* put new instruction in code array */ | 731 | /* put new instruction in code array */ |
741 | luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, | 732 | luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, |
742 | MAX_INT, "code size overflow"); | 733 | MAX_INT, "code size overflow"); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.h,v 1.33 2002/05/07 17:36:56 roberto Exp roberto $ | 2 | ** $Id: lcode.h,v 1.34 2002/05/10 17:02:32 roberto Exp roberto $ |
3 | ** Code generator for Lua | 3 | ** Code generator for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -55,12 +55,12 @@ void luaK_exp2val (FuncState *fs, expdesc *e); | |||
55 | int luaK_exp2RK (FuncState *fs, expdesc *e); | 55 | int luaK_exp2RK (FuncState *fs, expdesc *e); |
56 | void luaK_self (FuncState *fs, expdesc *e, expdesc *key); | 56 | void luaK_self (FuncState *fs, expdesc *e, expdesc *key); |
57 | void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); | 57 | void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); |
58 | void luaK_moveexp (expdesc *e, int offset); | ||
59 | void luaK_goiftrue (FuncState *fs, expdesc *e); | 58 | void luaK_goiftrue (FuncState *fs, expdesc *e); |
60 | void luaK_goiffalse (FuncState *fs, expdesc *e); | 59 | void luaK_goiffalse (FuncState *fs, expdesc *e); |
61 | void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); | 60 | void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); |
62 | void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); | 61 | void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); |
63 | int luaK_jump (FuncState *fs); | 62 | int luaK_jump (FuncState *fs); |
63 | void luaK_dischargejpc (FuncState *fs); | ||
64 | void luaK_patchlist (FuncState *fs, int list, int target); | 64 | void luaK_patchlist (FuncState *fs, int list, int target); |
65 | void luaK_patchtohere (FuncState *fs, int list); | 65 | void luaK_patchtohere (FuncState *fs, int list); |
66 | void luaK_concat (FuncState *fs, int *l1, int l2); | 66 | void luaK_concat (FuncState *fs, int *l1, int l2); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.c,v 1.179 2002/05/07 17:36:56 roberto Exp roberto $ | 2 | ** $Id: lparser.c,v 1.180 2002/05/10 17:02:32 roberto Exp roberto $ |
3 | ** Lua Parser | 3 | ** Lua Parser |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -367,7 +367,7 @@ static void open_func (LexState *ls, FuncState *fs) { | |||
367 | ls->fs = fs; | 367 | ls->fs = fs; |
368 | fs->pc = 0; | 368 | fs->pc = 0; |
369 | fs->lasttarget = 0; | 369 | fs->lasttarget = 0; |
370 | fs->jlt = NO_JUMP; | 370 | fs->jpc = NO_JUMP; |
371 | fs->freereg = 0; | 371 | fs->freereg = 0; |
372 | fs->nk = 0; | 372 | fs->nk = 0; |
373 | fs->h = luaH_new(ls->L, 0, 0); | 373 | fs->h = luaH_new(ls->L, 0, 0); |
@@ -391,7 +391,6 @@ static void close_func (LexState *ls) { | |||
391 | Proto *f = fs->f; | 391 | Proto *f = fs->f; |
392 | removevars(ls, 0); | 392 | removevars(ls, 0); |
393 | luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ | 393 | luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */ |
394 | luaK_getlabel(fs); /* close eventual list of pending jumps */ | ||
395 | lua_assert(G(L)->roottable == fs->h); | 394 | lua_assert(G(L)->roottable == fs->h); |
396 | G(L)->roottable = fs->h->next; | 395 | G(L)->roottable = fs->h->next; |
397 | luaH_free(L, fs->h); | 396 | luaH_free(L, fs->h); |
@@ -977,30 +976,33 @@ static void whilestat (LexState *ls, int line) { | |||
977 | int i; | 976 | int i; |
978 | int sizeexp; | 977 | int sizeexp; |
979 | FuncState *fs = ls->fs; | 978 | FuncState *fs = ls->fs; |
980 | int while_init = luaK_getlabel(fs); | 979 | int whileinit, blockinit, expinit; |
981 | expdesc v; | 980 | expdesc v; |
982 | BlockCnt bl; | 981 | BlockCnt bl; |
983 | next(ls); | 982 | next(ls); |
983 | whileinit = luaK_jump(fs); | ||
984 | expinit = luaK_getlabel(fs); | ||
984 | expr(ls, &v); | 985 | expr(ls, &v); |
985 | if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ | 986 | if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */ |
986 | lineexp = ls->linenumber; | 987 | lineexp = ls->linenumber; |
987 | luaK_goiffalse(fs, &v); | 988 | luaK_goiffalse(fs, &v); |
988 | sizeexp = fs->pc - while_init; | 989 | luaK_dischargejpc(fs); |
990 | sizeexp = fs->pc - expinit; | ||
989 | if (sizeexp > MAXEXPWHILE) | 991 | if (sizeexp > MAXEXPWHILE) |
990 | luaX_syntaxerror(ls, "while condition too complex"); | 992 | luaX_syntaxerror(ls, "while condition too complex"); |
991 | fs->pc = while_init; /* remove `exp' code */ | ||
992 | luaK_getlabel(fs); | ||
993 | for (i = 0; i < sizeexp; i++) /* save `exp' code */ | 993 | for (i = 0; i < sizeexp; i++) /* save `exp' code */ |
994 | codeexp[i] = fs->f->code[while_init + i]; | 994 | codeexp[i] = fs->f->code[expinit + i]; |
995 | luaK_jump(fs); | 995 | fs->pc = expinit; /* remove `exp' code */ |
996 | enterblock(fs, &bl, 1); | 996 | enterblock(fs, &bl, 1); |
997 | check(ls, TK_DO); | 997 | check(ls, TK_DO); |
998 | blockinit = luaK_getlabel(fs); | ||
998 | block(ls); | 999 | block(ls); |
999 | luaK_patchtohere(fs, while_init); /* initial jump jumps to here */ | 1000 | luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */ |
1000 | luaK_moveexp(&v, fs->pc - while_init); /* correct pointers */ | 1001 | if (v.t != NO_JUMP) v.t += fs->pc - expinit; |
1002 | if (v.f != NO_JUMP) v.f += fs->pc - expinit; | ||
1001 | for (i=0; i<sizeexp; i++) | 1003 | for (i=0; i<sizeexp; i++) |
1002 | luaK_code(fs, codeexp[i], lineexp); | 1004 | luaK_code(fs, codeexp[i], lineexp); |
1003 | luaK_patchlist(fs, v.t, while_init+1); | 1005 | luaK_patchlist(fs, v.t, blockinit); |
1004 | luaK_patchtohere(fs, v.f); | 1006 | luaK_patchtohere(fs, v.f); |
1005 | check_match(ls, TK_END, TK_WHILE, line); | 1007 | check_match(ls, TK_END, TK_WHILE, line); |
1006 | leaveblock(fs); | 1008 | leaveblock(fs); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lparser.h,v 1.41 2002/03/25 17:47:14 roberto Exp roberto $ | 2 | ** $Id: lparser.h,v 1.42 2002/05/09 18:00:38 roberto Exp roberto $ |
3 | ** Lua Parser | 3 | ** Lua Parser |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -63,7 +63,7 @@ typedef struct FuncState { | |||
63 | struct BlockCnt *bl; /* chain of current blocks */ | 63 | struct BlockCnt *bl; /* chain of current blocks */ |
64 | int pc; /* next position to code (equivalent to `ncode') */ | 64 | int pc; /* next position to code (equivalent to `ncode') */ |
65 | int lasttarget; /* `pc' of last `jump target' */ | 65 | int lasttarget; /* `pc' of last `jump target' */ |
66 | int jlt; /* list of jumps to `lasttarget' */ | 66 | int jpc; /* list of jumps to `pc' */ |
67 | int freereg; /* first free register */ | 67 | int freereg; /* first free register */ |
68 | int defaultglob; /* where to look for non-declared globals */ | 68 | int defaultglob; /* where to look for non-declared globals */ |
69 | int nk; /* number of elements in `k' */ | 69 | int nk; /* number of elements in `k' */ |