Browse Source

more generic way to handle 'gclist'

Roberto Ierusalimschy 7 years ago
parent
commit
1afd5a152d
6 changed files with 63 additions and 75 deletions
  1. 4 4
      lapi.c
  2. 50 62
      lgc.c
  3. 2 2
      lgc.h
  4. 2 2
      ltable.c
  5. 3 3
      lvm.c
  6. 2 2
      lvm.h

+ 4 - 4
lapi.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lapi.c,v 2.282 2018/01/29 16:21:35 roberto Exp roberto $
+** $Id: lapi.c,v 2.283 2018/02/05 17:10:52 roberto Exp roberto $
 ** Lua API
 ** Lua API
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -828,7 +828,7 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
   slot = luaH_set(L, hvalue(o), s2v(L->top - 2));
   slot = luaH_set(L, hvalue(o), s2v(L->top - 2));
   setobj2t(L, slot, s2v(L->top - 1));
   setobj2t(L, slot, s2v(L->top - 1));
   invalidateTMcache(hvalue(o));
   invalidateTMcache(hvalue(o));
-  luaC_barrierback(L, hvalue(o), s2v(L->top - 1));
+  luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
   L->top -= 2;
   L->top -= 2;
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -841,7 +841,7 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
   o = index2value(L, idx);
   o = index2value(L, idx);
   api_check(L, ttistable(o), "table expected");
   api_check(L, ttistable(o), "table expected");
   luaH_setint(L, hvalue(o), n, s2v(L->top - 1));
   luaH_setint(L, hvalue(o), n, s2v(L->top - 1));
-  luaC_barrierback(L, hvalue(o), s2v(L->top - 1));
+  luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
   L->top--;
   L->top--;
   lua_unlock(L);
   lua_unlock(L);
 }
 }
@@ -857,7 +857,7 @@ LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
   setpvalue(&k, cast_voidp(p));
   setpvalue(&k, cast_voidp(p));
   slot = luaH_set(L, hvalue(o), &k);
   slot = luaH_set(L, hvalue(o), &k);
   setobj2t(L, slot, s2v(L->top - 1));
   setobj2t(L, slot, s2v(L->top - 1));
-  luaC_barrierback(L, hvalue(o), s2v(L->top - 1));
+  luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
   L->top--;
   L->top--;
   lua_unlock(L);
   lua_unlock(L);
 }
 }

+ 50 - 62
lgc.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lgc.c,v 2.245 2018/01/28 15:13:26 roberto Exp roberto $
+** $Id: lgc.c,v 2.248 2018/02/19 16:02:25 roberto Exp roberto $
 ** Garbage Collector
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -110,12 +110,31 @@ static lu_mem atomic (lua_State *L);
 #define gnodelast(h)	gnode(h, cast_sizet(sizenode(h)))
 #define gnodelast(h)	gnode(h, cast_sizet(sizenode(h)))
 
 
 
 
+static GCObject **getgclist (GCObject *o) {
+  switch (o->tt) {
+    case LUA_TTABLE: return &gco2t(o)->gclist;
+    case LUA_TLCL: return &gco2lcl(o)->gclist;
+    case LUA_TCCL: return &gco2ccl(o)->gclist;
+    case LUA_TTHREAD: return &gco2th(o)->gclist;
+    case LUA_TPROTO: return &gco2p(o)->gclist;
+    default: lua_assert(0); return 0;
+  }
+}
+
+
 /*
 /*
-** link collectable object 'o' into list pointed by 'p'
+** Link a collectable object 'o' with a known type into list pointed by 'p'.
 */
 */
 #define linkgclist(o,p)	((o)->gclist = (p), (p) = obj2gco(o))
 #define linkgclist(o,p)	((o)->gclist = (p), (p) = obj2gco(o))
 
 
 
 
+/*
+** Link a generic collectable object 'o' into list pointed by 'p'.
+*/
+#define linkobjgclist(o,p) (*getgclist(o) = (p), (p) = obj2gco(o))
+
+
+
 /*
 /*
 ** Clear keys for empty entries in tables. If entry is empty
 ** Clear keys for empty entries in tables. If entry is empty
 ** and its key is not marked, mark its entry as dead. This allows the
 ** and its key is not marked, mark its entry as dead. This allows the
@@ -175,14 +194,14 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
 ** barrier that moves collector backward, that is, mark the black object
 ** barrier that moves collector backward, that is, mark the black object
 ** pointing to a white object as gray again.
 ** pointing to a white object as gray again.
 */
 */
