From ac27b7a84287a80488e3e34d4fa179df0b67c37c Mon Sep 17 00:00:00 2001
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Mon, 11 Nov 2002 09:52:43 -0200
Subject: avoid traversing extra elements when cleaning weak tables

---
 lgc.c | 73 +++++++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 40 insertions(+), 33 deletions(-)

(limited to 'lgc.c')

diff --git a/lgc.c b/lgc.c
index 840bc796..6fd41d34 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 1.154 2002/10/25 20:05:28 roberto Exp roberto $
+** $Id: lgc.c,v 1.155 2002/11/07 15:37:10 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -22,7 +22,9 @@
 
 typedef struct GCState {
   Table *tmark;  /* list of marked tables to be visited */
-  Table *toclear;  /* list of visited weak tables (to be cleared after GC) */
+  Table *wk;  /* list of visited key-weak tables (to be cleared after GC) */
+  Table *wv;  /* list of visited value-weak tables */
+  Table *wkv;  /* list of visited key-value weak tables */
   lua_State *L;
 } GCState;
 
@@ -198,10 +200,14 @@ static void traversetable (GCState *st, Table *h) {
   marktable(st, h->metatable);
   lua_assert(h->lsizenode || h->node == G(st->L)->dummynode);
   if (h->mode & (WEAKKEY | WEAKVALUE)) {  /* weak table? */
+    Table **weaklist;
     weakkey = h->mode & WEAKKEY;
     weakvalue = h->mode & WEAKVALUE;
-    h->gclist = st->toclear;  /* must be cleared after GC, ... */
-    st->toclear = h;  /* ... so put in the appropriate list */
+    weaklist = (weakkey && weakvalue) ? &st->wkv :
+                            (weakkey) ? &st->wk :
+                                        &st->wv;
+    h->gclist = *weaklist;  /* must be cleared after GC, ... */
+    *weaklist = h;  /* ... so put in the appropriate list */
   }
   if (!weakvalue) {
     i = sizearray(h);
@@ -241,14 +247,12 @@ static int valismarked (const TObject *o) {
 */
 static void cleartablekeys (Table *h) {
   for (; h; h = h->gclist) {
-    lua_assert(h->mode & (WEAKKEY | WEAKVALUE));
-    if ((h->mode & WEAKKEY)) {  /* table may have collected keys? */
-      int i = sizenode(h);
-      while (i--) {
-        Node *n = node(h, i);
-        if (!valismarked(key(n)))  /* key was collected? */
-          removekey(n);  /* remove entry from table */
-      }
+    int i = sizenode(h);
+    lua_assert(h->mode & WEAKKEY);
+    while (i--) {
+      Node *n = node(h, i);
+      if (!valismarked(key(n)))  /* key was collected? */
+        removekey(n);  /* remove entry from table */
     }
   }
 }
@@ -259,19 +263,18 @@ static void cleartablekeys (Table *h) {
 */
 static void cleartablevalues (Table *h) {
   for (; h; h = h->gclist) {
-    if ((h->mode & WEAKVALUE)) {  /* table may have collected values? */
-      int i = sizearray(h);
-      while (i--) {
-        TObject *o = &h->array[i];
-        if (!valismarked(o))  /* value was collected? */
-          setnilvalue(o);  /* remove value */
-      }
-      i = sizenode(h);
-      while (i--) {
-        Node *n = node(h, i);
-        if (!valismarked(val(n)))  /* value was collected? */
-          removekey(n);  /* remove entry from table */
-      }
+    int i = sizearray(h);
+    lua_assert(h->mode & WEAKVALUE);
+    while (i--) {
+      TObject *o = &h->array[i];
+      if (!valismarked(o))  /* value was collected? */
+        setnilvalue(o);  /* remove value */
+    }
+    i = sizenode(h);
+    while (i--) {
+      Node *n = node(h, i);
+      if (!valismarked(val(n)))  /* value was collected? */
+        removekey(n);  /* remove entry from table */
     }
   }
 }
@@ -398,22 +401,26 @@ static void markroot (GCState *st) {
 
 static void mark (lua_State *L) {
   GCState st;
-  Table *toclear;
+  Table *wkv;
   st.L = L;
   st.tmark = NULL;
-  st.toclear = NULL;
+  st.wkv = st.wk = st.wv = NULL;
   markroot(&st);
   propagatemarks(&st);  /* mark all reachable objects */
-  toclear = st.toclear;  /* weak tables; to be cleared */
-  st.toclear = NULL;
-  cleartablevalues(toclear);
+  cleartablevalues(st.wkv);
+  cleartablevalues(st.wv);
+  wkv = st.wkv;  /* keys must be cleared after preserving udata */
+  st.wkv = NULL;
+  st.wv = NULL;
   separateudata(L);  /* separate userdata to be preserved */
   marktmu(&st);  /* mark `preserved' userdata */
   propagatemarks(&st);  /* remark, to propagate `preserveness' */
-  cleartablekeys(toclear);
+  cleartablekeys(wkv);
   /* `propagatemarks' may reborne some weak tables; clear them too */
-  cleartablekeys(st.toclear);
-  cleartablevalues(st.toclear);
+  cleartablekeys(st.wk);
+  cleartablevalues(st.wv);
+  cleartablekeys(st.wkv);
+  cleartablevalues(st.wkv);
 }
 
 
-- 
cgit v1.2.3-55-g6feb