From 0682fe816929da2e5abe8e191ad9c8509e6bfc12 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 15 Feb 2018 13:34:29 -0200 Subject: [PATCH] some simplifications/optimizations in returns from Lua functions --- lcode.c | 32 ++++++++++++++++------------- ldo.c | 24 ++++++++++++++-------- ldo.h | 5 +---- lopcodes.c | 4 +--- lopcodes.h | 22 +++++++++++--------- ltm.c | 10 +++++---- lvm.c | 60 +++++++++++++++++++++++------------------------------- 7 files changed, 80 insertions(+), 77 deletions(-) diff --git a/lcode.c b/lcode.c index 25fb0770..eb5a2c82 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.152 2018/01/28 15:13:26 roberto Exp roberto $ +** $Id: lcode.c,v 2.153 2018/02/09 15:16:06 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -158,16 +158,12 @@ int luaK_jump (FuncState *fs) { */ void luaK_ret (FuncState *fs, int first, int nret) { OpCode op; - if (fs->f->is_vararg) - op = OP_RETVARARG; - else { - switch (nret) { - case 0: op = OP_RETURN0; break; - case 1: op = OP_RETURN1; break; - default: op = OP_RETURN; break; - } + switch (nret) { + case 0: op = OP_RETURN0; break; + case 1: op = OP_RETURN1; break; + default: op = OP_RETURN; break; } - luaK_codeABC(fs, op, first, nret + 1, fs->f->numparams); + luaK_codeABC(fs, op, first, nret + 1, 0); } @@ -1646,10 +1642,18 @@ void luaK_finish (FuncState *fs) { Instruction *pc = &p->code[i]; lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); switch (GET_OPCODE(*pc)) { - case OP_RETURN: case OP_RETURN0: case OP_RETURN1: - case OP_RETVARARG: case OP_TAILCALL: { - if (p->sizep > 0) - SETARG_k(*pc, 1); /* signal that they must close upvalues */ + case OP_RETURN0: case OP_RETURN1: { + if (p->sizep == 0 && !p->is_vararg) + break; /* no extra work */ + /* else use OP_RETURN to do the extra work */ + SET_OPCODE(*pc, OP_RETURN); + /* FALLTHROUGH */ + } + case OP_RETURN: case OP_TAILCALL: { + if (p->sizep > 0 || p->is_vararg) { + SETARG_C(*pc, p->is_vararg ? p->numparams + 1 : 0); + SETARG_k(*pc, 1); /* signal that there is extra work */ + } break; } case OP_JMP: { diff --git a/ldo.c b/ldo.c index 64512487..19d6aefd 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.192 2018/02/07 15:55:18 roberto Exp roberto $ +** $Id: ldo.c,v 2.193 2018/02/09 15:16:06 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -310,11 +310,19 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) { } -void luaD_rethook (lua_State *L, CallInfo *ci) { - if (isLuacode(ci)) +static void rethook (lua_State *L, CallInfo *ci) { + int delta = 0; + if (isLuacode(ci)) { + Proto *p = clLvalue(s2v(ci->func))->p; + if (p->is_vararg) + delta = ci->u.l.nextraargs + p->numparams + 1; L->top = ci->top; /* prepare top */ - if (L->hookmask & LUA_MASKRET) /* is return hook on? */ + } + if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ + ci->func += delta; /* if vararg, back to virtual 'func' */ luaD_hook(L, LUA_HOOKRET, -1); /* call it */ + ci->func -= delta; + } if (isLua(ci->previous)) L->oldpc = ci->previous->u.l.savedpc; /* update 'oldpc' */ } @@ -343,8 +351,8 @@ void luaD_tryfuncTM (lua_State *L, StkId func) { ** expressions, multiple results for tail calls/single parameters) ** separated. */ -void luaD_moveresults (lua_State *L, StkId firstResult, StkId res, - int nres, int wanted) { +static void moveresults (lua_State *L, StkId firstResult, StkId res, + int nres, int wanted) { switch (wanted) { /* handle typical cases separately */ case 0: break; /* nothing to move */ case 1: { /* one result needed */ @@ -387,12 +395,12 @@ void luaD_moveresults (lua_State *L, StkId firstResult, StkId res, void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { if (L->hookmask) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ - luaD_rethook(L, ci); + rethook(L, ci); firstResult = restorestack(L, fr); } L->ci = ci->previous; /* back to caller */ /* move results to proper place */ - luaD_moveresults(L, firstResult, ci->func, nres, ci->nresults); + moveresults(L, firstResult, ci->func, nres, ci->nresults); } diff --git a/ldo.h b/ldo.h index 864cf3e6..9d976b32 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.40 2018/02/06 19:16:56 roberto Exp roberto $ +** $Id: ldo.h,v 2.41 2018/02/09 15:16:06 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -62,10 +62,7 @@ LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres); -LUAI_FUNC void luaD_rethook (lua_State *L, CallInfo *ci); LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); -LUAI_FUNC void luaD_moveresults (lua_State *L, StkId firstResult, StkId res, - int nres, int wanted); LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_inctop (lua_State *L); diff --git a/lopcodes.c b/lopcodes.c index d04e707f..aa3055be 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.76 2018/02/07 15:18:04 roberto Exp roberto $ +** $Id: lopcodes.c,v 1.77 2018/02/09 15:16:06 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -80,7 +80,6 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "CALL", "TAILCALL", "RETURN", - "RETVARARG", "RETURN0", "RETURN1", "FORLOOP1", @@ -162,7 +161,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(1, 1, 0, 1, iABC) /* OP_CALL */ ,opmode(1, 1, 0, 1, iABC) /* OP_TAILCALL */ ,opmode(0, 1, 0, 0, iABC) /* OP_RETURN */ - ,opmode(0, 1, 0, 0, iABC) /* OP_RETVARARG */ ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN0 */ ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN1 */ ,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP1 */ diff --git a/lopcodes.h b/lopcodes.h index 3c7a9573..b2e22c27 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.186 2018/02/07 15:18:04 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.187 2018/02/09 15:16:06 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -267,8 +267,7 @@ OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ -OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ -OP_RETVARARG,/* A B return R(A), ... ,R(A+B-2) (see note) */ +OP_RETURN,/* A B C return R(A), ... ,R(A+B-2) (see note) */ OP_RETURN0,/* return */ OP_RETURN1,/* A return R(A) */ @@ -302,14 +301,13 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ /*=========================================================================== Notes: (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is - set to last_result+1, so next open instruction (OP_CALL, OP_RETURN, + set to last_result+1, so next open instruction (OP_CALL, OP_RETURN*, OP_SETLIST) may use 'top'. (*) In OP_VARARG, if (C == 0) then use actual number of varargs and set top (like in OP_CALL with C == 0). - (*) In OP_RETURN/OP_RETVARARG, if (B == 0) then return up to 'top'. - (OP_RETVARARG is the return instruction for vararg functions.) + (*) In OP_RETURN, if (B == 0) then return up to 'top'. (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). @@ -326,9 +324,11 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) All 'skips' (pc++) assume that next instruction is a jump. - (*) In instructions ending a function (OP_RETURN*, OP_TAILCALL), k - specifies that the function builds upvalues, which may need to be - closed. + (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the + function either builds upvalues, which may need to be closed, or is + vararg, which must be corrected before returning. When 'k' is true, + C > 0 means the function is vararg and (C - 1) is its number of + fixed parameters. ===========================================================================*/ @@ -351,7 +351,9 @@ LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; #define testOTMode(m) (luaP_opmodes[m] & (1 << 6)) /* "out top" (set top for next instruction) */ -#define isOT(i) (testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) +#define isOT(i) \ + ((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \ + GET_OPCODE(i) == OP_TAILCALL) /* "in top" (uses top from previous instruction) */ #define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0) diff --git a/ltm.c b/ltm.c index d88b636b..be7dc4f0 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.59 2018/02/07 15:18:04 roberto Exp roberto $ +** $Id: ltm.c,v 2.60 2018/02/09 15:16:06 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -222,10 +222,12 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci) { int nextra = actual - nfixparams; /* number of extra arguments */ ci->u.l.nextraargs = nextra; checkstackGC(L, nfixparams + 1); - /* copy function and fixed parameters to the top of the stack */ - for (i = 0; i <= nfixparams; i++) { + /* copy function to the top of the stack */ + setobjs2s(L, L->top++, ci->func); + /* move fixed parameters to the top of the stack */ + for (i = 1; i <= nfixparams; i++) { setobjs2s(L, L->top++, ci->func + i); - setnilvalue(s2v(ci->func + i)); /* erase original copy (for GC) */ + setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */ } ci->func += actual + 1; ci->top += actual + 1; diff --git a/lvm.c b/lvm.c index 2d01e4c1..0cc3a0b9 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.338 2018/02/07 15:18:04 roberto Exp roberto $ +** $Id: lvm.c,v 2.339 2018/02/09 15:16:06 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -1493,23 +1493,35 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } vmcase(OP_TAILCALL) { int b = GETARG_B(i); /* number of arguments + 1 (function) */ + int delta = 0; /* virtual 'func' - real 'func' (vararg functions) */ if (b != 0) L->top = ra + b; else /* previous instruction set top */ b = cast_int(L->top - ra); - lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + savepc(ci); + if (TESTARG_k(i)) { + int nparams1 = GETARG_C(i); + if (nparams1) /* vararg function? */ + delta = ci->u.l.nextraargs + nparams1; + luaF_close(L, base); /* close upvalues from current call */ + } if (!ttisfunction(vra)) { /* not a function? */ - ProtectNT(luaD_tryfuncTM(L, ra)); /* try '__call' metamethod */ + luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ b++; /* there is now one extra argument */ } - if (TESTARG_k(i)) - luaF_close(L, base); /* close upvalues from current call */ if (!ttisLclosure(vra)) { /* C function? */ - ProtectNT(luaD_call(L, ra, LUA_MULTRET)); /* call it */ + luaD_call(L, ra, LUA_MULTRET); /* call it */ + updatetrap(ci); + if (trap) { /* stack may have been relocated */ + updatebase(ci); + ra = RA(i); + } + ci->func -= delta; + luaD_poscall(L, ci, ra, cast_int(L->top - ra)); + return; } else { /* Lua tail call */ - if (cl->p->is_vararg) - ci->func -= cl->p->numparams + ci->u.l.nextraargs + 1; + ci->func -= delta; luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ goto tailcall; } @@ -1518,34 +1530,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmcase(OP_RETURN) { int b = GETARG_B(i); int n = (b != 0 ? b - 1 : cast_int(L->top - ra)); - if (TESTARG_k(i)) - luaF_close(L, base); + if (TESTARG_k(i)) { + int nparams1 = GETARG_C(i); + if (nparams1) /* vararg function? */ + ci->func -= ci->u.l.nextraargs + nparams1; + luaF_close(L, base); /* there may be open upvalues */ + } halfProtect(luaD_poscall(L, ci, ra, n)); return; } - vmcase(OP_RETVARARG) { - int b = GETARG_B(i); - int nparams = GETARG_C(i); - int nres = (b != 0 ? b - 1 : cast_int(L->top - ra)); - int delta = ci->u.l.nextraargs + nparams + 2; - if (TESTARG_k(i)) - luaF_close(L, base); - savepc(L); - /* code similar to 'luaD_poscall', but with a delta */ - if (L->hookmask) { - luaD_rethook(L, ci); - if (ci->u.l.trap) { - updatebase(ci); - ra = RA(i); - } - } - L->ci = ci->previous; /* back to caller */ - luaD_moveresults(L, ra, base - delta, nres, ci->nresults); - return; - } vmcase(OP_RETURN0) { - if (TESTARG_k(i)) - luaF_close(L, base); if (L->hookmask) halfProtect(luaD_poscall(L, ci, ra, 0)); /* no hurry... */ else { @@ -1558,8 +1552,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) { return; } vmcase(OP_RETURN1) { - if (TESTARG_k(i)) - luaF_close(L, base); if (L->hookmask) halfProtect(luaD_poscall(L, ci, ra, 1)); /* no hurry... */ else {