-void luaC_barrierback_ (lua_State *L, Table *t) {
+void luaC_barrierback_ (lua_State *L, GCObject *o) {
   global_State *g = G(L);
   global_State *g = G(L);
-  lua_assert(isblack(t) && !isdead(g, t));
-  lua_assert(g->gckind != KGC_GEN || (isold(t) && getage(t) != G_TOUCHED1));
-  if (getage(t) != G_TOUCHED2)  /* not already in gray list? */
-    linkgclist(t, g->grayagain);  /* link it in 'grayagain' */
-  black2gray(t);  /* make table gray (again) */
-  setage(t, G_TOUCHED1);  /* touched in current cycle */
+  lua_assert(isblack(o) && !isdead(g, o));
+  lua_assert(g->gckind != KGC_GEN || (isold(o) && getage(o) != G_TOUCHED1));
+  if (getage(o) != G_TOUCHED2)  /* not already in gray list? */
+    linkobjgclist(o, g->grayagain);  /* link it in 'grayagain' */
+  black2gray(o);  /* make table gray (again) */
+  setage(o, G_TOUCHED1);  /* touched in current cycle */
 }
 }
 
 
 
 
@@ -276,24 +295,9 @@ static void reallymarkobject (global_State *g, GCObject *o) {
       markvalue(g, uv->v);  /* mark its content */
       markvalue(g, uv->v);  /* mark its content */
       break;
       break;
     }
     }
-    case LUA_TLCL: {
-      linkgclist(gco2lcl(o), g->gray);
-      break;
-    }
-    case LUA_TCCL: {
-      linkgclist(gco2ccl(o), g->gray);
-      break;
-    }
-    case LUA_TTABLE: {
-      linkgclist(gco2t(o), g->gray);
-      break;
-    }
-    case LUA_TTHREAD: {
-      linkgclist(gco2th(o), g->gray);
-      break;
-    }
-    case LUA_TPROTO: {
-      linkgclist(gco2p(o), g->gray);
+    case LUA_TLCL: case LUA_TCCL: case LUA_TTABLE:
+    case LUA_TTHREAD: case LUA_TPROTO: {
+      linkobjgclist(o, g->gray);
       break;
       break;
     }
     }
     default: lua_assert(0); break;
     default: lua_assert(0); break;
