Bläddra i källkod

using 'trap' to stop 'luaV_execute' when necessary (tracing and
to update its copy of 'base' when the stack is reallocated)

Roberto Ierusalimschy 7 år sedan
förälder
incheckning
5440b42f43
5 ändrade filer med 67 tillägg och 24 borttagningar
  1. 21 2
      ldebug.c
  2. 12 3
      ldo.c
  3. 2 1
      lstate.c
  4. 2 1
      lstate.h
  5. 30 17
      lvm.c

+ 21 - 2
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.142 2017/11/08 14:50:23 roberto Exp roberto $
+** $Id: ldebug.c,v 2.143 2017/11/13 12:20:51 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -107,7 +107,24 @@ static int currentline (CallInfo *ci) {
 
 
 /*
-** This function can be called asynchronously (e.g. during a signal).
+** This function can be called asynchronously (e.g. during a signal),
+** under "reasonable" assumptions. A new 'ci' is completely linked
+** in the list before it becomes part of the "active" list, and
+** we assume that pointers are atomic (see comment in next function).
+** (If we traverse one more item, there is no problem. If we traverse
+** one less item, the worst that can happen is that the signal will
+** not interrupt the script.)
+*/
+static void settraps (CallInfo *ci) {
+  for (; ci != NULL; ci = ci->previous)
+    if (isLua(ci))
+      ci->u.l.trap = 1;
+}
+
+
+/*
+** This function can be called asynchronously (e.g. during a signal),
+** under "reasonable" assumptions.
 ** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
 ** 'resethookcount') are for debug only, and it is no problem if they
 ** get arbitrary values (causes at most one wrong hook call). 'hookmask'
@@ -126,6 +143,8 @@ LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
   L->basehookcount = count;
   resethookcount(L);
   L->hookmask = cast_byte(mask);
+  if (mask & (LUA_MASKLINE | LUA_MASKCOUNT))
+    settraps(L->ci);  /* to trace inside 'luaV_execute' */
 }
 
 

+ 12 - 3
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.170 2017/11/07 13:25:26 roberto Exp roberto $
+** $Id: ldo.c,v 2.171 2017/11/13 12:26:30 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -159,12 +159,16 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
 static void correctstack (lua_State *L, StkId oldstack) {
   CallInfo *ci;
   UpVal *up;
+  if (L->stack == oldstack)
+    return;  /* stack address did not change */
   L->top = (L->top - oldstack) + L->stack;
   for (up = L->openupval; up != NULL; up = up->u.open.next)
     up->v = s2v((uplevel(up) - oldstack) + L->stack);
   for (ci = L->ci; ci != NULL; ci = ci->previous) {
     ci->top = (ci->top - oldstack) + L->stack;
     ci->func = (ci->func - oldstack) + L->stack;
+    if (isLua(ci))
+      ci->u.l.trap = 1;  /* signal to update 'trap' in 'luaV_execute' */
   }
 }
 
@@ -277,13 +281,18 @@ void luaD_hook (lua_State *L, int event, int line) {
 
 
 static void callhook (lua_State *L, CallInfo *ci) {
-  int hook = LUA_HOOKCALL;
+  int hook;
+  ci->u.l.trap = 1;
+  if (!(L->hookmask & LUA_MASKCALL))
+    return;  /* some other hook */
   ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
   if (isLua(ci->previous) &&
       GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
     ci->callstatus |= CIST_TAIL;
     hook = LUA_HOOKTAILCALL;
   }
+  else
+    hook = LUA_HOOKCALL;
   luaD_hook(L, hook, -1);
   ci->u.l.savedpc--;  /* correct 'pc' */
 }
@@ -430,7 +439,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
       lua_assert(ci->top <= L->stack_last);
       ci->u.l.savedpc = p->code;  /* starting point */
       ci->callstatus = CIST_LUA;
-      if (L->hookmask & LUA_MASKCALL)
+      if (L->hookmask)
         callhook(L, ci);
       return 0;
     }

+ 2 - 1
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.143 2017/10/31 17:54:35 roberto Exp $
+** $Id: lstate.c,v 2.146 2017/11/07 13:25:26 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -103,6 +103,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
   L->ci->next = ci;
   ci->previous = L->ci;
   ci->next = NULL;
+  ci->u.l.trap = 0;
   L->nci++;
   return ci;
 }

