From fdbb243ff9980870c54676f3b2597b110ab82864 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 13 Aug 2008 14:02:42 -0300 Subject: [PATCH] first steps towards yielding through longjump --- ldo.c | 33 +++++++++++++++------------ ldo.h | 8 +------ lvm.c | 71 +++++++++++++++++++++++++---------------------------------- 3 files changed, 50 insertions(+), 62 deletions(-) diff --git a/ldo.c b/ldo.c index c156a40e..c984dd09 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.45 2007/03/27 14:11:38 roberto Exp roberto $ +** $Id: ldo.c,v 2.46 2008/01/18 22:36:50 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -193,6 +193,7 @@ void luaD_callhook (lua_State *L, int event, int line) { ar.i_ci = cast_int(L->ci - L->base_ci); luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; + L->ci->status |= 1; /* this level is running a hook */ lua_assert(L->ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ lua_unlock(L); @@ -202,6 +203,7 @@ void luaD_callhook (lua_State *L, int event, int line) { L->allowhook = 1; L->ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); + L->ci->status &= ~1; /* this level is not running a hook anymore */ } } @@ -264,6 +266,9 @@ static StkId tryfuncTM (lua_State *L, StkId func) { (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) +/* +** returns true if function has been executed (C function) +*/ int luaD_precall (lua_State *L, StkId func, int nresults) { LClosure *cl; ptrdiff_t funcr; @@ -292,6 +297,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_assert(ci->top <= L->stack_last); L->savedpc = p->code; /* starting point */ ci->tailcalls = 0; + ci->status = 0; ci->nresults = nresults; for (st = L->top; st < ci->top; st++) setnilvalue(st); @@ -301,7 +307,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { luaD_callhook(L, LUA_HOOKCALL, -1); L->savedpc--; /* correct 'pc' */ } - return PCRLUA; + return 0; } else { /* if is a C function, call it */ CallInfo *ci; @@ -318,12 +324,8 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ lua_lock(L); - if (n < 0) /* yielding? */ - return PCRYIELD; - else { - luaD_poscall(L, L->top - n); - return PCRC; - } + luaD_poscall(L, L->top - n); + return 1; } } @@ -378,7 +380,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ + if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L, 1); /* call it */ g->nCcalls--; luaC_checkGC(L); @@ -390,8 +392,8 @@ static void resume (lua_State *L, void *ud) { CallInfo *ci = L->ci; if (L->status == LUA_OK) { /* start coroutine? */ lua_assert(ci == L->base_ci && firstArg > L->base); - if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) - return; + if (luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* C function? */ + return; /* done */ } else { /* resuming from previous yield */ lua_assert(L->status == LUA_YIELD); @@ -434,14 +436,14 @@ LUA_API int lua_resume (lua_State *L, int nargs) { return resume_error(L, "C stack overflow"); L->baseCcalls = ++G(L)->nCcalls; status = luaD_rawrunprotected(L, resume, L->top - nargs); - if (status != LUA_OK) { /* error? */ + if (status != LUA_OK && status != LUA_YIELD) { /* error? */ L->status = cast_byte(status); /* mark thread as `dead' */ luaD_seterrorobj(L, status, L->top); L->ci->top = L->top; } else { lua_assert(L->baseCcalls == G(L)->nCcalls); - status = L->status; + lua_assert(status == L->status); } --G(L)->nCcalls; L->baseCcalls = 0; @@ -457,8 +459,11 @@ LUA_API int lua_yield (lua_State *L, int nresults) { luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); L->base = L->top - nresults; /* protect stack slots below */ L->status = LUA_YIELD; + if (!isLua(L->ci)) /* not inside a hook? */ + luaD_throw(L, LUA_YIELD); + lua_assert(L->ci->status & 1); /* must be inside a hook */ lua_unlock(L); - return -1; + return 0; /* otherwise, return to 'luaD_callhook' */ } diff --git a/ldo.h b/ldo.h index c8d0f872..ad86a09c 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.8 2006/07/11 15:53:29 roberto Exp roberto $ +** $Id: ldo.h,v 2.9 2008/07/03 14:24:36 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -28,12 +28,6 @@ #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); diff --git a/lvm.c b/lvm.c index b295d5eb..c499913a 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.73 2007/09/10 17:59:32 roberto Exp roberto $ +** $Id: lvm.c,v 2.74 2008/04/02 16:16:06 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -415,7 +415,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { traceexec(L); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc--; /* undo increment */ - return; + luaD_throw(L, LUA_YIELD); } base = L->base; } @@ -595,51 +595,40 @@ void luaV_execute (lua_State *L, int nexeccalls) { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - switch (luaD_precall(L, ra, nresults)) { - case PCRLUA: { - nexeccalls++; - goto reentry; /* restart luaV_execute over new Lua function */ - } - case PCRC: { - /* it was a C function (`precall' called it); adjust results */ - if (nresults >= 0) L->top = L->ci->top; - base = L->base; - continue; - } - default: { - return; /* yield */ - } + if (luaD_precall(L, ra, nresults)) { /* C function? */ + if (nresults >= 0) L->top = L->ci->top; /* adjust results */ + base = L->base; + continue; + } + else { /* Lua function */ + nexeccalls++; + goto reentry; /* restart luaV_execute over new Lua function */ } } case OP_TAILCALL: { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - switch (luaD_precall(L, ra, LUA_MULTRET)) { - case PCRLUA: { - /* tail call: put new frame in place of previous one */ - CallInfo *ci = L->ci - 1; /* previous frame */ - int aux; - StkId func = ci->func; - StkId pfunc = (ci+1)->func; /* previous function index */ - if (L->openupval) luaF_close(L, ci->base); - L->base = ci->base = ci->func + ((ci+1)->base - pfunc); - for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ - setobjs2s(L, func+aux, pfunc+aux); - ci->top = L->top = func+aux; /* correct top */ - lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); - ci->savedpc = L->savedpc; - ci->tailcalls++; /* one more call lost */ - L->ci--; /* remove new frame */ - goto reentry; - } - case PCRC: { /* it was a C function (`precall' called it) */ - base = L->base; - continue; - } - default: { - return; /* yield */ - } + if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + base = L->base; + continue; + } + else { + /* tail call: put new frame in place of previous one */ + CallInfo *ci = L->ci - 1; /* previous frame */ + int aux; + StkId func = ci->func; + StkId pfunc = (ci+1)->func; /* previous function index */ + if (L->openupval) luaF_close(L, ci->base); + L->base = ci->base = ci->func + ((ci+1)->base - pfunc); + for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci->top = L->top = func+aux; /* correct top */ + lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); + ci->savedpc = L->savedpc; + ci->tailcalls++; /* one more call lost */ + L->ci--; /* remove new frame */ + goto reentry; } } case OP_RETURN: {