1
0
mirror of https://github.com/lua/lua.git synced 2025-01-28 06:03:00 +08:00

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 ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -158,16 +158,12 @@ int luaK_jump (FuncState *fs) {
*/ */
void luaK_ret (FuncState *fs, int first, int nret) { void luaK_ret (FuncState *fs, int first, int nret) {
OpCode op; OpCode op;
if (fs->f->is_vararg) switch (nret) {
op = OP_RETVARARG; case 0: op = OP_RETURN0; break;
else { case 1: op = OP_RETURN1; break;
switch (nret) { default: op = OP_RETURN; break;
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]; Instruction *pc = &p->code[i];
lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc));
switch (GET_OPCODE(*pc)) { switch (GET_OPCODE(*pc)) {
case OP_RETURN: case OP_RETURN0: case OP_RETURN1: case OP_RETURN0: case OP_RETURN1: {
case OP_RETVARARG: case OP_TAILCALL: { if (p->sizep == 0 && !p->is_vararg)
if (p->sizep > 0) break; /* no extra work */
SETARG_k(*pc, 1); /* signal that they must close upvalues */ /* 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; break;
} }
case OP_JMP: { 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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** 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) { static void rethook (lua_State *L, CallInfo *ci) {
if (isLuacode(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 */ 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 */ luaD_hook(L, LUA_HOOKRET, -1); /* call it */
ci->func -= delta;
}
if (isLua(ci->previous)) if (isLua(ci->previous))
L->oldpc = ci->previous->u.l.savedpc; /* update 'oldpc' */ 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) ** expressions, multiple results for tail calls/single parameters)
** separated. ** separated.
*/ */
void luaD_moveresults (lua_State *L, StkId firstResult, StkId res, static void moveresults (lua_State *L, StkId firstResult, StkId res,
int nres, int wanted) { int nres, int wanted) {
switch (wanted) { /* handle typical cases separately */ switch (wanted) { /* handle typical cases separately */
case 0: break; /* nothing to move */ case 0: break; /* nothing to move */
case 1: { /* one result needed */ 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) { void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
if (L->hookmask) { if (L->hookmask) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_rethook(L, ci); rethook(L, ci);
firstResult = restorestack(L, fr); firstResult = restorestack(L, fr);
} }
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
/* move results to proper place */ /* 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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** 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); ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
int nres); 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 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 int luaD_growstack (lua_State *L, int n, int raiseerror);
LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (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 ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -80,7 +80,6 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"CALL", "CALL",
"TAILCALL", "TAILCALL",
"RETURN", "RETURN",
"RETVARARG",
"RETURN0", "RETURN0",
"RETURN1", "RETURN1",
"FORLOOP1", "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_CALL */
,opmode(1, 1, 0, 1, iABC) /* OP_TAILCALL */ ,opmode(1, 1, 0, 1, iABC) /* OP_TAILCALL */
,opmode(0, 1, 0, 0, iABC) /* OP_RETURN */ ,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_RETURN0 */
,opmode(0, 0, 0, 0, iABC) /* OP_RETURN1 */ ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN1 */
,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP1 */ ,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 ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** 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_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_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_RETURN,/* A B C return R(A), ... ,R(A+B-2) (see note) */
OP_RETVARARG,/* A B return R(A), ... ,R(A+B-2) (see note) */
OP_RETURN0,/* return */ OP_RETURN0,/* return */
OP_RETURN1,/* A return R(A) */ OP_RETURN1,/* A return R(A) */
@ -302,14 +301,13 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
/*=========================================================================== /*===========================================================================
Notes: Notes:
(*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is (*) 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'. OP_SETLIST) may use 'top'.
(*) In OP_VARARG, if (C == 0) then use actual number of varargs and (*) In OP_VARARG, if (C == 0) then use actual number of varargs and
set top (like in OP_CALL with C == 0). set top (like in OP_CALL with C == 0).
(*) In OP_RETURN/OP_RETVARARG, if (B == 0) then return up to 'top'. (*) In OP_RETURN, if (B == 0) then return up to 'top'.
(OP_RETVARARG is the return instruction for vararg functions.)
(*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then
next 'instruction' is EXTRAARG(real C). 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. (*) All 'skips' (pc++) assume that next instruction is a jump.
(*) In instructions ending a function (OP_RETURN*, OP_TAILCALL), k (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
specifies that the function builds upvalues, which may need to be function either builds upvalues, which may need to be closed, or is
closed. 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)) #define testOTMode(m) (luaP_opmodes[m] & (1 << 6))
/* "out top" (set top for next instruction) */ /* "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) */ /* "in top" (uses top from previous instruction) */
#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0) #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 ** Tag methods
** See Copyright Notice in lua.h ** 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 */ int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra; ci->u.l.nextraargs = nextra;
checkstackGC(L, nfixparams + 1); checkstackGC(L, nfixparams + 1);
/* copy function and fixed parameters to the top of the stack */ /* copy function to the top of the stack */
for (i = 0; i <= nfixparams; i++) { 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); 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->func += actual + 1;
ci->top += 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 ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -1493,23 +1493,35 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
vmcase(OP_TAILCALL) { vmcase(OP_TAILCALL) {
int b = GETARG_B(i); /* number of arguments + 1 (function) */ int b = GETARG_B(i); /* number of arguments + 1 (function) */
int delta = 0; /* virtual 'func' - real 'func' (vararg functions) */
if (b != 0) if (b != 0)
L->top = ra + b; L->top = ra + b;
else /* previous instruction set top */ else /* previous instruction set top */
b = cast_int(L->top - ra); 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? */ 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 */ 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? */ 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 */ else { /* Lua tail call */
if (cl->p->is_vararg) ci->func -= delta;
ci->func -= cl->p->numparams + ci->u.l.nextraargs + 1;
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
goto tailcall; goto tailcall;
} }
@ -1518,34 +1530,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
int b = GETARG_B(i); int b = GETARG_B(i);
int n = (b != 0 ? b - 1 : cast_int(L->top - ra)); int n = (b != 0 ? b - 1 : cast_int(L->top - ra));
if (TESTARG_k(i)) if (TESTARG_k(i)) {
luaF_close(L, base); 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)); halfProtect(luaD_poscall(L, ci, ra, n));
return; 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) { vmcase(OP_RETURN0) {
if (TESTARG_k(i))
luaF_close(L, base);
if (L->hookmask) if (L->hookmask)
halfProtect(luaD_poscall(L, ci, ra, 0)); /* no hurry... */ halfProtect(luaD_poscall(L, ci, ra, 0)); /* no hurry... */
else { else {
@ -1558,8 +1552,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
return; return;
} }
vmcase(OP_RETURN1) { vmcase(OP_RETURN1) {
if (TESTARG_k(i))
luaF_close(L, base);
if (L->hookmask) if (L->hookmask)
halfProtect(luaD_poscall(L, ci, ra, 1)); /* no hurry... */ halfProtect(luaD_poscall(L, ci, ra, 1)); /* no hurry... */
else { else {