diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-06-14 13:28:21 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-06-14 13:28:21 -0300 |
| commit | 04e19712a5d48b84869f9942836ff8314fb0be8e (patch) | |
| tree | 75aab8dff5bdf07026080eba0189e4025ec3b7ee /ldo.c | |
| parent | 901d76009346d76996679c02deee708bf225e91e (diff) | |
| download | lua-04e19712a5d48b84869f9942836ff8314fb0be8e.tar.gz lua-04e19712a5d48b84869f9942836ff8314fb0be8e.tar.bz2 lua-04e19712a5d48b84869f9942836ff8314fb0be8e.zip | |
C functions can be tail called, too
A tail call to a C function can have the behavior of a "real" tail
call, reusing the stack frame of the caller.
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 43 |
1 files changed, 25 insertions, 18 deletions
| @@ -478,12 +478,31 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { | |||
| 478 | ** (This is done only when no more errors can occur before entering the | 478 | ** (This is done only when no more errors can occur before entering the |
| 479 | ** new function, to keep debug information always consistent.) | 479 | ** new function, to keep debug information always consistent.) |
| 480 | */ | 480 | */ |
| 481 | static void moveparams (lua_State *L, StkId prevf, StkId func, int narg) { | 481 | static void moveparams (lua_State *L, StkId prevf, StkId func) { |
| 482 | int i; | 482 | int i; |
| 483 | narg++; /* function itself will be moved, too */ | 483 | for (i = 0; func + i < L->top; i++) /* move down function and arguments */ |
| 484 | for (i = 0; i < narg; i++) /* move down function and arguments */ | ||
| 485 | setobjs2s(L, prevf + i, func + i); | 484 | setobjs2s(L, prevf + i, func + i); |
| 486 | L->top = prevf + narg; /* correct top */ | 485 | L->top = prevf + i; /* correct top */ |
| 486 | } | ||
| 487 | |||
| 488 | |||
| 489 | static CallInfo *prepCallInfo (lua_State *L, StkId func, int nresults, | ||
| 490 | int delta1, int mask) { | ||
| 491 | CallInfo *ci; | ||
| 492 | if (delta1) { /* tail call? */ | ||
| 493 | ci = L->ci; /* reuse stack frame */ | ||
| 494 | ci->func -= delta1 - 1; /* correct 'func' */ | ||
| 495 | |||
| 496 | ci->callstatus |= mask | CIST_TAIL; | ||
| 497 | moveparams(L, ci->func, func); | ||
| 498 | } | ||
| 499 | else { /* regular call */ | ||
| 500 | ci = L->ci = next_ci(L); /* new frame */ | ||
| 501 | ci->func = func; | ||
| 502 | ci->nresults = nresults; | ||
| 503 | ci->callstatus = mask; | ||
| 504 | } | ||
| 505 | return ci; | ||
| 487 | } | 506 | } |
| 488 | 507 | ||
| 489 | 508 | ||
| @@ -512,11 +531,8 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { | |||
| 512 | int n; /* number of returns */ | 531 | int n; /* number of returns */ |
| 513 | CallInfo *ci; | 532 | CallInfo *ci; |
| 514 | checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ | 533 | checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ |
| 515 | L->ci = ci = next_ci(L); | 534 | ci = prepCallInfo(L, func, nresults, delta1, CIST_C); |
| 516 | ci->nresults = nresults; | ||
| 517 | ci->callstatus = CIST_C; | ||
| 518 | ci->top = L->top + LUA_MINSTACK; | 535 | ci->top = L->top + LUA_MINSTACK; |
| 519 | ci->func = func; | ||
| 520 | lua_assert(ci->top <= L->stack_last); | 536 | lua_assert(ci->top <= L->stack_last); |
| 521 | if (l_unlikely(L->hookmask & LUA_MASKCALL)) { | 537 | if (l_unlikely(L->hookmask & LUA_MASKCALL)) { |
| 522 | int narg = cast_int(L->top - func) - 1; | 538 | int narg = cast_int(L->top - func) - 1; |
| @@ -536,16 +552,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults, int delta1) { | |||
| 536 | int nfixparams = p->numparams; | 552 | int nfixparams = p->numparams; |
| 537 | int fsize = p->maxstacksize; /* frame size */ | 553 | int fsize = p->maxstacksize; /* frame size */ |
| 538 | checkstackGCp(L, fsize, func); | 554 | checkstackGCp(L, fsize, func); |
| 539 | if (delta1) { /* tail call? */ | 555 | ci = prepCallInfo(L, func, nresults, delta1, 0); |
| 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 | } | ||
| 549 | ci->u.l.savedpc = p->code; /* starting point */ | 556 | ci->u.l.savedpc = p->code; /* starting point */ |
| 550 | ci->top = func + 1 + fsize; | 557 | ci->top = func + 1 + fsize; |
| 551 | for (; narg < nfixparams; narg++) | 558 | for (; narg < nfixparams; narg++) |
