diff options
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 103 |
1 files changed, 41 insertions, 62 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.53 2009/03/03 18:51:24 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.54 2009/03/04 13:32:29 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 | */ |
| @@ -14,6 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | #include "lua.h" | 15 | #include "lua.h" |
| 16 | 16 | ||
| 17 | #include "lapi.h" | ||
| 17 | #include "ldebug.h" | 18 | #include "ldebug.h" |
| 18 | #include "ldo.h" | 19 | #include "ldo.h" |
| 19 | #include "lfunc.h" | 20 | #include "lfunc.h" |
| @@ -365,7 +366,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) { | |||
| 365 | ** When returns, all the results are on the stack, starting at the original | 366 | ** When returns, all the results are on the stack, starting at the original |
| 366 | ** function position. | 367 | ** function position. |
| 367 | */ | 368 | */ |
| 368 | void luaD_call (lua_State *L, StkId func, int nResults) { | 369 | void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { |
| 369 | global_State *g = G(L); | 370 | global_State *g = G(L); |
| 370 | if (++g->nCcalls >= LUAI_MAXCCALLS) { | 371 | if (++g->nCcalls >= LUAI_MAXCCALLS) { |
| 371 | if (g->nCcalls == LUAI_MAXCCALLS) | 372 | if (g->nCcalls == LUAI_MAXCCALLS) |
| @@ -373,64 +374,41 @@ void luaD_call (lua_State *L, StkId func, int nResults) { | |||
| 373 | else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) | 374 | else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) |
| 374 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ | 375 | luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ |
| 375 | } | 376 | } |
| 377 | if (!allowyield) L->nny++; | ||
| 376 | if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ | 378 | if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ |
| 377 | luaV_execute(L); /* call it */ | 379 | luaV_execute(L); /* call it */ |
| 380 | if (!allowyield) L->nny--; | ||
| 378 | g->nCcalls--; | 381 | g->nCcalls--; |
| 379 | luaC_checkGC(L); | 382 | luaC_checkGC(L); |
| 380 | } | 383 | } |
| 381 | 384 | ||
| 382 | 385 | ||
| 386 | static void finishCcall (lua_State *L) { | ||
| 387 | int n; | ||
| 388 | lua_assert(L->ci->u.c.cont != NULL); /* must have a continuation */ | ||
| 389 | lua_assert(L->nny == 0); | ||
| 390 | /* finish 'luaD_call' */ | ||
| 391 | G(L)->nCcalls--; | ||
| 392 | /* finish 'lua_callcont' */ | ||
| 393 | adjustresults(L, (L->ci + 1)->nresults); | ||
| 394 | /* call continuation function */ | ||
| 395 | lua_unlock(L); | ||
| 396 | n = (*L->ci->u.c.cont)(L); | ||
| 397 | lua_lock(L); | ||
| 398 | /* finish 'luaD_precall' */ | ||
| 399 | luaD_poscall(L, L->top - n); | ||
| 400 | } | ||
| 401 | |||
| 402 | |||
| 383 | static void unroll (lua_State *L) { | 403 | static void unroll (lua_State *L) { |
| 384 | for (;;) { | 404 | for (;;) { |
| 385 | Instruction inst; | 405 | if (L->ci == L->base_ci) /* stack is empty? */ |
| 386 | luaV_execute(L); /* execute down to higher C 'boundary' */ | ||
| 387 | if (L->ci == L->base_ci) { /* stack is empty? */ | ||
| 388 | lua_assert(L->baseCcalls == G(L)->nCcalls); | ||
| 389 | return; /* coroutine finished normally */ | 406 | return; /* coroutine finished normally */ |
| 390 | } | 407 | if (!isLua(L->ci)) /* C function? */ |
| 391 | L->baseCcalls--; /* undo increment that allows yields */ | 408 | finishCcall(L); |
| 392 | inst = *(L->savedpc - 1); /* interrupted instruction */ | 409 | else { /* Lua function */ |
| 393 | switch (GET_OPCODE(inst)) { /* finish its execution */ | 410 | luaV_finishOp(L); /* finish interrupted instruction */ |
| 394 | case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: | 411 | luaV_execute(L); /* execute down to higher C 'boundary' */ |
| 395 | case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: | ||
| 396 | case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { | ||
| 397 | setobjs2s(L, L->base + GETARG_A(inst), --L->top); | ||
| 398 | break; | ||
| 399 | } | ||
| 400 | case OP_LE: case OP_LT: case OP_EQ: { | ||
| 401 | int res = !l_isfalse(L->top - 1); | ||
| 402 | L->top--; | ||
| 403 | /* metamethod should not be called when operand is K */ | ||
| 404 | lua_assert(!ISK(GETARG_B(inst))); | ||
| 405 | if (GET_OPCODE(inst) == OP_LE && /* "<=" using "<" instead? */ | ||
| 406 | ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE))) | ||
| 407 | res = !res; /* invert result */ | ||
| 408 | lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP); | ||
| 409 | if (res != GETARG_A(inst)) /* condition failed? */ | ||
| 410 | L->savedpc++; /* skip jump instruction */ | ||
| 411 | break; | ||
| 412 | } | ||
| 413 | case OP_CONCAT: { | ||
| 414 | StkId top = L->top - 1; /* top when __concat was called */ | ||
| 415 | int last = cast_int(top - L->base) - 2; /* last element and ... */ | ||
| 416 | int b = GETARG_B(inst); /* ... first element to concatenate */ | ||
| 417 | int total = last - b + 1; /* number of elements to concatenate */ | ||
| 418 | setobj2s(L, top - 2, top); /* put TM result in proper position */ | ||
| 419 | L->top = L->ci->top; /* correct top */ | ||
| 420 | if (total > 1) /* are there elements to concat? */ | ||
| 421 | luaV_concat(L, total, last); /* concat them (may yield again) */ | ||
| 422 | /* move final result to final position */ | ||
| 423 | setobj2s(L, L->base + GETARG_A(inst), L->base + b); | ||
| 424 | continue; | ||
| 425 | } | ||
| 426 | case OP_TFORCALL: { | ||
| 427 | lua_assert(GET_OPCODE(*L->savedpc) == OP_TFORLOOP); | ||
| 428 | L->top = L->ci->top; /* correct top */ | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | case OP_SETGLOBAL: case OP_SETTABLE: | ||
| 432 | break; /* nothing to be done */ | ||
| 433 | default: lua_assert(0); | ||
| 434 | } | 412 | } |
| 435 | } | 413 | } |
| 436 | } | 414 | } |
| @@ -441,23 +419,22 @@ static void resume (lua_State *L, void *ud) { | |||
| 441 | CallInfo *ci = L->ci; | 419 | CallInfo *ci = L->ci; |
| 442 | if (L->status == LUA_OK) { /* start coroutine? */ | 420 | if (L->status == LUA_OK) { /* start coroutine? */ |
| 443 | lua_assert(ci == L->base_ci && firstArg > L->base); | 421 | lua_assert(ci == L->base_ci && firstArg > L->base); |
| 444 | if (luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* C function? */ | 422 | if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ |
| 445 | return; /* done */ | 423 | luaV_execute(L); /* call it */ |
| 446 | } | 424 | } |
| 447 | else { /* resuming from previous yield */ | 425 | else { /* resuming from previous yield */ |
| 448 | lua_assert(L->status == LUA_YIELD); | 426 | lua_assert(L->status == LUA_YIELD); |
| 449 | L->status = LUA_OK; | 427 | L->status = LUA_OK; |
| 450 | if (isLua(ci)) /* yielded inside a hook? */ | 428 | if (isLua(ci)) { /* yielded inside a hook? */ |
| 451 | L->base = L->ci->base; /* just continue its execution */ | 429 | L->base = L->ci->base; /* just continue its execution */ |
| 430 | luaV_execute(L); | ||
| 431 | } | ||
| 452 | else { /* 'common' yield */ | 432 | else { /* 'common' yield */ |
| 453 | /* finish interrupted execution of `OP_CALL' */ | 433 | G(L)->nCcalls--; /* finish 'luaD_call' */ |
| 454 | lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || | 434 | luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ |
| 455 | GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); | ||
| 456 | if (luaD_poscall(L, firstArg)) /* complete it... */ | ||
| 457 | L->top = L->ci->top; /* and correct top if not multiple results */ | ||
| 458 | } | 435 | } |
| 436 | unroll(L); | ||
| 459 | } | 437 | } |
| 460 | unroll(L); | ||
| 461 | } | 438 | } |
| 462 | 439 | ||
| 463 | 440 | ||
| @@ -484,7 +461,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { | |||
| 484 | if (G(L)->nCcalls >= LUAI_MAXCCALLS) | 461 | if (G(L)->nCcalls >= LUAI_MAXCCALLS) |
| 485 | return resume_error(L, "C stack overflow"); | 462 | return resume_error(L, "C stack overflow"); |
| 486 | ++G(L)->nCcalls; /* count resume */ | 463 | ++G(L)->nCcalls; /* count resume */ |
| 487 | L->baseCcalls += G(L)->nCcalls; | 464 | L->nny = 0; /* allow yields */ |
| 488 | status = luaD_rawrunprotected(L, resume, L->top - nargs); | 465 | status = luaD_rawrunprotected(L, resume, L->top - nargs); |
| 489 | if (status != LUA_OK && status != LUA_YIELD) { /* error? */ | 466 | if (status != LUA_OK && status != LUA_YIELD) { /* error? */ |
| 490 | L->status = cast_byte(status); /* mark thread as `dead' */ | 467 | L->status = cast_byte(status); /* mark thread as `dead' */ |
| @@ -494,7 +471,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { | |||
| 494 | else { | 471 | else { |
| 495 | lua_assert(status == L->status); | 472 | lua_assert(status == L->status); |
| 496 | } | 473 | } |
| 497 | L->baseCcalls -= G(L)->nCcalls; | 474 | L->nny = 1; /* do not allow yields */ |
| 498 | --G(L)->nCcalls; | 475 | --G(L)->nCcalls; |
| 499 | lua_unlock(L); | 476 | lua_unlock(L); |
| 500 | return status; | 477 | return status; |
| @@ -504,7 +481,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) { | |||
| 504 | LUA_API int lua_yield (lua_State *L, int nresults) { | 481 | LUA_API int lua_yield (lua_State *L, int nresults) { |
| 505 | luai_userstateyield(L, nresults); | 482 | luai_userstateyield(L, nresults); |
| 506 | lua_lock(L); | 483 | lua_lock(L); |
| 507 | if (G(L)->nCcalls > L->baseCcalls) | 484 | if (L->nny > 0) |
| 508 | luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); | 485 | luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); |
| 509 | L->base = L->top - nresults; /* protect stack slots below */ | 486 | L->base = L->top - nresults; /* protect stack slots below */ |
| 510 | L->status = LUA_YIELD; | 487 | L->status = LUA_YIELD; |
| @@ -521,6 +498,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
| 521 | int status; | 498 | int status; |
| 522 | ptrdiff_t old_ci = saveci(L, L->ci); | 499 | ptrdiff_t old_ci = saveci(L, L->ci); |
| 523 | lu_byte old_allowhooks = L->allowhook; | 500 | lu_byte old_allowhooks = L->allowhook; |
| 501 | unsigned short old_nny = L->nny; | ||
| 524 | ptrdiff_t old_errfunc = L->errfunc; | 502 | ptrdiff_t old_errfunc = L->errfunc; |
| 525 | L->errfunc = ef; | 503 | L->errfunc = ef; |
| 526 | status = luaD_rawrunprotected(L, func, u); | 504 | status = luaD_rawrunprotected(L, func, u); |
| @@ -532,6 +510,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, | |||
| 532 | L->base = L->ci->base; | 510 | L->base = L->ci->base; |
| 533 | L->savedpc = L->ci->savedpc; | 511 | L->savedpc = L->ci->savedpc; |
| 534 | L->allowhook = old_allowhooks; | 512 | L->allowhook = old_allowhooks; |
| 513 | L->nny = old_nny; | ||
| 535 | restore_stack_limit(L); | 514 | restore_stack_limit(L); |
| 536 | } | 515 | } |
| 537 | L->errfunc = old_errfunc; | 516 | L->errfunc = old_errfunc; |
