소스 검색

added 'local' bit (true => object is only refered by local variables)

Roberto Ierusalimschy 12 년 전
부모
커밋
439d74e29f
10개의 변경된 파일96개의 추가작업 그리고 53개의 파일을 삭제
  1. 6 2
      lapi.c
  2. 3 1
      lfunc.c
  3. 17 9
      lgc.c
  4. 14 6
      lgc.h
  5. 2 1
      lparser.c
  6. 10 7
      lstate.c
  7. 2 2
      lstring.h
  8. 35 22
      ltests.c
  9. 5 2
      lundump.c
  10. 2 1
      lvm.c

+ 6 - 2
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.185 2013/07/05 14:29:51 roberto Exp roberto $
+** $Id: lapi.c,v 2.186 2013/08/05 16:58:28 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -586,8 +586,11 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
     cl = luaF_newCclosure(L, n);
     cl->c.f = fn;
     L->top -= n;
-    while (n--)
+    while (n--) {
       setobj2n(L, &cl->c.upvalue[n], L->top + n);
+      /* does not need barrier because closure is white */
+      valnolocal(L->top + n);  /* but needs 'local barrier' */
+    }
     setclCvalue(L, L->top, cl);
   }
   api_incr_top(L);
@@ -861,6 +864,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
     }
     default: {
       G(L)->mt[ttnov(obj)] = mt;
+      if (mt) nolocal(obj2gco(mt));
       break;
     }
   }

+ 3 - 1
lfunc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lfunc.c,v 2.31 2013/08/05 16:58:28 roberto Exp roberto $
+** $Id: lfunc.c,v 2.32 2013/08/07 12:18:11 roberto Exp roberto $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */
@@ -80,6 +80,7 @@ void luaF_close (lua_State *L, StkId level) {
       uv->v = &uv->value;  /* now current value lives here */
       gch(o)->next = g->allgc;  /* link upvalue into 'allgc' list */
       g->allgc = o;
+      valnolocal(uv->v);  /* keep local invariant */
       luaC_checkupvalcolor(g, uv);
     }
   }
@@ -88,6 +89,7 @@ void luaF_close (lua_State *L, StkId level) {
 
 Proto *luaF_newproto (lua_State *L) {
   Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
+  nolocal(obj2gco(f));  /* prototypes are never local */
   f->k = NULL;
   f->sizek = 0;
   f->p = NULL;

+ 17 - 9
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.144 2013/08/07 15:39:09 roberto Exp roberto $
+** $Id: lgc.c,v 2.145 2013/08/13 17:36:44 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -74,11 +74,19 @@
   lua_longassert(!iscollectable(obj) || righttt(obj))
 
 
-#define markvalue(g,o) { checkconsistency(o); \
+#define marklocalvalue(g,o) { checkconsistency(o); \
   if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
 
-#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
-		reallymarkobject(g, obj2gco(t)); }
+#define markvalue(g,o) {  \
+  lua_longassert(!(iscollectable(o) && islocal(gcvalue(o)))); \
+  marklocalvalue(g,o); }
+
+#define marklocalobject(g,t) { \
+	if ((t) && iswhite(obj2gco(t))) \
+	  reallymarkobject(g, obj2gco(t)); }
+
+#define markobject(g,t) \
+  { lua_assert((t) == NULL || !islocal(obj2gco(t))); marklocalobject(g,t); }
 
 static void reallymarkobject (global_State *g, GCObject *o);
 
@@ -259,7 +267,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
     }
     case LUA_TUPVAL: {
       UpVal *uv = gco2uv(o);
-      markvalue(g, uv->v);
+      marklocalvalue(g, uv->v);
       if (uv->v != &uv->value)  /* open? */
         return;  /* open upvalues remain gray */
       size = sizeof(UpVal);
@@ -331,7 +339,7 @@ static void remarkupvals (global_State *g) {
       GCObject *uv = gco2th(thread)->openupval;
       for (; uv != NULL; uv = gch(uv)->next) {
         if (isgray(uv))  /* marked? */
-          markvalue(g, gco2uv(uv)->v);  /* remark upvalue's value */
+          marklocalvalue(g, gco2uv(uv)->v);  /* remark upvalue's value */
       }
     }
   }
