浏览代码

new interface for debug hooks

Roberto Ierusalimschy 23 年之前
父节点
当前提交
39b2d58c39
共有 10 个文件被更改,包括 165 次插入129 次删除
  1. 47 42
      ldblib.c
  2. 25 16
      ldebug.c
  3. 8 1
      ldebug.h
  4. 28 39
      ldo.c
  5. 2 2
      ldo.h
  6. 4 4
      lgc.c
  7. 5 4
      lstate.c
  8. 4 4
      lstate.h
  9. 17 4
      luadebug.h
  10. 25 13
      lvm.c

+ 47 - 42
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 */
-}
-
-
-static int setcallhook (lua_State *L) {
-  sethook(L, (void *)&KEY_CALLHOOK, callf, lua_setcallhook);
-  return 1;
+  lua_rawset(L, LUA_REGISTRYINDEX);  /* set new hook */
+  return 0;
 }
 
 
-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},

+ 25 - 16
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
+
 /* }====================================================== */
 
 

+ 8 - 1
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);

+ 28 - 39
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 */

+ 2 - 2
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);

+ 4 - 4
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 */
 }
 
 

+ 5 - 4
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;
 }
 
 

+ 4 - 4
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;
 };
 
 

+ 17 - 4
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' */

+ 25 - 13
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 ||