diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-08-18 11:21:33 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-08-18 11:21:33 -0300 |
| commit | 41871f1803770305f182f56cbd22a336c5236a19 (patch) | |
| tree | 4f15a23a06999d63dd605896c537f98861c605c2 | |
| parent | a393ac255493276b1ad9d7be057fe58ea824dd00 (diff) | |
| download | lua-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.c | 66 | ||||
| -rw-r--r-- | ldo.h | 15 | ||||
| -rw-r--r-- | lvm.c | 21 |
3 files changed, 51 insertions, 51 deletions
| @@ -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 | */ |
| 481 | static void moveparams (lua_State *L, StkId prevf, StkId func) { | 481 | void 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 */ | |
| 489 | static 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 | } | 500 | static 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 | */ |
| 520 | CallInfo *luaD_precall (lua_State *L, StkId func, int retdel) { | 519 | CallInfo *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); |
| @@ -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' */ |
| 65 | typedef void (*Pfunc) (lua_State *L, void *ud); | 53 | typedef 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, | |||
| 70 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, | 58 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, |
| 71 | int fTransfer, int nTransfer); | 59 | int fTransfer, int nTransfer); |
| 72 | LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); | 60 | LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); |
| 73 | LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int retdel); | 61 | LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); |
| 62 | LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); | ||
| 74 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); | 63 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); |
| 75 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); | 64 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); |
| 76 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); | 65 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); |
| @@ -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 | |||
| 771 | lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { | 772 | lua_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 */ |
