APPROVE COMMIT
NOTE: This patch has been committed
# HG changeset patch
# User Aidan Kehoe <kehoea(a)parhasard.net>
# Date 1534083534 -3600
#      Sun Aug 12 15:18:54 2018 +0100
# Node ID e3f754148ae1f883b101c7863e3448c813e6bc0d
# Parent  593de3c3ee78030276540da59f71602e7ea7e1a4
Use an explicit weak list object for the weak hash tables, too.
src/ChangeLog addition:
2018-08-12  Aidan Kehoe  <kehoea(a)parhasard.net>
	Use an explicit weak list object for the weak hash tables, too.
	* device.c:
	* device.c (clear_all_console_local_caches): New. Provided so the
	weak list code doesn't think various subwindow_instance_cache weak
	hash tables are reachable at dump time.
	* elhash.c:
	* elhash.c (struct Lisp_Hash_Table):
	Remove the next_weak chain pointer, it's not used for non-weak
	hash tables, and we've moved to an explicit weak list object for
	weak hash tables.
	* elhash.c (make_general_lisp_hash_table):
	Use the explicit weak list object.
	* elhash.c (Fcopy_hash_table):
	Ditto.
	* elhash.c (finish_marking_weak_hash_tables):
	Simplify, using the explicit weak list infrastructure.
	* elhash.c (prune_weak_hash_tables):
	Ditto.
	* elhash.c (syms_of_elhash):
	This can be simplified now we're using the explicit weak list
	infrastructure.
	* elhash.c (vars_of_elhash):
	Ditto.
	* glyphs.c:
	* glyphs.c (clear_all_subwindow_instance_caches): New.
	Clear a window's subwindow instance caches when dumping, so pdump
	doesn't have to try to dump an image instance.
	* glyphs.c (clear_frame_subwindow_instance_caches): New. When
	handed a frame, clear its subwindow instance caches.
	* glyphs.h:
	Declare clear_frame_subwindow_instance_caches().
diff -r 593de3c3ee78 -r e3f754148ae1 src/ChangeLog
--- a/src/ChangeLog	Sun Aug 12 01:30:52 2018 +0100
+++ b/src/ChangeLog	Sun Aug 12 15:18:54 2018 +0100
@@ -1,3 +1,37 @@
+2018-08-12  Aidan Kehoe  <kehoea(a)parhasard.net>
+
+	Use an explicit weak list object for the weak hash tables, too.
+	* device.c:
+	* device.c (clear_all_console_local_caches): New. Provided so the
+	weak list code doesn't think various subwindow_instance_cache weak
+	hash tables are reachable at dump time.
+	* elhash.c:
+	* elhash.c (struct Lisp_Hash_Table):
+	Remove the next_weak chain pointer, it's not used for non-weak
+	hash tables, and we've moved to an explicit weak list object for
+	weak hash tables.
+	* elhash.c (make_general_lisp_hash_table):
+	Use the explicit weak list object.
+	* elhash.c (Fcopy_hash_table):
+	Ditto.
+	* elhash.c (finish_marking_weak_hash_tables):
+	Simplify, using the explicit weak list infrastructure.
+	* elhash.c (prune_weak_hash_tables):
+	Ditto.
+	* elhash.c (syms_of_elhash):
+	This can be simplified now we're using the explicit weak list
+	infrastructure.
+	* elhash.c (vars_of_elhash):
+	Ditto.
+	* glyphs.c:
+	* glyphs.c (clear_all_subwindow_instance_caches): New.
+	Clear a window's subwindow instance caches when dumping, so pdump
+	doesn't have to try to dump an image instance.
+	* glyphs.c (clear_frame_subwindow_instance_caches): New. When
+	handed a frame, clear its subwindow instance caches.
+	* glyphs.h:
+	Declare clear_frame_subwindow_instance_caches(). 
+
 2018-08-12  Aidan Kehoe  <kehoea(a)parhasard.net>
 
 	Use an explicit weak list object for the syntax table and
diff -r 593de3c3ee78 -r e3f754148ae1 src/device.c
--- a/src/device.c	Sun Aug 12 01:30:52 2018 +0100
+++ b/src/device.c	Sun Aug 12 15:18:54 2018 +0100
@@ -35,6 +35,7 @@
 #include "events.h"
 #include "faces.h"
 #include "frame-impl.h"
+#include "glyphs.h"
 #include "keymap.h"
 #include "fontcolor.h"
 #include "redisplay.h"
@@ -457,10 +458,35 @@
   Vdefault_device_plist = Fplist_put (Vdefault_device_plist, type, device);
 }
 
