Pārlūkot izejas kodu

new interface for debug hooks

Roberto Ierusalimschy 23 gadi atpakaļ
vecāks
revīzija
39b2d58c39
10 mainītis faili ar 165 papildinājumiem un 129 dzēšanām
  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 ||