diff options
Diffstat (limited to 'lcode.c')
-rw-r--r-- | lcode.c | 91 |
1 files changed, 53 insertions, 38 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.c,v 2.138 2017/11/28 15:26:15 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 2.140 2017/11/30 13:17:06 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 | */ |
@@ -134,17 +134,10 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { | |||
134 | 134 | ||
135 | /* | 135 | /* |
136 | ** Create a jump instruction and return its position, so its destination | 136 | ** Create a jump instruction and return its position, so its destination |
137 | ** can be fixed later (with 'fixjump'). If there are jumps to | 137 | ** can be fixed later (with 'fixjump'). |
138 | ** this position (kept in 'jpc'), link them all together so that | ||
139 | ** 'patchlistaux' will fix all them directly to the final destination. | ||
140 | */ | 138 | */ |
141 | int luaK_jump (FuncState *fs) { | 139 | int luaK_jump (FuncState *fs) { |
142 | int jpc = fs->jpc; /* save list of jumps to here */ | 140 | return codesJ(fs, OP_JMP, NO_JUMP, 0); |
143 | int j; | ||
144 | fs->jpc = NO_JUMP; /* no more jumps to here */ | ||
145 | j = codesJ(fs, OP_JMP, NO_JUMP, 0); | ||
146 | luaK_concat(fs, &j, jpc); /* keep them on hold */ | ||
147 | return j; | ||
148 | } | 141 | } |
149 | 142 | ||
150 | 143 | ||
@@ -250,38 +243,19 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, | |||
250 | 243 | ||
251 | 244 | ||
252 | /* | 245 | /* |
253 | ** Ensure all pending jumps to current position are fixed (jumping | ||
254 | ** to current position with no values) and reset list of pending | ||
255 | ** jumps | ||
256 | */ | ||
257 | static void dischargejpc (FuncState *fs) { | ||
258 | patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); | ||
259 | fs->jpc = NO_JUMP; | ||
260 | } | ||
261 | |||
262 | |||
263 | /* | ||
264 | ** Add elements in 'list' to list of pending jumps to "here" | ||
265 | ** (current position) | ||
266 | */ | ||
267 | void luaK_patchtohere (FuncState *fs, int list) { | ||
268 | luaK_getlabel(fs); /* mark "here" as a jump target */ | ||
269 | luaK_concat(fs, &fs->jpc, list); | ||
270 | } | ||
271 | |||
272 | |||
273 | /* | ||
274 | ** Path all jumps in 'list' to jump to 'target'. | 246 | ** Path all jumps in 'list' to jump to 'target'. |
275 | ** (The assert means that we cannot fix a jump to a forward address | 247 | ** (The assert means that we cannot fix a jump to a forward address |
276 | ** because we only know addresses once code is generated.) | 248 | ** because we only know addresses once code is generated.) |
277 | */ | 249 | */ |
278 | void luaK_patchlist (FuncState *fs, int list, int target) { | 250 | void luaK_patchlist (FuncState *fs, int list, int target) { |
279 | if (target == fs->pc) /* 'target' is current position? */ | 251 | lua_assert(target <= fs->pc); |
280 | luaK_patchtohere(fs, list); /* add list to pending jumps */ | 252 | patchlistaux(fs, list, target, NO_REG, target); |
281 | else { | 253 | } |
282 | lua_assert(target < fs->pc); | 254 | |
283 | patchlistaux(fs, list, target, NO_REG, target); | 255 | |
284 | } | 256 | void luaK_patchtohere (FuncState *fs, int list) { |
257 | int hr = luaK_getlabel(fs); /* mark "here" as a jump target */ | ||
258 | luaK_patchlist(fs, list, hr); | ||
285 | } | 259 | } |
286 | 260 | ||
287 | 261 | ||
@@ -365,7 +339,6 @@ static void savelineinfo (FuncState *fs, Proto *f, int pc, int line) { | |||
365 | */ | 339 | */ |
366 | static int luaK_code (FuncState *fs, Instruction i) { | 340 | static int luaK_code (FuncState *fs, Instruction i) { |
367 | Proto *f = fs->f; | 341 | Proto *f = fs->f; |
368 | dischargejpc(fs); /* 'pc' will change */ | ||
369 | /* put new instruction in code array */ | 342 | /* put new instruction in code array */ |
370 | luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, | 343 | luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, |
371 | MAX_INT, "opcodes"); | 344 | MAX_INT, "opcodes"); |
@@ -1537,3 +1510,45 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { | |||
1537 | fs->freereg = base + 1; /* free registers with list values */ | 1510 | fs->freereg = base + 1; /* free registers with list values */ |
1538 | } | 1511 | } |
1539 | 1512 | ||
1513 | |||
1514 | /* | ||
1515 | ** return the final target of a jump (skipping jumps to jumps) | ||
1516 | */ | ||
1517 | static int finaltarget (Instruction *code, int i) { | ||
1518 | int count; | ||
1519 | for (count = 0; count < 100; count++) { /* avoid infinite loops */ | ||
1520 | Instruction pc = code[i]; | ||
1521 | if (GET_OPCODE(pc) != OP_JMP) | ||
1522 | break; | ||
1523 | else | ||
1524 | i += GETARG_sJ(pc) + 1; | ||
1525 | } | ||
1526 | return i; | ||
1527 | } | ||
1528 | |||
1529 | |||
1530 | /* | ||
1531 | ** Do a final pass over the code of a function, doing small peephole | ||
1532 | ** optimizations and adjustments. | ||
1533 | */ | ||
1534 | void luaK_finish (FuncState *fs) { | ||
1535 | int i; | ||
1536 | Proto *p = fs->f; | ||
1537 | for (i = 0; i < fs->pc; i++) { | ||
1538 | Instruction *pc = &p->code[i]; | ||
1539 | switch (GET_OPCODE(*pc)) { | ||
1540 | case OP_RETURN: case OP_RETURN0: case OP_RETURN1: | ||
1541 | case OP_TAILCALL: { | ||
1542 | if (p->sizep > 0) | ||
1543 | SETARG_k(*pc, 1); /* signal that they must close upvalues */ | ||
1544 | break; | ||
1545 | } | ||
1546 | case OP_JMP: { | ||
1547 | int target = finaltarget(p->code, i); | ||
1548 | fixjump(fs, i, target); | ||
1549 | break; | ||
1550 | } | ||
1551 | default: break; | ||
1552 | } | ||
1553 | } | ||
1554 | } | ||