diff options
Diffstat (limited to 'src/lua/ldo.c')
-rw-r--r-- | src/lua/ldo.c | 145 |
1 files changed, 90 insertions, 55 deletions
diff --git a/src/lua/ldo.c b/src/lua/ldo.c index 5473815..5729b19 100644 --- a/src/lua/ldo.c +++ b/src/lua/ldo.c | |||
@@ -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 | ||
@@ -183,10 +182,10 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { | |||
183 | 182 | ||
184 | 183 | ||
185 | int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | 184 | int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { |
186 | int lim = L->stacksize; | 185 | int lim = stacksize(L); |
187 | StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue); | 186 | StkId newstack = luaM_reallocvector(L, L->stack, |
187 | lim + EXTRA_STACK, newsize + EXTRA_STACK, StackValue); | ||
188 | lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); | 188 | lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); |
189 | lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); | ||
190 | if (unlikely(newstack == NULL)) { /* reallocation failed? */ | 189 | if (unlikely(newstack == NULL)) { /* reallocation failed? */ |
191 | if (raiseerror) | 190 | if (raiseerror) |
192 | luaM_error(L); | 191 | luaM_error(L); |
@@ -196,8 +195,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | |||
196 | setnilvalue(s2v(newstack + lim)); /* erase new segment */ | 195 | setnilvalue(s2v(newstack + lim)); /* erase new segment */ |
197 | correctstack(L, L->stack, newstack); | 196 | correctstack(L, L->stack, newstack); |
198 | L->stack = newstack; | 197 | L->stack = newstack; |
199 | L->stacksize = newsize; | 198 | L->stack_last = L->stack + newsize; |
200 | L->stack_last = L->stack + newsize - EXTRA_STACK; | ||
201 | return 1; | 199 | return 1; |
202 | } | 200 | } |
203 | 201 | ||
@@ -207,51 +205,73 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | |||
207 | ** is true, raises any error; otherwise, return 0 in case of errors. | 205 | ** is true, raises any error; otherwise, return 0 in case of errors. |
208 | */ | 206 | */ |
209 | int luaD_growstack (lua_State *L, int n, int raiseerror) { | 207 | int luaD_growstack (lua_State *L, int n, int raiseerror) { |
210 | int size = L->stacksize; | 208 | int size = stacksize(L); |
211 | int newsize = 2 * size; /* tentative new size */ | 209 | if (unlikely(size > LUAI_MAXSTACK)) { |
212 | if (unlikely(size > LUAI_MAXSTACK)) { /* need more space after extra size? */ | 210 | /* if stack is larger than maximum, thread is already using the |
211 | extra space reserved for errors, that is, thread is handling | ||
212 | a stack error; cannot grow further than that. */ | ||
213 | lua_assert(stacksize(L) == ERRORSTACKSIZE); | ||
213 | if (raiseerror) | 214 | if (raiseerror) |
214 | luaD_throw(L, LUA_ERRERR); /* error inside message handler */ | 215 | luaD_throw(L, LUA_ERRERR); /* error inside message handler */ |
215 | else return 0; | 216 | return 0; /* if not 'raiseerror', just signal it */ |
216 | } | 217 | } |
217 | else { | 218 | else { |
218 | int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; | 219 | int newsize = 2 * size; /* tentative new size */ |
220 | int needed = cast_int(L->top - L->stack) + n; | ||
219 | if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ | 221 | if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ |
220 | newsize = LUAI_MAXSTACK; | 222 | newsize = LUAI_MAXSTACK; |
221 | if (newsize < needed) /* but must respect what was asked for */ | 223 | if (newsize < needed) /* but must respect what was asked for */ |
222 | newsize = needed; | 224 | newsize = needed; |
223 | if (unlikely(newsize > LUAI_MAXSTACK)) { /* stack overflow? */ | 225 | if (likely(newsize <= LUAI_MAXSTACK)) |
226 | return luaD_reallocstack(L, newsize, raiseerror); | ||
227 | else { /* stack overflow */ | ||
224 | /* add extra size to be able to handle the error message */ | 228 | /* add extra size to be able to handle the error message */ |
225 | luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); | 229 | luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); |
226 | if (raiseerror) | 230 | if (raiseerror) |
227 | luaG_runerror(L, "stack overflow"); | 231 | luaG_runerror(L, "stack overflow"); |
228 | else return 0; | 232 | return 0; |
229 | } | 233 | } |
230 | } /* else no errors */ | 234 | } |
231 | return luaD_reallocstack(L, newsize, raiseerror); | ||
232 | } | 235 | } |
233 | 236 | ||
234 | 237 | ||
235 | static int stackinuse (lua_State *L) { | 238 | static int stackinuse (lua_State *L) { |
236 | CallInfo *ci; | 239 | CallInfo *ci; |
240 | int res; | ||
237 | StkId lim = L->top; | 241 | StkId lim = L->top; |
238 | for (ci = L->ci; ci != NULL; ci = ci->previous) { | 242 | for (ci = L->ci; ci != NULL; ci = ci->previous) { |
239 | if (lim < ci->top) lim = ci->top; | 243 | if (lim < ci->top) lim = ci->top; |
240 | } | 244 | } |
241 | lua_assert(lim <= L->stack_last); | 245 | lua_assert(lim <= L->stack_last); |
242 | return cast_int(lim - L->stack) + 1; /* part of stack in use */ | 246 | res = cast_int(lim - L->stack) + 1; /* part of stack in use */ |
247 | if (res < LUA_MINSTACK) | ||
248 | res = LUA_MINSTACK; /* ensure a minimum size */ | ||
249 | return res; | ||
243 | } | 250 | } |
244 | 251 | ||
245 | 252 | ||
253 | /* | ||
254 | ** If stack size is more than 3 times the current use, reduce that size | ||
255 | ** to twice the current use. (So, the final stack size is at most 2/3 the | ||
256 | ** previous size, and half of its entries are empty.) | ||
257 | ** As a particular case, if stack was handling a stack overflow and now | ||
258 | ** it is not, 'max' (limited by LUAI_MAXSTACK) will be smaller than | ||
259 | ** stacksize (equal to ERRORSTACKSIZE in this case), and so the stack | ||
260 | ** will be reduced to a "regular" size. | ||
261 | */ | ||
246 | void luaD_shrinkstack (lua_State *L) { | 262 | void luaD_shrinkstack (lua_State *L) { |
247 | int inuse = stackinuse(L); | 263 | int inuse = stackinuse(L); |
248 | int goodsize = inuse + BASIC_STACK_SIZE; | 264 | int nsize = inuse * 2; /* proposed new size */ |
249 | if (goodsize > LUAI_MAXSTACK) | 265 | int max = inuse * 3; /* maximum "reasonable" size */ |
250 | goodsize = LUAI_MAXSTACK; /* respect stack limit */ | 266 | if (max > LUAI_MAXSTACK) { |
267 | max = LUAI_MAXSTACK; /* respect stack limit */ | ||
268 | if (nsize > LUAI_MAXSTACK) | ||
269 | nsize = LUAI_MAXSTACK; | ||
270 | } | ||
251 | /* if thread is currently not handling a stack overflow and its | 271 | /* if thread is currently not handling a stack overflow and its |
252 | good size is smaller than current size, shrink its stack */ | 272 | size is larger than maximum "reasonable" size, shrink it */ |
253 | if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && goodsize < L->stacksize) | 273 | if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) |
254 | luaD_reallocstack(L, goodsize, 0); /* ok if that fails */ | 274 | luaD_reallocstack(L, nsize, 0); /* ok if that fails */ |
255 | else /* don't change stack */ | 275 | else /* don't change stack */ |
256 | condmovestack(L,{},{}); /* (change only for debugging) */ | 276 | condmovestack(L,{},{}); /* (change only for debugging) */ |
257 | luaE_shrinkCI(L); /* shrink CI list */ | 277 | luaE_shrinkCI(L); /* shrink CI list */ |
@@ -348,7 +368,7 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { | |||
348 | 368 | ||
349 | /* | 369 | /* |
350 | ** Check whether 'func' has a '__call' metafield. If so, put it in the | 370 | ** 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 | 371 | ** stack, below original 'func', so that 'luaD_precall' can call it. Raise |
352 | ** an error if there is no '__call' metafield. | 372 | ** an error if there is no '__call' metafield. |
353 | */ | 373 | */ |
354 | void luaD_tryfuncTM (lua_State *L, StkId func) { | 374 | void luaD_tryfuncTM (lua_State *L, StkId func) { |
@@ -449,12 +469,14 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { | |||
449 | 469 | ||
450 | 470 | ||
451 | /* | 471 | /* |
452 | ** Call a function (C or Lua). The function to be called is at *func. | 472 | ** Prepares the call to a function (C or Lua). For C functions, also do |
453 | ** The arguments are on the stack, right after the function. | 473 | ** the call. The function to be called is at '*func'. The arguments |
454 | ** When returns, all the results are on the stack, starting at the original | 474 | ** are on the stack, right after the function. Returns the CallInfo |
455 | ** function position. | 475 | ** to be executed, if it was a Lua function. Otherwise (a C function) |
476 | ** returns NULL, with all the results on the stack, starting at the | ||
477 | ** original function position. | ||
456 | */ | 478 | */ |
457 | void luaD_call (lua_State *L, StkId func, int nresults) { | 479 | CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { |
458 | lua_CFunction f; | 480 | lua_CFunction f; |
459 | retry: | 481 | retry: |
460 | switch (ttypetag(s2v(func))) { | 482 | switch (ttypetag(s2v(func))) { |
@@ -482,7 +504,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
482 | lua_lock(L); | 504 | lua_lock(L); |
483 | api_checknelems(L, n); | 505 | api_checknelems(L, n); |
484 | luaD_poscall(L, ci, n); | 506 | luaD_poscall(L, ci, n); |
485 | break; | 507 | return NULL; |
486 | } | 508 | } |
487 | case LUA_VLCL: { /* Lua function */ | 509 | case LUA_VLCL: { /* Lua function */ |
488 | CallInfo *ci; | 510 | CallInfo *ci; |
@@ -494,15 +516,13 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
494 | L->ci = ci = next_ci(L); | 516 | L->ci = ci = next_ci(L); |
495 | ci->nresults = nresults; | 517 | ci->nresults = nresults; |
496 | ci->u.l.savedpc = p->code; /* starting point */ | 518 | ci->u.l.savedpc = p->code; /* starting point */ |
497 | ci->callstatus = 0; | ||
498 | ci->top = func + 1 + fsize; | 519 | ci->top = func + 1 + fsize; |
499 | ci->func = func; | 520 | ci->func = func; |
500 | L->ci = ci; | 521 | L->ci = ci; |
501 | for (; narg < nfixparams; narg++) | 522 | for (; narg < nfixparams; narg++) |
502 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ | 523 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ |
503 | lua_assert(ci->top <= L->stack_last); | 524 | lua_assert(ci->top <= L->stack_last); |
504 | luaV_execute(L, ci); /* run the function */ | 525 | return ci; |
505 | break; | ||
506 | } | 526 | } |
507 | default: { /* not a function */ | 527 | default: { /* not a function */ |
508 | checkstackGCp(L, 1, func); /* space for metamethod */ | 528 | checkstackGCp(L, 1, func); /* space for metamethod */ |
@@ -514,16 +534,36 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
514 | 534 | ||
515 | 535 | ||
516 | /* | 536 | /* |
537 | ** Call a function (C or Lua). 'inc' can be 1 (increment number | ||
538 | ** of recursive invocations in the C stack) or nyci (the same plus | ||
539 | ** increment number of non-yieldable calls). | ||
540 | */ | ||
541 | static void docall (lua_State *L, StkId func, int nResults, int inc) { | ||
542 | CallInfo *ci; | ||
543 | L->nCcalls += inc; | ||
544 | if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) | ||
545 | luaE_checkcstack(L); | ||
546 | if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ | ||
547 | ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ | ||
548 | luaV_execute(L, ci); /* call it */ | ||
549 | } | ||
550 | L->nCcalls -= inc; | ||
551 | } | ||
552 | |||
553 | |||
554 | /* | ||
555 | ** External interface for 'docall' | ||
556 | */ | ||
557 | void luaD_call (lua_State *L, StkId func, int nResults) { | ||
558 | return docall(L, func, nResults, 1); | ||
559 | } | ||
560 | |||
561 | |||
562 | /* | ||
517 | ** Similar to 'luaD_call', but does not allow yields during the call. | 563 | ** Similar to 'luaD_call', but does not allow yields during the call. |
518 | */ | 564 | */ |
519 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | 565 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { |
520 | incXCcalls(L); | 566 | return docall(L, func, nResults, nyci); |
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); | ||
526 | decXCcalls(L); | ||
527 | } | 567 | } |
528 | 568 | ||
529 | 569 | ||
@@ -601,12 +641,12 @@ static int recover (lua_State *L, int status) { | |||
601 | if (ci == NULL) return 0; /* no recovery point */ | 641 | if (ci == NULL) return 0; /* no recovery point */ |
602 | /* "finish" luaD_pcall */ | 642 | /* "finish" luaD_pcall */ |
603 | oldtop = restorestack(L, ci->u2.funcidx); | 643 | oldtop = restorestack(L, ci->u2.funcidx); |
604 | luaF_close(L, oldtop, status); /* may change the stack */ | ||
605 | oldtop = restorestack(L, ci->u2.funcidx); | ||
606 | luaD_seterrorobj(L, status, oldtop); | ||
607 | L->ci = ci; | 644 | L->ci = ci; |
608 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | 645 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ |
609 | luaD_shrinkstack(L); | 646 | status = luaF_close(L, oldtop, status); /* may change the stack */ |
647 | oldtop = restorestack(L, ci->u2.funcidx); | ||
648 | luaD_seterrorobj(L, status, oldtop); | ||
649 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | ||
610 | L->errfunc = ci->u.c.old_errfunc; | 650 | L->errfunc = ci->u.c.old_errfunc; |
611 | return 1; /* continue running the coroutine */ | 651 | return 1; /* continue running the coroutine */ |
612 | } | 652 | } |
@@ -637,12 +677,12 @@ static void resume (lua_State *L, void *ud) { | |||
637 | int n = *(cast(int*, ud)); /* number of arguments */ | 677 | int n = *(cast(int*, ud)); /* number of arguments */ |
638 | StkId firstArg = L->top - n; /* first argument */ | 678 | StkId firstArg = L->top - n; /* first argument */ |
639 | CallInfo *ci = L->ci; | 679 | CallInfo *ci = L->ci; |
640 | if (L->status == LUA_OK) { /* starting a coroutine? */ | 680 | if (L->status == LUA_OK) /* starting a coroutine? */ |
641 | luaD_call(L, firstArg - 1, LUA_MULTRET); | 681 | docall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ |
642 | } | ||
643 | else { /* resuming from previous yield */ | 682 | else { /* resuming from previous yield */ |
644 | lua_assert(L->status == LUA_YIELD); | 683 | lua_assert(L->status == LUA_YIELD); |
645 | L->status = LUA_OK; /* mark that it is running (again) */ | 684 | L->status = LUA_OK; /* mark that it is running (again) */ |
685 | luaE_incCstack(L); /* control the C stack */ | ||
646 | if (isLua(ci)) /* yielded inside a hook? */ | 686 | if (isLua(ci)) /* yielded inside a hook? */ |
647 | luaV_execute(L, ci); /* just continue running Lua code */ | 687 | luaV_execute(L, ci); /* just continue running Lua code */ |
648 | else { /* 'common' yield */ | 688 | else { /* 'common' yield */ |
@@ -670,12 +710,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
670 | } | 710 | } |
671 | else if (L->status != LUA_YIELD) /* ended with errors? */ | 711 | else if (L->status != LUA_YIELD) /* ended with errors? */ |
672 | return resume_error(L, "cannot resume dead coroutine", nargs); | 712 | return resume_error(L, "cannot resume dead coroutine", nargs); |
673 | if (from == NULL) | 713 | L->nCcalls = (from) ? getCcalls(from) : 0; |
674 | L->nCcalls = CSTACKTHREAD; | ||
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); | ||
679 | luai_userstateresume(L, nargs); | 714 | luai_userstateresume(L, nargs); |
680 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 715 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
681 | status = luaD_rawrunprotected(L, resume, &nargs); | 716 | status = luaD_rawrunprotected(L, resume, &nargs); |
@@ -754,7 +789,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
754 | status = luaF_close(L, oldtop, status); | 789 | status = luaF_close(L, oldtop, status); |
755 | oldtop = restorestack(L, old_top); /* previous call may change stack */ | 790 | oldtop = restorestack(L, old_top); /* previous call may change stack */ |
756 | luaD_seterrorobj(L, status, oldtop); | 791 | luaD_seterrorobj(L, status, oldtop); |
757 | luaD_shrinkstack(L); | 792 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
758 | } | 793 | } |
759 | L->errfunc = old_errfunc; | 794 | L->errfunc = old_errfunc; |
760 | return status; | 795 | return status; |