diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-05-14 16:25:09 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-05-14 16:25:09 -0300 |
commit | 0bda88e6cd960d3b1ad1d46826bfdef179098d2a (patch) | |
tree | d3b237faef502dba76747a5563be9ccc4c404754 /lvm.c | |
parent | 7966a4acaea50230e30acc8fd6997bce22307f24 (diff) | |
download | lua-0bda88e6cd960d3b1ad1d46826bfdef179098d2a.tar.gz lua-0bda88e6cd960d3b1ad1d46826bfdef179098d2a.tar.bz2 lua-0bda88e6cd960d3b1ad1d46826bfdef179098d2a.zip |
small steps towards yields in iterators and tag methods
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 127 |
1 files changed, 72 insertions, 55 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.4 2004/04/30 20:13:38 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.5 2004/05/10 17:50:51 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 | */ |
@@ -106,7 +106,8 @@ static void callTM (lua_State *L) { | |||
106 | } | 106 | } |
107 | 107 | ||
108 | 108 | ||
109 | void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { | 109 | StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, |
110 | const Instruction *pc) { | ||
110 | int loop; | 111 | int loop; |
111 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 112 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
112 | const TValue *tm; | 113 | const TValue *tm; |
@@ -116,24 +117,30 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { | |||
116 | if (!ttisnil(res) || /* result is no nil? */ | 117 | if (!ttisnil(res) || /* result is no nil? */ |
117 | (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ | 118 | (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ |
118 | setobj2s(L, val, res); | 119 | setobj2s(L, val, res); |
119 | return; | 120 | return L->base; |
120 | } | 121 | } |
121 | /* else will try the tag method */ | 122 | /* else will try the tag method */ |
122 | } | 123 | } |
123 | else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) | 124 | else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) { |
125 | if (pc) L->ci->u.l.savedpc = pc; | ||
124 | luaG_typeerror(L, t, "index"); | 126 | luaG_typeerror(L, t, "index"); |
127 | } | ||
125 | if (ttisfunction(tm)) { | 128 | if (ttisfunction(tm)) { |
129 | if (pc) L->ci->u.l.savedpc = pc; | ||
126 | prepTMcall(L, tm, t, key); | 130 | prepTMcall(L, tm, t, key); |
127 | callTMres(L, val); | 131 | callTMres(L, val); |
128 | return; | 132 | return L->base; |
129 | } | 133 | } |
130 | t = tm; /* else repeat with `tm' */ | 134 | t = tm; /* else repeat with `tm' */ |
131 | } | 135 | } |
136 | if (pc) L->ci->u.l.savedpc = pc; | ||
132 | luaG_runerror(L, "loop in gettable"); | 137 | luaG_runerror(L, "loop in gettable"); |
138 | return NULL; /* to avoid warnings */ | ||
133 | } | 139 | } |
134 | 140 | ||
135 | 141 | ||
136 | void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | 142 | StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, |
143 | const Instruction *pc) { | ||
137 | int loop; | 144 | int loop; |
138 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 145 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
139 | const TValue *tm; | 146 | const TValue *tm; |
@@ -144,21 +151,26 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | |||
144 | (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ | 151 | (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ |
145 | setobj2t(L, oldval, val); | 152 | setobj2t(L, oldval, val); |
146 | luaC_barrier(L, h, val); | 153 | luaC_barrier(L, h, val); |
147 | return; | 154 | return L->base; |
148 | } | 155 | } |
149 | /* else will try the tag method */ | 156 | /* else will try the tag method */ |
150 | } | 157 | } |
151 | else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) | 158 | else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) { |
159 | if (pc) L->ci->u.l.savedpc = pc; | ||
152 | luaG_typeerror(L, t, "index"); | 160 | luaG_typeerror(L, t, "index"); |
161 | } | ||
153 | if (ttisfunction(tm)) { | 162 | if (ttisfunction(tm)) { |
163 | if (pc) L->ci->u.l.savedpc = pc; | ||
154 | prepTMcall(L, tm, t, key); | 164 | prepTMcall(L, tm, t, key); |
155 | setobj2s(L, L->top+3, val); /* 3th argument */ | 165 | setobj2s(L, L->top+3, val); /* 3th argument */ |
156 | callTM(L); | 166 | callTM(L); |
157 | return; | 167 | return L->base; |
158 | } | 168 | } |
159 | t = tm; /* else repeat with `tm' */ | 169 | t = tm; /* else repeat with `tm' */ |
160 | } | 170 | } |
171 | if (pc) L->ci->u.l.savedpc = pc; | ||
161 | luaG_runerror(L, "loop in settable"); | 172 | luaG_runerror(L, "loop in settable"); |
173 | return NULL; /* to avoid warnings */ | ||
162 | } | 174 | } |
163 | 175 | ||
164 | 176 | ||
@@ -427,22 +439,16 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { | |||
427 | case OP_GETGLOBAL: { | 439 | case OP_GETGLOBAL: { |
428 | TValue *rb = KBx(i); | 440 | TValue *rb = KBx(i); |
429 | lua_assert(ttisstring(rb) && ttistable(&cl->g)); | 441 | lua_assert(ttisstring(rb) && ttistable(&cl->g)); |
430 | L->ci->u.l.savedpc = pc; | 442 | base = luaV_gettable(L, &cl->g, rb, ra, pc); /***/ |
431 | luaV_gettable(L, &cl->g, rb, ra); /***/ | ||
432 | base = L->base; | ||
433 | break; | 443 | break; |
434 | } | 444 | } |
435 | case OP_GETTABLE: { | 445 | case OP_GETTABLE: { |
436 | L->ci->u.l.savedpc = pc; | 446 | base = luaV_gettable(L, RB(i), RKC(i), ra, pc); /***/ |
437 | luaV_gettable(L, RB(i), RKC(i), ra); /***/ | ||
438 | base = L->base; | ||
439 | break; | 447 | break; |
440 | } | 448 | } |
441 | case OP_SETGLOBAL: { | 449 | case OP_SETGLOBAL: { |
442 | lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); | 450 | lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); |
443 | L->ci->u.l.savedpc = pc; | 451 | base = luaV_settable(L, &cl->g, KBx(i), ra, pc); /***/ |
444 | luaV_settable(L, &cl->g, KBx(i), ra); /***/ | ||
445 | base = L->base; | ||
446 | break; | 452 | break; |
447 | } | 453 | } |
448 | case OP_SETUPVAL: { | 454 | case OP_SETUPVAL: { |
@@ -452,9 +458,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { | |||
452 | break; | 458 | break; |
453 | } | 459 | } |
454 | case OP_SETTABLE: { | 460 | case OP_SETTABLE: { |
455 | L->ci->u.l.savedpc = pc; | 461 | base = luaV_settable(L, ra, RKB(i), RKC(i), pc); /***/ |
456 | luaV_settable(L, ra, RKB(i), RKC(i)); /***/ | ||
457 | base = L->base; | ||
458 | break; | 462 | break; |
459 | } | 463 | } |
460 | case OP_NEWTABLE: { | 464 | case OP_NEWTABLE: { |
@@ -469,9 +473,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { | |||
469 | case OP_SELF: { | 473 | case OP_SELF: { |
470 | StkId rb = RB(i); | 474 | StkId rb = RB(i); |
471 | setobjs2s(L, ra+1, rb); | 475 | setobjs2s(L, ra+1, rb); |
472 | L->ci->u.l.savedpc = pc; | 476 | base = luaV_gettable(L, rb, RKC(i), ra, pc); /***/ |
473 | luaV_gettable(L, rb, RKC(i), ra); /***/ | ||
474 | base = L->base; | ||
475 | break; | 477 | break; |
476 | } | 478 | } |
477 | case OP_ADD: { | 479 | case OP_ADD: { |
@@ -582,43 +584,59 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { | |||
582 | } | 584 | } |
583 | break; | 585 | break; |
584 | } | 586 | } |
585 | case OP_CALL: | 587 | case OP_CALL: { /***/ |
586 | case OP_TAILCALL: { /***/ | 588 | int pcr; |
587 | StkId firstResult; | ||
588 | int b = GETARG_B(i); | 589 | int b = GETARG_B(i); |
590 | int nresults = GETARG_C(i) - 1; | ||
589 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ | 591 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ |
590 | L->ci->u.l.savedpc = pc; | 592 | L->ci->u.l.savedpc = pc; |
591 | firstResult = luaD_precall(L, ra); | 593 | pcr = luaD_precall(L, ra, nresults); |
592 | if (firstResult) { | 594 | if (pcr == PCRLUA) { |
593 | int nresults = GETARG_C(i) - 1; | 595 | nexeccalls++; |
594 | if (firstResult > L->top) { /* yield? */ | 596 | goto callentry; /* restart luaV_execute over new Lua function */ |
595 | (L->ci - 1)->u.l.savedpc = pc; | 597 | } |
596 | return NULL; | 598 | else if (pcr == PCRC) { |
597 | } | ||
598 | /* it was a C function (`precall' called it); adjust results */ | 599 | /* it was a C function (`precall' called it); adjust results */ |
599 | luaD_poscall(L, nresults, firstResult); | ||
600 | if (nresults >= 0) L->top = L->ci->top; | 600 | if (nresults >= 0) L->top = L->ci->top; |
601 | base = L->base; | ||
602 | break; | ||
601 | } | 603 | } |
602 | else { /* it is a Lua function */ | 604 | else { |
603 | if (GET_OPCODE(i) == OP_CALL) /* regular call? */ | 605 | lua_assert(pcr == PCRYIELD); |
604 | nexeccalls++; | 606 | return NULL; |
605 | else { /* tail call: put new frame in place of previous one */ | 607 | } |
606 | int aux; | 608 | } |
607 | base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ | 609 | case OP_TAILCALL: { /***/ |
608 | ra = RA(i); | 610 | int pcr; |
609 | if (L->openupval) luaF_close(L, base); | 611 | int b = GETARG_B(i); |
610 | for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ | 612 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ |
611 | setobjs2s(L, base+aux-1, ra+aux); | 613 | L->ci->u.l.savedpc = pc; |
612 | (L->ci - 1)->top = L->top = base+aux; /* correct top */ | 614 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); |
613 | (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; | 615 | pcr = luaD_precall(L, ra, LUA_MULTRET); |
614 | (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ | 616 | if (pcr == PCRLUA) { |
615 | L->ci--; /* remove new frame */ | 617 | /* tail call: put new frame in place of previous one */ |
616 | L->base = L->ci->base; | 618 | int aux; |
617 | } | 619 | base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ |
620 | ra = RA(i); | ||
621 | if (L->openupval) luaF_close(L, base); | ||
622 | for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ | ||
623 | setobjs2s(L, base+aux-1, ra+aux); | ||
624 | (L->ci - 1)->top = L->top = base+aux; /* correct top */ | ||
625 | (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; | ||
626 | (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ | ||
627 | L->ci--; /* remove new frame */ | ||
628 | L->base = L->ci->base; | ||
618 | goto callentry; | 629 | goto callentry; |
619 | } | 630 | } |
620 | base = L->base; | 631 | else if (pcr == PCRC) { |
621 | break; | 632 | /* it was a C function (`precall' called it) */ |
633 | base = L->base; | ||
634 | break; | ||
635 | } | ||
636 | else { | ||
637 | lua_assert(pcr == PCRYIELD); | ||
638 | return NULL; | ||
639 | } | ||
622 | } | 640 | } |
623 | case OP_RETURN: { | 641 | case OP_RETURN: { |
624 | CallInfo *ci = L->ci - 1; /* previous function frame */ | 642 | CallInfo *ci = L->ci - 1; /* previous function frame */ |
@@ -629,10 +647,9 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { | |||
629 | if (--nexeccalls == 0) /* was previous function running `here'? */ | 647 | if (--nexeccalls == 0) /* was previous function running `here'? */ |
630 | return ra; /* no: return */ | 648 | return ra; /* no: return */ |
631 | else { /* yes: continue its execution */ | 649 | else { /* yes: continue its execution */ |
632 | int nresults; | 650 | int nresults = (ci+1)->nresults; |
633 | lua_assert(isLua(ci)); | 651 | lua_assert(isLua(ci)); |
634 | lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); | 652 | lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); |
635 | nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; | ||
636 | luaD_poscall(L, nresults, ra); | 653 | luaD_poscall(L, nresults, ra); |
637 | if (nresults >= 0) L->top = L->ci->top; | 654 | if (nresults >= 0) L->top = L->ci->top; |
638 | goto retentry; | 655 | goto retentry; |