+static void
+clear_all_console_local_caches (void)
+{
+  Lisp_Object concons;
+
+  CONSOLE_LOOP (concons)
+    {
+      Lisp_Object console = XCAR (concons);
+      
+      LIST_LOOP_2 (device, CONSOLE_DEVICE_LIST (XCONSOLE (console)))
+        {
+          Lisp_Object frmcons;
+          struct device *d = XDEVICE (device);
+
+          d->image_instance_cache = Qnil;
+
+          DEVICE_FRAME_LOOP (frmcons, d)
+            {
+              clear_frame_subwindow_instance_caches (XFRAME (XCAR (frmcons)));
+            }
+        }
+    }
+}
+
 void
 clear_default_devices (void)
 {
   Vdefault_device_plist = Qnil;
+  clear_all_console_local_caches ();
 }
 
 static Lisp_Object
diff -r 593de3c3ee78 -r e3f754148ae1 src/elhash.c
--- a/src/elhash.c	Sun Aug 12 01:30:52 2018 +0100
+++ b/src/elhash.c	Sun Aug 12 15:18:54 2018 +0100
@@ -157,8 +157,6 @@
   htentry *hentries;
   Lisp_Object test;
   enum hash_table_weakness weakness;
-  Lisp_Object next_weak;     /* Used to chain together all of the weak
-			        hash tables.  Don't mark through this. */
 };
 
 #define CLEAR_HTENTRY(htentry)   \
@@ -704,7 +702,6 @@
   { XD_INT,	   offsetof (Lisp_Hash_Table, weakness) },
   { XD_UNION,	   offsetof (Lisp_Hash_Table, hentries), XD_INDIRECT (1, 0),
     { &htentry_union_description } },
-  { XD_LO_LINK,    offsetof (Lisp_Hash_Table, next_weak) },
   { XD_LISP_OBJECT,offsetof (Lisp_Hash_Table, test) },
   { XD_END }
 };
@@ -787,10 +784,11 @@
   /* We leave room for one never-occupied sentinel htentry at the end.  */
   ht->hentries = allocate_hash_table_entries (ht->size + 1);
 
-  if (weakness == HASH_TABLE_NON_WEAK)
-    ht->next_weak = Qunbound;
-  else
-    ht->next_weak = Vall_weak_hash_tables, Vall_weak_hash_tables = hash_table;
+  if (weakness != HASH_TABLE_NON_WEAK)
+    {
+      XWEAK_LIST_LIST (Vall_weak_hash_tables)
+        = Fcons (hash_table, XWEAK_LIST_LIST (Vall_weak_hash_tables));
+    }
 
   return hash_table;
 }
@@ -1265,11 +1263,10 @@
   /* We leave room for one never-occupied sentinel htentry at the end.  */
   ht->hentries = allocate_hash_table_entries (ht_old->size + 1);
   memcpy (ht->hentries, ht_old->hentries, (ht_old->size + 1) * sizeof
(htentry));
-
-  if (! EQ (ht->next_weak, Qunbound))
+  if (ht->weakness != HASH_TABLE_NON_WEAK)
     {
-      ht->next_weak = Vall_weak_hash_tables;
-      Vall_weak_hash_tables = obj;
+      XWEAK_LIST_LIST (Vall_weak_hash_tables)
+        = Fcons (hash_table, XWEAK_LIST_LIST (Vall_weak_hash_tables));
     }
 
   return obj;
@@ -2170,20 +2167,20 @@
 int
 finish_marking_weak_hash_tables (void)
 {
-  Lisp_Object hash_table;
   int did_mark = 0;
 
-  for (hash_table = Vall_weak_hash_tables;
-       !NILP (hash_table);
-       hash_table = XHASH_TABLE (hash_table)->next_weak)
+  LIST_LOOP_2 (hash_table, XWEAK_LIST_LIST (Vall_weak_hash_tables))
     {
       const Lisp_Hash_Table *ht = XHASH_TABLE (hash_table);
       const htentry *e = ht->hentries;
       const htentry *sentinel = e + ht->size;
 
-      if (! marked_p (hash_table))
-	/* The hash table is probably garbage.  Ignore it. */
-	continue;
+      if (!marked_p (hash_table))
+        {
+	  /* This hash table itself is garbage, let prune_weak_lists() remove
+             it. */
+          continue;
+	}
 
       /* Now, scan over all the pairs.  For all pairs that are
 	 half-marked, we may need to mark the other half if we're
@@ -2264,43 +2261,27 @@
 void
 prune_weak_hash_tables (void)
 {
-  Lisp_Object hash_table, prev = Qnil;
-  for (hash_table = Vall_weak_hash_tables;
-       !NILP (hash_table);
-       hash_table = XHASH_TABLE (hash_table)->next_weak)
+  LIST_LOOP_2 (hash_table, XWEAK_LIST_LIST (Vall_weak_hash_tables))
     {
-      if (! marked_p (hash_table))
-	{
-	  /* This hash table itself is garbage.  Remove it from the list. */
-	  if (NILP (prev))
-	    Vall_weak_hash_tables = XHASH_TABLE (hash_table)->next_weak;
-	  else
-	    XHASH_TABLE (prev)->next_weak = XHASH_TABLE (hash_table)->next_weak;
-	}
-      else
-	{
-	  /* Now, scan over all the pairs.  Remove all of the pairs
-	     in which the key or value, or both, is unmarked
-	     (depending on the weakness of the hash table). */
-	  Lisp_Hash_Table *ht = XHASH_TABLE (hash_table);
-	  htentry *entries = ht->hentries;
-	  htentry *sentinel = entries + ht->size;
-	  htentry *e;
-
-	  for (e = entries; e < sentinel; e++)
-	    if (!HTENTRY_CLEAR_P (e))
-	      {
-	      again:
-		if (!marked_p (e->key) || !marked_p (e->value))
-		  {
-		    remhash_1 (ht, entries, e);
-		    if (!HTENTRY_CLEAR_P (e))
-		      goto again;
-		  }
-	      }
-
-	  prev = hash_table;
-	}
+      /* Now, scan over all the pairs.  Remove all of the pairs
+         in which the key or value, or both, is unmarked
+         (depending on the weakness of the hash table). */
+      Lisp_Hash_Table *ht = XHASH_TABLE (hash_table);
+      htentry *entries = ht->hentries;
+      htentry *sentinel = entries + ht->size;
+      htentry *e;
+
+      for (e = entries; e < sentinel; e++)
+        if (!HTENTRY_CLEAR_P (e))
+          {
+          again:
+            if (!marked_p (e->key) || !marked_p (e->value))
+              {
+                remhash_1 (ht, entries, e);
+                if (!HTENTRY_CLEAR_P (e))
+                  goto again;
+              }
+          }
     }
 }
 
