aboutsummaryrefslogtreecommitdiff
path: root/ldo.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2008-10-28 14:53:16 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2008-10-28 14:53:16 -0200
commitf6978173e03fdbe5536887b08beb53884f7c1a18 (patch)
treebc31173c72e358649dda82a532c29066db352a70 /ldo.c
parente02483dbc031ca0cdba17cb511c1e674551f90c5 (diff)
downloadlua-f6978173e03fdbe5536887b08beb53884f7c1a18.tar.gz
lua-f6978173e03fdbe5536887b08beb53884f7c1a18.tar.bz2
lua-f6978173e03fdbe5536887b08beb53884f7c1a18.zip
yields accross metamethods and for iterators (except for __concat)
Diffstat (limited to 'ldo.c')
-rw-r--r--ldo.c69
1 files changed, 59 insertions, 10 deletions
diff --git a/ldo.c b/ldo.c
index 6df778bc..2bbbde92 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ldo.c,v 2.47 2008/08/13 17:02:42 roberto Exp roberto $ 2** $Id: ldo.c,v 2.48 2008/08/26 13:27: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*/
@@ -374,7 +374,6 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
374*/ 374*/
375void luaD_call (lua_State *L, StkId func, int nResults) { 375void luaD_call (lua_State *L, StkId func, int nResults) {
376 global_State *g = G(L); 376 global_State *g = G(L);
377 lua_assert(g->nCcalls >= L->baseCcalls);
378 if (++g->nCcalls >= LUAI_MAXCCALLS) { 377 if (++g->nCcalls >= LUAI_MAXCCALLS) {
379 if (g->nCcalls == LUAI_MAXCCALLS) 378 if (g->nCcalls == LUAI_MAXCCALLS)
380 luaG_runerror(L, "C stack overflow"); 379 luaG_runerror(L, "C stack overflow");
@@ -388,6 +387,55 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
388} 387}
389 388
390 389
390static void unroll (lua_State *L) {
391 for (;;) {
392 Instruction inst;
393 luaV_execute(L); /* execute up to higher C 'boundary' */
394 if (L->ci == L->base_ci) /* stack is empty? */
395 return; /* coroutine finished normally */
396 L->baseCcalls--; /* undo increment that allows yields */
397 inst = *(L->savedpc - 1); /* interrupted instruction */
398 switch (GET_OPCODE(inst)) { /* finish its execution */
399 case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
400 case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN:
401 case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: {
402 setobjs2s(L, L->base + GETARG_A(inst), --L->top);
403 break;
404 }
405 case OP_LE: case OP_LT: case OP_EQ: {
406 int res;
407 L->top--;
408 res = !l_isfalse(L->top);
409 /* cannot call metamethod with K operand */
410 lua_assert(!ISK(GETARG_B(inst)));
411 if (GET_OPCODE(inst) == OP_LE && /* "<=" using "<" instead? */
412 ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE)))
413 res = !res; /* invert result */
414 lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP);
415 if (res == GETARG_A(inst))
416 L->savedpc += GETARG_sBx(*L->savedpc); /* jump */
417 L->savedpc++; /* skip jump instruction */
418 break;
419 }
420 case OP_SETGLOBAL: case OP_SETTABLE:
421 break; /* nothing to be done */
422 case OP_TFORLOOP: {
423 StkId cb = L->base + GETARG_A(inst) + 3;
424 L->top = L->ci->top;
425 lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP);
426 if (!ttisnil(cb)) { /* continue loop? */
427 setobjs2s(L, cb - 1, cb); /* save control variable */
428 L->savedpc += GETARG_sBx(*L->savedpc); /* jump back */
429 }
430 L->savedpc++;
431 break;
432 }
433 default: lua_assert(0);
434 }
435 }
436}
437
438
391static void resume (lua_State *L, void *ud) { 439static void resume (lua_State *L, void *ud) {
392 StkId firstArg = cast(StkId, ud); 440 StkId firstArg = cast(StkId, ud);
393 CallInfo *ci = L->ci; 441 CallInfo *ci = L->ci;
@@ -399,17 +447,17 @@ static void resume (lua_State *L, void *ud) {
399 else { /* resuming from previous yield */ 447 else { /* resuming from previous yield */
400 lua_assert(L->status == LUA_YIELD); 448 lua_assert(L->status == LUA_YIELD);
401 L->status = LUA_OK; 449 L->status = LUA_OK;
402 if (!isLua(ci)) { /* `common' yield? */ 450 if (isLua(ci)) /* yielded inside a hook? */
451 L->base = L->ci->base; /* just continue its execution */
452 else { /* 'common' yield */
403 /* finish interrupted execution of `OP_CALL' */ 453 /* finish interrupted execution of `OP_CALL' */
404 lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || 454 lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
405 GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); 455 GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
406 if (luaD_poscall(L, firstArg)) /* complete it... */ 456 if (luaD_poscall(L, firstArg)) /* complete it... */
407 L->top = L->ci->top; /* and correct top if not multiple results */ 457 L->top = L->ci->top; /* and correct top if not multiple results */
408 } 458 }
409 else /* yielded inside a hook: just continue its execution */
410 L->base = L->ci->base;
411 } 459 }
412 luaV_execute(L); 460 unroll(L);
413} 461}
414 462
415 463
@@ -432,10 +480,11 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
432 return resume_error(L, "cannot resume non-suspended coroutine"); 480 return resume_error(L, "cannot resume non-suspended coroutine");
433 } 481 }
434 luai_userstateresume(L, nargs); 482 luai_userstateresume(L, nargs);
435 lua_assert(L->errfunc == 0 && L->baseCcalls == 0); 483 lua_assert(L->errfunc == 0);
436 if (G(L)->nCcalls >= LUAI_MAXCCALLS) 484 if (G(L)->nCcalls >= LUAI_MAXCCALLS)
437 return resume_error(L, "C stack overflow"); 485 return resume_error(L, "C stack overflow");
438 L->baseCcalls = ++G(L)->nCcalls; 486 ++G(L)->nCcalls; /* count resume */
487 L->baseCcalls += G(L)->nCcalls;
439 status = luaD_rawrunprotected(L, resume, L->top - nargs); 488 status = luaD_rawrunprotected(L, resume, L->top - nargs);
440 if (status != LUA_OK && status != LUA_YIELD) { /* error? */ 489 if (status != LUA_OK && status != LUA_YIELD) { /* error? */
441 L->status = cast_byte(status); /* mark thread as `dead' */ 490 L->status = cast_byte(status); /* mark thread as `dead' */
@@ -443,11 +492,10 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
443 L->ci->top = L->top; 492 L->ci->top = L->top;
444 } 493 }
445 else { 494 else {
446 lua_assert(L->baseCcalls == G(L)->nCcalls);
447 lua_assert(status == L->status); 495 lua_assert(status == L->status);
448 } 496 }
497 L->baseCcalls -= G(L)->nCcalls;
449 --G(L)->nCcalls; 498 --G(L)->nCcalls;
450 L->baseCcalls = 0;
451 lua_unlock(L); 499 lua_unlock(L);
452 return status; 500 return status;
453} 501}
@@ -456,6 +504,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
456LUA_API int lua_yield (lua_State *L, int nresults) { 504LUA_API int lua_yield (lua_State *L, int nresults) {
457 luai_userstateyield(L, nresults); 505 luai_userstateyield(L, nresults);
458 lua_lock(L); 506 lua_lock(L);
507/*printf("yield: %d - %d\n", G(L)->nCcalls, L->baseCcalls);*/
459 if (G(L)->nCcalls > L->baseCcalls) 508 if (G(L)->nCcalls > L->baseCcalls)
460 luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); 509 luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
461 L->base = L->top - nresults; /* protect stack slots below */ 510 L->base = L->top - nresults; /* protect stack slots below */