From d388c165ef79cb9c668e28fa92242ffbc0430e54 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 18 Dec 2017 15:53:50 -0200 Subject: [PATCH] new opcodes 'FORLOOP1'/'FORPREP1' for "basic for" (integer variable with increment of 1) --- lopcodes.c | 6 +++++- lopcodes.h | 6 +++++- lparser.c | 51 ++++++++++++++++++++++++++++++++++++--------------- lvm.c | 28 +++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 18 deletions(-) diff --git a/lopcodes.c b/lopcodes.c index 1d246384..f5896ba0 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.72 2017/12/04 17:41:30 roberto Exp roberto $ +** $Id: lopcodes.c,v 1.73 2017/12/13 18:32:09 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -82,6 +82,8 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "RETURN", "RETURN0", "RETURN1", + "FORLOOP1", + "FORPREP1", "FORLOOP", "FORPREP", "TFORCALL", @@ -160,6 +162,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 0, iABC) /* OP_RETURN */ ,opmode(0, 0, iABC) /* OP_RETURN0 */ ,opmode(0, 0, iABC) /* OP_RETURN1 */ + ,opmode(0, 1, iABx) /* OP_FORLOOP1 */ + ,opmode(0, 1, iABx) /* OP_FORPREP1 */ ,opmode(0, 1, iABx) /* OP_FORLOOP */ ,opmode(0, 1, iABx) /* OP_FORPREP */ ,opmode(0, 0, iABC) /* OP_TFORCALL */ diff --git a/lopcodes.h b/lopcodes.h index c3269dff..ec880703 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.178 2017/12/15 18:35:22 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.179 2017/12/15 18:53:48 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -267,6 +267,10 @@ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ OP_RETURN0,/* return */ OP_RETURN1,/* A return R(A) */ +OP_FORLOOP1,/* A Bx R(A)++; + if R(A) <= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */ +OP_FORPREP1,/* A Bx R(A)--; pc+=Bx */ + OP_FORLOOP,/* A Bx R(A)+=R(A+2); if R(A) fs, &e); lua_assert(e.k == VNONRELOC); + return res; } @@ -1337,29 +1346,37 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) { } -static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { +/* +** Generate code for a 'for' loop. 'kind' can be zero (a common for +** loop), one (a basic for loop, with integer values and increment of +** 1), or two (a generic for loop). +*/ +static void forbody (LexState *ls, int base, int line, int nvars, int kind) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); - prep = isnum ? luaK_codeABx(fs, OP_FORPREP, base, 0) : luaK_jump(fs); + prep = (kind == 0) ? luaK_codeABx(fs, OP_FORPREP, base, 0) + : (kind == 1) ? luaK_codeABx(fs, OP_FORPREP1, base, 0) + : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ - if (isnum) { /* numeric for? */ - fixforjump(fs, prep, luaK_getlabel(fs), 0); - endfor = luaK_codeABx(fs, OP_FORLOOP, base, 0); - } - else { /* generic for */ + if (kind == 2) { /* generic for? */ luaK_patchtohere(fs, prep); luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); luaK_fixline(fs, line); endfor = luaK_codeABx(fs, OP_TFORLOOP, base + 2, 0); } + else { + fixforjump(fs, prep, luaK_getlabel(fs), 0); + endfor = (kind == 0) ? luaK_codeABx(fs, OP_FORLOOP, base, 0) + : luaK_codeABx(fs, OP_FORLOOP1, base, 0); + } fixforjump(fs, endfor, prep + 1, 1); luaK_fixline(fs, line); } @@ -1369,21 +1386,25 @@ static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp,exp[,exp] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; + int basicfor = 1; /* true if it is a "basic" 'for' (integer + 1) */ new_localvarliteral(ls, "(for index)"); new_localvarliteral(ls, "(for limit)"); new_localvarliteral(ls, "(for step)"); new_localvar(ls, varname); checknext(ls, '='); - exp1(ls); /* initial value */ + if (!exp1(ls, 0)) /* initial value not an integer? */ + basicfor = 0; /* not a basic 'for' */ checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ + exp1(ls, 0); /* limit */ + if (testnext(ls, ',')) { + if (!exp1(ls, 1)) /* optional step not 1? */ + basicfor = 0; /* not a basic 'for' */ + } else { /* default step = 1 */ luaK_int(fs, fs->freereg, 1); luaK_reserveregs(fs, 1); } - forbody(ls, base, line, 1, 1); + forbody(ls, base, line, 1, basicfor); } @@ -1408,7 +1429,7 @@ static void forlist (LexState *ls, TString *indexname) { line = ls->linenumber; adjust_assign(ls, 3, explist(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 3, 0); + forbody(ls, base, line, nvars - 3, 2); } diff --git a/lvm.c b/lvm.c index 90fd1060..22d37bbb 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.324 2017/12/04 17:41:30 roberto Exp roberto $ +** $Id: lvm.c,v 2.326 2017/12/18 17:49:31 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -1564,6 +1564,32 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } return; } + vmcase(OP_FORLOOP1) { + lua_Integer idx = intop(+, ivalue(vra), 1); /* increment index */ + lua_Integer limit = ivalue(s2v(ra + 1)); + if (idx <= limit) { + pc -= GETARG_Bx(i); /* jump back */ + chgivalue(vra, idx); /* update internal index... */ + setivalue(s2v(ra + 3), idx); /* ...and external index */ + } + updatetrap(ci); + vmbreak; + } + vmcase(OP_FORPREP1) { + TValue *init = vra; + TValue *plimit = s2v(ra + 1); + lua_Integer ilimit, initv; + int stopnow; + if (!forlimit(plimit, &ilimit, 1, &stopnow)) { + savepc(L); /* for the error message */ + luaG_runerror(L, "'for' limit must be a number"); + } + initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, 1)); + pc += GETARG_Bx(i); + vmbreak; + } vmcase(OP_FORLOOP) { if (ttisinteger(vra)) { /* integer loop? */ lua_Integer step = ivalue(s2v(ra + 2));