some simplifications/optimizations in returns from Lua functions

This commit is contained in:
Roberto Ierusalimschy 2018-02-15 13:34:29 -02:00
parent b1379936cf
commit 0682fe8169
7 changed files with 80 additions and 77 deletions

32
lcode.c
View File

@ -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: {

24
ldo.c
View File

@ -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);
}

5
ldo.h
View File

@ -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);

View File

@ -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 */

View File

@ -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)

10
ltm.c
View File

@ -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;

60
lvm.c
View File

@ -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 {