From 12d78e2577eabdc36cae04bbfc08b66af777c0b7 Mon Sep 17 00:00:00 2001
From: rtoy <rtoy>
Date: Wed, 16 Aug 2006 16:19:09 +0000
Subject: [PATCH] code/hash-new.lisp: o Add a new slot to the hash-table
 structure for GC to use for linking   weak tables together.  (Previously we
 used the weak-p slot for   this.  Let's make it explicit, now.  Plus, this
 allows us to use   weak-p to indicate other types of weak tables, should they
 be   implemented.)

lisp/gencgc.c:
o Update defstruct appropriately.
o Use the new next-weak-table slot to chain the weak tables together.
o Previously we scanned the weak tables in several places in the
  code.  However, this scanning also removed entries.  I don't think
  we want that because later scans could make a key valid.  Thus:

  - Change scav_hash_entries so that it doesn't remove a hash-table
    entry unless told to.
  - Add new function to scavenge weak tables without removing a weak
    entry.
  - Adjust scan_weak_tables to remove weak entries.

NOTE:  When building, you'll be asked twice about the hash-table
structure changing size.  Just select the CLOBBER-IT restart in both
cases.
---
 code/hash-new.lisp | 14 ++++++---
 lisp/gencgc.c      | 77 +++++++++++++++++++++++++++++-----------------
 2 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/code/hash-new.lisp b/code/hash-new.lisp
index b233bc9dc..f9ea1319a 100644
--- a/code/hash-new.lisp
+++ b/code/hash-new.lisp
@@ -5,7 +5,7 @@
 ;;; Carnegie Mellon University, and has been placed in the public domain.
 ;;;
 (ext:file-comment
-  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/code/hash-new.lisp,v 1.40 2006/08/14 14:37:30 rtoy Exp $")
+  "$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/code/hash-new.lisp,v 1.41 2006/08/16 16:19:09 rtoy Exp $")
 ;;;
 ;;; **********************************************************************
 ;;;
@@ -100,9 +100,15 @@
   ;; This table parallels the KV table, and can be used to store the
   ;; hash associated with the key, saving recalculation. Could be
   ;; useful for EQL, and EQUAL hash tables. This table is not needed
