Przeglądaj źródła

weak keys are removed only after finalization

Roberto Ierusalimschy 23 lat temu
rodzic
commit
9f4b5b5232
3 zmienionych plików z 53 dodań i 15 usunięć
  1. 44 10
      lgc.c
  2. 1 4
      lobject.h
  3. 8 1
      ltm.h

+ 44 - 10
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 1.138 2002/06/24 17:19:43 roberto Exp roberto $
+** $Id: lgc.c,v 1.139 2002/06/25 19:17:42 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -31,6 +31,17 @@ typedef struct GCState {
 #define strmark(s)    {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;}
 
 
+/* unmarked tables are represented by pointing `mark' to themselves */
+#define ismarked(x)	((x)->mark != (x))
+
+
+/* `Table.flag' bits to indicate whether table is key-weak and/or value-weak */
+#define KEYWEAKBIT	(TM_MODE+1)		/* ORDER TM */
+#define VALUEWEAKBIT	(TM_MODE+2)
+#define KEYWEAK         (1<<KEYWEAKBIT)
+#define VALUEWEAK       (1<<VALUEWEAKBIT)
+
+
 /* mark tricks for userdata */
 #define isudmarked(u)	(u->uv.len & 1)
 #define markud(u)	(u->uv.len |= 1)
@@ -202,8 +213,8 @@ static void separateudata (lua_State *L) {
 
 
 static void removekey (Node *n) {
-  lua_assert(ttype(val(n)) == LUA_TNIL);
-  if (ttype(key(n)) != LUA_TNIL && ttype(key(n)) != LUA_TNUMBER)
+  setnilvalue(val(n));  /* remove corresponding value ... */
+  if (ismarkable(key(n)))
     setttype(key(n), LUA_TNONE);  /* dead key; remove it */
 }
 
@@ -221,6 +232,8 @@ static void traversetable (GCState *st, Table *h) {
     st->toclear = h;  /* ...put in the appropriate list */
     weakkey = (strchr(svalue(mode), 'k') != NULL);
     weakvalue = (strchr(svalue(mode), 'v') != NULL);
+    h->flags &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */
+    h->flags |= (weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT);
   }
   if (!weakvalue) {
     i = sizearray(h);
@@ -265,11 +278,33 @@ static int hasmark (const TObject *o) {
 
 
 /*
-** clear (set to nil) keys and values from weaktables that were collected
+** clear collected keys from weaktables
 */
-static void cleartables (Table *h) {
-  for (; h; h = h->mark) {
+static void cleartablekeys (GCState *st) {
+  Table *h;
+  for (h = st->toclear; h; h = h->mark) {
     int i;
+    if (!(h->flags & KEYWEAK)) continue;
+    lua_assert(strchr(svalue(fasttm(st->L, h->metatable, TM_MODE)), 'k'));
+    i = sizenode(h);
+    while (i--) {
+      Node *n = node(h, i);
+      if (!hasmark(key(n)))
+        removekey(n);  /* ... and key */
+    }
+  }
+}
+
+
+/*
+** clear collected values from weaktables
+*/
+static void cleartablevalues (GCState *st) {
+  Table *h;
+  for (h = st->toclear; h; h = h->mark) {
+    int i;
+    if (!(h->flags & VALUEWEAK)) continue;
+    lua_assert(strchr(svalue(fasttm(st->L, h->metatable, TM_MODE)), 'v'));
     i = sizearray(h);
     while (i--) {
       TObject *o = &h->array[i];
@@ -279,10 +314,8 @@ static void cleartables (Table *h) {
     i = sizenode(h);
     while (i--) {
       Node *n = node(h, i);
-      if (!hasmark(val(n)) || !hasmark(key(n))) {
-        setnilvalue(val(n));  /* remove value ... */
+      if (!hasmark(val(n)))
         removekey(n);  /* ... and key */
-      }
     }
   }
 }
@@ -458,10 +491,11 @@ void luaC_collectgarbage (lua_State *L) {
   st.toclear = NULL;
   markstacks(&st); /* mark all stacks */
   propagatemarks(&st);  /* mark all reachable objects */
-  cleartables(st.toclear);
+  cleartablevalues(&st);
   separateudata(L);  /* separate userdata to be preserved */
   marktmu(&st);  /* mark `preserved' userdata */
   propagatemarks(&st);  /* remark */
+  cleartablekeys(&st);
   luaC_collect(L, 0);
   checkMbuffer(L);
   G(L)->GCthreshold = 2*G(L)->nblocks;  /* new threshold */

+ 1 - 4
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 1.137 2002/06/24 13:08:45 roberto Exp roberto $
+** $Id: lobject.h,v 1.138 2002/06/24 20:17:59 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -217,9 +217,6 @@ typedef struct Table {
 } Table;
 
 
-/* unmarked tables are represented by pointing `mark' to themselves */
-#define ismarked(x)	((x)->mark != (x))
-
 
 /*
 ** `module' operation for hashing (size is always a power of 2)

+ 8 - 1
ltm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.h,v 1.36 2002/06/24 20:17:59 roberto Exp roberto $
+** $Id: ltm.h,v 1.37 2002/06/25 19:17:22 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -10,6 +10,13 @@
 
 #include "lobject.h"
 
+
+/*
+** Important: garbage collection uses two extra bits of `Table.flags'
+** (after TM_MODE), so the maximum number of `fast tag methods' is six
+** (at least while `flags' is a byte).
+*/
+
 /*
 * WARNING: if you change the order of this enumeration,
 * grep "ORDER TM"