commit 4e23699aa647fd9dc04933bf5582217ca594c8ce
parent 1c0ac3c0f53720c53dcfae13308b11b29dca38e4
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Mon, 5 Aug 2002 14:36:02 -0300
new implementation for error handling
Diffstat:
M | lauxlib.c | | | 15 | +++++++-------- |
M | ldblib.c | | | 21 | ++++++++------------- |
M | ldo.c | | | 275 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | ldo.h | | | 11 | +++++++---- |
M | lstate.c | | | 23 | +++++++++++++++-------- |
M | lstate.h | | | 31 | +++++++++++++++++++++---------- |
M | luadebug.h | | | 3 | +-- |
M | lvm.c | | | 150 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
M | lvm.h | | | 9 | ++++++++- |
9 files changed, 279 insertions(+), 259 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 <stdio.h>
@@ -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
@@ -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);