Browse Source

better control over GC collors of upvalues

Roberto Ierusalimschy 20 years ago
parent
commit
621ef9f767
3 changed files with 26 additions and 6 deletions
  1. 9 3
      lfunc.c
  2. 2 1
      lgc.h
  3. 15 2
      ltests.c

+ 9 - 3
lfunc.c

@@ -56,7 +56,11 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
   UpVal *uv;
   while ((p = ngcotouv(*pp)) != NULL && p->v >= level) {
     lua_assert(p->v != &p->u.value);
-    if (p->v == level) return p;
+    if (p->v == level) {  /* found a corresponding upvalue? */
+      if (isdead(G(L), obj2gco(p)))  /* is it dead? */
+        changewhite(obj2gco(p));  /* ressurect it */
+      return p;
+    }
     pp = &p->next;
   }
   uv = luaM_new(L, UpVal);  /* not found: create a new one */
@@ -65,8 +69,6 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
   uv->v = level;  /* current value lives in the stack */
   uv->next = *pp;  /* chain it in the proper position */
   *pp = obj2gco(uv);
-  lua_assert(g->uvhead.u.l.next->u.l.prev == &g->uvhead &&
-             g->uvhead.u.l.prev->u.l.next == &g->uvhead);
   uv->u.l.prev = &g->uvhead;  /* double link it in `uvhead' list */
   uv->u.l.next = g->uvhead.u.l.next;
   uv->u.l.next->u.l.prev = uv;
@@ -102,6 +104,10 @@ void luaF_close (lua_State *L, StkId level) {
     else {
       unlinkupval(uv);
       setobj(L, &uv->u.value, uv->v);
+      if (isgray(o)) {
+        gray2black(o);  /* closed upvalues are never gray */
+        luaC_barrier(L, uv, uv->v);
+      }
       uv->v = &uv->u.value;  /* now current value lives here */
       luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */
     }

+ 2 - 1
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.8 2004/08/30 13:44:44 roberto Exp roberto $
+** $Id: lgc.h,v 2.9 2004/09/15 20:38:15 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -66,6 +66,7 @@
 #define isdead(g,v)	((v)->gch.marked & otherwhite(g))
 
 #define changewhite(x)	((x)->gch.marked ^= bit2mask(WHITE0BIT, WHITE1BIT))
+#define gray2black(x)	setbit((x)->gch.marked, BLACKBIT)
 
 #define valiswhite(x)	(iscollectable(x) && iswhite(gcvalue(x)))
 

+ 15 - 2
ltests.c

@@ -272,7 +272,13 @@ static void checkclosure (global_State *g, Closure *cl) {
 static void checkstack (global_State *g, lua_State *L1) {
   StkId o;
   CallInfo *ci;
+  GCObject *uvo;
   lua_assert(!isdead(g, obj2gco(L1)));
+  for (uvo = L1->openupval; uvo != NULL; uvo = uvo->gch.next) {
+    UpVal *uv = gco2uv(uvo);
+    lua_assert(uv->v != &uv->u.value);  /* must be open */
+    lua_assert(!isblack(uvo));  /* open upvalues cannot be black */
+  }
   checkliveness(g, gt(L1));
   if (L1->base_ci) {
     for (ci = L1->base_ci; ci <= L1->ci; ci++)
@@ -300,6 +306,7 @@ printf(">>> %d  %s  %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marke
       case LUA_TUPVAL: {
         UpVal *uv = gco2uv(o);
         lua_assert(uv->v == &uv->u.value);  /* must be closed */
+        lua_assert(!isgray(o));  /* closed upvalues are never gray */
         checkvalref(g, o, uv->v);
         break;
       }
@@ -333,14 +340,20 @@ printf(">>> %d  %s  %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marke
 int lua_checkmemory (lua_State *L) {
   global_State *g = G(L);
   GCObject *o;
+  UpVal *uv;
   checkstack(g, g->mainthread);
   for (o = g->rootgc; o != obj2gco(g->mainthread); o = o->gch.next)
     checkobject(g, o);
-  checkobject(g, obj2gco(g->mainthread));
-  for (o = g->mainthread->next; o != NULL; o = o->gch.next) {
+  for (o = o->gch.next; o != NULL; o = o->gch.next) {
     lua_assert(o->gch.tt == LUA_TUSERDATA);
     checkobject(g, o);
   }
+  for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
+    lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+    lua_assert(uv->v != &uv->u.value);  /* must be open */
+    lua_assert(!isblack(obj2gco(uv)));  /* open upvalues are never black */
+    checkvalref(g, obj2gco(uv), uv->v);
+  }
   return 0;
 }