From 0bda88e6cd960d3b1ad1d46826bfdef179098d2a Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 14 May 2004 16:25:09 -0300 Subject: [PATCH] small steps towards yields in iterators and tag methods --- lapi.c | 10 ++--- ldo.c | 30 ++++++++----- ldo.h | 10 ++++- lstate.h | 5 ++- lvm.c | 131 +++++++++++++++++++++++++++++++------------------------ lvm.h | 8 ++-- 6 files changed, 113 insertions(+), 81 deletions(-) diff --git a/lapi.c b/lapi.c index bb436ebd..7a1a72d3 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.7 2004/04/30 20:13:38 roberto Exp roberto $ +** $Id: lapi.c,v 2.8 2004/05/11 16:52:08 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -488,7 +488,7 @@ LUA_API void lua_gettable (lua_State *L, int idx) { lua_lock(L); t = luaA_index(L, idx); api_checkvalidindex(L, t); - luaV_gettable(L, t, L->top - 1, L->top - 1); + luaV_gettable(L, t, L->top - 1, L->top - 1, NULL); lua_unlock(L); } @@ -500,7 +500,7 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { t = luaA_index(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top); + luaV_gettable(L, t, &key, L->top, NULL); api_incr_top(L); lua_unlock(L); } @@ -584,7 +584,7 @@ LUA_API void lua_settable (lua_State *L, int idx) { api_checknelems(L, 2); t = luaA_index(L, idx); api_checkvalidindex(L, t); - luaV_settable(L, t, L->top - 2, L->top - 1); + luaV_settable(L, t, L->top - 2, L->top - 1, NULL); L->top -= 2; /* pop index and value */ lua_unlock(L); } @@ -598,7 +598,7 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { t = luaA_index(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1); + luaV_settable(L, t, &key, L->top - 1, NULL); L->top--; /* pop value */ lua_unlock(L); } diff --git a/ldo.c b/ldo.c index f2682670..fc1caa7f 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.3 2004/04/30 20:13:38 roberto Exp roberto $ +** $Id: ldo.c,v 2.4 2004/05/10 17:50:51 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -219,7 +219,7 @@ static StkId tryfuncTM (lua_State *L, StkId func) { } -StkId luaD_precall (lua_State *L, StkId func) { +int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr = savestack(L, func); if (!ttisfunction(func)) /* `func' is not a function? */ @@ -239,10 +239,11 @@ StkId luaD_precall (lua_State *L, StkId func) { ci->top = L->base + p->maxstacksize; ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.tailcalls = 0; + ci->nresults = nresults; for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; - return NULL; + return PCRLUA; } else { /* if is a C function, call it */ CallInfo *ci; @@ -256,7 +257,14 @@ StkId luaD_precall (lua_State *L, StkId func) { lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); - return L->top - n; + if (n >= 0) { /* no yielding? */ + luaD_poscall(L, nresults, L->top - n); + return PCRC; + } + else { + ci->nresults = nresults; + return PCRYIELD; + } } } @@ -297,17 +305,16 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults) { - StkId firstResult; if (++L->nCcalls >= LUA_MAXCCALLS) { if (L->nCcalls == LUA_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - firstResult = luaD_precall(L, func); - if (firstResult == NULL) /* is a Lua function? */ - firstResult = luaV_execute(L, 1); /* call it */ - luaD_poscall(L, nResults, firstResult); + if (luaD_precall(L, func, nResults) == PCRLUA) { /* is a Lua function? */ + StkId firstResult = luaV_execute(L, 1); /* call it */ + luaD_poscall(L, nResults, firstResult); + } L->nCcalls--; luaC_checkGC(L); } @@ -319,15 +326,14 @@ static void resume (lua_State *L, void *ud) { CallInfo *ci = L->ci; if (!L->isSuspended) { lua_assert(ci == L->base_ci && nargs < L->top - L->base); - luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ + luaD_precall(L, L->top - (nargs + 1), LUA_MULTRET); /* start coroutine */ } else { /* resuming from previous yield */ if (!f_isLua(ci)) { /* `common' yield? */ /* finish interrupted execution of `OP_CALL' */ - int nresults; + int nresults = ci->nresults; lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); - nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, L->top - nargs); /* complete it */ if (nresults >= 0) L->top = L->ci->top; } /* else yielded inside a hook: just continue its execution */ diff --git a/ldo.h b/ldo.h index fc13692c..8e2e026b 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.58 2003/08/27 21:01:44 roberto Exp roberto $ +** $Id: ldo.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -38,13 +38,19 @@ #define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) +/* results from luaD_precall */ +#define PCRLUA 0 /* initiated a call to a Lua function */ +#define PCRC 1 /* did a call to a C function */ +#define PCRYIELD 2 /* C funtion yielded */ + + /* type of protected functions, to be ran by `runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); void luaD_resetprotection (lua_State *L); int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); void luaD_callhook (lua_State *L, int event, int line); -StkId luaD_precall (lua_State *L, StkId func); +int luaD_precall (lua_State *L, StkId func, int nresults); void luaD_call (lua_State *L, StkId func, int nResults); int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); diff --git a/lstate.h b/lstate.h index 19ff1bd9..3a1eb329 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ +** $Id: lstate.h,v 2.2 2004/03/23 17:02:58 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -70,8 +70,9 @@ typedef struct stringtable { ** informations about a call */ typedef struct CallInfo { - StkId base; /* base for called function */ + StkId base; /* base for this function */ StkId top; /* top for this function */ + int nresults; /* expected number of results from this function */ union { struct { /* for Lua functions */ const Instruction *savedpc; diff --git a/lvm.c b/lvm.c index a7a4b3b3..4c5a7ec7 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.4 2004/04/30 20:13:38 roberto Exp roberto $ +** $Id: lvm.c,v 2.5 2004/05/10 17:50:51 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -106,7 +106,8 @@ static void callTM (lua_State *L) { } -void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { +StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, + const Instruction *pc) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; @@ -116,24 +117,30 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); - return; + return L->base; } /* else will try the tag method */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) { + if (pc) L->ci->u.l.savedpc = pc; luaG_typeerror(L, t, "index"); + } if (ttisfunction(tm)) { + if (pc) L->ci->u.l.savedpc = pc; prepTMcall(L, tm, t, key); callTMres(L, val); - return; + return L->base; } t = tm; /* else repeat with `tm' */ } + if (pc) L->ci->u.l.savedpc = pc; luaG_runerror(L, "loop in gettable"); + return NULL; /* to avoid warnings */ } -void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { +StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, + const Instruction *pc) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; @@ -144,21 +151,26 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barrier(L, h, val); - return; + return L->base; } /* else will try the tag method */ } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) { + if (pc) L->ci->u.l.savedpc = pc; luaG_typeerror(L, t, "index"); + } if (ttisfunction(tm)) { + if (pc) L->ci->u.l.savedpc = pc; prepTMcall(L, tm, t, key); setobj2s(L, L->top+3, val); /* 3th argument */ callTM(L); - return; + return L->base; } t = tm; /* else repeat with `tm' */ } + if (pc) L->ci->u.l.savedpc = pc; luaG_runerror(L, "loop in settable"); + return NULL; /* to avoid warnings */ } @@ -427,22 +439,16 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { case OP_GETGLOBAL: { TValue *rb = KBx(i); lua_assert(ttisstring(rb) && ttistable(&cl->g)); - L->ci->u.l.savedpc = pc; - luaV_gettable(L, &cl->g, rb, ra); /***/ - base = L->base; + base = luaV_gettable(L, &cl->g, rb, ra, pc); /***/ break; } case OP_GETTABLE: { - L->ci->u.l.savedpc = pc; - luaV_gettable(L, RB(i), RKC(i), ra); /***/ - base = L->base; + base = luaV_gettable(L, RB(i), RKC(i), ra, pc); /***/ break; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); - L->ci->u.l.savedpc = pc; - luaV_settable(L, &cl->g, KBx(i), ra); /***/ - base = L->base; + base = luaV_settable(L, &cl->g, KBx(i), ra, pc); /***/ break; } case OP_SETUPVAL: { @@ -452,9 +458,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { break; } case OP_SETTABLE: { - L->ci->u.l.savedpc = pc; - luaV_settable(L, ra, RKB(i), RKC(i)); /***/ - base = L->base; + base = luaV_settable(L, ra, RKB(i), RKC(i), pc); /***/ break; } case OP_NEWTABLE: { @@ -469,9 +473,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); - L->ci->u.l.savedpc = pc; - luaV_gettable(L, rb, RKC(i), ra); /***/ - base = L->base; + base = luaV_gettable(L, rb, RKC(i), ra, pc); /***/ break; } case OP_ADD: { @@ -582,43 +584,59 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { } break; } - case OP_CALL: + case OP_CALL: { /***/ + int pcr; + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L->top = ra+b; /* else previous instruction set top */ + L->ci->u.l.savedpc = pc; + pcr = luaD_precall(L, ra, nresults); + if (pcr == PCRLUA) { + nexeccalls++; + goto callentry; /* restart luaV_execute over new Lua function */ + } + else if (pcr == PCRC) { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L->top = L->ci->top; + base = L->base; + break; + } + else { + lua_assert(pcr == PCRYIELD); + return NULL; + } + } case OP_TAILCALL: { /***/ - StkId firstResult; + int pcr; int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ L->ci->u.l.savedpc = pc; - firstResult = luaD_precall(L, ra); - if (firstResult) { - int nresults = GETARG_C(i) - 1; - if (firstResult > L->top) { /* yield? */ - (L->ci - 1)->u.l.savedpc = pc; - return NULL; - } - /* it was a C function (`precall' called it); adjust results */ - luaD_poscall(L, nresults, firstResult); - if (nresults >= 0) L->top = L->ci->top; - } - else { /* it is a Lua function */ - if (GET_OPCODE(i) == OP_CALL) /* regular call? */ - nexeccalls++; - else { /* tail call: put new frame in place of previous one */ - int aux; - base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ - ra = RA(i); - if (L->openupval) luaF_close(L, base); - for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ - setobjs2s(L, base+aux-1, ra+aux); - (L->ci - 1)->top = L->top = base+aux; /* correct top */ - (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; - (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ - L->ci--; /* remove new frame */ - L->base = L->ci->base; - } + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + pcr = luaD_precall(L, ra, LUA_MULTRET); + if (pcr == PCRLUA) { + /* tail call: put new frame in place of previous one */ + int aux; + base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ + ra = RA(i); + if (L->openupval) luaF_close(L, base); + for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, base+aux-1, ra+aux); + (L->ci - 1)->top = L->top = base+aux; /* correct top */ + (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; + (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ + L->ci--; /* remove new frame */ + L->base = L->ci->base; goto callentry; } - base = L->base; - break; + else if (pcr == PCRC) { + /* it was a C function (`precall' called it) */ + base = L->base; + break; + } + else { + lua_assert(pcr == PCRYIELD); + return NULL; + } } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ @@ -629,10 +647,9 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { if (--nexeccalls == 0) /* was previous function running `here'? */ return ra; /* no: return */ else { /* yes: continue its execution */ - int nresults; + int nresults = (ci+1)->nresults; lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); - nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; goto retentry; diff --git a/lvm.h b/lvm.h index defe611f..0cae36c9 100644 --- a/lvm.h +++ b/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.49 2003/07/16 20:49:02 roberto Exp roberto $ +** $Id: lvm.h,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -26,8 +26,10 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); const TValue *luaV_tonumber (const TValue *obj, TValue *n); int luaV_tostring (lua_State *L, StkId obj); -void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val); -void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); +StkId luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val, + const Instruction *pc); +StkId luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val, + const Instruction *pc); StkId luaV_execute (lua_State *L, int nexeccalls); void luaV_concat (lua_State *L, int total, int last);