diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-11-23 14:41:16 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-11-23 14:41:16 -0200 |
| commit | 196c87c9cecfacf978f37de4ec69eba0a5971256 (patch) | |
| tree | ce434c8a63228cf1f25adcc2210ba741ee899887 /ldo.c | |
| parent | 39f26b1480502cc2f75a5af6e06e5410e06634ba (diff) | |
| download | lua-196c87c9cecfacf978f37de4ec69eba0a5971256.tar.gz lua-196c87c9cecfacf978f37de4ec69eba0a5971256.tar.bz2 lua-196c87c9cecfacf978f37de4ec69eba0a5971256.zip | |
no more 'stackless' implementation; 'luaV_execute' calls itself
recursively to execute function calls. 'unroll' continues all
executions suspended by an yield (through a long jump)
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 66 |
1 files changed, 18 insertions, 48 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.172 2017/11/13 15:36:52 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.173 2017/11/21 14:17:35 roberto Exp roberto $ |
| 3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -135,7 +135,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
| 135 | 135 | ||
| 136 | 136 | ||
| 137 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | 137 | int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { |
| 138 | unsigned short oldnCcalls = L->nCcalls; | 138 | unsigned short oldnCcalls = L->nCcalls - L->nci; |
| 139 | struct lua_longjmp lj; | 139 | struct lua_longjmp lj; |
| 140 | lj.status = LUA_OK; | 140 | lj.status = LUA_OK; |
| 141 | lj.previous = L->errorJmp; /* chain new error handler */ | 141 | lj.previous = L->errorJmp; /* chain new error handler */ |
| @@ -144,7 +144,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
| 144 | (*f)(L, ud); | 144 | (*f)(L, ud); |
| 145 | ); | 145 | ); |
| 146 | L->errorJmp = lj.previous; /* restore old error handler */ | 146 | L->errorJmp = lj.previous; /* restore old error handler */ |
| 147 | L->nCcalls = oldnCcalls; | 147 | L->nCcalls = oldnCcalls + L->nci; |
| 148 | return lj.status; | 148 | return lj.status; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| @@ -299,7 +299,7 @@ static void callhook (lua_State *L, CallInfo *ci, int istail) { | |||
| 299 | 299 | ||
| 300 | /* | 300 | /* |
| 301 | ** Check whether __call metafield of 'func' is a function. If so, put | 301 | ** Check whether __call metafield of 'func' is a function. If so, put |
| 302 | ** it in stack below original 'func' so that 'luaD_precall' can call | 302 | ** it in stack below original 'func' so that 'luaD_call' can call |
| 303 | ** it. Raise an error if __call metafield is not a function. | 303 | ** it. Raise an error if __call metafield is not a function. |
| 304 | */ | 304 | */ |
| 305 | StkId luaD_tryfuncTM (lua_State *L, StkId func) { | 305 | StkId luaD_tryfuncTM (lua_State *L, StkId func) { |
| @@ -417,13 +417,12 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n) { | |||
| 417 | 417 | ||
| 418 | 418 | ||
| 419 | /* | 419 | /* |
| 420 | ** Prepares a function call: checks the stack, creates a new CallInfo | 420 | ** Call a function (C or Lua). The function to be called is at *func. |
| 421 | ** entry, fills in the relevant information, calls hook if needed. | 421 | ** The arguments are on the stack, right after the function. |
| 422 | ** If function is a C function, does the call, too. (Otherwise, leave | 422 | ** When returns, all the results are on the stack, starting at the original |
| 423 | ** the execution ('luaV_execute') to the caller, to allow stackless | 423 | ** function position. |
| 424 | ** calls.) Returns true iff function has been executed (C function). | ||
| 425 | */ | 424 | */ |
| 426 | int luaD_precall (lua_State *L, StkId func, int nresults) { | 425 | void luaD_call (lua_State *L, StkId func, int nresults) { |
| 427 | lua_CFunction f; | 426 | lua_CFunction f; |
| 428 | TValue *funcv = s2v(func); | 427 | TValue *funcv = s2v(func); |
| 429 | CallInfo *ci; | 428 | CallInfo *ci; |
| @@ -449,7 +448,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 449 | lua_lock(L); | 448 | lua_lock(L); |
| 450 | api_checknelems(L, n); | 449 | api_checknelems(L, n); |
| 451 | luaD_poscall(L, ci, L->top - n, n); | 450 | luaD_poscall(L, ci, L->top - n, n); |
| 452 | return 1; | 451 | break; |
| 453 | } | 452 | } |
| 454 | case LUA_TLCL: { /* Lua function: prepare its call */ | 453 | case LUA_TLCL: { /* Lua function: prepare its call */ |
| 455 | Proto *p = clLvalue(funcv)->p; | 454 | Proto *p = clLvalue(funcv)->p; |
| @@ -469,47 +468,19 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 469 | ci->callstatus = CIST_LUA; | 468 | ci->callstatus = CIST_LUA; |
| 470 | if (L->hookmask) | 469 | if (L->hookmask) |
| 471 | callhook(L, ci, 0); | 470 | callhook(L, ci, 0); |
| 472 | return 0; | 471 | luaV_execute(L); /* run the function */ |
| 472 | break; | ||
| 473 | } | 473 | } |
| 474 | default: { /* not a function */ | 474 | default: { /* not a function */ |
| 475 | func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ | 475 | func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ |
| 476 | return luaD_precall(L, func, nresults); /* now it must be a function */ | 476 | luaD_call(L, func, nresults); /* now it must be a function */ |
| 477 | break; | ||
| 477 | } | 478 | } |
| 478 | } | 479 | } |
| 479 | } | 480 | } |
| 480 | 481 | ||
| 481 | 482 | ||
| 482 | /* | 483 | /* |
| 483 | ** Check appropriate error for stack overflow ("regular" overflow or | ||
| 484 | ** overflow while handling stack overflow). If 'nCalls' is larger than | ||
| 485 | ** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but | ||
| 486 | ** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to | ||
| 487 | ** allow overflow handling to work) | ||
| 488 | */ | ||
| 489 | static void stackerror (lua_State *L) { | ||
| 490 | if (L->nCcalls == LUAI_MAXCCALLS) | ||
| 491 | luaG_runerror(L, "C stack overflow"); | ||
| 492 | else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) | ||
| 493 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ | ||
| 494 | } | ||
| 495 | |||
| 496 | |||
| 497 | /* | ||
| 498 | ** Call a function (C or Lua). The function to be called is at *func. | ||
| 499 | ** The arguments are on the stack, right after the function. | ||
| 500 | ** When returns, all the results are on the stack, starting at the original | ||
| 501 | ** function position. | ||
| 502 | */ | ||
| 503 | void luaD_call (lua_State *L, StkId func, int nResults) { | ||
| 504 | if (++L->nCcalls >= LUAI_MAXCCALLS) | ||
| 505 | stackerror(L); | ||
| 506 | if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ | ||
| 507 | luaV_execute(L); /* call it */ | ||
| 508 | L->nCcalls--; | ||
| 509 | } | ||
| 510 | |||
| 511 | |||
| 512 | /* | ||
| 513 | ** Similar to 'luaD_call', but does not allow yields during the call | 484 | ** Similar to 'luaD_call', but does not allow yields during the call |
| 514 | */ | 485 | */ |
| 515 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { | 486 | void luaD_callnoyield (lua_State *L, StkId func, int nResults) { |
| @@ -541,7 +512,7 @@ static void finishCcall (lua_State *L, int status) { | |||
| 541 | n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ | 512 | n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ |
| 542 | lua_lock(L); | 513 | lua_lock(L); |
| 543 | api_checknelems(L, n); | 514 | api_checknelems(L, n); |
| 544 | luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ | 515 | luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_call' */ |
| 545 | } | 516 | } |
| 546 | 517 | ||
| 547 | 518 | ||
| @@ -629,8 +600,7 @@ static void resume (lua_State *L, void *ud) { | |||
| 629 | StkId firstArg = L->top - n; /* first argument */ | 600 | StkId firstArg = L->top - n; /* first argument */ |
| 630 | CallInfo *ci = L->ci; | 601 | CallInfo *ci = L->ci; |
| 631 | if (L->status == LUA_OK) { /* starting a coroutine? */ | 602 | if (L->status == LUA_OK) { /* starting a coroutine? */ |
| 632 | if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ | 603 | luaD_call(L, firstArg - 1, LUA_MULTRET); |
| 633 | luaV_execute(L); /* call it */ | ||
| 634 | } | 604 | } |
| 635 | else { /* resuming from previous yield */ | 605 | else { /* resuming from previous yield */ |
| 636 | lua_assert(L->status == LUA_YIELD); | 606 | lua_assert(L->status == LUA_YIELD); |
| @@ -645,7 +615,7 @@ static void resume (lua_State *L, void *ud) { | |||
| 645 | api_checknelems(L, n); | 615 | api_checknelems(L, n); |
| 646 | firstArg = L->top - n; /* yield results come from continuation */ | 616 | firstArg = L->top - n; /* yield results come from continuation */ |
| 647 | } | 617 | } |
| 648 | luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ | 618 | luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_call' */ |
| 649 | } | 619 | } |
| 650 | unroll(L, NULL); /* run continuation */ | 620 | unroll(L, NULL); /* run continuation */ |
| 651 | } | 621 | } |
| @@ -688,7 +658,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
| 688 | : L->top - (L->ci->func + 1); | 658 | : L->top - (L->ci->func + 1); |
| 689 | L->nny = oldnny; /* restore 'nny' */ | 659 | L->nny = oldnny; /* restore 'nny' */ |
| 690 | L->nCcalls--; | 660 | L->nCcalls--; |
| 691 | lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); | 661 | // lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); |
| 692 | lua_unlock(L); | 662 | lua_unlock(L); |
| 693 | return status; | 663 | return status; |
| 694 | } | 664 | } |
