diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-03-10 14:14:37 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-03-10 14:14:37 -0300 |
| commit | ba484b9eb16dd62a7c3a5400a66eb952b654d3f0 (patch) | |
| tree | 31692ddf85265e5a46eab0cd55a0b0757a225e68 | |
| parent | f9d015523ef48266cea37e13717c223c16941b23 (diff) | |
| download | lua-ba484b9eb16dd62a7c3a5400a66eb952b654d3f0.tar.gz lua-ba484b9eb16dd62a7c3a5400a66eb952b654d3f0.tar.bz2 lua-ba484b9eb16dd62a7c3a5400a66eb952b654d3f0.zip | |
yielding across lua_call (first version)
| -rw-r--r-- | lapi.c | 22 | ||||
| -rw-r--r-- | lapi.h | 6 | ||||
| -rw-r--r-- | lbaselib.c | 11 | ||||
| -rw-r--r-- | ldebug.c | 4 | ||||
| -rw-r--r-- | ldo.c | 103 | ||||
| -rw-r--r-- | ldo.h | 5 | ||||
| -rw-r--r-- | lgc.c | 4 | ||||
| -rw-r--r-- | lstate.c | 4 | ||||
| -rw-r--r-- | lstate.h | 7 | ||||
| -rw-r--r-- | ltablib.c | 30 | ||||
| -rw-r--r-- | lua.h | 8 | ||||
| -rw-r--r-- | lvm.c | 72 | ||||
| -rw-r--r-- | lvm.h | 3 |
13 files changed, 169 insertions, 110 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lapi.c,v 2.69 2009/02/18 17:20:56 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.70 2009/02/19 17:15:13 roberto Exp roberto $ |
| 3 | ** Lua API | 3 | ** Lua API |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -757,21 +757,25 @@ LUA_API int lua_setfenv (lua_State *L, int idx) { | |||
| 757 | */ | 757 | */ |
| 758 | 758 | ||
| 759 | 759 | ||
| 760 | #define adjustresults(L,nres) \ | ||
| 761 | { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } | ||
| 762 | |||
| 763 | |||
| 764 | #define checkresults(L,na,nr) \ | 760 | #define checkresults(L,na,nr) \ |
| 765 | api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) | 761 | api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na))) |
| 766 | 762 | ||
| 767 | 763 | ||
| 768 | LUA_API void lua_call (lua_State *L, int nargs, int nresults) { | 764 | LUA_API void lua_callcont (lua_State *L, int nargs, int nresults, |
| 765 | lua_CFunction cont) { | ||
| 769 | StkId func; | 766 | StkId func; |
| 770 | lua_lock(L); | 767 | lua_lock(L); |
| 768 | /* cannot use continuations inside hooks */ | ||
| 769 | api_check(L, cont == NULL || !isLua(L->ci)); | ||
| 771 | api_checknelems(L, nargs+1); | 770 | api_checknelems(L, nargs+1); |
| 772 | checkresults(L, nargs, nresults); | 771 | checkresults(L, nargs, nresults); |
| 773 | func = L->top - (nargs+1); | 772 | func = L->top - (nargs+1); |
| 774 | luaD_call(L, func, nresults); | 773 | if (cont) { |
| 774 | L->ci->u.c.cont = cont; | ||
| 775 | luaD_call(L, func, nresults, 1); | ||
| 776 | } | ||
| 777 | else | ||
| 778 | luaD_call(L, func, nresults, 0); | ||
| 775 | adjustresults(L, nresults); | 779 | adjustresults(L, nresults); |
| 776 | lua_unlock(L); | 780 | lua_unlock(L); |
| 777 | } | 781 | } |
| @@ -789,7 +793,7 @@ struct CallS { /* data to `f_call' */ | |||
| 789 | 793 | ||
| 790 | static void f_call (lua_State *L, void *ud) { | 794 | static void f_call (lua_State *L, void *ud) { |
| 791 | struct CallS *c = cast(struct CallS *, ud); | 795 | struct CallS *c = cast(struct CallS *, ud); |
| 792 | luaD_call(L, c->func, c->nresults); | 796 | luaD_call(L, c->func, c->nresults, 0); |
| 793 | } | 797 | } |
| 794 | 798 | ||
| 795 | 799 | ||
| @@ -835,7 +839,7 @@ static void f_Ccall (lua_State *L, void *ud) { | |||
| 835 | api_incr_top(L); | 839 | api_incr_top(L); |
| 836 | setpvalue(L->top, c->ud); /* push only argument */ | 840 | setpvalue(L->top, c->ud); /* push only argument */ |
| 837 | api_incr_top(L); | 841 | api_incr_top(L); |
| 838 | luaD_call(L, L->top - 2, 0); | 842 | luaD_call(L, L->top - 2, 0, 0); |
| 839 | } | 843 | } |
| 840 | 844 | ||
| 841 | 845 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp roberto $ | 2 | ** $Id: lapi.h,v 2.3 2006/07/11 15:53:29 roberto Exp roberto $ |
| 3 | ** Auxiliary functions from Lua API | 3 | ** Auxiliary functions from Lua API |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -13,4 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top);} | 14 | #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top);} |
| 15 | 15 | ||
| 16 | #define adjustresults(L,nres) \ | ||
| 17 | { if ((nres) == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; } | ||
| 18 | |||
| 19 | |||
| 16 | #endif | 20 | #endif |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lbaselib.c,v 1.209 2009/02/06 18:38:47 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.210 2009/02/07 12:23:15 roberto Exp roberto $ |
| 3 | ** Basic library | 3 | ** Basic library |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -323,12 +323,17 @@ static int luaB_load (lua_State *L) { | |||
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | 325 | ||
| 326 | static int dofilecont (lua_State *L) { | ||
| 327 | return lua_gettop(L) - 1; | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 326 | static int luaB_dofile (lua_State *L) { | 331 | static int luaB_dofile (lua_State *L) { |
| 327 | const char *fname = luaL_optstring(L, 1, NULL); | 332 | const char *fname = luaL_optstring(L, 1, NULL); |
| 328 | lua_settop(L, 1); | 333 | lua_settop(L, 1); |
| 329 | if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); | 334 | if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); |
| 330 | lua_call(L, 0, LUA_MULTRET); | 335 | lua_callcont(L, 0, LUA_MULTRET, dofilecont); |
| 331 | return lua_gettop(L) - 1; | 336 | return dofilecont(L); |
| 332 | } | 337 | } |
| 333 | 338 | ||
| 334 | 339 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldebug.c,v 2.42 2008/10/30 15:39:30 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 2.43 2009/03/04 13:32:29 roberto Exp roberto $ |
| 3 | ** Debug Interface | 3 | ** Debug Interface |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -628,7 +628,7 @@ void luaG_errormsg (lua_State *L) { | |||
| 628 | setobjs2s(L, L->top, L->top - 1); /* move argument */ | 628 | setobjs2s(L, L->top, L->top - 1); /* move argument */ |
| 629 | setobjs2s(L, L->top - 1, errfunc); /* push function */ | 629 | setobjs2s(L, L->top - 1, errfunc); /* push function */ |
| 630 | incr_top(L); | 630 | incr_top(L); |
| 631 | luaD_call(L, L->top - 2, 1); /* call it */ | 631 | luaD_call(L, L->top - 2, 1, 0); /* call it */ |
| 632 | } | 632 | } |
| 633 | luaD_throw(L, LUA_ERRRUN); | 633 | luaD_throw(L, LUA_ERRRUN); |
| 634 | } | 634 | } |
| @@ -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; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.h,v 2.9 2008/07/03 14:24:36 roberto Exp roberto $ | 2 | ** $Id: ldo.h,v 2.10 2008/08/13 17:02:42 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 | */ |
| @@ -34,7 +34,8 @@ typedef void (*Pfunc) (lua_State *L, void *ud); | |||
| 34 | LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); | 34 | LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); |
| 35 | LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); | 35 | LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); |
| 36 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); | 36 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); |
| 37 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); | 37 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults, |
| 38 | int allowyield); | ||
| 38 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, | 39 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, |
| 39 | ptrdiff_t oldtop, ptrdiff_t ef); | 40 | ptrdiff_t oldtop, ptrdiff_t ef); |
| 40 | LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); | 41 | LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.47 2008/06/26 19:42:45 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.48 2009/02/17 19:47:58 roberto Exp roberto $ |
| 3 | ** Garbage Collector | 3 | ** Garbage Collector |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -601,7 +601,7 @@ static Udata *udata2finalize (global_State *g) { | |||
| 601 | 601 | ||
| 602 | static void dothecall (lua_State *L, void *ud) { | 602 | static void dothecall (lua_State *L, void *ud) { |
| 603 | UNUSED(ud); | 603 | UNUSED(ud); |
| 604 | luaD_call(L, L->top - 2, 0); | 604 | luaD_call(L, L->top - 2, 0, 0); |
| 605 | } | 605 | } |
| 606 | 606 | ||
| 607 | 607 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.48 2009/02/17 19:47:58 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.49 2009/02/18 17:20:56 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -95,7 +95,7 @@ static void preinit_state (lua_State *L, global_State *g) { | |||
| 95 | resethookcount(L); | 95 | resethookcount(L); |
| 96 | L->openupval = NULL; | 96 | L->openupval = NULL; |
| 97 | L->size_ci = 0; | 97 | L->size_ci = 0; |
| 98 | L->baseCcalls = 0; | 98 | L->nny = 1; |
| 99 | L->status = LUA_OK; | 99 | L->status = LUA_OK; |
| 100 | L->base_ci = L->ci = NULL; | 100 | L->base_ci = L->ci = NULL; |
| 101 | L->savedpc = NULL; | 101 | L->savedpc = NULL; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.37 2009/02/18 17:20:56 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.38 2009/03/04 13:32:29 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -87,6 +87,9 @@ typedef struct CallInfo { | |||
| 87 | struct { /* only for Lua functions */ | 87 | struct { /* only for Lua functions */ |
| 88 | int tailcalls; /* number of tail calls lost under this entry */ | 88 | int tailcalls; /* number of tail calls lost under this entry */ |
| 89 | } l; | 89 | } l; |
| 90 | struct { /* only for C functions */ | ||
| 91 | lua_CFunction cont; /* continuation in case of yields */ | ||
| 92 | } c; | ||
| 90 | } u; | 93 | } u; |
| 91 | } CallInfo; | 94 | } CallInfo; |
| 92 | 95 | ||
| @@ -160,7 +163,7 @@ struct lua_State { | |||
| 160 | CallInfo *base_ci; /* array of CallInfo's */ | 163 | CallInfo *base_ci; /* array of CallInfo's */ |
| 161 | int stacksize; | 164 | int stacksize; |
| 162 | int size_ci; /* size of array `base_ci' */ | 165 | int size_ci; /* size of array `base_ci' */ |
| 163 | unsigned short baseCcalls; /* number of nested C calls when resuming */ | 166 | unsigned short nny; /* number of non-yieldable calls in stack */ |
| 164 | lu_byte hookmask; | 167 | lu_byte hookmask; |
| 165 | lu_byte allowhook; | 168 | lu_byte allowhook; |
| 166 | int basehookcount; | 169 | int basehookcount; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltablib.c,v 1.43 2008/02/14 16:03:27 roberto Exp roberto $ | 2 | ** $Id: ltablib.c,v 1.44 2008/04/07 18:43:00 roberto Exp roberto $ |
| 3 | ** Library for Table Manipulation | 3 | ** Library for Table Manipulation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -36,20 +36,28 @@ static int foreachi (lua_State *L) { | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | 38 | ||
| 39 | static int foreach (lua_State *L) { | 39 | static int foreachcont (lua_State *L) { |
| 40 | luaL_checktype(L, 1, LUA_TTABLE); | 40 | for (;;) { |
| 41 | luaL_checktype(L, 2, LUA_TFUNCTION); | ||
| 42 | lua_pushnil(L); /* first key */ | ||
| 43 | while (lua_next(L, 1)) { | ||
| 44 | lua_pushvalue(L, 2); /* function */ | ||
| 45 | lua_pushvalue(L, -3); /* key */ | ||
| 46 | lua_pushvalue(L, -3); /* value */ | ||
| 47 | lua_call(L, 2, 1); | ||
| 48 | if (!lua_isnil(L, -1)) | 41 | if (!lua_isnil(L, -1)) |
| 49 | return 1; | 42 | return 1; |
| 50 | lua_pop(L, 2); /* remove value and result */ | 43 | lua_pop(L, 2); /* remove value and result */ |
| 44 | if (lua_next(L, 1) == 0) /* no more elements? */ | ||
| 45 | return 0; | ||
| 46 | lua_pushvalue(L, 2); /* function */ | ||
| 47 | lua_pushvalue(L, -3); /* key */ | ||
| 48 | lua_pushvalue(L, -3); /* value */ | ||
| 49 | lua_callcont(L, 2, 1, &foreachcont); | ||
| 51 | } | 50 | } |
| 52 | return 0; | 51 | } |
| 52 | |||
| 53 | |||
| 54 | static int foreach (lua_State *L) { | ||
| 55 | luaL_checktype(L, 1, LUA_TTABLE); | ||
| 56 | luaL_checktype(L, 2, LUA_TFUNCTION); | ||
| 57 | lua_pushnil(L); /* first key */ | ||
| 58 | lua_pushnil(L); /* first value */ | ||
| 59 | lua_pushnil(L); /* first "return" */ | ||
| 60 | return foreachcont(L); | ||
| 53 | } | 61 | } |
| 54 | 62 | ||
| 55 | 63 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lua.h,v 1.231 2008/08/13 14:08:49 roberto Exp roberto $ | 2 | ** $Id: lua.h,v 1.232 2009/02/18 17:20:56 roberto Exp roberto $ |
| 3 | ** Lua - An Extensible Extension Language | 3 | ** Lua - An Extensible Extension Language |
| 4 | ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) | 4 | ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) |
| 5 | ** See Copyright Notice at the end of this file | 5 | ** See Copyright Notice at the end of this file |
| @@ -203,7 +203,9 @@ LUA_API int (lua_setfenv) (lua_State *L, int idx); | |||
| 203 | /* | 203 | /* |
| 204 | ** 'load' and 'call' functions (load and run Lua code) | 204 | ** 'load' and 'call' functions (load and run Lua code) |
| 205 | */ | 205 | */ |
| 206 | LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); | 206 | LUA_API void (lua_callcont) (lua_State *L, int nargs, int nresults, |
| 207 | lua_CFunction cont); | ||
| 208 | |||
| 207 | LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); | 209 | LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); |
| 208 | LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); | 210 | LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); |
| 209 | LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, | 211 | LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, |
| @@ -281,6 +283,8 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); | |||
| 281 | 283 | ||
| 282 | #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) | 284 | #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) |
| 283 | 285 | ||
| 286 | #define lua_call(L,n,r) lua_callcont(L, (n), (r), NULL); | ||
| 287 | |||
| 284 | 288 | ||
| 285 | 289 | ||
| 286 | /* | 290 | /* |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 2.82 2009/03/02 16:34:23 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.83 2009/03/04 13:32:29 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -79,17 +79,14 @@ static void traceexec (lua_State *L) { | |||
| 79 | static void callTM (lua_State *L, const TValue *f, const TValue *p1, | 79 | static void callTM (lua_State *L, const TValue *f, const TValue *p1, |
| 80 | const TValue *p2, TValue *p3, int hasres) { | 80 | const TValue *p2, TValue *p3, int hasres) { |
| 81 | ptrdiff_t result = savestack(L, p3); | 81 | ptrdiff_t result = savestack(L, p3); |
| 82 | int oldbase = L->baseCcalls; | ||
| 83 | setobj2s(L, L->top++, f); /* push function */ | 82 | setobj2s(L, L->top++, f); /* push function */ |
| 84 | setobj2s(L, L->top++, p1); /* 1st argument */ | 83 | setobj2s(L, L->top++, p1); /* 1st argument */ |
| 85 | setobj2s(L, L->top++, p2); /* 2nd argument */ | 84 | setobj2s(L, L->top++, p2); /* 2nd argument */ |
| 86 | if (!hasres) /* no result? 'p3' is third argument */ | 85 | if (!hasres) /* no result? 'p3' is third argument */ |
| 87 | setobj2s(L, L->top++, p3); /* 3th argument */ | 86 | setobj2s(L, L->top++, p3); /* 3th argument */ |
| 88 | luaD_checkstack(L, 0); | 87 | luaD_checkstack(L, 0); |
| 89 | if (isLua(L->ci)) /* metamethod invoked from a Lua function? */ | 88 | /* metamethod may yield only when called from Lua code */ |
| 90 | L->baseCcalls++; /* allow it to yield */ | 89 | luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); |
| 91 | luaD_call(L, L->top - (4 - hasres), hasres); | ||
| 92 | L->baseCcalls = oldbase; | ||
| 93 | if (hasres) { /* if has result, move it to its place */ | 90 | if (hasres) { /* if has result, move it to its place */ |
| 94 | p3 = restorestack(L, result); | 91 | p3 = restorestack(L, result); |
| 95 | setobjs2s(L, p3, --L->top); | 92 | setobjs2s(L, p3, --L->top); |
| @@ -356,6 +353,61 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb, | |||
| 356 | } | 353 | } |
| 357 | 354 | ||
| 358 | 355 | ||
| 356 | /* | ||
| 357 | ** finish execution of an opcode interrupted by an yield | ||
| 358 | */ | ||
| 359 | void luaV_finishOp (lua_State *L) { | ||
| 360 | Instruction inst = *(L->savedpc - 1); /* interrupted instruction */ | ||
| 361 | switch (GET_OPCODE(inst)) { /* finish its execution */ | ||
| 362 | case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: | ||
| 363 | case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: | ||
| 364 | case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { | ||
| 365 | setobjs2s(L, L->base + GETARG_A(inst), --L->top); | ||
| 366 | break; | ||
| 367 | } | ||
| 368 | case OP_LE: case OP_LT: case OP_EQ: { | ||
| 369 | int res = !l_isfalse(L->top - 1); | ||
| 370 | L->top--; | ||
| 371 | /* metamethod should not be called when operand is K */ | ||
| 372 | lua_assert(!ISK(GETARG_B(inst))); | ||
| 373 | if (GET_OPCODE(inst) == OP_LE && /* "<=" using "<" instead? */ | ||
| 374 | ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE))) | ||
| 375 | res = !res; /* invert result */ | ||
| 376 | lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP); | ||
| 377 | if (res != GETARG_A(inst)) /* condition failed? */ | ||
| 378 | L->savedpc++; /* skip jump instruction */ | ||
| 379 | break; | ||
| 380 | } | ||
| 381 | case OP_CONCAT: { | ||
| 382 | StkId top = L->top - 1; /* top when __concat was called */ | ||
| 383 | int last = cast_int(top - L->base) - 2; /* last element and ... */ | ||
| 384 | int b = GETARG_B(inst); /* ... first element to concatenate */ | ||
| 385 | int total = last - b + 1; /* number of elements to concatenate */ | ||
| 386 | setobj2s(L, top - 2, top); /* put TM result in proper position */ | ||
| 387 | L->top = L->ci->top; /* correct top */ | ||
| 388 | if (total > 1) /* are there elements to concat? */ | ||
| 389 | luaV_concat(L, total, last); /* concat them (may yield again) */ | ||
| 390 | /* move final result to final position */ | ||
| 391 | setobj2s(L, L->base + GETARG_A(inst), L->base + b); | ||
| 392 | break; | ||
| 393 | } | ||
| 394 | case OP_TFORCALL: { | ||
| 395 | lua_assert(GET_OPCODE(*L->savedpc) == OP_TFORLOOP); | ||
| 396 | L->top = L->ci->top; /* correct top */ | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | case OP_CALL: { | ||
| 400 | if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ | ||
| 401 | L->top = L->ci->top; /* adjust results */ | ||
| 402 | break; | ||
| 403 | } | ||
| 404 | case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE: | ||
| 405 | break; | ||
| 406 | default: lua_assert(0); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | |||
| 359 | 411 | ||
| 360 | /* | 412 | /* |
| 361 | ** some macros for common tasks in `luaV_execute' | 413 | ** some macros for common tasks in `luaV_execute' |
| @@ -672,11 +724,9 @@ void luaV_execute (lua_State *L) { | |||
| 672 | setobjs2s(L, cb+2, ra+2); | 724 | setobjs2s(L, cb+2, ra+2); |
| 673 | setobjs2s(L, cb+1, ra+1); | 725 | setobjs2s(L, cb+1, ra+1); |
| 674 | setobjs2s(L, cb, ra); | 726 | setobjs2s(L, cb, ra); |
| 675 | L->baseCcalls++; /* allow yields */ | ||
| 676 | L->top = cb + 3; /* func. + 2 args (state and index) */ | 727 | L->top = cb + 3; /* func. + 2 args (state and index) */ |
| 677 | Protect(luaD_call(L, cb, GETARG_C(i))); | 728 | Protect(luaD_call(L, cb, GETARG_C(i), 1)); |
| 678 | L->top = L->ci->top; | 729 | L->top = L->ci->top; |
| 679 | L->baseCcalls--; | ||
| 680 | i = *(L->savedpc++); /* go to next instruction */ | 730 | i = *(L->savedpc++); /* go to next instruction */ |
| 681 | ra = RA(i); | 731 | ra = RA(i); |
| 682 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP); | 732 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP); |
| @@ -725,8 +775,8 @@ void luaV_execute (lua_State *L) { | |||
| 725 | ncl = luaF_newLclosure(L, nup, cl->env); | 775 | ncl = luaF_newLclosure(L, nup, cl->env); |
| 726 | ncl->l.p = p; | 776 | ncl->l.p = p; |
| 727 | setclvalue(L, ra, ncl); | 777 | setclvalue(L, ra, ncl); |
| 728 | for (j=0; j<nup; j++, L->savedpc++) { | 778 | for (j=0; j<nup; j++) { |
| 729 | Instruction u = *L->savedpc; | 779 | Instruction u = *L->savedpc++; |
| 730 | if (GET_OPCODE(u) == OP_GETUPVAL) | 780 | if (GET_OPCODE(u) == OP_GETUPVAL) |
| 731 | ncl->l.upvals[j] = cl->upvals[GETARG_B(u)]; | 781 | ncl->l.upvals[j] = cl->upvals[GETARG_B(u)]; |
| 732 | else { | 782 | else { |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.h,v 2.6 2007/02/09 13:04:52 roberto Exp roberto $ | 2 | ** $Id: lvm.h,v 2.7 2008/08/26 13:27:42 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -32,6 +32,7 @@ LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key, | |||
| 32 | StkId val); | 32 | StkId val); |
| 33 | LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, | 33 | LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, |
| 34 | StkId val); | 34 | StkId val); |
| 35 | LUAI_FUNC void luaV_finishOp (lua_State *L); | ||
| 35 | LUAI_FUNC void luaV_execute (lua_State *L); | 36 | LUAI_FUNC void luaV_execute (lua_State *L); |
| 36 | LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); | 37 | LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); |
| 37 | 38 | ||
