diff --git a/ldblib.c b/ldblib.c index a0601b14..b6c78588 100644 --- a/ldblib.c +++ b/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.60 2002/06/18 17:42:52 roberto Exp roberto $ +** $Id: ldblib.c,v 1.61 2002/06/25 19:16:44 roberto Exp roberto $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -108,65 +108,70 @@ static int setlocal (lua_State *L) { -static const char KEY_CALLHOOK = 'c'; -static const char KEY_LINEHOOK = 'l'; +static const char KEY_HOOK = 'h'; -static void hookf (lua_State *L, void *key) { - lua_pushudataval(L, key); +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = {"call", "return", "line", "count"}; + lua_pushudataval(L, (void *)&KEY_HOOK); lua_rawget(L, LUA_REGISTRYINDEX); if (lua_isfunction(L, -1)) { - lua_pushvalue(L, -2); /* original argument (below function) */ - lua_call(L, 1, 0); + lua_pushstring(L, hooknames[(int)ar->event]); + if (ar->currentline >= 0) lua_pushnumber(L, ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); } else lua_pop(L, 1); /* pop result from gettable */ } -static void callf (lua_State *L, lua_Debug *ar) { - lua_pushstring(L, ar->event); - lua_assert(lua_getinfo(L, "lS", ar) && ar->currentline == -1); - hookf(L, (void *)&KEY_CALLHOOK); +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + return mask | lua_maskcount(count); } -static void linef (lua_State *L, lua_Debug *ar) { - lua_pushnumber(L, ar->currentline); - lua_assert((ar->currentline = ar->linedefined = -1, - lua_getinfo(L, "lS", ar) && - ar->currentline == lua_tonumber(L, -1) && - ar->linedefined >= 0)); - hookf(L, (void *)&KEY_LINEHOOK); +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; } -static void sethook (lua_State *L, void *key, lua_Hook hook, - lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) { - lua_settop(L, 1); - if (lua_isnoneornil(L, 1)) - (*sethookf)(L, NULL); - else if (lua_isfunction(L, 1)) - (*sethookf)(L, hook); - else - luaL_argerror(L, 1, "function expected"); - lua_pushudataval(L, key); - lua_rawget(L, LUA_REGISTRYINDEX); /* get old value */ - lua_pushudataval(L, key); +static int sethook (lua_State *L) { + if (lua_isnoneornil(L, 1)) { + lua_settop(L, 1); + lua_sethook(L, NULL, 0); /* turn off hooks */ + } + else { + const char *smask = luaL_check_string(L, 2); + int count = luaL_opt_int(L, 3, 0); + luaL_check_type(L, 1, LUA_TFUNCTION); + lua_sethook(L, hookf, makemask(smask, count)); + } + lua_pushudataval(L, (void *)&KEY_HOOK); lua_pushvalue(L, 1); - lua_rawset(L, LUA_REGISTRYINDEX); /* set new value */ + lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ + return 0; } -static int setcallhook (lua_State *L) { - sethook(L, (void *)&KEY_CALLHOOK, callf, lua_setcallhook); - return 1; -} - - -static int setlinehook (lua_State *L) { - sethook(L, (void *)&KEY_LINEHOOK, linef, lua_setlinehook); - return 1; +static int gethook (lua_State *L) { + char buff[5]; + int mask = lua_gethookmask(L); + lua_pushudataval(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushnumber(L, lua_getmaskcount(mask)); + return 3; } @@ -245,8 +250,8 @@ static int errorfb (lua_State *L) { static const luaL_reg dblib[] = { {"getlocal", getlocal}, {"getinfo", getinfo}, - {"setcallhook", setcallhook}, - {"setlinehook", setlinehook}, + {"gethook", gethook}, + {"sethook", sethook}, {"setlocal", setlocal}, {"debug", debug}, {"traceback", errorfb}, diff --git a/ldebug.c b/ldebug.c index 5123f77d..73029a5d 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 1.122 2002/06/20 20:39:44 roberto Exp roberto $ +** $Id: ldebug.c,v 1.123 2002/06/24 15:07:21 roberto Exp roberto $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -53,26 +53,31 @@ static int currentline (lua_State *L, CallInfo *ci) { } -LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) { - lua_Hook oldhook; - lua_lock(L); - oldhook = L->callhook; - L->callhook = func; - lua_unlock(L); - return oldhook; -} - - -LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) { +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask) { CallInfo *ci; - lua_Hook oldhook; + int allow; lua_lock(L); - oldhook = L->linehook; - L->linehook = func; + allow = allowhook(L); + if (func == NULL) mask = 0; + else if (mask == 0) func = NULL; + L->hook = func; + L->hookmask = mask; + setallowhook(L, allow); + resethookcount(L); for (ci = L->base_ci; ci <= L->ci; ci++) currentpc(L, ci); /* update `savedpc' */ lua_unlock(L); - return oldhook; + return 1; +} + + +LUA_API lua_Hook lua_gethook (lua_State *L) { + return L->hook; +} + + +LUA_API int lua_gethookmask (lua_State *L) { + return L->hookmask; } @@ -396,6 +401,10 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { return pt->code[last]; } +#undef check +#undef checkjump +#undef checkreg + /* }====================================================== */ diff --git a/ldebug.h b/ldebug.h index 764b39a9..0849a302 100644 --- a/ldebug.h +++ b/ldebug.h @@ -1,5 +1,5 @@ /* -** $Id: ldebug.h,v 1.22 2002/06/18 15:19:27 roberto Exp roberto $ +** $Id: ldebug.h,v 1.23 2002/06/24 15:07:21 roberto Exp roberto $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ @@ -16,6 +16,13 @@ #define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0) +#define resethookcount(L) \ + (L->hookcount = (1 << lua_getmaskcount(L->hookmask)) >> 1) + +#define setallowhook(L,cond) ((L->hookmask) = ((L->hookmask) & ~1) | (cond)) +#define allowhook(L) ((L->hookmask) & 1) + + void luaG_typeerror (lua_State *L, const TObject *o, const char *opname); void luaG_concaterror (lua_State *L, StkId p1, StkId p2); void luaG_aritherror (lua_State *L, StkId p1, const TObject *p2); diff --git a/ldo.c b/ldo.c index 5ff1c068..d52506b4 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 1.184 2002/06/26 16:37:23 roberto Exp roberto $ +** $Id: ldo.c,v 1.185 2002/07/04 12:29:32 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -135,40 +135,29 @@ static void luaD_openstack (lua_State *L, StkId pos) { } -static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) { - ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, L->ci->top); - ar->i_ci = L->ci - L->base_ci; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - L->ci->top = L->top + LUA_MINSTACK; - L->allowhooks = 0; /* cannot call hooks inside a hook */ - lua_unlock(L); - (*hook)(L, ar); - lua_lock(L); - lua_assert(L->allowhooks == 0); - L->allowhooks = 1; - L->ci->top = restorestack(L, ci_top); - L->top = restorestack(L, top); -} - - -void luaD_lineHook (lua_State *L, int line) { - if (L->allowhooks) { - lua_Debug ar; - ar.event = "line"; - ar.currentline = line; - dohook(L, &ar, L->linehook); - } -} - - -static void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) { - if (L->allowhooks) { +void luaD_callhook (lua_State *L, lua_Hookevent event, int line) { + lua_Hook hook = L->hook; + if (hook && allowhook(L)) { + ptrdiff_t top = savestack(L, L->top); + ptrdiff_t ci_top = savestack(L, L->ci->top); lua_Debug ar; ar.event = event; - L->ci->pc = NULL; /* function is not active */ - L->ci->top = L->ci->base; /* `top' may not have a valid value yet */ - dohook(L, &ar, callhook); + ar.currentline = line; + ar.i_ci = L->ci - L->base_ci; + if (event <= LUA_HOOKRET) { /* `call' or `return' event? */ + L->ci->pc = NULL; /* function is not active */ + L->ci->top = L->ci->base; /* `top' may not have a valid value yet */ + } + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + L->ci->top = L->top + LUA_MINSTACK; + setallowhook(L, 0); /* cannot call hooks inside a hook */ + lua_unlock(L); + (*hook)(L, &ar); + lua_lock(L); + lua_assert(!allowhook(L)); + setallowhook(L, 1); + L->ci->top = restorestack(L, ci_top); + L->top = restorestack(L, top); } } @@ -219,8 +208,8 @@ StkId luaD_precall (lua_State *L, StkId func) { if (ttype(func) != LUA_TFUNCTION) /* `func' is not a function? */ func = tryfuncTM(L, func); /* check the `function' tag method */ cl = &clvalue(func)->l; - if (L->callhook) { - luaD_callHook(L, L->callhook, "call"); + if (L->hookmask & LUA_MASKCALL) { + luaD_callhook(L, LUA_HOOKCALL, -1); ci = L->ci; /* previous call may realocate `ci' */ } if (!cl->isC) { /* Lua function? prepare its call */ @@ -252,9 +241,9 @@ StkId luaD_precall (lua_State *L, StkId func) { void luaD_poscall (lua_State *L, int wanted, StkId firstResult) { StkId res; - if (L->callhook) { + if (L->hookmask & LUA_MASKRET) { ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ - luaD_callHook(L, L->callhook, "return"); + luaD_callhook(L, LUA_HOOKRET, -1); firstResult = restorestack(L, fr); } res = L->ci->base - 1; /* res == final position of 1st result */ @@ -483,7 +472,7 @@ int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) { struct lua_longjmp lj; lj.ci = L->ci; lj.top = L->top; - lj.allowhooks = L->allowhooks; + lj.allowhooks = allowhook(L); lj.status = 0; lj.err = ud; lj.previous = L->errorJmp; /* chain new error handler */ @@ -493,7 +482,7 @@ int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) { else { /* an error occurred */ L->ci = lj.ci; /* restore the state */ L->top = lj.top; - L->allowhooks = lj.allowhooks; + setallowhook(L, lj.allowhooks); restore_stack_limit(L); } L->errorJmp = lj.previous; /* restore old error handler */ diff --git a/ldo.h b/ldo.h index dc856bf6..c18193d1 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.46 2002/06/18 15:19:27 roberto Exp roberto $ +** $Id: ldo.h,v 1.47 2002/06/18 17:10:43 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -32,7 +32,7 @@ typedef void (*Pfunc) (lua_State *L, void *v); int luaD_protectedparser (lua_State *L, ZIO *z, int bin); -void luaD_lineHook (lua_State *L, int line); +void luaD_callhook (lua_State *L, lua_Hookevent event, int line); StkId luaD_precall (lua_State *L, StkId func); void luaD_call (lua_State *L, StkId func, int nResults); int luaD_pcall (lua_State *L, int nargs, int nresults); diff --git a/lgc.c b/lgc.c index c9bcf666..991ff51d 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.140 2002/07/01 17:06:58 roberto Exp roberto $ +** $Id: lgc.c,v 1.141 2002/07/04 17:57:42 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -451,8 +451,8 @@ static void do1gcTM (lua_State *L, Udata *udata) { static void callGCTM (lua_State *L) { - int oldah = L->allowhooks; - L->allowhooks = 0; /* stop debug hooks during GC tag methods */ + int oldah = allowhook(L); + setallowhook(L, 0); /* stop debug hooks during GC tag methods */ L->top++; /* reserve space to keep udata while runs its gc method */ while (G(L)->tmudata != NULL) { Udata *udata = G(L)->tmudata; @@ -465,7 +465,7 @@ static void callGCTM (lua_State *L) { do1gcTM(L, udata); } L->top--; - L->allowhooks = oldah; /* restore hooks */ + setallowhook(L, oldah); /* restore hooks */ } diff --git a/lstate.c b/lstate.c index 2d4bc94c..241c177b 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.96 2002/06/06 18:17:33 roberto Exp roberto $ +** $Id: lstate.c,v 1.97 2002/06/18 15:19:27 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -92,12 +92,13 @@ static void preinit_state (lua_State *L) { L->stack = NULL; L->stacksize = 0; L->errorJmp = NULL; - L->callhook = NULL; - L->linehook = NULL; + L->hook = NULL; + L->hookmask = 0; + setallowhook(L, 1); + resethookcount(L); L->openupval = NULL; L->size_ci = 0; L->base_ci = NULL; - L->allowhooks = 1; } diff --git a/lstate.h b/lstate.h index 4a379e2c..4f3290ef 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.85 2002/05/08 17:34:23 roberto Exp roberto $ +** $Id: lstate.h,v 1.86 2002/07/02 16:43:28 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -130,8 +130,9 @@ struct lua_State { CallInfo *end_ci; /* points after end of ci array*/ CallInfo *base_ci; /* array of CallInfo's */ global_State *l_G; - lua_Hook linehook; - lua_Hook callhook; + int hookmask; + int 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 */ @@ -139,7 +140,6 @@ struct lua_State { lua_State *previous; int stacksize; int size_ci; /* size of array `base_ci' */ - int allowhooks; }; diff --git a/luadebug.h b/luadebug.h index c7ea3da4..d8c82c2d 100644 --- a/luadebug.h +++ b/luadebug.h @@ -1,5 +1,5 @@ /* -** $Id: luadebug.h,v 1.27 2002/04/04 17:21:31 roberto Exp roberto $ +** $Id: luadebug.h,v 1.28 2002/06/18 17:10:43 roberto Exp roberto $ ** Debugging API ** See Copyright Notice in lua.h */ @@ -11,6 +11,18 @@ #include "lua.h" +typedef enum lua_Hookevent { + LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKLINE, LUA_HOOKCOUNT +} lua_Hookevent; + + +#define LUA_MASKCALL (2 << LUA_HOOKCALL) +#define LUA_MASKRET (2 << LUA_HOOKRET) +#define LUA_MASKLINE (2 << LUA_HOOKLINE) +#define lua_maskcount(count) ((count) << (LUA_HOOKCOUNT+1)) +#define lua_getmaskcount(mask) ((mask) >> (LUA_HOOKCOUNT+1)) +#define LUA_MASKCOUNT (lua_maskcount(1)) + typedef struct lua_Debug lua_Debug; /* activation record */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); @@ -21,14 +33,15 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); -LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func); -LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func); +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask); +LUA_API lua_Hook lua_gethook (lua_State *L); +LUA_API int lua_gethookmask (lua_State *L); #define LUA_IDSIZE 60 struct lua_Debug { - const char *event; /* `call', `return', `line' */ + lua_Hookevent event; const char *name; /* (n) */ const char *namewhat; /* (n) `global', `local', `field', `method' */ const char *what; /* (S) `Lua' function, `C' function, Lua `main' */ diff --git a/lvm.c b/lvm.c index 0e643f7f..20674c61 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.243 2002/06/24 15:07:21 roberto Exp roberto $ +** $Id: lvm.c,v 1.244 2002/07/05 18:27:39 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -69,17 +69,28 @@ int luaV_tostring (lua_State *L, TObject *obj) { static void traceexec (lua_State *L) { - CallInfo *ci = L->ci; - Proto *p = ci_func(ci)->l.p; - int newline = getline(p, pcRel(*ci->pc, p)); - if (pcRel(*ci->pc, p) == 0) /* tracing may be starting now? */ - ci->savedpc = *ci->pc; /* initialize `savedpc' */ - /* calls linehook when enters a new line or jumps back (loop) */ - if (*ci->pc <= ci->savedpc || newline != getline(p, pcRel(ci->savedpc, p))) { - luaD_lineHook(L, newline); - ci = L->ci; /* previous call may reallocate `ci' */ + int mask = L->hookmask; + if (mask >= LUA_MASKCOUNT) { /* instruction hook set? */ + if (L->hookcount == 0) { + luaD_callhook(L, LUA_HOOKCOUNT, -1); + resethookcount(L); + return; + } + } + if (mask & LUA_MASKLINE) { + CallInfo *ci = L->ci; + Proto *p = ci_func(ci)->l.p; + int newline = getline(p, pcRel(*ci->pc, p)); + if (pcRel(*ci->pc, p) == 0) /* tracing may be starting now? */ + ci->savedpc = *ci->pc; /* initialize `savedpc' */ + /* calls linehook when enters a new line or jumps back (loop) */ + if (*ci->pc <= ci->savedpc || + newline != getline(p, pcRel(ci->savedpc, p))) { + luaD_callhook(L, LUA_HOOKLINE, newline); + ci = L->ci; /* previous call may reallocate `ci' */ + } + ci->savedpc = *ci->pc; } - ci->savedpc = *ci->pc; } @@ -370,8 +381,9 @@ StkId luaV_execute (lua_State *L) { for (;;) { const Instruction i = *pc++; StkId ra; - if (L->linehook) - traceexec(L); + if (L->hookmask >= LUA_MASKLINE && + (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) + traceexec(L); ra = RA(i); lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base); lua_assert(L->top == L->ci->top ||