Browse Source

first steps towards yielding through longjump

pull/9/head
Roberto Ierusalimschy 16 years ago
parent
commit
fdbb243ff9
  1. 33
      ldo.c
  2. 8
      ldo.h
  3. 71
      lvm.c

33
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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** 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); ar.i_ci = cast_int(L->ci - L->base_ci);
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
L->ci->top = L->top + LUA_MINSTACK; 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); lua_assert(L->ci->top <= L->stack_last);
L->allowhook = 0; /* cannot call hooks inside a hook */ L->allowhook = 0; /* cannot call hooks inside a hook */
lua_unlock(L); lua_unlock(L);
@ -202,6 +203,7 @@ void luaD_callhook (lua_State *L, int event, int line) {
L->allowhook = 1; L->allowhook = 1;
L->ci->top = restorestack(L, ci_top); L->ci->top = restorestack(L, ci_top);
L->top = restorestack(L, 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)) (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) { int luaD_precall (lua_State *L, StkId func, int nresults) {
LClosure *cl; LClosure *cl;
ptrdiff_t funcr; ptrdiff_t funcr;
@ -292,6 +297,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top <= L->stack_last);
L->savedpc = p->code; /* starting point */ L->savedpc = p->code; /* starting point */
ci->tailcalls = 0; ci->tailcalls = 0;
ci->status = 0;
ci->nresults = nresults; ci->nresults = nresults;
for (st = L->top; st < ci->top; st++) for (st = L->top; st < ci->top; st++)
setnilvalue(st); setnilvalue(st);
@ -301,7 +307,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
luaD_callhook(L, LUA_HOOKCALL, -1); luaD_callhook(L, LUA_HOOKCALL, -1);
L->savedpc--; /* correct 'pc' */ L->savedpc--; /* correct 'pc' */
} }
return PCRLUA; return 0;
} }
else { /* if is a C function, call it */ else { /* if is a C function, call it */
CallInfo *ci; CallInfo *ci;
@ -318,12 +324,8 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_unlock(L); lua_unlock(L);
n = (*curr_func(L)->c.f)(L); /* do the actual call */ n = (*curr_func(L)->c.f)(L); /* do the actual call */
lua_lock(L); lua_lock(L);
if (n < 0) /* yielding? */ luaD_poscall(L, L->top - n);
return PCRYIELD; return 1;
else {
luaD_poscall(L, L->top - n);
return PCRC;
}
} }
} }
@ -378,7 +380,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ 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 */ luaV_execute(L, 1); /* call it */
g->nCcalls--; g->nCcalls--;
luaC_checkGC(L); luaC_checkGC(L);
@ -390,8 +392,8 @@ static void resume (lua_State *L, void *ud) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (L->status == LUA_OK) { /* start coroutine? */ if (L->status == LUA_OK) { /* start coroutine? */
lua_assert(ci == L->base_ci && firstArg > L->base); lua_assert(ci == L->base_ci && firstArg > L->base);
if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) if (luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* C function? */
return; return; /* done */
} }
else { /* resuming from previous yield */ else { /* resuming from previous yield */
lua_assert(L->status == LUA_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"); return resume_error(L, "C stack overflow");
L->baseCcalls = ++G(L)->nCcalls; L->baseCcalls = ++G(L)->nCcalls;
status = luaD_rawrunprotected(L, resume, L->top - nargs); 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' */ L->status = cast_byte(status); /* mark thread as `dead' */
luaD_seterrorobj(L, status, L->top); luaD_seterrorobj(L, status, L->top);
L->ci->top = L->top; L->ci->top = L->top;
} }
else { else {
lua_assert(L->baseCcalls == G(L)->nCcalls); lua_assert(L->baseCcalls == G(L)->nCcalls);
status = L->status; lua_assert(status == L->status);
} }
--G(L)->nCcalls; --G(L)->nCcalls;
L->baseCcalls = 0; 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"); luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
L->base = L->top - nresults; /* protect stack slots below */ L->base = L->top - nresults; /* protect stack slots below */
L->status = LUA_YIELD; 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); lua_unlock(L);
return -1; return 0; /* otherwise, return to 'luaD_callhook' */
} }

8
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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -28,12 +28,6 @@
#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) #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' */ /* type of protected functions, to be ran by `runprotected' */
typedef void (*Pfunc) (lua_State *L, void *ud); typedef void (*Pfunc) (lua_State *L, void *ud);

71
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 ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -415,7 +415,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
traceexec(L); traceexec(L);
if (L->status == LUA_YIELD) { /* did hook yield? */ if (L->status == LUA_YIELD) { /* did hook yield? */
L->savedpc--; /* undo increment */ L->savedpc--; /* undo increment */
return; luaD_throw(L, LUA_YIELD);
} }
base = L->base; base = L->base;
} }
@ -595,51 +595,40 @@ void luaV_execute (lua_State *L, int nexeccalls) {
int b = GETARG_B(i); int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1; int nresults = GETARG_C(i) - 1;
if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (b != 0) L->top = ra+b; /* else previous instruction set top */
switch (luaD_precall(L, ra, nresults)) { if (luaD_precall(L, ra, nresults)) { /* C function? */
case PCRLUA: { if (nresults >= 0) L->top = L->ci->top; /* adjust results */
nexeccalls++; base = L->base;
goto reentry; /* restart luaV_execute over new Lua function */ continue;
} }
case PCRC: { else { /* Lua function */
/* it was a C function (`precall' called it); adjust results */ nexeccalls++;
if (nresults >= 0) L->top = L->ci->top; goto reentry; /* restart luaV_execute over new Lua function */
base = L->base;
continue;
}
default: {
return; /* yield */
}
} }
} }
case OP_TAILCALL: { case OP_TAILCALL: {
int b = GETARG_B(i); int b = GETARG_B(i);
if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
switch (luaD_precall(L, ra, LUA_MULTRET)) { if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
case PCRLUA: { base = L->base;
/* tail call: put new frame in place of previous one */ continue;
CallInfo *ci = L->ci - 1; /* previous frame */ }
int aux; else {
StkId func = ci->func; /* tail call: put new frame in place of previous one */
StkId pfunc = (ci+1)->func; /* previous function index */ CallInfo *ci = L->ci - 1; /* previous frame */
if (L->openupval) luaF_close(L, ci->base); int aux;
L->base = ci->base = ci->func + ((ci+1)->base - pfunc); StkId func = ci->func;
for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ StkId pfunc = (ci+1)->func; /* previous function index */
setobjs2s(L, func+aux, pfunc+aux); if (L->openupval) luaF_close(L, ci->base);
ci->top = L->top = func+aux; /* correct top */ L->base = ci->base = ci->func + ((ci+1)->base - pfunc);
lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */
ci->savedpc = L->savedpc; setobjs2s(L, func+aux, pfunc+aux);
ci->tailcalls++; /* one more call lost */ ci->top = L->top = func+aux; /* correct top */
L->ci--; /* remove new frame */ lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize);
goto reentry; ci->savedpc = L->savedpc;
} ci->tailcalls++; /* one more call lost */
case PCRC: { /* it was a C function (`precall' called it) */ L->ci--; /* remove new frame */
base = L->base; goto reentry;
continue;
}
default: {
return; /* yield */
}
} }
} }
case OP_RETURN: { case OP_RETURN: {

Loading…
Cancel
Save