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 | |
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.
-rw-r--r-- | ldo.c | 51 | ||||
-rw-r--r-- | ldo.h | 1 | ||||
-rw-r--r-- | lparser.c | 12 | ||||
-rw-r--r-- | lstate.c | 43 | ||||
-rw-r--r-- | lstate.h | 7 | ||||
-rw-r--r-- | ltests.h | 5 | ||||
-rw-r--r-- | luaconf.h | 8 | ||||
-rw-r--r-- | lvm.c | 27 | ||||
-rw-r--r-- | testes/all.lua | 4 | ||||
-rw-r--r-- | testes/cstack.lua | 2 | ||||
-rw-r--r-- | testes/errors.lua | 7 |
11 files changed, 72 insertions, 95 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); |
@@ -59,6 +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 void luaD_call (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_callnoyield (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_tryfuncTM (lua_State *L, StkId func); | 65 | LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); |
@@ -489,12 +489,14 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { | |||
489 | } | 489 | } |
490 | 490 | ||
491 | 491 | ||
492 | /* | 492 | static void enterlevel (LexState *ls) { |
493 | ** Macros to limit the maximum recursion depth while parsing | 493 | lua_State *L = ls->L; |
494 | */ | 494 | L->nCcalls++; |
495 | #define enterlevel(ls) luaE_enterCcall((ls)->L) | 495 | checklimit(ls->fs, getCcalls(L), LUAI_MAXCCALLS, "C levels"); |
496 | } | ||
497 | |||
496 | 498 | ||
497 | #define leavelevel(ls) luaE_exitCcall((ls)->L) | 499 | #define leavelevel(ls) ((ls)->L->nCcalls--) |
498 | 500 | ||
499 | 501 | ||
500 | /* | 502 | /* |
@@ -119,44 +119,9 @@ LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) { | |||
119 | } | 119 | } |
120 | 120 | ||
121 | 121 | ||
122 | /* | ||
123 | ** Decrement count of "C calls" and check for overflows. In case of | ||
124 | ** a stack overflow, check appropriate error ("regular" overflow or | ||
125 | ** overflow while handling stack overflow). If 'nCcalls' is smaller | ||
126 | ** than CSTACKERR but larger than CSTACKMARK, it means it has just | ||
127 | ** entered the "overflow zone", so the function raises an overflow | ||
128 | ** error. If 'nCcalls' is smaller than CSTACKMARK (which means it is | ||
129 | ** already handling an overflow) but larger than CSTACKERRMARK, does | ||
130 | ** not report an error (to allow message handling to work). Otherwise, | ||
131 | ** report a stack overflow while handling a stack overflow (probably | ||
132 | ** caused by a repeating error in the message handling function). | ||
133 | */ | ||
134 | |||
135 | void luaE_enterCcall (lua_State *L) { | ||
136 | int ncalls = getCcalls(L); | ||
137 | L->nCcalls--; | ||
138 | if (ncalls <= CSTACKERR) { /* possible overflow? */ | ||
139 | luaE_freeCI(L); /* release unused CIs */ | ||
140 | ncalls = getCcalls(L); /* update call count */ | ||
141 | if (ncalls <= CSTACKERR) { /* still overflow? */ | ||
142 | if (ncalls <= CSTACKERRMARK) /* below error-handling zone? */ | ||
143 | luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ | ||
144 | else if (ncalls >= CSTACKMARK) { | ||
145 | /* not in error-handling zone; raise the error now */ | ||
146 | L->nCcalls = (CSTACKMARK - 1); /* enter error-handling zone */ | ||
147 | luaG_runerror(L, "C stack overflow"); | ||
148 | } | ||
149 | /* else stack is in the error-handling zone; | ||
150 | allow message handler to work */ | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | |||
156 | CallInfo *luaE_extendCI (lua_State *L) { | 122 | CallInfo *luaE_extendCI (lua_State *L) { |
157 | CallInfo *ci; | 123 | CallInfo *ci; |
158 | lua_assert(L->ci->next == NULL); | 124 | lua_assert(L->ci->next == NULL); |
159 | luaE_enterCcall(L); | ||
160 | ci = luaM_new(L, CallInfo); | 125 | ci = luaM_new(L, CallInfo); |
161 | lua_assert(L->ci->next == NULL); | 126 | lua_assert(L->ci->next == NULL); |
162 | L->ci->next = ci; | 127 | L->ci->next = ci; |
@@ -175,13 +140,11 @@ void luaE_freeCI (lua_State *L) { | |||
175 | CallInfo *ci = L->ci; | 140 | CallInfo *ci = L->ci; |
176 | CallInfo *next = ci->next; | 141 | CallInfo *next = ci->next; |
177 | ci->next = NULL; | 142 | ci->next = NULL; |
178 | L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */ | ||
179 | while ((ci = next) != NULL) { | 143 | while ((ci = next) != NULL) { |
180 | next = ci->next; | 144 | next = ci->next; |
181 | luaM_free(L, ci); | 145 | luaM_free(L, ci); |
182 | L->nci--; | 146 | L->nci--; |
183 | } | 147 | } |
184 | L->nCcalls -= L->nci; /* adjust result */ | ||
185 | } | 148 | } |
186 | 149 | ||
187 | 150 | ||
@@ -194,7 +157,6 @@ void luaE_shrinkCI (lua_State *L) { | |||
194 | CallInfo *next; | 157 | CallInfo *next; |
195 | if (ci == NULL) | 158 | if (ci == NULL) |
196 | return; /* no extra elements */ | 159 | return; /* no extra elements */ |
197 | L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */ | ||
198 | while ((next = ci->next) != NULL) { /* two extra elements? */ | 160 | while ((next = ci->next) != NULL) { /* two extra elements? */ |
199 | CallInfo *next2 = next->next; /* next's next */ | 161 | CallInfo *next2 = next->next; /* next's next */ |
200 | ci->next = next2; /* remove next from the list */ | 162 | ci->next = next2; /* remove next from the list */ |
@@ -207,7 +169,6 @@ void luaE_shrinkCI (lua_State *L) { | |||
207 | ci = next2; /* continue */ | 169 | ci = next2; /* continue */ |
208 | } | 170 | } |
209 | } | 171 | } |
210 | L->nCcalls -= L->nci; /* adjust result */ | ||
211 | } | 172 | } |
212 | 173 | ||
213 | 174 | ||
@@ -335,7 +296,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { | |||
335 | setthvalue2s(L, L->top, L1); | 296 | setthvalue2s(L, L->top, L1); |
336 | api_incr_top(L); | 297 | api_incr_top(L); |
337 | preinit_thread(L1, g); | 298 | preinit_thread(L1, g); |
338 | L1->nCcalls = getCcalls(L); | 299 | L1->nCcalls = 0; |
339 | L1->hookmask = L->hookmask; | 300 | L1->hookmask = L->hookmask; |
340 | L1->basehookcount = L->basehookcount; | 301 | L1->basehookcount = L->basehookcount; |
341 | L1->hook = L->hook; | 302 | L1->hook = L->hook; |
@@ -396,7 +357,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
396 | preinit_thread(L, g); | 357 | preinit_thread(L, g); |
397 | g->allgc = obj2gco(L); /* by now, only object is the main thread */ | 358 | g->allgc = obj2gco(L); /* by now, only object is the main thread */ |
398 | L->next = NULL; | 359 | L->next = NULL; |
399 | g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR; | 360 | g->Cstacklimit = L->nCcalls = 0; |
400 | incnny(L); /* main thread is always non yieldable */ | 361 | incnny(L); /* main thread is always non yieldable */ |
401 | g->frealloc = f; | 362 | g->frealloc = f; |
402 | g->ud = ud; | 363 | g->ud = ud; |
@@ -144,12 +144,6 @@ | |||
144 | /* Decrement the number of non-yieldable calls */ | 144 | /* Decrement the number of non-yieldable calls */ |
145 | #define decnny(L) ((L)->nCcalls -= 0x10000) | 145 | #define decnny(L) ((L)->nCcalls -= 0x10000) |
146 | 146 | ||
147 | /* Increment the number of non-yieldable calls and decrement nCcalls */ | ||
148 | #define incXCcalls(L) ((L)->nCcalls += 0x10000 - CSTACKCF) | ||
149 | |||
150 | /* Decrement the number of non-yieldable calls and increment nCcalls */ | ||
151 | #define decXCcalls(L) ((L)->nCcalls -= 0x10000 - CSTACKCF) | ||
152 | |||
153 | 147 | ||
154 | 148 | ||
155 | 149 | ||
@@ -389,7 +383,6 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); | |||
389 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); | 383 | LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); |
390 | LUAI_FUNC void luaE_freeCI (lua_State *L); | 384 | LUAI_FUNC void luaE_freeCI (lua_State *L); |
391 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); | 385 | LUAI_FUNC void luaE_shrinkCI (lua_State *L); |
392 | LUAI_FUNC void luaE_enterCcall (lua_State *L); | ||
393 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); | 386 | LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); |
394 | LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); | 387 | LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); |
395 | 388 | ||
@@ -23,11 +23,6 @@ | |||
23 | #define LUAI_ASSERT | 23 | #define LUAI_ASSERT |
24 | 24 | ||
25 | 25 | ||
26 | |||
27 | /* compiled with -O0, Lua uses a lot of C stack space... */ | ||
28 | #undef LUAI_MAXCSTACK | ||
29 | #define LUAI_MAXCSTACK 400 | ||
30 | |||
31 | /* to avoid warnings, and to make sure value is really unused */ | 26 | /* to avoid warnings, and to make sure value is really unused */ |
32 | #define UNUSED(x) (x=0, (void)(x)) | 27 | #define UNUSED(x) (x=0, (void)(x)) |
33 | 28 | ||
@@ -36,8 +36,8 @@ | |||
36 | ** ===================================================================== | 36 | ** ===================================================================== |
37 | */ | 37 | */ |
38 | 38 | ||
39 | /* | 39 | /* >>> move back to llimits.h |
40 | @@ LUAI_MAXCSTACK defines the maximum depth for nested calls and | 40 | @@ LUAI_MAXCCALLS defines the maximum depth for nested calls and |
41 | ** also limits the maximum depth of other recursive algorithms in | 41 | ** also limits the maximum depth of other recursive algorithms in |
42 | ** the implementation, such as syntactic analysis. A value too | 42 | ** the implementation, such as syntactic analysis. A value too |
43 | ** large may allow the interpreter to crash (C-stack overflow). | 43 | ** large may allow the interpreter to crash (C-stack overflow). |
@@ -46,8 +46,8 @@ | |||
46 | ** The test file 'cstack.lua' may help finding a good limit. | 46 | ** The test file 'cstack.lua' may help finding a good limit. |
47 | ** (It will crash with a limit too high.) | 47 | ** (It will crash with a limit too high.) |
48 | */ | 48 | */ |
49 | #if !defined(LUAI_MAXCSTACK) | 49 | #if !defined(LUAI_MAXCCALLS) |
50 | #define LUAI_MAXCSTACK 2000 | 50 | #define LUAI_MAXCCALLS 200 |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | 53 | ||
@@ -229,7 +229,7 @@ static int forprep (lua_State *L, StkId ra) { | |||
229 | count /= l_castS2U(-(step + 1)) + 1u; | 229 | count /= l_castS2U(-(step + 1)) + 1u; |
230 | } | 230 | } |
231 | /* store the counter in place of the limit (which won't be | 231 | /* store the counter in place of the limit (which won't be |
232 | needed anymore */ | 232 | needed anymore) */ |
233 | setivalue(plimit, l_castU2S(count)); | 233 | setivalue(plimit, l_castU2S(count)); |
234 | } | 234 | } |
235 | } | 235 | } |
@@ -1124,6 +1124,7 @@ 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 | const CallInfo *origci = ci; | ||
1127 | LClosure *cl; | 1128 | LClosure *cl; |
1128 | TValue *k; | 1129 | TValue *k; |
1129 | StkId base; | 1130 | StkId base; |
@@ -1611,7 +1612,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1611 | if (b != 0) /* fixed number of arguments? */ | 1612 | if (b != 0) /* fixed number of arguments? */ |
1612 | L->top = ra + b; /* top signals number of arguments */ | 1613 | L->top = ra + b; /* top signals number of arguments */ |
1613 | /* else previous instruction set top */ | 1614 | /* else previous instruction set top */ |
1614 | ProtectNT(luaD_call(L, ra, nresults)); | 1615 | savepc(L); /* in case of errors */ |
1616 | if (luaD_precall(L, ra, nresults)) | ||
1617 | updatetrap(ci); /* C call; nothing else to be done */ | ||
1618 | else { /* Lua call: run function in this same invocation */ | ||
1619 | ci = L->ci; | ||
1620 | goto tailcall; | ||
1621 | } | ||
1615 | vmbreak; | 1622 | vmbreak; |
1616 | } | 1623 | } |
1617 | vmcase(OP_TAILCALL) { | 1624 | vmcase(OP_TAILCALL) { |
@@ -1637,12 +1644,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1637 | checkstackGCp(L, 1, ra); | 1644 | checkstackGCp(L, 1, ra); |
1638 | } | 1645 | } |
1639 | if (!ttisLclosure(s2v(ra))) { /* C function? */ | 1646 | if (!ttisLclosure(s2v(ra))) { /* C function? */ |
1640 | luaD_call(L, ra, LUA_MULTRET); /* call it */ | 1647 | luaD_precall(L, ra, LUA_MULTRET); /* call it */ |
1641 | updatetrap(ci); | 1648 | updatetrap(ci); |
1642 | updatestack(ci); /* stack may have been relocated */ | 1649 | updatestack(ci); /* stack may have been relocated */ |
1643 | ci->func -= delta; | 1650 | ci->func -= delta; |
1644 | luaD_poscall(L, ci, cast_int(L->top - ra)); | 1651 | luaD_poscall(L, ci, cast_int(L->top - ra)); |
1645 | return; | 1652 | goto ret; |
1646 | } | 1653 | } |
1647 | ci->func -= delta; | 1654 | ci->func -= delta; |
1648 | luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ | 1655 | luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ |
@@ -1665,7 +1672,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1665 | ci->func -= ci->u.l.nextraargs + nparams1; | 1672 | ci->func -= ci->u.l.nextraargs + nparams1; |
1666 | L->top = ra + n; /* set call for 'luaD_poscall' */ | 1673 | L->top = ra + n; /* set call for 'luaD_poscall' */ |
1667 | luaD_poscall(L, ci, n); | 1674 | luaD_poscall(L, ci, n); |
1668 | return; | 1675 | goto ret; |
1669 | } | 1676 | } |
1670 | vmcase(OP_RETURN0) { | 1677 | vmcase(OP_RETURN0) { |
1671 | if (L->hookmask) { | 1678 | if (L->hookmask) { |
@@ -1679,7 +1686,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1679 | while (nres-- > 0) | 1686 | while (nres-- > 0) |
1680 | setnilvalue(s2v(L->top++)); /* all results are nil */ | 1687 | setnilvalue(s2v(L->top++)); /* all results are nil */ |
1681 | } | 1688 | } |
1682 | return; | 1689 | goto ret; |
1683 | } | 1690 | } |
1684 | vmcase(OP_RETURN1) { | 1691 | vmcase(OP_RETURN1) { |
1685 | if (L->hookmask) { | 1692 | if (L->hookmask) { |
@@ -1698,7 +1705,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1698 | setnilvalue(s2v(L->top++)); | 1705 | setnilvalue(s2v(L->top++)); |
1699 | } | 1706 | } |
1700 | } | 1707 | } |
1701 | return; | 1708 | ret: |
1709 | if (ci == origci) | ||
1710 | return; | ||
1711 | else { | ||
1712 | ci = ci->previous; | ||
1713 | goto tailcall; | ||
1714 | } | ||
1702 | } | 1715 | } |
1703 | vmcase(OP_FORLOOP) { | 1716 | vmcase(OP_FORLOOP) { |
1704 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ | 1717 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ |
diff --git a/testes/all.lua b/testes/all.lua index db074dd8..a4feeec1 100644 --- a/testes/all.lua +++ b/testes/all.lua | |||
@@ -127,8 +127,8 @@ else | |||
127 | end | 127 | end |
128 | 128 | ||
129 | Cstacklevel = function () | 129 | Cstacklevel = function () |
130 | local _, _, ncalls, nci = T.stacklevel() | 130 | local _, _, ncalls = T.stacklevel() |
131 | return ncalls + nci -- number of free slots in the C stack | 131 | return ncalls -- number of C calls |
132 | end | 132 | end |
133 | end | 133 | end |
134 | 134 | ||
diff --git a/testes/cstack.lua b/testes/cstack.lua index 4e37b988..c1177f3b 100644 --- a/testes/cstack.lua +++ b/testes/cstack.lua | |||
@@ -1,6 +1,8 @@ | |||
1 | -- $Id: testes/cstack.lua $ | 1 | -- $Id: testes/cstack.lua $ |
2 | -- See Copyright Notice in file all.lua | 2 | -- See Copyright Notice in file all.lua |
3 | 3 | ||
4 | do return end | ||
5 | |||
4 | local debug = require "debug" | 6 | local debug = require "debug" |
5 | 7 | ||
6 | print"testing C-stack overflow detection" | 8 | print"testing C-stack overflow detection" |
diff --git a/testes/errors.lua b/testes/errors.lua index f9623b1d..88918df7 100644 --- a/testes/errors.lua +++ b/testes/errors.lua | |||
@@ -530,10 +530,9 @@ local function testrep (init, rep, close, repc, finalresult) | |||
530 | if (finalresult) then | 530 | if (finalresult) then |
531 | assert(res() == finalresult) | 531 | assert(res() == finalresult) |
532 | end | 532 | end |
533 | s = init .. string.rep(rep, 10000) | 533 | s = init .. string.rep(rep, 500) |
534 | local res, msg = load(s) -- 10000 levels not ok | 534 | local res, msg = load(s) -- 500 levels not ok |
535 | assert(not res and (string.find(msg, "too many registers") or | 535 | assert(not res and string.find(msg, "too many")) |
536 | string.find(msg, "stack overflow"))) | ||
537 | end | 536 | end |
538 | 537 | ||
539 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment | 538 | testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment |