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) { |