diff --git a/lauxlib.c b/lauxlib.c index d66250b3..01bcf9a1 100644 --- a/lauxlib.c +++ b/lauxlib.c @@ -1,5 +1,5 @@ /* -** $Id: lauxlib.c,v 1.77 2002/06/26 19:28:44 roberto Exp roberto $ +** $Id: lauxlib.c,v 1.78 2002/07/01 19:23:58 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ @@ -394,21 +394,20 @@ LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size, static void callalert (lua_State *L, int status) { if (status != 0) { - int top; - if (status == LUA_ERRRUN) - lua_concat(L, 2); /* concat error message and traceback */ - top = lua_gettop(L); lua_getglobal(L, "_ALERT"); lua_insert(L, -2); - lua_pcall(L, 1, 0); - lua_settop(L, top-1); + lua_call(L, 1, 0); + lua_pop(L, 1); } } static int aux_do (lua_State *L, int status) { - if (status == 0) /* parse OK? */ + if (status == 0) { /* parse OK? */ status = lua_pcall(L, 0, LUA_MULTRET); /* call main */ + if (status != 0) + lua_pcallreset(L); + } callalert(L, status); return status; } diff --git a/ldblib.c b/ldblib.c index 13e328d3..c86a12b4 100644 --- a/ldblib.c +++ b/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.63 2002/07/08 20:22:08 roberto Exp roberto $ +** $Id: ldblib.c,v 1.64 2002/07/17 16:25:13 roberto Exp roberto $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -194,15 +194,11 @@ static int debug (lua_State *L) { static int errorfb (lua_State *L) { int level = 1; /* skip level 0 (it's this function) */ int firstpart = 1; /* still before eventual `...' */ - int alllevels = 1; - const char *msg = lua_tostring(L, 1); lua_Debug ar; - lua_settop(L, 0); - if (msg) { - alllevels = 0; - if (!strstr(msg, "stack traceback:\n")) - lua_pushliteral(L, "stack traceback:\n"); - } + if (lua_gettop(L) == 0) + lua_pushliteral(L, ""); + else if (!lua_isstring(L, 1)) return 1; /* no string message */ + lua_pushliteral(L, "stack traceback:\n"); while (lua_getstack(L, level++, &ar)) { if (level > LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ @@ -217,7 +213,7 @@ static int errorfb (lua_State *L) { continue; } lua_pushliteral(L, "\t"); - lua_getinfo(L, "Snlc", &ar); + lua_getinfo(L, "Snl", &ar); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); @@ -240,7 +236,6 @@ static int errorfb (lua_State *L) { } lua_pushliteral(L, "\n"); lua_concat(L, lua_gettop(L)); - if (!alllevels && ar.isprotected) break; } lua_concat(L, lua_gettop(L)); return 1; @@ -261,9 +256,9 @@ static const luaL_reg dblib[] = { LUALIB_API int lua_dblibopen (lua_State *L) { luaL_opennamedlib(L, LUA_DBLIBNAME, dblib, 0); - lua_pushliteral(L, LUA_TRACEBACK); + lua_pushliteral(L, "_TRACEBACK"); lua_pushcfunction(L, errorfb); - lua_settable(L, LUA_REGISTRYINDEX); + lua_settable(L, LUA_GLOBALSINDEX); return 0; } diff --git a/ldo.c b/ldo.c index 55f7958f..e6307b0c 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.187 2002/07/09 18:19:19 roberto Exp roberto $ +** $Id: ldo.c,v 1.188 2002/07/16 14:26:56 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -29,40 +29,113 @@ +/* +** {====================================================== +** Error-recovery functions (based on long jumps) +** ======================================================= +*/ + + /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; - CallInfo *ci; /* index of call info of active function that set protection */ - StkId top; /* top stack when protection was set */ jmp_buf b; - int allowhooks; /* `allowhook' state when protection was set */ volatile int status; /* error code */ - TObject *err; /* error messages (start of `ud') */ }; -static void pusherrormsg (lua_State *L, int status, TObject *err) { - setobj(L->top++, &err[0]); - if (status == LUA_ERRRUN) - setobj(L->top++, &err[1]); +static void seterrorobj (lua_State *L, int errcode) { + switch (errcode) { + case LUA_ERRMEM: { + setsvalue(L->top, luaS_new(L, MEMERRMSG)); + break; + } + case LUA_ERRERR: { + setsvalue(L->top, luaS_new(L, "error in error handling")); + break; + } + case LUA_ERRSYNTAX: + case LUA_ERRRUN: { + return; /* error message already on top */ + } + } + L->top++; +} + + +void luaD_throw (lua_State *L, int errcode) { + if (errcode == LUA_ERRRUN) + luaD_checkstack(L, LUA_MINSTACK); /* ensure stack space to handle error */ + luaG_saveallpcs(L); /* C stack will disapear */ + if (L->errorJmp) { + L->errorJmp->status = errcode; + longjmp(L->errorJmp->b, 1); + } + else { + G(L)->panic(L); + exit(EXIT_FAILURE); + } +} + + +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { + struct lua_longjmp lj; + lj.status = 0; + lj.previous = L->errorJmp; /* chain new error handler */ + L->errorJmp = &lj; + if (setjmp(lj.b) == 0) + (*f)(L, ud); + L->errorJmp = lj.previous; /* restore old error handler */ + return lj.status; +} + + +static void restore_stack_limit (lua_State *L) { + L->stack_last = L->stack+L->stacksize-1; + if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ + int inuse = (L->ci - L->base_ci); + if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUA_MAXCALLS); + } } +void luaD_resetprotection (lua_State *L) { + Protection *p; + StkId err = L->top - 1; /* error msg. position (if there is one) */ + lua_assert(L->number_toreset > 0); + p = &L->toreset[--L->number_toreset]; + L->ci = restoreci(L, p->ci); + L->top = restorestack(L, p->top); + L->ci->top = L->top + LUA_MINSTACK; + setallowhook(L, p->allowhooks); + restore_stack_limit(L); + setobj(L->top++, err); /* copy error message to corrected top */ +} + + +/* +** invalidate all pc pointers from stack part that becomes inactive +*/ +static void deactivateinfo (lua_State *L, CallInfo *p_ci) { + CallInfo *ci; + for (ci = L->ci; ci > p_ci; ci--) + ci->pc = NULL; +} + +/* }====================================================== */ + + static void correctstack (lua_State *L, TObject *oldstack) { - struct lua_longjmp *lj; CallInfo *ci; UpVal *up; L->top = (L->top - oldstack) + L->stack; - for (lj = L->errorJmp; lj != NULL; lj = lj->previous) - lj->top = (lj->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->next) up->v = (up->v - oldstack) + L->stack; for (ci = L->base_ci; ci <= L->ci; ci++) { ci->base = (ci->base - oldstack) + L->stack; ci->top = (ci->top - oldstack) + L->stack; - if (isLua(ci) && /* is a Lua function... */ - !(isLua(ci-1) && /* and next is not a Lua function... */ - ci->u.l.pc == (ci-1)->u.l.pc)) /* sharing the same C frame? */ + if (ci->pc && ci->pc != &luaV_callingmark) /* function has a frame? */ *ci->u.l.pb = (*ci->u.l.pb - oldstack) + L->stack; /* correct frame */ } } @@ -72,35 +145,17 @@ void luaD_reallocstack (lua_State *L, int newsize) { TObject *oldstack = L->stack; luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject); L->stacksize = newsize; - L->stack_last = L->stack+(newsize-EXTRA_STACK)-1; + L->stack_last = L->stack+newsize-1-EXTRA_STACK; correctstack(L, oldstack); } -static void correctCI (lua_State *L, CallInfo *oldci) { - struct lua_longjmp *lj; - for (lj = L->errorJmp; lj != NULL; lj = lj->previous) { - lj->ci = (lj->ci - oldci) + L->base_ci; - } -} - - void luaD_reallocCI (lua_State *L, int newsize) { CallInfo *oldci = L->base_ci; luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); L->size_ci = newsize; L->ci = (L->ci - oldci) + L->base_ci; L->end_ci = L->base_ci + L->size_ci; - correctCI(L, oldci); -} - - -static void restore_stack_limit (lua_State *L) { - if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */ - int inuse = (L->ci - L->base_ci); - if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUA_MAXCALLS); - } } @@ -175,7 +230,7 @@ static StkId tryfuncTM (lua_State *L, StkId func) { const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; ptrdiff_t funcr = savestack(L, func); - if (ttype(tm) != LUA_TFUNCTION) + if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at `func' */ for (p = L->top; p > func; p--) setobj(p, p-1); @@ -189,7 +244,7 @@ static StkId tryfuncTM (lua_State *L, StkId func) { StkId luaD_precall (lua_State *L, StkId func) { LClosure *cl; ptrdiff_t funcr = savestack(L, func); - if (ttype(func) != LUA_TFUNCTION) /* `func' is not a function? */ + if (!ttisfunction(func)) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ if (L->ci + 1 == L->end_ci) luaD_growCI(L); cl = &clvalue(func)->l; @@ -202,7 +257,7 @@ StkId luaD_precall (lua_State *L, StkId func) { ci = ++L->ci; /* now `enter' new function */ ci->base = restorestack(L, funcr) + 1; ci->top = ci->base + p->maxstacksize; - ci->savedpc = p->code; /* starting point */ + ci->u.l.savedpc = p->code; /* starting point */ while (L->top < ci->top) setnilvalue(L->top++); L->top = ci->top; @@ -215,7 +270,7 @@ StkId luaD_precall (lua_State *L, StkId func) { ci = ++L->ci; /* now `enter' new function */ ci->base = restorestack(L, funcr) + 1; ci->top = L->top + LUA_MINSTACK; - ci->savedpc = NULL; /* not a Lua function */ + ci->pc = NULL; /* not a Lua function */ if (L->hookmask & LUA_MASKCALL) { luaD_callhook(L, LUA_HOOKCALL, -1); ci = L->ci; /* previous call may realocate `ci' */ @@ -274,6 +329,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { LUA_API void lua_cobegin (lua_State *L, int nargs) { lua_lock(L); luaD_precall(L, L->top - (nargs+1)); + L->ci->pc = &luaV_callingmark; /* function is not active (yet) */ lua_unlock(L); } @@ -287,28 +343,24 @@ static void move_results (lua_State *L, TObject *from, TObject *to) { } -struct ResS { - TObject err[2]; - int numres; -}; - static void resume (lua_State *L, void *ud) { StkId firstResult; CallInfo *ci = L->ci; - if (!isLua(ci)) { /* not first time? */ + if (ci->pc == NULL) { /* not first time? */ /* finish interrupted execution of `OP_CALL' */ int nresults; - lua_assert(isLua(ci - 1)); - lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL); - nresults = GETARG_C(*((ci-1)->savedpc - 1)) - 1; + lua_assert((ci - 1)->pc == &luaV_callingmark); + 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); /* complete it */ if (nresults >= 0) L->top = L->ci->top; } firstResult = luaV_execute(L); if (firstResult == NULL) /* yield? */ - cast(struct ResS *, ud)->numres = L->ci->u.c.yield_results; + *cast(int *, ud) = L->ci->u.c.yield_results; else { /* return */ - cast(struct ResS *, ud)->numres = L->top - firstResult; + *cast(int *, ud) = L->top - firstResult; luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ } } @@ -316,7 +368,7 @@ static void resume (lua_State *L, void *ud) { LUA_API int lua_resume (lua_State *L, lua_State *co) { CallInfo *ci; - struct ResS ud; + int numres; int status; lua_lock(L); ci = co->ci; @@ -324,11 +376,13 @@ LUA_API int lua_resume (lua_State *L, lua_State *co) { luaG_runerror(L, "cannot resume dead thread"); if (co->errorJmp != NULL) /* ?? */ luaG_runerror(L, "cannot resume active thread"); - status = luaD_runprotected(co, resume, ud.err); + status = luaD_rawrunprotected(co, resume, &numres); if (status == 0) - move_results(L, co->top - ud.numres, co->top); - else - pusherrormsg(L, status, ud.err); + move_results(L, co->top - numres, co->top); + else { + setobj(L->top++, co->top - 1); /* move error message to other stack */ + co->ci = co->base_ci; /* `kill' thread */ + } lua_unlock(L); return status; } @@ -338,9 +392,9 @@ LUA_API int lua_yield (lua_State *L, int nresults) { CallInfo *ci; lua_lock(L); ci = L->ci; - if (!isLua(ci-1)) + if ((ci-1)->pc == NULL) luaG_runerror(L, "cannot yield a C function"); - lua_assert(!isLua(ci)); + lua_assert(ci->pc == NULL); /* current function is not Lua */ ci->u.c.yield_results = nresults; lua_unlock(L); return -1; @@ -351,7 +405,6 @@ LUA_API int lua_yield (lua_State *L, int nresults) { ** Execute a protected call. */ struct CallS { /* data to `f_call' */ - TObject err[2]; StkId func; int nresults; }; @@ -359,6 +412,8 @@ struct CallS { /* data to `f_call' */ static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); + luaM_growvector(L, L->toreset, L->number_toreset, L->size_toreset, + Protection, MAX_INT, ""); luaD_call(L, c->func, c->nresults); } @@ -366,13 +421,24 @@ static void f_call (lua_State *L, void *ud) { int luaD_pcall (lua_State *L, int nargs, int nresults) { struct CallS c; int status; + int protectionlevel = L->number_toreset; + Protection protection; + protection.top = savestack(L, L->top); + protection.ci = saveci(L, L->ci); + protection.allowhooks = allowhook(L); c.func = L->top - (nargs+1); /* function to be called */ c.nresults = nresults; - status = luaD_runprotected(L, &f_call, c.err); + status = luaD_rawrunprotected(L, &f_call, &c); if (status != 0) { /* an error occurred? */ - L->top -= nargs+1; /* remove parameters and func from the stack */ - luaF_close(L, L->top); /* close eventual pending closures */ - pusherrormsg(L, status, c.err); + /* remove parameters and func from the stack */ + protection.top = savestack(L, restorestack(L, protection.top) - (nargs+1)); + /* close eventual pending closures */ + luaF_close(L, restorestack(L, protection.top)); + L->ci->top = L->top + LUA_MINSTACK; /* extra space to handle error */ + seterrorobj(L, status); + deactivateinfo(L, restoreci(L, protection.ci)); + L->number_toreset = protectionlevel + 1; + L->toreset[L->number_toreset - 1] = protection; } return status; } @@ -382,7 +448,6 @@ int luaD_pcall (lua_State *L, int nargs, int nresults) { ** Execute a protected parser. */ struct SParser { /* data to `f_parser' */ - TObject err[2]; ZIO *z; int bin; }; @@ -401,95 +466,25 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { struct SParser p; lu_mem old_blocks; int status; + ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */ p.z = z; p.bin = bin; /* before parsing, give a (good) chance to GC */ if (G(L)->nblocks + G(L)->nblocks/4 >= G(L)->GCthreshold) luaC_collectgarbage(L); old_blocks = G(L)->nblocks; - status = luaD_runprotected(L, f_parser, p.err); + status = luaD_rawrunprotected(L, f_parser, &p); if (status == 0) { /* add new memory to threshold (as it probably will stay) */ lua_assert(G(L)->nblocks >= old_blocks); G(L)->GCthreshold += (G(L)->nblocks - old_blocks); } - else - pusherrormsg(L, status, p.err); - return status; -} - - - -/* -** {====================================================== -** Error-recovery functions (based on long jumps) -** ======================================================= -*/ - -static void seterrorobj (lua_State *L, int errcode, TObject *m) { - switch (errcode) { - case LUA_ERRMEM: { - if (G(L) != NULL && G(L)->GCthreshold > 0) /* state is OK? */ - setsvalue(&m[0], luaS_new(L, MEMERRMSG)); - break; - } - case LUA_ERRERR: { - setsvalue(&m[0], luaS_new(L, "error in error handling")); - break; - } - case LUA_ERRSYNTAX: { /* message is on stack top */ - setobj(&m[0], L->top - 1); - break; - } - case LUA_ERRRUN: { /* traceback is on stack top */ - setobj(&m[0], L->top - 2); - setobj(&m[1], L->top - 1); - break; - } - } -} - - -void luaD_throw (lua_State *L, int errcode) { - if (L->errorJmp) { - seterrorobj(L, errcode, L->errorJmp->err); - L->errorJmp->status = errcode; - longjmp(L->errorJmp->b, 1); - } - else { - G(L)->panic(L); - exit(EXIT_FAILURE); - } -} - - -int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) { - struct lua_longjmp lj; - lj.ci = L->ci; - lj.top = L->top; - lj.allowhooks = allowhook(L); - lj.status = 0; - lj.err = ud; - lj.previous = L->errorJmp; /* chain new error handler */ - L->errorJmp = &lj; - if (setjmp(lj.b) == 0) - (*f)(L, ud); - else { /* an error occurred */ - L->ci = lj.ci; /* restore the state */ - L->top = lj.top; - setallowhook(L, lj.allowhooks); - restore_stack_limit(L); + else { /* error */ + StkId oldtop = restorestack(L, oldtopr); + seterrorobj(L, status); + setobj(oldtop, L->top - 1); /* copy error message to old top */ + L->top = oldtop+1; } - L->errorJmp = lj.previous; /* restore old error handler */ - return lj.status; -} - - -int luaD_isprotected (lua_State *L, CallInfo *ci) { - struct lua_longjmp *l; - for (l = L->errorJmp; l; l = l->previous) - if (l->ci+1 == ci) return 1; - return 0; + return status; } -/* }====================================================== */ diff --git a/ldo.h b/ldo.h index c18193d1..fdd889ed 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.47 2002/06/18 17:10:43 roberto Exp roberto $ +** $Id: ldo.h,v 1.48 2002/07/08 18:21:33 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -27,10 +27,14 @@ #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TObject *)((char *)L->stack + (n))) +#define saveci(L,p) ((char *)(p) - (char *)L->base_ci) +#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n))) + /* type of protected functions, to be ran by `runprotected' */ -typedef void (*Pfunc) (lua_State *L, void *v); +typedef void (*Pfunc) (lua_State *L, void *ud); +void luaD_resetprotection (lua_State *L); int luaD_protectedparser (lua_State *L, ZIO *z, int bin); void luaD_callhook (lua_State *L, lua_Hookevent event, int line); StkId luaD_precall (lua_State *L, StkId func); @@ -42,8 +46,7 @@ void luaD_reallocstack (lua_State *L, int newsize); void luaD_growstack (lua_State *L, int n); void luaD_throw (lua_State *L, int errcode); -int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud); -int luaD_isprotected (lua_State *L, CallInfo *ci); +int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); #endif diff --git a/lstate.c b/lstate.c index 1edb93f4..17d45f5f 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.98 2002/07/08 18:21:33 roberto Exp roberto $ +** $Id: lstate.c,v 1.99 2002/07/16 14:26:56 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -35,17 +35,19 @@ static int default_panic (lua_State *L) { static void stack_init (lua_State *L, lua_State *OL) { - L->stack = luaM_newvector(OL, BASIC_STACK_SIZE, TObject); - L->stacksize = BASIC_STACK_SIZE; + L->stack = luaM_newvector(OL, BASIC_STACK_SIZE + EXTRA_STACK, TObject); + L->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; L->top = L->stack; - L->stack_last = L->stack+(BASIC_STACK_SIZE-EXTRA_STACK)-1; + L->stack_last = L->stack+(L->stacksize - EXTRA_STACK)-1; L->base_ci = luaM_newvector(OL, BASIC_CI_SIZE, CallInfo); L->ci = L->base_ci; - L->ci->savedpc = NULL; + L->ci->pc = NULL; /* not a Lua function */ L->ci->base = L->top; L->ci->top = L->top + LUA_MINSTACK; L->size_ci = BASIC_CI_SIZE; L->end_ci = L->base_ci + L->size_ci; + L->toreset = luaM_newvector(OL, 2, Protection); + L->size_toreset = 2; } @@ -98,7 +100,12 @@ static void preinit_state (lua_State *L) { resethookcount(L); L->openupval = NULL; L->size_ci = 0; - L->base_ci = NULL; + L->base_ci = L->ci = NULL; + L->toreset = NULL; + L->size_toreset = L->number_toreset = 0; + setnilvalue(defaultmeta(L)); + setnilvalue(gt(L)); + setnilvalue(registry(L)); } @@ -124,13 +131,12 @@ LUA_API lua_State *lua_newthread (lua_State *OL) { LUA_API lua_State *lua_open (void) { lua_State *L; - TObject dummy[2]; L = luaM_new(NULL, lua_State); if (L) { /* allocation OK? */ preinit_state(L); L->l_G = NULL; L->next = L->previous = L; - if (luaD_runprotected(L, f_luaopen, dummy) != 0) { + if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); L = NULL; @@ -147,6 +153,7 @@ void luaE_closethread (lua_State *OL, lua_State *L) { L->previous->next = L->next; L->next->previous = L->previous; luaM_freearray(OL, L->base_ci, L->size_ci, CallInfo); + luaM_freearray(OL, L->toreset, L->size_toreset, Protection); luaM_freearray(OL, L->stack, L->stacksize, TObject); luaM_freelem(OL, L); } diff --git a/lstate.h b/lstate.h index 5db528ff..a334921a 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.88 2002/07/08 20:22:08 roberto Exp roberto $ +** $Id: lstate.h,v 1.89 2002/07/16 14:26:56 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -65,7 +65,7 @@ struct lua_longjmp; /* defined in ldo.c */ #define registry(L) (L->globs + 2) -/* space to handle TM calls and other temporary overflows */ +/* extra stack space to handle TM calls and some other extras */ #define EXTRA_STACK 5 @@ -88,10 +88,10 @@ typedef struct stringtable { typedef struct CallInfo { StkId base; /* base for called function */ StkId top; /* top for this function */ - const Instruction *savedpc; /* NULL means not a Lua function */ + const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ union { struct { /* for Lua functions */ - const Instruction **pc; /* points to `pc' variable in `luaV_execute' */ + const Instruction *savedpc; StkId *pb; /* points to `base' variable in `luaV_execute' */ } l; struct { /* for C functions */ @@ -101,7 +101,15 @@ typedef struct CallInfo { } CallInfo; -#define isLua(ci) ((ci)->savedpc != NULL) +/* +** informations about a `protection' (error recovery points) +*/ +typedef struct Protection { + ptrdiff_t ci; + ptrdiff_t top; + int allowhooks; +} Protection; + #define ci_func(ci) (clvalue((ci)->base - 1)) @@ -133,22 +141,25 @@ typedef struct global_State { struct lua_State { LUA_USERSTATE StkId top; /* first free slot in the stack */ + global_State *l_G; CallInfo *ci; /* call info for current function */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ + int stacksize; CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ - global_State *l_G; + int size_ci; /* size of array `base_ci' */ int hookmask; ls_count hookcount; lua_Hook hook; - TObject globs[NUMGLOBS]; /* registry, table of globals, etc. */ - struct lua_longjmp *errorJmp; /* current error recover point */ UpVal *openupval; /* list of open upvalues in this stack */ + struct lua_longjmp *errorJmp; /* current error recover point */ + Protection *toreset; /* array of pending pcall resets */ + int number_toreset; + int size_toreset; lua_State *next; /* circular double linked list of states */ lua_State *previous; - int stacksize; - int size_ci; /* size of array `base_ci' */ + TObject globs[NUMGLOBS]; /* registry, table of globals, etc. */ }; diff --git a/luadebug.h b/luadebug.h index 0f277727..4a37c640 100644 --- a/luadebug.h +++ b/luadebug.h @@ -1,5 +1,5 @@ /* -** $Id: luadebug.h,v 1.29 2002/07/08 18:21:33 roberto Exp roberto $ +** $Id: luadebug.h,v 1.30 2002/07/08 20:22:08 roberto Exp $ ** Debugging API ** See Copyright Notice in lua.h */ @@ -46,7 +46,6 @@ struct lua_Debug { const char *what; /* (S) `Lua' function, `C' function, Lua `main' */ const char *source; /* (S) */ int currentline; /* (l) */ - int isprotected; /* (c) function was called in protected mode */ int nups; /* (u) number of upvalues */ int linedefined; /* (S) */ char short_src[LUA_IDSIZE]; /* (S) */ diff --git a/lvm.c b/lvm.c index d966a179..071b1d0f 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.247 2002/07/16 14:26:56 roberto Exp roberto $ +** $Id: lvm.c,v 1.248 2002/07/17 16:25:13 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -24,6 +24,9 @@ #include "lvm.h" +Instruction const *luaV_callingmark = NULL; + + /* function to convert a lua_Number to a string */ #ifndef lua_number2str #include @@ -46,8 +49,8 @@ static void luaV_checkGC (lua_State *L, StkId top) { const TObject *luaV_tonumber (const TObject *obj, TObject *n) { lua_Number num; - if (ttype(obj) == LUA_TNUMBER) return obj; - if (ttype(obj) == LUA_TSTRING && luaO_str2d(svalue(obj), &num)) { + if (ttisnumber(obj)) return obj; + if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { setnvalue(n, num); return n; } @@ -57,7 +60,7 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n) { int luaV_tostring (lua_State *L, TObject *obj) { - if (ttype(obj) != LUA_TNUMBER) + if (!ttisnumber(obj)) return 0; else { char s[32]; /* 16 digits, sign, point and \0 (+ some extra...) */ @@ -80,16 +83,16 @@ static void traceexec (lua_State *L) { if (mask & LUA_MASKLINE) { CallInfo *ci = L->ci; Proto *p = ci_func(ci)->l.p; - int newline = getline(p, pcRel(*ci->u.l.pc, p)); - if (pcRel(*ci->u.l.pc, p) == 0) /* tracing may be starting now? */ - ci->savedpc = *ci->u.l.pc; /* initialize `savedpc' */ + int newline = getline(p, pcRel(*ci->pc, p)); + if (pcRel(*ci->pc, p) == 0) /* tracing may be starting now? */ + ci->u.l.savedpc = *ci->pc; /* initialize `savedpc' */ /* calls linehook when enters a new line or jumps back (loop) */ - if (*ci->u.l.pc <= ci->savedpc || - newline != getline(p, pcRel(ci->savedpc, p))) { + if (*ci->pc <= ci->u.l.savedpc || + newline != getline(p, pcRel(ci->u.l.savedpc, p))) { luaD_callhook(L, LUA_HOOKLINE, newline); ci = L->ci; /* previous call may reallocate `ci' */ } - ci->savedpc = *ci->u.l.pc; + ci->u.l.savedpc = *ci->pc; } } @@ -123,7 +126,7 @@ static const TObject *luaV_index (lua_State *L, const TObject *t, TObject *key, int loop) { const TObject *tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); if (tm == NULL) return &luaO_nilobject; /* no TM */ - if (ttype(tm) == LUA_TFUNCTION) { + if (ttisfunction(tm)) { callTMres(L, tm, t, key); return L->top; } @@ -133,9 +136,9 @@ static const TObject *luaV_index (lua_State *L, const TObject *t, static const TObject *luaV_getnotable (lua_State *L, const TObject *t, TObject *key, int loop) { const TObject *tm = luaT_gettmbyobj(L, t, TM_GETTABLE); - if (ttype(tm) == LUA_TNIL) + if (ttisnil(tm)) luaG_typeerror(L, t, "index"); - if (ttype(tm) == LUA_TFUNCTION) { + if (ttisfunction(tm)) { callTMres(L, tm, t, key); return L->top; } @@ -152,10 +155,10 @@ const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key, int loop) { if (loop > MAXTAGLOOP) luaG_runerror(L, "loop in gettable"); - if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ + if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TObject *v = luaH_get(h, key); /* do a primitive get */ - if (ttype(v) != LUA_TNIL) return v; + if (!ttisnil(v)) return v; else return luaV_index(L, t, key, loop+1); } else return luaV_getnotable(L, t, key, loop+1); @@ -169,19 +172,19 @@ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { const TObject *tm; int loop = 0; do { - if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ + if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ - if (ttype(oldval) != LUA_TNIL || /* result is no nil? */ + if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj(oldval, val); return; } /* else will try the tag method */ } - else if (ttype(tm = luaT_gettmbyobj(L, t, TM_SETTABLE)) == LUA_TNIL) + else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_SETTABLE))) luaG_typeerror(L, t, "index"); - if (ttype(tm) == LUA_TFUNCTION) { + if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } @@ -195,9 +198,9 @@ static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, TObject *res, TMS event) { ptrdiff_t result = savestack(L, res); const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ - if (ttype(tm) == LUA_TNIL) + if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ - if (ttype(tm) != LUA_TFUNCTION) return 0; + if (!ttisfunction(tm)) return 0; callTMres(L, tm, p1, p2); res = restorestack(L, result); /* previous call may change stack */ setobj(res, L->top); @@ -230,9 +233,9 @@ static int luaV_strcmp (const TString *ls, const TString *rs) { int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); - else if (ttype(l) == LUA_TNUMBER) + else if (ttisnumber(l)) return nvalue(l) < nvalue(r); - else if (ttype(l) == LUA_TSTRING) + else if (ttisstring(l)) return luaV_strcmp(tsvalue(l), tsvalue(r)) < 0; else if (call_binTM(L, l, r, L->top, TM_LT)) return !l_isfalse(L->top); @@ -243,9 +246,9 @@ int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) { static int luaV_lessequal (lua_State *L, const TObject *l, const TObject *r) { if (ttype(l) != ttype(r)) return luaG_ordererror(L, l, r); - else if (ttype(l) == LUA_TNUMBER) + else if (ttisnumber(l)) return nvalue(l) <= nvalue(r); - else if (ttype(l) == LUA_TSTRING) + else if (ttisstring(l)) return luaV_strcmp(tsvalue(l), tsvalue(r)) <= 0; else if (call_binTM(L, l, r, L->top, TM_LE)) /* first try `le' */ return !l_isfalse(L->top); @@ -330,7 +333,7 @@ static void Arith (lua_State *L, StkId ra, StkId rb, StkId rc, TMS op) { const TObject *f = luaH_getstr(hvalue(registry(L)), G(L)->tmname[TM_POW]); ptrdiff_t res = savestack(L, ra); - if (ttype(f) != LUA_TFUNCTION) + if (!ttisfunction(f)) luaG_runerror(L, "`pow' (for `^' operator) is not a function"); callTMres(L, f, b, c); ra = restorestack(L, res); /* previous call may change stack */ @@ -370,9 +373,9 @@ StkId luaV_execute (lua_State *L) { TObject *k; const Instruction *pc; callentry: /* entry point when calling new functions */ - L->ci->u.l.pc = &pc; L->ci->u.l.pb = &base; - pc = L->ci->savedpc; + L->ci->pc = &pc; + pc = L->ci->u.l.savedpc; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ @@ -382,11 +385,10 @@ StkId luaV_execute (lua_State *L) { /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; - StkId ra; + const StkId ra = RA(i); if (L->hookmask >= LUA_MASKLINE && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) - traceexec(L); - ra = RA(i); + traceexec(L); lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || @@ -420,9 +422,9 @@ StkId luaV_execute (lua_State *L) { case OP_GETGLOBAL: { StkId rb = KBx(i); const TObject *v; - lua_assert(ttype(rb) == LUA_TSTRING && ttype(&cl->g) == LUA_TTABLE); + lua_assert(ttisstring(rb) && ttistable(&cl->g)); v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); - if (ttype(v) != LUA_TNIL) { setobj(ra, v); } + if (!ttisnil(v)) { setobj(ra, v); } else setobj(RA(i), luaV_index(L, &cl->g, rb, 0)); break; @@ -430,9 +432,9 @@ StkId luaV_execute (lua_State *L) { case OP_GETTABLE: { StkId rb = RB(i); TObject *rc = RKC(i); - if (ttype(rb) == LUA_TTABLE) { + if (ttistable(rb)) { const TObject *v = luaH_get(hvalue(rb), rc); - if (ttype(v) != LUA_TNIL) { setobj(ra, v); } + if (!ttisnil(v)) { setobj(ra, v); } else setobj(RA(i), luaV_index(L, rb, rc, 0)); } @@ -441,7 +443,7 @@ StkId luaV_execute (lua_State *L) { break; } case OP_SETGLOBAL: { - lua_assert(ttype(KBx(i)) == LUA_TSTRING && ttype(&cl->g) == LUA_TTABLE); + lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); luaV_settable(L, &cl->g, KBx(i), ra); break; } @@ -464,11 +466,11 @@ StkId luaV_execute (lua_State *L) { case OP_SELF: { StkId rb = RB(i); TObject *rc = RKC(i); - runtime_check(L, ttype(rc) == LUA_TSTRING); + runtime_check(L, ttisstring(rc)); setobj(ra+1, rb); - if (ttype(rb) == LUA_TTABLE) { + if (ttistable(rb)) { const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); - if (ttype(v) != LUA_TNIL) { setobj(ra, v); } + if (!ttisnil(v)) { setobj(ra, v); } else setobj(RA(i), luaV_index(L, rb, rc, 0)); } @@ -479,7 +481,7 @@ StkId luaV_execute (lua_State *L) { case OP_ADD: { StkId rb = RB(i); StkId rc = RKC(i); - if (ttype(rb) == LUA_TNUMBER && ttype(rc) == LUA_TNUMBER) { + if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) + nvalue(rc)); } else @@ -489,7 +491,7 @@ StkId luaV_execute (lua_State *L) { case OP_SUB: { StkId rb = RB(i); StkId rc = RKC(i); - if (ttype(rb) == LUA_TNUMBER && ttype(rc) == LUA_TNUMBER) { + if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) - nvalue(rc)); } else @@ -499,7 +501,7 @@ StkId luaV_execute (lua_State *L) { case OP_MUL: { StkId rb = RB(i); StkId rc = RKC(i); - if (ttype(rb) == LUA_TNUMBER && ttype(rc) == LUA_TNUMBER) { + if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) * nvalue(rc)); } else @@ -509,7 +511,7 @@ StkId luaV_execute (lua_State *L) { case OP_DIV: { StkId rb = RB(i); StkId rc = RKC(i); - if (ttype(rb) == LUA_TNUMBER && ttype(rc) == LUA_TNUMBER) { + if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) / nvalue(rc)); } else @@ -584,7 +586,8 @@ StkId luaV_execute (lua_State *L) { } break; } - case OP_CALL: { + case OP_CALL: + case OP_TAILCALL: { StkId firstResult; int b = GETARG_B(i); int nresults; @@ -593,46 +596,47 @@ StkId luaV_execute (lua_State *L) { firstResult = luaD_precall(L, ra); if (firstResult) { if (firstResult > L->top) { /* yield? */ - (L->ci-1)->savedpc = pc; + (L->ci - 1)->u.l.savedpc = pc; + (L->ci - 1)->pc = &luaV_callingmark; 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: `call' it */ - (L->ci-1)->savedpc = pc; + else { /* it is a Lua function */ + if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ + (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ + (L->ci-1)->pc = &luaV_callingmark; /* function is calling */ + } + else { /* tail call: put new frame in place of previous one */ + int aux; + StkId ra1 = RA(i); /* `luaD_precall' may change the stack */ + if (L->openupval) luaF_close(L, base); + for (aux = 0; ra1+aux < L->top; aux++) /* move frame down */ + setobj(base+aux-1, ra1+aux); + (L->ci - 1)->top = L->top = base+aux; /* correct top */ + (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; + L->ci--; /* remove previous frame */ + } goto callentry; } break; } - case OP_TAILCALL: { - int b = GETARG_B(i); - if (L->openupval) luaF_close(L, base); - if (b != 0) L->top = ra+b; /* else previous instruction set top */ - luaD_poscall(L, LUA_MULTRET, ra); /* move down function and args. */ - ra = luaD_precall(L, base-1); - if (ra == NULL) goto callentry; /* it is a Lua function */ - else if (ra > L->top) return NULL; /* yield??? */ - else goto ret; - } case OP_RETURN: { - int b; - if (L->openupval) luaF_close(L, base); - b = GETARG_B(i); + CallInfo *ci = L->ci - 1; + int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; - lua_assert(L->ci->u.l.pc == &pc); - } - ret: { - CallInfo *ci; - ci = L->ci - 1; + lua_assert(L->ci->pc == &pc); + if (L->openupval) luaF_close(L, base); /* previous function was running `here'? */ - if (!isLua(ci) || ci->u.l.pc != &pc) + if (ci->pc != &luaV_callingmark) return ra; /* no: return */ - else { /* yes: continue its execution */ + else { /* yes: continue its execution (go through) */ int nresults; - lua_assert(ttype(ci->base-1) == LUA_TFUNCTION); - pc = ci->savedpc; + lua_assert(ttisfunction(ci->base-1)); + ci->pc = &pc; /* function is active again */ + pc = ci->u.l.savedpc; lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL); nresults = GETARG_C(*(pc-1)) - 1; luaD_poscall(L, nresults, ra); @@ -644,7 +648,7 @@ StkId luaV_execute (lua_State *L) { lua_Number step, index, limit; const TObject *plimit = ra+1; const TObject *pstep = ra+2; - if (ttype(ra) != LUA_TNUMBER) + if (!ttisnumber(ra)) luaG_runerror(L, "`for' initial value must be a number"); if (!tonumber(plimit, ra+1)) luaG_runerror(L, "`for' limit must be a number"); @@ -666,12 +670,12 @@ StkId luaV_execute (lua_State *L) { L->top = ra+5; luaD_call(L, ra+2, GETARG_C(i) + 1); L->top = L->ci->top; - if (ttype(ra+2) == LUA_TNIL) pc++; /* skip jump (break loop) */ + if (ttisnil(ra+2)) pc++; /* skip jump (break loop) */ else dojump(pc, GETARG_sBx(*pc) + 1); /* else jump back */ break; } case OP_TFORPREP: { /* for compatibility only */ - if (ttype(ra) == LUA_TTABLE) { + if (ttistable(ra)) { setobj(ra+1, ra); setobj(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } @@ -683,7 +687,7 @@ StkId luaV_execute (lua_State *L) { int bc; int n; Table *h; - runtime_check(L, ttype(ra) == LUA_TTABLE); + runtime_check(L, ttistable(ra)); h = hvalue(ra); bc = GETARG_Bx(i); if (GET_OPCODE(i) == OP_SETLIST) diff --git a/lvm.h b/lvm.h index 6b462e09..c1b2c312 100644 --- a/lvm.h +++ b/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 1.43 2002/06/24 13:08:45 roberto Exp roberto $ +** $Id: lvm.h,v 1.44 2002/07/05 18:27:39 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -22,6 +22,13 @@ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) +/* +** dummy addrees, to mark Lua functions calling other Lua functions (and +** therefore without a valid `pc' +*/ +extern Instruction const *luaV_callingmark; + + int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r); int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2); const TObject *luaV_tonumber (const TObject *obj, TObject *n);