+ 2 - 1
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.146 2017/11/02 11:28:56 roberto Exp $
+** $Id: lstate.h,v 2.150 2017/11/07 13:25:26 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -91,6 +91,7 @@ typedef struct CallInfo {
   union {
     struct {  /* only for Lua functions */
       const Instruction *savedpc;
+      l_signalT trap;
     } l;
     struct {  /* only for C functions */
       lua_KFunction k;  /* continuation in case of yields */

+ 30 - 17
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.308 2017/11/08 14:50:23 roberto Exp roberto $
+** $Id: lvm.c,v 2.309 2017/11/08 19:01:02 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -756,14 +756,16 @@ void luaV_finishOp (lua_State *L) {
 
 
 
-#define updatemask(L)  (mask = L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT))
+#define updatetrap(ci)  (trap = ci->u.l.trap)
+
+#define updatebase(ci)	(base = ci->func + 1)
 
 
 /*
-** Execute a jump instruction. The 'updatemask' allows signals to stop
-** tight loops. (Without it, the local copy of 'mask' could never change.)
+** Execute a jump instruction. The 'updatetrap' allows signals to stop
+** tight loops. (Without it, the local copy of 'trap' could never change.)
 */
-#define dojump(ci,i,e)	{ pc += GETARG_sJ(i) + e; updatemask(L); }
+#define dojump(ci,i,e)	{ pc += GETARG_sJ(i) + e; updatetrap(ci); }
 
 
 /* for test instructions, execute the jump instruction that follows it */
@@ -780,19 +782,24 @@ void luaV_finishOp (lua_State *L) {
 ** Protect code that, in general, can raise errors, reallocate the
 ** stack, and change the hooks.
 */
-#define Protect(exp)  (savepc(L), (exp), base = ci->func + 1, updatemask(L))
+#define Protect(exp)  (savepc(L), (exp), updatetrap(ci))
 
 
 #define checkGC(L,c)  \
 	{ luaC_condGC(L, L->top = (c),  /* limit of live values */ \
-                         Protect(L->top = ci->top));  /* restore top */ \
+                   (L->top = ci->top, updatetrap(ci)));  /* restore top */ \
            luai_threadyield(L); }
 
 
 /* fetch an instruction and prepare its execution */
 #define vmfetch()	{ \
   i = *(pc++); \
-  if (mask) Protect(luaG_traceexec(L)); \
+  if (trap) { \
+    if (!(L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT))) \
+      trap = ci->u.l.trap = 0;  /* no need to stop again */ \
+    else { savepc(L); luaG_traceexec(L); } \
+    updatebase(ci);  /* the trap may be just for that */ \
+  } \
   ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
 }
 
@@ -802,19 +809,19 @@ void luaV_finishOp (lua_State *L) {
 
 
 void luaV_execute (lua_State *L) {
-  CallInfo *ci = L->ci;
+  CallInfo *ci = L->ci;  /* local copy of 'L->ci' */
   LClosure *cl;
   TValue *k;
   StkId base;  /* local copy of 'ci->func + 1' */
-  int mask;  /* local copy of 'L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)' */
+  int trap;
   const Instruction *pc;  /* local copy of 'ci->u.l.savedpc' */
   ci->callstatus |= CIST_FRESH;  /* fresh invocation of 'luaV_execute" */
  newframe:  /* reentry point when frame changes (call/return) */
   lua_assert(ci == L->ci);
   cl = clLvalue(s2v(ci->func));  /* local reference to function's closure */
   k = cl->p->k;  /* local reference to function's constant table */
-  updatemask(L);
-  base = ci->func + 1;
+  updatetrap(ci);
+  updatebase(ci);
   pc = ci->u.l.savedpc;
   /* main loop of interpreter */
   for (;;) {
@@ -1294,7 +1301,10 @@ void luaV_execute (lua_State *L) {
         StkId rb;
         L->top = base + c + 1;  /* mark the end of concat operands */
         Protect(luaV_concat(L, c - b + 1));
-        ra = RA(i);  /* 'luaV_concat' may invoke TMs and move the stack */
+        if (trap) {  /* 'luaV_concat' may move the stack */
+          updatebase(ci);
+          ra = RA(i);
+        }
         rb = base + b;
         setobjs2s(L, ra, rb);
         checkGC(L, (ra >= rb ? ra + 1 : rb));
@@ -1390,7 +1400,7 @@ void luaV_execute (lua_State *L) {
         lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
         savepc(L);
         if (luaD_precall(L, ra, LUA_MULTRET))  /* C function? */
-          Protect((void)0);  /* update 'base' */
+          updatetrap(ci);
         else {
           /* tail call: put called frame (n) in place of caller one (o) */
           CallInfo *nci = L->ci;  /* called frame (new) */
@@ -1416,7 +1426,8 @@ void luaV_execute (lua_State *L) {
       }
       vmcase(OP_RETURN) {
         int b = GETARG_B(i);
-        if (cl->p->sizep > 0) luaF_close(L, base);
+        if (cl->p->sizep > 0)
+          luaF_close(L, base);
         savepc(L);
         b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
         if (ci->callstatus & CIST_FRESH)  /* local 'ci' still from callee */
@@ -1452,7 +1463,7 @@ void luaV_execute (lua_State *L) {
             setfltvalue(s2v(ra + 3), idx);  /* ...and external index */
           }
         }
-        updatemask(L);
+        updatetrap(ci);
         vmbreak;
       }
       vmcase(OP_FORPREP) {
@@ -1492,8 +1503,10 @@ void luaV_execute (lua_State *L) {
         L->top = cb + 3;  /* func. + 2 args (state and index) */
         Protect(luaD_call(L, cb, GETARG_C(i)));
         L->top = ci->top;
+        if (trap)  /* keep 'base' correct for next instruction */
+          updatebase(ci);
         i = *(pc++);  /* go to next instruction */
-        ra = RA(i);
+        ra = RA(i);  /* get its 'ra' */
         lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
         goto l_tforloop;
       }