Browse Source

'luaC_linkupval' moved into 'lfunc.c' code + new way to control GC speed

Roberto Ierusalimschy 15 năm trước cách đây
mục cha
commit
aaa5d7adab
2 tập tin đã thay đổi với 80 bổ sung80 xóa
  1. 60 76
      lgc.c
  2. 20 4
      lgc.h

+ 60 - 76
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.79 2010/04/20 20:15:30 roberto Exp roberto $
+** $Id: lgc.c,v 2.80 2010/04/26 17:58:00 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -23,16 +23,19 @@
 #include "ltm.h"
 
 
-#define GCSTEPSIZE	1024u
+#define GCSTEPSIZE	1024
 #define GCSWEEPMAX	40
-#define GCSWEEPCOST	10
-#define GCFINALIZECOST	100
+#define GCSWEEPCOST	1
+#define GCFINALIZECOST	50
 #define GCROOTCOST	10
 #define GCATOMICCOST	1000
 
 
-#define issweepphase(g)  \
-	(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
+/*
+** standard negative debt for GC; a reasonable "time" to wait before
+** starting a new cycle
+*/
+#define stddebt(g)	(-cast(l_mem, g->totalbytes/100) * g->gcpause)
 
 
 /*
@@ -60,17 +63,6 @@
 #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
 		reallymarkobject(g, obj2gco(t)); }
 
-
-/*
-** macro to tell when main invariant (white objects cannot point to black
-** ones) must be kept. During a non-generational collection, the sweep
-** phase may brak 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.
-*/
-#define keepinvariant(g)  (g->gckind == KGC_GEN || g->gcstate == GCSpropagate)
-
 static void reallymarkobject (global_State *g, GCObject *o);
 
 
@@ -142,9 +134,15 @@ void luaC_barrierback (lua_State *L, Table *t) {
   global_State *g = G(L);
   GCObject *o = obj2gco(t);
   lua_assert(isblack(o) && !isdead(g, o));
-  black2gray(o);  /* make table gray (again) */
-  t->gclist = g->grayagain;
-  g->grayagain = o;
+  if (keepinvariant(g)) {
+    black2gray(o);  /* make table gray (again) */
+    t->gclist = g->grayagain;
+    g->grayagain = o;
+  }
+  else {  /* sweep phase */
+    lua_assert(issweepphase(g));
+    makewhite(g, o);  /* mark main obj. as white to avoid other barriers */
+  }
 }
 
 
@@ -166,23 +164,6 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
   return o;
 }
 
-
-/*
-** link an upvalue back to the main root list. (It was previously in the
-** list of open upvalues of some thread.)
-*/
-void luaC_linkupval (lua_State *L, UpVal *uv) {
-  global_State *g = G(L);
-  GCObject *o = obj2gco(uv);
-  gch(o)->next = g->allgc;  /* link upvalue into `allgc' list */
-  g->allgc = o;
-  lua_assert(!isblack(o));  /* open upvalues are never black */
-  if (isgray(o)) {  /* is it marked? */
-    gray2black(o);  /* could not be black; now it can */
-    luaC_barrier(L, uv, uv->v);
-  }
-}
-
 /* }====================================================== */
 
 
