From 41871f1803770305f182f56cbd22a336c5236a19 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 18 Aug 2021 11:21:33 -0300 Subject: Undo simplification of tail calls (commit 901d760) Not that simpler and slower. --- ldo.c | 66 ++++++++++++++++++++++++++++++++---------------------------------- ldo.h | 15 ++------------- lvm.c | 21 +++++++++++++++++---- 3 files changed, 51 insertions(+), 51 deletions(-) diff --git a/ldo.c b/ldo.c index 93fcbb1a..fa8d98b2 100644 --- a/ldo.c +++ b/ldo.c @@ -474,33 +474,36 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { /* -** In a tail call, move function and parameters to previous call frame. -** (This is done only when no more errors can occur before entering the -** new function, to keep debug information always consistent.) +** Prepare a function for a tail call, building its call info on top +** of the current call info. 'narg1' is the number of arguments plus 1 +** (so that it includes the function itself). */ -static void moveparams (lua_State *L, StkId prevf, StkId func) { +void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { + Proto *p = clLvalue(s2v(func))->p; + int fsize = p->maxstacksize; /* frame size */ + int nfixparams = p->numparams; int i; - for (i = 0; func + i < L->top; i++) /* move down function and arguments */ - setobjs2s(L, prevf + i, func + i); - L->top = prevf + i; /* correct top */ -} - - -static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel, - int mask) { - CallInfo *ci; - if (isdelta(retdel)) { /* tail call? */ - ci = L->ci; /* reuse stack frame */ - ci->func -= retdel2delta(retdel); /* correct 'func' */ - ci->callstatus |= mask | CIST_TAIL; - moveparams(L, ci->func, func); - } - else { /* regular call */ - ci = L->ci = next_ci(L); /* new frame */ - ci->func = func; - ci->nresults = retdel; - ci->callstatus = mask; - } + for (i = 0; i < narg1; i++) /* move down function and arguments */ + setobjs2s(L, ci->func + i, func + i); + checkstackGC(L, fsize); + func = ci->func; /* moved-down function */ + for (; narg1 <= nfixparams; narg1++) + setnilvalue(s2v(func + narg1)); /* complete missing arguments */ + ci->top = func + 1 + fsize; /* top for new function */ + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus |= CIST_TAIL; + L->top = func + narg1; /* set top */ +} + + +static CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + int mask, StkId top) { + CallInfo *ci = L->ci = next_ci(L); /* new frame */ + ci->func = func; + ci->nresults = nret; + ci->callstatus = mask; + ci->top = top; return ci; } @@ -512,12 +515,8 @@ static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel, ** to be executed, if it was a Lua function. Otherwise (a C function) ** returns NULL, with all the results on the stack, starting at the ** original function position. -** For regular calls, 'delta1' is 0. For tail calls, 'delta1' is the -** 'delta' (correction of base for vararg functions) plus 1, so that it -** cannot be zero. Like 'moveparams', this correction can only be done -** when no more errors can occur in the call. */ -CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { +CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; retry: switch (ttypetag(s2v(func))) { @@ -530,8 +529,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { int n; /* number of returns */ CallInfo *ci; checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ - ci = prepCallInfo(L, func, retdel, CIST_C); - ci->top = L->top + LUA_MINSTACK; + L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, + L->top + LUA_MINSTACK); lua_assert(ci->top <= L->stack_last); if (l_unlikely(L->hookmask & LUA_MASKCALL)) { int narg = cast_int(L->top - func) - 1; @@ -551,9 +550,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { int nfixparams = p->numparams; int fsize = p->maxstacksize; /* frame size */ checkstackGCp(L, fsize, func); - ci = prepCallInfo(L, func, retdel, 0); + L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); ci->u.l.savedpc = p->code; /* starting point */ - ci->top = func + 1 + fsize; for (; narg < nfixparams; narg++) setnilvalue(s2v(L->top++)); /* complete missing arguments */ lua_assert(ci->top <= L->stack_last); diff --git a/ldo.h b/ldo.h index 49fbb492..6bf0ed86 100644 --- a/ldo.h +++ b/ldo.h @@ -49,18 +49,6 @@ luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) -/* -** 'luaD_precall' is used for regular calls, when it needs the -** number of results, and in tail calls, when it needs the 'delta' -** (correction of base for vararg functions). The argument 'retdel' -** codes these two options. A number of results is represented by -** itself, while a delta is represented by 'delta2retdel(delta)' -*/ -#define delta2retdel(d) (-(d) + LUA_MULTRET - 1) -#define retdel2delta(d) (-(d) + LUA_MULTRET - 1) -#define isdelta(rd) ((rd) < LUA_MULTRET) - - /* type of protected functions, to be ran by 'runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); @@ -70,7 +58,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, int fTransfer, int nTransfer); LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); -LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int retdel); +LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); +LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); diff --git a/lvm.c b/lvm.c index c84a665f..df1dec83 100644 --- a/lvm.c +++ b/lvm.c @@ -768,6 +768,7 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) { */ #define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) + lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { if (y < 0) { /* shift right? */ if (y <= -NBITS) return 0; @@ -1647,19 +1648,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) { int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; if (b != 0) L->top = ra + b; - /* else previous instruction set top */ + else /* previous instruction set top */ + b = cast_int(L->top - ra); savepc(ci); /* several calls here can raise errors */ if (TESTARG_k(i)) { luaF_closeupval(L, base); /* close upvalues from current call */ lua_assert(L->tbclist < base); /* no pending tbc variables */ lua_assert(base == ci->func + 1); } - if (luaD_precall(L, ra, delta2retdel(delta))) /* Lua function? */ - goto startfunc; /* execute the callee */ - else { /* C function */ + while (!ttisfunction(s2v(ra))) { /* not a function? */ + luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ + b++; /* there is now one extra argument */ + checkstackGCp(L, 1, ra); + } + if (!ttisLclosure(s2v(ra))) { /* C function? */ + luaD_precall(L, ra, LUA_MULTRET); /* call it */ updatetrap(ci); + updatestack(ci); /* stack may have been relocated */ + ci->func -= delta; /* restore 'func' (if vararg) */ + luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ + updatetrap(ci); /* 'luaD_poscall' can change hooks */ goto ret; /* caller returns after the tail call */ } + ci->func -= delta; /* restore 'func' (if vararg) */ + luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ + goto startfunc; /* execute the callee */ } vmcase(OP_RETURN) { int n = GETARG_B(i) - 1; /* number of results */ -- cgit v1.2.1