Browse Source

new implementation for error handling

v5-2
Roberto Ierusalimschy 23 years ago
parent
commit
4e23699aa6
  1. 15
      lauxlib.c
  2. 21
      ldblib.c
  3. 275
      ldo.c
  4. 11
      ldo.h
  5. 23
      lstate.c
  6. 31
      lstate.h
  7. 3
      luadebug.h
  8. 150
      lvm.c
  9. 9
      lvm.h

15
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;
}

21
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;
}

275
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;
}
/* }====================================================== */

11
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

23
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);
}

31
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. */
};

3
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) */

150
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)

9
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);

Loading…
Cancel
Save