diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-09-24 13:26:51 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-10-12 12:29:09 -0300 |
| commit | 490d42b5f89563a94994505c75e24086b0a487e6 (patch) | |
| tree | d8d9c68deb5879a99cf6574ab0903fba30cef7a4 | |
| parent | 287b302acb8d925178e9edb800f0a8d18c7d35f6 (diff) | |
| download | lua-490d42b5f89563a94994505c75e24086b0a487e6.tar.gz lua-490d42b5f89563a94994505c75e24086b0a487e6.tar.bz2 lua-490d42b5f89563a94994505c75e24086b0a487e6.zip | |
Correct handling of 'luaV_execute' invocations
The previous stackless implementations marked all 'luaV_execute'
invocations as fresh. However, re-entering 'luaV_execute' when
resuming a coroutine should not be a fresh invocation. (It works
because 'unroll' called 'luaV_execute' for each call entry, but
it was slower than letting 'luaV_execute' finish all non-fresh
invocations.)
| -rw-r--r-- | ldo.c | 25 | ||||
| -rw-r--r-- | ldo.h | 2 | ||||
| -rw-r--r-- | lstate.c | 2 | ||||
| -rw-r--r-- | lstate.h | 15 | ||||
| -rw-r--r-- | lvm.c | 25 |
5 files changed, 37 insertions, 32 deletions
| @@ -449,12 +449,13 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { | |||
| 449 | 449 | ||
| 450 | /* | 450 | /* |
| 451 | ** Prepares the call to a function (C or Lua). For C functions, also do | 451 | ** Prepares the call to a function (C or Lua). For C functions, also do |
| 452 | ** the call. The function to be called is at '*func'. The arguments are | 452 | ** the call. The function to be called is at '*func'. The arguments |
| 453 | ** on the stack, right after the function. Returns true if the call was | 453 | ** are on the stack, right after the function. Returns the CallInfo |
| 454 | ** made (it was a C function). When returns true, all the results are | 454 | ** to be executed, if it was a Lua function. Otherwise (a C function) |
| 455 | ** on the stack, starting at the original function position. | 455 | ** returns NULL, with all the results on the stack, starting at the |
| 456 | ** original function position. | ||
| 456 | */ | 457 | */ |
| 457 | int luaD_precall (lua_State *L, StkId func, int nresults) { | 458 | CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { |
| 458 | lua_CFunction f; | 459 | lua_CFunction f; |
| 459 | retry: | 460 | retry: |
| 460 | switch (ttypetag(s2v(func))) { | 461 | switch (ttypetag(s2v(func))) { |
| @@ -482,7 +483,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 482 | lua_lock(L); | 483 | lua_lock(L); |
| 483 | api_checknelems(L, n); | 484 | api_checknelems(L, n); |
| 484 | luaD_poscall(L, ci, n); | 485 | luaD_poscall(L, ci, n); |
| 485 | return 1; | 486 | return NULL; |
| 486 | } | 487 | } |
| 487 | case LUA_VLCL: { /* Lua function */ | 488 | case LUA_VLCL: { /* Lua function */ |
| 488 | CallInfo *ci; | 489 | CallInfo *ci; |
| @@ -494,14 +495,13 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 494 | L->ci = ci = next_ci(L); | 495 | L->ci = ci = next_ci(L); |
| 495 | ci->nresults = nresults; | 496 | ci->nresults = nresults; |
| 496 | ci->u.l.savedpc = p->code; /* starting point */ | 497 | ci->u.l.savedpc = p->code; /* starting point */ |
| 497 | ci->callstatus = 0; | ||
| 498 | ci->top = func + 1 + fsize; | 498 | ci->top = func + 1 + fsize; |
| 499 | ci->func = func; | 499 | ci->func = func; |
| 500 | L->ci = ci; | 500 | L->ci = ci; |
| 501 | for (; narg < nfixparams; narg++) | 501 | for (; narg < nfixparams; narg++) |
| 502 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ | 502 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ |
| 503 | lua_assert(ci->top <= L->stack_last); | 503 | lua_assert(ci->top <= L->stack_last); |
| 504 | return 0; | 504 | return ci; |
| 505 | } | 505 | } |
| 506 | default: { /* not a function */ | 506 | default: { /* not a function */ |
| 507 | checkstackGCp(L, 1, func); /* space for metamethod */ | 507 | checkstackGCp(L, 1, func); /* space for metamethod */ |
| @@ -518,11 +518,14 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 518 | ** increment number of non-yieldable calls). | 518 | ** increment number of non-yieldable calls). |
| 519 | */ | 519 | */ |
| 520 | static void docall (lua_State *L, StkId func, int nResults, int inc) { | 520 | static void docall (lua_State *L, StkId func, int nResults, int inc) { |
| 521 | CallInfo *ci; | ||
| 521 | L->nCcalls += inc; | 522 | L->nCcalls += inc; |
| 522 | if (getCcalls(L) >= LUAI_MAXCCALLS) | 523 | if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) |
| 523 | luaE_checkcstack(L); | 524 | luaE_checkcstack(L); |
| 524 | if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ | 525 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ |
| 525 | luaV_execute(L, L->ci); /* call it */ | 526 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ |
| 527 | luaV_execute(L, ci); /* call it */ | ||
| 528 | } | ||
| 526 | L->nCcalls -= inc; | 529 | L->nCcalls -= inc; |
| 527 | } | 530 | } |
| 528 | 531 | ||
| @@ -59,7 +59,7 @@ LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, | |||
| 59 | int fTransfer, int nTransfer); | 59 | int fTransfer, int nTransfer); |
| 60 | LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); | 60 | LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); |
| 61 | LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); | 61 | LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); |
| 62 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nResults); | 62 | LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); |
| 63 | 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); |
| 64 | 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); |
| 65 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); | 65 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); |
| @@ -172,7 +172,7 @@ void luaE_checkcstack (lua_State *L) { | |||
| 172 | 172 | ||
| 173 | LUAI_FUNC void luaE_incCstack (lua_State *L) { | 173 | LUAI_FUNC void luaE_incCstack (lua_State *L) { |
| 174 | L->nCcalls++; | 174 | L->nCcalls++; |
| 175 | if (getCcalls(L) >= LUAI_MAXCCALLS) | 175 | if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) |
| 176 | luaE_checkcstack(L); | 176 | luaE_checkcstack(L); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| @@ -183,14 +183,15 @@ typedef struct CallInfo { | |||
| 183 | */ | 183 | */ |
| 184 | #define CIST_OAH (1<<0) /* original value of 'allowhook' */ | 184 | #define CIST_OAH (1<<0) /* original value of 'allowhook' */ |
| 185 | #define CIST_C (1<<1) /* call is running a C function */ | 185 | #define CIST_C (1<<1) /* call is running a C function */ |
| 186 | #define CIST_HOOKED (1<<2) /* call is running a debug hook */ | 186 | #define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ |
| 187 | #define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ | 187 | #define CIST_HOOKED (1<<3) /* call is running a debug hook */ |
| 188 | #define CIST_TAIL (1<<4) /* call was tail called */ | 188 | #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ |
| 189 | #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ | 189 | #define CIST_TAIL (1<<5) /* call was tail called */ |
| 190 | #define CIST_FIN (1<<6) /* call is running a finalizer */ | 190 | #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ |
| 191 | #define CIST_TRAN (1<<7) /* 'ci' has transfer information */ | 191 | #define CIST_FIN (1<<7) /* call is running a finalizer */ |
| 192 | #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ | ||
| 192 | #if defined(LUA_COMPAT_LT_LE) | 193 | #if defined(LUA_COMPAT_LT_LE) |
| 193 | #define CIST_LEQ (1<<8) /* using __lt for __le */ | 194 | #define CIST_LEQ (1<<9) /* using __lt for __le */ |
| 194 | #endif | 195 | #endif |
| 195 | 196 | ||
| 196 | /* active function is a Lua function */ | 197 | /* active function is a Lua function */ |
| @@ -1124,7 +1124,6 @@ void luaV_finishOp (lua_State *L) { | |||
| 1124 | 1124 | ||
| 1125 | 1125 | ||
| 1126 | void luaV_execute (lua_State *L, CallInfo *ci) { | 1126 | void luaV_execute (lua_State *L, CallInfo *ci) { |
| 1127 | CallInfo * const origci = ci; | ||
| 1128 | LClosure *cl; | 1127 | LClosure *cl; |
| 1129 | TValue *k; | 1128 | TValue *k; |
| 1130 | StkId base; | 1129 | StkId base; |
| @@ -1133,7 +1132,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1133 | #if LUA_USE_JUMPTABLE | 1132 | #if LUA_USE_JUMPTABLE |
| 1134 | #include "ljumptab.h" | 1133 | #include "ljumptab.h" |
| 1135 | #endif | 1134 | #endif |
| 1136 | tailcall: | 1135 | execute: |
| 1137 | trap = L->hookmask; | 1136 | trap = L->hookmask; |
| 1138 | cl = clLvalue(s2v(ci->func)); | 1137 | cl = clLvalue(s2v(ci->func)); |
| 1139 | k = cl->p->k; | 1138 | k = cl->p->k; |
| @@ -1607,17 +1606,19 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1607 | vmbreak; | 1606 | vmbreak; |
| 1608 | } | 1607 | } |
| 1609 | vmcase(OP_CALL) { | 1608 | vmcase(OP_CALL) { |
| 1609 | CallInfo *newci; | ||
| 1610 | int b = GETARG_B(i); | 1610 | int b = GETARG_B(i); |
| 1611 | int nresults = GETARG_C(i) - 1; | 1611 | int nresults = GETARG_C(i) - 1; |
| 1612 | if (b != 0) /* fixed number of arguments? */ | 1612 | if (b != 0) /* fixed number of arguments? */ |
| 1613 | L->top = ra + b; /* top signals number of arguments */ | 1613 | L->top = ra + b; /* top signals number of arguments */ |
| 1614 | /* else previous instruction set top */ | 1614 | /* else previous instruction set top */ |
| 1615 | savepc(L); /* in case of errors */ | 1615 | savepc(L); /* in case of errors */ |
| 1616 | if (luaD_precall(L, ra, nresults)) | 1616 | if ((newci = luaD_precall(L, ra, nresults)) == NULL) |
| 1617 | updatetrap(ci); /* C call; nothing else to be done */ | 1617 | updatetrap(ci); /* C call; nothing else to be done */ |
| 1618 | else { /* Lua call: run function in this same invocation */ | 1618 | else { /* Lua call: run function in this same invocation */ |
| 1619 | ci = L->ci; | 1619 | ci = newci; |
| 1620 | goto tailcall; | 1620 | ci->callstatus = 0; /* call re-uses 'luaV_execute' */ |
| 1621 | goto execute; | ||
| 1621 | } | 1622 | } |
| 1622 | vmbreak; | 1623 | vmbreak; |
| 1623 | } | 1624 | } |
| @@ -1647,13 +1648,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1647 | luaD_precall(L, ra, LUA_MULTRET); /* call it */ | 1648 | luaD_precall(L, ra, LUA_MULTRET); /* call it */ |
| 1648 | updatetrap(ci); | 1649 | updatetrap(ci); |
| 1649 | updatestack(ci); /* stack may have been relocated */ | 1650 | updatestack(ci); /* stack may have been relocated */ |
| 1650 | ci->func -= delta; | 1651 | ci->func -= delta; /* restore 'func' (if vararg) */ |
| 1651 | luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ | 1652 | luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ |
| 1652 | goto ret; | 1653 | goto ret; /* caller returns after the tail call */ |
| 1653 | } | 1654 | } |
| 1654 | ci->func -= delta; | 1655 | ci->func -= delta; /* restore 'func' (if vararg) */ |
| 1655 | luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ | 1656 | luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ |
| 1656 | goto tailcall; | 1657 | goto execute; /* execute the callee */ |
| 1657 | } | 1658 | } |
| 1658 | vmcase(OP_RETURN) { | 1659 | vmcase(OP_RETURN) { |
| 1659 | int n = GETARG_B(i) - 1; /* number of results */ | 1660 | int n = GETARG_B(i) - 1; /* number of results */ |
| @@ -1706,11 +1707,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1706 | } | 1707 | } |
| 1707 | } | 1708 | } |
| 1708 | ret: | 1709 | ret: |
| 1709 | if (ci == origci) | 1710 | if (ci->callstatus & CIST_FRESH) |
| 1710 | return; | 1711 | return; /* end this frame */ |
| 1711 | else { | 1712 | else { |
| 1712 | ci = ci->previous; | 1713 | ci = ci->previous; |
| 1713 | goto tailcall; | 1714 | goto execute; /* continue running caller in this frame */ |
| 1714 | } | 1715 | } |
| 1715 | } | 1716 | } |
| 1716 | vmcase(OP_FORLOOP) { | 1717 | vmcase(OP_FORLOOP) { |
