jumps do not close upvalues (to be faster and simpler);

explicit instruction to close upvalues; command 'break' not
handled like a 'goto' (to optimize removal of uneeded 'close'
instructions)
This commit is contained in:
Roberto Ierusalimschy
2017-09-13 16:50:08 -03:00
parent 029d269f4d
commit 80d9b09f35
6 changed files with 139 additions and 67 deletions

51
lcode.c
View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.c,v 2.120 2017/06/27 11:35:31 roberto Exp roberto $
** $Id: lcode.c,v 2.121 2017/06/29 15:06:44 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -272,20 +272,51 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
/*
** Path all jumps in 'list' to close upvalues up to given 'level'
** (The assertion checks that jumps either were closing nothing
** or were closing higher levels, from inner blocks.)
** Check whether some jump in given list needs a close instruction.
*/
void luaK_patchclose (FuncState *fs, int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
int luaK_needclose (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) {
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
if (GETARG_A(fs->f->code[list])) /* needs close? */
return 1;
}
return 0;
}
/*
** Correct a jump list to jump to 'target'. If 'hasclose' is true,
** 'target' contains an OP_CLOSE instruction (see first assert).
** Only jumps with the A arg true need that close; other jumps
** avoid it jumping to the next instruction.
*/
void luaK_patchgoto (FuncState *fs, int list, int target, int hasclose) {
lua_assert(!hasclose || GET_OPCODE(fs->f->code[target]) == OP_CLOSE);
while (list != NO_JUMP) {
int next = getjump(fs, list);
lua_assert(!GETARG_A(fs->f->code[list]) || hasclose);
patchtestreg(fs, list, NO_REG); /* do not generate values */
if (!hasclose || GETARG_A(fs->f->code[list]))
fixjump(fs, list, target);
else /* there is a CLOSE instruction but jump does not need it */
fixjump(fs, list, target + 1); /* avoid CLOSE instruction */
list = next;
}
}
/*
** Mark (using the A arg) all jumps in 'list' to close upvalues. Mark
** will instruct 'luaK_patchgoto' to make these jumps go to OP_CLOSE
** instructions.
*/
void luaK_patchclose (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) {
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP);
SETARG_A(fs->f->code[list], 1);
}
}
#if !defined(MAXIWTHABS)
#define MAXIWTHABS 120
#endif