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 | } | ||
