diff -ruN oldsrc/lapi.c newsrc/lapi.c --- oldsrc/lapi.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lapi.c 2006年04月15日 23:44:03.000000000 -0500 @@ -283,7 +283,9 @@ lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); + notresumable(L, + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); + ) lua_unlock(L); return i; } @@ -295,8 +297,10 @@ lua_lock(L); /* may call tag method */ o1 = index2adr(L, index1); o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaV_lessthan(L, o1, o2); + notresumable(L, + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); + ) lua_unlock(L); return i; } @@ -529,7 +533,9 @@ lua_lock(L); t = index2adr(L, idx); api_checkvalidindex(L, t); - luaV_gettable(L, t, L->top - 1, L->top - 1); + notresumable(L, + luaV_gettable(L, t, L->top - 1, L->top - 1); + ) lua_unlock(L); } @@ -541,7 +547,9 @@ t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top); + notresumable(L, + luaV_gettable(L, t, &key, L->top); + ) api_incr_top(L); lua_unlock(L); } @@ -641,7 +649,9 @@ api_checknelems(L, 2); t = index2adr(L, idx); api_checkvalidindex(L, t); - luaV_settable(L, t, L->top - 2, L->top - 1); + notresumable(L, + luaV_settable(L, t, L->top - 2, L->top - 1); + ) L->top -= 2; /* pop index and value */ lua_unlock(L); } @@ -655,7 +665,9 @@ t = index2adr(L, idx); api_checkvalidindex(L, t); setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1); + notresumable(L, + luaV_settable(L, t, &key, L->top - 1); + ) L->top--; /* pop value */ lua_unlock(L); } @@ -758,22 +770,29 @@ */ -#define adjustresults(L,nres) \ - { if (nres == LUA_MULTRET && L->top>= L->ci->top) L->ci->top = L->top; } - - #define checkresults(L,na,nr) \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top>= (nr) - (na))) - -LUA_API void lua_call (lua_State *L, int nargs, int nresults) { - StkId func; + +LUA_API void *lua_vcontext (lua_State *L) { + return L->ctx; +} + + +LUA_API void lua_vcall (lua_State *L, int nargs, int nresults, void *ctx) { + int flags; lua_lock(L); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); - func = L->top - (nargs+1); - luaD_call(L, func, nresults); - adjustresults(L, nresults); + if (ctx == NULL) + flags = LUA_NOYIELD | LUA_NOVPCALL; + else { + lua_assert(iscfunction(L->ci->func)); + L->ctx = ctx; + flags = 0; + } + luaD_call(L, L->top - (nargs+1), nresults, flags); + if (L->top> L->ci->top) L->ci->top = L->top; lua_unlock(L); } @@ -788,31 +807,36 @@ }; -static void f_call (lua_State *L, void *ud) { +static int f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); - luaD_call(L, c->func, c->nresults); + luaD_call(L, c->func, c->nresults, LUA_NOYIELD); + return 0; } - -LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { - struct CallS c; +LUA_API int lua_vpcall (lua_State *L, int nargs, int nresults, + int errfunc, void *ctx) { int status; - ptrdiff_t func; lua_lock(L); api_checknelems(L, nargs+1); checkresults(L, nargs, nresults); - if (errfunc == 0) - func = 0; - else { - StkId o = index2adr(L, errfunc); - api_checkvalidindex(L, o); - func = savestack(L, o); - } - c.func = L->top - (nargs+1); /* function to be called */ - c.nresults = nresults; - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); - adjustresults(L, nresults); + if (errfunc < 0) errfunc = (L->top - L->base) + errfunc + 1; + api_check(L, L->base + errfunc <= L->top - (nargs+1)); + if (ctx == NULL || novpcall(L)) { /* use classic pcall */ + struct CallS c; + c.func = L->top - (nargs+1); /* function to be called */ + c.nresults = nresults; + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), + errfunc, ~LUA_NOVPCALL); + } + else { /* else use vpcall */ + luaD_catch(L, errfunc); + L->ctx = ctx; + luaD_call(L, L->top - (nargs+1), nresults, 0); + L->ci->errfunc = 0; + status = 0; + } + if (L->top> L->ci->top) L->ci->top = L->top; lua_unlock(L); return status; } @@ -827,7 +851,7 @@ }; -static void f_Ccall (lua_State *L, void *ud) { +static int f_Ccall (lua_State *L, void *ud) { struct CCallS *c = cast(struct CCallS *, ud); Closure *cl; cl = luaF_newCclosure(L, 0, getcurrenv(L)); @@ -836,7 +860,8 @@ api_incr_top(L); setpvalue(L->top, c->ud); /* push only argument */ api_incr_top(L); - luaD_call(L, L->top - 2, 0); + luaD_call(L, L->top - 2, 0, LUA_NOYIELD); + return 0; } @@ -846,7 +871,7 @@ lua_lock(L); c.func = func; c.ud = ud; - status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0); + status = luaD_pcall(L, f_Ccall, &c, savestack(L, L->top), 0, ~LUA_NOVPCALL); lua_unlock(L); return status; } @@ -954,7 +979,7 @@ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); - luaG_errormsg(L); + luaD_throw(L, LUA_ERRRUN); lua_unlock(L); return 0; /* to avoid warnings */ } @@ -982,7 +1007,9 @@ api_checknelems(L, n); if (n>= 2) { luaC_checkGC(L); - luaV_concat(L, n, cast_int(L->top - L->base) - 1); + notresumable(L, + luaV_concat(L, n, cast_int(L->top - L->base) - 1); + ) L->top -= (n-1); } else if (n == 0) { /* push empty string */ diff -ruN oldsrc/lbaselib.c newsrc/lbaselib.c --- oldsrc/lbaselib.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lbaselib.c 2006年04月15日 23:44:03.000000000 -0500 @@ -30,13 +30,18 @@ */ static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ - int i; + int i = lua_icontext(L); + if (i) { + n -= 2; /* compensate for tostring function and result */ + goto resume; + } lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); + lua_icall(L, 1, 1, i); +resume: s = lua_tostring(L, -1); /* get result */ if (s == NULL) return luaL_error(L, LUA_QL("tostring") " must return a string to " @@ -323,11 +328,12 @@ static int luaB_dofile (lua_State *L) { - const char *fname = luaL_optstring(L, 1, NULL); - int n = lua_gettop(L); - if (luaL_loadfile(L, fname) != 0) lua_error(L); - lua_call(L, 0, LUA_MULTRET); - return lua_gettop(L) - n; + if (lua_icontext(L)) goto resume; + lua_settop(L, 1); + if (luaL_loadfile(L, luaL_optstring(L, 1, NULL)) != 0) lua_error(L); + lua_icall(L, 0, LUA_MULTRET, 1); +resume: + return lua_gettop(L) - 1; } @@ -369,32 +375,53 @@ } +static int aux_pcall (lua_State *L, int ef) { + int status = lua_icontext(L); + if (status) goto resume; + luaL_checkany(L, ef+1); + status = lua_ipcall(L, lua_gettop(L) - ef - 1, LUA_MULTRET, ef, -1); +resume: + if (status> 0) { /* error */ + lua_pushboolean(L, 0); + lua_insert(L, -2); /* args may be left on stack with vpcall/ipcall */ + return 2; /* return status + error */ + } + else { /* ok */ + lua_pushboolean(L, 1); + lua_insert(L, ef+1); + return lua_gettop(L) - ef; /* return status + all results */ + } +} + + static int luaB_pcall (lua_State *L) { - int status; - luaL_checkany(L, 1); - status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - lua_pushboolean(L, (status == 0)); - lua_insert(L, 1); - return lua_gettop(L); /* return status + all results */ + return aux_pcall(L, 0); } -static int luaB_xpcall (lua_State *L) { - int status; - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_insert(L, 1); /* put error function under function to be called */ - status = lua_pcall(L, 0, LUA_MULTRET, 1); - lua_pushboolean(L, (status == 0)); - lua_replace(L, 1); - return lua_gettop(L); /* return status + all results */ +static int luaB_epcall (lua_State *L) { + return aux_pcall(L, 1); +} + + +static int luaB_xpcall (lua_State *L) { /* for compatibility only */ + if (lua_icontext(L) == 0) { + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_insert(L, 1); /* put error function under function to be called */ + } + return aux_pcall(L, 1); } static int luaB_tostring (lua_State *L) { + if (lua_icontext(L)) return 1; luaL_checkany(L, 1); - if (luaL_callmeta(L, 1, "__tostring")) /* is there a metafield? */ - return 1; /* use its value */ + if (luaL_getmetafield(L, 1, "__tostring")) { + lua_pushvalue(L, 1); + lua_icall(L, 1, 1, 1); /* call metamethod */ + return 1; + } switch (lua_type(L, 1)) { case LUA_TNUMBER: lua_pushstring(L, lua_tostring(L, 1)); @@ -466,6 +493,7 @@ {"tostring", luaB_tostring}, {"type", luaB_type}, {"unpack", luaB_unpack}, + {"epcall", luaB_epcall}, {"xpcall", luaB_xpcall}, {NULL, NULL} }; @@ -482,6 +510,7 @@ if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); if (lua_status(co) == 0 && lua_gettop(co) == 0) { + lua_pushboolean(L, 0); lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } @@ -489,13 +518,16 @@ status = lua_resume(co, narg); if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); - if (!lua_checkstack(L, nres)) + if (!lua_checkstack(L, nres+1)) luaL_error(L, "too many results to resume"); + lua_pushboolean(L, 1); lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { lua_xmove(co, L, 1); /* move error message */ + lua_pushboolean(L, 0); /* must do it this way for the L == co case */ + lua_insert(L, -2); return -1; /* error flag */ } } @@ -506,16 +538,10 @@ int r; luaL_argcheck(L, co, 1, "coroutine expected"); r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); + if (r < 0) return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - lua_insert(L, -(r + 1)); + else return r + 1; /* return true + `resume' returns */ - } } @@ -536,8 +562,7 @@ static int luaB_cocreate (lua_State *L) { lua_State *NL = lua_newthread(L); - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); + luaL_checkany(L, 1); /* any callable is ok */ lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; diff -ruN oldsrc/ldebug.c newsrc/ldebug.c --- oldsrc/ldebug.c 2006-04-15 23:40:17.000000000 -0500 +++ newsrc/ldebug.c 2006-04-15 23:44:03.000000000 -0500 @@ -36,8 +36,8 @@ static int currentpc (lua_State *L, CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ if (ci == L->ci) - ci->savedpc = L->savedpc; - return pcRel(ci->savedpc, ci_func(ci)->l.p); + ci->ctx = L->ctx; + return pcRel(cast(const Instruction *, ci->ctx), ci_func(ci)->l.p); } @@ -597,24 +597,11 @@ } -void luaG_errormsg (lua_State *L) { - if (L->errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L->errfunc); - if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); - setobjs2s(L, L->top, L->top - 1); /* move argument */ - setobjs2s(L, L->top - 1, errfunc); /* push function */ - incr_top(L); - luaD_call(L, L->top - 2, 1); /* call it */ - } - luaD_throw(L, LUA_ERRRUN); -} - - void luaG_runerror (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); addinfo(L, luaO_pushvfstring(L, fmt, argp)); va_end(argp); - luaG_errormsg(L); + luaD_throw(L, LUA_ERRRUN); } diff -ruN oldsrc/ldebug.h newsrc/ldebug.h --- oldsrc/ldebug.h 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/ldebug.h 2006年04月15日 23:44:03.000000000 -0500 @@ -26,7 +26,6 @@ LUAI_FUNC int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC void luaG_runerror (lua_State *L, const char *fmt, ...); -LUAI_FUNC void luaG_errormsg (lua_State *L); LUAI_FUNC int luaG_checkcode (const Proto *pt); LUAI_FUNC int luaG_checkopenop (Instruction i); diff -ruN oldsrc/ldo.c newsrc/ldo.c --- oldsrc/ldo.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/ldo.c 2006年04月15日 23:44:03.000000000 -0500 @@ -58,6 +58,10 @@ setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } + case LUA_ERREXC: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "unhandled C++ exception")); + break; + } case LUA_ERRSYNTAX: case LUA_ERRRUN: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ @@ -83,18 +87,34 @@ L->base = L->ci->base; luaF_close(L, L->base); /* close eventual pending closures */ luaD_seterrorobj(L, status, L->base); - L->nCcalls = 0; - L->allowhook = 1; + L->nCcalls = LUA_NOYIELD | LUA_NOVPCALL; restore_stack_limit(L); - L->errfunc = 0; L->errorJmp = NULL; } +/* search for an error handler in the frame stack and call it */ +static int call_errfunc (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci> L->base_ci && ci->errfunc == 0; ci--) ; + if (ci->errfunc>= 2) { + StkId errfunc = ci->base + (ci->errfunc - 2); + if (!ttisfunction(errfunc)) return LUA_ERRERR; + setobjs2s(L, L->top, L->top - 1); /* move argument */ + setobjs2s(L, L->top - 1, errfunc); /* push function */ + incr_top(L); + luaD_call(L, L->top - 2, 1, LUA_NOYIELD | LUA_NOVPCALL); /* call it */ + } + return LUA_ERRRUN; +} + void luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { - L->errorJmp->status = errcode; - LUAI_THROW(L, L->errorJmp); + struct lua_longjmp *lj = L->errorJmp; + if (lj) { + if (errcode == LUA_ERRRUN) + errcode = call_errfunc(L); + lj->status = errcode; + LUAI_THROW(L, lj); } else { L->status = cast_byte(errcode); @@ -114,12 +134,84 @@ lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, - (*f)(L, ud); + lj.status = (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ return lj.status; } + +static int f_continue (lua_State *L, void *ud) { + ptrdiff_t stop_ci = (ptrdiff_t)ud; + while (L->ci> restoreci(L, stop_ci)) { /* continue frames, top to bottom */ + CClosure *cc = &ci_func(L->ci)->c; + L->ci->errfunc = 0; + if (cc->isC) { /* continue C function */ + int n; + lua_assert(L->ctx != NULL); + if (L->top> L->ci->top) L->ci->top = L->top; + lua_unlock(L); + n = (*cc->f)(L); /* (re-)call it */ + lua_lock(L); + if (n < 0) return LUA_YIELD; + lua_assert(L->base + n <= L->top); + luaD_poscall(L, L->top - n); + } + else { /* continue Lua function */ + luaV_resume(L); + if (luaV_execute(L)) return LUA_YIELD; + } + } + return 0; +} + + +static int unwind_frames (lua_State *L, CallInfo *stop, ptrdiff_t old_top, + int status) { + CallInfo *ci; + StkId otop; + for (ci = L->ci; ci> stop; ci--) + if (ci->errfunc) { /* found vpcall catch frame */ + L->ctx = (void *)(ptrdiff_t)status; + otop = L->ci> ci ? (ci+1)->func : L->top - 1; + goto found; + } + if (old_top == 0) return -1; /* no unwind? */ + otop = restorestack(L, old_top); +found: + luaF_close(L, otop); /* close eventual pending closures */ + luaD_seterrorobj(L, status, otop); /* sets L->top, too */ + L->ci = ci; + L->base = ci->base; + L->hookmask = ci->hookmask; + restore_stack_limit(L); + return ci == stop; +} + + +int luaD_pcall (lua_State *L, Pfunc func, void *ud, ptrdiff_t old_top, + int ef, unsigned int flagmask) { + int status; + ptrdiff_t stop_ci = saveci(L, L->ci); + unsigned int old_nCcalls = L->nCcalls; + luaD_catch(L, ef); + for (;;) { + L->nCcalls = old_nCcalls & flagmask; + status = luaD_rawrunprotected(L, func, ud); + if (status == 0) + break; + if (unwind_frames(L, restoreci(L, stop_ci), old_top, status)) + break; + func = f_continue; + ud = (void *)stop_ci; + } + lua_assert(L->ci == restoreci(L, stop_ci)); + L->ci->errfunc = 0; + L->nCcalls = old_nCcalls; + return status; +} + + /* }====================================================== */ @@ -180,10 +272,11 @@ void luaD_callhook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; - if (hook && L->allowhook) { + if (hook && !nohooks(L)) { ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, L->ci->top); lua_Debug ar; + unsigned short old_nCcalls; ar.event = event; ar.currentline = line; if (event == LUA_HOOKTAILRET) @@ -193,14 +286,22 @@ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ L->ci->top = L->top + LUA_MINSTACK; lua_assert(L->ci->top <= L->stack_last); - L->allowhook = 0; /* cannot call hooks inside a hook */ + old_nCcalls = L->nCcalls; + L->nCcalls = old_nCcalls | (event>= LUA_HOOKLINE ? + (LUA_NOVPCALL | LUA_NOHOOKS) : /* line+count hook can yield */ + (LUA_NOVPCALL | LUA_NOHOOKS | LUA_NOYIELD)); lua_unlock(L); (*hook)(L, &ar); lua_lock(L); - lua_assert(!L->allowhook); - L->allowhook = 1; + lua_assert(nohooks(L)); + L->nCcalls = old_nCcalls; /* restore call flags */ L->ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); + if (L->status == LUA_YIELD) { /* handle hook yield here, after restore */ + L->base = L->top; /* protect Lua frame, undo this in f_coresume */ + SAVEPC(L, GETPC(L) - 1); /* correct pc */ + luaD_throw(L, LUA_YIELD); + } } } @@ -262,17 +363,17 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { - LClosure *cl; + Closure *cl; ptrdiff_t funcr; if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ funcr = savestack(L, func); - cl = &clvalue(func)->l; - L->ci->savedpc = L->savedpc; - if (!cl->isC) { /* Lua function? prepare its call */ + cl = clvalue(func); + L->ci->ctx = L->ctx; + if (!cl->l.isC) { /* Lua function? prepare its call */ CallInfo *ci; StkId st, base; - Proto *p = cl->p; + Proto *p = cl->l.p; luaD_checkstack(L, p->maxstacksize); func = restorestack(L, funcr); if (!p->is_vararg) { /* no varargs? */ @@ -290,16 +391,18 @@ L->base = ci->base = base; ci->top = L->base + p->maxstacksize; lua_assert(ci->top <= L->stack_last); - L->savedpc = p->code; /* starting point */ + SAVEPC(L, p->code); /* starting point */ ci->tailcalls = 0; - ci->nresults = nresults; + ci->nresults = cast(short, nresults); + ci->errfunc = 0; for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; if (L->hookmask & LUA_MASKCALL) { - L->savedpc++; /* hooks assume 'pc' is already incremented */ + const Instruction* pc = GETPC(L); + SAVEPC(L, pc+1); /* hooks assume 'pc' is already incremented */ luaD_callhook(L, LUA_HOOKCALL, -1); - L->savedpc--; /* correct 'pc' */ + SAVEPC(L, pc); /* correct 'pc' */ } return PCRLUA; } @@ -312,11 +415,13 @@ L->base = ci->base = ci->func + 1; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); - ci->nresults = nresults; + L->ctx = NULL; /* initial vcontext */ + ci->nresults = cast(short, nresults); + ci->errfunc = 0; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); - n = (*curr_func(L)->c.f)(L); /* do the actual call */ + n = (*cl->c.f)(L); /* do the actual call */ lua_lock(L); if (n < 0) /* yielding? */ return PCRYIELD; @@ -349,7 +454,7 @@ res = ci->func; /* res == final position of 1st result */ wanted = ci->nresults; L->base = (ci - 1)->base; /* restore base */ - L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ + L->ctx = (ci - 1)->ctx; /* restore ctx */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); @@ -366,41 +471,51 @@ ** When returns, all the results are on the stack, starting at the original ** function position. */ -void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls>= LUAI_MAXCCALLS) { - if (L->nCcalls == LUAI_MAXCCALLS) +void luaD_call (lua_State *L, StkId func, int nresults, int callflags) { + unsigned short old_nCcalls = L->nCcalls; + int pcr; + L->nCcalls = (old_nCcalls + 8) | callflags; + if (L->nCcalls>= LUAI_MAXCCALLS*8) { + if (L->nCcalls < (LUAI_MAXCCALLS+1)*8) luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls>= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + else if (L->nCcalls>= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))*8) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } - if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ - luaV_execute(L, 1); /* call it */ - L->nCcalls--; + pcr = luaD_precall(L, func, nresults); + if ((pcr == PCRLUA && luaV_execute(L)) || pcr == PCRYIELD) + luaD_throw(L, LUA_YIELD); /* need to break C call boundary */ luaC_checkGC(L); + L->nCcalls = old_nCcalls; } -static void resume (lua_State *L, void *ud) { - StkId firstArg = cast(StkId, ud); - CallInfo *ci = L->ci; - if (L->status != LUA_YIELD) { /* start coroutine */ - lua_assert(ci == L->base_ci && firstArg> L->base); - if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) - return; - } - else { /* resuming from previous yield */ - if (!f_isLua(ci)) { /* `common' yield? */ - /* finish interrupted execution of `OP_CALL' */ - lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || - GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); - if (luaD_poscall(L, firstArg)) /* complete it... */ - L->top = L->ci->top; /* and correct top if not multiple results */ +static int f_coresume (lua_State *L, void *ud) { + StkId base = cast(StkId, ud); + if (L->ctx == NULL) /* tail yield from C */ + luaD_poscall(L, base); /* finish C call */ + else if (f_isLua(L->ci)) { /* yield from Lua hook */ + L->base = L->ci->base; /* restore invariant */ + if (luaV_execute(L)) return LUA_YIELD; + } + else { /* resumable yield from C */ + StkId rbase = L->base; + if (rbase < base) { + while (base < L->top) + setobjs2s(L, rbase++, base++); /* move results down */ + L->top = rbase; } - else /* yielded inside a hook: just continue its execution */ - L->base = L->ci->base; + L->base = L->ci->base; /* restore invariant */ } - L->status = 0; - luaV_execute(L, cast_int(L->ci - L->base_ci)); + return f_continue(L, (void *)(ptrdiff_t)0); /* resume remaining frames */ +} + + +static int f_costart (lua_State *L, void *ud) { + int pcr = luaD_precall(L, cast(StkId, ud), LUA_MULTRET); + if ((pcr == PCRLUA && luaV_execute(L)) || pcr == PCRYIELD) + return LUA_YIELD; + else + return 0; } @@ -414,67 +529,61 @@ LUA_API int lua_resume (lua_State *L, int nargs) { + Pfunc pf; + void *ud; int status; lua_lock(L); - if (L->status != LUA_YIELD) { - if (L->status != 0) - return resume_error(L, "cannot resume dead coroutine"); - else if (L->ci != L->base_ci) + switch (L->status) { + case LUA_YIELD: + pf = f_coresume; + ud = L->top - nargs; + L->status = 0; + break; + case 0: + if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); + pf = f_costart; + ud = L->top - (nargs + 1); + break; + default: + return resume_error(L, "cannot resume dead coroutine"); + } + lua_assert(cast(StkId, ud)>= L->base); + for (;;) { + L->nCcalls = 0; + status = luaD_rawrunprotected(L, pf, ud); + if (status <= LUA_YIELD) + break; + if (unwind_frames(L, L->base_ci, 0, status)) { /* fallthrough? */ + /* keep frames for traceback, but mark coroutine as `dead' */ + luaD_seterrorobj(L, status, L->top); + break; + } + pf = f_continue; + ud = (void *)(ptrdiff_t)0; /* (void *)saveci(L, L->base_ci); */ } - luai_userstateresume(L, nargs); - lua_assert(L->errfunc == 0 && L->nCcalls == 0); - status = luaD_rawrunprotected(L, resume, L->top - nargs); - if (status != 0) { /* error? */ - L->status = cast_byte(status); /* mark thread as `dead' */ - luaD_seterrorobj(L, status, L->top); - L->ci->top = L->top; - } - else - status = L->status; + L->nCcalls = LUA_NOYIELD | LUA_NOVPCALL; + L->status = status; lua_unlock(L); return status; } -LUA_API int lua_yield (lua_State *L, int nresults) { - luai_userstateyield(L, nresults); +LUA_API int lua_vyield (lua_State *L, int nresults, void *ctx) { lua_lock(L); - if (L->nCcalls> 0) - 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 (noyield(L)) + luaG_runerror(L, "attempt to yield across non-resumable call boundary"); + lua_assert(L->ci> L->base_ci); + if (!f_isLua(L->ci)) { /* usual yield */ + L->ctx = ctx; + L->base = L->top - nresults; /* no longer in sync with L->ci->base */ + } + L->status = LUA_YIELD; /* marker for luaD_callhook */ lua_unlock(L); return -1; } -int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t old_top, ptrdiff_t ef) { - int status; - unsigned short oldnCcalls = L->nCcalls; - ptrdiff_t old_ci = saveci(L, L->ci); - lu_byte old_allowhooks = L->allowhook; - ptrdiff_t old_errfunc = L->errfunc; - L->errfunc = ef; - status = luaD_rawrunprotected(L, func, u); - if (status != 0) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close eventual pending closures */ - luaD_seterrorobj(L, status, oldtop); - L->nCcalls = oldnCcalls; - L->ci = restoreci(L, old_ci); - L->base = L->ci->base; - L->savedpc = L->ci->savedpc; - L->allowhook = old_allowhooks; - restore_stack_limit(L); - } - L->errfunc = old_errfunc; - return status; -} - - - /* ** Execute a protected parser. */ @@ -484,12 +593,13 @@ const char *name; }; -static void f_parser (lua_State *L, void *ud) { +static int f_parser (lua_State *L, void *ud) { int i; Proto *tf; Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = luaZ_lookahead(p->z); + L->nCcalls |= (LUA_NOYIELD | LUA_NOVPCALL); /* parser is not resumable */ luaC_checkGC(L); tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, &p->buff, p->name); @@ -499,6 +609,7 @@ cl->l.upvals[i] = luaF_newupval(L); setclvalue(L, L->top, cl); incr_top(L); + return 0; } @@ -507,7 +618,8 @@ int status; p.z = z; p.name = name; luaZ_initbuffer(L, &p.buff); - status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); + status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), + -1, ~0); /* -1 = inherit errfunc */ luaZ_freebuffer(L, &p.buff); return status; } diff -ruN oldsrc/ldo.h newsrc/ldo.h --- oldsrc/ldo.h 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/ldo.h 2006年04月15日 23:44:03.000000000 -0500 @@ -31,18 +31,30 @@ /* 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 */ +#define PCRYIELD 2 /* C function yielded */ +/* call flags for luaD_call, stored in least significant bits of nCcalls */ +#define LUA_NOHOOKS 1 +#define LUA_NOVPCALL 2 +#define LUA_NOYIELD 4 + +#define nohooks(L) (L->nCcalls & LUA_NOHOOKS) +#define novpcall(L) (L->nCcalls & LUA_NOVPCALL) +#define noyield(L) (L->nCcalls & LUA_NOYIELD) + +#define notresumable(L, stmt) \ + { unsigned short save_ncc = L->nCcalls; \ + L->nCcalls = save_ncc | (LUA_NOYIELD | LUA_NOVPCALL); \ + stmt \ + L->nCcalls = save_ncc; } -/* type of protected functions, to be ran by `runprotected' */ -typedef void (*Pfunc) (lua_State *L, void *ud); +/* type of protected functions, to be run by `runprotected' */ +typedef int (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name); LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); -LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); -LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, - ptrdiff_t oldtop, ptrdiff_t ef); +LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nresults, int callflags); LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult); LUAI_FUNC void luaD_reallocCI (lua_State *L, int newsize); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); @@ -50,6 +62,13 @@ LUAI_FUNC void luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); +LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *ud, + ptrdiff_t old_top, int ef, unsigned int flagmask); + +#define luaD_catch(L, ef) \ + { lua_assert((ef) + 1>= 0 && (ef) + 1 <= 255); \ + L->ci->hookmask = L->hookmask; \ + L->ci->errfunc = (ef) + 1; } LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); diff -ruN oldsrc/lgc.c newsrc/lgc.c --- oldsrc/lgc.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lgc.c 2006年04月15日 23:44:03.000000000 -0500 @@ -455,15 +455,12 @@ makewhite(g, o); tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { - lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; - L->allowhook = 0; /* stop debug hooks during GC tag method */ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; - luaD_call(L, L->top - 2, 0); - L->allowhook = oldah; /* restore hooks */ + luaD_call(L, L->top - 2, 0, LUA_NOYIELD | LUA_NOVPCALL | LUA_NOHOOKS); g->GCthreshold = oldt; /* restore threshold */ } } diff -ruN oldsrc/lstate.c newsrc/lstate.c --- oldsrc/lstate.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lstate.c 2006年04月15日 23:44:03.000000000 -0500 @@ -55,6 +55,7 @@ setnilvalue(L1->top++); /* `function' entry for this `ci' */ L1->base = L1->ci->base = L1->top; L1->ci->top = L1->top + LUA_MINSTACK; + L1->ci->errfunc = 0; } @@ -67,7 +68,7 @@ /* ** open parts that may cause memory-allocation errors */ -static void f_luaopen (lua_State *L, void *ud) { +static int f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ @@ -78,6 +79,7 @@ luaX_init(L); luaS_fix(luaS_newliteral(L, MEMERRMSG)); g->GCthreshold = 4*g->totalbytes; + return 0; } @@ -89,15 +91,13 @@ L->hook = NULL; L->hookmask = 0; L->basehookcount = 0; - L->allowhook = 1; resethookcount(L); L->openupval = NULL; L->size_ci = 0; - L->nCcalls = 0; + L->nCcalls = LUA_NOYIELD | LUA_NOVPCALL; L->status = 0; L->base_ci = L->ci = NULL; - L->savedpc = NULL; - L->errfunc = 0; + L->ctx = NULL; setnilvalue(gt(L)); } @@ -190,9 +190,10 @@ } -static void callallgcTM (lua_State *L, void *ud) { +static int callallgcTM (lua_State *L, void *ud) { UNUSED(ud); luaC_callGCTM(L); /* call GC metamethods for all udata */ + return 0; } @@ -202,9 +203,9 @@ lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ - L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; + L->ci->errfunc = 0; /* no error function during GC metamethods */ L->base = L->top = L->ci->base; L->nCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); diff -ruN oldsrc/lstate.h newsrc/lstate.h --- oldsrc/lstate.h 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lstate.h 2006年04月15日 23:44:03.000000000 -0500 @@ -48,10 +48,12 @@ typedef struct CallInfo { StkId base; /* base for this function */ StkId func; /* function index in the stack */ - StkId top; /* top for this function */ - const Instruction *savedpc; - int nresults; /* expected number of results from this function */ + StkId top; /* top for this function */ + void *ctx; /* saved pc for Lua functions or vcontext for C functions */ int tailcalls; /* number of tail calls lost under this entry */ + short nresults; /* expected number of results from this function */ + lu_byte hookmask; /* restore on catch: hookmask */ + lu_byte errfunc; /* 0: no catch, 1: catch,>=2: catch with errfunc */ } CallInfo; @@ -100,21 +102,19 @@ struct lua_State { CommonHeader; lu_byte status; + lu_byte hookmask; + int stacksize; StkId top; /* first free slot in the stack */ StkId base; /* base of current function */ global_State *l_G; CallInfo *ci; /* call info for current function */ - const Instruction *savedpc; /* `savedpc' of current function */ + void *ctx; /* ctx for current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ - int stacksize; int size_ci; /* size of array `base_ci' */ - unsigned short nCcalls; /* number of nested C calls */ - lu_byte hookmask; - lu_byte allowhook; - int basehookcount; + unsigned short nCcalls; /* number of nested C calls + callflags */ int hookcount; lua_Hook hook; TValue l_gt; /* table of globals */ @@ -122,7 +122,7 @@ GCObject *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_longjmp *errorJmp; /* current error recover point */ - ptrdiff_t errfunc; /* current error handling function (stack index) */ + int basehookcount; }; diff -ruN oldsrc/ltablib.c newsrc/ltablib.c --- oldsrc/ltablib.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/ltablib.c 2006年04月15日 23:44:03.000000000 -0500 @@ -20,14 +20,22 @@ static int foreachi (lua_State *L) { - int i; - int n = aux_getn(L, 1); + int n; + int i = lua_icontext(L); + if (i) { + n = lua_tointeger(L, 3); /* get cached n */ + goto resume; + } + n = aux_getn(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); + lua_settop(L, 2); + lua_pushinteger(L, n); /* cache n because aux_getn may be expensive */ for (i=1; i <= n; i++) { lua_pushvalue(L, 2); /* function */ lua_pushinteger(L, i); /* 1st argument */ lua_rawgeti(L, 1, i); /* 2nd argument */ - lua_call(L, 2, 1); + lua_icall(L, 2, 1, i); +resume: if (!lua_isnil(L, -1)) return 1; lua_pop(L, 1); /* remove nil result */ @@ -37,6 +45,7 @@ static int foreach (lua_State *L) { + if (lua_vcontext(L)) goto resume; luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TFUNCTION); lua_pushnil(L); /* first key */ @@ -44,7 +53,8 @@ lua_pushvalue(L, 2); /* function */ lua_pushvalue(L, -3); /* key */ lua_pushvalue(L, -3); /* value */ - lua_call(L, 2, 1); + lua_icall(L, 2, 1, 1); +resume: if (!lua_isnil(L, -1)) return 1; lua_pop(L, 2); /* remove value and result */ diff -ruN oldsrc/luaconf.h newsrc/luaconf.h --- oldsrc/luaconf.h 2006-04-15 23:40:17.000000000 -0500 +++ newsrc/luaconf.h 2006-04-15 23:44:03.000000000 -0500 @@ -580,7 +580,7 @@ /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) try { a } catch(...) \ - { if ((c)->status == 0) (c)->status = -1; } + { if ((c)->status == 0) (c)->status = LUA_ERREXC; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_ULONGJMP) diff -ruN oldsrc/lua.h newsrc/lua.h --- oldsrc/lua.h 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lua.h 2006年04月15日 23:44:03.000000000 -0500 @@ -16,7 +16,7 @@ #include "luaconf.h" -#define LUA_VERSION "Lua 5.1" +#define LUA_VERSION "Lua 5.1+rvm" #define LUA_VERSION_NUM 501 #define LUA_COPYRIGHT "Copyright (C) 1994-2006 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" @@ -44,6 +44,7 @@ #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 #define LUA_ERRERR 5 +#define LUA_ERREXC 6 typedef struct lua_State lua_State; @@ -197,22 +198,37 @@ /* ** `load' and `call' functions (load and run Lua code) */ -LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); -LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API void (lua_vcall) (lua_State *L, int nargs, int nresults, void *ctx); +LUA_API int (lua_vpcall) (lua_State *L, int nargs, int nresults, + int errfunc, void *ctx); LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname); LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); +LUA_API void *lua_vcontext (lua_State *L); + +#define lua_icontext(L) ((int)(ptrdiff_t)lua_vcontext(L)) +#define lua_call(L, na, nr) lua_vcall(L, (na), (nr), NULL) +#define lua_icall(L, na, nr, i) \ + lua_vcall(L, (na), (nr), (void *)(ptrdiff_t)(i)) +#define lua_pcall(L, na, nr, ef) lua_vpcall(L, (na), (nr), (ef), NULL) +#define lua_ipcall(L, na, nr, ef, i) \ + lua_vpcall(L, (na), (nr), (ef), (void *)(ptrdiff_t)(i)) + /* ** coroutine functions */ -LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_vyield) (lua_State *L, int nresults, void *ctx); LUA_API int (lua_resume) (lua_State *L, int narg); LUA_API int (lua_status) (lua_State *L); +#define lua_yield(L, nr) lua_vyield(L, (nr), NULL) +#define lua_iyield(L, nr, i) lua_vyield(L, (nr), (void *)(ptrdiff_t)(i)) + + /* ** garbage-collection function and options */ diff -ruN oldsrc/lvm.c newsrc/lvm.c --- oldsrc/lvm.c 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lvm.c 2006年04月15日 23:44:03.000000000 -0500 @@ -57,10 +57,10 @@ } -static void traceexec (lua_State *L, const Instruction *pc) { +static StkId traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; - const Instruction *oldpc = L->savedpc; - L->savedpc = pc; + const Instruction *oldpc = GETPC(L); + SAVEPC(L, pc); if (mask> LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); @@ -76,6 +76,7 @@ if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); } + return L->base; } @@ -87,7 +88,7 @@ setobj2s(L, L->top+2, p2); /* 2nd argument */ luaD_checkstack(L, 3); L->top += 3; - luaD_call(L, L->top - 3, 1); + luaD_call(L, L->top - 3, 1, 0); res = restorestack(L, result); L->top--; setobjs2s(L, res, L->top); @@ -103,7 +104,7 @@ setobj2s(L, L->top+3, p3); /* 3th argument */ luaD_checkstack(L, 4); L->top += 4; - luaD_call(L, L->top - 4, 0); + luaD_call(L, L->top - 4, 0, 0); } @@ -282,8 +283,11 @@ StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!tostring(L, top-2) || !tostring(L, top-1)) { + setpvalue(L->top, (void *)(ptrdiff_t)(last - 1)); /* for luaV_resume */ + L->top++; if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); + L->top--; } else if (tsvalue(top-1)->len> 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; @@ -354,7 +358,7 @@ #define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} -#define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } +#define Protect(x) { SAVEPC(L, pc); {x;}; base = L->base; } #define arith_op(op,tm) { \ @@ -370,13 +374,14 @@ -void luaV_execute (lua_State *L, int nexeccalls) { +int luaV_execute (lua_State *L) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; + int nexeccalls = 1; reentry: /* entry point */ - pc = L->savedpc; + pc = GETPC(L); cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; @@ -385,14 +390,8 @@ const Instruction i = *pc++; StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && - (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L, pc); - if (L->status == LUA_YIELD) { /* did hook yield? */ - L->savedpc = pc - 1; - return; - } - base = L->base; - } + (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) + base = traceexec(L, pc); /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == L->base && L->base == L->ci->base); @@ -582,7 +581,7 @@ int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->savedpc = pc; + SAVEPC(L, pc); switch (luaD_precall(L, ra, nresults)) { case PCRLUA: { nexeccalls++; @@ -595,14 +594,14 @@ continue; } default: { - return; /* yield */ + return LUA_YIELD; } } } case OP_TAILCALL: { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ - L->savedpc = pc; + SAVEPC(L, pc); lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); switch (luaD_precall(L, ra, LUA_MULTRET)) { case PCRLUA: { @@ -617,7 +616,7 @@ 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->ctx = L->ctx; ci->tailcalls++; /* one more call lost */ L->ci--; /* remove new frame */ goto reentry; @@ -627,7 +626,7 @@ continue; } default: { - return; /* yield */ + return LUA_YIELD; } } } @@ -635,14 +634,13 @@ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); - L->savedpc = pc; + SAVEPC(L, pc); b = luaD_poscall(L, ra); if (--nexeccalls == 0) /* was previous function running `here'? */ - return; /* no: return */ + return 0; /* no: return */ else { /* yes: continue its execution */ if (b) L->top = L->ci->top; - lua_assert(isLua(L->ci)); - lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); + lua_assert(isLua(L->ci) && GET_OPCODE(*(GETPC(L)-1)) == OP_CALL); goto reentry; } } @@ -662,7 +660,7 @@ const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; - L->savedpc = pc; /* next steps may throw errors */ + SAVEPC(L, pc); /* next steps may throw errors */ if (!tonumber(init, ra)) luaG_runerror(L, LUA_QL("for") " initial value must be a number"); else if (!tonumber(plimit, ra+1)) @@ -679,7 +677,7 @@ setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb+3; /* func. + 2 args (state and index) */ - Protect(luaD_call(L, cb, GETARG_C(i))); + Protect(luaD_call(L, cb, GETARG_C(i), 0)); L->top = L->ci->top; cb = RA(i) + 3; /* previous call may change the stack */ if (!ttisnil(cb)) { /* continue loop? */ @@ -760,3 +758,56 @@ } } + +void luaV_resume (lua_State *L) { + const Instruction *pc = GETPC(L); + const Instruction i = *(pc - 1); + switch (GET_OPCODE(i)) { /* finish opcodes */ + case OP_CALL: + if (i & MASK1(SIZE_C,POS_C)) L->top = L->ci->top; + break; + case OP_SETGLOBAL: case OP_SETTABLE: case OP_TAILCALL: + break; /* ok, but nothing to do */ + case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: case OP_ADD: case OP_SUB: + case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: + L->top--; + setobjs2s(L, L->base + GETARG_A(i), L->top); + break; + case OP_LT: case OP_LE: case OP_EQ: + L->top--; + if (!l_isfalse(L->top) != GETARG_A(i)) pc++; + else dojump(L, pc, GETARG_sBx(*pc) + 1); + SAVEPC(L, pc); + break; + case OP_TFORLOOP: { + StkId cb; /* call base */ + L->top = L->ci->top; + cb = L->base + GETARG_A(i) + 3; + if (ttisnil(cb)) /* break loop? */ + pc++; /* skip jump (break loop) */ + else { + setobjs2s(L, cb-1, cb); /* save control variable */ + dojump(L, pc, GETARG_sBx(*pc) + 1); /* jump back */ + } + SAVEPC(L, pc); + break; + } + case OP_CONCAT: { + int b = GETARG_B(i); + int c; + L->top -= 2; + c = (int)(ptrdiff_t)pvalue(L->top); + setobjs2s(L, L->base + c, L->top + 1); + if (c> b) luaV_concat(L, c-b+1, c); + luaC_checkGC(L); /***/ + setobjs2s(L, L->base + GETARG_A(i), L->base + b); + break; + } + default: + luaG_runerror(L, "return to non-resumable opcode %d", GET_OPCODE(i)); + break; + } + lua_assert(L->top == L->ci->top || + GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL); +} + diff -ruN oldsrc/lvm.h newsrc/lvm.h --- oldsrc/lvm.h 2006年04月15日 23:40:17.000000000 -0500 +++ newsrc/lvm.h 2006年04月15日 23:44:03.000000000 -0500 @@ -21,6 +21,9 @@ #define equalobj(L,o1,o2) \ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) +#define GETPC(L) (cast(const Instruction *, L->ctx)) +#define SAVEPC(L, pc) L->ctx = cast(void *, (pc)) + LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); @@ -30,7 +33,8 @@ StkId val); LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); -LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); +LUAI_FUNC int luaV_execute (lua_State *L); +LUAI_FUNC void luaV_resume (lua_State *L); LUAI_FUNC void luaV_concat (lua_State *L, int total, int last); #endif