@@ -605,34 +609,18 @@ static int traversethread (global_State *g, lua_State *th) {
 static lu_mem propagatemark (global_State *g) {
 static lu_mem propagatemark (global_State *g) {
   GCObject *o = g->gray;
   GCObject *o = g->gray;
   gray2black(o);
   gray2black(o);
+  g->gray = *getgclist(o);  /* remove from 'gray' list */
   switch (o->tt) {
   switch (o->tt) {
-    case LUA_TTABLE: {
-      Table *h = gco2t(o);
-      g->gray = h->gclist;  /* remove from 'gray' list */
-      return traversetable(g, h);
-    }
-    case LUA_TLCL: {
-      LClosure *cl = gco2lcl(o);
-      g->gray = cl->gclist;  /* remove from 'gray' list */
-      return traverseLclosure(g, cl);
-    }
-    case LUA_TCCL: {
-      CClosure *cl = gco2ccl(o);
-      g->gray = cl->gclist;  /* remove from 'gray' list */
-      return traverseCclosure(g, cl);
-    }
+    case LUA_TTABLE: return traversetable(g, gco2t(o));
+    case LUA_TLCL: return traverseLclosure(g, gco2lcl(o));
+    case LUA_TCCL: return traverseCclosure(g, gco2ccl(o));
+    case LUA_TPROTO: return traverseproto(g, gco2p(o));
     case LUA_TTHREAD: {
     case LUA_TTHREAD: {
       lua_State *th = gco2th(o);
       lua_State *th = gco2th(o);
-      g->gray = th->gclist;  /* remove from 'gray' list */
       linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */
       linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */
       black2gray(o);
       black2gray(o);
       return traversethread(g, th);
       return traversethread(g, th);
     }
     }
-    case LUA_TPROTO: {
-      Proto *p = gco2p(o);
-      g->gray = p->gclist;  /* remove from 'gray' list */
-      return traverseproto(g, p);
-    }
     default: lua_assert(0); return 0;
     default: lua_assert(0); return 0;
   }
   }
 }
 }
@@ -1069,8 +1057,8 @@ static void whitelist (global_State *g, GCObject *p) {
 ** Correct a list of gray objects. Because this correction is
 ** Correct a list of gray objects. Because this correction is
 ** done after sweeping, young objects can be white and still
 ** done after sweeping, young objects can be white and still
 ** be in the list. They are only removed.
 ** be in the list. They are only removed.
-** For tables, advance 'touched1' to 'touched2'; 'touched2' objects
-** become regular old and are removed from the list.
+** For tables and userdata, advance 'touched1' to 'touched2'; 'touched2'
+** objects become regular old and are removed from the list.
 ** For threads, just remove white ones from the list.
 ** For threads, just remove white ones from the list.
 */
 */
 static GCObject **correctgraylist (GCObject **p) {
 static GCObject **correctgraylist (GCObject **p) {
@@ -1078,21 +1066,21 @@ static GCObject **correctgraylist (GCObject **p) {
   while ((curr = *p) != NULL) {
   while ((curr = *p) != NULL) {
     switch (curr->tt) {
     switch (curr->tt) {
       case LUA_TTABLE: {
       case LUA_TTABLE: {
-        Table *h = gco2t(curr);
-        if (getage(h) == G_TOUCHED1) {  /* touched in this cycle? */
-          lua_assert(isgray(h));
-          gray2black(h);  /* make it black, for next barrier */
-          changeage(h, G_TOUCHED1, G_TOUCHED2);
-          p = &h->gclist;  /* go to next element */
+        GCObject **next = getgclist(curr);
+        if (getage(curr) == G_TOUCHED1) {  /* touched in this cycle? */
+          lua_assert(isgray(curr));
+          gray2black(curr);  /* make it black, for next barrier */
+          changeage(curr, G_TOUCHED1, G_TOUCHED2);
+          p = next;  /* go to next element */
         }
         }
         else {
         else {
-          if (!iswhite(h)) {
-            lua_assert(isold(h));
-            if (getage(h) == G_TOUCHED2)
-              changeage(h, G_TOUCHED2, G_OLD);
-            gray2black(h);  /* make it black */
+          if (!iswhite(curr)) {
+            lua_assert(isold(curr));
+            if (getage(curr) == G_TOUCHED2)
+              changeage(curr, G_TOUCHED2, G_OLD);
+            gray2black(curr);  /* make it black */
           }
           }
-          *p = h->gclist;  /* remove 'curr' from gray list */
+          *p = *next;  /* remove 'curr' from gray list */
         }
         }
         break;
         break;
       }
       }

+ 2 - 2
lgc.h

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lgc.h,v 2.100 2018/01/28 15:13:26 roberto Exp roberto $
+** $Id: lgc.h,v 2.102 2018/02/19 13:55:34 roberto Exp roberto $
 ** Garbage Collector
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -173,7 +173,7 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
 LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
 LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
 LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
 LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
 LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
 LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
-LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o);
+LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
 LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
 LUAI_FUNC void luaC_protobarrier_ (lua_State *L, Proto *p);
 LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
 LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
 LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
 LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);

+ 2 - 2
ltable.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: ltable.c,v 2.130 2017/12/29 15:58:23 roberto Exp roberto $
+** $Id: ltable.c,v 2.131 2018/01/28 15:13:26 roberto Exp roberto $
 ** Lua tables (hash)
 ** Lua tables (hash)
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -600,7 +600,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
     }
     }
   }
   }
   setnodekey(L, mp, key);
   setnodekey(L, mp, key);
-  luaC_barrierback(L, t, key);
+  luaC_barrierback(L, obj2gco(t), key);
   lua_assert(ttisnil(gval(mp)));
   lua_assert(ttisnil(gval(mp)));
   return gval(mp);
   return gval(mp);
 }
 }

+ 3 - 3
lvm.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lvm.c,v 2.340 2018/02/15 15:34:29 roberto Exp roberto $
+** $Id: lvm.c,v 2.341 2018/02/17 19:20:00 roberto Exp roberto $
 ** Lua virtual machine
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -223,7 +223,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
         /* no metamethod and (now) there is an entry with given key */
         /* no metamethod and (now) there is an entry with given key */
         setobj2t(L, cast(TValue *, slot), val);  /* set its new value */
         setobj2t(L, cast(TValue *, slot), val);  /* set its new value */
         invalidateTMcache(h);
         invalidateTMcache(h);
-        luaC_barrierback(L, h, val);
+        luaC_barrierback(L, obj2gco(h), val);
         return;
         return;
       }
       }
       /* else will try the metamethod */
       /* else will try the metamethod */
@@ -1691,7 +1691,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           TValue *val = s2v(ra + n);
           TValue *val = s2v(ra + n);
           setobj2t(L, &h->array[last - 1], val);
           setobj2t(L, &h->array[last - 1], val);
           last--;
           last--;
-          luaC_barrierback(L, h, val);
+          luaC_barrierback(L, obj2gco(h), val);
         }
         }
         vmbreak;
         vmbreak;
       }
       }

+ 2 - 2
lvm.h

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lvm.h,v 2.47 2017/11/08 14:50:23 roberto Exp roberto $
+** $Id: lvm.h,v 2.48 2017/11/29 13:02:17 roberto Exp roberto $
 ** Lua virtual machine
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -96,7 +96,7 @@
 */
 */
 #define luaV_finishfastset(L,t,slot,v) \
 #define luaV_finishfastset(L,t,slot,v) \
     { setobj2t(L, cast(TValue *,slot), v); \
     { setobj2t(L, cast(TValue *,slot), v); \
-      luaC_barrierback(L, hvalue(t), v); }
+      luaC_barrierback(L, gcvalue(t), v); }