@@ -287,9 +268,9 @@ static void remarkupvals (global_State *g) {
 */
 static void markroot (lua_State *L) {
   global_State *g = G(L);
-  g->gray = NULL;
-  g->grayagain = NULL;
-  g->weak = g->ephemeron = g->allweak = NULL;
+  lua_assert(g->gckind == KGC_GEN ||
+    (g->gray == NULL && g->grayagain == NULL && g->weak == NULL &&
+     g->allweak == NULL && g->ephemeron == NULL));
   markobject(g, g->mainthread);
   markvalue(g, &g->l_registry);
   markmt(g);
@@ -372,7 +353,7 @@ static void traversestrongtable (global_State *g, Table *h) {
 }
 
 
-static void traversetable (global_State *g, Table *h) {
+static int traversetable (global_State *g, Table *h) {
   const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
   markobject(g, h->metatable);
   if (mode && ttisstring(mode)) {  /* is there a weak mode? */
@@ -380,20 +361,26 @@ static void traversetable (global_State *g, Table *h) {
     int weakvalue = (strchr(svalue(mode), 'v') != NULL);
     if (weakkey || weakvalue) {  /* is really weak? */
       black2gray(obj2gco(h));  /* keep table gray */
-      if (!weakkey)  /* strong keys? */
+      if (!weakkey) {  /* strong keys? */
         traverseweakvalue(g, h);
-      else if (!weakvalue)  /* strong values? */
+        return 1 + sizenode(h);
+      }
+      else if (!weakvalue) {  /* strong values? */
         traverseephemeron(g, h);
-      else
+        return 1 + h->sizearray + sizenode(h);
+      }
+      else {
         linktable(h, &g->allweak);  /* nothing to traverse now */
-      return;
+        return 1;
+      }
     }  /* else go through */
   }
   traversestrongtable(g, h);
+  return 1 + h->sizearray + (2 * sizenode(h));
 }
 
 
-static void traverseproto (global_State *g, Proto *f) {
+static int traverseproto (global_State *g, Proto *f) {
   int i;
   stringmark(f->source);
   for (i = 0; i < f->sizek; i++)  /* mark literals */
@@ -404,6 +391,7 @@ static void traverseproto (global_State *g, Proto *f) {
     markobject(g, f->p[i]);
   for (i = 0; i < f->sizelocvars; i++)  /* mark local-variable names */
     stringmark(f->locvars[i].varname);
+  return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
 }
 
 
@@ -425,26 +413,27 @@ static l_mem traverseclosure (global_State *g, Closure *cl) {
 }
 
 
-static void traversestack (global_State *g, lua_State *L) {
-  StkId o;
+static int traversestack (global_State *g, lua_State *L) {
+  StkId o = L->stack;
   if (L->stack == NULL)
-    return;  /* stack not completely built yet */
-  for (o = L->stack; o < L->top; o++)
+    return 1;  /* stack not completely built yet */
+  for (; o < L->top; o++)
     markvalue(g, o);
   if (g->gcstate == GCSatomic) {  /* final traversal? */
     StkId lim = L->stack + L->stacksize;  /* real end of stack */
     for (; o < lim; o++)  /* clear not-marked stack slice */
       setnilvalue(o);
   }
+  return 1 + cast_int(o - L->stack);
 }
 
 
 /*
 ** traverse one gray object, turning it to black (except for threads,
 ** which are always gray).
-** Returns 'quantity' traversed.
+** Returns number of values traversed.
 */
-static l_mem propagatemark (global_State *g) {
+static int propagatemark (global_State *g) {
   GCObject *o = g->gray;
   lua_assert(isgray(o));
   gray2black(o);
@@ -452,9 +441,7 @@ static l_mem propagatemark (global_State *g) {
     case LUA_TTABLE: {
       Table *h = gco2t(o);
       g->gray = h->gclist;
-      traversetable(g, h);
-      return sizeof(Table) + sizeof(TValue) * h->sizearray +
-                             sizeof(Node) * sizenode(h);
+      return traversetable(g, h);
     }
     case LUA_TFUNCTION: {
       Closure *cl = gco2cl(o);
@@ -467,19 +454,12 @@ static l_mem propagatemark (global_State *g) {
       th->gclist = g->grayagain;
       g->grayagain = o;
       black2gray(o);
-      traversestack(g, th);
-      return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
+      return traversestack(g, th);
     }
     case LUA_TPROTO: {
       Proto *p = gco2p(o);
       g->gray = p->gclist;
-      traverseproto(g, p);
-      return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
-                             sizeof(Proto *) * p->sizep +
-                             sizeof(TValue) * p->sizek +
-                             sizeof(int) * p->sizelineinfo +
-                             sizeof(LocVar) * p->sizelocvars +
-                             sizeof(TString *) * p->sizeupvalues;
+      return traverseproto(g, p);
     }
     default: lua_assert(0); return 0;
   }
@@ -673,15 +653,15 @@ static void GCTM (lua_State *L, int propagateerrors) {
   if (tm != NULL && ttisfunction(tm)) {  /* is there a finalizer? */
     int status;
     lu_byte oldah = L->allowhook;
-    lu_mem oldt = g->GCthreshold;
+    lu_mem oldd = g->GCdebt;
     L->allowhook = 0;  /* stop debug hooks during GC tag method */
-    g->GCthreshold = 2 * g->totalbytes;  /* avoid GC steps */
+    g->GCdebt = -2 * g->totalbytes;  /* avoid GC steps */
     setobj2s(L, L->top, tm);  /* push finalizer... */
     setuvalue(L, L->top+1, udata);  /* ... and its argument */
     L->top += 2;  /* and (next line) call the finalizer */
     status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
     L->allowhook = oldah;  /* restore hooks */
-    g->GCthreshold = oldt;  /* restore threshold */
+    g->GCdebt = oldd;  /* restore threshold */
     if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */
       if (status == LUA_ERRRUN) {  /* is there an error msg.? */
         luaO_pushfstring(L, "error in __gc tag method (%s)",
@@ -791,7 +771,13 @@ static void atomic (lua_State *L) {
   cleartable(g->weak);
   cleartable(g->ephemeron);
   cleartable(g->allweak);
+  lua_checkmemory(L);
   g->currentwhite = cast_byte(otherwhite(g));  /* flip current white */
+  if (g->gckind != KGC_GEN) {
+    g->gray = NULL;  /* all gray objects will become white */
+    g->grayagain = NULL;
+    g->weak = g->ephemeron = g->allweak = NULL;
+  }
 }
 
 
@@ -890,23 +876,18 @@ static void generationalcollection (lua_State *L) {
     if (g->totalbytes > g->lastmajormem/100 * g->gcpause)
       g->lastmajormem = 0;  /* signal for a major collection */
   }
-  g->GCthreshold = (g->totalbytes/100) * g->gcpause;
+  g->GCdebt = stddebt(g);
 }
 
 
 static void step (lua_State *L) {
   global_State *g = G(L);
-  l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;  /* how much to work */
-  lu_mem debt = g->totalbytes - g->GCthreshold;
+  l_mem lim = g->gcstepmul;  /* how much to work */
   lua_assert(g->gckind == KGC_NORMAL);
   do {  /* always perform at least one single step */
     lim -= singlestep(L);
   } while (lim > 0 && g->gcstate != GCSpause);
-  g->GCthreshold =  (g->gcstate != GCSpause)
-                       ? g->totalbytes + GCSTEPSIZE
-                       : (g->totalbytes/100) * g->gcpause;
-  /* compensate if GC is "behind schedule" (has some debt to pay) */
-  if (g->GCthreshold > debt) g->GCthreshold -= debt;
+  g->GCdebt += (g->gcstate != GCSpause) ? -GCSTEPSIZE : stddebt(g);
 }
 
 
@@ -930,6 +911,9 @@ void luaC_fullgc (lua_State *L, int isemergency) {
        (as white has not changed, nothing will be collected) */
     g->sweepstrgc = 0;
     g->gcstate = GCSsweepstring;
+    g->gray = NULL;
+    g->grayagain = NULL;
+    g->weak = g->ephemeron = g->allweak = NULL;
   }
   /* finish any pending sweep phase */
   luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize));
@@ -943,7 +927,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
     g->gcstate = GCSpause;  /* collector must be always in... */
     luaC_runtilstate(L, bitmask(GCSpropagate));  /* ...propagate phase */
   }
-  g->GCthreshold = (g->totalbytes/100) * g->gcpause;
+  g->GCdebt = stddebt(g);
 }
 
 /* }====================================================== */

+ 20 - 4
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.29 2010/03/24 15:51:10 roberto Exp roberto $
+** $Id: lgc.h,v 2.30 2010/03/25 13:06:36 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -23,6 +23,24 @@
 #define GCSfinalize	6
 
 
+#define issweepphase(g)  \
+	(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
+
+
+/*
+** macro to tell when main invariant (white objects cannot point to black
+** ones) must be kept. During a non-generational collection, the sweep
+** phase may brak 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.
+*/
+#define keepinvariant(g)  (g->gckind == KGC_GEN || g->gcstate == GCSpropagate)
+
+
+#define gcstopped(g)	((g)->GCdebt == MIN_LMEM)
+#define stopgc(g)	((g)->GCdebt = MIN_LMEM)
+
 
 /*
 ** some useful bit tricks
@@ -76,8 +94,7 @@
 #define luaC_white(g)	cast(lu_byte, (g)->currentwhite & WHITEBITS)
 
 
-#define luaC_checkGC(L) \
-  {condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);}
+#define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);}
 
 
 #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p)))  \
@@ -100,7 +117,6 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
 LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
 LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
                                  GCObject **list, int offset);
-LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
 LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
 LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
 LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u);