From e4f609d0ee1cbbd357bec00c43effc659971bc7a Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 4 Jul 2012 12:52:38 -0300
Subject: collector in generational mode must be in 'propagate' state when not
 running a collection

---
 lgc.c    | 30 +++++++++++++-----------------
 lgc.h    |  7 ++++---
 ltests.c | 12 +++++++-----
 3 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/lgc.c b/lgc.c
index 7874f205..8b559cb6 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.133 2012/05/31 21:28:59 roberto Exp roberto $
+** $Id: lgc.c,v 2.134 2012/07/02 13:40:05 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -144,7 +144,7 @@ static int iscleared (global_State *g, const TValue *o) {
 void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
   global_State *g = G(L);
   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
-  lua_assert(isgenerational(g) || g->gcstate != GCSpause);
+  lua_assert(g->gcstate != GCSpause);
   lua_assert(gch(o)->tt != LUA_TTABLE);
   if (keepinvariant(g))  /* must keep invariant? */
     reallymarkobject(g, v);  /* restore invariant */
@@ -343,7 +343,7 @@ static void remarkupvals (global_State *g) {
 ** mark root set and reset all gray lists, to start a new
 ** incremental (or full) collection
 */
-static void startcollection (global_State *g) {
+static void restartcollection (global_State *g) {
   g->gray = g->grayagain = NULL;
   g->weak = g->allweak = g->ephemeron = NULL;
   markobject(g, g->mainthread);
@@ -855,7 +855,7 @@ static void separatetobefnz (lua_State *L, int all) {
   while ((curr = *p) != NULL) {  /* traverse all finalizable objects */
     lua_assert(!isfinalized(curr));
     lua_assert(testbit(gch(curr)->marked, SEPARATED));
-    if (!(all || iswhite(curr)))  /* not being collected? */
+    if (!(iswhite(curr) || all))  /* not being collected? */
       p = &gch(curr)->next;  /* don't bother with it */
     else {
       l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
@@ -1029,11 +1029,8 @@ static lu_mem singlestep (lua_State *L) {
   switch (g->gcstate) {
     case GCSpause: {
       g->GCmemtrav = 0;  /* start to count memory traversed */
-      if (!isgenerational(g))
-        startcollection(g);
-      /* in any case, root must be marked at this point */
-      lua_assert(!iswhite(obj2gco(g->mainthread))
-              && !iswhite(gcvalue(&g->l_registry)));
+      lua_assert(!isgenerational(g));
+      restartcollection(g);
       g->gcstate = GCSpropagate;
       return g->GCmemtrav;
     }
@@ -1105,14 +1102,15 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
 
 static void generationalcollection (lua_State *L) {
   global_State *g = G(L);
+  lua_assert(g->gcstate == GCSpropagate);
   if (g->GCestimate == 0) {  /* signal for another major collection? */
     luaC_fullgc(L, 0);  /* perform a full regular collection */
     g->GCestimate = gettotalbytes(g);  /* update control */
   }
   else {
     lu_mem estimate = g->GCestimate;
-    luaC_runtilstate(L, ~bitmask(GCSpause));  /* run complete cycle */
-    luaC_runtilstate(L, bitmask(GCSpause));
+    luaC_runtilstate(L, bitmask(GCSpause));  /* run complete (minor) cycle */
+    g->gcstate = GCSpropagate;  /* skip restart */
     if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
       g->GCestimate = 0;  /* signal for a major collection */
     else
@@ -1175,7 +1173,6 @@ void luaC_step (lua_State *L) {
 void luaC_fullgc (lua_State *L, int isemergency) {
   global_State *g = G(L);
   int origkind = g->gckind;
-  int someblack = keepinvariant(g);
   lua_assert(origkind != KGC_EMERGENCY);
   if (isemergency)  /* do not run finalizers during emergency GC */
     g->gckind = KGC_EMERGENCY;
@@ -1183,18 +1180,17 @@ void luaC_fullgc (lua_State *L, int isemergency) {
     g->gckind = KGC_NORMAL;
     callallpendingfinalizers(L, 1);
   }
-  if (someblack) {  /* may there be some black objects? */
+  if (keepinvariant(g)) {  /* may there be some black objects? */
     /* must sweep all objects to turn them back to white
        (as white has not changed, nothing will be collected) */
     entersweep(L);
   }
   /* finish any pending sweep phase to start a new cycle */
   luaC_runtilstate(L, bitmask(GCSpause));
-  /* run entire collector */
-  luaC_runtilstate(L, ~bitmask(GCSpause));
-  luaC_runtilstate(L, bitmask(GCSpause));
+  luaC_runtilstate(L, ~bitmask(GCSpause));  /* start new collection */
+  luaC_runtilstate(L, bitmask(GCSpause));  /* run entire collection */
   if (origkind == KGC_GEN) {  /* generational mode? */
-    /* generational mode must always start in propagate phase */
+    /* generational mode must be kept in propagate phase */
     luaC_runtilstate(L, bitmask(GCSpropagate));
   }
   g->gckind = origkind;
diff --git a/lgc.h b/lgc.h
index 282336c7..569aefae 100644
--- a/lgc.h
+++ b/lgc.h
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.55 2012/05/21 13:18:10 roberto Exp roberto $
+** $Id: lgc.h,v 2.56 2012/05/23 15:43:14 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -55,9 +55,10 @@
 ** phase may break the invariant, as objects turned white may point to
 ** still-black objects. The invariant is restored when sweep ends and
 ** all objects are white again. During a generational collection, the
-** invariant must be kept all times.
+** invariant must be kept all times. (The state in generational mode
+** is kept in 'propagate', so 'keepinvariant' is always true.)
 */
-#define keepinvariant(g)  (isgenerational(g) || g->gcstate <= GCSatomic)
+#define keepinvariant(g)  (g->gcstate <= GCSatomic)
 
 
 /*
diff --git a/ltests.c b/ltests.c
index 0a8b526a..610af463 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.130 2012/06/07 18:52:47 roberto Exp roberto $
+** $Id: ltests.c,v 2.131 2012/07/02 15:38:36 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -182,8 +182,8 @@ void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) {
 
 static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
   if (isdead(g,t)) return 0;
-  if (isgenerational(g) || !issweepphase(g))
-    return !isblack(f) || !iswhite(t);
+  if (!issweepphase(g))
+    return !(isblack(f) && iswhite(t));
   else return 1;
 }
 
@@ -329,7 +329,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
   if (isdead(g, o))
     lua_assert(maybedead);
   else {
-    if (g->gcstate == GCSpause && !isgenerational(g))
+    if (g->gcstate == GCSpause)
       lua_assert(iswhite(o));
     switch (gch(o)->tt) {
       case LUA_TUPVAL: {
@@ -432,6 +432,8 @@ int lua_checkmemory (lua_State *L) {
     lua_assert(!iswhite(obj2gco(g->mainthread)));
     lua_assert(!iswhite(gcvalue(&g->l_registry)));
   }
+  else  /* generational mode keeps collector in 'propagate' state */
+    lua_assert(!isgenerational(g));
   lua_assert(!isdead(g, gcvalue(&g->l_registry)));
   checkstack(g, g->mainthread);
   resetbit(g->mainthread->marked, TESTGRAYBIT);
@@ -457,7 +459,7 @@ int lua_checkmemory (lua_State *L) {
   /* check 'tobefnz' list */
   checkold(g, g->tobefnz);
   for (o = g->tobefnz; o != NULL; o = gch(o)->next) {
-    lua_assert(!iswhite(o));
+    lua_assert(!iswhite(o) || g->gcstate == GCSpause);
     lua_assert(!isdead(g, o) && testbit(o->gch.marked, SEPARATED));
     lua_assert(gch(o)->tt == LUA_TUSERDATA ||
                gch(o)->tt == LUA_TTABLE);
-- 
cgit v1.2.3-55-g6feb