diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-06-11 13:41:07 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-06-11 13:41:07 -0300 |
| commit | 901d76009346d76996679c02deee708bf225e91e (patch) | |
| tree | 51fb561c607c498e5dd229ab26c439645715c49e /ldo.c | |
| parent | c0ed74c1e130aa6d80e5ffc7b6e32b433aca1765 (diff) | |
| download | lua-901d76009346d76996679c02deee708bf225e91e.tar.gz lua-901d76009346d76996679c02deee708bf225e91e.tar.bz2 lua-901d76009346d76996679c02deee708bf225e91e.zip | |
Simpler implementation for tail calls
Tail calls handled by 'luaD_precall', like regular calls, to avoid
code duplication.
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 48 |
1 files changed, 24 insertions, 24 deletions
| @@ -474,26 +474,16 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { | |||
| 474 | 474 | ||
| 475 | 475 | ||
| 476 | /* | 476 | /* |
| 477 | ** Prepare a function for a tail call, building its call info on top | 477 | ** In a tail call, move function and parameters to previous call frame. |
| 478 | ** of the current call info. 'narg1' is the number of arguments plus 1 | 478 | ** (This is done only when no more errors can occur before entering the |
| 479 | ** (so that it includes the function itself). | 479 | ** new function, to keep debug information always consistent.) |
| 480 | */ | 480 | */ |
| 481 | void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { | 481 | static void moveparams (lua_State *L, StkId prevf, StkId func, int narg) { |
| 482 | Proto *p = clLvalue(s2v(func))->p; | ||
| 483 | int fsize = p->maxstacksize; /* frame size */ | ||
| 484 | int nfixparams = p->numparams; | ||
| 485 | int i; | 482 | int i; |
| 486 | for (i = 0; i < narg1; i++) /* move down function and arguments */ | 483 | narg++; /* function itself will be moved, too */ |
| 487 | setobjs2s(L, ci->func + i, func + i); | 484 | for (i = 0; i < narg; i++) /* move down function and arguments */ |
| 488 | checkstackGC(L, fsize); | 485 | setobjs2s(L, prevf + i, func + i); |
| 489 | func = ci->func; /* moved-down function */ | 486 | L->top = prevf + narg; /* correct top */ |
| 490 | for (; narg1 <= nfixparams; narg1++) | ||
| 491 | setnilvalue(s2v(func + narg1)); /* complete missing arguments */ | ||
| 492 | ci->top = func + 1 + fsize; /* top for new function */ | ||
| 493 | lua_assert(ci->top <= L->stack_last); | ||
| 494 | ci->u.l.savedpc = p->code; /* starting point */ | ||
| 495 | ci->callstatus |= CIST_TAIL; | ||
| 496 | L->top = func + narg1; /* set top */ | ||
| 497 | } | 487 | } |
| 498 | 488 | ||
| 499 | 489 | ||
| @@ -504,8 +494,12 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { | |||
| 504 | ** to be executed, if it was a Lua function. Otherwise (a C function) | 494 | ** to be executed, if it was a Lua function. Otherwise (a C function) |
| 505 | ** returns NULL, with all the results on the stack, starting at the | 495 | ** returns NULL, with all the results on the stack, starting at the |
| 506 | ** original function position. | 496 | ** original function position. |
| 497 | ** For regular calls, 'delta1' is 0. For tail calls, 'delta1' is the | ||
| 498 | ** 'delta' (correction of base for vararg functions) plus 1, so that it | ||
| 499 | ** cannot be zero. Like 'moveparams', this correction can only be done | ||
| 500 | ** when no more errors can occur in the call. | ||
| 507 | */ | 501 | */ |
| 508 | CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { | 502 | CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { |
| 509 | lua_CFunction f; | 503 | lua_CFunction f; |
| 510 | retry: | 504 | retry: |
| 511 | switch (ttypetag(s2v(func))) { | 505 | switch (ttypetag(s2v(func))) { |
| @@ -542,12 +536,18 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 542 | int nfixparams = p->numparams; | 536 | int nfixparams = p->numparams; |
| 543 | int fsize = p->maxstacksize; /* frame size */ | 537 | int fsize = p->maxstacksize; /* frame size */ |
| 544 | checkstackGCp(L, fsize, func); | 538 | checkstackGCp(L, fsize, func); |
| 545 | L->ci = ci = next_ci(L); | 539 | if (delta1) { /* tail call? */ |
| 546 | ci->nresults = nresults; | 540 | ci = L->ci; /* reuse stack frame */ |
| 541 | ci->func -= delta1 - 1; /* correct 'func' */ | ||
| 542 | moveparams(L, ci->func, func, narg); | ||
| 543 | } | ||
| 544 | else { /* regular call */ | ||
| 545 | L->ci = ci = next_ci(L); /* new frame */ | ||
| 546 | ci->func = func; | ||
| 547 | ci->nresults = nresults; | ||
| 548 | } | ||
| 547 | ci->u.l.savedpc = p->code; /* starting point */ | 549 | ci->u.l.savedpc = p->code; /* starting point */ |
| 548 | ci->top = func + 1 + fsize; | 550 | ci->top = func + 1 + fsize; |
| 549 | ci->func = func; | ||
| 550 | L->ci = ci; | ||
| 551 | for (; narg < nfixparams; narg++) | 551 | for (; narg < nfixparams; narg++) |
| 552 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ | 552 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ |
| 553 | lua_assert(ci->top <= L->stack_last); | 553 | lua_assert(ci->top <= L->stack_last); |
| @@ -572,7 +572,7 @@ static void ccall (lua_State *L, StkId func, int nResults, int inc) { | |||
| 572 | L->nCcalls += inc; | 572 | L->nCcalls += inc; |
| 573 | if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) | 573 | if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) |
| 574 | luaE_checkcstack(L); | 574 | luaE_checkcstack(L); |
| 575 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ | 575 | if ((ci = luaD_precall(L, func, nResults, 0)) != NULL) { /* Lua function? */ |
| 576 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ | 576 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ |
| 577 | luaV_execute(L, ci); /* call it */ | 577 | luaV_execute(L, ci); /* call it */ |
| 578 | } | 578 | } |
