Преглед на файлове

retraverse all gray lists together to avoid traversing some weak
tables twice (as they may change lists when traversed)

Roberto Ierusalimschy преди 14 години
родител
ревизия
bc90cf4b83
променени са 1 файла, в които са добавени 34 реда и са изтрити 14 реда
  1. 34 14
      lgc.c

+ 34 - 14
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.110 2011/09/19 17:03:38 roberto Exp roberto $
+** $Id: lgc.c,v 2.112 2011/09/24 21:12:01 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -153,7 +153,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
 */
 void luaC_barrierback_ (lua_State *L, GCObject *o) {
   global_State *g = G(L);
-  lua_assert(isblack(o) && !isdead(g, o));
+  lua_assert(isblack(o) && !isdead(g, o) && gch(o)->tt == LUA_TTABLE);
   black2gray(o);  /* make object gray (again) */
   gco2t(o)->gclist = g->grayagain;
   g->grayagain = o;
@@ -343,6 +343,9 @@ static void markroot (global_State *g) {
 
 static void traverseweakvalue (global_State *g, Table *h) {
   Node *n, *limit = gnode(h, sizenode(h));
+  /* if there is array part, assume it may have white values (do not
+     traverse it just to check) */
+  int hasclears = (h->sizearray > 0);
   for (n = gnode(h, 0); n < limit; n++) {
     checkdeadkey(n);
     if (ttisnil(gval(n)))  /* entry is empty? */
@@ -350,9 +353,14 @@ static void traverseweakvalue (global_State *g, Table *h) {
     else {
       lua_assert(!ttisnil(gkey(n)));
       markvalue(g, gkey(n));  /* mark key */
+      if (!hasclears && iscleared(gval(n)))  /* is there a white value? */
+        hasclears = 1;  /* table will have to be cleared */
     }
   }
-  linktable(h, &g->weak);  /* link into appropriate list */
+  if (hasclears)
+    linktable(h, &g->weak);  /* has to be cleared later */
+  else  /* no white values */
+    linktable(h, &g->grayagain);  /* no need to clean */
 }
 
 
@@ -531,11 +539,26 @@ static void propagateall (global_State *g) {
 }
 
 
-static void traverselistofgrays (global_State *g, GCObject **l) {
+static void propagatelist (global_State *g, GCObject *l) {
   lua_assert(g->gray == NULL);  /* no grays left */
-  g->gray = *l;  /* now 'l' is new gray list */
-  *l = NULL;
-  propagateall(g);
+  g->gray = l;
+  propagateall(g);  /* traverse all elements from 'l' */
+}
+
+/*
+** retraverse all gray lists. Because tables may be reinserted in other
+** lists when traversed, traverse the original lists to avoid traversing
+** twice the same table (which is not wrong, but inefficient)
+*/
+static void retraversegrays (global_State *g) {
+  GCObject *weak = g->weak;  /* save original lists */
+  GCObject *grayagain = g->grayagain;
+  GCObject *ephemeron = g->ephemeron;
+  g->weak = g->grayagain = g->ephemeron = NULL;
+  propagateall(g);  /* traverse main gray list */
+  propagatelist(g, grayagain);
+  propagatelist(g, weak);
+  propagatelist(g, ephemeron);
 }
 
 
@@ -890,10 +913,7 @@ static void atomic (lua_State *L) {
   /* remark occasional upvalues of (maybe) dead threads */
   remarkupvals(g);
   /* traverse objects caught by write barrier and by 'remarkupvals' */
-  propagateall(g);
-  traverselistofgrays(g, &g->weak);  /* remark weak tables */
-  traverselistofgrays(g, &g->grayagain);  /* remark gray again */
-  traverselistofgrays(g, &g->ephemeron);  /* remark ephemeron tables */
+  retraversegrays(g);
   convergeephemerons(g);
   /* at this point, all strongly accessible objects are marked. */
   /* clear values from weak tables, before checking finalizers */
@@ -904,11 +924,11 @@ static void atomic (lua_State *L) {
   markbeingfnz(g);  /* mark userdata that will be finalized */
   propagateall(g);  /* remark, to propagate `preserveness' */
   convergeephemerons(g);
-  /* at this point, all accessible objects are marked. */
-  /* remove collected objects from weak tables */
+  /* at this point, all resurrected objects are marked. */
+  /* remove dead objects from weak tables */
   clearkeys(g->ephemeron, NULL);  /* clear keys from all ephemeron tables */
   clearkeys(g->allweak, NULL);  /* clear keys from all allweak tables */
-  /* clear values from weak tables accessible from separated objects  */
+  /* clear values from resurrected weak tables */
   clearvalues(g->weak, origweak);
   clearvalues(g->allweak, origall);
   g->sweepstrgc = 0;  /* prepare to sweep strings */