@@ -486,7 +494,7 @@ static int traverseproto (global_State *g, Proto *f) {
 static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
   int i;
   for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
-    markvalue(g, &cl->upvalue[i]);
+    marklocalvalue(g, &cl->upvalue[i]);
   return sizeCclosure(cl->nupvalues);
 }
 
@@ -494,7 +502,7 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
   int i;
   markobject(g, cl->p);  /* mark its prototype */
   for (i = 0; i < cl->nupvalues; i++)  /* mark its upvalues */
-    markobject(g, cl->upvals[i]);
+    marklocalobject(g, cl->upvals[i]);
   return sizeLclosure(cl->nupvalues);
 }
 
@@ -505,7 +513,7 @@ static lu_mem traversestack (global_State *g, lua_State *th) {
   if (o == NULL)
     return 1;  /* stack not completely built yet */
   for (; o < th->top; o++)  /* mark live elements in the stack */
-    markvalue(g, o);
+    marklocalvalue(g, o);
   if (g->gcstate == GCSatomic) {  /* final traversal? */
     StkId lim = th->stack + th->stacksize;  /* real end of stack */
     for (; o < lim; o++)  /* clear not-marked stack slice */

+ 14 - 6
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.59 2013/08/05 16:58:28 roberto Exp roberto $
+** $Id: lgc.h,v 2.60 2013/08/13 17:36:44 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -79,6 +79,7 @@
 #define FINALIZEDBIT	3  /* object has been separated for finalization */
 #define SEPARATED	4  /* object is in 'finobj' list or in 'tobefnz' */
 #define FIXEDBIT	5  /* object is fixed (should not be collected) */
+#define LOCALBIT	6  /* object is not local */
 /* bit 7 is currently used by tests (luaL_checkmemory) */
 
 #define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
@@ -88,6 +89,7 @@
 #define isblack(x)      testbit((x)->gch.marked, BLACKBIT)
 #define isgray(x)  /* neither white nor black */  \
 	(!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
+#define islocal(x)	(!testbit((x)->gch.marked, LOCALBIT))
 
 
 #define otherwhite(g)	(g->currentwhite ^ WHITEBITS)
@@ -97,6 +99,9 @@
 #define changewhite(x)	((x)->gch.marked ^= WHITEBITS)
 #define gray2black(x)	l_setbit((x)->gch.marked, BLACKBIT)
 
+#define nolocal(x)	l_setbit((x)->gch.marked, LOCALBIT)
+#define valnolocal(v)	{ if (iscollectable(v)) nolocal(gcvalue(v)); }
+
 #define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS)
 
 
@@ -106,22 +111,25 @@
 
 
 #define luaC_barrier(L,p,v) {  \
-	if (iscollectable(v) && isblack(obj2gco(p)) && iswhite(gcvalue(v)))  \
+	if (iscollectable(v) && \
+          (nolocal(gcvalue(v)), isblack(obj2gco(p)) && iswhite(gcvalue(v))))  \
 	luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
 
 #define luaC_barrierback(L,p,v) {  \
-	if (iscollectable(v) && isblack(obj2gco(p)) && iswhite(gcvalue(v)))  \
+	if (iscollectable(v) && \
+          (nolocal(gcvalue(v)), isblack(obj2gco(p)) && iswhite(gcvalue(v))))  \
 	luaC_barrierback_(L,p); }
 
 #define luaC_objbarrier(L,p,o) {  \
-	if (isblack(obj2gco(p)) && iswhite(obj2gco(o))) \
+	if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \
 		luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
 
 #define luaC_objbarrierback(L,p,o)  \
-   { if (isblack(obj2gco(p)) && iswhite(obj2gco(o))) luaC_barrierback_(L,p); }
+   { if (nolocal(obj2gco(o)), isblack(obj2gco(p)) && iswhite(obj2gco(o))) \
+	luaC_barrierback_(L,p); }
 
 #define luaC_barrierproto(L,p,c) \
-   { if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
+   { if (nolocal(obj2gco(c)), isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
 
 LUAI_FUNC void luaC_freeallobjects (lua_State *L);
 LUAI_FUNC void luaC_step (lua_State *L);

+ 2 - 1
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.132 2013/04/25 19:35:19 roberto Exp roberto $
+** $Id: lparser.c,v 2.133 2013/04/26 13:07:53 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -1632,6 +1632,7 @@ Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
   incr_top(L);
   funcstate.f = cl->l.p = luaF_newproto(L);
   funcstate.f->source = luaS_new(L, name);  /* create and anchor TString */
+  luaC_objbarrier(L, funcstate.f, funcstate.f->source);
   lexstate.buff = buff;
   lexstate.dyd = dyd;
   dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;

+ 10 - 7
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.100 2013/08/05 16:58:28 roberto Exp roberto $
+** $Id: lstate.c,v 2.101 2013/08/07 12:18:11 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -159,17 +159,19 @@ static void freestack (lua_State *L) {
 ** Create registry table and its predefined values
 */
 static void init_registry (lua_State *L, global_State *g) {
-  TValue mt;
+  TValue temp;
   /* create registry */
   Table *registry = luaH_new(L);
   sethvalue(L, &g->l_registry, registry);
   luaH_resize(L, registry, LUA_RIDX_LAST, 0);
+  nolocal(obj2gco(registry));
   /* registry[LUA_RIDX_MAINTHREAD] = L */
-  setthvalue(L, &mt, L);
-  luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &mt);
+  setthvalue(L, &temp, L);  /* temp = L */
+  luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
   /* registry[LUA_RIDX_GLOBALS] = table of globals */
-  sethvalue(L, &mt, luaH_new(L));
-  luaH_setint(L, registry, LUA_RIDX_GLOBALS, &mt);
+  sethvalue(L, &temp, luaH_new(L));  /* temp = new table (global table) */
+  luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
+  valnolocal(&temp);  /* keep local invariant */
 }
 
 
@@ -236,6 +238,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
   setthvalue(L, L->top, L1);
   api_incr_top(L);
   preinit_state(L1, G(L));
+  nolocal(obj2gco(L1));  /* threads are never local */
   L1->hookmask = L->hookmask;
   L1->basehookcount = L->basehookcount;
   L1->hook = L->hook;
@@ -268,7 +271,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   L->next = NULL;
   L->tt = LUA_TTHREAD;
   g->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT);
-  L->marked = luaC_white(g);
+  L->marked = luaC_white(g) | bitmask(LOCALBIT);
   g->gckind = KGC_NORMAL;
   preinit_state(L, g);
   g->frealloc = f;

+ 2 - 2
lstring.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstring.h,v 1.48 2012/01/25 21:05:40 roberto Exp roberto $
+** $Id: lstring.h,v 1.49 2012/02/01 21:57:15 roberto Exp roberto $
 ** String table (keep all strings handled by Lua)
 ** See Copyright Notice in lua.h
 */
@@ -19,7 +19,7 @@
 #define luaS_newliteral(L, s)	(luaS_newlstr(L, "" s, \
                                  (sizeof(s)/sizeof(char))-1))
 
-#define luaS_fix(s)	l_setbit((s)->tsv.marked, FIXEDBIT)
+#define luaS_fix(s)	setbits((s)->tsv.marked, bit2mask(FIXEDBIT, LOCALBIT))
 
 
 /*

+ 35 - 22
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.140 2013/08/05 16:58:28 roberto Exp roberto $
+** $Id: ltests.c,v 2.141 2013/08/07 12:18:11 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -188,6 +188,25 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
 }
 
 
+/*
+** Check locality
+*/
+static int testobjref2 (GCObject *f, GCObject *t) {
+  /* not a local or pointed by a thread? */
+  if (!islocal(t) || gch(f)->tt == LUA_TTHREAD)
+    return 1;  /* ok */
+  if (gch(t)->tt == LUA_TUPVAL) {
+    lua_assert(gch(f)->tt == LUA_TLCL);
+    return 1;  /* upvalue pointed by a closure */
+  }
+  if (gch(f)->tt == LUA_TUPVAL) {
+    UpVal *uv = gco2uv(f);
+    return (uv->v != &uv->value);  /* open upvalue can point to local stuff */
+  }
+  return 0;
+}
+
+
 static void printobj (global_State *g, GCObject *o) {
   int i = 1;
   GCObject *p;
@@ -198,24 +217,30 @@ static void printobj (global_State *g, GCObject *o) {
     if (p == NULL) i = 0;  /* zero means 'not found' */
     else i = -i;  /* negative means 'found in findobj list */
   }
-  printf("||%d:%s(%p)-%c(%02X)||", i, ttypename(gch(o)->tt), (void *)o,
+  printf("||%d:%s(%p)-%s-%c(%02X)||",
+           i, ttypename(novariant(gch(o)->tt)), (void *)o,
+           islocal(o)?"L":"NL",
            isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked);
 }
 
 
 static int testobjref (global_State *g, GCObject *f, GCObject *t) {
-  int r = testobjref1(g,f,t);
-  if (!r) {
-    printf("%d(%02X) - ", g->gcstate, g->currentwhite);
+  int r1 = testobjref1(g,f,t);
+  int r2 = testobjref2(f,t);
+  if (!r1 || !r2) {
+    if (!r1)
+      printf("%d(%02X) - ", g->gcstate, g->currentwhite);
+    else
+      printf("local violation - ");
     printobj(g, f);
-    printf("\t-> ");
+    printf("  ->  ");
     printobj(g, t);
     printf("\n");
   }
-  return r;
+  return r1 && r2;
 }
 
-#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t)))
+#define checkobjref(g,f,t)	lua_assert(testobjref(g,f,obj2gco(t)))
 
 
 static void checkvalref (global_State *g, GCObject *f, const TValue *t) {
@@ -349,6 +374,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
         break;
       }
       case LUA_TTHREAD: {
+        lua_assert(!islocal(o));
         checkstack(g, gco2th(o));
         break;
       }
@@ -617,22 +643,9 @@ static int get_gccolor (lua_State *L) {
   o = obj_at(L, 1);
   if (!iscollectable(o))
     lua_pushstring(L, "no collectable");
-  else {
-    int marked = gcvalue(o)->gch.marked;
-    int n = 1;
+  else
     lua_pushstring(L, iswhite(gcvalue(o)) ? "white" :
                       isblack(gcvalue(o)) ? "black" : "grey");
-    if (testbit(marked, FINALIZEDBIT)) {
-      lua_pushliteral(L, "/finalized"); n++;
-    }
-    if (testbit(marked, SEPARATED)) {
-      lua_pushliteral(L, "/separated"); n++;
-    }
-    if (testbit(marked, FIXEDBIT)) {
-      lua_pushliteral(L, "/fixed"); n++;
-    }
-    lua_concat(L, n);
-  }
   return 1;
 }
 

+ 5 - 2
lundump.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lundump.c,v 2.22 2012/05/08 13:53:33 roberto Exp roberto $
+** $Id: lundump.c,v 2.23 2013/04/26 18:48:35 roberto Exp roberto $
 ** load precompiled Lua chunks
 ** See Copyright Notice in lua.h
 */
@@ -84,9 +84,12 @@ static TString* LoadString(LoadState* S)
   return NULL;
  else
  {
+  TString* ts;
   char* s=luaZ_openspace(S->L,S->b,size);
   LoadBlock(S,s,size*sizeof(char));
-  return luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */
+  ts = luaS_newlstr(S->L,s,size-1);		/* remove trailing '\0' */
+  nolocal(obj2gco(ts));  /* all strings here anchored in non-thread objects */
+  return ts;
  }
 }
 

+ 2 - 1
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.175 2013/06/20 15:02:49 roberto Exp roberto $
+** $Id: lvm.c,v 2.176 2013/07/10 17:15:12 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -416,6 +416,7 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
       ncl->l.upvals[i] = luaF_findupval(L, base + uv[i].idx);
     else  /* get upvalue from enclosing function */
       ncl->l.upvals[i] = encup[uv[i].idx];
+    /* new closure is white and local, so we do not need a barrier here */
   }
   luaC_barrierproto(L, p, ncl);
   p->cache = ncl;  /* save it on cache for reuse */