aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-08-18 11:21:33 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-08-18 11:21:33 -0300
commit41871f1803770305f182f56cbd22a336c5236a19 (patch)
tree4f15a23a06999d63dd605896c537f98861c605c2
parenta393ac255493276b1ad9d7be057fe58ea824dd00 (diff)
downloadlua-41871f1803770305f182f56cbd22a336c5236a19.tar.gz
lua-41871f1803770305f182f56cbd22a336c5236a19.tar.bz2
lua-41871f1803770305f182f56cbd22a336c5236a19.zip
Undo simplification of tail calls (commit 901d760)
Not that simpler and slower.
-rw-r--r--ldo.c66
-rw-r--r--ldo.h15
-rw-r--r--lvm.c21
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) {
474 474
475 475
476/* 476/*
477** In a tail call, move function and parameters to previous call frame. 477** Prepare a function for a tail call, building its call info on top
478** (This is done only when no more errors can occur before entering the 478** of the current call info. 'narg1' is the number of arguments plus 1
479** new function, to keep debug information always consistent.) 479** (so that it includes the function itself).
480*/ 480*/
481static void moveparams (lua_State *L, StkId prevf, StkId func) { 481void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
482 Proto *p = clLvalue(s2v(func))->p;
483 int fsize = p->maxstacksize; /* frame size */
484 int nfixparams = p->numparams;
482 int i; 485 int i;
483 for (i = 0; func + i < L->top; i++) /* move down function and arguments */ 486 for (i = 0; i < narg1; i++) /* move down function and arguments */
484 setobjs2s(L, prevf + i, func + i); 487 setobjs2s(L, ci->func + i, func + i);
485 L->top = prevf + i; /* correct top */ 488 checkstackGC(L, fsize);
486} 489 func = ci->func; /* moved-down function */
487 490 for (; narg1 <= nfixparams; narg1++)
488 491 setnilvalue(s2v(func + narg1)); /* complete missing arguments */
489static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel, 492 ci->top = func + 1 + fsize; /* top for new function */
490 int mask) { 493 lua_assert(ci->top <= L->stack_last);
491 CallInfo *ci; 494 ci->u.l.savedpc = p->code; /* starting point */
492 if (isdelta(retdel)) { /* tail call? */ 495 ci->callstatus |= CIST_TAIL;
493 ci = L->ci; /* reuse stack frame */ 496 L->top = func + narg1; /* set top */
494 ci->func -= retdel2delta(retdel); /* correct 'func' */ 497}
495 ci->callstatus |= mask | CIST_TAIL; 498
496 moveparams(L, ci->func, func); 499
497 } 500static CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
498 else { /* regular call */ 501 int mask, StkId top) {
499 ci = L->ci = next_ci(L); /* new frame */ 502 CallInfo *ci = L->ci = next_ci(L); /* new frame */
500 ci->func = func; 503 ci->func = func;
501 ci->nresults = retdel; 504 ci->nresults = nret;
502 ci->callstatus = mask; 505 ci->callstatus = mask;
503 } 506 ci->top = top;
504 return ci; 507 return ci;
505} 508}
506 509
@@ -512,12 +515,8 @@ static CallInfo *prepCallInfo (lua_State *L, StkId func, int retdel,
512** to be executed, if it was a Lua function. Otherwise (a C function) 515** to be executed, if it was a Lua function. Otherwise (a C function)
513** returns NULL, with all the results on the stack, starting at the 516** returns NULL, with all the results on the stack, starting at the
514** original function position. 517** original function position.
515** For regular calls, 'delta1' is 0. For tail calls, 'delta1' is the
516** 'delta' (correction of base for vararg functions) plus 1, so that it
517** cannot be zero. Like 'moveparams', this correction can only be done
518** when no more errors can occur in the call.
519*/ 518*/
520CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { 519CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
521 lua_CFunction f; 520 lua_CFunction f;
522 retry: 521 retry:
523 switch (ttypetag(s2v(func))) { 522 switch (ttypetag(s2v(func))) {
@@ -530,8 +529,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) {
530 int n; /* number of returns */ 529 int n; /* number of returns */
531 CallInfo *ci; 530 CallInfo *ci;
532 checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ 531 checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
533 ci = prepCallInfo(L, func, retdel, CIST_C); 532 L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
534 ci->top = L->top + LUA_MINSTACK; 533 L->top + LUA_MINSTACK);
535 lua_assert(ci->top <= L->stack_last); 534 lua_assert(ci->top <= L->stack_last);
536 if (l_unlikely(L->hookmask & LUA_MASKCALL)) { 535 if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
537 int narg = cast_int(L->top - func) - 1; 536 int narg = cast_int(L->top - func) - 1;
@@ -551,9 +550,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) {
551 int nfixparams = p->numparams; 550 int nfixparams = p->numparams;
552 int fsize = p->maxstacksize; /* frame size */ 551 int fsize = p->maxstacksize; /* frame size */
553 checkstackGCp(L, fsize, func); 552 checkstackGCp(L, fsize, func);
554 ci = prepCallInfo(L, func, retdel, 0); 553 L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
555 ci->u.l.savedpc = p->code; /* starting point */ 554 ci->u.l.savedpc = p->code; /* starting point */
556 ci->top = func + 1 + fsize;
557 for (; narg < nfixparams; narg++) 555 for (; narg < nfixparams; narg++)
558 setnilvalue(s2v(L->top++)); /* complete missing arguments */ 556 setnilvalue(s2v(L->top++)); /* complete missing arguments */
559 lua_assert(ci->top <= L->stack_last); 557 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 @@
49 luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) 49 luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
50 50
51 51
52/*
53** 'luaD_precall' is used for regular calls, when it needs the
54** number of results, and in tail calls, when it needs the 'delta'
55** (correction of base for vararg functions). The argument 'retdel'
56** codes these two options. A number of results is represented by
57** itself, while a delta is represented by 'delta2retdel(delta)'
58*/
59#define delta2retdel(d) (-(d) + LUA_MULTRET - 1)
60#define retdel2delta(d) (-(d) + LUA_MULTRET - 1)
61#define isdelta(rd) ((rd) < LUA_MULTRET)
62
63
64/* type of protected functions, to be ran by 'runprotected' */ 52/* type of protected functions, to be ran by 'runprotected' */
65typedef void (*Pfunc) (lua_State *L, void *ud); 53typedef void (*Pfunc) (lua_State *L, void *ud);
66 54
@@ -70,7 +58,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
70LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, 58LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
71 int fTransfer, int nTransfer); 59 int fTransfer, int nTransfer);
72LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); 60LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
73LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int retdel); 61LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
62LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
74LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); 63LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
75LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); 64LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
76LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); 65LUAI_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) {
768*/ 768*/
769#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) 769#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
770 770
771
771lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { 772lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
772 if (y < 0) { /* shift right? */ 773 if (y < 0) { /* shift right? */
773 if (y <= -NBITS) return 0; 774 if (y <= -NBITS) return 0;
@@ -1647,19 +1648,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1647 int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; 1648 int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
1648 if (b != 0) 1649 if (b != 0)
1649 L->top = ra + b; 1650 L->top = ra + b;
1650 /* else previous instruction set top */ 1651 else /* previous instruction set top */
1652 b = cast_int(L->top - ra);
1651 savepc(ci); /* several calls here can raise errors */ 1653 savepc(ci); /* several calls here can raise errors */
1652 if (TESTARG_k(i)) { 1654 if (TESTARG_k(i)) {
1653 luaF_closeupval(L, base); /* close upvalues from current call */ 1655 luaF_closeupval(L, base); /* close upvalues from current call */
1654 lua_assert(L->tbclist < base); /* no pending tbc variables */ 1656 lua_assert(L->tbclist < base); /* no pending tbc variables */
1655 lua_assert(base == ci->func + 1); 1657 lua_assert(base == ci->func + 1);
1656 } 1658 }
1657 if (luaD_precall(L, ra, delta2retdel(delta))) /* Lua function? */ 1659 while (!ttisfunction(s2v(ra))) { /* not a function? */
1658 goto startfunc; /* execute the callee */ 1660 luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
1659 else { /* C function */ 1661 b++; /* there is now one extra argument */
1662 checkstackGCp(L, 1, ra);
1663 }
1664 if (!ttisLclosure(s2v(ra))) { /* C function? */
1665 luaD_precall(L, ra, LUA_MULTRET); /* call it */
1660 updatetrap(ci); 1666 updatetrap(ci);
1667 updatestack(ci); /* stack may have been relocated */
1668 ci->func -= delta; /* restore 'func' (if vararg) */
1669 luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */
1670 updatetrap(ci); /* 'luaD_poscall' can change hooks */
1661 goto ret; /* caller returns after the tail call */ 1671 goto ret; /* caller returns after the tail call */
1662 } 1672 }
1673 ci->func -= delta; /* restore 'func' (if vararg) */
1674 luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
1675 goto startfunc; /* execute the callee */
1663 } 1676 }
1664 vmcase(OP_RETURN) { 1677 vmcase(OP_RETURN) {
1665 int n = GETARG_B(i) - 1; /* number of results */ 1678 int n = GETARG_B(i) - 1; /* number of results */