From 7d4c7ae2af686df4a9f3cc0c6110986d886d55e6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 22 Dec 2022 13:52:53 -0300 Subject: [PATCH] Changes in opcodes for generic 'for' Again, as the control variable is read only, the code doesn't need to keep an internal copy of it. --- lparser.c | 23 +++++++++++------------ lvm.c | 40 +++++++++++++++++++++++++--------------- testes/files.lua | 4 ++-- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lparser.c b/lparser.c index ff6f4009..c0eb7890 100644 --- a/lparser.c +++ b/lparser.c @@ -1558,6 +1558,7 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isgen) { int prep, endfor; checknext(ls, TK_DO); prep = luaK_codeABx(fs, forprep[isgen], base, 0); + fs->freereg--; /* both 'forprep' remove one register from the stack */ enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); @@ -1591,8 +1592,7 @@ static void fornum (LexState *ls, TString *varname, int line) { luaK_int(fs, fs->freereg, 1); luaK_reserveregs(fs, 1); } - adjustlocalvars(ls, 2); /* start scope for internal state variables */ - fs->freereg--; /* OP_FORPREP removes one register from the stack */ + adjustlocalvars(ls, 2); /* start scope for internal variables */ forbody(ls, base, line, 1, 0); } @@ -1601,14 +1601,13 @@ static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist forbody */ FuncState *fs = ls->fs; expdesc e; - int nvars = 5; /* gen, state, control, toclose, 'indexname' */ + int nvars = 4; /* function, state, closing, control */ int line; int base = fs->freereg; - /* create control variables */ - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for state)"); - new_localvarliteral(ls, "(for state)"); + /* create internal variables */ + new_localvarliteral(ls, "(for state)"); /* iterator function */ + new_localvarliteral(ls, "(for state)"); /* state */ + new_localvarliteral(ls, "(for state)"); /* closing var. (after swap) */ new_localvarkind(ls, indexname, RDKCONST); /* control variable */ /* other declared variables */ while (testnext(ls, ',')) { @@ -1618,10 +1617,10 @@ static void forlist (LexState *ls, TString *indexname) { checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 4, explist(ls, &e), &e); - adjustlocalvars(ls, 4); /* control variables */ - marktobeclosed(fs); /* last control var. must be closed */ - luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 4, 1); + adjustlocalvars(ls, 3); /* start scope for internal variables */ + marktobeclosed(fs); /* last internal var. must be closed */ + luaK_checkstack(fs, 2); /* extra space to call iterator */ + forbody(ls, base, line, nvars - 3, 1); } diff --git a/lvm.c b/lvm.c index bdfef434..8ab8753d 100644 --- a/lvm.c +++ b/lvm.c @@ -1806,26 +1806,38 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_TFORPREP) { + /* before: 'ra' has the iterator function, 'ra + 1' has the state, + 'ra + 2' has the initial value for the control variable, and + 'ra + 3' has the closing variable. This opcode then swaps the + control and the closing variables and marks the closing variable + as to-be-closed. + */ StkId ra = RA(i); - /* create to-be-closed upvalue (if needed) */ - halfProtect(luaF_newtbcupval(L, ra + 3)); - pc += GETARG_Bx(i); - i = *(pc++); /* go to next instruction */ + TValue temp; /* to swap control and closing variables */ + setobj(L, &temp, s2v(ra + 3)); + setobjs2s(L, ra + 3, ra + 2); + setobj2s(L, ra + 2, &temp); + /* create to-be-closed upvalue (if closing var. is not nil) */ + halfProtect(luaF_newtbcupval(L, ra + 2)); + pc += GETARG_Bx(i); /* go to end of the loop */ + i = *(pc++); /* fetch next instruction */ lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); goto l_tforcall; } vmcase(OP_TFORCALL) { l_tforcall: { - StkId ra = RA(i); /* 'ra' has the iterator function, 'ra + 1' has the state, - 'ra + 2' has the control variable, and 'ra + 3' has the - to-be-closed variable. The call will use the stack after - these values (starting at 'ra + 4') + 'ra + 2' has the closing variable, and 'ra + 3' has the control + variable. The call will use the stack starting at 'ra + 3', + so that it preserves the first three values, and the first + return will be the new value for the control variable. */ - /* push function, state, and control variable */ - memcpy(ra + 4, ra, 3 * sizeof(*ra)); - L->top.p = ra + 4 + 3; - ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ + StkId ra = RA(i); + setobjs2s(L, ra + 5, ra + 3); /* copy the control variable */ + setobjs2s(L, ra + 4, ra + 1); /* copy state */ + setobjs2s(L, ra + 3, ra); /* copy function */ + L->top.p = ra + 3 + 3; + ProtectNT(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call */ updatestack(ci); /* stack may have changed */ i = *(pc++); /* go to next instruction */ lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); @@ -1834,10 +1846,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmcase(OP_TFORLOOP) { l_tforloop: { StkId ra = RA(i); - if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ - setobjs2s(L, ra + 2, ra + 4); /* save control variable */ + if (!ttisnil(s2v(ra + 3))) /* continue loop? */ pc -= GETARG_Bx(i); /* jump back */ - } vmbreak; }} vmcase(OP_SETLIST) { diff --git a/testes/files.lua b/testes/files.lua index 78f962e5..599644f3 100644 --- a/testes/files.lua +++ b/testes/files.lua @@ -427,12 +427,12 @@ do -- testing closing file in line iteration -- get the to-be-closed variable from a loop local function gettoclose (lv) lv = lv + 1 - local stvar = 0 -- to-be-closed is 4th state variable in the loop + local stvar = 0 -- to-be-closed is 3th state variable in the loop for i = 1, 1000 do local n, v = debug.getlocal(lv, i) if n == "(for state)" then stvar = stvar + 1 - if stvar == 4 then return v end + if stvar == 3 then return v end end end end