-  ;; for EQ hash tables, and when present the value of #x8000000
-  ;; represents EQ-based hashing on the respective Key.
-  (hash-vector nil :type (or null (simple-array (unsigned-byte 32) (*)))))
+  ;; for EQ hash tables (an is NIL in that case), and when present the
+  ;; value of #x8000000 represents EQ-based hashing on the respective
+  ;; Key.
+  (hash-vector nil :type (or null (simple-array (unsigned-byte 32) (*))))
+  ;;
+  ;; This is used by GC to chain the list of weak hash tables
+  ;; together.  It should otherwise always be NIL.
+  (next-weak-table nil :type (or null hash-table)))
+
 ;;;
 (defun %print-hash-table (ht stream depth)
   (declare (ignore depth) (stream stream))
diff --git a/lisp/gencgc.c b/lisp/gencgc.c
index 0378e4663..4d0b85f29 100644
--- a/lisp/gencgc.c
+++ b/lisp/gencgc.c
@@ -7,7 +7,7 @@
  *
  * Douglas Crosher, 1996, 1997, 1998, 1999.
  *
- * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/gencgc.c,v 1.78 2006/08/12 12:26:44 rtoy Exp $
+ * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/gencgc.c,v 1.79 2006/08/16 16:19:09 rtoy Exp $
  *
  */
 
@@ -3595,6 +3595,7 @@ struct hash_table {
     lispobj index_vector;
     lispobj next_vector;
     lispobj hash_vector;	/* 15 */
+    lispobj next_weak_table;
 };
 
 /* The size of a hash-table in Lisp objects.  */
@@ -3742,7 +3743,7 @@ record_for_rehashing(struct hash_table *hash_table, int hash_index,
    scheduled for rehashing or removed.  */
 
 static void
-scav_hash_entries(struct hash_table *hash_table, int weak)
+scav_hash_entries(struct hash_table *hash_table, int weak, int removep)
 {
     unsigned kv_length;
     lispobj *kv_vector;
@@ -3773,9 +3774,11 @@ scav_hash_entries(struct hash_table *hash_table, int weak)
 
 	if (weak && !survives_gc(old_key)
 	    && index_vector[old_index] != 0
-	    && (hash_vector == 0 || hash_vector[i] == 0x80000000))
-	    free_hash_entry(hash_table, old_index, i);
-	else {
+	    && (hash_vector == 0 || hash_vector[i] == 0x80000000)) {
+            if (removep) {
+                free_hash_entry(hash_table, old_index, i);
+            }
+        } else {
 	    /* If the key is EQ-hashed and moves, schedule it for rehashing. */
 #if 0
             if ((i < 4) && (hash_table >= (void*)0x40000000)) {
@@ -3852,10 +3855,8 @@ scav_weak_entries(struct hash_table *hash_table)
     return scavenged;
 }
 
-/* Process weak hash-tables at the end of a GC.  */
-
 static void
-scan_weak_tables(void)
+scav_weak_tables(void)
 {
     lispobj table, next;
     int more_scavenged;
@@ -3869,7 +3870,7 @@ scan_weak_tables(void)
 	for (table = weak_hash_tables; table != NIL; table = next) {
 	    struct hash_table *ht = (struct hash_table *) PTR(table);
 
-	    next = ht->weak_p;
+	    next = ht->next_weak_table;
 	    if (scav_weak_entries(ht))
 		more_scavenged = 1;
 	}
@@ -3879,9 +3880,31 @@ scan_weak_tables(void)
     for (table = weak_hash_tables; table != NIL; table = next) {
 	struct hash_table *ht = (struct hash_table *) PTR(table);
 
-	next = ht->weak_p;
-	ht->weak_p = T;
-	scav_hash_entries(ht, 1);
+	next = ht->next_weak_table;
+	scav_hash_entries(ht, 1, 0);
+    }
+}
+
+    
+/* Process weak hash-tables at the end of a GC.  */
+
+static void
+scan_weak_tables(void)
+{
+    lispobj table, next;
+    int more_scavenged;
+
+    for (table = weak_hash_tables; table != NIL; table = next) {
+	struct hash_table *ht = (struct hash_table *) PTR(table);
+
+	next = ht->next_weak_table;
+        /* We're done with the table, so reset the link! */
+	ht->next_weak_table = NIL;
+        /*
+         * Remove the entries in the table.  (This probably does too
+         * much work!)
+         */
+	scav_hash_entries(ht, 1, 1);
     }
 
     weak_hash_tables = NIL;
@@ -3955,19 +3978,17 @@ scav_hash_vector(lispobj * where, lispobj object)
 
     scavenge((lispobj *) hash_table, HASH_TABLE_SIZE);
 
-    /* Testing for T here instead of NIL automatially makes sure we
-       don't add the same table twice to the list of weak tables, should
-       this function ever be called twice for the same object.  */
-
-    if (hash_table->weak_p == T) {
-	hash_table->weak_p = weak_hash_tables;
-#if 0
-        fprintf(stderr, "  adding %p to weak_hash_tables\n", hash_table);
-#endif
-	weak_hash_tables = hash_table_obj;
-    } else
-	scav_hash_entries(hash_table, 0);
-
+    if (hash_table->weak_p == NIL) {
+        scav_hash_entries(hash_table, 0, 1);
+    } else if (hash_table->next_weak_table == NIL) {
+        /*
+         * Make sure we only add the table once, which means
+         * next_weak_table is NIL if it isn't already on the list.
+         */
+        hash_table->next_weak_table = weak_hash_tables;
+        weak_hash_tables = hash_table_obj;
+    }
+      
     return CEILING(kv_length + 2, 2);
 }
 
@@ -6002,7 +6023,7 @@ scavenge_newspace_generation(int generation)
      * regions are updated, so it seems to make sense to do it here as
      * well.
      */
-    scan_weak_tables();
+    scav_weak_tables();
 
     
     /* Record all new areas now. */
@@ -6075,7 +6096,7 @@ scavenge_newspace_generation(int generation)
              * scavenges stuff too.
              */
             
-            scan_weak_tables();
+            scav_weak_tables();
 
 	    /* Record all new areas now. */
 	    record_new_objects = 2;
@@ -6111,7 +6132,7 @@ scavenge_newspace_generation(int generation)
              * This fixes a bug with weak hash tables, reported by
              * Lynn Quam, cmucl-imp, 2006-07-04.
              */ 
-            scan_weak_tables();
+            scav_weak_tables();
             
 	    /* Flush the current regions updating the tables. */
 	    gc_alloc_update_page_tables(0, &boxed_region);
-- 
GitLab