aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-09-21 10:31:03 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-10-12 12:29:09 -0300
commit5d8ce05b3f6fad79e37ed21c1076e47a322472c6 (patch)
tree7629a59887da63d44267e872bc8e33be6db36582
parentf83de8e34e24e30acf277f60de62a33bd51d1ddd (diff)
downloadlua-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.c51
-rw-r--r--ldo.h1
-rw-r--r--lparser.c12
-rw-r--r--lstate.c43
-rw-r--r--lstate.h7
-rw-r--r--ltests.h5
-rw-r--r--luaconf.h8
-rw-r--r--lvm.c27
-rw-r--r--testes/all.lua4
-rw-r--r--testes/cstack.lua2
-rw-r--r--testes/errors.lua7
11 files changed, 72 insertions, 95 deletions
diff --git a/ldo.c b/ldo.c
index 5473815a..dc3cc9fd 100644
--- a/ldo.c
+++ b/ldo.c
@@ -139,8 +139,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
139 139
140 140
141int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { 141int 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*/
354void luaD_tryfuncTM (lua_State *L, StkId func) { 353void 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*/
457void luaD_call (lua_State *L, StkId func, int nresults) { 456int 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
514static 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
522void 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*/
519void luaD_callnoyield (lua_State *L, StkId func, int nResults) { 536void 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);
diff --git a/ldo.h b/ldo.h
index 6c6cb285..7d032117 100644
--- a/ldo.h
+++ b/ldo.h
@@ -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);
60LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); 60LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
61LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); 61LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
62LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nResults);
62LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); 63LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
63LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); 64LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
64LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); 65LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
diff --git a/lparser.c b/lparser.c
index bc7d9a4f..502a9b2d 100644
--- a/lparser.c
+++ b/lparser.c
@@ -489,12 +489,14 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
489} 489}
490 490
491 491
492/* 492static 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/*
diff --git a/lstate.c b/lstate.c
index 86b3761f..8cda3072 100644
--- a/lstate.c
+++ b/lstate.c
@@ -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
135void 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
156CallInfo *luaE_extendCI (lua_State *L) { 122CallInfo *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;
diff --git a/lstate.h b/lstate.h
index c1c38204..983aa0d5 100644
--- a/lstate.h
+++ b/lstate.h
@@ -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);
389LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); 383LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
390LUAI_FUNC void luaE_freeCI (lua_State *L); 384LUAI_FUNC void luaE_freeCI (lua_State *L);
391LUAI_FUNC void luaE_shrinkCI (lua_State *L); 385LUAI_FUNC void luaE_shrinkCI (lua_State *L);
392LUAI_FUNC void luaE_enterCcall (lua_State *L);
393LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); 386LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
394LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); 387LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
395 388
diff --git a/ltests.h b/ltests.h
index e9219e29..f8c4466f 100644
--- a/ltests.h
+++ b/ltests.h
@@ -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
diff --git a/luaconf.h b/luaconf.h
index bdf927e7..229413d2 100644
--- a/luaconf.h
+++ b/luaconf.h
@@ -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
diff --git a/lvm.c b/lvm.c
index 08681af1..a232e1e7 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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
1126void luaV_execute (lua_State *L, CallInfo *ci) { 1126void 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
133end 133end
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
4do return end
5
4local debug = require "debug" 6local debug = require "debug"
5 7
6print"testing C-stack overflow detection" 8print"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")))
537end 536end
538 537
539testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment 538testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment