Browse Source

double-linked list of all upvalues elliminated and changed to a
traversal of all non-marked threads

Roberto Ierusalimschy 12 years ago
parent
commit
623e388bb4
7 changed files with 47 additions and 72 deletions
  1. 7 27
      lfunc.c
  2. 1 2
      lfunc.h
  3. 16 9
      lgc.c
  4. 2 8
      lobject.h
  5. 4 4
      lstate.c
  6. 10 10
      lstate.h
  7. 7 12
      ltests.c

+ 7 - 27
lfunc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lfunc.c,v 2.30 2012/10/03 12:36:46 roberto Exp roberto $
+** $Id: lfunc.c,v 2.31 2013/08/05 16:58:28 roberto Exp roberto $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */
@@ -38,7 +38,7 @@ Closure *luaF_newLclosure (lua_State *L, int n) {
 
 UpVal *luaF_newupval (lua_State *L) {
   UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
-  uv->v = &uv->u.value;
+  uv->v = &uv->value;
   setnilvalue(uv->v);
   return uv;
 }
@@ -51,7 +51,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
   UpVal *uv;
   while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
     GCObject *o = obj2gco(p);
-    lua_assert(p->v != &p->u.value);
+    lua_assert(p->v != &p->value);
     if (p->v == level) {  /* found a corresponding upvalue? */
       if (isdead(g, o))  /* is it dead? */
         changewhite(o);  /* resurrect it */
@@ -62,42 +62,22 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
   /* not found: create a new one */
   uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
   uv->v = level;  /* current value lives in the stack */
-  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;
-  g->uvhead.u.l.next = uv;
-  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
   return uv;
 }
 
 
-static void unlinkupval (UpVal *uv) {
-  lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
-  uv->u.l.next->u.l.prev = uv->u.l.prev;  /* remove from `uvhead' list */
-  uv->u.l.prev->u.l.next = uv->u.l.next;
-}
-
-
-void luaF_freeupval (lua_State *L, UpVal *uv) {
-  if (uv->v != &uv->u.value)  /* is it open? */
-    unlinkupval(uv);  /* remove from open list */
-  luaM_free(L, uv);  /* free upvalue */
-}
-
-
 void luaF_close (lua_State *L, StkId level) {
   UpVal *uv;
   global_State *g = G(L);
   while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
     GCObject *o = obj2gco(uv);
-    lua_assert(!isblack(o) && uv->v != &uv->u.value);
+    lua_assert(!isblack(o) && uv->v != &uv->value);
     L->openupval = uv->next;  /* remove from `open' list */
     if (isdead(g, o))
-      luaF_freeupval(L, uv);  /* free upvalue */
+      luaM_free(L, uv);  /* free upvalue */
     else {
-      unlinkupval(uv);  /* remove upvalue from 'uvhead' list */
-      setobj(L, &uv->u.value, uv->v);  /* move value to upvalue slot */
-      uv->v = &uv->u.value;  /* now current value lives here */
+      setobj(L, &uv->value, uv->v);  /* move value to upvalue slot */
+      uv->v = &uv->value;  /* now current value lives here */
       gch(o)->next = g->allgc;  /* link upvalue into 'allgc' list */
       g->allgc = o;
       luaC_checkupvalcolor(g, uv);

+ 1 - 2
lfunc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lfunc.h,v 2.7 2012/01/20 22:05:50 roberto Exp roberto $
+** $Id: lfunc.h,v 2.8 2012/05/08 13:53:33 roberto Exp roberto $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */
@@ -25,7 +25,6 @@ LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
 LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
 LUAI_FUNC void luaF_close (lua_State *L, StkId level);
 LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
-LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
 LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
                                          int pc);
 

+ 16 - 9
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.141 2013/04/26 18:26:49 roberto Exp roberto $
+** $Id: lgc.c,v 2.142 2013/08/05 16:58:28 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -258,7 +258,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
     case LUA_TUPVAL: {
       UpVal *uv = gco2uv(o);
       markvalue(g, uv->v);
-      if (uv->v != &uv->u.value)  /* open? */
+      if (uv->v != &uv->value)  /* open? */
         return;  /* open upvalues remain gray */
       size = sizeof(UpVal);
       break;
@@ -317,14 +317,21 @@ static void markbeingfnz (global_State *g) {
 
 
 /*
-** mark all values stored in marked open upvalues. (See comment in
-** 'lstate.h'.)
+** Mark all values stored in marked open upvalues from non-marked threads.
+** (Values from marked threads were already marked when traversing the
+** thread.)
 */
 static void remarkupvals (global_State *g) {
-  UpVal *uv;
-  for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
-    if (isgray(obj2gco(uv)))
-      markvalue(g, uv->v);
+  GCObject *thread = hvalue(&g->l_registry)->next;
+  for (; thread != NULL; thread = gch(thread)->next) {
+    lua_assert(!isblack(thread));  /* threads are never black */
+    if (!isgray(thread)) {  /* dead thread? */
+      GCObject *uv = gco2th(thread)->openupval;
+      for (; uv != NULL; uv = gch(uv)->next) {
+        if (isgray(uv))  /* marked? */
+          markvalue(g, gco2uv(uv)->v);  /* remark upvalue's value */
+      }
+    }
   }
 }
 
@@ -669,7 +676,7 @@ static void freeobj (lua_State *L, GCObject *o) {
       luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
       break;
     }
-    case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
+    case LUA_TUPVAL: luaM_free(L, gco2uv(o)); break;
     case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
     case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
     case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;

+ 2 - 8
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 2.77 2013/05/06 17:17:09 roberto Exp roberto $
+** $Id: lobject.h,v 2.78 2013/05/14 15:59:04 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -395,13 +395,7 @@ typedef struct Proto {
 typedef struct UpVal {
   CommonHeader;
   TValue *v;  /* points to stack or to its own value */
-  union {
-    TValue value;  /* the value (when closed) */
-    struct {  /* double linked list (when open) */
-      struct UpVal *prev;
-      struct UpVal *next;
-    } l;
-  } u;
+  TValue value;  /* the value (when closed) */
 } UpVal;
 
 

+ 4 - 4
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.99 2012/10/02 17:40:53 roberto Exp roberto $
+** $Id: lstate.c,v 2.100 2013/08/05 16:58:28 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -230,7 +230,9 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
   lua_State *L1;
   lua_lock(L);
   luaC_checkGC(L);
-  L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX), NULL, offsetof(LX, l))->th;
+  /* create new thread, linked after 'l_registry' */
+  L1 = &luaC_newobj(L, LUA_TTHREAD, sizeof(LX),
+         &hvalue(&G(L)->l_registry)->next, offsetof(LX, l))->th;
   setthvalue(L, L->top, L1);
   api_incr_top(L);
   preinit_state(L1, G(L));
@@ -273,8 +275,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->ud = ud;
   g->mainthread = L;
   g->seed = makeseed(L);
-  g->uvhead.u.l.prev = &g->uvhead;
-  g->uvhead.u.l.next = &g->uvhead;
   g->gcrunning = 0;  /* no GC while building state */
   g->GCestimate = 0;
   g->strt.size = 0;

+ 10 - 10
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.82 2012/07/02 13:37:04 roberto Exp roberto $
+** $Id: lstate.h,v 2.83 2013/08/05 16:58:28 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -20,17 +20,18 @@
 ** be kept somehow accessible until being freed.
 **
 ** Lua keeps most objects linked in list g->allgc. The link uses field
-** 'next' of the CommonHeader.
+** 'next' of the CommonHeader. Threads (except the main one) ar kept
+** at the end of the 'allgc' list, after the 'l_registry' (which is
+** the first object to be added to the list).
 **
-** Strings are kept in several lists headed by the array g->strt.hash.
+** Short strings are kept in several lists headed by the array g->strt.hash.
 **
 ** Open upvalues are not subject to independent garbage collection. They
-** are collected together with their respective threads. Lua keeps a
-** double-linked list with all open upvalues (g->uvhead) so that it can
-** mark objects referred by them. (They are always gray, so they must
-** be remarked in the atomic step. Usually their contents would be marked
-** when traversing the respective threads, but the thread may already be
-** dead, while the upvalue is still accessible through closures.)
+** are collected together with their respective threads. (They are
+** always gray, so they must be remarked in the atomic step. Usually
+** their contents would be marked when traversing the respective
+** threads, but the thread may already be dead, while the upvalue is
+** still accessible through closures.)
 **
 ** Objects with finalizers are kept in the list g->finobj.
 **
@@ -133,7 +134,6 @@ typedef struct global_State {
   GCObject *ephemeron;  /* list of ephemeron tables (weak keys) */
   GCObject *allweak;  /* list of all-weak tables */
   GCObject *tobefnz;  /* list of userdata to be GC */
-  UpVal uvhead;  /* head of double-linked list of all open upvalues */
   Mbuffer buff;  /* temporary buffer for string concatenation */
   int gcpause;  /* size of pause between successive GCs */
   int gcstepmul;  /* GC `granularity' */

+ 7 - 12
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.139 2013/06/20 21:59:13 roberto Exp roberto $
+** $Id: ltests.c,v 2.140 2013/08/05 16:58:28 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -310,7 +310,7 @@ static void checkstack (global_State *g, lua_State *L1) {
   lua_assert(!isdead(g, obj2gco(L1)));
   for (uvo = L1->openupval; uvo != NULL; uvo = gch(uvo)->next) {
     UpVal *uv = gco2uv(uvo);
-    lua_assert(uv->v != &uv->u.value);  /* must be open */
+    lua_assert(uv->v != &uv->value);  /* must be open */
     lua_assert(!isblack(uvo));  /* open upvalues cannot be black */
   }
   for (ci = L1->ci; ci != NULL; ci = ci->previous) {
@@ -334,7 +334,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) {
     switch (gch(o)->tt) {
       case LUA_TUPVAL: {
         UpVal *uv = gco2uv(o);
-        lua_assert(uv->v == &uv->u.value);  /* must be closed */
+        lua_assert(uv->v == &uv->value);  /* must be closed */
         lua_assert(!isgray(o));  /* closed upvalues are never gray */
         checkvalref(g, o, uv->v);
         break;
@@ -419,8 +419,8 @@ static void checkgray (global_State *g, GCObject *o) {
 int lua_checkmemory (lua_State *L) {
   global_State *g = G(L);
   GCObject *o;
-  UpVal *uv;
   int maybedead;
+  int isthread;
   if (keepinvariant(g)) {
     lua_assert(!iswhite(obj2gco(g->mainthread)));
     lua_assert(!iswhite(gcvalue(&g->l_registry)));
@@ -433,9 +433,12 @@ int lua_checkmemory (lua_State *L) {
   checkgray(g, g->allgc);
   lua_assert(g->sweepgc == NULL || issweepphase(g));
   maybedead = 0;
+  isthread = 0;  /* not traversing threads (yet) */  
   for (o = g->allgc; o != NULL; o = gch(o)->next) {
     if (g->sweepgc && o == *g->sweepgc)
       maybedead = 1;  /* part of the list not yet swept */
+    if (gch(o)->tt == LUA_TTHREAD) isthread = 1;  /* now travesing threads... */
+    else lua_assert(!isthread);  /* ... and only threads */
     checkobject(g, o, maybedead);
     lua_assert(!testbit(o->gch.marked, SEPARATED));
   }
@@ -455,14 +458,6 @@ int lua_checkmemory (lua_State *L) {
     lua_assert(gch(o)->tt == LUA_TUSERDATA ||
                gch(o)->tt == LUA_TTABLE);
   }
-  /* check 'uvhead' list */
-  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 */
-    if (!isdead(g, obj2gco(uv)))
-      checkvalref(g, obj2gco(uv), uv->v);
-  }
   return 0;
 }