@@ -2837,13 +2818,6 @@
 void
 syms_of_elhash (void)
 {
-  /* This was set incorrectly since init_elhash_once_early() was called before
-     Qunbound had a useful value. */
-  xhash_table (Vobarray)->next_weak = Qunbound;
-
-  /* This must NOT be staticpro'd */
-  DUMP_ADD_WEAK_OBJECT_CHAIN (Vall_weak_hash_tables);
- 
   staticpro (&Vhash_table_test_weak_list);
   Vhash_table_test_weak_list = make_weak_list (WEAK_LIST_KEY_ASSOC);
   /* syms_of_elhash() is called *very* early, don't confuse the weak list code
@@ -2970,6 +2944,10 @@
   Vhash_table_test_weak_list = make_weak_list (WEAK_LIST_KEY_ASSOC);
   XWEAK_LIST_LIST (Vhash_table_test_weak_list) = weak_list_list;
 
+  gc_checking_assert (EQ (Vall_weak_hash_tables, Qnull_pointer));
+  Vall_weak_hash_tables = make_weak_list (WEAK_LIST_SIMPLE);
+  staticpro (&Vall_weak_hash_tables);
+
 #ifdef MEMORY_USAGE_STATS
   OBJECT_HAS_PROPERTY
     (hash_table, memusage_stats_list, list1 (intern ("hash-entries")));
diff -r 593de3c3ee78 -r e3f754148ae1 src/glyphs.c
--- a/src/glyphs.c	Sun Aug 12 01:30:52 2018 +0100
+++ b/src/glyphs.c	Sun Aug 12 15:18:54 2018 +0100
@@ -4594,6 +4594,25 @@
     }
 }
 
+static void
+clear_all_subwindow_instance_caches (struct window *w)
+{
+  if (!NILP (w->next)) clear_all_subwindow_instance_caches (XWINDOW (w->next));
+  if (!NILP (w->vchild)) clear_all_subwindow_instance_caches (XWINDOW
(w->vchild));
+  if (!NILP (w->hchild)) clear_all_subwindow_instance_caches (XWINDOW
(w->hchild));
+
+  /* Setting w->subwindow_instance_cache to Qnil trips some assertion failures
+     elsewhere on shutdown. */
+  Fclrhash (w->subwindow_instance_cache);
+}
+
+/* Used when dumping, so no image instances need to be dumped. */
+void
+clear_frame_subwindow_instance_caches (struct frame* f)
+{
+  clear_all_subwindow_instance_caches (XWINDOW (f->root_window));
+}
+
 /*****************************************************************************
  *                           subwindow exposure ignorance                    *
  *****************************************************************************/
diff -r 593de3c3ee78 -r e3f754148ae1 src/glyphs.h
--- a/src/glyphs.h	Sun Aug 12 01:30:52 2018 +0100
+++ b/src/glyphs.h	Sun Aug 12 15:18:54 2018 +0100
@@ -1191,6 +1191,8 @@
 int unmap_subwindow_instance_cache_mapper (Lisp_Object key,
 					   Lisp_Object value, void* finalize);
 
+void clear_frame_subwindow_instance_caches (struct frame*);
+
 struct expose_ignore
 {
 #ifdef NEW_GC
-- 
‘As I sat looking up at the Guinness ad, I could never figure out /
How your man stayed up on the surfboard after forty pints of stout’
(C. Moore)