+#ifdef HAVE_WINDOW_SYSTEM
+
+/* Remove unmarked font-spec and font-entity objects from ENTRY, which is
+ (DRIVER-TYPE NUM-FRAMES FONT-CACHE-DATA ...), and return changed entry. */
+
+static Lisp_Object
+compact_font_cache_entry (Lisp_Object entry)
+{
+ Lisp_Object tail, *prev = &entry;
+
+ for (tail = entry; CONSP (tail); tail = XCDR (tail))
+ {
+ bool drop = 0;
+ Lisp_Object obj = XCAR (tail);
+
+ /* Consider OBJ if it is (font-spec . [font-entity font-entity ...]). */
+ if (CONSP (obj) && FONT_SPEC_P (XCAR (obj))
+ && !VECTOR_MARKED_P (XFONT_SPEC (XCAR (obj)))
+ && VECTORP (XCDR (obj)))
+ {
+ ptrdiff_t i, size = ASIZE (XCDR (obj)) & ~ARRAY_MARK_FLAG;
+
+ /* If font-spec is not marked, most likely all font-entities
+ are not marked too. But we must be sure that nothing is
+ marked within OBJ before we really drop it. */
+ for (i = 0; i < size; i++)
+ if (VECTOR_MARKED_P (XFONT_ENTITY (AREF (XCDR (obj), i))))
+ break;
+
+ if (i == size)
+ drop = 1;
+ }
+ if (drop)
+ *prev = XCDR (tail);
+ else
+ prev = xcdr_addr (tail);
+ }
+ return entry;
+}
+
+/* Compact font caches on all terminals and mark
+ everything which is still here after compaction. */
+
+static void
+compact_font_caches (void)
+{
+ struct terminal *t;
+
+ for (t = terminal_list; t; t = t->next_terminal)
+ {
+ Lisp_Object cache = TERMINAL_FONT_CACHE (t);
+
+ if (CONSP (cache))
+ {
+ Lisp_Object entry;
+
+ for (entry = XCDR (cache); CONSP (entry); entry = XCDR (entry))
+ XSETCAR (entry, compact_font_cache_entry (XCAR (entry)));
+ }
+ mark_object (cache);
+ }
+}
+
+#else /* not HAVE_WINDOW_SYSTEM */
+
+#define compact_font_caches() (void)(0)
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+/* Remove (MARKER . DATA) entries with unmarked MARKER
+ from buffer undo LIST and return changed list. */
+
+static Lisp_Object
+compact_undo_list (Lisp_Object list)
+{
+ Lisp_Object tail, *prev = &list;
+
+ for (tail = list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (CONSP (XCAR (tail))
+ && MARKERP (XCAR (XCAR (tail)))
+ && !XMARKER (XCAR (XCAR (tail)))->gcmarkbit)
+ *prev = XCDR (tail);
+ else
+ prev = xcdr_addr (tail);
+ }
+ return list;
+}
+