diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-09-21 10:31:03 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-10-12 12:29:09 -0300 |
commit | 5d8ce05b3f6fad79e37ed21c1076e47a322472c6 (patch) | |
tree | 7629a59887da63d44267e872bc8e33be6db36582 /ldo.c | |
parent | f83de8e34e24e30acf277f60de62a33bd51d1ddd (diff) | |
download | lua-5d8ce05b3f6fad79e37ed21c1076e47a322472c6.tar.gz lua-5d8ce05b3f6fad79e37ed21c1076e47a322472c6.tar.bz2 lua-5d8ce05b3f6fad79e37ed21c1076e47a322472c6.zip |
Back to a stackless implementation
A "with stack" implementation gains too little in performance to be
worth all the noise from C-stack overflows.
This commit is almost a sketch, to test performance. There are several
pending stuff:
- review control of C-stack overflow and error messages;
- what to do with setcstacklimit;
- review comments;
- review unroll of Lua calls.
Diffstat (limited to 'ldo.c')
-rw-r--r-- | ldo.c | 51 |
1 files changed, 31 insertions, 20 deletions
@@ -139,8 +139,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
139 | 139 | ||
140 | 140 | ||
141 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | 141 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { |
142 | global_State *g = G(L); | 142 | l_uint32 oldnCcalls = L->nCcalls; |
143 | l_uint32 oldnCcalls = g->Cstacklimit - (L->nCcalls + L->nci); | ||
144 | struct lua_longjmp lj; | 143 | struct lua_longjmp lj; |
145 | lj.status = LUA_OK; | 144 | lj.status = LUA_OK; |
146 | lj.previous = L->errorJmp; /* chain new error handler */ | 145 | lj.previous = L->errorJmp; /* chain new error handler */ |
@@ -149,7 +148,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
149 | (*f)(L, ud); | 148 | (*f)(L, ud); |
150 | ); | 149 | ); |
151 | L->errorJmp = lj.previous; /* restore old error handler */ | 150 | L->errorJmp = lj.previous; /* restore old error handler */ |
152 | L->nCcalls = g->Cstacklimit - oldnCcalls - L->nci; | 151 | L->nCcalls = oldnCcalls; |
153 | return lj.status; | 152 | return lj.status; |
154 | } | 153 | } |
155 | 154 | ||
@@ -348,7 +347,7 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { | |||
348 | 347 | ||
349 | /* | 348 | /* |
350 | ** Check whether 'func' has a '__call' metafield. If so, put it in the | 349 | ** Check whether 'func' has a '__call' metafield. If so, put it in the |
351 | ** stack, below original 'func', so that 'luaD_call' can call it. Raise | 350 | ** stack, below original 'func', so that 'luaD_precall' can call it. Raise |
352 | ** an error if there is no '__call' metafield. | 351 | ** an error if there is no '__call' metafield. |
353 | */ | 352 | */ |
354 | void luaD_tryfuncTM (lua_State *L, StkId func) { | 353 | void luaD_tryfuncTM (lua_State *L, StkId func) { |
@@ -454,7 +453,7 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { | |||
454 | ** When returns, all the results are on the stack, starting at the original | 453 | ** When returns, all the results are on the stack, starting at the original |
455 | ** function position. | 454 | ** function position. |
456 | */ | 455 | */ |
457 | void luaD_call (lua_State *L, StkId func, int nresults) { | 456 | int luaD_precall (lua_State *L, StkId func, int nresults) { |
458 | lua_CFunction f; | 457 | lua_CFunction f; |
459 | retry: | 458 | retry: |
460 | switch (ttypetag(s2v(func))) { | 459 | switch (ttypetag(s2v(func))) { |
@@ -482,7 +481,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
482 | lua_lock(L); | 481 | lua_lock(L); |
483 | api_checknelems(L, n); | 482 | api_checknelems(L, n); |
484 | luaD_poscall(L, ci, n); | 483 | luaD_poscall(L, ci, n); |
485 | break; | 484 | return 1; |
486 | } | 485 | } |
487 | case LUA_VLCL: { /* Lua function */ | 486 | case LUA_VLCL: { /* Lua function */ |
488 | CallInfo *ci; | 487 | CallInfo *ci; |
@@ -501,8 +500,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
501 | for (; narg < nfixparams; narg++) | 500 | for (; narg < nfixparams; narg++) |
502 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ | 501 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ |
503 | lua_assert(ci->top <= L->stack_last); | 502 | lua_assert(ci->top <= L->stack_last); |
504 | luaV_execute(L, ci); /* run the function */ | 503 | return 0; |
505 | break; | ||
506 | } | 504 | } |
507 | default: { /* not a function */ | 505 | default: { /* not a function */ |
508 | checkstackGCp(L, 1, func); /* space for metamethod */ | 506 | checkstackGCp(L, 1, func); /* space for metamethod */ |
@@ -513,17 +511,32 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
513 | } | 511 | } |
514 | 512 | ||
515 | 513 | ||
514 | static void stackerror (lua_State *L) { | ||
515 | if (getCcalls(L) == LUAI_MAXCCALLS) | ||
516 | luaG_runerror(L, "C stack overflow"); | ||
517 | else if (getCcalls(L) >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) | ||
518 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ | ||
519 | } | ||
520 | |||
521 | |||
522 | void luaD_call (lua_State *L, StkId func, int nResults) { | ||
523 | L->nCcalls++; | ||
524 | if (getCcalls(L) >= LUAI_MAXCCALLS) | ||
525 | stackerror(L); | ||
526 | if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ | ||
527 | luaV_execute(L, L->ci); /* call it */ | ||
528 | L->nCcalls--; | ||
529 | } | ||
530 | |||
531 | |||
532 | |||
516 | /* | 533 | /* |
517 | ** Similar to 'luaD_call', but does not allow yields during the call. | 534 | ** Similar to 'luaD_call', but does not allow yields during the call. |
518 | */ | 535 | */ |
519 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | 536 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { |
520 | incXCcalls(L); | 537 | incnny(L); |
521 | if (getCcalls(L) <= CSTACKERR) { /* possible C stack overflow? */ | ||
522 | luaE_exitCcall(L); /* to compensate decrement in next call */ | ||
523 | luaE_enterCcall(L); /* check properly */ | ||
524 | } | ||
525 | luaD_call(L, func, nResults); | 538 | luaD_call(L, func, nResults); |
526 | decXCcalls(L); | 539 | decnny(L); |
527 | } | 540 | } |
528 | 541 | ||
529 | 542 | ||
@@ -638,7 +651,8 @@ static void resume (lua_State *L, void *ud) { | |||
638 | StkId firstArg = L->top - n; /* first argument */ | 651 | StkId firstArg = L->top - n; /* first argument */ |
639 | CallInfo *ci = L->ci; | 652 | CallInfo *ci = L->ci; |
640 | if (L->status == LUA_OK) { /* starting a coroutine? */ | 653 | if (L->status == LUA_OK) { /* starting a coroutine? */ |
641 | luaD_call(L, firstArg - 1, LUA_MULTRET); | 654 | if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ |
655 | luaV_execute(L, L->ci); /* call it */ | ||
642 | } | 656 | } |
643 | else { /* resuming from previous yield */ | 657 | else { /* resuming from previous yield */ |
644 | lua_assert(L->status == LUA_YIELD); | 658 | lua_assert(L->status == LUA_YIELD); |
@@ -670,11 +684,8 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
670 | } | 684 | } |
671 | else if (L->status != LUA_YIELD) /* ended with errors? */ | 685 | else if (L->status != LUA_YIELD) /* ended with errors? */ |
672 | return resume_error(L, "cannot resume dead coroutine", nargs); | 686 | return resume_error(L, "cannot resume dead coroutine", nargs); |
673 | if (from == NULL) | 687 | L->nCcalls = (from) ? getCcalls(from) + 1 : 1; |
674 | L->nCcalls = CSTACKTHREAD; | 688 | if (getCcalls(L) >= LUAI_MAXCCALLS) |
675 | else /* correct 'nCcalls' for this thread */ | ||
676 | L->nCcalls = getCcalls(from) - L->nci - CSTACKCF; | ||
677 | if (L->nCcalls <= CSTACKERR) | ||
678 | return resume_error(L, "C stack overflow", nargs); | 689 | return resume_error(L, "C stack overflow", nargs); |
679 | luai_userstateresume(L, nargs); | 690 | luai_userstateresume(L, nargs); |
680 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 691 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |