commit 0bda88e6cd960d3b1ad1d46826bfdef179098d2a
parent 7966a4acaea50230e30acc8fd6997bce22307f24
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Fri, 14 May 2004 16:24:47 -0300
small steps towards yields in iterators and tag methods
Diffstat:
M | lapi.c | | | 10 | +++++----- |
M | ldo.c | | | 30 | ++++++++++++++++++------------ |
M | ldo.h | | | 10 | ++++++++-- |
M | lstate.h | | | 5 | +++-- |
M | lvm.c | | | 127 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | lvm.h | | | 8 | +++++--- |
6 files changed, 111 insertions(+), 79 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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_TAILCALL: { /***/
- StkId firstResult;
+ 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;
- 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;
- }
+ 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 */
- luaD_poscall(L, nresults, firstResult);
if (nresults >= 0) L->top = L->ci->top;
+ base = L->base;
+ break;
}
- 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;
- }
+ else {
+ lua_assert(pcr == PCRYIELD);
+ return NULL;
+ }
+ }
+ case OP_TAILCALL: { /***/
+ 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;
+ 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
@@ -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);