From b36b4b521f53e5ff2e18fff3c194d28f9a840868 Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 22 May 2012 14:32:25 -0300
Subject: try to avoid sweeping new objects created with new white (and
 therefore not collectable in the current cycle)

---
 lgc.c    | 62 ++++++++++++++++++++++++++++++++++++++------------------------
 lstate.c |  3 ++-
 lstate.h |  5 +++--
 3 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/lgc.c b/lgc.c
index 435c5e48..9831dce9 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.123 2012/05/20 20:36:44 roberto Exp roberto $
+** $Id: lgc.c,v 2.124 2012/05/21 13:18:10 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -49,6 +49,7 @@
 #define workrate(x,mul)  \
 	((x) < MAX_INT/80 ? ((x) * 80) / mul : ((x) / mul) * 80)
 
+
 /*
 ** standard negative debt for GC; a reasonable "time" to wait before
 ** starting a new cycle
@@ -738,19 +739,16 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
       freeobj(L, curr);  /* erase 'curr' */
     }
     else {
+      if (testbits(marked, tostop))
+        return NULL;  /* stop sweeping this list */
       if (gch(curr)->tt == LUA_TTHREAD)
         sweepthread(L, gco2th(curr));  /* sweep thread's upvalues */
-      if (testbits(marked, tostop)) {
-        static GCObject *nullp = NULL;
-        p = &nullp;  /* stop sweeping this list */
-        break;
-      }
       /* update marks */
       gch(curr)->marked = cast_byte((marked & toclear) | toset);
       p = &gch(curr)->next;  /* go to next element */
     }
   }
-  return p;
+  return (*p == NULL) ? NULL : p;
 }
 
 /* }====================================================== */
@@ -865,7 +863,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
     GCObject **p;
     GCheader *ho = gch(o);
     /* avoid removing current sweep object */
-    if (g->gcstate == GCSsweep && g->sweepgc == &ho->next) {
+    if (g->sweepgc == &ho->next) {
       /* step to next object in the list */
       g->sweepgc = (ho->next == NULL) ? NULL : &gch(ho->next)->next;
     }
@@ -892,6 +890,24 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
 #define sweepphases  \
 	(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
 
+
+/*
+** enter first sweep phase (strings) and prepare pointers for other
+** sweep phases.  The calls to 'sweeplist' attempt to make pointers
+** point to an object inside the list (instead of to the header), so
+** that the real sweep do not need to skip objects created between "now"
+** and the start of the real sweep.
+*/
+static void entersweep (lua_State *L) {
+  global_State *g = G(L);
+  g->gcstate = GCSsweepstring;
+  lua_assert(g->sweepgc == NULL && g->sweepfin == NULL);
+  g->sweepstrgc = 0;  /* prepare to sweep strings, ... */
+  g->sweepfin = sweeplist(L, &g->finobj, 1);  /* finalizable objects, ... */
+  g->sweepgc = sweeplist(L, &g->allgc, 1);  /* and regular objects */
+}
+
+
 /*
 ** change GC mode
 */
@@ -907,9 +923,8 @@ void luaC_changemode (lua_State *L, int mode) {
   else {  /* change to incremental mode */
     /* sweep all objects to turn them back to white
        (as white has not changed, nothing extra will be collected) */
-    g->sweepstrgc = 0;
-    g->gcstate = GCSsweepstring;
     g->gckind = KGC_NORMAL;
+    entersweep(L);
     luaC_runtilstate(L, ~sweepphases);
   }
 }
@@ -972,9 +987,8 @@ static void atomic (lua_State *L) {
   /* clear values from resurrected weak tables */
   clearvalues(g, g->weak, origweak);
   clearvalues(g, g->allweak, origall);
-  g->sweepstrgc = 0;  /* prepare to sweep strings */
-  g->gcstate = GCSsweepstring;
   g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
+  entersweep(L);  /* prepare to sweep strings */
   /*lua_checkmemory(L);*/
 }
 
@@ -1010,25 +1024,22 @@ static lu_mem singlestep (lua_State *L) {
       for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
         sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
       g->sweepstrgc += i;
-      if (g->sweepstrgc >= g->strt.size) {  /* no more strings to sweep? */
-        g->sweepgc = &g->finobj;  /* prepare to sweep finalizable objects */
+      if (g->sweepstrgc >= g->strt.size)  /* no more strings to sweep? */
         g->gcstate = GCSsweepudata;
-      }
       return i * GCSWEEPCOST;
     }
     case GCSsweepudata: {
-      if (*g->sweepgc) {
-        g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
+      if (g->sweepfin) {
+        g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);
         return GCSWEEPMAX*GCSWEEPCOST;
       }
       else {
-        g->sweepgc = &g->allgc;  /* go to next phase */
         g->gcstate = GCSsweep;
         return 0;
       }
     }
     case GCSsweep: {
-      if (*g->sweepgc) {
+      if (g->sweepgc) {
         g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
         return GCSWEEPMAX*GCSWEEPCOST;
       }
@@ -1121,16 +1132,19 @@ 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 */
+  if (isemergency)  /* do not run finalizers during emergency GC */
+    g->gckind = KGC_EMERGENCY;
+  else {
+    g->gckind = KGC_NORMAL;
     callallpendingfinalizers(L, 1);
-  if (keepinvariant(g)) {  /* marking phase? */
+  }
+  if (someblack) {  /* 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) */
-    g->sweepstrgc = 0;
-    g->gcstate = GCSsweepstring;
+    entersweep(L);
   }
-  g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL;
   /* finish any pending sweep phase to start a new cycle */
   luaC_runtilstate(L, bitmask(GCSpause));
   /* run entire collector */
diff --git a/lstate.c b/lstate.c
index 0a61ea1a..fecd0fba 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.93 2012/02/01 21:57:15 roberto Exp roberto $
+** $Id: lstate.c,v 2.94 2012/05/11 14:06:07 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -292,6 +292,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->allgc = NULL;
   g->finobj = NULL;
   g->tobefnz = NULL;
+  g->sweepgc = g->sweepfin = NULL;
   g->gray = g->grayagain = NULL;
   g->weak = g->ephemeron = g->allweak = NULL;
   g->totalbytes = sizeof(LG);
diff --git a/lstate.h b/lstate.h
index 85359fe3..302834ab 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.77 2012/02/01 21:57:15 roberto Exp roberto $
+** $Id: lstate.h,v 2.78 2012/05/20 20:36:44 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -126,7 +126,8 @@ typedef struct global_State {
   int sweepstrgc;  /* position of sweep in `strt' */
   GCObject *allgc;  /* list of all collectable objects */
   GCObject *finobj;  /* list of collectable objects with finalizers */
-  GCObject **sweepgc;  /* current position of sweep */
+  GCObject **sweepgc;  /* current position of sweep in list 'allgc' */
+  GCObject **sweepfin;  /* current position of sweep in list 'finobj' */
   GCObject *gray;  /* list of gray objects */
   GCObject *grayagain;  /* list of objects to be traversed atomically */
   GCObject *weak;  /* list of tables with weak values */
-- 
cgit v1.2.3-55-g6feb