unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#36649: 27.0.50; pure space and pdumper
@ 2019-07-14 14:26 Pip Cet
  2019-07-21  7:28 ` Paul Eggert
                   ` (2 more replies)
  0 siblings, 3 replies; 125+ messages in thread
From: Pip Cet @ 2019-07-14 14:26 UTC (permalink / raw)
  To: 36649

This is a follow-up to bug #36447, which has been fixed and closed.

Currently, pure space is wasted when using pdumper, and CHECK_IMPURE
does nothing at run time.

The current situation when using pdumper is this:

- pure space is put into the initial emacs executable as an all-zero
area with a single 1 in it, which is used to prevent the area being
placed into BSS
- before dump, data is placed into the pure space by purecopy
- before dump, PURE_P returns true for pure data, and CHECK_IMPURE
dies for pure arguments
- when dumping, pure data is indiscriminately mixed with impure data
and placed in the pdumper file without special treatment of any kind
- when launching the real emacs, pure space is also initialized from
the executable, as an all-zero area
- all data from the pdumper file is restored to heap memory, without
distinguishing formerly-pure data from formerly-impure data
- PURE_P is never called with a pure space pointer, it essentially
always returns false
- CHECK_IMPURE does nothing except waste a few cycles

That situation is unsatisfactory. We fail to catch modification of
formerly-pure data after loading the dump, and we waste several
megabytes of executable image size on zeroed data.

I think we have the following options:

1. remove pure space entirely
2. remove pure space, but leave PURE_P and CHECK_IMPURE as reminders
to do something about it.
3. move pure space to BSS
4. xmalloc() pure space, only when needed
5. modify pdumper to mark and recognize pure objects
6. do nothing and accept the wastefulness


I prefer (2), for this reason:

CHECK_IMPURE is useful, and should be extended to something like
CHECK_MUTABLE, which checks for objects including:

1. pure data
2. data read with `read'
3. data explicitly marked as immutable

(That would mean code like

(defconst list-a (nconc '(a b c) list-b))

would cease to be valid, and that's one of the problems I'm running
into with code I'm playing around with.)





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-14 14:26 bug#36649: 27.0.50; pure space and pdumper Pip Cet
@ 2019-07-21  7:28 ` Paul Eggert
  2019-07-21 12:53   ` Pip Cet
  2022-07-01 13:46 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-03  7:14 ` Gerd Möllmann
  2 siblings, 1 reply; 125+ messages in thread
From: Paul Eggert @ 2019-07-21  7:28 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649

> I think we have the following options:
> 
> 1. remove pure space entirely
> 2. remove pure space, but leave PURE_P and CHECK_IMPURE as reminders
> to do something about it.
> 3. move pure space to BSS
> 4. xmalloc() pure space, only when needed
> 5. modify pdumper to mark and recognize pure objects
> 6. do nothing and accept the wastefulness

I suggest (1), since it will result in simpler code. Although (2) would be OK 
too, if we ever introduce immutable objects it's likely that PURE_P and/or 
CHECK_IMPURE will just get in the way anyway. We can see a hint of that in my 
patch today that added temporary immutability to hash tables to fix a core-dump bug.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21  7:28 ` Paul Eggert
@ 2019-07-21 12:53   ` Pip Cet
  2019-07-21 13:44     ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-21 12:53 UTC (permalink / raw)
  To: Paul Eggert; +Cc: 36649

[-- Attachment #1: Type: text/plain, Size: 1418 bytes --]

On Sun, Jul 21, 2019 at 7:29 AM Paul Eggert <eggert@cs.ucla.edu> wrote:
> > I think we have the following options:
> >
> > 1. remove pure space entirely
> > 2. remove pure space, but leave PURE_P and CHECK_IMPURE as reminders
> > to do something about it.
> > 3. move pure space to BSS
> > 4. xmalloc() pure space, only when needed
> > 5. modify pdumper to mark and recognize pure objects
> > 6. do nothing and accept the wastefulness
>
> I suggest (1), since it will result in simpler code.

I think we should do (1) for now, since it simplifies the code enough
to introduce immutable objects "soon"; but until that time, we waste
more space on duplicate objects that we no longer know to be
immutable, so cannot merge.

I'm attaching a first patch that removes pure space, pinned symbols,
pinned objects, but keeps Fpurecopy (for hash consing), and doesn't
touch the Lisp codebase.

With this patch, I have:
-rw-r--r-- 2 pip pip 11102752 Jul 21 12:28 src/emacs.pdmp

before:
-rw-r--r-- 2 pip pip 10381464 Jul 21 12:29 src/emacs.pdmp

However, the (uncompressed) disk space requirement is about the same,
since the emacs binary is a lot smaller.

I think the next steps are to look at actual live memory usage (which
will increase due to the non-duplication of objects, but not by an
entire megabyte because some of that data is relocations), and GC
performance (no prediction here, it could improve or deteriorate).

[-- Attachment #2: 0001-Remove-pure-space.patch --]
[-- Type: text/x-patch, Size: 84651 bytes --]

From 92ed5b8604363fe546aacd7a4bd3856f8ea56a4b Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Sun, 21 Jul 2019 12:51:21 +0000
Subject: [PATCH] Remove pure space

* src/lisp.h (struct Lisp_Symbol): Remove `pinned' flag.
(build_pure_c_string, pure_listn): Remove.  All calls removed.
* src/puresize.h: Remove file.
* src/fns.c (Fmake_hash_table): Ignore `:purecopy' argument.
* src/doc.c (store_function_docstring): Remove comment about pure
space.
* src/data.c (pure_write_error): Remove.  All calls removed.
* src/conf_post.h (SYSTEM_PURESIZE_EXTRA): Remove.
* src/fns.c (make_hash_table): Drop `purecopy' argument.  All
callers changed to remove argument.
* src/alloc.c (make_pure_string, make_pure_c_string, pure_cons)
(pure_list): Remove.  All calls removed.
(check_pure_size): Remove.  All calls removed.
(cons_listn): Simplify.
(Fmake_byte_code): Remove comment about pure space.
(pointer_align): Move definition to avoid warning.
* src/Makefile.in: Remove comment about pure space.
---
 src/Makefile.in    |   2 -
 src/alloc.c        | 537 ++++-----------------------------------------
 src/buffer.c       |  16 +-
 src/callint.c      |   8 +-
 src/category.c     |   4 +-
 src/coding.c       |  18 +-
 src/conf_post.h    |  33 ---
 src/data.c         |  29 +--
 src/dbusbind.c     |   4 +-
 src/deps.mk        |  10 +-
 src/doc.c          |   3 -
 src/emacs-module.c |  26 +--
 src/emacs.c        |   3 -
 src/eval.c         |  12 +-
 src/fileio.c       |  20 +-
 src/fns.c          |  29 +--
 src/fontset.c      |   4 +-
 src/frame.c        |   2 +-
 src/intervals.c    |   2 -
 src/json.c         |   4 +-
 src/keyboard.c     |   8 +-
 src/keymap.c       |  33 ++-
 src/lisp.h         |  41 +---
 src/lread.c        |  45 ++--
 src/pdumper.c      |   2 -
 src/print.c        |   6 -
 src/process.c      |   4 +-
 src/profiler.c     |   2 +-
 src/puresize.h     | 115 ----------
 src/search.c       |  12 +-
 src/syntax.c       |   4 +-
 src/w32fns.c       |   4 +-
 src/xdisp.c        |  20 +-
 src/xfaces.c       |   2 +-
 src/xfns.c         |   9 +-
 src/xterm.c        |   4 +-
 36 files changed, 182 insertions(+), 895 deletions(-)

diff --git a/src/Makefile.in b/src/Makefile.in
index fd05a45df5..d6e489d822 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -403,8 +403,6 @@ .c.o:
 .m.o:
 	$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
 
-## lastfile must follow all files whose initialized data areas should
-## be dumped as pure by dump-emacs.
 base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
 	charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \
 	$(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \
diff --git a/src/alloc.c b/src/alloc.c
index 1718ce0faf..df8b1caf4e 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -35,7 +35,6 @@ Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2019 Free Software
 #include "dispextern.h"
 #include "intervals.h"
 #include "ptr-bounds.h"
-#include "puresize.h"
 #include "sheap.h"
 #include "sysstdio.h"
 #include "systime.h"
@@ -265,33 +264,6 @@ #define GC_DEFAULT_THRESHOLD (100000 * word_size)
 
 #define SPARE_MEMORY (1 << 14)
 
-/* Initialize it to a nonzero value to force it into data space
-   (rather than bss space).  That way unexec will remap it into text
-   space (pure), on some systems.  We have not implemented the
-   remapping on more recent systems because this is less important
-   nowadays than in the days of small memories and timesharing.  */
-
-EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,};
-#define PUREBEG (char *) pure
-
-/* Pointer to the pure area, and its size.  */
-
-static char *purebeg;
-static ptrdiff_t pure_size;
-
-/* Number of bytes of pure storage used before pure storage overflowed.
-   If this is non-zero, this implies that an overflow occurred.  */
-
-static ptrdiff_t pure_bytes_used_before_overflow;
-
-/* Index in pure at which next pure Lisp object will be allocated..  */
-
-static ptrdiff_t pure_bytes_used_lisp;
-
-/* Number of bytes allocated for non-Lisp objects in pure storage.  */
-
-static ptrdiff_t pure_bytes_used_non_lisp;
-
 /* If positive, garbage collection is inhibited.  Otherwise, zero.  */
 
 static intptr_t garbage_collection_inhibited;
@@ -366,7 +338,6 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
 static void unchain_finalizer (struct Lisp_Finalizer *);
 static void mark_terminals (void);
 static void gc_sweep (void);
-static Lisp_Object make_pure_vector (ptrdiff_t);
 static void mark_buffer (struct buffer *);
 
 #if !defined REL_ALLOC || defined SYSTEM_MALLOC || defined HYBRID_MALLOC
@@ -509,16 +480,6 @@ #define MEM_NIL &mem_z
 
 int staticidx;
 
-static void *pure_alloc (size_t, int);
-
-/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
-
-static void *
-pointer_align (void *ptr, int alignment)
-{
-  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
-}
-
 /* Extract the pointer hidden within O.  */
 
 static ATTRIBUTE_NO_SANITIZE_UNDEFINED void *
@@ -1002,6 +963,15 @@ verify (POWER_OF_2 (BLOCK_ALIGN));
 # elif !defined HYBRID_MALLOC && defined HAVE_POSIX_MEMALIGN
 #  define USE_ALIGNED_ALLOC 1
 #  define aligned_alloc my_aligned_alloc /* Avoid collision with lisp.h.  */
+
+/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
+
+static void *
+pointer_align (void *ptr, int alignment)
+{
+  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
+}
+
 static void *
 aligned_alloc (size_t alignment, size_t size)
 {
@@ -1605,9 +1575,9 @@ #define GC_STRING_EXTRA GC_STRING_OVERRUN_COOKIE_SIZE
 static void
 init_strings (void)
 {
-  empty_unibyte_string = make_pure_string ("", 0, 0, 0);
+  empty_unibyte_string = make_specified_string ("", 0, 0, false);
   staticpro (&empty_unibyte_string);
-  empty_multibyte_string = make_pure_string ("", 0, 0, 1);
+  empty_multibyte_string = make_specified_string ("", 0, 0, true);
   staticpro (&empty_multibyte_string);
 }
 
@@ -1625,7 +1595,7 @@ string_bytes (struct Lisp_String *s)
   ptrdiff_t nbytes =
     (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
 
-  if (!PURE_P (s) && !pdumper_object_p (s) && s->u.s.data
+  if (!pdumper_object_p (s) && s->u.s.data
       && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
     emacs_abort ();
   return nbytes;
@@ -2302,7 +2272,7 @@ make_specified_string (const char *contents,
 {
   Lisp_Object val;
 
-  if (nchars < 0)
+  if (nchars <= 0)
     {
       if (multibyte)
 	nchars = multibyte_chars_in_text ((const unsigned char *) contents,
@@ -2326,8 +2296,6 @@ make_uninit_string (EMACS_INT length)
 {
   Lisp_Object val;
 
-  if (!length)
-    return empty_unibyte_string;
   val = make_uninit_multibyte_string (length, length);
   STRING_SET_UNIBYTE (val);
   return val;
@@ -2345,8 +2313,6 @@ make_uninit_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes)
 
   if (nchars < 0)
     emacs_abort ();
-  if (!nbytes)
-    return empty_multibyte_string;
 
   s = allocate_string ();
   s->u.s.intervals = NULL;
@@ -2636,17 +2602,16 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4,
 }
 
 /* Make a list of COUNT Lisp_Objects, where ARG is the first one.
-   Use CONS to construct the pairs.  AP has any remaining args.  */
+   AP has any remaining args.  */
 static Lisp_Object
-cons_listn (ptrdiff_t count, Lisp_Object arg,
-	    Lisp_Object (*cons) (Lisp_Object, Lisp_Object), va_list ap)
+cons_listn (ptrdiff_t count, Lisp_Object arg, va_list ap)
 {
   eassume (0 < count);
-  Lisp_Object val = cons (arg, Qnil);
+  Lisp_Object val = Fcons (arg, Qnil);
   Lisp_Object tail = val;
   for (ptrdiff_t i = 1; i < count; i++)
     {
-      Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil);
+      Lisp_Object elem = Fcons (va_arg (ap, Lisp_Object), Qnil);
       XSETCDR (tail, elem);
       tail = elem;
     }
@@ -2659,18 +2624,7 @@ listn (ptrdiff_t count, Lisp_Object arg1, ...)
 {
   va_list ap;
   va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, Fcons, ap);
-  va_end (ap);
-  return val;
-}
-
-/* Make a pure list of COUNT Lisp_Objects, where ARG1 is the first one.  */
-Lisp_Object
-pure_listn (ptrdiff_t count, Lisp_Object arg1, ...)
-{
-  va_list ap;
-  va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, pure_cons, ap);
+  Lisp_Object val = cons_listn (count, arg1, ap);
   va_end (ap);
   return val;
 }
@@ -2836,7 +2790,7 @@ large_vector_vec (struct large_vector *p)
 
 static struct large_vector *large_vectors;
 
-/* The only vector with 0 slots, allocated from pure space.  */
+/* The only vector with 0 slots.  */
 
 Lisp_Object zero_vector;
 
@@ -2874,15 +2828,6 @@ allocate_vector_block (void)
   return block;
 }
 
-/* Called once to initialize vector allocation.  */
-
-static void
-init_vectors (void)
-{
-  zero_vector = make_pure_vector (0);
-  staticpro (&zero_vector);
-}
-
 /* Allocate vector from a vector block.  */
 
 static struct Lisp_Vector *
@@ -3200,6 +3145,17 @@ allocate_vector (ptrdiff_t len)
 }
 
 
+/* Called once to initialize vector allocation.  */
+
+static void
+init_vectors (void)
+{
+  zero_vector =
+    make_lisp_ptr (allocate_vectorlike (sizeof (struct Lisp_Vector)),
+		   Lisp_Vectorlike);
+  staticpro (&zero_vector);
+}
+
 /* Allocate other vector-like structures.  */
 
 struct Lisp_Vector *
@@ -3354,14 +3310,6 @@ and (optional) INTERACTIVE-SPEC.
   Lisp_Object val = make_uninit_vector (nargs);
   struct Lisp_Vector *p = XVECTOR (val);
 
-  /* We used to purecopy everything here, if purify-flag was set.  This worked
-     OK for Emacs-23, but with Emacs-24's lexical binding code, it can be
-     dangerous, since make-byte-code is used during execution to build
-     closures, so any closure built during the preload phase would end up
-     copied into pure space, including its free variables, which is sometimes
-     just wasteful and other times plainly wrong (e.g. those free vars may want
-     to be setcar'd).  */
-
   memcpy (p->contents, args, nargs * sizeof *args);
   make_byte_code (p);
   XSETCOMPILED (val, p);
@@ -3393,13 +3341,6 @@ #define SYMBOL_BLOCK_SIZE \
 
 static struct symbol_block *symbol_block;
 static int symbol_block_index = SYMBOL_BLOCK_SIZE;
-/* Pointer to the first symbol_block that contains pinned symbols.
-   Tests for 24.4 showed that at dump-time, Emacs contains about 15K symbols,
-   10K of which are pinned (and all but 250 of them are interned in obarray),
-   whereas a "typical session" has in the order of 30K symbols.
-   `symbol_block_pinned' lets mark_pinned_symbols scan only 15K symbols rather
-   than 30K to find the 10K symbols we need to mark.  */
-static struct symbol_block *symbol_block_pinned;
 
 /* List of free symbols.  */
 
@@ -3425,7 +3366,6 @@ init_symbol (Lisp_Object val, Lisp_Object name)
   p->u.s.interned = SYMBOL_UNINTERNED;
   p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
   p->u.s.declared_special = false;
-  p->u.s.pinned = false;
 }
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
@@ -5021,8 +4961,6 @@ valid_lisp_object_p (Lisp_Object obj)
     return 1;
 
   void *p = XPNTR (obj);
-  if (PURE_P (p))
-    return 1;
 
   if (SYMBOLP (obj) && c_symbol_p (p))
     return ((char *) p - (char *) lispsym) % sizeof lispsym[0] == 0;
@@ -5079,287 +5017,8 @@ valid_lisp_object_p (Lisp_Object obj)
   return 0;
 }
 
-/***********************************************************************
-		       Pure Storage Management
- ***********************************************************************/
-
-/* Allocate room for SIZE bytes from pure Lisp storage and return a
-   pointer to it.  TYPE is the Lisp type for which the memory is
-   allocated.  TYPE < 0 means it's not used for a Lisp object,
-   and that the result should have an alignment of -TYPE.  */
-
-static void *
-pure_alloc (size_t size, int type)
-{
-  void *result;
-
- again:
-  if (type >= 0)
-    {
-      /* Allocate space for a Lisp object from the beginning of the free
-	 space with taking account of alignment.  */
-      result = pointer_align (purebeg + pure_bytes_used_lisp, LISP_ALIGNMENT);
-      pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size;
-    }
-  else
-    {
-      /* Allocate space for a non-Lisp object from the end of the free
-	 space.  */
-      ptrdiff_t unaligned_non_lisp = pure_bytes_used_non_lisp + size;
-      char *unaligned = purebeg + pure_size - unaligned_non_lisp;
-      int decr = (intptr_t) unaligned & (-1 - type);
-      pure_bytes_used_non_lisp = unaligned_non_lisp + decr;
-      result = unaligned - decr;
-    }
-  pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp;
-
-  if (pure_bytes_used <= pure_size)
-    return ptr_bounds_clip (result, size);
-
-  /* Don't allocate a large amount here,
-     because it might get mmap'd and then its address
-     might not be usable.  */
-  purebeg = xmalloc (10000);
-  pure_size = 10000;
-  pure_bytes_used_before_overflow += pure_bytes_used - size;
-  pure_bytes_used = 0;
-  pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0;
-
-  /* Can't GC if pure storage overflowed because we can't determine
-     if something is a pure object or not.  */
-  garbage_collection_inhibited++;
-  goto again;
-}
-
-
-#ifdef HAVE_UNEXEC
-
-/* Print a warning if PURESIZE is too small.  */
-
-void
-check_pure_size (void)
-{
-  if (pure_bytes_used_before_overflow)
-    message (("emacs:0:Pure Lisp storage overflow (approx. %"pI"d"
-	      " bytes needed)"),
-	     pure_bytes_used + pure_bytes_used_before_overflow);
-}
-#endif
-
-
-/* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
-   the non-Lisp data pool of the pure storage, and return its start
-   address.  Return NULL if not found.  */
-
-static char *
-find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
-{
-  int i;
-  ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max;
-  const unsigned char *p;
-  char *non_lisp_beg;
-
-  if (pure_bytes_used_non_lisp <= nbytes)
-    return NULL;
-
-  /* Set up the Boyer-Moore table.  */
-  skip = nbytes + 1;
-  for (i = 0; i < 256; i++)
-    bm_skip[i] = skip;
-
-  p = (const unsigned char *) data;
-  while (--skip > 0)
-    bm_skip[*p++] = skip;
-
-  last_char_skip = bm_skip['\0'];
-
-  non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp;
-  start_max = pure_bytes_used_non_lisp - (nbytes + 1);
-
-  /* See the comments in the function `boyer_moore' (search.c) for the
-     use of `infinity'.  */
-  infinity = pure_bytes_used_non_lisp + 1;
-  bm_skip['\0'] = infinity;
-
-  p = (const unsigned char *) non_lisp_beg + nbytes;
-  start = 0;
-  do
-    {
-      /* Check the last character (== '\0').  */
-      do
-	{
-	  start += bm_skip[*(p + start)];
-	}
-      while (start <= start_max);
-
-      if (start < infinity)
-	/* Couldn't find the last character.  */
-	return NULL;
-
-      /* No less than `infinity' means we could find the last
-	 character at `p[start - infinity]'.  */
-      start -= infinity;
-
-      /* Check the remaining characters.  */
-      if (memcmp (data, non_lisp_beg + start, nbytes) == 0)
-	/* Found.  */
-	return ptr_bounds_clip (non_lisp_beg + start, nbytes + 1);
-
-      start += last_char_skip;
-    }
-  while (start <= start_max);
-
-  return NULL;
-}
-
-
-/* Return a string allocated in pure space.  DATA is a buffer holding
-   NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
-   means make the result string multibyte.
-
-   Must get an error if pure storage is full, since if it cannot hold
-   a large string it may be able to hold conses that point to that
-   string; then the string is not protected from gc.  */
-
-Lisp_Object
-make_pure_string (const char *data,
-		  ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->u.s.data == NULL)
-    {
-      s->u.s.data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->u.s.data, data, nbytes);
-      s->u.s.data[nbytes] = '\0';
-    }
-  s->u.s.size = nchars;
-  s->u.s.size_byte = multibyte ? nbytes : -1;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-/* Return a string allocated in pure space.  Do not
-   allocate the string data, just point to DATA.  */
-
-Lisp_Object
-make_pure_c_string (const char *data, ptrdiff_t nchars)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.size = nchars;
-  s->u.s.size_byte = -2;
-  s->u.s.data = (unsigned char *) data;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-static Lisp_Object purecopy (Lisp_Object obj);
-
-/* Return a cons allocated from pure space.  Give it pure copies
-   of CAR as car and CDR as cdr.  */
-
-Lisp_Object
-pure_cons (Lisp_Object car, Lisp_Object cdr)
-{
-  Lisp_Object new;
-  struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons);
-  XSETCONS (new, p);
-  XSETCAR (new, purecopy (car));
-  XSETCDR (new, purecopy (cdr));
-  return new;
-}
-
-
-/* Value is a float object with value NUM allocated from pure space.  */
-
-static Lisp_Object
-make_pure_float (double num)
-{
-  Lisp_Object new;
-  struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float);
-  XSETFLOAT (new, p);
-  XFLOAT_INIT (new, num);
-  return new;
-}
-
-/* Value is a bignum object with value VALUE allocated from pure
-   space.  */
-
-static Lisp_Object
-make_pure_bignum (struct Lisp_Bignum *value)
-{
-  size_t i, nlimbs = mpz_size (value->value);
-  size_t nbytes = nlimbs * sizeof (mp_limb_t);
-  mp_limb_t *pure_limbs;
-  mp_size_t new_size;
-
-  struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike);
-  XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum));
-
-  int limb_alignment = alignof (mp_limb_t);
-  pure_limbs = pure_alloc (nbytes, - limb_alignment);
-  for (i = 0; i < nlimbs; ++i)
-    pure_limbs[i] = mpz_getlimbn (value->value, i);
-
-  new_size = nlimbs;
-  if (mpz_sgn (value->value) < 0)
-    new_size = -new_size;
-
-  mpz_roinit_n (b->value, pure_limbs, new_size);
-
-  return make_lisp_ptr (b, Lisp_Vectorlike);
-}
-
-/* Return a vector with room for LEN Lisp_Objects allocated from
-   pure space.  */
-
 static Lisp_Object
-make_pure_vector (ptrdiff_t len)
-{
-  Lisp_Object new;
-  size_t size = header_size + len * word_size;
-  struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike);
-  XSETVECTOR (new, p);
-  XVECTOR (new)->header.size = len;
-  return new;
-}
-
-/* Copy all contents and parameters of TABLE to a new table allocated
-   from pure space, return the purified table.  */
-static struct Lisp_Hash_Table *
-purecopy_hash_table (struct Lisp_Hash_Table *table)
-{
-  eassert (NILP (table->weak));
-  eassert (table->purecopy);
-
-  struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
-  struct hash_table_test pure_test = table->test;
-
-  /* Purecopy the hash table test.  */
-  pure_test.name = purecopy (table->test.name);
-  pure_test.user_hash_function = purecopy (table->test.user_hash_function);
-  pure_test.user_cmp_function = purecopy (table->test.user_cmp_function);
-
-  pure->header = table->header;
-  pure->weak = purecopy (Qnil);
-  pure->hash = purecopy (table->hash);
-  pure->next = purecopy (table->next);
-  pure->index = purecopy (table->index);
-  pure->count = table->count;
-  pure->next_free = table->next_free;
-  pure->purecopy = table->purecopy;
-  eassert (!pure->mutable);
-  pure->rehash_threshold = table->rehash_threshold;
-  pure->rehash_size = table->rehash_size;
-  pure->key_and_value = purecopy (table->key_and_value);
-  pure->test = pure_test;
-
-  return pure;
-}
+purecopy (Lisp_Object obj);
 
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
        doc: /* Make a copy of object OBJ in pure storage.
@@ -5376,100 +5035,23 @@ DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
     return purecopy (obj);
 }
 
-/* Pinned objects are marked before every GC cycle.  */
-static struct pinned_object
-{
-  Lisp_Object object;
-  struct pinned_object *next;
-} *pinned_objects;
-
 static Lisp_Object
 purecopy (Lisp_Object obj)
 {
-  if (FIXNUMP (obj)
-      || (! SYMBOLP (obj) && PURE_P (XPNTR (obj)))
-      || SUBRP (obj))
+  if (FIXNUMP (obj) || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
-    message_with_string ("Dropping text-properties while making string `%s' pure",
-			 obj, true);
-
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
     {
       Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
       if (!NILP (tmp))
 	return tmp;
+      Fputhash (obj, obj, Vpurify_flag);
     }
 
-  if (CONSP (obj))
-    obj = pure_cons (XCAR (obj), XCDR (obj));
-  else if (FLOATP (obj))
-    obj = make_pure_float (XFLOAT_DATA (obj));
-  else if (STRINGP (obj))
-    obj = make_pure_string (SSDATA (obj), SCHARS (obj),
-			    SBYTES (obj),
-			    STRING_MULTIBYTE (obj));
-  else if (HASH_TABLE_P (obj))
-    {
-      struct Lisp_Hash_Table *table = XHASH_TABLE (obj);
-      /* Do not purify hash tables which haven't been defined with
-         :purecopy as non-nil or are weak - they aren't guaranteed to
-         not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
-        {
-          /* Instead, add the hash table to the list of pinned objects,
-             so that it will be marked during GC.  */
-          struct pinned_object *o = xmalloc (sizeof *o);
-          o->object = obj;
-          o->next = pinned_objects;
-          pinned_objects = o;
-          return obj; /* Don't hash cons it.  */
-        }
-
-      struct Lisp_Hash_Table *h = purecopy_hash_table (table);
-      XSET_HASH_TABLE (obj, h);
-    }
-  else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
-    {
-      struct Lisp_Vector *objp = XVECTOR (obj);
-      ptrdiff_t nbytes = vector_nbytes (objp);
-      struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
-      register ptrdiff_t i;
-      ptrdiff_t size = ASIZE (obj);
-      if (size & PSEUDOVECTOR_FLAG)
-	size &= PSEUDOVECTOR_SIZE_MASK;
-      memcpy (vec, objp, nbytes);
-      for (i = 0; i < size; i++)
-	vec->contents[i] = purecopy (vec->contents[i]);
-      XSETVECTOR (obj, vec);
-    }
-  else if (SYMBOLP (obj))
-    {
-      if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
-	{ /* We can't purify them, but they appear in many pure objects.
-	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XSYMBOL (obj)->u.s.pinned = true;
-	  symbol_block_pinned = symbol_block;
-	}
-      /* Don't hash-cons it.  */
-      return obj;
-    }
-  else if (BIGNUMP (obj))
-    obj = make_pure_bignum (XBIGNUM (obj));
-  else
-    {
-      AUTO_STRING (fmt, "Don't know how to purify: %S");
-      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
-    }
-
-  if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
-    Fputhash (obj, obj, Vpurify_flag);
-
   return obj;
 }
 
-
 \f
 /***********************************************************************
 			  Protection from GC
@@ -5658,31 +5240,6 @@ compact_undo_list (Lisp_Object list)
   return list;
 }
 
-static void
-mark_pinned_objects (void)
-{
-  for (struct pinned_object *pobj = pinned_objects; pobj; pobj = pobj->next)
-    mark_object (pobj->object);
-}
-
-static void
-mark_pinned_symbols (void)
-{
-  struct symbol_block *sblk;
-  int lim = (symbol_block_pinned == symbol_block
-	     ? symbol_block_index : SYMBOL_BLOCK_SIZE);
-
-  for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
-    {
-      struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
-      for (; sym < end; ++sym)
-	if (sym->u.s.pinned)
-	  mark_object (make_lisp_symbol (sym));
-
-      lim = SYMBOL_BLOCK_SIZE;
-    }
-}
-
 static void
 visit_vectorlike_root (struct gc_root_visitor visitor,
                        struct Lisp_Vector *ptr,
@@ -5869,8 +5426,6 @@ garbage_collect_1 (struct gcstat *gcst)
   struct gc_root_visitor visitor = { .visit = mark_object_root_visitor };
   visit_static_gc_roots (visitor);
 
-  mark_pinned_objects ();
-  mark_pinned_symbols ();
   mark_terminals ();
   mark_kboards ();
   mark_threads ();
@@ -6008,8 +5563,6 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
 - FREE is the number of those objects that are not live but that Emacs
   keeps around for future allocations (maybe because it does not know how
   to return them to the OS).
-However, if there was overflow in pure space, `garbage-collect'
-returns nil, because real GC can't be done.
 See Info node `(elisp)Garbage Collection'.  */)
   (void)
 {
@@ -6350,8 +5903,6 @@ mark_object (Lisp_Object arg)
  loop:
 
   po = XPNTR (obj);
-  if (PURE_P (po))
-    return;
 
   last_marked[last_marked_index++] = obj;
   last_marked_index &= LAST_MARKED_SIZE - 1;
@@ -6557,8 +6108,7 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL()	((void) 0)
 	    break;
 	  default: emacs_abort ();
 	  }
-	if (!PURE_P (XSTRING (ptr->u.s.name)))
-          set_string_marked (XSTRING (ptr->u.s.name));
+	set_string_marked (XSTRING (ptr->u.s.name));
         mark_interval_tree (string_intervals (ptr->u.s.name));
 	/* Inner loop to mark next symbol in this bucket, if any.  */
 	po = ptr = ptr->u.s.next;
@@ -6672,7 +6222,7 @@ survives_gc_p (Lisp_Object obj)
       emacs_abort ();
     }
 
-  return survives_p || PURE_P (XPNTR (obj));
+  return survives_p;
 }
 
 
@@ -7255,8 +6805,6 @@ init_alloc_once (void)
 static void
 init_alloc_once_for_pdumper (void)
 {
-  purebeg = PUREBEG;
-  pure_size = PURESIZE;
   mem_init ();
 
 #ifdef DOUG_LEA_MALLOC
@@ -7300,7 +6848,7 @@ syms_of_alloc (void)
   Vgc_cons_percentage = make_float (0.1);
 
   DEFVAR_INT ("pure-bytes-used", pure_bytes_used,
-	      doc: /* Number of bytes of shareable Lisp data allocated so far.  */);
+	      doc: /* No longer used.  */);
 
   DEFVAR_INT ("cons-cells-consed", cons_cells_consed,
 	      doc: /* Number of cons cells that have been consed so far.  */);
@@ -7325,10 +6873,7 @@ syms_of_alloc (void)
 	      doc: /* Number of strings that have been consed so far.  */);
 
   DEFVAR_LISP ("purify-flag", Vpurify_flag,
-	       doc: /* Non-nil means loading Lisp code in order to dump an executable.
-This means that certain objects should be allocated in shared (pure) space.
-It can also be set to a hash-table, in which case this table is used to
-do hash-consing of the objects allocated to pure space.  */);
+	       doc: /* No longer used.  */);
 
   DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages,
 	       doc: /* Non-nil means display messages at start and end of garbage collection.  */);
@@ -7344,10 +6889,10 @@ syms_of_alloc (void)
   /* We build this in advance because if we wait until we need it, we might
      not be able to allocate the memory to hold it.  */
   Vmemory_signal_data
-    = pure_list (Qerror,
-		 build_pure_c_string ("Memory exhausted--use"
-				      " M-x save-some-buffers then"
-				      " exit and restart Emacs"));
+    = list (Qerror,
+	    build_string ("Memory exhausted--use"
+			  " M-x save-some-buffers then"
+			  " exit and restart Emacs"));
 
   DEFVAR_LISP ("memory-full", Vmemory_full,
 	       doc: /* Non-nil means Emacs cannot get much more Lisp memory.  */);
diff --git a/src/buffer.c b/src/buffer.c
index ea785bbcd7..4abab37abd 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5222,8 +5222,8 @@ init_buffer_once (void)
   set_buffer_intervals (&buffer_defaults, NULL);
   set_buffer_intervals (&buffer_local_symbols, NULL);
   /* This is not strictly necessary, but let's make them initialized.  */
-  bset_name (&buffer_defaults, build_pure_c_string (" *buffer-defaults*"));
-  bset_name (&buffer_local_symbols, build_pure_c_string (" *buffer-local-symbols*"));
+  bset_name (&buffer_defaults, build_string (" *buffer-defaults*"));
+  bset_name (&buffer_local_symbols, build_string (" *buffer-local-symbols*"));
   BUFFER_PVEC_INIT (&buffer_defaults);
   BUFFER_PVEC_INIT (&buffer_local_symbols);
 
@@ -5231,7 +5231,7 @@ init_buffer_once (void)
   /* Must do these before making the first buffer! */
 
   /* real setup is done in bindings.el */
-  bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
+  bset_mode_line_format (&buffer_defaults, build_string ("%-"));
   bset_header_line_format (&buffer_defaults, Qnil);
   bset_abbrev_mode (&buffer_defaults, Qnil);
   bset_overwrite_mode (&buffer_defaults, Qnil);
@@ -5299,7 +5299,7 @@ init_buffer_once (void)
   all_buffers = 0;
   pdumper_remember_lv_ptr_raw (&all_buffers, Lisp_Vectorlike);
 
-  QSFundamental = build_pure_c_string ("Fundamental");
+  QSFundamental = build_string ("Fundamental");
 
   DEFSYM (Qfundamental_mode, "fundamental-mode");
   bset_major_mode (&buffer_defaults, Qfundamental_mode);
@@ -5312,10 +5312,10 @@ init_buffer_once (void)
   Fput (Qkill_buffer_hook, Qpermanent_local, Qt);
 
   /* Super-magic invisible buffer.  */
-  Vprin1_to_string_buffer = Fget_buffer_create (build_pure_c_string (" prin1"));
+  Vprin1_to_string_buffer = Fget_buffer_create (build_string (" prin1"));
   Vbuffer_alist = Qnil;
 
-  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*")));
+  Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
 
   inhibit_modification_hooks = 0;
 }
@@ -5500,9 +5500,9 @@ syms_of_buffer (void)
 	       Qoverwrite_mode_binary));
 
   Fput (Qprotected_field, Qerror_conditions,
-	pure_list (Qprotected_field, Qerror));
+	list (Qprotected_field, Qerror));
   Fput (Qprotected_field, Qerror_message,
-	build_pure_c_string ("Attempt to modify a protected field"));
+	build_string ("Attempt to modify a protected field"));
 
   DEFVAR_PER_BUFFER ("header-line-format",
 		     &BVAR (current_buffer, header_line_format),
diff --git a/src/callint.c b/src/callint.c
index 812287d365..910c1ab73f 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -816,10 +816,10 @@ syms_of_callint (void)
   callint_message = Qnil;
   staticpro (&callint_message);
 
-  preserved_fns = pure_list (intern_c_string ("region-beginning"),
-			     intern_c_string ("region-end"),
-			     intern_c_string ("point"),
-			     intern_c_string ("mark"));
+  preserved_fns = list (intern_c_string ("region-beginning"),
+			intern_c_string ("region-end"),
+			intern_c_string ("point"),
+			intern_c_string ("mark"));
   staticpro (&preserved_fns);
 
   DEFSYM (Qlist, "list");
diff --git a/src/category.c b/src/category.c
index 9e460cfc64..9e7864f319 100644
--- a/src/category.c
+++ b/src/category.c
@@ -53,7 +53,7 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
       (table, 1,
        make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			Qnil, false));
+			Qnil));
   struct Lisp_Hash_Table *h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
   Lisp_Object hash;
   ptrdiff_t i = hash_lookup (h, category_set, &hash);
@@ -120,8 +120,6 @@ DEFUN ("define-category", Fdefine_category, Sdefine_category, 2, 3, 0,
 
   if (!NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category))))
     error ("Category `%c' is already defined", (int) XFIXNAT (category));
-  if (!NILP (Vpurify_flag))
-    docstring = Fpurecopy (docstring);
   SET_CATEGORY_DOCSTRING (table, XFIXNAT (category), docstring);
 
   return Qnil;
diff --git a/src/coding.c b/src/coding.c
index 189a4b39d1..5654ae333d 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -10821,7 +10821,7 @@ syms_of_coding (void)
   Vcode_conversion_reused_workbuf = Qnil;
 
   staticpro (&Vcode_conversion_workbuf_name);
-  Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
+  Vcode_conversion_workbuf_name = build_string (" *code-conversion-work*");
 
   reused_workbuf_in_use = 0;
   PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
@@ -10885,9 +10885,9 @@ syms_of_coding (void)
   /* Error signaled when there's a problem with detecting a coding system.  */
   DEFSYM (Qcoding_system_error, "coding-system-error");
   Fput (Qcoding_system_error, Qerror_conditions,
-	pure_list (Qcoding_system_error, Qerror));
+	list (Qcoding_system_error, Qerror));
   Fput (Qcoding_system_error, Qerror_message,
-	build_pure_c_string ("Invalid coding system"));
+	build_string ("Invalid coding system"));
 
   DEFSYM (Qtranslation_table, "translation-table");
   Fput (Qtranslation_table, Qchar_table_extra_slots, make_fixnum (2));
@@ -11154,22 +11154,22 @@ syms_of_coding (void)
   DEFVAR_LISP ("eol-mnemonic-unix", eol_mnemonic_unix,
 	       doc: /*
 String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
-  eol_mnemonic_unix = build_pure_c_string (":");
+  eol_mnemonic_unix = build_string (":");
 
   DEFVAR_LISP ("eol-mnemonic-dos", eol_mnemonic_dos,
 	       doc: /*
 String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
-  eol_mnemonic_dos = build_pure_c_string ("\\");
+  eol_mnemonic_dos = build_string ("\\");
 
   DEFVAR_LISP ("eol-mnemonic-mac", eol_mnemonic_mac,
 	       doc: /*
 String displayed in mode line for MAC-like (CR) end-of-line format.  */);
-  eol_mnemonic_mac = build_pure_c_string ("/");
+  eol_mnemonic_mac = build_string ("/");
 
   DEFVAR_LISP ("eol-mnemonic-undecided", eol_mnemonic_undecided,
 	       doc: /*
 String displayed in mode line when end-of-line format is not yet determined.  */);
-  eol_mnemonic_undecided = build_pure_c_string (":");
+  eol_mnemonic_undecided = build_string (":");
 
   DEFVAR_LISP ("enable-character-translation", Venable_character_translation,
 	       doc: /*
@@ -11309,7 +11309,7 @@ system (e.g. `iso-2022-7bit').
       intern_c_string (":for-unibyte"),
       args[coding_arg_for_unibyte] = Qt,
       intern_c_string (":docstring"),
-      (build_pure_c_string
+      (build_string
        ("Do no conversion.\n"
 	"\n"
 	"When you visit a file with this coding, the file is read into a\n"
@@ -11329,7 +11329,7 @@ system (e.g. `iso-2022-7bit').
   plist[8] = intern_c_string (":charset-list");
   plist[9] = args[coding_arg_charset_list] = list1 (Qascii);
   plist[11] = args[coding_arg_for_unibyte] = Qnil;
-  plist[13] = build_pure_c_string ("No conversion on encoding, "
+  plist[13] = build_string ("No conversion on encoding, "
 				   "automatic conversion on decoding.");
   plist[15] = args[coding_arg_eol_type] = Qnil;
   args[coding_arg_plist] = CALLMANY (Flist, plist);
diff --git a/src/conf_post.h b/src/conf_post.h
index 4af1ba9331..92eaf75375 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -158,41 +158,8 @@ #define emacs_raise(sig) msdos_fatal_signal (sig)
 
 /* DATA_START is needed by vm-limit.c and unexcoff.c. */
 #define DATA_START (&etext + 1)
-
-/* Define one of these for easier conditionals.  */
-#ifdef HAVE_X_WINDOWS
-/* We need a little extra space, see ../../lisp/loadup.el and the
-   commentary below, in the non-X branch.  The 140KB number was
-   measured on GNU/Linux and on MS-Windows.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+140000)
-#else
-/* We need a little extra space, see ../../lisp/loadup.el.
-   As of 20091024, DOS-specific files use up 62KB of pure space.  But
-   overall, we end up wasting 130KB of pure space, because
-   BASE_PURESIZE starts at 1.47MB, while we need only 1.3MB (including
-   non-DOS specific files and load history; the latter is about 55K,
-   but depends on the depth of the top-level Emacs directory in the
-   directory tree).  Given the unknown policy of different DPMI
-   hosts regarding loading of untouched pages, I'm not going to risk
-   enlarging Emacs footprint by another 100+ KBytes.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+90000)
-#endif
 #endif  /* MSDOS */
 
-/* macOS / GNUstep need a bit more pure memory.  Of the existing knobs,
-   SYSTEM_PURESIZE_EXTRA seems like the least likely to cause problems.  */
-#ifdef HAVE_NS
-#if defined NS_IMPL_GNUSTEP
-#  define SYSTEM_PURESIZE_EXTRA 30000
-#elif defined DARWIN_OS
-#  define SYSTEM_PURESIZE_EXTRA 200000
-#endif
-#endif
-
-#ifdef CYGWIN
-#define SYSTEM_PURESIZE_EXTRA 50000
-#endif
-
 #if defined HAVE_NTGUI && !defined DebPrint
 # ifdef EMACSDEBUG
 extern void _DebPrint (const char *fmt, ...);
diff --git a/src/data.c b/src/data.c
index 46bd7e0e25..39d0d4bdfa 100644
--- a/src/data.c
+++ b/src/data.c
@@ -30,7 +30,6 @@
 
 #include "lisp.h"
 #include "bignum.h"
-#include "puresize.h"
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
@@ -155,12 +154,6 @@ wrong_type_argument (register Lisp_Object predicate, register Lisp_Object value)
   xsignal2 (Qwrong_type_argument, predicate, value);
 }
 
-void
-pure_write_error (Lisp_Object obj)
-{
-  xsignal2 (Qerror, build_string ("Attempt to modify read-only object"), obj);
-}
-
 void
 args_out_of_range (Lisp_Object a1, Lisp_Object a2)
 {
@@ -631,7 +624,6 @@ DEFUN ("setcar", Fsetcar, Ssetcar, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcar)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCAR (cell, newcar);
   return newcar;
 }
@@ -641,7 +633,6 @@ DEFUN ("setcdr", Fsetcdr, Ssetcdr, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcdr)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCDR (cell, newcdr);
   return newcdr;
 }
@@ -795,10 +786,6 @@ DEFUN ("defalias", Fdefalias, Sdefalias, 2, 3, 0,
   (register Lisp_Object symbol, Lisp_Object definition, Lisp_Object docstring)
 {
   CHECK_SYMBOL (symbol);
-  if (!NILP (Vpurify_flag)
-      /* If `definition' is a keymap, immutable (and copying) is wrong.  */
-      && !KEYMAPP (definition))
-    definition = Fpurecopy (definition);
 
   {
     bool autoload = AUTOLOADP (definition);
@@ -2271,7 +2258,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
 
   if (VECTORP (array))
     {
-      CHECK_IMPURE (array, XVECTOR (array));
       if (idxval < 0 || idxval >= ASIZE (array))
 	args_out_of_range (array, idx);
       ASET (array, idxval, newelt);
@@ -2297,7 +2283,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
     {
       int c;
 
-      CHECK_IMPURE (array, XSTRING (array));
       if (idxval < 0 || idxval >= SCHARS (array))
 	args_out_of_range (array, idx);
       CHECK_CHARACTER (newelt);
@@ -3854,7 +3839,7 @@ syms_of_data (void)
 
   DEFSYM (Qcdr, "cdr");
 
-  error_tail = pure_cons (Qerror, Qnil);
+  error_tail = Fcons (Qerror, Qnil);
 
   /* ERROR is used as a signaler for random errors for which nothing else is
      right.  */
@@ -3862,11 +3847,11 @@ syms_of_data (void)
   Fput (Qerror, Qerror_conditions,
 	error_tail);
   Fput (Qerror, Qerror_message,
-	build_pure_c_string ("error"));
+	build_string ("error"));
 
 #define PUT_ERROR(sym, tail, msg)			\
-  Fput (sym, Qerror_conditions, pure_cons (sym, tail)); \
-  Fput (sym, Qerror_message, build_pure_c_string (msg))
+  Fput (sym, Qerror_conditions, Fcons (sym, tail)); \
+  Fput (sym, Qerror_message, build_string (msg))
 
   PUT_ERROR (Qquit, Qnil, "Quit");
 
@@ -3894,14 +3879,14 @@ #define PUT_ERROR(sym, tail, msg)			\
   PUT_ERROR (Qno_catch, error_tail, "No catch for tag");
   PUT_ERROR (Qend_of_file, error_tail, "End of file during parsing");
 
-  arith_tail = pure_cons (Qarith_error, error_tail);
+  arith_tail = Fcons (Qarith_error, error_tail);
   Fput (Qarith_error, Qerror_conditions, arith_tail);
-  Fput (Qarith_error, Qerror_message, build_pure_c_string ("Arithmetic error"));
+  Fput (Qarith_error, Qerror_message, build_string ("Arithmetic error"));
 
   PUT_ERROR (Qbeginning_of_buffer, error_tail, "Beginning of buffer");
   PUT_ERROR (Qend_of_buffer, error_tail, "End of buffer");
   PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only");
-  PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail),
+  PUT_ERROR (Qtext_read_only, Fcons (Qbuffer_read_only, error_tail),
 	     "Text is read-only");
 
   DEFSYM (Qrange_error, "range-error");
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 90ba461c6b..4c9bb4abca 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1690,7 +1690,7 @@ syms_of_dbusbind (void)
   Fput (Qdbus_error, Qerror_conditions,
 	list2 (Qdbus_error, Qerror));
   Fput (Qdbus_error, Qerror_message,
-	build_pure_c_string ("D-Bus error"));
+	build_string ("D-Bus error"));
 
   /* Lisp symbols of the system and session buses.  */
   DEFSYM (QCsystem, ":system");
@@ -1729,7 +1729,7 @@ syms_of_dbusbind (void)
 	       Vdbus_compiled_version,
     doc: /* The version of D-Bus Emacs is compiled against.  */);
 #ifdef DBUS_VERSION_STRING
-  Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
+  Vdbus_compiled_version = build_string (DBUS_VERSION_STRING);
 #else
   Vdbus_compiled_version = Qnil;
 #endif
diff --git a/src/deps.mk b/src/deps.mk
index 2cdeba8d4a..637d82c35f 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -132,10 +132,10 @@ insdel.o:
 keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \
    commands.h frame.h window.h macros.h disptab.h keyboard.h syssignal.h \
    systime.h syntax.h $(INTERVALS_H) blockinput.h atimer.h composite.h \
-   xterm.h puresize.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
+   xterm.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
    process.h ../lib/unistd.h gnutls.h lisp.h globals.h $(config_h)
 keymap.o: keymap.c buffer.h commands.h keyboard.h termhooks.h blockinput.h \
-   atimer.h systime.h puresize.h character.h charset.h $(INTERVALS_H) \
+   atimer.h systime.h character.h charset.h $(INTERVALS_H) \
    keymap.h window.h coding.h frame.h lisp.h globals.h $(config_h)
 lastfile.o: lastfile.c $(config_h)
 macros.o: macros.c window.h buffer.h commands.h macros.h keyboard.h msdos.h \
@@ -270,12 +270,12 @@ xsettings.o:
    atimer.h termopts.h globals.h
 
 ## The files of Lisp proper.
-alloc.o: alloc.c process.h frame.h window.h buffer.h  puresize.h syssignal.h \
+alloc.o: alloc.c process.h frame.h window.h buffer.h syssignal.h \
    keyboard.h blockinput.h atimer.h systime.h character.h lisp.h $(config_h) \
    $(INTERVALS_H) termhooks.h gnutls.h coding.h ../lib/unistd.h globals.h
 bytecode.o: bytecode.c buffer.h syntax.h character.h window.h dispextern.h \
   lisp.h globals.h $(config_h) msdos.h
-data.o: data.c buffer.h puresize.h character.h syssignal.h keyboard.h frame.h \
+data.o: data.c buffer.h character.h syssignal.h keyboard.h frame.h \
    termhooks.h systime.h coding.h composite.h dispextern.h font.h ccl.h \
    lisp.h globals.h $(config_h) msdos.h
 eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h frame.h \
@@ -298,7 +298,7 @@ lread.o:
 composite.o: composite.c composite.h buffer.h character.h coding.h font.h \
    ccl.h frame.h termhooks.h $(INTERVALS_H) window.h \
    lisp.h globals.h $(config_h)
-intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h puresize.h \
+intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h \
    keymap.h lisp.h globals.h $(config_h) systime.h coding.h
 textprop.o: textprop.c buffer.h window.h $(INTERVALS_H) \
    lisp.h globals.h $(config_h)
diff --git a/src/doc.c b/src/doc.c
index 8b663f0f24..5cc268b7e9 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -500,8 +500,6 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
 	{
 	  tem = Fcdr (Fcdr (fun));
 	  if (CONSP (tem) && FIXNUMP (XCAR (tem)))
-	    /* FIXME: This modifies typically pure hash-cons'd data, so its
-	       correctness is quite delicate.  */
 	    XSETCAR (tem, make_fixnum (offset));
 	}
     }
@@ -585,7 +583,6 @@ DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
       int i = ARRAYELTS (buildobj);
       while (0 <= --i)
 	Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
-      Vbuild_files = Fpurecopy (Vbuild_files);
     }
 
   fd = emacs_open (name, O_RDONLY, 0);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index 4b991a1c74..cb302c7022 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -1328,40 +1328,40 @@ syms_of_module (void)
 
   DEFSYM (Qmodule_load_failed, "module-load-failed");
   Fput (Qmodule_load_failed, Qerror_conditions,
-	pure_list (Qmodule_load_failed, Qerror));
+	list (Qmodule_load_failed, Qerror));
   Fput (Qmodule_load_failed, Qerror_message,
-        build_pure_c_string ("Module load failed"));
+        build_string ("Module load failed"));
 
   DEFSYM (Qmodule_open_failed, "module-open-failed");
   Fput (Qmodule_open_failed, Qerror_conditions,
-	pure_list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_open_failed, Qerror_message,
-        build_pure_c_string ("Module could not be opened"));
+        build_string ("Module could not be opened"));
 
   DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible");
   Fput (Qmodule_not_gpl_compatible, Qerror_conditions,
-	pure_list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
+	list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
   Fput (Qmodule_not_gpl_compatible, Qerror_message,
-        build_pure_c_string ("Module is not GPL compatible"));
+        build_string ("Module is not GPL compatible"));
 
   DEFSYM (Qmissing_module_init_function, "missing-module-init-function");
   Fput (Qmissing_module_init_function, Qerror_conditions,
-	pure_list (Qmissing_module_init_function, Qmodule_load_failed,
-		   Qerror));
+	list (Qmissing_module_init_function, Qmodule_load_failed,
+	      Qerror));
   Fput (Qmissing_module_init_function, Qerror_message,
-        build_pure_c_string ("Module does not export an "
+        build_string ("Module does not export an "
                              "initialization function"));
 
   DEFSYM (Qmodule_init_failed, "module-init-failed");
   Fput (Qmodule_init_failed, Qerror_conditions,
-	pure_list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_init_failed, Qerror_message,
-        build_pure_c_string ("Module initialization failed"));
+        build_string ("Module initialization failed"));
 
   DEFSYM (Qinvalid_arity, "invalid-arity");
-  Fput (Qinvalid_arity, Qerror_conditions, pure_list (Qinvalid_arity, Qerror));
+  Fput (Qinvalid_arity, Qerror_conditions, list (Qinvalid_arity, Qerror));
   Fput (Qinvalid_arity, Qerror_message,
-        build_pure_c_string ("Invalid function arity"));
+        build_string ("Invalid function arity"));
 
   DEFSYM (Qmodule_function_p, "module-function-p");
 
diff --git a/src/emacs.c b/src/emacs.c
index ad661a081b..f4f42a908c 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -89,7 +89,6 @@ #define MAIN_PROGRAM
 #include "syntax.h"
 #include "sysselect.h"
 #include "systime.h"
-#include "puresize.h"
 
 #include "getpagesize.h"
 #include "gnutls.h"
@@ -2537,8 +2536,6 @@ DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
   Lisp_Object symbol;
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  check_pure_size ();
-
   if (! noninteractive)
     error ("Dumping Emacs works only in batch mode");
 
diff --git a/src/eval.c b/src/eval.c
index 02a6c3555a..a4f37c295a 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -725,8 +725,6 @@ DEFUN ("internal--define-uninitialized-variable",
   XSYMBOL (symbol)->u.s.declared_special = true;
   if (!NILP (doc))
     {
-      if (!NILP (Vpurify_flag))
-	doc = Fpurecopy (doc);
       Fput (symbol, Qvariable_documentation, doc);
     }
   LOADHIST_ATTACH (symbol);
@@ -840,8 +838,6 @@ DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
 
   Finternal__define_uninitialized_variable (sym, docstring);
   tem = eval_sub (XCAR (XCDR (args)));
-  if (!NILP (Vpurify_flag))
-    tem = Fpurecopy (tem);
   Fset_default (sym, tem);      /* FIXME: set-default-toplevel-value? */
   Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why?  */
   return sym;
@@ -1986,12 +1982,6 @@ DEFUN ("autoload", Fautoload, Sautoload, 2, 5, 0,
       && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_fixnum (0)))
-    /* `read1' in lread.c has found the docstring starting with "\
-       and assumed the docstring will be provided by Snarf-documentation, so it
-       passed us 0 instead.  But that leads to accidental sharing in purecopy's
-       hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_fixnum (XHASH (function));
   return Fdefalias (function,
 		    list5 (Qautoload, file, docstring, interactive, type),
 		    Qnil);
@@ -4182,7 +4172,7 @@ syms_of_eval (void)
      also use something like Fcons (Qnil, Qnil), but json.c treats any
      cons cell as error data, so use an uninterned symbol instead.  */
   Qcatch_all_memory_full
-    = Fmake_symbol (build_pure_c_string ("catch-all-memory-full"));
+    = Fmake_symbol (build_string ("catch-all-memory-full"));
 
   defsubr (&Sor);
   defsubr (&Sand);
diff --git a/src/fileio.c b/src/fileio.c
index 7f83267956..5b0c9d4cab 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6227,29 +6227,29 @@ syms_of_fileio (void)
   DEFSYM (Qcar_less_than_car, "car-less-than-car");
 
   Fput (Qfile_error, Qerror_conditions,
-	Fpurecopy (list2 (Qfile_error, Qerror)));
+	list2 (Qfile_error, Qerror));
   Fput (Qfile_error, Qerror_message,
-	build_pure_c_string ("File error"));
+	build_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
+	list3 (Qfile_already_exists, Qfile_error, Qerror));
   Fput (Qfile_already_exists, Qerror_message,
-	build_pure_c_string ("File already exists"));
+	build_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
+	list3 (Qfile_date_error, Qfile_error, Qerror));
   Fput (Qfile_date_error, Qerror_message,
-	build_pure_c_string ("Cannot set file date"));
+	build_string ("Cannot set file date"));
 
   Fput (Qfile_missing, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_missing, Qfile_error, Qerror)));
+	list3 (Qfile_missing, Qfile_error, Qerror));
   Fput (Qfile_missing, Qerror_message,
-	build_pure_c_string ("File is missing"));
+	build_string ("File is missing"));
 
   Fput (Qfile_notify_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_notify_error, Qfile_error, Qerror)));
+	list3 (Qfile_notify_error, Qfile_error, Qerror));
   Fput (Qfile_notify_error, Qerror_message,
-	build_pure_c_string ("File notification error"));
+	build_string ("File notification error"));
 
   DEFVAR_LISP ("file-name-handler-alist", Vfile_name_handler_alist,
 	       doc: /* Alist of elements (REGEXP . HANDLER) for file names handled specially.
diff --git a/src/fns.c b/src/fns.c
index d7e123122d..1297db9acf 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -35,7 +35,6 @@ Copyright (C) 1985-1987, 1993-1995, 1997-2019 Free Software Foundation,
 #include "buffer.h"
 #include "intervals.h"
 #include "window.h"
-#include "puresize.h"
 #include "gnutls.h"
 
 #if defined WINDOWSNT && defined HAVE_GNUTLS3
@@ -4066,16 +4065,12 @@ #define INDEX_SIZE_BOUND \
    size exceeds REHASH_THRESHOLD.
 
    WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value', `key-or-value', or `key-and-value'.
-
-   If PURECOPY is non-nil, the table can be copied to pure storage via
-   `purecopy' when Emacs is being dumped. Such tables can no longer be
-   changed after purecopy.  */
+   one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
 
 Lisp_Object
 make_hash_table (struct hash_table_test test, EMACS_INT size,
 		 float rehash_size, float rehash_threshold,
-		 Lisp_Object weak, bool purecopy)
+		 Lisp_Object weak)
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
@@ -4114,7 +4109,6 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
   h->next = make_vector (size, make_fixnum (-1));
   h->index = make_vector (index_size, make_fixnum (-1));
   h->next_weak = NULL;
-  h->purecopy = purecopy;
   h->mutable = true;
 
   /* Set up the free list.  */
@@ -4214,10 +4208,6 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
 	    set_hash_index_slot (h, start_of_bucket, i);
 	  }
 
-#ifdef ENABLE_CHECKING
-      if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h)
-	message ("Growing hash table to: %"pD"d", new_size);
-#endif
     }
 }
 
@@ -4302,7 +4292,6 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h)
 {
   if (!h->mutable)
     signal_error ("hash table test modifies table", obj);
-  eassert (!PURE_P (h));
 }
 
 /* Put an entry into hash table H that associates KEY with VALUE.
@@ -4760,16 +4749,10 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
 WEAK.  WEAK t is equivalent to `key-and-value'.  Default value of WEAK
 is nil.
 
-:purecopy PURECOPY -- If PURECOPY is non-nil, the table can be copied
-to pure storage when Emacs is being dumped, making the contents of the
-table read only. Any further changes to purified tables will result
-in an error.
-
 usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object test, weak;
-  bool purecopy;
   struct hash_table_test testdesc;
   ptrdiff_t i;
   USE_SAFE_ALLOCA;
@@ -4803,9 +4786,8 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       testdesc.cmpfn = cmpfn_user_defined;
     }
 
-  /* See if there's a `:purecopy PURECOPY' argument.  */
-  i = get_key_arg (QCpurecopy, nargs, args, used);
-  purecopy = i && !NILP (args[i]);
+  /* Ignore a `:purecopy PURECOPY' argument.  */
+  get_key_arg (QCpurecopy, nargs, args, used);
   /* See if there's a `:size SIZE' argument.  */
   i = get_key_arg (QCsize, nargs, args, used);
   Lisp_Object size_arg = i ? args[i] : Qnil;
@@ -4855,8 +4837,7 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       signal_error ("Invalid argument list", args[i]);
 
   SAFE_FREE ();
-  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak,
-			  purecopy);
+  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
 }
 
 
diff --git a/src/fontset.c b/src/fontset.c
index 828e7fe70c..c55196f324 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -2128,7 +2128,7 @@ syms_of_fontset (void)
   set_fontset_id (Vdefault_fontset, make_fixnum (0));
   set_fontset_name
     (Vdefault_fontset,
-     build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
+     build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
   ASET (Vfontset_table, 0, Vdefault_fontset);
   next_fontset_id = 1;
   PDUMPER_REMEMBER_SCALAR (next_fontset_id);
@@ -2186,7 +2186,7 @@ syms_of_fontset (void)
 	       doc: /* Alist of fontset names vs the aliases.  */);
   Vfontset_alias_alist
     = list1 (Fcons (FONTSET_NAME (Vdefault_fontset),
-		    build_pure_c_string ("fontset-default")));
+		    build_string ("fontset-default")));
 
   DEFVAR_LISP ("vertical-centering-font-regexp",
 	       Vvertical_centering_font_regexp,
diff --git a/src/frame.c b/src/frame.c
index 6363a87368..a5e617b092 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1068,7 +1068,7 @@ make_initial_frame (void)
   Vframe_list = Fcons (frame, Vframe_list);
 
   tty_frame_count = 1;
-  fset_name (f, build_pure_c_string ("F1"));
+  fset_name (f, build_string ("F1"));
 
   SET_FRAME_VISIBLE (f, 1);
 
diff --git a/src/intervals.c b/src/intervals.c
index 38367460a5..c58611cb21 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -44,7 +44,6 @@
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "puresize.h"
 #include "keymap.h"
 
 /* Test for membership, allowing for t (actually any non-cons) to mean the
@@ -101,7 +100,6 @@ create_root_interval (Lisp_Object parent)
     }
   else
     {
-      CHECK_IMPURE (parent, XSTRING (parent));
       new->total_length = SCHARS (parent);
       eassert (TOTAL_LENGTH (new) >= 0);
       set_string_intervals (parent, new);
diff --git a/src/json.c b/src/json.c
index d05f2c54e2..0ce2ac94a6 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1106,8 +1106,8 @@ define_error (Lisp_Object name, const char *message, Lisp_Object parent)
   eassert (CONSP (parent_conditions));
   eassert (!NILP (Fmemq (parent, parent_conditions)));
   eassert (NILP (Fmemq (name, parent_conditions)));
-  Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
-  Fput (name, Qerror_message, build_pure_c_string (message));
+  Fput (name, Qerror_conditions, Fcons (name, parent_conditions));
+  Fput (name, Qerror_message, build_string (message));
 }
 
 void
diff --git a/src/keyboard.c b/src/keyboard.c
index b86ad03851..1a784b5330 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1106,8 +1106,6 @@ top_level_1 (Lisp_Object ignore)
   /* On entry to the outer level, run the startup file.  */
   if (!NILP (Vtop_level))
     internal_condition_case (top_level_2, Qerror, cmd_error);
-  else if (!NILP (Vpurify_flag))
-    message1 ("Bare impure Emacs (standard Lisp code not loaded)");
   else
     message1 ("Bare Emacs (standard Lisp code not loaded)");
   return Qnil;
@@ -11034,14 +11032,14 @@ syms_of_keyboard (void)
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
-  Vlispy_mouse_stem = build_pure_c_string ("mouse");
+  Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
-  regular_top_level_message = build_pure_c_string ("Back to top level");
+  regular_top_level_message = build_string ("Back to top level");
   staticpro (&regular_top_level_message);
 #ifdef HAVE_STACK_OVERFLOW_HANDLING
   recover_top_level_message
-    = build_pure_c_string ("Re-entering top level after C stack overflow");
+    = build_string ("Re-entering top level after C stack overflow");
   staticpro (&recover_top_level_message);
 #endif
   DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
diff --git a/src/keymap.c b/src/keymap.c
index 6762915f70..bcc48b9520 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -50,7 +50,6 @@
 #include "keyboard.h"
 #include "termhooks.h"
 #include "blockinput.h"
-#include "puresize.h"
 #include "intervals.h"
 #include "keymap.h"
 #include "window.h"
@@ -138,8 +137,6 @@ DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 1, 0,
 {
   if (!NILP (string))
     {
-      if (!NILP (Vpurify_flag))
-	string = Fpurecopy (string);
       return list2 (Qkeymap, string);
     }
   return list1 (Qkeymap);
@@ -336,7 +333,6 @@ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
 	 If we came to the end, add the parent in PREV.  */
       if (!CONSP (list) || KEYMAPP (list))
 	{
-	  CHECK_IMPURE (prev, XCONS (prev));
 	  XSETCDR (prev, parent);
 	  return parent;
 	}
@@ -757,7 +753,7 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 
   /* If we are preparing to dump, and DEF is a menu element
      with a menu item indicator, copy it to ensure it is not pure.  */
-  if (CONSP (def) && PURE_P (XCONS (def))
+  if (CONSP (def)
       && (EQ (XCAR (def), Qmenu_item) || STRINGP (XCAR (def))))
     def = Fcons (XCAR (def), XCDR (def));
 
@@ -805,7 +801,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	  {
 	    if (FIXNATP (idx) && XFIXNAT (idx) < ASIZE (elt))
 	      {
-		CHECK_IMPURE (elt, XVECTOR (elt));
 		ASET (elt, XFIXNAT (idx), def);
 		return def;
 	      }
@@ -858,7 +853,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	      }
 	    else if (EQ (idx, XCAR (elt)))
 	      {
-		CHECK_IMPURE (elt, XCONS (elt));
 		XSETCDR (elt, def);
 		return def;
 	      }
@@ -904,7 +898,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	}
       else
 	elt = Fcons (idx, def);
-      CHECK_IMPURE (insertion_point, XCONS (insertion_point));
       XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
     }
   }
@@ -3604,12 +3597,12 @@ syms_of_keymap (void)
   Fset (intern_c_string ("ctl-x-map"), control_x_map);
   Ffset (intern_c_string ("Control-X-prefix"), control_x_map);
 
-  exclude_keys = pure_list
-    (pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")),
-     pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")),
-     pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")),
-     pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")),
-     pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" ")));
+  exclude_keys = list
+    (Fcons (build_string ("DEL"), build_string ("\\d")),
+     Fcons (build_string ("TAB"), build_string ("\\t")),
+     Fcons (build_string ("RET"), build_string ("\\r")),
+     Fcons (build_string ("ESC"), build_string ("\\e")),
+     Fcons (build_string ("SPC"), build_string (" ")));
   staticpro (&exclude_keys);
 
   DEFVAR_LISP ("define-key-rebound-commands", Vdefine_key_rebound_commands,
@@ -3665,12 +3658,12 @@ syms_of_keymap (void)
   DEFSYM (Qmode_line, "mode-line");
 
   staticpro (&Vmouse_events);
-  Vmouse_events = pure_list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
-			     intern_c_string ("mouse-1"),
-			     intern_c_string ("mouse-2"),
-			     intern_c_string ("mouse-3"),
-			     intern_c_string ("mouse-4"),
-			     intern_c_string ("mouse-5"));
+  Vmouse_events = list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
+			intern_c_string ("mouse-1"),
+			intern_c_string ("mouse-2"),
+			intern_c_string ("mouse-3"),
+			intern_c_string ("mouse-4"),
+			intern_c_string ("mouse-5"));
 
   /* Keymap used for minibuffers when doing completion.  */
   /* Keymap used for minibuffers when doing completion and require a match.  */
diff --git a/src/lisp.h b/src/lisp.h
index 6d101fed90..8fb6f493b3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -821,9 +821,6 @@ #define XUNTAG(a, type, ctype) ((ctype *) \
 	 special (with `defvar' etc), and shouldn't be lexically bound.  */
       bool_bf declared_special : 1;
 
-      /* True if pointed to from purespace and hence can't be GC'd.  */
-      bool_bf pinned : 1;
-
       /* The symbol's name, as a Lisp string.  */
       Lisp_Object name;
 
@@ -1513,20 +1510,14 @@ #define STRING_BYTES_BOUND  \
 /* Mark STR as a unibyte string.  */
 #define STRING_SET_UNIBYTE(STR)				\
   do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_unibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = -1;		\
+    XSTRING (STR)->u.s.size_byte = -1;			\
   } while (false)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
-#define STRING_SET_MULTIBYTE(STR)			\
-  do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_multibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
+#define STRING_SET_MULTIBYTE(STR)				\
+  do {								\
+    XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size;	\
   } while (false)
 
 /* Convenience functions for dealing with Lisp strings.  */
@@ -2287,12 +2278,8 @@ #define DEFSYM(sym, name) /* empty */
   /* Index of first free entry in free list, or -1 if none.  */
   ptrdiff_t next_free;
 
-  /* True if the table can be purecopied.  The table cannot be
-     changed afterwards.  */
-  bool purecopy;
-
   /* True if the table is mutable.  Ordinarily tables are mutable, but
-     pure tables are not, and while a table is being mutated it is
+     some tables are not, and while a table is being mutated it is
      immutable for recursive attempts to mutate it.  */
   bool mutable;
 
@@ -3601,7 +3588,7 @@ #define CONS_TO_INTEGER(cons, type, var)				\
 Lisp_Object hashfn_eql (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object hashfn_equal (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
-                             Lisp_Object, bool);
+                             Lisp_Object);
 ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object *);
 ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
 		    Lisp_Object);
@@ -3752,7 +3739,6 @@ #define CONS_TO_INTEGER(cons, type, var)				\
 
 /* Defined in alloc.c.  */
 extern void *my_heap_start (void);
-extern void check_pure_size (void);
 extern void allocate_string_data (struct Lisp_String *, EMACS_INT, EMACS_INT);
 extern void malloc_warning (const char *);
 extern AVOID memory_full (size_t);
@@ -3783,11 +3769,8 @@ #define OBJECT_CT_MAX INTPTR_MAX
 extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
 			  Lisp_Object);
 extern Lisp_Object listn (ptrdiff_t, Lisp_Object, ...);
-extern Lisp_Object pure_listn (ptrdiff_t, Lisp_Object, ...);
 #define list(...) \
   listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
-#define pure_list(...) \
-  pure_listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
 
 enum gc_root_type
 {
@@ -3861,17 +3844,6 @@ build_unibyte_string (const char *str)
 extern Lisp_Object make_string_from_bytes (const char *, ptrdiff_t, ptrdiff_t);
 extern Lisp_Object make_specified_string (const char *,
 					  ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_string (const char *, ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_c_string (const char *, ptrdiff_t);
-
-/* Make a string allocated in pure space, use STR as string data.  */
-
-INLINE Lisp_Object
-build_pure_c_string (const char *str)
-{
-  return make_pure_c_string (str, strlen (str));
-}
-
 /* Make a string from the data at STR, treating it as multibyte if the
    data warrants.  */
 
@@ -3881,7 +3853,6 @@ build_string (const char *str)
   return make_string (str, strlen (str));
 }
 
-extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
 extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
 extern void make_byte_code (struct Lisp_Vector *);
 extern struct Lisp_Vector *allocate_vector (ptrdiff_t);
diff --git a/src/lread.c b/src/lread.c
index eecb5e141d..4ff7808527 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2043,13 +2043,13 @@ readevalloop (Lisp_Object readcharfun,
 	read_objects_map
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (! HASH_TABLE_P (read_objects_completed)
 	  || XHASH_TABLE (read_objects_completed)->count)
 	read_objects_completed
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (!NILP (Vpurify_flag) && c == '(')
 	{
 	  val = read_list (0, readcharfun);
@@ -2261,12 +2261,12 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
       || XHASH_TABLE (read_objects_map)->count)
     read_objects_map
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (! HASH_TABLE_P (read_objects_completed)
       || XHASH_TABLE (read_objects_completed)->count)
     read_objects_completed
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (EQ (Vread_with_symbol_positions, Qt)
       || EQ (Vread_with_symbol_positions, stream))
     Vread_symbol_positions_list = Qnil;
@@ -2835,11 +2835,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      if (!NILP (params[param_count + 1]))
 		param_count += 2;
 
-              params[param_count] = QCpurecopy;
-              params[param_count + 1] = Fplist_get (tmp, Qpurecopy);
-              if (!NILP (params[param_count + 1]))
-                param_count += 2;
-
 	      /* This is the hash table data.  */
 	      data = Fplist_get (tmp, Qdata);
 
@@ -3109,13 +3104,13 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      /* No symbol character follows, this is the empty
 		 symbol.  */
 	      UNREAD (c);
-	      return Fmake_symbol (empty_unibyte_string);
+	      return Fmake_symbol (build_string (""));
 	    }
 	  goto read_symbol;
 	}
       /* ## is the empty symbol.  */
       if (c == '#')
-	return Fintern (empty_unibyte_string, Qnil);
+	return Fintern (build_string (""), Qnil);
 
       if (c >= '0' && c <= '9')
 	{
@@ -3566,9 +3561,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	  if (uninterned_symbol)
 	    {
 	      Lisp_Object name
-		= ((! NILP (Vpurify_flag)
-		    ? make_pure_string : make_specified_string)
-		   (read_buffer, nchars, nbytes, multibyte));
+		= make_specified_string (read_buffer, nchars, nbytes,
+					 multibyte);
 	      result = Fmake_symbol (name);
 	    }
 	  else
@@ -4153,10 +4147,8 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 
   if (!SYMBOLP (tem))
     {
-      /* Creating a non-pure string from a string literal not implemented yet.
-	 We could just use make_string here and live with the extra copy.  */
       eassert (!NILP (Vpurify_flag));
-      tem = intern_driver (make_pure_c_string (str, len), obarray, tem);
+      tem = intern_driver (make_string (str, len), obarray, tem);
     }
   return tem;
 }
@@ -4165,7 +4157,7 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 define_symbol (Lisp_Object sym, char const *str)
 {
   ptrdiff_t len = strlen (str);
-  Lisp_Object string = make_pure_c_string (str, len);
+  Lisp_Object string = make_string (str, len);
   init_symbol (sym, string);
 
   /* Qunbound is uninterned, so that it's not confused with any symbol
@@ -4192,8 +4184,7 @@ DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
 
   tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
   if (!SYMBOLP (tem))
-    tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
-			 obarray, tem);
+    tem = intern_driver (string, obarray, tem);
   return tem;
 }
 
@@ -4843,17 +4834,17 @@ syms_of_lread (void)
 `load' and related functions try to append these suffixes, in order,
 to the specified file name if a suffix is allowed or required.  */);
 #ifdef HAVE_MODULES
-  Vload_suffixes = list3 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX));
+  Vload_suffixes = list3 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX));
 #else
-  Vload_suffixes = list2 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"));
+  Vload_suffixes = list2 (build_string (".elc"),
+			  build_string (".el"));
 #endif
   DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
 	       doc: /* Suffix of loadable module file, or nil if modules are not supported.  */);
 #ifdef HAVE_MODULES
-  Vmodule_file_suffix = build_pure_c_string (MODULES_SUFFIX);
+  Vmodule_file_suffix = build_string (MODULES_SUFFIX);
 #else
   Vmodule_file_suffix = Qnil;
 #endif
@@ -4996,7 +4987,7 @@ syms_of_lread (void)
 When the regular expression matches, the file is considered to be safe
 to load.  See also `load-dangerous-libraries'.  */);
   Vbytecomp_version_regexp
-    = build_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
   DEFSYM (Qlexical_binding, "lexical-binding");
   DEFVAR_LISP ("lexical-binding", Vlexical_binding,
diff --git a/src/pdumper.c b/src/pdumper.c
index 2abac80a37..efebe8e57c 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2471,7 +2471,6 @@ dump_symbol (struct dump_context *ctx,
   DUMP_FIELD_COPY (&out, symbol, u.s.trapped_write);
   DUMP_FIELD_COPY (&out, symbol, u.s.interned);
   DUMP_FIELD_COPY (&out, symbol, u.s.declared_special);
-  DUMP_FIELD_COPY (&out, symbol, u.s.pinned);
   dump_field_lv (ctx, &out, symbol, &symbol->u.s.name, WEIGHT_STRONG);
   switch (symbol->u.s.redirect)
     {
@@ -2741,7 +2740,6 @@ dump_hash_table (struct dump_context *ctx,
      them as close to the hash table as possible.  */
   DUMP_FIELD_COPY (out, hash, count);
   DUMP_FIELD_COPY (out, hash, next_free);
-  DUMP_FIELD_COPY (out, hash, purecopy);
   DUMP_FIELD_COPY (out, hash, mutable);
   DUMP_FIELD_COPY (out, hash, rehash_threshold);
   DUMP_FIELD_COPY (out, hash, rehash_size);
diff --git a/src/print.c b/src/print.c
index cb34090514..534fc168fb 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1575,12 +1575,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 	print_object (Fhash_table_rehash_threshold (obj),
 		      printcharfun, escapeflag);
 
-	if (h->purecopy)
-	  {
-	    print_c_string (" purecopy ", printcharfun);
-	    print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
-	  }
-
 	print_c_string (" data ", printcharfun);
 
 	/* Print the data here as a plist. */
diff --git a/src/process.c b/src/process.c
index abadabe77e..1600f9d45e 100644
--- a/src/process.c
+++ b/src/process.c
@@ -8368,7 +8368,7 @@ syms_of_process (void)
    const struct socket_options *sopt;
 
 #define ADD_SUBFEATURE(key, val) \
-  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
+  subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures)
 
    ADD_SUBFEATURE (QCnowait, Qt);
 #ifdef DATAGRAM_SOCKETS
@@ -8390,7 +8390,7 @@ #define ADD_SUBFEATURE(key, val) \
    ADD_SUBFEATURE (QCserver, Qt);
 
    for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
+     subfeatures = Fcons (intern_c_string (sopt->name), subfeatures);
 
    Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
diff --git a/src/profiler.c b/src/profiler.c
index ed0e9ddd88..3838f9c836 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -63,7 +63,7 @@ make_log (void)
   Lisp_Object log = make_hash_table (hashtest_profiler, heap_size,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
   struct Lisp_Hash_Table *h = XHASH_TABLE (log);
 
   /* What is special about our hash-tables is that the keys are pre-filled
diff --git a/src/puresize.h b/src/puresize.h
index f5fad8b42b..e69de29bb2 100644
--- a/src/puresize.h
+++ b/src/puresize.h
@@ -1,115 +0,0 @@
-/* How much read-only Lisp storage a dumped Emacs needs.
-   Copyright (C) 1993, 2001-2019 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
-
-#ifndef EMACS_PURESIZE_H
-#define EMACS_PURESIZE_H
-
-#include "lisp.h"
-
-INLINE_HEADER_BEGIN
-
-/* Define PURESIZE, the number of bytes of pure Lisp code to leave space for.
-
-   At one point, this was defined in config.h, meaning that changing
-   PURESIZE would make Make recompile all of Emacs.  But only a few
-   files actually use PURESIZE, so we split it out to its own .h file.
-
-   Make sure to include this file after config.h, since that tells us
-   whether we are running X windows, which tells us how much pure
-   storage to allocate.  */
-
-/* First define a measure of the amount of data we have.  */
-
-/* A system configuration file may set this to request a certain extra
-   amount of storage.  This is a lot more update-robust that defining
-   BASE_PURESIZE or even PURESIZE directly.  */
-#ifndef SYSTEM_PURESIZE_EXTRA
-#define SYSTEM_PURESIZE_EXTRA 0
-#endif
-
-#ifndef SITELOAD_PURESIZE_EXTRA
-#define SITELOAD_PURESIZE_EXTRA 0
-#endif
-
-#ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA)
-#endif
-
-/* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
-#ifndef PURESIZE_RATIO
-#if EMACS_INT_MAX >> 31 != 0
-#if PTRDIFF_MAX >> 31 != 0
-#define PURESIZE_RATIO 10 / 6	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_RATIO 8 / 6	/* Don't surround with `()'.  */
-#endif
-#else
-#define PURESIZE_RATIO 1
-#endif
-#endif
-
-#ifdef ENABLE_CHECKING
-/* ENABLE_CHECKING somehow increases the purespace used, probably because
-   it tends to cause some macro arguments to be evaluated twice.  This is
-   a bug, but it's difficult to track it down.  */
-#define PURESIZE_CHECKING_RATIO 12 / 10	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_CHECKING_RATIO 1
-#endif
-
-/* This is the actual size in bytes to allocate.  */
-#ifndef PURESIZE
-#define PURESIZE  (BASE_PURESIZE * PURESIZE_RATIO * PURESIZE_CHECKING_RATIO)
-#endif
-
-extern AVOID pure_write_error (Lisp_Object);
-
-extern EMACS_INT pure[];
-
-/* The puresize_h_* macros are private to this include file.  */
-
-/* True if PTR is pure.  */
-
-#define puresize_h_PURE_P(ptr) \
-  ((uintptr_t) (ptr) - (uintptr_t) pure <= PURESIZE)
-
-INLINE bool
-PURE_P (void *ptr)
-{
-  return puresize_h_PURE_P (ptr);
-}
-
-/* Signal an error if OBJ is pure.  PTR is OBJ untagged.  */
-
-#define puresize_h_CHECK_IMPURE(obj, ptr) \
-  (PURE_P (ptr) ? pure_write_error (obj) : (void) 0)
-
-INLINE void
-CHECK_IMPURE (Lisp_Object obj, void *ptr)
-{
-  puresize_h_CHECK_IMPURE (obj, ptr);
-}
-
-#if DEFINE_KEY_OPS_AS_MACROS
-# define PURE_P(ptr) puresize_h_PURE_P (ptr)
-# define CHECK_IMPURE(obj, ptr) puresize_h_CHECK_IMPURE (obj, ptr)
-#endif
-
-INLINE_HEADER_END
-
-#endif /* EMACS_PURESIZE_H */
diff --git a/src/search.c b/src/search.c
index fa574959fb..49c2a29e19 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3368,19 +3368,19 @@ syms_of_search (void)
   DEFSYM (Qinvalid_regexp, "invalid-regexp");
 
   Fput (Qsearch_failed, Qerror_conditions,
-	pure_list (Qsearch_failed, Qerror));
+	list (Qsearch_failed, Qerror));
   Fput (Qsearch_failed, Qerror_message,
-	build_pure_c_string ("Search failed"));
+	build_string ("Search failed"));
 
   Fput (Quser_search_failed, Qerror_conditions,
-	pure_list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
+	list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
   Fput (Quser_search_failed, Qerror_message,
-        build_pure_c_string ("Search failed"));
+        build_string ("Search failed"));
 
   Fput (Qinvalid_regexp, Qerror_conditions,
-	pure_list (Qinvalid_regexp, Qerror));
+	list (Qinvalid_regexp, Qerror));
   Fput (Qinvalid_regexp, Qerror_message,
-	build_pure_c_string ("Invalid regexp"));
+	build_string ("Invalid regexp"));
 
   re_match_object = Qnil;
   staticpro (&re_match_object);
diff --git a/src/syntax.c b/src/syntax.c
index edfdae2259..15bfba9024 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3716,9 +3716,9 @@ syms_of_syntax (void)
 
   DEFSYM (Qscan_error, "scan-error");
   Fput (Qscan_error, Qerror_conditions,
-	pure_list (Qscan_error, Qerror));
+	list (Qscan_error, Qerror));
   Fput (Qscan_error, Qerror_message,
-	build_pure_c_string ("Scan error"));
+	build_string ("Scan error"));
 
   DEFVAR_BOOL ("parse-sexp-ignore-comments", parse_sexp_ignore_comments,
 	       doc: /* Non-nil means `forward-sexp', etc., should treat comments as whitespace.  */);
diff --git a/src/w32fns.c b/src/w32fns.c
index acd9c80528..ed3b0b3a2d 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10259,9 +10259,9 @@ syms_of_w32fns (void)
   DEFSYM (Qjson, "json");
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   staticpro (&w32_grabbed_keys);
   w32_grabbed_keys = Qnil;
diff --git a/src/xdisp.c b/src/xdisp.c
index 50f6443f6b..1781774148 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -32985,7 +32985,7 @@ syms_of_xdisp (void)
   staticpro (&echo_area_buffer[0]);
   staticpro (&echo_area_buffer[1]);
 
-  Vmessages_buffer_name = build_pure_c_string ("*Messages*");
+  Vmessages_buffer_name = build_string ("*Messages*");
   staticpro (&Vmessages_buffer_name);
 
   mode_line_proptrans_alist = Qnil;
@@ -33068,7 +33068,7 @@ syms_of_xdisp (void)
   DEFVAR_LISP ("overlay-arrow-string", Voverlay_arrow_string,
     doc: /* String to display as an arrow in non-window frames.
 See also `overlay-arrow-position'.  */);
-  Voverlay_arrow_string = build_pure_c_string ("=>");
+  Voverlay_arrow_string = build_string ("=>");
 
   DEFVAR_LISP ("overlay-arrow-variable-list", Voverlay_arrow_variable_list,
     doc: /* List of variables (symbols) which hold markers for overlay arrows.
@@ -33176,18 +33176,18 @@ syms_of_xdisp (void)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
 \(see `modify-frame-parameters').  */);
-  /* Do not nest calls to pure_list.  This works around a bug in
+  /* Do not nest calls to list.  This works around a bug in
      Oracle Developer Studio 12.6.  */
   Lisp_Object icon_title_name_format
-    = pure_list (empty_unibyte_string,
-		 intern_c_string ("invocation-name"),
-		 build_pure_c_string ("@"),
-		 intern_c_string ("system-name"));
+    = list (empty_unibyte_string,
+	    intern_c_string ("invocation-name"),
+	    build_string ("@"),
+	    intern_c_string ("system-name"));
   Vicon_title_format
     = Vframe_title_format
-    = pure_list (intern_c_string ("multiple-frames"),
-		 build_pure_c_string ("%b"),
-		 icon_title_name_format);
+    = list (intern_c_string ("multiple-frames"),
+	    build_string ("%b"),
+	    icon_title_name_format);
 
   DEFVAR_LISP ("message-log-max", Vmessage_log_max,
     doc: /* Maximum number of lines to keep in the message log buffer.
diff --git a/src/xfaces.c b/src/xfaces.c
index c3cae7e2a6..41e02f2a80 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -6659,7 +6659,7 @@ syms_of_xfaces (void)
 This stipple pattern is used on monochrome displays
 instead of shades of gray for a face background color.
 See `set-face-stipple' for possible values for this variable.  */);
-  Vface_default_stipple = build_pure_c_string ("gray3");
+  Vface_default_stipple = build_string ("gray3");
 
   DEFVAR_LISP ("tty-defined-color-alist", Vtty_defined_color_alist,
    doc: /* An alist of defined terminal colors and their RGB values.
diff --git a/src/xfns.c b/src/xfns.c
index b8a1914186..aee20630a3 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -7680,9 +7680,9 @@ syms_of_xfns (void)
 #endif
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
     doc: /* The shape of the pointer when over text.
@@ -7871,7 +7871,7 @@ syms_of_xfns (void)
     char gtk_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
     int len = sprintf (gtk_version, "%d.%d.%d",
 		       GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
-    Vgtk_version_string = make_pure_string (gtk_version, len, len, false);
+    Vgtk_version_string = make_specified_string (gtk_version, len, len, false);
   }
 #endif /* USE_GTK */
 
@@ -7885,7 +7885,8 @@ syms_of_xfns (void)
     int len = sprintf (cairo_version, "%d.%d.%d",
 		       CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
                        CAIRO_VERSION_MICRO);
-    Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+    Vcairo_version_string = make_specified_string (cairo_version, len, len,
+						   false);
   }
 #endif
 
diff --git a/src/xterm.c b/src/xterm.c
index c96aa74a7a..964c588e05 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13498,7 +13498,7 @@ syms_of_xterm (void)
   DEFSYM (Qlatin_1, "latin-1");
 
 #ifdef USE_GTK
-  xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
+  xg_default_icon_file = build_string ("icons/hicolor/scalable/apps/emacs.svg");
   staticpro (&xg_default_icon_file);
 
   DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
@@ -13619,7 +13619,7 @@ syms_of_xterm (void)
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
 
   DEFVAR_BOOL ("x-frame-normalize-before-maximize",
 	       x_frame_normalize_before_maximize,
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 12:53   ` Pip Cet
@ 2019-07-21 13:44     ` Robert Pluim
  2019-07-21 14:36       ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Robert Pluim @ 2019-07-21 13:44 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Sun, 21 Jul 2019 12:53:21 +0000, Pip Cet <pipcet@gmail.com> said:
    Pip> I think we should do (1) for now, since it simplifies the code enough
    Pip> to introduce immutable objects "soon"; but until that time, we waste
    Pip> more space on duplicate objects that we no longer know to be
    Pip> immutable, so cannot merge.

    Pip> I'm attaching a first patch that removes pure space, pinned symbols,
    Pip> pinned objects, but keeps Fpurecopy (for hash consing), and doesn't
    Pip> touch the Lisp codebase.

This doesnʼt build for me on macOS. After adjusting the parameters to
the call to make_hash_table in image.c, it crashes when dumping:

make[1]: Nothing to be done for `charscript.el'.
rm -f bootstrap-emacs.pdmp
./temacs --batch  -l loadup --temacs=pbootstrap
make: *** [bootstrap-emacs.pdmp] Segmentation fault: 11


* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x000000010016dc70 temacs`mark_object [inlined] symbol_marked_p(s=0x00080401003fdde0) at alloc.c:3741:14 [opt]
   3738	{
   3739	  return pdumper_object_p (s)
   3740	    ? pdumper_marked_p (s)
-> 3741	    : s->u.s.gcmarkbit;
   3742	}
   3743

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x000000010016dc70 temacs`mark_object [inlined] symbol_marked_p(s=0x00080401003fdde0) at alloc.c:3741:14 [opt]
    frame #1: 0x000000010016dc4c temacs`mark_object(arg=<unavailable>) at alloc.c:6082 [opt]
    frame #2: 0x000000010016f30a temacs`mark_vectorlike(header=0x0000000101804000) at alloc.c:5666:5 [opt]
    frame #3: 0x000000010016d6e0 temacs`mark_object(arg=<unavailable>) at alloc.c:5607:1 [opt] [artificial]
    frame #4: 0x000000010016c4cc temacs`garbage_collect_1 [inlined] mark_object_root_visitor(root_ptr=<unavailable>, type=GC_ROOT_STATICPRO) at alloc.c:5303:3 [opt]
    frame #5: 0x000000010016c4c4 temacs`garbage_collect_1 at alloc.c:5295 [opt]
    frame #6: 0x000000010016c34f temacs`garbage_collect_1(gcst=0x00007ffeefbff248) at alloc.c:5427 [opt]
    frame #7: 0x000000010016c114 temacs`garbage_collect at alloc.c:5551:3 [opt]
    frame #8: 0x000000010019b836 temacs`eval_sub [inlined] maybe_gc at lisp.h:4974:5 [opt]
    frame #9: 0x000000010019b824 temacs`eval_sub(form=0x000000010302e843) at eval.c:2166 [opt]
    frame #10: 0x00000001001a023a temacs`Feval(form=0x000000010302e843, lexical=<unavailable>) at eval.c:2089:28 [opt]
    frame #11: 0x000000010019f082 temacs`internal_condition_case(bfun=(temacs`top_level_2 at keyboard.c:1099), handlers=0x0000000000000090, hfun=(temacs`cmd_error at keyboard.c:919)) at eval.c:1347:25 [opt]
    frame #12: 0x00000001001107ed temacs`top_level_1(ignore=<unavailable>) at keyboard.c:1108:5 [opt]
    frame #13: 0x000000010019e617 temacs`internal_catch(tag=0x000000000000c420, func=(temacs`top_level_1 at keyboard.c:1105), arg=0x0000000000000000) at eval.c:1108:25 [opt]
    frame #14: 0x00000001000fc16f temacs`command_loop at keyboard.c:1069:2 [opt]
    frame #15: 0x00000001000fc093 temacs`recursive_edit_1 at keyboard.c:714:9 [opt]
    frame #16: 0x00000001000fc3ac temacs`Frecursive_edit at keyboard.c:786:3 [opt]
    frame #17: 0x00000001000fa9b1 temacs`main(argc=<unavailable>, argv=0x00007ffeefbff6b8) at emacs.c:2085:3 [opt]
    frame #18: 0x00007fff7f9da3d5 libdyld.dylib`start + 1
    frame #19: 0x00007fff7f9da3d5 libdyld.dylib`start + 1
    





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 13:44     ` Robert Pluim
@ 2019-07-21 14:36       ` Pip Cet
  2019-07-21 15:06         ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-21 14:36 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, Paul Eggert

[-- Attachment #1: Type: text/plain, Size: 1065 bytes --]

On Sun, Jul 21, 2019 at 1:44 PM Robert Pluim <rpluim@gmail.com> wrote:
> >>>>> On Sun, 21 Jul 2019 12:53:21 +0000, Pip Cet <pipcet@gmail.com> said:
>     Pip> I think we should do (1) for now, since it simplifies the code enough
>     Pip> to introduce immutable objects "soon"; but until that time, we waste
>     Pip> more space on duplicate objects that we no longer know to be
>     Pip> immutable, so cannot merge.
>
>     Pip> I'm attaching a first patch that removes pure space, pinned symbols,
>     Pip> pinned objects, but keeps Fpurecopy (for hash consing), and doesn't
>     Pip> touch the Lisp codebase.
>
> This doesnʼt build for me on macOS. After adjusting the parameters to
> the call to make_hash_table in image.c, it crashes when dumping:

Thanks for testing! Indeed, I'd only verified it builds here.

My first guess is there's a symbol in the obarray which used to be
pinned, but is now collected before it is interned.

Can you try with the attached patch relative to the one I'd sent
before, and see what the output is?

[-- Attachment #2: 0001-debugging-changes.patch --]
[-- Type: text/x-patch, Size: 1408 bytes --]

From 45e8f7bdbba43f627b39957366b70dcbdc6575a8 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Sun, 21 Jul 2019 14:35:04 +0000
Subject: [PATCH] debugging changes

---
 src/alloc.c | 3 ++-
 src/image.c | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/alloc.c b/src/alloc.c
index df8b1caf4e..1b55ad8cab 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -6428,6 +6428,7 @@ sweep_symbols (void)
         {
           if (!sym->u.s.gcmarkbit)
             {
+	      fprintf (stderr, "freeing symbol %s\n", SDATA (sym->u.s.name));
               if (sym->u.s.redirect == SYMBOL_LOCALIZED)
 		{
                   xfree (SYMBOL_BLV (sym));
@@ -6519,12 +6520,12 @@ sweep_buffers (void)
 static void
 gc_sweep (void)
 {
+  sweep_symbols ();
   sweep_strings ();
   check_string_bytes (!noninteractive);
   sweep_conses ();
   sweep_floats ();
   sweep_intervals ();
-  sweep_symbols ();
   sweep_buffers ();
   sweep_vectors ();
   pdumper_clear_marks ();
diff --git a/src/image.c b/src/image.c
index 355c849491..b21dff34d4 100644
--- a/src/image.c
+++ b/src/image.c
@@ -4596,7 +4596,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			  DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			  Qnil, false);
+			  Qnil);
 }
 
 static void
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 14:36       ` Pip Cet
@ 2019-07-21 15:06         ` Robert Pluim
  2019-07-21 17:43           ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Robert Pluim @ 2019-07-21 15:06 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Sun, 21 Jul 2019 14:36:41 +0000, Pip Cet <pipcet@gmail.com> said:

    Pip> On Sun, Jul 21, 2019 at 1:44 PM Robert Pluim <rpluim@gmail.com> wrote:
    >> >>>>> On Sun, 21 Jul 2019 12:53:21 +0000, Pip Cet <pipcet@gmail.com> said:
    Pip> I think we should do (1) for now, since it simplifies the code enough
    Pip> to introduce immutable objects "soon"; but until that time, we waste
    Pip> more space on duplicate objects that we no longer know to be
    Pip> immutable, so cannot merge.
    >> 
    Pip> I'm attaching a first patch that removes pure space, pinned symbols,
    Pip> pinned objects, but keeps Fpurecopy (for hash consing), and doesn't
    Pip> touch the Lisp codebase.
    >> 
    >> This doesnʼt build for me on macOS. After adjusting the parameters to
    >> the call to make_hash_table in image.c, it crashes when dumping:

    Pip> Thanks for testing! Indeed, I'd only verified it builds here.

    Pip> My first guess is there's a symbol in the obarray which used to be
    Pip> pinned, but is now collected before it is interned.

    Pip> Can you try with the attached patch relative to the one I'd sent
    Pip> before, and see what the output is?

Hmm, it crashed the first time I ran make, then I got distracted, so I
ran make again later, and this time it built:

make[2]: Nothing to be done for `all'.
  ELC      char-fold.elc
freeing symbol def-tmp-var





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 15:06         ` Robert Pluim
@ 2019-07-21 17:43           ` Pip Cet
  2019-07-21 17:56             ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-21 17:43 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, Paul Eggert

On Sun, Jul 21, 2019 at 3:06 PM Robert Pluim <rpluim@gmail.com> wrote:

> Hmm, it crashed the first time I ran make, then I got distracted, so I
> ran make again later, and this time it built:
>
> make[2]: Nothing to be done for `all'.
>   ELC      char-fold.elc
> freeing symbol def-tmp-var

Hmm. So it worked with the second patch, but only when you reran make?
That's strange. Looking at the crash backtrace again, it seems that
this is the initial garbage collection, when everything should be
pristine. I still think it dies while marking the obarray, upon
encountering a symbol which has somehow become corrupted...





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 17:43           ` Pip Cet
@ 2019-07-21 17:56             ` Robert Pluim
  2019-07-21 18:07               ` Pip Cet
  2019-07-21 18:14               ` Eli Zaretskii
  0 siblings, 2 replies; 125+ messages in thread
From: Robert Pluim @ 2019-07-21 17:56 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Sun, 21 Jul 2019 17:43:05 +0000, Pip Cet <pipcet@gmail.com> said:

    Pip> On Sun, Jul 21, 2019 at 3:06 PM Robert Pluim <rpluim@gmail.com> wrote:
    >> Hmm, it crashed the first time I ran make, then I got distracted, so I
    >> ran make again later, and this time it built:
    >> 
    >> make[2]: Nothing to be done for `all'.
    >> ELC      char-fold.elc
    >> freeing symbol def-tmp-var

    Pip> Hmm. So it worked with the second patch, but only when you reran make?
    Pip> That's strange. Looking at the crash backtrace again, it seems that
    Pip> this is the initial garbage collection, when everything should be
    Pip> pristine. I still think it dies while marking the obarray, upon
    Pip> encountering a symbol which has somehow become corrupted...

OK. How do we go about detecting which symbol that is?

Robert





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 17:56             ` Robert Pluim
@ 2019-07-21 18:07               ` Pip Cet
  2019-07-21 19:12                 ` Robert Pluim
  2019-07-21 18:14               ` Eli Zaretskii
  1 sibling, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-21 18:07 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, Paul Eggert

[-- Attachment #1: Type: text/plain, Size: 1228 bytes --]

On Sun, Jul 21, 2019 at 5:56 PM Robert Pluim <rpluim@gmail.com> wrote:
> >>>>> On Sun, 21 Jul 2019 17:43:05 +0000, Pip Cet <pipcet@gmail.com> said:
>
>     Pip> On Sun, Jul 21, 2019 at 3:06 PM Robert Pluim <rpluim@gmail.com> wrote:
>     >> Hmm, it crashed the first time I ran make, then I got distracted, so I
>     >> ran make again later, and this time it built:
>     >>
>     >> make[2]: Nothing to be done for `all'.
>     >> ELC      char-fold.elc
>     >> freeing symbol def-tmp-var
>
>     Pip> Hmm. So it worked with the second patch, but only when you reran make?
>     Pip> That's strange. Looking at the crash backtrace again, it seems that
>     Pip> this is the initial garbage collection, when everything should be
>     Pip> pristine. I still think it dies while marking the obarray, upon
>     Pip> encountering a symbol which has somehow become corrupted...
>
> OK. How do we go about detecting which symbol that is?

I'm not sure about debugging on macOS, but can you get a full
backtrace, or a core dump, or both? We're particularly interested in
what "i" is in mark_vectorlike.

Otherwise, the attached patch should produce (probably a lot of)
information, the last lines of which would be interesting...

[-- Attachment #2: 0001-Other-debugging-changes.patch --]
[-- Type: text/x-patch, Size: 1189 bytes --]

From f366d66e83d76df1d89e264b463a6f903459d024 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Sun, 21 Jul 2019 18:03:17 +0000
Subject: [PATCH] Other debugging changes.

---
 src/alloc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/alloc.c b/src/alloc.c
index 1b55ad8cab..fe98eca086 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -5663,7 +5663,10 @@ mark_vectorlike (union vectorlike_header *header)
      The distinction is used e.g. by Lisp_Process which places extra
      non-Lisp_Object fields at the end of the structure...  */
   for (i = 0; i < size; i++) /* ...and then mark its elements.  */
-    mark_object (ptr->contents[i]);
+    {
+      fprintf (stderr, "%d\n", (int)i);
+      mark_object (ptr->contents[i]);
+    }
 }
 
 /* Like mark_vectorlike but optimized for char-tables (and
@@ -6079,6 +6082,8 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL()	((void) 0)
       {
 	struct Lisp_Symbol *ptr = XSYMBOL (obj);
       nextsym:
+	if (!NILP (ptr->u.s.name))
+	  fprintf (stderr, "%p %s\n", ptr, SDATA (ptr->u.s.name));
         if (symbol_marked_p (ptr))
           break;
         CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 17:56             ` Robert Pluim
  2019-07-21 18:07               ` Pip Cet
@ 2019-07-21 18:14               ` Eli Zaretskii
  1 sibling, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2019-07-21 18:14 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, eggert, pipcet

> From: Robert Pluim <rpluim@gmail.com>
> Date: Sun, 21 Jul 2019 19:56:42 +0200
> Cc: 36649@debbugs.gnu.org, Paul Eggert <eggert@cs.ucla.edu>
> 
>     Pip> That's strange. Looking at the crash backtrace again, it seems that
>     Pip> this is the initial garbage collection, when everything should be
>     Pip> pristine. I still think it dies while marking the obarray, upon
>     Pip> encountering a symbol which has somehow become corrupted...
> 
> OK. How do we go about detecting which symbol that is?

etc/DEBUG has some advice for debugging crashes inside GC.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 18:07               ` Pip Cet
@ 2019-07-21 19:12                 ` Robert Pluim
  2019-07-21 19:35                   ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Robert Pluim @ 2019-07-21 19:12 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Sun, 21 Jul 2019 18:07:43 +0000, Pip Cet <pipcet@gmail.com> said:
    Pip> I'm not sure about debugging on macOS, but can you get a full
    Pip> backtrace, or a core dump, or both? We're particularly interested in
    Pip> what "i" is in mark_vectorlike.

You want a lisp backtrace? I can always run under gdb if needed. As to
'i':

(lldb) up
frame #1: 0x000000010016dbec temacs`mark_object(arg=<unavailable>) at alloc.c:6082 [opt]
   6079	      {
   6080		struct Lisp_Symbol *ptr = XSYMBOL (obj);
   6081	      nextsym:
-> 6082	        if (symbol_marked_p (ptr))
   6083	          break;
   6084	        CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
   6085	        set_symbol_marked(ptr);
(lldb)
frame #2: 0x000000010016f2aa temacs`mark_vectorlike(header=0x0000000101803200) at alloc.c:5666:5 [opt]
   5663	     The distinction is used e.g. by Lisp_Process which places extra
   5664	     non-Lisp_Object fields at the end of the structure...  */
   5665	  for (i = 0; i < size; i++) /* ...and then mark its elements.  */
-> 5666	    mark_object (ptr->contents[i]);
   5667	}
   5668
   5669	/* Like mark_vectorlike but optimized for char-tables (and
(lldb) p i
(ptrdiff_t) $0 = 0
(lldb) p ptr->contents
error: incomplete type 'Lisp_Object []' where a complete type is required
(lldb) p ptr->contents[0]
(Lisp_Object) $1 = 0x0008040000080400

    Pip> Otherwise, the attached patch should produce (probably a lot of)
    Pip> information, the last lines of which would be interesting...

Since you broke Robert's Second Rule of printf debugging, I stuck an
extra 'mark ' on the front of the fprintf in 'mark_vectorlike' :-)

0x10320c9e0 nil
0x10320c9e0 nil
0x10320c9e0 nil
0x10321ab70 z-group
0x10320c9e0 nil
0x10321a6f0 x-frame-parameter
0x10320ca40 unbound
0x10321aba0 zero-width
0x10320c9e0 nil
0x10320c9e0 nil
0x10320ca40 unbound
mark 0
make[1]: *** [bootstrap-emacs.pdmp] Segmentation fault: 11
make: *** [src] Error 2






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 19:12                 ` Robert Pluim
@ 2019-07-21 19:35                   ` Pip Cet
  2019-07-21 20:20                     ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-21 19:35 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, Paul Eggert

[-- Attachment #1: Type: text/plain, Size: 1720 bytes --]

On Sun, Jul 21, 2019 at 7:12 PM Robert Pluim <rpluim@gmail.com> wrote:
> >>>>> On Sun, 21 Jul 2019 18:07:43 +0000, Pip Cet <pipcet@gmail.com> said:
>     Pip> I'm not sure about debugging on macOS, but can you get a full
>     Pip> backtrace, or a core dump, or both? We're particularly interested in
>     Pip> what "i" is in mark_vectorlike.
>
> You want a lisp backtrace? I can always run under gdb if needed. As to
> 'i':
>
> (lldb) up
> frame #1: 0x000000010016dbec temacs`mark_object(arg=<unavailable>) at alloc.c:6082 [opt]
>    6079       {
>    6080         struct Lisp_Symbol *ptr = XSYMBOL (obj);
>    6081       nextsym:
> -> 6082         if (symbol_marked_p (ptr))
>    6083           break;
>    6084         CHECK_ALLOCATED_AND_LIVE_SYMBOL ();
>    6085         set_symbol_marked(ptr);
> (lldb)
> frame #2: 0x000000010016f2aa temacs`mark_vectorlike(header=0x0000000101803200) at alloc.c:5666:5 [opt]
>    5663      The distinction is used e.g. by Lisp_Process which places extra
>    5664      non-Lisp_Object fields at the end of the structure...  */
>    5665   for (i = 0; i < size; i++) /* ...and then mark its elements.  */
> -> 5666     mark_object (ptr->contents[i]);
>    5667 }
>    5668
>    5669 /* Like mark_vectorlike but optimized for char-tables (and
> (lldb) p i
> (ptrdiff_t) $0 = 0
> (lldb) p ptr->contents
> error: incomplete type 'Lisp_Object []' where a complete type is required
> (lldb) p ptr->contents[0]
> (Lisp_Object) $1 = 0x0008040000080400

Thanks! I messed up quite badly initializing the zero vector, it turns
out, so it was trying to initialize the first entry in the zero
vector, which, er, obviously wasn't a good idea :-)

Can you try again with this incremental patch?

[-- Attachment #2: 0001-Initialize-the-zero-vector-properly.patch --]
[-- Type: text/x-patch, Size: 716 bytes --]

From 911211705f3e1cb0fafb407c363a3a492dc97022 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Sun, 21 Jul 2019 19:32:49 +0000
Subject: [PATCH] Initialize the zero vector properly.

---
 src/alloc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/alloc.c b/src/alloc.c
index df8b1caf4e..5c1bec7666 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3151,8 +3151,8 @@ allocate_vector (ptrdiff_t len)
 init_vectors (void)
 {
   zero_vector =
-    make_lisp_ptr (allocate_vectorlike (sizeof (struct Lisp_Vector)),
-		   Lisp_Vectorlike);
+    make_lisp_ptr (allocate_vectorlike (0), Lisp_Vectorlike);
+  zero_vector->header.size = 0;
   staticpro (&zero_vector);
 }
 
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 19:35                   ` Pip Cet
@ 2019-07-21 20:20                     ` Robert Pluim
  2019-07-22  3:58                       ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Robert Pluim @ 2019-07-21 20:20 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Sun, 21 Jul 2019 19:35:01 +0000, Pip Cet <pipcet@gmail.com> said:

    Pip> Thanks! I messed up quite badly initializing the zero vector, it turns
    Pip> out, so it was trying to initialize the first entry in the zero
    Pip> vector, which, er, obviously wasn't a good idea :-)

    Pip> Can you try again with this incremental patch?

I offer two alternatives, both of which build and run:

diff --git i/src/alloc.c w/src/alloc.c
index 1b55ad8cab..206f0ce8d7 100644
--- i/src/alloc.c
+++ w/src/alloc.c
@@ -3091,7 +3091,7 @@ #define VECTOR_ELTS_MAX \
 static struct Lisp_Vector *
 allocate_vectorlike (ptrdiff_t len)
 {
-  eassert (0 < len && len <= VECTOR_ELTS_MAX);
+  eassert (0 <= len && len <= VECTOR_ELTS_MAX);
   ptrdiff_t nbytes = header_size + len * word_size;
   struct Lisp_Vector *p;
 
@@ -3151,8 +3151,8 @@ allocate_vector (ptrdiff_t len)
 init_vectors (void)
 {
   zero_vector =
-    make_lisp_ptr (allocate_vectorlike (sizeof (struct Lisp_Vector)),
-		   Lisp_Vectorlike);
+    make_lisp_ptr (allocate_vectorlike (0), Lisp_Vectorlike);
+  XVECTOR(zero_vector)->header.size = 0;
   staticpro (&zero_vector);
 }
 

diff --git i/src/alloc.c w/src/alloc.c
index 1b55ad8cab..294aa9a2aa 100644
--- i/src/alloc.c
+++ w/src/alloc.c
@@ -3151,8 +3151,8 @@ allocate_vector (ptrdiff_t len)
 init_vectors (void)
 {
   zero_vector =
-    make_lisp_ptr (allocate_vectorlike (sizeof (struct Lisp_Vector)),
-		   Lisp_Vectorlike);
+    make_lisp_ptr (allocate_vectorlike (1), Lisp_Vectorlike);
+  XVECTOR(zero_vector)->header.size = 0;
   staticpro (&zero_vector);
 }
 





^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-21 20:20                     ` Robert Pluim
@ 2019-07-22  3:58                       ` Pip Cet
  2019-07-22  8:14                         ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-22  3:58 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, Paul Eggert

[-- Attachment #1: Type: text/plain, Size: 303 bytes --]

On Sun, Jul 21, 2019 at 8:20 PM Robert Pluim <rpluim@gmail.com> wrote:
>     Pip> Can you try again with this incremental patch?
>
> I offer two alternatives, both of which build and run:

Oops, sorry. I think the second alternative might break
live_vector_holding, though?

Attaching an updated patch.

[-- Attachment #2: 0001-Remove-pure-space.patch.gz --]
[-- Type: application/gzip, Size: 25425 bytes --]

^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-22  3:58                       ` Pip Cet
@ 2019-07-22  8:14                         ` Robert Pluim
  2019-07-22 14:30                           ` Eli Zaretskii
  2019-07-22 15:03                           ` Pip Cet
  0 siblings, 2 replies; 125+ messages in thread
From: Robert Pluim @ 2019-07-22  8:14 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Mon, 22 Jul 2019 03:58:29 +0000, Pip Cet <pipcet@gmail.com> said:

    Pip> On Sun, Jul 21, 2019 at 8:20 PM Robert Pluim <rpluim@gmail.com> wrote:
    Pip> Can you try again with this incremental patch?
    >> 
    >> I offer two alternatives, both of which build and run:

    Pip> Oops, sorry. I think the second alternative might break
    Pip> live_vector_holding, though?

OK. Hereʼs hoping no other code in emacs tries to create a 0-length
vector :-)

    Pip> Attaching an updated patch.

I put this on top of it. The result builds, runs, and is sending this
email.

diff --git i/src/image.c w/src/image.c
index 355c849491..b21dff34d4 100644
--- i/src/image.c
+++ w/src/image.c
@@ -4596,7 +4596,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			  DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			  Qnil, false);
+			  Qnil);
 }
 
 static void





^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-22  8:14                         ` Robert Pluim
@ 2019-07-22 14:30                           ` Eli Zaretskii
  2019-07-22 15:46                             ` Robert Pluim
  2019-07-22 15:03                           ` Pip Cet
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2019-07-22 14:30 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, eggert, pipcet

> From: Robert Pluim <rpluim@gmail.com>
> Date: Mon, 22 Jul 2019 10:14:47 +0200
> Cc: 36649@debbugs.gnu.org, Paul Eggert <eggert@cs.ucla.edu>
> 
> >>>>> On Mon, 22 Jul 2019 03:58:29 +0000, Pip Cet <pipcet@gmail.com> said:
> 
>     Pip> On Sun, Jul 21, 2019 at 8:20 PM Robert Pluim <rpluim@gmail.com> wrote:
>     Pip> Can you try again with this incremental patch?
>     >> 
>     >> I offer two alternatives, both of which build and run:
> 
>     Pip> Oops, sorry. I think the second alternative might break
>     Pip> live_vector_holding, though?
> 
> OK. Hereʼs hoping no other code in emacs tries to create a 0-length
> vector :-)

I think font.c (or fontset.c?) does.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-22  8:14                         ` Robert Pluim
  2019-07-22 14:30                           ` Eli Zaretskii
@ 2019-07-22 15:03                           ` Pip Cet
  2019-07-22 18:45                             ` Robert Pluim
  1 sibling, 1 reply; 125+ messages in thread
From: Pip Cet @ 2019-07-22 15:03 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 36649, Paul Eggert

[-- Attachment #1: Type: text/plain, Size: 1004 bytes --]

On Mon, Jul 22, 2019 at 8:14 AM Robert Pluim <rpluim@gmail.com> wrote:
> >>>>> On Mon, 22 Jul 2019 03:58:29 +0000, Pip Cet <pipcet@gmail.com> said:
>
>     Pip> On Sun, Jul 21, 2019 at 8:20 PM Robert Pluim <rpluim@gmail.com> wrote:
>     Pip> Can you try again with this incremental patch?
>     >>
>     >> I offer two alternatives, both of which build and run:
>
>     Pip> Oops, sorry. I think the second alternative might break
>     Pip> live_vector_holding, though?
>
> OK. Hereʼs hoping no other code in emacs tries to create a 0-length
> vector :-)

By modifying header.size? That would be a problem. (I'd say no one
should ever do it, but I'd actually like to suggest it for hash
tables...)

>     Pip> Attaching an updated patch.
>
> I put this on top of it. The result builds, runs, and is sending this
> email.

Hmm. Apparently I'm building without XPM? I should investigate that.

Anyway, there's another make_hash_table in emacs-module.c, but I think
that's it.

[-- Attachment #2: 0001-Remove-pure-space.patch.gz --]
[-- Type: application/gzip, Size: 25589 bytes --]

^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-22 14:30                           ` Eli Zaretskii
@ 2019-07-22 15:46                             ` Robert Pluim
  0 siblings, 0 replies; 125+ messages in thread
From: Robert Pluim @ 2019-07-22 15:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, eggert, pipcet

>>>>> On Mon, 22 Jul 2019 17:30:35 +0300, Eli Zaretskii <eliz@gnu.org> said:

    >> From: Robert Pluim <rpluim@gmail.com>
    >> Date: Mon, 22 Jul 2019 10:14:47 +0200
    >> Cc: 36649@debbugs.gnu.org, Paul Eggert <eggert@cs.ucla.edu>
    >> 
    >> >>>>> On Mon, 22 Jul 2019 03:58:29 +0000, Pip Cet <pipcet@gmail.com> said:
    >> 
    Pip> On Sun, Jul 21, 2019 at 8:20 PM Robert Pluim <rpluim@gmail.com> wrote:
    Pip> Can you try again with this incremental patch?
    >> >> 
    >> >> I offer two alternatives, both of which build and run:
    >> 
    Pip> Oops, sorry. I think the second alternative might break
    Pip> live_vector_holding, though?
    >> 
    >> OK. Hereʼs hoping no other code in emacs tries to create a 0-length
    >> vector :-)

    Eli> I think font.c (or fontset.c?) does.

If it does, that will be caught by allocate_vector, and this changes
allocate_vectorlike. Having said that, there are other callers of
allocate_vectorlike in alloc.c which donʼt check for a
zero-length. Maybe Iʼm over-worrying here.

Robert





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-22 15:03                           ` Pip Cet
@ 2019-07-22 18:45                             ` Robert Pluim
  2020-08-21 12:51                               ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Robert Pluim @ 2019-07-22 18:45 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Paul Eggert

>>>>> On Mon, 22 Jul 2019 15:03:55 +0000, Pip Cet <pipcet@gmail.com> said:

    Pip> On Mon, Jul 22, 2019 at 8:14 AM Robert Pluim <rpluim@gmail.com> wrote:
    >> >>>>> On Mon, 22 Jul 2019 03:58:29 +0000, Pip Cet <pipcet@gmail.com> said:
    >> 
    Pip> On Sun, Jul 21, 2019 at 8:20 PM Robert Pluim <rpluim@gmail.com> wrote:
    Pip> Can you try again with this incremental patch?
    >> >>
    >> >> I offer two alternatives, both of which build and run:
    >> 
    Pip> Oops, sorry. I think the second alternative might break
    Pip> live_vector_holding, though?
    >> 
    >> OK. Hereʼs hoping no other code in emacs tries to create a 0-length
    >> vector :-)

    Pip> By modifying header.size? That would be a problem. (I'd say no one
    Pip> should ever do it, but I'd actually like to suggest it for hash
    Pip> tables...)

    Pip> Attaching an updated patch.

It works for me. I think Iʼm with Eli on the prospect of putting this
in emacs-27, there are other things Iʼd like to see fixed first
(thereʼs still a potential TLS 1.3 issue that Iʼve not had time to
look at).

Robert





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-22 18:45                             ` Robert Pluim
@ 2020-08-21 12:51                               ` Lars Ingebrigtsen
  2020-08-21 13:04                                 ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-21 12:51 UTC (permalink / raw)
  To: Pip Cet, 36649, Paul Eggert

Robert Pluim <rpluim@gmail.com> writes:

>     Pip> Attaching an updated patch.
>
> It works for me. I think Iʼm with Eli on the prospect of putting this
> in emacs-27, there are other things Iʼd like to see fixed first
> (thereʼs still a potential TLS 1.3 issue that Iʼve not had time to
> look at).

I didn't read this thread closely, but it seems like the conclusion that
this patch should have been applied.  (It removes pure space,
apparently?)

The patch never was applied, though -- should it be applied now?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-21 12:51                               ` Lars Ingebrigtsen
@ 2020-08-21 13:04                                 ` Pip Cet
  2020-08-21 13:47                                   ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2020-08-21 13:04 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 36649, Paul Eggert

On Fri, Aug 21, 2020 at 12:52 PM Lars Ingebrigtsen <larsi@gnus.org> wrote:
> I didn't read this thread closely, but it seems like the conclusion that
> this patch should have been applied.  (It removes pure space,
> apparently?)
>
> The patch never was applied, though -- should it be applied now?

I believe it's best to be careful with this one. Pure space affects GC
in subtle ways, and it also affects performance.

See this thread:
https://lists.gnu.org/archive/html/emacs-devel/2019-07/msg00588.html

I'd be happy to set up a separate branch for removing pure space if
that's preferred.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-21 13:04                                 ` Pip Cet
@ 2020-08-21 13:47                                   ` Eli Zaretskii
  2020-08-21 15:26                                     ` Andreas Schwab
                                                       ` (3 more replies)
  0 siblings, 4 replies; 125+ messages in thread
From: Eli Zaretskii @ 2020-08-21 13:47 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, larsi, eggert

> From: Pip Cet <pipcet@gmail.com>
> Date: Fri, 21 Aug 2020 13:04:47 +0000
> Cc: 36649@debbugs.gnu.org, Paul Eggert <eggert@cs.ucla.edu>
> 
> On Fri, Aug 21, 2020 at 12:52 PM Lars Ingebrigtsen <larsi@gnus.org> wrote:
> > I didn't read this thread closely, but it seems like the conclusion that
> > this patch should have been applied.  (It removes pure space,
> > apparently?)
> >
> > The patch never was applied, though -- should it be applied now?
> 
> I believe it's best to be careful with this one. Pure space affects GC
> in subtle ways, and it also affects performance.
> 
> See this thread:
> https://lists.gnu.org/archive/html/emacs-devel/2019-07/msg00588.html
> 
> I'd be happy to set up a separate branch for removing pure space if
> that's preferred.

What do we do with unexec builds, which are still supported?  Remove
that support? or ignore the possibility of an unexec build?





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-21 13:47                                   ` Eli Zaretskii
@ 2020-08-21 15:26                                     ` Andreas Schwab
  2020-08-21 21:41                                     ` Paul Eggert
                                                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 125+ messages in thread
From: Andreas Schwab @ 2020-08-21 15:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, larsi, eggert, Pip Cet

On Aug 21 2020, Eli Zaretskii wrote:

> What do we do with unexec builds, which are still supported?  Remove
> that support? or ignore the possibility of an unexec build?

What do we gain by keeping unexec alive?

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-21 13:47                                   ` Eli Zaretskii
  2020-08-21 15:26                                     ` Andreas Schwab
@ 2020-08-21 21:41                                     ` Paul Eggert
  2020-08-22  3:51                                     ` Richard Stallman
  2020-08-22  8:55                                     ` Pip Cet
  3 siblings, 0 replies; 125+ messages in thread
From: Paul Eggert @ 2020-08-21 21:41 UTC (permalink / raw)
  To: Eli Zaretskii, Pip Cet; +Cc: 36649, larsi

On 8/21/20 6:47 AM, Eli Zaretskii wrote:
> What do we do with unexec builds, which are still supported?  Remove
> that support? or ignore the possibility of an unexec build?

It's a good time to remove unexec support. Nobody is using it, there's a good 
chance that it doesn't work nowadays on many platforms, and its continued 
presence in the source code is costing us all more than it's benefiting.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-21 13:47                                   ` Eli Zaretskii
  2020-08-21 15:26                                     ` Andreas Schwab
  2020-08-21 21:41                                     ` Paul Eggert
@ 2020-08-22  3:51                                     ` Richard Stallman
  2020-08-22  8:55                                     ` Pip Cet
  3 siblings, 0 replies; 125+ messages in thread
From: Richard Stallman @ 2020-08-22  3:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, larsi, eggert, pipcet

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

I don't think we should desupport unexec while the pdumper is so new.

-- 
Dr Richard Stallman
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-21 13:47                                   ` Eli Zaretskii
                                                       ` (2 preceding siblings ...)
  2020-08-22  3:51                                     ` Richard Stallman
@ 2020-08-22  8:55                                     ` Pip Cet
  2020-08-22  9:59                                       ` Andreas Schwab
  2020-08-22 17:36                                       ` Paul Eggert
  3 siblings, 2 replies; 125+ messages in thread
From: Pip Cet @ 2020-08-22  8:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, larsi, eggert

[-- Attachment #1: Type: text/plain, Size: 1373 bytes --]

On Fri, Aug 21, 2020 at 1:47 PM Eli Zaretskii <eliz@gnu.org> wrote:
> > From: Pip Cet <pipcet@gmail.com>
> > Date: Fri, 21 Aug 2020 13:04:47 +0000
> > Cc: 36649@debbugs.gnu.org, Paul Eggert <eggert@cs.ucla.edu>
> >
> > On Fri, Aug 21, 2020 at 12:52 PM Lars Ingebrigtsen <larsi@gnus.org> wrote:
> > > I didn't read this thread closely, but it seems like the conclusion that
> > > this patch should have been applied.  (It removes pure space,
> > > apparently?)
> > >
> > > The patch never was applied, though -- should it be applied now?
> >
> > I believe it's best to be careful with this one. Pure space affects GC
> > in subtle ways, and it also affects performance.
> >
> > See this thread:
> > https://lists.gnu.org/archive/html/emacs-devel/2019-07/msg00588.html
> >
> > I'd be happy to set up a separate branch for removing pure space if
> > that's preferred.
>
> What do we do with unexec builds, which are still supported?

I think that's an important question, but I don't think it's strongly
connected to pure space.

In fact, it appears like unexec builds are currently broken on master,
and on this GNU/Linux machine, I've got to force use of HYBRID_MALLOC
to get an unexec build starting at all. But, having done that, it
works with and without the patch, at first glance.

Rebased patch attached (but I just noticed  the commit message is no
longer complete).

[-- Attachment #2: 0001-Remove-pure-space.patch --]
[-- Type: text/x-patch, Size: 87571 bytes --]

From abafd4533f45bbec1929b0cfdf06c4d7d31018c3 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Sat, 22 Aug 2020 06:18:51 +0000
Subject: [PATCH] Remove pure space

* src/lisp.h (struct Lisp_Symbol): Remove `pinned' flag.
(build_pure_c_string, pure_listn): Remove.  All calls removed.
* src/puresize.h: Remove file.
* src/fns.c (Fmake_hash_table): Ignore `:purecopy' argument.
* src/doc.c (store_function_docstring): Remove comment about pure
space.
* src/data.c (pure_write_error): Remove.  All calls removed.
* src/conf_post.h (SYSTEM_PURESIZE_EXTRA): Remove.
* src/fns.c (make_hash_table): Drop `purecopy' argument.  All
callers changed to remove argument.
* src/alloc.c (make_pure_string, make_pure_c_string, pure_cons)
(pure_list): Remove.  All calls removed.
(check_pure_size): Remove.  All calls removed.
(cons_listn): Simplify.
(Fmake_byte_code): Remove comment about pure space.
(pointer_align): Move definition to avoid warning.
* src/Makefile.in: Remove comment about pure space.
---
 configure.ac       |   2 +-
 src/Makefile.in    |   2 -
 src/alloc.c        | 544 ++++-----------------------------------------
 src/buffer.c       |  16 +-
 src/callint.c      |   8 +-
 src/category.c     |   4 +-
 src/coding.c       |  18 +-
 src/conf_post.h    |  33 ---
 src/data.c         |  29 +--
 src/dbusbind.c     |   4 +-
 src/deps.mk        |  10 +-
 src/doc.c          |   3 -
 src/emacs-module.c |  28 +--
 src/emacs.c        |   5 +-
 src/eval.c         |  12 +-
 src/fileio.c       |  20 +-
 src/fns.c          |  32 +--
 src/fontset.c      |   4 +-
 src/frame.c        |   2 +-
 src/image.c        |   2 +-
 src/intervals.c    |   2 -
 src/json.c         |   4 +-
 src/keyboard.c     |   8 +-
 src/keymap.c       |  34 ++-
 src/lisp.h         |  41 +---
 src/lread.c        |  53 ++---
 src/pdumper.c      |   5 +-
 src/print.c        |   6 -
 src/process.c      |   4 +-
 src/profiler.c     |   2 +-
 src/puresize.h     | 115 ----------
 src/search.c       |  12 +-
 src/syntax.c       |   4 +-
 src/w32fns.c       |   4 +-
 src/xdisp.c        |  20 +-
 src/xfaces.c       |   2 +-
 src/xfns.c         |   9 +-
 src/xterm.c        |   4 +-
 38 files changed, 194 insertions(+), 913 deletions(-)

diff --git a/configure.ac b/configure.ac
index ace1085284..6ba3c77f5e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2284,7 +2284,7 @@ AC_DEFUN
 case "$opsys" in
   ## darwin ld insists on the use of malloc routines in the System framework.
   darwin | mingw32 | nacl | solaris) ;;
-  cygwin | qnxnto | freebsd)
+  cygwin | qnxnto | freebsd | gnu-linux )
 	  hybrid_malloc=yes
           system_malloc= ;;
   *) test "$ac_cv_func_sbrk" = yes && system_malloc=$emacs_cv_sanitize_address;;
diff --git a/src/Makefile.in b/src/Makefile.in
index c5fb2ea3ab..cab5f69ef7 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -402,8 +402,6 @@ .c.o:
 .m.o:
 	$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
 
-## lastfile must follow all files whose initialized data areas should
-## be dumped as pure by dump-emacs.
 base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
 	charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \
 	$(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \
diff --git a/src/alloc.c b/src/alloc.c
index b16b2f8b93..26a15f1d08 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -34,7 +34,6 @@ Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2020 Free Software
 #include "bignum.h"
 #include "dispextern.h"
 #include "intervals.h"
-#include "puresize.h"
 #include "sheap.h"
 #include "sysstdio.h"
 #include "systime.h"
@@ -333,33 +332,6 @@ #define HI_THRESHOLD (EMACS_INT_MAX / 2)
 
 #define SPARE_MEMORY (1 << 14)
 
-/* Initialize it to a nonzero value to force it into data space
-   (rather than bss space).  That way unexec will remap it into text
-   space (pure), on some systems.  We have not implemented the
-   remapping on more recent systems because this is less important
-   nowadays than in the days of small memories and timesharing.  */
-
-EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,};
-#define PUREBEG (char *) pure
-
-/* Pointer to the pure area, and its size.  */
-
-static char *purebeg;
-static ptrdiff_t pure_size;
-
-/* Number of bytes of pure storage used before pure storage overflowed.
-   If this is non-zero, this implies that an overflow occurred.  */
-
-static ptrdiff_t pure_bytes_used_before_overflow;
-
-/* Index in pure at which next pure Lisp object will be allocated..  */
-
-static ptrdiff_t pure_bytes_used_lisp;
-
-/* Number of bytes allocated for non-Lisp objects in pure storage.  */
-
-static ptrdiff_t pure_bytes_used_non_lisp;
-
 /* If positive, garbage collection is inhibited.  Otherwise, zero.  */
 
 static intptr_t garbage_collection_inhibited;
@@ -434,7 +406,6 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
 static void unchain_finalizer (struct Lisp_Finalizer *);
 static void mark_terminals (void);
 static void gc_sweep (void);
-static Lisp_Object make_pure_vector (ptrdiff_t);
 static void mark_buffer (struct buffer *);
 
 #if !defined REL_ALLOC || defined SYSTEM_MALLOC || defined HYBRID_MALLOC
@@ -576,16 +547,6 @@ #define MEM_NIL &mem_z
 
 int staticidx;
 
-static void *pure_alloc (size_t, int);
-
-/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
-
-static void *
-pointer_align (void *ptr, int alignment)
-{
-  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
-}
-
 /* Extract the pointer hidden within O.  */
 
 static ATTRIBUTE_NO_SANITIZE_UNDEFINED void *
@@ -1071,6 +1032,15 @@ verify (POWER_OF_2 (BLOCK_ALIGN));
 # elif !defined HYBRID_MALLOC && defined HAVE_POSIX_MEMALIGN
 #  define USE_ALIGNED_ALLOC 1
 #  define aligned_alloc my_aligned_alloc /* Avoid collision with lisp.h.  */
+
+/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
+
+static void *
+pointer_align (void *ptr, int alignment)
+{
+  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
+}
+
 static void *
 aligned_alloc (size_t alignment, size_t size)
 {
@@ -1675,9 +1645,9 @@ #define GC_STRING_EXTRA GC_STRING_OVERRUN_COOKIE_SIZE
 static void
 init_strings (void)
 {
-  empty_unibyte_string = make_pure_string ("", 0, 0, 0);
+  empty_unibyte_string = make_specified_string ("", 0, 0, false);
   staticpro (&empty_unibyte_string);
-  empty_multibyte_string = make_pure_string ("", 0, 0, 1);
+  empty_multibyte_string = make_specified_string ("", 0, 0, true);
   staticpro (&empty_multibyte_string);
 }
 
@@ -1695,7 +1665,7 @@ string_bytes (struct Lisp_String *s)
   ptrdiff_t nbytes =
     (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
 
-  if (!PURE_P (s) && !pdumper_object_p (s) && s->u.s.data
+  if (!pdumper_object_p (s) && s->u.s.data
       && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
     emacs_abort ();
   return nbytes;
@@ -2411,7 +2381,7 @@ make_specified_string (const char *contents,
 {
   Lisp_Object val;
 
-  if (nchars < 0)
+  if (nchars <= 0)
     {
       if (multibyte)
 	nchars = multibyte_chars_in_text ((const unsigned char *) contents,
@@ -2465,8 +2435,6 @@ make_clear_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes, bool clearit)
 
   if (nchars < 0)
     emacs_abort ();
-  if (!nbytes)
-    return empty_multibyte_string;
 
   s = allocate_string ();
   s->u.s.intervals = NULL;
@@ -2747,17 +2715,16 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4,
 }
 
 /* Make a list of COUNT Lisp_Objects, where ARG is the first one.
-   Use CONS to construct the pairs.  AP has any remaining args.  */
+   AP has any remaining args.  */
 static Lisp_Object
-cons_listn (ptrdiff_t count, Lisp_Object arg,
-	    Lisp_Object (*cons) (Lisp_Object, Lisp_Object), va_list ap)
+cons_listn (ptrdiff_t count, Lisp_Object arg, va_list ap)
 {
   eassume (0 < count);
-  Lisp_Object val = cons (arg, Qnil);
+  Lisp_Object val = Fcons (arg, Qnil);
   Lisp_Object tail = val;
   for (ptrdiff_t i = 1; i < count; i++)
     {
-      Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil);
+      Lisp_Object elem = Fcons (va_arg (ap, Lisp_Object), Qnil);
       XSETCDR (tail, elem);
       tail = elem;
     }
@@ -2770,18 +2737,7 @@ listn (ptrdiff_t count, Lisp_Object arg1, ...)
 {
   va_list ap;
   va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, Fcons, ap);
-  va_end (ap);
-  return val;
-}
-
-/* Make a pure list of COUNT Lisp_Objects, where ARG1 is the first one.  */
-Lisp_Object
-pure_listn (ptrdiff_t count, Lisp_Object arg1, ...)
-{
-  va_list ap;
-  va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, pure_cons, ap);
+  Lisp_Object val = cons_listn (count, arg1, ap);
   va_end (ap);
   return val;
 }
@@ -2947,7 +2903,7 @@ large_vector_vec (struct large_vector *p)
 
 static struct large_vector *large_vectors;
 
-/* The only vector with 0 slots, allocated from pure space.  */
+/* The only vector with 0 slots.  */
 
 Lisp_Object zero_vector;
 
@@ -2983,15 +2939,6 @@ allocate_vector_block (void)
   return block;
 }
 
-/* Called once to initialize vector allocation.  */
-
-static void
-init_vectors (void)
-{
-  zero_vector = make_pure_vector (0);
-  staticpro (&zero_vector);
-}
-
 /* Allocate vector from a vector block.  */
 
 static struct Lisp_Vector *
@@ -3264,7 +3211,7 @@ #define VECTOR_ELTS_MAX \
 static struct Lisp_Vector *
 allocate_vectorlike (ptrdiff_t len, bool clearit)
 {
-  eassert (0 < len && len <= VECTOR_ELTS_MAX);
+  eassert (0 <= len && len <= VECTOR_ELTS_MAX);
   ptrdiff_t nbytes = header_size + len * word_size;
   struct Lisp_Vector *p;
 
@@ -3339,6 +3286,17 @@ allocate_nil_vector (ptrdiff_t len)
 }
 
 
+/* Called once to initialize vector allocation.  */
+
+static void
+init_vectors (void)
+{
+  zero_vector =
+    make_lisp_ptr (allocate_vectorlike (0, true), Lisp_Vectorlike);
+  XVECTOR (zero_vector)->header.size = 0;
+  staticpro (&zero_vector);
+}
+
 /* Allocate other vector-like structures.  */
 
 struct Lisp_Vector *
@@ -3519,13 +3477,6 @@ #define SYMBOL_BLOCK_SIZE \
 
 static struct symbol_block *symbol_block;
 static int symbol_block_index = SYMBOL_BLOCK_SIZE;
-/* Pointer to the first symbol_block that contains pinned symbols.
-   Tests for 24.4 showed that at dump-time, Emacs contains about 15K symbols,
-   10K of which are pinned (and all but 250 of them are interned in obarray),
-   whereas a "typical session" has in the order of 30K symbols.
-   `symbol_block_pinned' lets mark_pinned_symbols scan only 15K symbols rather
-   than 30K to find the 10K symbols we need to mark.  */
-static struct symbol_block *symbol_block_pinned;
 
 /* List of free symbols.  */
 
@@ -3551,7 +3502,6 @@ init_symbol (Lisp_Object val, Lisp_Object name)
   p->u.s.interned = SYMBOL_UNINTERNED;
   p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
   p->u.s.declared_special = false;
-  p->u.s.pinned = false;
 }
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
@@ -5129,8 +5079,6 @@ valid_lisp_object_p (Lisp_Object obj)
     return 1;
 
   void *p = XPNTR (obj);
-  if (PURE_P (p))
-    return 1;
 
   if (SYMBOLP (obj) && c_symbol_p (p))
     return ((char *) p - (char *) lispsym) % sizeof lispsym[0] == 0;
@@ -5186,296 +5134,8 @@ valid_lisp_object_p (Lisp_Object obj)
   return 0;
 }
 
-/***********************************************************************
-		       Pure Storage Management
- ***********************************************************************/
-
-/* Allocate room for SIZE bytes from pure Lisp storage and return a
-   pointer to it.  TYPE is the Lisp type for which the memory is
-   allocated.  TYPE < 0 means it's not used for a Lisp object,
-   and that the result should have an alignment of -TYPE.
-
-   The bytes are initially zero.
-
-   If pure space is exhausted, allocate space from the heap.  This is
-   merely an expedient to let Emacs warn that pure space was exhausted
-   and that Emacs should be rebuilt with a larger pure space.  */
-
-static void *
-pure_alloc (size_t size, int type)
-{
-  void *result;
-
- again:
-  if (type >= 0)
-    {
-      /* Allocate space for a Lisp object from the beginning of the free
-	 space with taking account of alignment.  */
-      result = pointer_align (purebeg + pure_bytes_used_lisp, LISP_ALIGNMENT);
-      pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size;
-    }
-  else
-    {
-      /* Allocate space for a non-Lisp object from the end of the free
-	 space.  */
-      ptrdiff_t unaligned_non_lisp = pure_bytes_used_non_lisp + size;
-      char *unaligned = purebeg + pure_size - unaligned_non_lisp;
-      int decr = (intptr_t) unaligned & (-1 - type);
-      pure_bytes_used_non_lisp = unaligned_non_lisp + decr;
-      result = unaligned - decr;
-    }
-  pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp;
-
-  if (pure_bytes_used <= pure_size)
-    return result;
-
-  /* Don't allocate a large amount here,
-     because it might get mmap'd and then its address
-     might not be usable.  */
-  int small_amount = 10000;
-  eassert (size <= small_amount - LISP_ALIGNMENT);
-  purebeg = xzalloc (small_amount);
-  pure_size = small_amount;
-  pure_bytes_used_before_overflow += pure_bytes_used - size;
-  pure_bytes_used = 0;
-  pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0;
-
-  /* Can't GC if pure storage overflowed because we can't determine
-     if something is a pure object or not.  */
-  garbage_collection_inhibited++;
-  goto again;
-}
-
-
-#ifdef HAVE_UNEXEC
-
-/* Print a warning if PURESIZE is too small.  */
-
-void
-check_pure_size (void)
-{
-  if (pure_bytes_used_before_overflow)
-    message (("emacs:0:Pure Lisp storage overflow (approx. %"pI"d"
-	      " bytes needed)"),
-	     pure_bytes_used + pure_bytes_used_before_overflow);
-}
-#endif
-
-
-/* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
-   the non-Lisp data pool of the pure storage, and return its start
-   address.  Return NULL if not found.  */
-
-static char *
-find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
-{
-  int i;
-  ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max;
-  const unsigned char *p;
-  char *non_lisp_beg;
-
-  if (pure_bytes_used_non_lisp <= nbytes)
-    return NULL;
-
-  /* Set up the Boyer-Moore table.  */
-  skip = nbytes + 1;
-  for (i = 0; i < 256; i++)
-    bm_skip[i] = skip;
-
-  p = (const unsigned char *) data;
-  while (--skip > 0)
-    bm_skip[*p++] = skip;
-
-  last_char_skip = bm_skip['\0'];
-
-  non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp;
-  start_max = pure_bytes_used_non_lisp - (nbytes + 1);
-
-  /* See the comments in the function `boyer_moore' (search.c) for the
-     use of `infinity'.  */
-  infinity = pure_bytes_used_non_lisp + 1;
-  bm_skip['\0'] = infinity;
-
-  p = (const unsigned char *) non_lisp_beg + nbytes;
-  start = 0;
-  do
-    {
-      /* Check the last character (== '\0').  */
-      do
-	{
-	  start += bm_skip[*(p + start)];
-	}
-      while (start <= start_max);
-
-      if (start < infinity)
-	/* Couldn't find the last character.  */
-	return NULL;
-
-      /* No less than `infinity' means we could find the last
-	 character at `p[start - infinity]'.  */
-      start -= infinity;
-
-      /* Check the remaining characters.  */
-      if (memcmp (data, non_lisp_beg + start, nbytes) == 0)
-	/* Found.  */
-	return non_lisp_beg + start;
-
-      start += last_char_skip;
-    }
-  while (start <= start_max);
-
-  return NULL;
-}
-
-
-/* Return a string allocated in pure space.  DATA is a buffer holding
-   NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
-   means make the result string multibyte.
-
-   Must get an error if pure storage is full, since if it cannot hold
-   a large string it may be able to hold conses that point to that
-   string; then the string is not protected from gc.  */
-
-Lisp_Object
-make_pure_string (const char *data,
-		  ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->u.s.data == NULL)
-    {
-      s->u.s.data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->u.s.data, data, nbytes);
-      s->u.s.data[nbytes] = '\0';
-    }
-  s->u.s.size = nchars;
-  s->u.s.size_byte = multibyte ? nbytes : -1;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-/* Return a string allocated in pure space.  Do not
-   allocate the string data, just point to DATA.  */
-
-Lisp_Object
-make_pure_c_string (const char *data, ptrdiff_t nchars)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.size = nchars;
-  s->u.s.size_byte = -2;
-  s->u.s.data = (unsigned char *) data;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-static Lisp_Object purecopy (Lisp_Object obj);
-
-/* Return a cons allocated from pure space.  Give it pure copies
-   of CAR as car and CDR as cdr.  */
-
-Lisp_Object
-pure_cons (Lisp_Object car, Lisp_Object cdr)
-{
-  Lisp_Object new;
-  struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons);
-  XSETCONS (new, p);
-  XSETCAR (new, purecopy (car));
-  XSETCDR (new, purecopy (cdr));
-  return new;
-}
-
-
-/* Value is a float object with value NUM allocated from pure space.  */
-
 static Lisp_Object
-make_pure_float (double num)
-{
-  Lisp_Object new;
-  struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float);
-  XSETFLOAT (new, p);
-  XFLOAT_INIT (new, num);
-  return new;
-}
-
-/* Value is a bignum object with value VALUE allocated from pure
-   space.  */
-
-static Lisp_Object
-make_pure_bignum (Lisp_Object value)
-{
-  mpz_t const *n = xbignum_val (value);
-  size_t i, nlimbs = mpz_size (*n);
-  size_t nbytes = nlimbs * sizeof (mp_limb_t);
-  mp_limb_t *pure_limbs;
-  mp_size_t new_size;
-
-  struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike);
-  XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum));
-
-  int limb_alignment = alignof (mp_limb_t);
-  pure_limbs = pure_alloc (nbytes, - limb_alignment);
-  for (i = 0; i < nlimbs; ++i)
-    pure_limbs[i] = mpz_getlimbn (*n, i);
-
-  new_size = nlimbs;
-  if (mpz_sgn (*n) < 0)
-    new_size = -new_size;
-
-  mpz_roinit_n (b->value, pure_limbs, new_size);
-
-  return make_lisp_ptr (b, Lisp_Vectorlike);
-}
-
-/* Return a vector with room for LEN Lisp_Objects allocated from
-   pure space.  */
-
-static Lisp_Object
-make_pure_vector (ptrdiff_t len)
-{
-  Lisp_Object new;
-  size_t size = header_size + len * word_size;
-  struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike);
-  XSETVECTOR (new, p);
-  XVECTOR (new)->header.size = len;
-  return new;
-}
-
-/* Copy all contents and parameters of TABLE to a new table allocated
-   from pure space, return the purified table.  */
-static struct Lisp_Hash_Table *
-purecopy_hash_table (struct Lisp_Hash_Table *table)
-{
-  eassert (NILP (table->weak));
-  eassert (table->purecopy);
-
-  struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
-  struct hash_table_test pure_test = table->test;
-
-  /* Purecopy the hash table test.  */
-  pure_test.name = purecopy (table->test.name);
-  pure_test.user_hash_function = purecopy (table->test.user_hash_function);
-  pure_test.user_cmp_function = purecopy (table->test.user_cmp_function);
-
-  pure->header = table->header;
-  pure->weak = purecopy (Qnil);
-  pure->hash = purecopy (table->hash);
-  pure->next = purecopy (table->next);
-  pure->index = purecopy (table->index);
-  pure->count = table->count;
-  pure->next_free = table->next_free;
-  pure->purecopy = table->purecopy;
-  eassert (!pure->mutable);
-  pure->rehash_threshold = table->rehash_threshold;
-  pure->rehash_size = table->rehash_size;
-  pure->key_and_value = purecopy (table->key_and_value);
-  pure->test = pure_test;
-
-  return pure;
-}
+purecopy (Lisp_Object obj);
 
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
        doc: /* Make a copy of object OBJ in pure storage.
@@ -5492,100 +5152,23 @@ DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
     return purecopy (obj);
 }
 
-/* Pinned objects are marked before every GC cycle.  */
-static struct pinned_object
-{
-  Lisp_Object object;
-  struct pinned_object *next;
-} *pinned_objects;
-
 static Lisp_Object
 purecopy (Lisp_Object obj)
 {
-  if (FIXNUMP (obj)
-      || (! SYMBOLP (obj) && PURE_P (XPNTR (obj)))
-      || SUBRP (obj))
+  if (FIXNUMP (obj) || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
-    message_with_string ("Dropping text-properties while making string `%s' pure",
-			 obj, true);
-
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
     {
       Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
       if (!NILP (tmp))
 	return tmp;
+      Fputhash (obj, obj, Vpurify_flag);
     }
 
-  if (CONSP (obj))
-    obj = pure_cons (XCAR (obj), XCDR (obj));
-  else if (FLOATP (obj))
-    obj = make_pure_float (XFLOAT_DATA (obj));
-  else if (STRINGP (obj))
-    obj = make_pure_string (SSDATA (obj), SCHARS (obj),
-			    SBYTES (obj),
-			    STRING_MULTIBYTE (obj));
-  else if (HASH_TABLE_P (obj))
-    {
-      struct Lisp_Hash_Table *table = XHASH_TABLE (obj);
-      /* Do not purify hash tables which haven't been defined with
-         :purecopy as non-nil or are weak - they aren't guaranteed to
-         not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
-        {
-          /* Instead, add the hash table to the list of pinned objects,
-             so that it will be marked during GC.  */
-          struct pinned_object *o = xmalloc (sizeof *o);
-          o->object = obj;
-          o->next = pinned_objects;
-          pinned_objects = o;
-          return obj; /* Don't hash cons it.  */
-        }
-
-      struct Lisp_Hash_Table *h = purecopy_hash_table (table);
-      XSET_HASH_TABLE (obj, h);
-    }
-  else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
-    {
-      struct Lisp_Vector *objp = XVECTOR (obj);
-      ptrdiff_t nbytes = vector_nbytes (objp);
-      struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
-      register ptrdiff_t i;
-      ptrdiff_t size = ASIZE (obj);
-      if (size & PSEUDOVECTOR_FLAG)
-	size &= PSEUDOVECTOR_SIZE_MASK;
-      memcpy (vec, objp, nbytes);
-      for (i = 0; i < size; i++)
-	vec->contents[i] = purecopy (vec->contents[i]);
-      XSETVECTOR (obj, vec);
-    }
-  else if (SYMBOLP (obj))
-    {
-      if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
-	{ /* We can't purify them, but they appear in many pure objects.
-	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XSYMBOL (obj)->u.s.pinned = true;
-	  symbol_block_pinned = symbol_block;
-	}
-      /* Don't hash-cons it.  */
-      return obj;
-    }
-  else if (BIGNUMP (obj))
-    obj = make_pure_bignum (obj);
-  else
-    {
-      AUTO_STRING (fmt, "Don't know how to purify: %S");
-      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
-    }
-
-  if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
-    Fputhash (obj, obj, Vpurify_flag);
-
   return obj;
 }
 
-
 \f
 /***********************************************************************
 			  Protection from GC
@@ -5776,31 +5359,6 @@ compact_undo_list (Lisp_Object list)
   return list;
 }
 
-static void
-mark_pinned_objects (void)
-{
-  for (struct pinned_object *pobj = pinned_objects; pobj; pobj = pobj->next)
-    mark_object (pobj->object);
-}
-
-static void
-mark_pinned_symbols (void)
-{
-  struct symbol_block *sblk;
-  int lim = (symbol_block_pinned == symbol_block
-	     ? symbol_block_index : SYMBOL_BLOCK_SIZE);
-
-  for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
-    {
-      struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
-      for (; sym < end; ++sym)
-	if (sym->u.s.pinned)
-	  mark_object (make_lisp_symbol (sym));
-
-      lim = SYMBOL_BLOCK_SIZE;
-    }
-}
-
 static void
 visit_vectorlike_root (struct gc_root_visitor visitor,
                        struct Lisp_Vector *ptr,
@@ -6061,8 +5619,6 @@ garbage_collect (void)
   struct gc_root_visitor visitor = { .visit = mark_object_root_visitor };
   visit_static_gc_roots (visitor);
 
-  mark_pinned_objects ();
-  mark_pinned_symbols ();
   mark_terminals ();
   mark_kboards ();
   mark_threads ();
@@ -6172,9 +5728,6 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
 - FREE is the number of those objects that are not live but that Emacs
   keeps around for future allocations (maybe because it does not know how
   to return them to the OS).
-However, if there was overflow in pure space, and Emacs was dumped
-using the 'unexec' method, `garbage-collect' returns nil, because
-real GC can't be done.
 See Info node `(elisp)Garbage Collection'.  */)
   (void)
 {
@@ -6512,7 +6065,6 @@ mark_hash_table (struct Lisp_Vector *ptr)
 mark_object (Lisp_Object arg)
 {
   register Lisp_Object obj;
-  void *po;
 #if GC_CHECK_MARKED_OBJECTS
   struct mem_node *m = NULL;
 #endif
@@ -6521,10 +6073,6 @@ mark_object (Lisp_Object arg)
   obj = arg;
  loop:
 
-  po = XPNTR (obj);
-  if (PURE_P (po))
-    return;
-
   last_marked[last_marked_index++] = obj;
   last_marked_index &= LAST_MARKED_SIZE - 1;
 
@@ -6717,11 +6265,10 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL()		((void) 0)
 	    break;
 	  default: emacs_abort ();
 	  }
-	if (!PURE_P (XSTRING (ptr->u.s.name)))
-          set_string_marked (XSTRING (ptr->u.s.name));
+	set_string_marked (XSTRING (ptr->u.s.name));
         mark_interval_tree (string_intervals (ptr->u.s.name));
 	/* Inner loop to mark next symbol in this bucket, if any.  */
-	po = ptr = ptr->u.s.next;
+	ptr = ptr->u.s.next;
 	if (ptr)
 	  goto nextsym;
       }
@@ -6832,7 +6379,7 @@ survives_gc_p (Lisp_Object obj)
       emacs_abort ();
     }
 
-  return survives_p || PURE_P (XPNTR (obj));
+  return survives_p;
 }
 
 
@@ -7406,8 +6953,6 @@ init_alloc_once (void)
 static void
 init_alloc_once_for_pdumper (void)
 {
-  purebeg = PUREBEG;
-  pure_size = PURESIZE;
   mem_init ();
 
 #ifdef DOUG_LEA_MALLOC
@@ -7451,7 +6996,7 @@ syms_of_alloc (void)
   Vgc_cons_percentage = make_float (0.1);
 
   DEFVAR_INT ("pure-bytes-used", pure_bytes_used,
-	      doc: /* Number of bytes of shareable Lisp data allocated so far.  */);
+	      doc: /* No longer used.  */);
 
   DEFVAR_INT ("cons-cells-consed", cons_cells_consed,
 	      doc: /* Number of cons cells that have been consed so far.  */);
@@ -7476,10 +7021,7 @@ syms_of_alloc (void)
 	      doc: /* Number of strings that have been consed so far.  */);
 
   DEFVAR_LISP ("purify-flag", Vpurify_flag,
-	       doc: /* Non-nil means loading Lisp code in order to dump an executable.
-This means that certain objects should be allocated in shared (pure) space.
-It can also be set to a hash-table, in which case this table is used to
-do hash-consing of the objects allocated to pure space.  */);
+	       doc: /* No longer used.  */);
 
   DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages,
 	       doc: /* Non-nil means display messages at start and end of garbage collection.  */);
@@ -7495,10 +7037,10 @@ syms_of_alloc (void)
   /* We build this in advance because if we wait until we need it, we might
      not be able to allocate the memory to hold it.  */
   Vmemory_signal_data
-    = pure_list (Qerror,
-		 build_pure_c_string ("Memory exhausted--use"
-				      " M-x save-some-buffers then"
-				      " exit and restart Emacs"));
+    = list (Qerror,
+	    build_string ("Memory exhausted--use"
+			  " M-x save-some-buffers then"
+			  " exit and restart Emacs"));
 
   DEFVAR_LISP ("memory-full", Vmemory_full,
 	       doc: /* Non-nil means Emacs cannot get much more Lisp memory.  */);
diff --git a/src/buffer.c b/src/buffer.c
index 241f2d43a9..686c6748c5 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5266,8 +5266,8 @@ init_buffer_once (void)
   set_buffer_intervals (&buffer_defaults, NULL);
   set_buffer_intervals (&buffer_local_symbols, NULL);
   /* This is not strictly necessary, but let's make them initialized.  */
-  bset_name (&buffer_defaults, build_pure_c_string (" *buffer-defaults*"));
-  bset_name (&buffer_local_symbols, build_pure_c_string (" *buffer-local-symbols*"));
+  bset_name (&buffer_defaults, build_string (" *buffer-defaults*"));
+  bset_name (&buffer_local_symbols, build_string (" *buffer-local-symbols*"));
   BUFFER_PVEC_INIT (&buffer_defaults);
   BUFFER_PVEC_INIT (&buffer_local_symbols);
 
@@ -5275,7 +5275,7 @@ init_buffer_once (void)
   /* Must do these before making the first buffer! */
 
   /* real setup is done in bindings.el */
-  bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
+  bset_mode_line_format (&buffer_defaults, build_string ("%-"));
   bset_header_line_format (&buffer_defaults, Qnil);
   bset_tab_line_format (&buffer_defaults, Qnil);
   bset_abbrev_mode (&buffer_defaults, Qnil);
@@ -5342,7 +5342,7 @@ init_buffer_once (void)
   current_buffer = 0;
   pdumper_remember_lv_ptr_raw (&current_buffer, Lisp_Vectorlike);
 
-  QSFundamental = build_pure_c_string ("Fundamental");
+  QSFundamental = build_string ("Fundamental");
 
   DEFSYM (Qfundamental_mode, "fundamental-mode");
   bset_major_mode (&buffer_defaults, Qfundamental_mode);
@@ -5355,10 +5355,10 @@ init_buffer_once (void)
   Fput (Qkill_buffer_hook, Qpermanent_local, Qt);
 
   /* Super-magic invisible buffer.  */
-  Vprin1_to_string_buffer = Fget_buffer_create (build_pure_c_string (" prin1"));
+  Vprin1_to_string_buffer = Fget_buffer_create (build_string (" prin1"));
   Vbuffer_alist = Qnil;
 
-  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*")));
+  Fset_buffer (Fget_buffer_create (build_string ("*scratch*")));
 
   inhibit_modification_hooks = 0;
 }
@@ -5533,9 +5533,9 @@ syms_of_buffer (void)
 	       Qoverwrite_mode_binary));
 
   Fput (Qprotected_field, Qerror_conditions,
-	pure_list (Qprotected_field, Qerror));
+	list (Qprotected_field, Qerror));
   Fput (Qprotected_field, Qerror_message,
-	build_pure_c_string ("Attempt to modify a protected field"));
+	build_string ("Attempt to modify a protected field"));
 
   DEFVAR_PER_BUFFER ("tab-line-format",
 		     &BVAR (current_buffer, tab_line_format),
diff --git a/src/callint.c b/src/callint.c
index f609c96a6f..668b2089ab 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -812,10 +812,10 @@ syms_of_callint (void)
   callint_message = Qnil;
   staticpro (&callint_message);
 
-  preserved_fns = pure_list (intern_c_string ("region-beginning"),
-			     intern_c_string ("region-end"),
-			     intern_c_string ("point"),
-			     intern_c_string ("mark"));
+  preserved_fns = list (intern_c_string ("region-beginning"),
+			intern_c_string ("region-end"),
+			intern_c_string ("point"),
+			intern_c_string ("mark"));
   staticpro (&preserved_fns);
 
   DEFSYM (Qlist, "list");
diff --git a/src/category.c b/src/category.c
index c80571ecd4..0b055f327a 100644
--- a/src/category.c
+++ b/src/category.c
@@ -53,7 +53,7 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
       (table, 1,
        make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			Qnil, false));
+			Qnil));
   struct Lisp_Hash_Table *h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
   Lisp_Object hash;
   ptrdiff_t i = hash_lookup (h, category_set, &hash);
@@ -120,8 +120,6 @@ DEFUN ("define-category", Fdefine_category, Sdefine_category, 2, 3, 0,
 
   if (!NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category))))
     error ("Category `%c' is already defined", (int) XFIXNAT (category));
-  if (!NILP (Vpurify_flag))
-    docstring = Fpurecopy (docstring);
   SET_CATEGORY_DOCSTRING (table, XFIXNAT (category), docstring);
 
   return Qnil;
diff --git a/src/coding.c b/src/coding.c
index 51bd441de9..1020bd651d 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -11631,7 +11631,7 @@ syms_of_coding (void)
   Vcode_conversion_reused_workbuf = Qnil;
 
   staticpro (&Vcode_conversion_workbuf_name);
-  Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
+  Vcode_conversion_workbuf_name = build_string (" *code-conversion-work*");
 
   reused_workbuf_in_use = 0;
   PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
@@ -11695,9 +11695,9 @@ syms_of_coding (void)
   /* Error signaled when there's a problem with detecting a coding system.  */
   DEFSYM (Qcoding_system_error, "coding-system-error");
   Fput (Qcoding_system_error, Qerror_conditions,
-	pure_list (Qcoding_system_error, Qerror));
+	list (Qcoding_system_error, Qerror));
   Fput (Qcoding_system_error, Qerror_message,
-	build_pure_c_string ("Invalid coding system"));
+	build_string ("Invalid coding system"));
 
   DEFSYM (Qtranslation_table, "translation-table");
   Fput (Qtranslation_table, Qchar_table_extra_slots, make_fixnum (2));
@@ -11971,22 +11971,22 @@ syms_of_coding (void)
   DEFVAR_LISP ("eol-mnemonic-unix", eol_mnemonic_unix,
 	       doc: /*
 String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
-  eol_mnemonic_unix = build_pure_c_string (":");
+  eol_mnemonic_unix = build_string (":");
 
   DEFVAR_LISP ("eol-mnemonic-dos", eol_mnemonic_dos,
 	       doc: /*
 String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
-  eol_mnemonic_dos = build_pure_c_string ("\\");
+  eol_mnemonic_dos = build_string ("\\");
 
   DEFVAR_LISP ("eol-mnemonic-mac", eol_mnemonic_mac,
 	       doc: /*
 String displayed in mode line for MAC-like (CR) end-of-line format.  */);
-  eol_mnemonic_mac = build_pure_c_string ("/");
+  eol_mnemonic_mac = build_string ("/");
 
   DEFVAR_LISP ("eol-mnemonic-undecided", eol_mnemonic_undecided,
 	       doc: /*
 String displayed in mode line when end-of-line format is not yet determined.  */);
-  eol_mnemonic_undecided = build_pure_c_string (":");
+  eol_mnemonic_undecided = build_string (":");
 
   DEFVAR_LISP ("enable-character-translation", Venable_character_translation,
 	       doc: /*
@@ -12126,7 +12126,7 @@ system (e.g. `iso-2022-7bit').
       intern_c_string (":for-unibyte"),
       args[coding_arg_for_unibyte] = Qt,
       intern_c_string (":docstring"),
-      (build_pure_c_string
+      (build_string
        ("Do no conversion.\n"
 	"\n"
 	"When you visit a file with this coding, the file is read into a\n"
@@ -12146,7 +12146,7 @@ system (e.g. `iso-2022-7bit').
   plist[8] = intern_c_string (":charset-list");
   plist[9] = args[coding_arg_charset_list] = list1 (Qascii);
   plist[11] = args[coding_arg_for_unibyte] = Qnil;
-  plist[13] = build_pure_c_string ("No conversion on encoding, "
+  plist[13] = build_string ("No conversion on encoding, "
 				   "automatic conversion on decoding.");
   plist[15] = args[coding_arg_eol_type] = Qnil;
   args[coding_arg_plist] = CALLMANY (Flist, plist);
diff --git a/src/conf_post.h b/src/conf_post.h
index 1ef4ff3342..7c1b7c222c 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -161,41 +161,8 @@ #define emacs_raise(sig) msdos_fatal_signal (sig)
 
 /* DATA_START is needed by vm-limit.c and unexcoff.c. */
 #define DATA_START (&etext + 1)
-
-/* Define one of these for easier conditionals.  */
-#ifdef HAVE_X_WINDOWS
-/* We need a little extra space, see ../../lisp/loadup.el and the
-   commentary below, in the non-X branch.  The 140KB number was
-   measured on GNU/Linux and on MS-Windows.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+140000)
-#else
-/* We need a little extra space, see ../../lisp/loadup.el.
-   As of 20091024, DOS-specific files use up 62KB of pure space.  But
-   overall, we end up wasting 130KB of pure space, because
-   BASE_PURESIZE starts at 1.47MB, while we need only 1.3MB (including
-   non-DOS specific files and load history; the latter is about 55K,
-   but depends on the depth of the top-level Emacs directory in the
-   directory tree).  Given the unknown policy of different DPMI
-   hosts regarding loading of untouched pages, I'm not going to risk
-   enlarging Emacs footprint by another 100+ KBytes.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+90000)
-#endif
 #endif  /* MSDOS */
 
-/* macOS / GNUstep need a bit more pure memory.  Of the existing knobs,
-   SYSTEM_PURESIZE_EXTRA seems like the least likely to cause problems.  */
-#ifdef HAVE_NS
-#if defined NS_IMPL_GNUSTEP
-#  define SYSTEM_PURESIZE_EXTRA 30000
-#elif defined DARWIN_OS
-#  define SYSTEM_PURESIZE_EXTRA 200000
-#endif
-#endif
-
-#ifdef CYGWIN
-#define SYSTEM_PURESIZE_EXTRA 50000
-#endif
-
 #if defined HAVE_NTGUI && !defined DebPrint
 # ifdef EMACSDEBUG
 extern void _DebPrint (const char *fmt, ...);
diff --git a/src/data.c b/src/data.c
index 59d148166f..fc4662cba2 100644
--- a/src/data.c
+++ b/src/data.c
@@ -30,7 +30,6 @@
 
 #include "lisp.h"
 #include "bignum.h"
-#include "puresize.h"
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
@@ -149,12 +148,6 @@ wrong_type_argument (Lisp_Object predicate, Lisp_Object value)
   xsignal2 (Qwrong_type_argument, predicate, value);
 }
 
-void
-pure_write_error (Lisp_Object obj)
-{
-  xsignal2 (Qerror, build_string ("Attempt to modify read-only object"), obj);
-}
-
 void
 args_out_of_range (Lisp_Object a1, Lisp_Object a2)
 {
@@ -625,7 +618,6 @@ DEFUN ("setcar", Fsetcar, Ssetcar, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcar)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCAR (cell, newcar);
   return newcar;
 }
@@ -635,7 +627,6 @@ DEFUN ("setcdr", Fsetcdr, Ssetcdr, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcdr)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCDR (cell, newcdr);
   return newcdr;
 }
@@ -798,10 +789,6 @@ DEFUN ("defalias", Fdefalias, Sdefalias, 2, 3, 0,
   (register Lisp_Object symbol, Lisp_Object definition, Lisp_Object docstring)
 {
   CHECK_SYMBOL (symbol);
-  if (!NILP (Vpurify_flag)
-      /* If `definition' is a keymap, immutable (and copying) is wrong.  */
-      && !KEYMAPP (definition))
-    definition = Fpurecopy (definition);
 
   {
     bool autoload = AUTOLOADP (definition);
@@ -2276,7 +2263,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
 
   if (VECTORP (array))
     {
-      CHECK_IMPURE (array, XVECTOR (array));
       if (idxval < 0 || idxval >= ASIZE (array))
 	args_out_of_range (array, idx);
       ASET (array, idxval, newelt);
@@ -2300,7 +2286,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
     }
   else /* STRINGP */
     {
-      CHECK_IMPURE (array, XSTRING (array));
       if (idxval < 0 || idxval >= SCHARS (array))
 	args_out_of_range (array, idx);
       CHECK_CHARACTER (newelt);
@@ -3781,7 +3766,7 @@ syms_of_data (void)
 
   DEFSYM (Qcdr, "cdr");
 
-  error_tail = pure_cons (Qerror, Qnil);
+  error_tail = Fcons (Qerror, Qnil);
 
   /* ERROR is used as a signaler for random errors for which nothing else is
      right.  */
@@ -3789,11 +3774,11 @@ syms_of_data (void)
   Fput (Qerror, Qerror_conditions,
 	error_tail);
   Fput (Qerror, Qerror_message,
-	build_pure_c_string ("error"));
+	build_string ("error"));
 
 #define PUT_ERROR(sym, tail, msg)			\
-  Fput (sym, Qerror_conditions, pure_cons (sym, tail)); \
-  Fput (sym, Qerror_message, build_pure_c_string (msg))
+  Fput (sym, Qerror_conditions, Fcons (sym, tail)); \
+  Fput (sym, Qerror_message, build_string (msg))
 
   PUT_ERROR (Qquit, Qnil, "Quit");
 
@@ -3821,14 +3806,14 @@ #define PUT_ERROR(sym, tail, msg)			\
   PUT_ERROR (Qno_catch, error_tail, "No catch for tag");
   PUT_ERROR (Qend_of_file, error_tail, "End of file during parsing");
 
-  arith_tail = pure_cons (Qarith_error, error_tail);
+  arith_tail = Fcons (Qarith_error, error_tail);
   Fput (Qarith_error, Qerror_conditions, arith_tail);
-  Fput (Qarith_error, Qerror_message, build_pure_c_string ("Arithmetic error"));
+  Fput (Qarith_error, Qerror_message, build_string ("Arithmetic error"));
 
   PUT_ERROR (Qbeginning_of_buffer, error_tail, "Beginning of buffer");
   PUT_ERROR (Qend_of_buffer, error_tail, "End of buffer");
   PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only");
-  PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail),
+  PUT_ERROR (Qtext_read_only, Fcons (Qbuffer_read_only, error_tail),
 	     "Text is read-only");
 
   DEFSYM (Qrange_error, "range-error");
diff --git a/src/dbusbind.c b/src/dbusbind.c
index f6a0879e6a..105d9905f8 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1702,7 +1702,7 @@ syms_of_dbusbind (void)
   Fput (Qdbus_error, Qerror_conditions,
 	list2 (Qdbus_error, Qerror));
   Fput (Qdbus_error, Qerror_message,
-	build_pure_c_string ("D-Bus error"));
+	build_string ("D-Bus error"));
 
   /* Lisp symbols of the system and session buses.  */
   DEFSYM (QCsystem, ":system");
@@ -1741,7 +1741,7 @@ syms_of_dbusbind (void)
 	       Vdbus_compiled_version,
     doc: /* The version of D-Bus Emacs is compiled against.  */);
 #ifdef DBUS_VERSION_STRING
-  Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
+  Vdbus_compiled_version = build_string (DBUS_VERSION_STRING);
 #else
   Vdbus_compiled_version = Qnil;
 #endif
diff --git a/src/deps.mk b/src/deps.mk
index 4d162eeb0f..ee27d80797 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -132,10 +132,10 @@ insdel.o:
 keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \
    commands.h frame.h window.h macros.h disptab.h keyboard.h syssignal.h \
    systime.h syntax.h $(INTERVALS_H) blockinput.h atimer.h composite.h \
-   xterm.h puresize.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
+   xterm.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
    process.h ../lib/unistd.h gnutls.h lisp.h globals.h $(config_h)
 keymap.o: keymap.c buffer.h commands.h keyboard.h termhooks.h blockinput.h \
-   atimer.h systime.h puresize.h character.h charset.h $(INTERVALS_H) \
+   atimer.h systime.h character.h charset.h $(INTERVALS_H) \
    keymap.h window.h coding.h frame.h lisp.h globals.h $(config_h)
 lastfile.o: lastfile.c $(config_h)
 macros.o: macros.c window.h buffer.h commands.h macros.h keyboard.h msdos.h \
@@ -267,12 +267,12 @@ xsettings.o:
    atimer.h termopts.h globals.h
 
 ## The files of Lisp proper.
-alloc.o: alloc.c process.h frame.h window.h buffer.h  puresize.h syssignal.h \
+alloc.o: alloc.c process.h frame.h window.h buffer.h syssignal.h \
    keyboard.h blockinput.h atimer.h systime.h character.h lisp.h $(config_h) \
    $(INTERVALS_H) termhooks.h gnutls.h coding.h ../lib/unistd.h globals.h
 bytecode.o: bytecode.c buffer.h syntax.h character.h window.h dispextern.h \
   lisp.h globals.h $(config_h) msdos.h
-data.o: data.c buffer.h puresize.h character.h syssignal.h keyboard.h frame.h \
+data.o: data.c buffer.h character.h syssignal.h keyboard.h frame.h \
    termhooks.h systime.h coding.h composite.h dispextern.h font.h ccl.h \
    lisp.h globals.h $(config_h) msdos.h
 eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h frame.h \
@@ -295,7 +295,7 @@ lread.o:
 composite.o: composite.c composite.h buffer.h character.h coding.h font.h \
    ccl.h frame.h termhooks.h $(INTERVALS_H) window.h \
    lisp.h globals.h $(config_h)
-intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h puresize.h \
+intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h \
    keymap.h lisp.h globals.h $(config_h) systime.h coding.h
 textprop.o: textprop.c buffer.h window.h $(INTERVALS_H) \
    lisp.h globals.h $(config_h)
diff --git a/src/doc.c b/src/doc.c
index 285c0dbbbe..d35cd8bc4c 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -500,8 +500,6 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
 	{
 	  tem = Fcdr (Fcdr (fun));
 	  if (CONSP (tem) && FIXNUMP (XCAR (tem)))
-	    /* FIXME: This modifies typically pure hash-cons'd data, so its
-	       correctness is quite delicate.  */
 	    XSETCAR (tem, make_fixnum (offset));
 	}
     }
@@ -585,7 +583,6 @@ DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
       int i = ARRAYELTS (buildobj);
       while (0 <= --i)
 	Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
-      Vbuild_files = Fpurecopy (Vbuild_files);
     }
 
   fd = emacs_open (name, O_RDONLY, 0);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index a0bab11801..1a3c460304 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -1576,7 +1576,7 @@ syms_of_module (void)
   Vmodule_refs_hash
     = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 		       DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-		       Qnil, false);
+		       Qnil);
 
   staticpro (&Vmodule_runtimes);
   Vmodule_runtimes = Qnil;
@@ -1586,40 +1586,40 @@ syms_of_module (void)
 
   DEFSYM (Qmodule_load_failed, "module-load-failed");
   Fput (Qmodule_load_failed, Qerror_conditions,
-	pure_list (Qmodule_load_failed, Qerror));
+	list (Qmodule_load_failed, Qerror));
   Fput (Qmodule_load_failed, Qerror_message,
-        build_pure_c_string ("Module load failed"));
+        build_string ("Module load failed"));
 
   DEFSYM (Qmodule_open_failed, "module-open-failed");
   Fput (Qmodule_open_failed, Qerror_conditions,
-	pure_list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_open_failed, Qerror_message,
-        build_pure_c_string ("Module could not be opened"));
+        build_string ("Module could not be opened"));
 
   DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible");
   Fput (Qmodule_not_gpl_compatible, Qerror_conditions,
-	pure_list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
+	list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
   Fput (Qmodule_not_gpl_compatible, Qerror_message,
-        build_pure_c_string ("Module is not GPL compatible"));
+        build_string ("Module is not GPL compatible"));
 
   DEFSYM (Qmissing_module_init_function, "missing-module-init-function");
   Fput (Qmissing_module_init_function, Qerror_conditions,
-	pure_list (Qmissing_module_init_function, Qmodule_load_failed,
-		   Qerror));
+	list (Qmissing_module_init_function, Qmodule_load_failed,
+	      Qerror));
   Fput (Qmissing_module_init_function, Qerror_message,
-        build_pure_c_string ("Module does not export an "
+        build_string ("Module does not export an "
                              "initialization function"));
 
   DEFSYM (Qmodule_init_failed, "module-init-failed");
   Fput (Qmodule_init_failed, Qerror_conditions,
-	pure_list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_init_failed, Qerror_message,
-        build_pure_c_string ("Module initialization failed"));
+        build_string ("Module initialization failed"));
 
   DEFSYM (Qinvalid_arity, "invalid-arity");
-  Fput (Qinvalid_arity, Qerror_conditions, pure_list (Qinvalid_arity, Qerror));
+  Fput (Qinvalid_arity, Qerror_conditions, list (Qinvalid_arity, Qerror));
   Fput (Qinvalid_arity, Qerror_message,
-        build_pure_c_string ("Invalid function arity"));
+        build_string ("Invalid function arity"));
 
   DEFSYM (Qmodule_function_p, "module-function-p");
   DEFSYM (Qunicode_string_p, "unicode-string-p");
diff --git a/src/emacs.c b/src/emacs.c
index 059e1c6d8f..ce10fc8004 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -88,7 +88,6 @@ #define MAIN_PROGRAM
 #include "syntax.h"
 #include "sysselect.h"
 #include "systime.h"
-#include "puresize.h"
 
 #include "getpagesize.h"
 #include "gnutls.h"
@@ -1536,7 +1535,9 @@ main (int argc, char **argv)
   if (!initialized)
     {
       init_alloc_once ();
+#ifdef HAVE_PDUMPER
       init_pdumper_once ();
+#endif
       init_obarray_once ();
       init_eval_once ();
       init_charset_once ();
@@ -2499,8 +2500,6 @@ DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
   Lisp_Object symbol;
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  check_pure_size ();
-
   if (! noninteractive)
     error ("Dumping Emacs works only in batch mode");
 
diff --git a/src/eval.c b/src/eval.c
index 9daae92e55..66aea08e00 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -726,8 +726,6 @@ DEFUN ("internal--define-uninitialized-variable",
   XSYMBOL (symbol)->u.s.declared_special = true;
   if (!NILP (doc))
     {
-      if (!NILP (Vpurify_flag))
-	doc = Fpurecopy (doc);
       Fput (symbol, Qvariable_documentation, doc);
     }
   LOADHIST_ATTACH (symbol);
@@ -842,8 +840,6 @@ DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
 
   Finternal__define_uninitialized_variable (sym, docstring);
   tem = eval_sub (XCAR (XCDR (args)));
-  if (!NILP (Vpurify_flag))
-    tem = Fpurecopy (tem);
   Fset_default (sym, tem);      /* FIXME: set-default-toplevel-value? */
   Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why?  */
   return sym;
@@ -1990,12 +1986,6 @@ DEFUN ("autoload", Fautoload, Sautoload, 2, 5, 0,
       && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_fixnum (0)))
-    /* `read1' in lread.c has found the docstring starting with "\
-       and assumed the docstring will be provided by Snarf-documentation, so it
-       passed us 0 instead.  But that leads to accidental sharing in purecopy's
-       hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_ufixnum (XHASH (function));
   return Fdefalias (function,
 		    list5 (Qautoload, file, docstring, interactive, type),
 		    Qnil);
@@ -4195,7 +4185,7 @@ syms_of_eval (void)
      also use something like Fcons (Qnil, Qnil), but json.c treats any
      cons cell as error data, so use an uninterned symbol instead.  */
   Qcatch_all_memory_full
-    = Fmake_symbol (build_pure_c_string ("catch-all-memory-full"));
+    = Fmake_symbol (build_string ("catch-all-memory-full"));
 
   defsubr (&Sor);
   defsubr (&Sand);
diff --git a/src/fileio.c b/src/fileio.c
index 37072d9b6b..6619801a08 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6274,29 +6274,29 @@ syms_of_fileio (void)
   DEFSYM (Qcar_less_than_car, "car-less-than-car");
 
   Fput (Qfile_error, Qerror_conditions,
-	Fpurecopy (list2 (Qfile_error, Qerror)));
+	list2 (Qfile_error, Qerror));
   Fput (Qfile_error, Qerror_message,
-	build_pure_c_string ("File error"));
+	build_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
+	list3 (Qfile_already_exists, Qfile_error, Qerror));
   Fput (Qfile_already_exists, Qerror_message,
-	build_pure_c_string ("File already exists"));
+	build_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
+	list3 (Qfile_date_error, Qfile_error, Qerror));
   Fput (Qfile_date_error, Qerror_message,
-	build_pure_c_string ("Cannot set file date"));
+	build_string ("Cannot set file date"));
 
   Fput (Qfile_missing, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_missing, Qfile_error, Qerror)));
+	list3 (Qfile_missing, Qfile_error, Qerror));
   Fput (Qfile_missing, Qerror_message,
-	build_pure_c_string ("File is missing"));
+	build_string ("File is missing"));
 
   Fput (Qfile_notify_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_notify_error, Qfile_error, Qerror)));
+	list3 (Qfile_notify_error, Qfile_error, Qerror));
   Fput (Qfile_notify_error, Qerror_message,
-	build_pure_c_string ("File notification error"));
+	build_string ("File notification error"));
 
   DEFVAR_LISP ("file-name-handler-alist", Vfile_name_handler_alist,
 	       doc: /* Alist of elements (REGEXP . HANDLER) for file names handled specially.
diff --git a/src/fns.c b/src/fns.c
index a3b8d6ef57..64b29a542f 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -36,7 +36,6 @@ Copyright (C) 1985-1987, 1993-1995, 1997-2020 Free Software Foundation,
 #include "buffer.h"
 #include "intervals.h"
 #include "window.h"
-#include "puresize.h"
 #include "gnutls.h"
 
 static void sort_vector_copy (Lisp_Object, ptrdiff_t,
@@ -2527,7 +2526,6 @@ DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
       size = SCHARS (array);
       if (size != 0)
 	{
-	  CHECK_IMPURE (array, XSTRING (array));
 	  unsigned char str[MAX_MULTIBYTE_LENGTH];
 	  int len;
 	  if (STRING_MULTIBYTE (array))
@@ -2569,7 +2567,6 @@ DEFUN ("clear-string", Fclear_string, Sclear_string,
   ptrdiff_t len = SBYTES (string);
   if (len != 0 || STRING_MULTIBYTE (string))
     {
-      CHECK_IMPURE (string, XSTRING (string));
       memset (SDATA (string), 0, len);
       STRING_SET_CHARS (string, len);
       STRING_SET_UNIBYTE (string);
@@ -4101,16 +4098,12 @@ hash_index_size (struct Lisp_Hash_Table *h, ptrdiff_t size)
    size exceeds REHASH_THRESHOLD.
 
    WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value', `key-or-value', or `key-and-value'.
-
-   If PURECOPY is non-nil, the table can be copied to pure storage via
-   `purecopy' when Emacs is being dumped. Such tables can no longer be
-   changed after purecopy.  */
+   one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
 
 Lisp_Object
 make_hash_table (struct hash_table_test test, EMACS_INT size,
 		 float rehash_size, float rehash_threshold,
-		 Lisp_Object weak, bool purecopy)
+		 Lisp_Object weak)
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
@@ -4139,7 +4132,6 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
   h->next = make_vector (size, make_fixnum (-1));
   h->index = make_vector (hash_index_size (h, size), make_fixnum (-1));
   h->next_weak = NULL;
-  h->purecopy = purecopy;
   h->mutable = true;
 
   /* Set up the free list.  */
@@ -4240,11 +4232,6 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
 	    set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
 	    set_hash_index_slot (h, start_of_bucket, i);
 	  }
-
-#ifdef ENABLE_CHECKING
-      if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h)
-	message ("Growing hash table to: %"pD"d", next_size);
-#endif
     }
 }
 
@@ -4307,7 +4294,6 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h)
 {
   if (!h->mutable)
     signal_error ("hash table test modifies table", obj);
-  eassert (!PURE_P (h));
 }
 
 /* Put an entry into hash table H that associates KEY with VALUE.
@@ -4784,16 +4770,10 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
 WEAK.  WEAK t is equivalent to `key-and-value'.  Default value of WEAK
 is nil.
 
-:purecopy PURECOPY -- If PURECOPY is non-nil, the table can be copied
-to pure storage when Emacs is being dumped, making the contents of the
-table read only. Any further changes to purified tables will result
-in an error.
-
 usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object test, weak;
-  bool purecopy;
   struct hash_table_test testdesc;
   ptrdiff_t i;
   USE_SAFE_ALLOCA;
@@ -4827,9 +4807,8 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       testdesc.cmpfn = cmpfn_user_defined;
     }
 
-  /* See if there's a `:purecopy PURECOPY' argument.  */
-  i = get_key_arg (QCpurecopy, nargs, args, used);
-  purecopy = i && !NILP (args[i]);
+  /* Ignore a `:purecopy PURECOPY' argument.  */
+  get_key_arg (QCpurecopy, nargs, args, used);
   /* See if there's a `:size SIZE' argument.  */
   i = get_key_arg (QCsize, nargs, args, used);
   Lisp_Object size_arg = i ? args[i] : Qnil;
@@ -4879,8 +4858,7 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       signal_error ("Invalid argument list", args[i]);
 
   SAFE_FREE ();
-  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak,
-			  purecopy);
+  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
 }
 
 
diff --git a/src/fontset.c b/src/fontset.c
index 8c86075c07..92c7268c38 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -2129,7 +2129,7 @@ syms_of_fontset (void)
   set_fontset_id (Vdefault_fontset, make_fixnum (0));
   set_fontset_name
     (Vdefault_fontset,
-     build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
+     build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
   ASET (Vfontset_table, 0, Vdefault_fontset);
   next_fontset_id = 1;
   PDUMPER_REMEMBER_SCALAR (next_fontset_id);
@@ -2187,7 +2187,7 @@ syms_of_fontset (void)
 	       doc: /* Alist of fontset names vs the aliases.  */);
   Vfontset_alias_alist
     = list1 (Fcons (FONTSET_NAME (Vdefault_fontset),
-		    build_pure_c_string ("fontset-default")));
+		    build_string ("fontset-default")));
 
   DEFVAR_LISP ("vertical-centering-font-regexp",
 	       Vvertical_centering_font_regexp,
diff --git a/src/frame.c b/src/frame.c
index c4dfc35a0c..c8cd094c97 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1107,7 +1107,7 @@ make_initial_frame (void)
   Vframe_list = Fcons (frame, Vframe_list);
 
   tty_frame_count = 1;
-  fset_name (f, build_pure_c_string ("F1"));
+  fset_name (f, build_string ("F1"));
 
   SET_FRAME_VISIBLE (f, 1);
 
diff --git a/src/image.c b/src/image.c
index 123de54ba2..a44c09836e 100644
--- a/src/image.c
+++ b/src/image.c
@@ -4708,7 +4708,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			  DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			  Qnil, false);
+			  Qnil);
 }
 
 static void
diff --git a/src/intervals.c b/src/intervals.c
index 0257591a14..e01689fe61 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -44,7 +44,6 @@
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "puresize.h"
 #include "keymap.h"
 
 /* Test for membership, allowing for t (actually any non-cons) to mean the
@@ -101,7 +100,6 @@ create_root_interval (Lisp_Object parent)
     }
   else
     {
-      CHECK_IMPURE (parent, XSTRING (parent));
       new->total_length = SCHARS (parent);
       eassert (TOTAL_LENGTH (new) >= 0);
       set_string_intervals (parent, new);
diff --git a/src/json.c b/src/json.c
index 8c9583631a..3393d2b4a2 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1109,8 +1109,8 @@ define_error (Lisp_Object name, const char *message, Lisp_Object parent)
   eassert (CONSP (parent_conditions));
   eassert (!NILP (Fmemq (parent, parent_conditions)));
   eassert (NILP (Fmemq (name, parent_conditions)));
-  Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
-  Fput (name, Qerror_message, build_pure_c_string (message));
+  Fput (name, Qerror_conditions, Fcons (name, parent_conditions));
+  Fput (name, Qerror_message, build_string (message));
 }
 
 void
diff --git a/src/keyboard.c b/src/keyboard.c
index 5fa58abce1..bada67c519 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1106,8 +1106,6 @@ top_level_1 (Lisp_Object ignore)
   /* On entry to the outer level, run the startup file.  */
   if (!NILP (Vtop_level))
     internal_condition_case (top_level_2, Qerror, cmd_error);
-  else if (!NILP (Vpurify_flag))
-    message1 ("Bare impure Emacs (standard Lisp code not loaded)");
   else
     message1 ("Bare Emacs (standard Lisp code not loaded)");
   return Qnil;
@@ -11465,14 +11463,14 @@ syms_of_keyboard (void)
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
-  Vlispy_mouse_stem = build_pure_c_string ("mouse");
+  Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
-  regular_top_level_message = build_pure_c_string ("Back to top level");
+  regular_top_level_message = build_string ("Back to top level");
   staticpro (&regular_top_level_message);
 #ifdef HAVE_STACK_OVERFLOW_HANDLING
   recover_top_level_message
-    = build_pure_c_string ("Re-entering top level after C stack overflow");
+    = build_string ("Re-entering top level after C stack overflow");
   staticpro (&recover_top_level_message);
 #endif
   DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
diff --git a/src/keymap.c b/src/keymap.c
index d98b27b7a1..67e9b8a6d2 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -50,7 +50,6 @@
 #include "keyboard.h"
 #include "termhooks.h"
 #include "blockinput.h"
-#include "puresize.h"
 #include "intervals.h"
 #include "keymap.h"
 #include "window.h"
@@ -138,8 +137,6 @@ DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 1, 0,
 {
   if (!NILP (string))
     {
-      if (!NILP (Vpurify_flag))
-	string = Fpurecopy (string);
       return list2 (Qkeymap, string);
     }
   return list1 (Qkeymap);
@@ -336,7 +333,6 @@ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
 	 If we came to the end, add the parent in PREV.  */
       if (!CONSP (list) || KEYMAPP (list))
 	{
-	  CHECK_IMPURE (prev, XCONS (prev));
 	  XSETCDR (prev, parent);
 	  return parent;
 	}
@@ -757,7 +753,7 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 
   /* If we are preparing to dump, and DEF is a menu element
      with a menu item indicator, copy it to ensure it is not pure.  */
-  if (CONSP (def) && PURE_P (XCONS (def))
+  if (CONSP (def)
       && (EQ (XCAR (def), Qmenu_item) || STRINGP (XCAR (def))))
     def = Fcons (XCAR (def), XCDR (def));
 
@@ -805,7 +801,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	  {
 	    if (FIXNATP (idx) && XFIXNAT (idx) < ASIZE (elt))
 	      {
-		CHECK_IMPURE (elt, XVECTOR (elt));
 		ASET (elt, XFIXNAT (idx), def);
 		return def;
 	      }
@@ -858,7 +853,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	      }
 	    else if (EQ (idx, XCAR (elt)))
 	      {
-		CHECK_IMPURE (elt, XCONS (elt));
 		XSETCDR (elt, def);
 		return def;
 	      }
@@ -904,7 +898,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	}
       else
 	elt = Fcons (idx, def);
-      CHECK_IMPURE (insertion_point, XCONS (insertion_point));
       XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
     }
   }
@@ -3598,12 +3591,12 @@ syms_of_keymap (void)
   Fset (intern_c_string ("ctl-x-map"), control_x_map);
   Ffset (intern_c_string ("Control-X-prefix"), control_x_map);
 
-  exclude_keys = pure_list
-    (pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")),
-     pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")),
-     pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")),
-     pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")),
-     pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" ")));
+  exclude_keys = list
+    (Fcons (build_string ("DEL"), build_string ("\\d")),
+     Fcons (build_string ("TAB"), build_string ("\\t")),
+     Fcons (build_string ("RET"), build_string ("\\r")),
+     Fcons (build_string ("ESC"), build_string ("\\e")),
+     Fcons (build_string ("SPC"), build_string (" ")));
   staticpro (&exclude_keys);
 
   DEFVAR_LISP ("define-key-rebound-commands", Vdefine_key_rebound_commands,
@@ -3659,13 +3652,12 @@ syms_of_keymap (void)
   DEFSYM (Qmode_line, "mode-line");
 
   staticpro (&Vmouse_events);
-  Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar,
-			     Qtab_line, Qheader_line, Qmode_line,
-			     intern_c_string ("mouse-1"),
-			     intern_c_string ("mouse-2"),
-			     intern_c_string ("mouse-3"),
-			     intern_c_string ("mouse-4"),
-			     intern_c_string ("mouse-5"));
+  Vmouse_events = list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
+			intern_c_string ("mouse-1"),
+			intern_c_string ("mouse-2"),
+			intern_c_string ("mouse-3"),
+			intern_c_string ("mouse-4"),
+			intern_c_string ("mouse-5"));
 
   /* Keymap used for minibuffers when doing completion.  */
   /* Keymap used for minibuffers when doing completion and require a match.  */
diff --git a/src/lisp.h b/src/lisp.h
index 7983339ac5..59d086cd65 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -834,9 +834,6 @@ #define XUNTAG(a, type, ctype) ((ctype *) \
 	 special (with `defvar' etc), and shouldn't be lexically bound.  */
       bool_bf declared_special : 1;
 
-      /* True if pointed to from purespace and hence can't be GC'd.  */
-      bool_bf pinned : 1;
-
       /* The symbol's name, as a Lisp string.  */
       Lisp_Object name;
 
@@ -1545,20 +1542,14 @@ #define STRING_BYTES_BOUND  \
 /* Mark STR as a unibyte string.  */
 #define STRING_SET_UNIBYTE(STR)				\
   do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_unibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = -1;		\
+    XSTRING (STR)->u.s.size_byte = -1;			\
   } while (false)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
-#define STRING_SET_MULTIBYTE(STR)			\
-  do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_multibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
+#define STRING_SET_MULTIBYTE(STR)				\
+  do {								\
+    XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size;	\
   } while (false)
 
 /* Convenience functions for dealing with Lisp strings.  */
@@ -2311,12 +2302,8 @@ #define DEFSYM(sym, name) /* empty */
   /* Index of first free entry in free list, or -1 if none.  */
   ptrdiff_t next_free;
 
-  /* True if the table can be purecopied.  The table cannot be
-     changed afterwards.  */
-  bool purecopy;
-
   /* True if the table is mutable.  Ordinarily tables are mutable, but
-     pure tables are not, and while a table is being mutated it is
+     some tables are not, and while a table is being mutated it is
      immutable for recursive attempts to mutate it.  */
   bool mutable;
 
@@ -3606,7 +3593,7 @@ #define CONS_TO_INTEGER(cons, type, var)				\
 Lisp_Object hashfn_equal (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
-                             Lisp_Object, bool);
+                             Lisp_Object);
 ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object *);
 ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
 		    Lisp_Object);
@@ -3760,7 +3747,6 @@ verify (FLT_RADIX == 2 || FLT_RADIX == 16);
 
 /* Defined in alloc.c.  */
 extern void *my_heap_start (void);
-extern void check_pure_size (void);
 unsigned char *resize_string_data (Lisp_Object, ptrdiff_t, int, int);
 extern void malloc_warning (const char *);
 extern AVOID memory_full (size_t);
@@ -3817,11 +3803,8 @@ flush_stack_call_func (void (*func) (void *arg), void *arg)
 extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
 			  Lisp_Object);
 extern Lisp_Object listn (ptrdiff_t, Lisp_Object, ...);
-extern Lisp_Object pure_listn (ptrdiff_t, Lisp_Object, ...);
 #define list(...) \
   listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
-#define pure_list(...) \
-  pure_listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
 
 enum gc_root_type
 {
@@ -3894,17 +3877,6 @@ build_unibyte_string (const char *str)
 extern Lisp_Object make_string_from_bytes (const char *, ptrdiff_t, ptrdiff_t);
 extern Lisp_Object make_specified_string (const char *,
 					  ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_string (const char *, ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_c_string (const char *, ptrdiff_t);
-
-/* Make a string allocated in pure space, use STR as string data.  */
-
-INLINE Lisp_Object
-build_pure_c_string (const char *str)
-{
-  return make_pure_c_string (str, strlen (str));
-}
-
 /* Make a string from the data at STR, treating it as multibyte if the
    data warrants.  */
 
@@ -3914,7 +3886,6 @@ build_string (const char *str)
   return make_string (str, strlen (str));
 }
 
-extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
 extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
 extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
 
diff --git a/src/lread.c b/src/lread.c
index 8064bf4d0e..a5cb877034 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2042,13 +2042,13 @@ readevalloop (Lisp_Object readcharfun,
 	read_objects_map
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (! HASH_TABLE_P (read_objects_completed)
 	  || XHASH_TABLE (read_objects_completed)->count)
 	read_objects_completed
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (!NILP (Vpurify_flag) && c == '(')
 	{
 	  val = read_list (0, readcharfun);
@@ -2265,12 +2265,12 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
       || XHASH_TABLE (read_objects_map)->count)
     read_objects_map
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (! HASH_TABLE_P (read_objects_completed)
       || XHASH_TABLE (read_objects_completed)->count)
     read_objects_completed
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (EQ (Vread_with_symbol_positions, Qt)
       || EQ (Vread_with_symbol_positions, stream))
     Vread_symbol_positions_list = Qnil;
@@ -2840,11 +2840,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      if (!NILP (params[param_count + 1]))
 		param_count += 2;
 
-              params[param_count] = QCpurecopy;
-              params[param_count + 1] = Fplist_get (tmp, Qpurecopy);
-              if (!NILP (params[param_count + 1]))
-                param_count += 2;
-
 	      /* This is the hash table data.  */
 	      data = Fplist_get (tmp, Qdata);
 
@@ -3154,13 +3149,13 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      /* No symbol character follows, this is the empty
 		 symbol.  */
 	      UNREAD (c);
-	      return Fmake_symbol (empty_unibyte_string);
+	      return Fmake_symbol (build_string (""));
 	    }
 	  goto read_symbol;
 	}
       /* ## is the empty symbol.  */
       if (c == '#')
-	return Fintern (empty_unibyte_string, Qnil);
+	return Fintern (build_string (""), Qnil);
 
       if (c >= '0' && c <= '9')
 	{
@@ -3556,9 +3551,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	  if (uninterned_symbol)
 	    {
 	      Lisp_Object name
-		= ((! NILP (Vpurify_flag)
-		    ? make_pure_string : make_specified_string)
-		   (read_buffer, nchars, nbytes, multibyte));
+		= make_specified_string (read_buffer, nchars, nbytes,
+					 multibyte);
 	      result = Fmake_symbol (name);
 	    }
 	  else
@@ -4145,10 +4139,8 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 
   if (!SYMBOLP (tem))
     {
-      /* Creating a non-pure string from a string literal not implemented yet.
-	 We could just use make_string here and live with the extra copy.  */
       eassert (!NILP (Vpurify_flag));
-      tem = intern_driver (make_pure_c_string (str, len), obarray, tem);
+      tem = intern_driver (make_string (str, len), obarray, tem);
     }
   return tem;
 }
@@ -4157,7 +4149,7 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 define_symbol (Lisp_Object sym, char const *str)
 {
   ptrdiff_t len = strlen (str);
-  Lisp_Object string = make_pure_c_string (str, len);
+  Lisp_Object string = make_string (str, len);
   init_symbol (sym, string);
 
   /* Qunbound is uninterned, so that it's not confused with any symbol
@@ -4184,8 +4176,7 @@ DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
 
   tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
   if (!SYMBOLP (tem))
-    tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
-			 obarray, tem);
+    tem = intern_driver (string, obarray, tem);
   return tem;
 }
 
@@ -4833,23 +4824,23 @@ syms_of_lread (void)
 to the specified file name if a suffix is allowed or required.  */);
 #ifdef HAVE_MODULES
 #ifdef MODULES_SECONDARY_SUFFIX
-  Vload_suffixes = list4 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX),
-                          build_pure_c_string (MODULES_SECONDARY_SUFFIX));
+  Vload_suffixes = list4 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX),
+                          build_string (MODULES_SECONDARY_SUFFIX));
 #else
-  Vload_suffixes = list3 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX));
+  Vload_suffixes = list3 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX));
 #endif
 #else
-  Vload_suffixes = list2 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"));
+  Vload_suffixes = list2 (build_string (".elc"),
+			  build_string (".el"));
 #endif
   DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
 	       doc: /* Suffix of loadable module file, or nil if modules are not supported.  */);
 #ifdef HAVE_MODULES
-  Vmodule_file_suffix = build_pure_c_string (MODULES_SUFFIX);
+  Vmodule_file_suffix = build_string (MODULES_SUFFIX);
 #else
   Vmodule_file_suffix = Qnil;
 #endif
@@ -4992,7 +4983,7 @@ syms_of_lread (void)
 When the regular expression matches, the file is considered to be safe
 to load.  */);
   Vbytecomp_version_regexp
-    = build_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
   DEFSYM (Qlexical_binding, "lexical-binding");
   DEFVAR_LISP ("lexical-binding", Vlexical_binding,
diff --git a/src/pdumper.c b/src/pdumper.c
index 217ffa6783..2543fe92c7 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2440,7 +2440,6 @@ dump_symbol (struct dump_context *ctx,
   DUMP_FIELD_COPY (&out, symbol, u.s.trapped_write);
   DUMP_FIELD_COPY (&out, symbol, u.s.interned);
   DUMP_FIELD_COPY (&out, symbol, u.s.declared_special);
-  DUMP_FIELD_COPY (&out, symbol, u.s.pinned);
   dump_field_lv (ctx, &out, symbol, &symbol->u.s.name, WEIGHT_STRONG);
   switch (symbol->u.s.redirect)
     {
@@ -2673,7 +2672,6 @@ dump_hash_table (struct dump_context *ctx,
      them as close to the hash table as possible.  */
   DUMP_FIELD_COPY (out, hash, count);
   DUMP_FIELD_COPY (out, hash, next_free);
-  DUMP_FIELD_COPY (out, hash, purecopy);
   DUMP_FIELD_COPY (out, hash, mutable);
   DUMP_FIELD_COPY (out, hash, rehash_threshold);
   DUMP_FIELD_COPY (out, hash, rehash_size);
@@ -5466,8 +5464,6 @@ DEFUN ("pdumper-stats", Fpdumper_stats, Spdumper_stats, 0, 0, 0,
 		Fcons (Qdump_file_name, dump_fn));
 }
 
-#endif /* HAVE_PDUMPER */
-
 \f
 static void
 thaw_hash_tables (void)
@@ -5482,6 +5478,7 @@ init_pdumper_once (void)
 {
   pdumper_do_now_and_after_load (thaw_hash_tables);
 }
+#endif /* HAVE_PDUMPER */
 
 void
 syms_of_pdumper (void)
diff --git a/src/print.c b/src/print.c
index bd1769144e..1da1c4a1a4 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1580,12 +1580,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 	print_object (Fhash_table_rehash_threshold (obj),
 		      printcharfun, escapeflag);
 
-	if (h->purecopy)
-	  {
-	    print_c_string (" purecopy ", printcharfun);
-	    print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
-	  }
-
 	print_c_string (" data ", printcharfun);
 
 	/* Print the data here as a plist. */
diff --git a/src/process.c b/src/process.c
index 3aa105ae34..9fb62be6d5 100644
--- a/src/process.c
+++ b/src/process.c
@@ -8514,7 +8514,7 @@ syms_of_process (void)
    const struct socket_options *sopt;
 
 #define ADD_SUBFEATURE(key, val) \
-  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
+  subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures)
 
    ADD_SUBFEATURE (QCnowait, Qt);
 #ifdef DATAGRAM_SOCKETS
@@ -8536,7 +8536,7 @@ #define ADD_SUBFEATURE(key, val) \
    ADD_SUBFEATURE (QCserver, Qt);
 
    for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
+     subfeatures = Fcons (intern_c_string (sopt->name), subfeatures);
 
    Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
diff --git a/src/profiler.c b/src/profiler.c
index 9d2e828f22..3e61ade433 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -63,7 +63,7 @@ make_log (void)
   Lisp_Object log = make_hash_table (hashtest_profiler, heap_size,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
   struct Lisp_Hash_Table *h = XHASH_TABLE (log);
 
   /* What is special about our hash-tables is that the values are pre-filled
diff --git a/src/puresize.h b/src/puresize.h
index 7611f6e53f..e69de29bb2 100644
--- a/src/puresize.h
+++ b/src/puresize.h
@@ -1,115 +0,0 @@
-/* How much read-only Lisp storage a dumped Emacs needs.
-   Copyright (C) 1993, 2001-2020 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
-
-#ifndef EMACS_PURESIZE_H
-#define EMACS_PURESIZE_H
-
-#include "lisp.h"
-
-INLINE_HEADER_BEGIN
-
-/* Define PURESIZE, the number of bytes of pure Lisp code to leave space for.
-
-   At one point, this was defined in config.h, meaning that changing
-   PURESIZE would make Make recompile all of Emacs.  But only a few
-   files actually use PURESIZE, so we split it out to its own .h file.
-
-   Make sure to include this file after config.h, since that tells us
-   whether we are running X windows, which tells us how much pure
-   storage to allocate.  */
-
-/* First define a measure of the amount of data we have.  */
-
-/* A system configuration file may set this to request a certain extra
-   amount of storage.  This is a lot more update-robust that defining
-   BASE_PURESIZE or even PURESIZE directly.  */
-#ifndef SYSTEM_PURESIZE_EXTRA
-#define SYSTEM_PURESIZE_EXTRA 0
-#endif
-
-#ifndef SITELOAD_PURESIZE_EXTRA
-#define SITELOAD_PURESIZE_EXTRA 0
-#endif
-
-#ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA)
-#endif
-
-/* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
-#ifndef PURESIZE_RATIO
-#if EMACS_INT_MAX >> 31 != 0
-#if PTRDIFF_MAX >> 31 != 0
-#define PURESIZE_RATIO 10 / 6	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_RATIO 8 / 6	/* Don't surround with `()'.  */
-#endif
-#else
-#define PURESIZE_RATIO 1
-#endif
-#endif
-
-#ifdef ENABLE_CHECKING
-/* ENABLE_CHECKING somehow increases the purespace used, probably because
-   it tends to cause some macro arguments to be evaluated twice.  This is
-   a bug, but it's difficult to track it down.  */
-#define PURESIZE_CHECKING_RATIO 12 / 10	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_CHECKING_RATIO 1
-#endif
-
-/* This is the actual size in bytes to allocate.  */
-#ifndef PURESIZE
-#define PURESIZE  (BASE_PURESIZE * PURESIZE_RATIO * PURESIZE_CHECKING_RATIO)
-#endif
-
-extern AVOID pure_write_error (Lisp_Object);
-
-extern EMACS_INT pure[];
-
-/* The puresize_h_* macros are private to this include file.  */
-
-/* True if PTR is pure.  */
-
-#define puresize_h_PURE_P(ptr) \
-  ((uintptr_t) (ptr) - (uintptr_t) pure <= PURESIZE)
-
-INLINE bool
-PURE_P (void *ptr)
-{
-  return puresize_h_PURE_P (ptr);
-}
-
-/* Signal an error if OBJ is pure.  PTR is OBJ untagged.  */
-
-#define puresize_h_CHECK_IMPURE(obj, ptr) \
-  (PURE_P (ptr) ? pure_write_error (obj) : (void) 0)
-
-INLINE void
-CHECK_IMPURE (Lisp_Object obj, void *ptr)
-{
-  puresize_h_CHECK_IMPURE (obj, ptr);
-}
-
-#if DEFINE_KEY_OPS_AS_MACROS
-# define PURE_P(ptr) puresize_h_PURE_P (ptr)
-# define CHECK_IMPURE(obj, ptr) puresize_h_CHECK_IMPURE (obj, ptr)
-#endif
-
-INLINE_HEADER_END
-
-#endif /* EMACS_PURESIZE_H */
diff --git a/src/search.c b/src/search.c
index 6fb3716cd4..023d41236c 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3337,19 +3337,19 @@ syms_of_search (void)
   DEFSYM (Qinvalid_regexp, "invalid-regexp");
 
   Fput (Qsearch_failed, Qerror_conditions,
-	pure_list (Qsearch_failed, Qerror));
+	list (Qsearch_failed, Qerror));
   Fput (Qsearch_failed, Qerror_message,
-	build_pure_c_string ("Search failed"));
+	build_string ("Search failed"));
 
   Fput (Quser_search_failed, Qerror_conditions,
-	pure_list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
+	list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
   Fput (Quser_search_failed, Qerror_message,
-        build_pure_c_string ("Search failed"));
+        build_string ("Search failed"));
 
   Fput (Qinvalid_regexp, Qerror_conditions,
-	pure_list (Qinvalid_regexp, Qerror));
+	list (Qinvalid_regexp, Qerror));
   Fput (Qinvalid_regexp, Qerror_message,
-	build_pure_c_string ("Invalid regexp"));
+	build_string ("Invalid regexp"));
 
   re_match_object = Qnil;
   staticpro (&re_match_object);
diff --git a/src/syntax.c b/src/syntax.c
index 9f77ea5f9b..20390b2474 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3709,9 +3709,9 @@ syms_of_syntax (void)
 
   DEFSYM (Qscan_error, "scan-error");
   Fput (Qscan_error, Qerror_conditions,
-	pure_list (Qscan_error, Qerror));
+	list (Qscan_error, Qerror));
   Fput (Qscan_error, Qerror_message,
-	build_pure_c_string ("Scan error"));
+	build_string ("Scan error"));
 
   DEFVAR_BOOL ("parse-sexp-ignore-comments", parse_sexp_ignore_comments,
 	       doc: /* Non-nil means `forward-sexp', etc., should treat comments as whitespace.  */);
diff --git a/src/w32fns.c b/src/w32fns.c
index ab864332e7..f2d102aa33 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10317,9 +10317,9 @@ syms_of_w32fns (void)
   DEFSYM (Qjson, "json");
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   staticpro (&w32_grabbed_keys);
   w32_grabbed_keys = Qnil;
diff --git a/src/xdisp.c b/src/xdisp.c
index ad03ac4605..10df3b777e 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -34508,7 +34508,7 @@ syms_of_xdisp (void)
   staticpro (&echo_area_buffer[0]);
   staticpro (&echo_area_buffer[1]);
 
-  Vmessages_buffer_name = build_pure_c_string ("*Messages*");
+  Vmessages_buffer_name = build_string ("*Messages*");
   staticpro (&Vmessages_buffer_name);
 
   mode_line_proptrans_alist = Qnil;
@@ -34591,7 +34591,7 @@ syms_of_xdisp (void)
   DEFVAR_LISP ("overlay-arrow-string", Voverlay_arrow_string,
     doc: /* String to display as an arrow in non-window frames.
 See also `overlay-arrow-position'.  */);
-  Voverlay_arrow_string = build_pure_c_string ("=>");
+  Voverlay_arrow_string = build_string ("=>");
 
   DEFVAR_LISP ("overlay-arrow-variable-list", Voverlay_arrow_variable_list,
     doc: /* List of variables (symbols) which hold markers for overlay arrows.
@@ -34699,18 +34699,18 @@ syms_of_xdisp (void)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
 \(see `modify-frame-parameters').  */);
-  /* Do not nest calls to pure_list.  This works around a bug in
+  /* Do not nest calls to list.  This works around a bug in
      Oracle Developer Studio 12.6.  */
   Lisp_Object icon_title_name_format
-    = pure_list (empty_unibyte_string,
-		 intern_c_string ("invocation-name"),
-		 build_pure_c_string ("@"),
-		 intern_c_string ("system-name"));
+    = list (empty_unibyte_string,
+	    intern_c_string ("invocation-name"),
+	    build_string ("@"),
+	    intern_c_string ("system-name"));
   Vicon_title_format
     = Vframe_title_format
-    = pure_list (intern_c_string ("multiple-frames"),
-		 build_pure_c_string ("%b"),
-		 icon_title_name_format);
+    = list (intern_c_string ("multiple-frames"),
+	    build_string ("%b"),
+	    icon_title_name_format);
 
   DEFVAR_LISP ("message-log-max", Vmessage_log_max,
     doc: /* Maximum number of lines to keep in the message log buffer.
diff --git a/src/xfaces.c b/src/xfaces.c
index 06d2f994de..d2c4a904fa 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -7024,7 +7024,7 @@ syms_of_xfaces (void)
 This stipple pattern is used on monochrome displays
 instead of shades of gray for a face background color.
 See `set-face-stipple' for possible values for this variable.  */);
-  Vface_default_stipple = build_pure_c_string ("gray3");
+  Vface_default_stipple = build_string ("gray3");
 
   DEFVAR_LISP ("tty-defined-color-alist", Vtty_defined_color_alist,
    doc: /* An alist of defined terminal colors and their RGB values.
diff --git a/src/xfns.c b/src/xfns.c
index 78f977bf0a..cda96b4f97 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -7850,9 +7850,9 @@ syms_of_xfns (void)
 #endif
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
     doc: /* The shape of the pointer when over text.
@@ -8063,7 +8063,7 @@ syms_of_xfns (void)
     char gtk_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
     int len = sprintf (gtk_version, "%d.%d.%d",
 		       GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
-    Vgtk_version_string = make_pure_string (gtk_version, len, len, false);
+    Vgtk_version_string = make_specified_string (gtk_version, len, len, false);
   }
 #endif /* USE_GTK */
 
@@ -8077,7 +8077,8 @@ syms_of_xfns (void)
     int len = sprintf (cairo_version, "%d.%d.%d",
 		       CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
                        CAIRO_VERSION_MICRO);
-    Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+    Vcairo_version_string = make_specified_string (cairo_version, len, len,
+						   false);
   }
 #endif
 
diff --git a/src/xterm.c b/src/xterm.c
index 2e0407aff4..8eade7e8c8 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13623,7 +13623,7 @@ syms_of_xterm (void)
   DEFSYM (Qlatin_1, "latin-1");
 
 #ifdef USE_GTK
-  xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
+  xg_default_icon_file = build_string ("icons/hicolor/scalable/apps/emacs.svg");
   staticpro (&xg_default_icon_file);
 
   DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
@@ -13744,7 +13744,7 @@ syms_of_xterm (void)
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
 
   DEFVAR_BOOL ("x-frame-normalize-before-maximize",
 	       x_frame_normalize_before_maximize,
-- 
2.28.0


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-22  8:55                                     ` Pip Cet
@ 2020-08-22  9:59                                       ` Andreas Schwab
  2020-08-28 12:32                                         ` Pip Cet
  2020-08-22 17:36                                       ` Paul Eggert
  1 sibling, 1 reply; 125+ messages in thread
From: Andreas Schwab @ 2020-08-22  9:59 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, eggert, larsi

On Aug 22 2020, Pip Cet wrote:

> +purecopy (Lisp_Object obj);
>  
>  DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
>         doc: /* Make a copy of object OBJ in pure storage.

Perhaps purecopy should be dropped or made a no-op?

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-22  8:55                                     ` Pip Cet
  2020-08-22  9:59                                       ` Andreas Schwab
@ 2020-08-22 17:36                                       ` Paul Eggert
  1 sibling, 0 replies; 125+ messages in thread
From: Paul Eggert @ 2020-08-22 17:36 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, larsi

On 8/22/20 1:55 AM, Pip Cet wrote:
> it appears like unexec builds are currently broken on master

At this point any effort to keep unexec builds working is wasted effort, except 
perhaps as an exercise in nostalgia.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-22  9:59                                       ` Andreas Schwab
@ 2020-08-28 12:32                                         ` Pip Cet
  2020-08-28 14:24                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2020-11-15 15:19                                           ` Stefan Kangas
  0 siblings, 2 replies; 125+ messages in thread
From: Pip Cet @ 2020-08-28 12:32 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: 36649, eggert, larsi, akrl

On Sat, Aug 22, 2020 at 9:59 AM Andreas Schwab <schwab@linux-m68k.org> wrote:
> On Aug 22 2020, Pip Cet wrote:
> > +purecopy (Lisp_Object obj);
> >
> >  DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
> >         doc: /* Make a copy of object OBJ in pure storage.
>
> Perhaps purecopy should be dropped or made a no-op?

I believe that would be a logical next step, yes. The comment in
loadup.el says hash-consing saves "around 11% of pure space", which
sounds like it isn't worth the hassle to me.

So my suggestion would be to apply this patch first (removing the C
parts of pure space), then remove unexec, then turn purecopy into an
alias for identity and remove as many instances of it as possible.

Just as a reminder, we're still putting a 3 MB block of zero bytes
into every emacs binary...

Should this be discussed on emacs-devel? I've CC'd Andrea since I
believe the native-comp branch interacts with pure space in
complicated ways.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-28 12:32                                         ` Pip Cet
@ 2020-08-28 14:24                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2020-11-15 15:19                                           ` Stefan Kangas
  1 sibling, 0 replies; 125+ messages in thread
From: Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2020-08-28 14:24 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, Eli Zaretskii, eggert, Andreas Schwab, larsi

Pip Cet <pipcet@gmail.com> writes:

> Should this be discussed on emacs-devel? I've CC'd Andrea since I
> believe the native-comp branch interacts with pure space in
> complicated ways.

Hi Pip,

thanks, as this gets into master I'll do the required modifications into
native-comp.  It should bring some simplification in.

Ciao

  Andrea





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-08-28 12:32                                         ` Pip Cet
  2020-08-28 14:24                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2020-11-15 15:19                                           ` Stefan Kangas
  2021-03-03 15:34                                             ` Pip Cet
  1 sibling, 1 reply; 125+ messages in thread
From: Stefan Kangas @ 2020-11-15 15:19 UTC (permalink / raw)
  To: Pip Cet, Andreas Schwab; +Cc: 36649, larsi, eggert, akrl

Pip Cet <pipcet@gmail.com> writes:

> On Sat, Aug 22, 2020 at 9:59 AM Andreas Schwab <schwab@linux-m68k.org> wrote:
>> On Aug 22 2020, Pip Cet wrote:
>> > +purecopy (Lisp_Object obj);
>> >
>> >  DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
>> >         doc: /* Make a copy of object OBJ in pure storage.
>>
>> Perhaps purecopy should be dropped or made a no-op?
>
> I believe that would be a logical next step, yes. The comment in
> loadup.el says hash-consing saves "around 11% of pure space", which
> sounds like it isn't worth the hassle to me.
>
> So my suggestion would be to apply this patch first (removing the C
> parts of pure space), then remove unexec, then turn purecopy into an
> alias for identity and remove as many instances of it as possible.
>
> Just as a reminder, we're still putting a 3 MB block of zero bytes
> into every emacs binary...

To me, the above sounds like a reasonable plan, given the discussion in
this thread and lack of any objections.

> Should this be discussed on emacs-devel?

Bringing this up on emacs-devel could perhaps get a few more eyes on
this before it lands on master.  At the very least, it would inform
everyone about the planned change.  So why not proceed to do that?





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2020-11-15 15:19                                           ` Stefan Kangas
@ 2021-03-03 15:34                                             ` Pip Cet
  2021-03-04 12:55                                               ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2021-03-03 15:34 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: 36649, larsi, eggert, Andreas Schwab, Andrea Corallo

[-- Attachment #1: Type: text/plain, Size: 1014 bytes --]

On Sun, Nov 15, 2020 at 3:19 PM Stefan Kangas <stefankangas@gmail.com> wrote:
> Pip Cet <pipcet@gmail.com> writes:
> > On Sat, Aug 22, 2020 at 9:59 AM Andreas Schwab <schwab@linux-m68k.org> wrote:
> >> On Aug 22 2020, Pip Cet wrote:
> >
> > So my suggestion would be to apply this patch first (removing the C
> > parts of pure space), then remove unexec, then turn purecopy into an
> > alias for identity and remove as many instances of it as possible.
> >
> > Just as a reminder, we're still putting a 3 MB block of zero bytes
> > into every emacs binary...
>
> To me, the above sounds like a reasonable plan, given the discussion in
> this thread and lack of any objections.

Thanks.

> > Should this be discussed on emacs-devel?
>
> Bringing this up on emacs-devel could perhaps get a few more eyes on
> this before it lands on master.  At the very least, it would inform
> everyone about the planned change.  So why not proceed to do that?

I have time for that now, so here's a revised patch as a first step.

[-- Attachment #2: 0001-Remove-pure-space-Bug-36649.patch --]
[-- Type: text/x-patch, Size: 87434 bytes --]

From 72fa919c7cc15f7c4f50c9006f08a773bf150311 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Wed, 3 Mar 2021 15:27:02 +0000
Subject: [PATCH] Remove pure space (Bug#36649)

* src/lisp.h (struct Lisp_Symbol): Remove `pinned' flag.
(build_pure_c_string, pure_listn): Remove.  All calls removed.
* src/puresize.h: Remove file.
* src/fns.c (Fmake_hash_table): Ignore `:purecopy' argument.
* src/doc.c (store_function_docstring): Remove comment about pure
space.
* src/data.c (pure_write_error): Remove.  All calls removed.
* src/conf_post.h (SYSTEM_PURESIZE_EXTRA): Remove.
* src/fns.c (make_hash_table): Drop `purecopy' argument.  All
callers changed to remove argument.
* src/alloc.c (make_pure_string, make_pure_c_string, pure_cons)
(pure_list): Remove.  All calls removed.
(check_pure_size): Remove.  All calls removed.
(cons_listn): Simplify.
(Fmake_byte_code): Remove comment about pure space.
(pointer_align): Move definition to avoid warning.
* src/Makefile.in: Remove comment about pure space.
---
 src/Makefile.in    |   2 -
 src/alloc.c        | 545 ++++-----------------------------------------
 src/buffer.c       |  16 +-
 src/callint.c      |   8 +-
 src/category.c     |   4 +-
 src/coding.c       |  18 +-
 src/conf_post.h    |  33 ---
 src/data.c         |  29 +--
 src/dbusbind.c     |   4 +-
 src/deps.mk        |  10 +-
 src/doc.c          |   3 -
 src/emacs-module.c |  28 +--
 src/emacs.c        |   5 +-
 src/eval.c         |  12 +-
 src/fileio.c       |  22 +-
 src/fns.c          |  32 +--
 src/fontset.c      |   4 +-
 src/frame.c        |   2 +-
 src/image.c        |   2 +-
 src/intervals.c    |   2 -
 src/json.c         |   4 +-
 src/keyboard.c     |   8 +-
 src/keymap.c       |  34 ++-
 src/lisp.h         |  41 +---
 src/lread.c        |  53 ++---
 src/pdumper.c      |   5 +-
 src/print.c        |   6 -
 src/process.c      |   4 +-
 src/profiler.c     |   2 +-
 src/puresize.h     | 115 ----------
 src/search.c       |  12 +-
 src/syntax.c       |   4 +-
 src/w32fns.c       |   4 +-
 src/xdisp.c        |  18 +-
 src/xfaces.c       |   2 +-
 src/xfns.c         |   9 +-
 src/xterm.c        |   4 +-
 37 files changed, 193 insertions(+), 913 deletions(-)
 delete mode 100644 src/puresize.h

diff --git a/src/Makefile.in b/src/Makefile.in
index 4100edf4712fe..0330b2d354b18 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -406,8 +406,6 @@ .c.o:
 .m.o:
 	$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
 
-## lastfile must follow all files whose initialized data areas should
-## be dumped as pure by dump-emacs.
 base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
 	charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \
 	$(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \
diff --git a/src/alloc.c b/src/alloc.c
index e72fc4c4332de..4fa07c7e5983f 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -34,7 +34,6 @@ Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2021 Free Software
 #include "bignum.h"
 #include "dispextern.h"
 #include "intervals.h"
-#include "puresize.h"
 #include "sheap.h"
 #include "sysstdio.h"
 #include "systime.h"
@@ -333,33 +332,6 @@ #define HI_THRESHOLD (EMACS_INT_MAX / 2)
 
 #define SPARE_MEMORY (1 << 14)
 
-/* Initialize it to a nonzero value to force it into data space
-   (rather than bss space).  That way unexec will remap it into text
-   space (pure), on some systems.  We have not implemented the
-   remapping on more recent systems because this is less important
-   nowadays than in the days of small memories and timesharing.  */
-
-EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,};
-#define PUREBEG (char *) pure
-
-/* Pointer to the pure area, and its size.  */
-
-static char *purebeg;
-static ptrdiff_t pure_size;
-
-/* Number of bytes of pure storage used before pure storage overflowed.
-   If this is non-zero, this implies that an overflow occurred.  */
-
-static ptrdiff_t pure_bytes_used_before_overflow;
-
-/* Index in pure at which next pure Lisp object will be allocated..  */
-
-static ptrdiff_t pure_bytes_used_lisp;
-
-/* Number of bytes allocated for non-Lisp objects in pure storage.  */
-
-static ptrdiff_t pure_bytes_used_non_lisp;
-
 /* If positive, garbage collection is inhibited.  Otherwise, zero.  */
 
 static intptr_t garbage_collection_inhibited;
@@ -434,7 +406,6 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
 static void unchain_finalizer (struct Lisp_Finalizer *);
 static void mark_terminals (void);
 static void gc_sweep (void);
-static Lisp_Object make_pure_vector (ptrdiff_t);
 static void mark_buffer (struct buffer *);
 
 #if !defined REL_ALLOC || defined SYSTEM_MALLOC || defined HYBRID_MALLOC
@@ -576,16 +547,6 @@ #define MEM_NIL &mem_z
 
 int staticidx;
 
-static void *pure_alloc (size_t, int);
-
-/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
-
-static void *
-pointer_align (void *ptr, int alignment)
-{
-  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
-}
-
 /* Extract the pointer hidden within O.  */
 
 static ATTRIBUTE_NO_SANITIZE_UNDEFINED void *
@@ -1075,6 +1036,15 @@ verify (POWER_OF_2 (BLOCK_ALIGN));
 # elif !defined HYBRID_MALLOC && defined HAVE_POSIX_MEMALIGN
 #  define USE_ALIGNED_ALLOC 1
 #  define aligned_alloc my_aligned_alloc /* Avoid collision with lisp.h.  */
+
+/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
+
+static void *
+pointer_align (void *ptr, int alignment)
+{
+  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
+}
+
 static void *
 aligned_alloc (size_t alignment, size_t size)
 {
@@ -1679,9 +1649,9 @@ #define GC_STRING_EXTRA GC_STRING_OVERRUN_COOKIE_SIZE
 static void
 init_strings (void)
 {
-  empty_unibyte_string = make_pure_string ("", 0, 0, 0);
+  empty_unibyte_string = make_specified_string ("", 0, 0, false);
   staticpro (&empty_unibyte_string);
-  empty_multibyte_string = make_pure_string ("", 0, 0, 1);
+  empty_multibyte_string = make_specified_string ("", 0, 0, true);
   staticpro (&empty_multibyte_string);
 }
 
@@ -1699,7 +1669,7 @@ string_bytes (struct Lisp_String *s)
   ptrdiff_t nbytes =
     (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
 
-  if (!PURE_P (s) && !pdumper_object_p (s) && s->u.s.data
+  if (!pdumper_object_p (s) && s->u.s.data
       && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
     emacs_abort ();
   return nbytes;
@@ -2415,7 +2385,7 @@ make_specified_string (const char *contents,
 {
   Lisp_Object val;
 
-  if (nchars < 0)
+  if (nchars <= 0)
     {
       if (multibyte)
 	nchars = multibyte_chars_in_text ((const unsigned char *) contents,
@@ -2469,8 +2439,6 @@ make_clear_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes, bool clearit)
 
   if (nchars < 0)
     emacs_abort ();
-  if (!nbytes)
-    return empty_multibyte_string;
 
   s = allocate_string ();
   s->u.s.intervals = NULL;
@@ -2751,17 +2719,16 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4,
 }
 
 /* Make a list of COUNT Lisp_Objects, where ARG is the first one.
-   Use CONS to construct the pairs.  AP has any remaining args.  */
+   AP has any remaining args.  */
 static Lisp_Object
-cons_listn (ptrdiff_t count, Lisp_Object arg,
-	    Lisp_Object (*cons) (Lisp_Object, Lisp_Object), va_list ap)
+cons_listn (ptrdiff_t count, Lisp_Object arg, va_list ap)
 {
   eassume (0 < count);
-  Lisp_Object val = cons (arg, Qnil);
+  Lisp_Object val = Fcons (arg, Qnil);
   Lisp_Object tail = val;
   for (ptrdiff_t i = 1; i < count; i++)
     {
-      Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil);
+      Lisp_Object elem = Fcons (va_arg (ap, Lisp_Object), Qnil);
       XSETCDR (tail, elem);
       tail = elem;
     }
@@ -2774,18 +2741,7 @@ listn (ptrdiff_t count, Lisp_Object arg1, ...)
 {
   va_list ap;
   va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, Fcons, ap);
-  va_end (ap);
-  return val;
-}
-
-/* Make a pure list of COUNT Lisp_Objects, where ARG1 is the first one.  */
-Lisp_Object
-pure_listn (ptrdiff_t count, Lisp_Object arg1, ...)
-{
-  va_list ap;
-  va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, pure_cons, ap);
+  Lisp_Object val = cons_listn (count, arg1, ap);
   va_end (ap);
   return val;
 }
@@ -2951,7 +2907,7 @@ large_vector_vec (struct large_vector *p)
 
 static struct large_vector *large_vectors;
 
-/* The only vector with 0 slots, allocated from pure space.  */
+/* The only vector with 0 slots.  */
 
 Lisp_Object zero_vector;
 
@@ -2987,15 +2943,6 @@ allocate_vector_block (void)
   return block;
 }
 
-/* Called once to initialize vector allocation.  */
-
-static void
-init_vectors (void)
-{
-  zero_vector = make_pure_vector (0);
-  staticpro (&zero_vector);
-}
-
 /* Allocate vector from a vector block.  */
 
 static struct Lisp_Vector *
@@ -3268,7 +3215,7 @@ #define VECTOR_ELTS_MAX \
 static struct Lisp_Vector *
 allocate_vectorlike (ptrdiff_t len, bool clearit)
 {
-  eassert (0 < len && len <= VECTOR_ELTS_MAX);
+  eassert (0 <= len && len <= VECTOR_ELTS_MAX);
   ptrdiff_t nbytes = header_size + len * word_size;
   struct Lisp_Vector *p;
 
@@ -3343,6 +3290,17 @@ allocate_nil_vector (ptrdiff_t len)
 }
 
 
+/* Called once to initialize vector allocation.  */
+
+static void
+init_vectors (void)
+{
+  zero_vector =
+    make_lisp_ptr (allocate_vectorlike (0, true), Lisp_Vectorlike);
+  XVECTOR (zero_vector)->header.size = 0;
+  staticpro (&zero_vector);
+}
+
 /* Allocate other vector-like structures.  */
 
 struct Lisp_Vector *
@@ -3555,13 +3513,6 @@ #define SYMBOL_BLOCK_SIZE \
 
 static struct symbol_block *symbol_block;
 static int symbol_block_index = SYMBOL_BLOCK_SIZE;
-/* Pointer to the first symbol_block that contains pinned symbols.
-   Tests for 24.4 showed that at dump-time, Emacs contains about 15K symbols,
-   10K of which are pinned (and all but 250 of them are interned in obarray),
-   whereas a "typical session" has in the order of 30K symbols.
-   `symbol_block_pinned' lets mark_pinned_symbols scan only 15K symbols rather
-   than 30K to find the 10K symbols we need to mark.  */
-static struct symbol_block *symbol_block_pinned;
 
 /* List of free symbols.  */
 
@@ -3587,7 +3538,6 @@ init_symbol (Lisp_Object val, Lisp_Object name)
   p->u.s.interned = SYMBOL_UNINTERNED;
   p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
   p->u.s.declared_special = false;
-  p->u.s.pinned = false;
 }
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
@@ -5151,8 +5101,6 @@ valid_lisp_object_p (Lisp_Object obj)
     return 1;
 
   void *p = XPNTR (obj);
-  if (PURE_P (p))
-    return 1;
 
   if (SYMBOLP (obj) && c_symbol_p (p))
     return ((char *) p - (char *) lispsym) % sizeof lispsym[0] == 0;
@@ -5208,296 +5156,8 @@ valid_lisp_object_p (Lisp_Object obj)
   return 0;
 }
 
-/***********************************************************************
-		       Pure Storage Management
- ***********************************************************************/
-
-/* Allocate room for SIZE bytes from pure Lisp storage and return a
-   pointer to it.  TYPE is the Lisp type for which the memory is
-   allocated.  TYPE < 0 means it's not used for a Lisp object,
-   and that the result should have an alignment of -TYPE.
-
-   The bytes are initially zero.
-
-   If pure space is exhausted, allocate space from the heap.  This is
-   merely an expedient to let Emacs warn that pure space was exhausted
-   and that Emacs should be rebuilt with a larger pure space.  */
-
-static void *
-pure_alloc (size_t size, int type)
-{
-  void *result;
-
- again:
-  if (type >= 0)
-    {
-      /* Allocate space for a Lisp object from the beginning of the free
-	 space with taking account of alignment.  */
-      result = pointer_align (purebeg + pure_bytes_used_lisp, LISP_ALIGNMENT);
-      pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size;
-    }
-  else
-    {
-      /* Allocate space for a non-Lisp object from the end of the free
-	 space.  */
-      ptrdiff_t unaligned_non_lisp = pure_bytes_used_non_lisp + size;
-      char *unaligned = purebeg + pure_size - unaligned_non_lisp;
-      int decr = (intptr_t) unaligned & (-1 - type);
-      pure_bytes_used_non_lisp = unaligned_non_lisp + decr;
-      result = unaligned - decr;
-    }
-  pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp;
-
-  if (pure_bytes_used <= pure_size)
-    return result;
-
-  /* Don't allocate a large amount here,
-     because it might get mmap'd and then its address
-     might not be usable.  */
-  int small_amount = 10000;
-  eassert (size <= small_amount - LISP_ALIGNMENT);
-  purebeg = xzalloc (small_amount);
-  pure_size = small_amount;
-  pure_bytes_used_before_overflow += pure_bytes_used - size;
-  pure_bytes_used = 0;
-  pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0;
-
-  /* Can't GC if pure storage overflowed because we can't determine
-     if something is a pure object or not.  */
-  garbage_collection_inhibited++;
-  goto again;
-}
-
-
-#ifdef HAVE_UNEXEC
-
-/* Print a warning if PURESIZE is too small.  */
-
-void
-check_pure_size (void)
-{
-  if (pure_bytes_used_before_overflow)
-    message (("emacs:0:Pure Lisp storage overflow (approx. %"pI"d"
-	      " bytes needed)"),
-	     pure_bytes_used + pure_bytes_used_before_overflow);
-}
-#endif
-
-
-/* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
-   the non-Lisp data pool of the pure storage, and return its start
-   address.  Return NULL if not found.  */
-
-static char *
-find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
-{
-  int i;
-  ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max;
-  const unsigned char *p;
-  char *non_lisp_beg;
-
-  if (pure_bytes_used_non_lisp <= nbytes)
-    return NULL;
-
-  /* Set up the Boyer-Moore table.  */
-  skip = nbytes + 1;
-  for (i = 0; i < 256; i++)
-    bm_skip[i] = skip;
-
-  p = (const unsigned char *) data;
-  while (--skip > 0)
-    bm_skip[*p++] = skip;
-
-  last_char_skip = bm_skip['\0'];
-
-  non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp;
-  start_max = pure_bytes_used_non_lisp - (nbytes + 1);
-
-  /* See the comments in the function `boyer_moore' (search.c) for the
-     use of `infinity'.  */
-  infinity = pure_bytes_used_non_lisp + 1;
-  bm_skip['\0'] = infinity;
-
-  p = (const unsigned char *) non_lisp_beg + nbytes;
-  start = 0;
-  do
-    {
-      /* Check the last character (== '\0').  */
-      do
-	{
-	  start += bm_skip[*(p + start)];
-	}
-      while (start <= start_max);
-
-      if (start < infinity)
-	/* Couldn't find the last character.  */
-	return NULL;
-
-      /* No less than `infinity' means we could find the last
-	 character at `p[start - infinity]'.  */
-      start -= infinity;
-
-      /* Check the remaining characters.  */
-      if (memcmp (data, non_lisp_beg + start, nbytes) == 0)
-	/* Found.  */
-	return non_lisp_beg + start;
-
-      start += last_char_skip;
-    }
-  while (start <= start_max);
-
-  return NULL;
-}
-
-
-/* Return a string allocated in pure space.  DATA is a buffer holding
-   NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
-   means make the result string multibyte.
-
-   Must get an error if pure storage is full, since if it cannot hold
-   a large string it may be able to hold conses that point to that
-   string; then the string is not protected from gc.  */
-
-Lisp_Object
-make_pure_string (const char *data,
-		  ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->u.s.data == NULL)
-    {
-      s->u.s.data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->u.s.data, data, nbytes);
-      s->u.s.data[nbytes] = '\0';
-    }
-  s->u.s.size = nchars;
-  s->u.s.size_byte = multibyte ? nbytes : -1;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-/* Return a string allocated in pure space.  Do not
-   allocate the string data, just point to DATA.  */
-
-Lisp_Object
-make_pure_c_string (const char *data, ptrdiff_t nchars)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.size = nchars;
-  s->u.s.size_byte = -2;
-  s->u.s.data = (unsigned char *) data;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-static Lisp_Object purecopy (Lisp_Object obj);
-
-/* Return a cons allocated from pure space.  Give it pure copies
-   of CAR as car and CDR as cdr.  */
-
-Lisp_Object
-pure_cons (Lisp_Object car, Lisp_Object cdr)
-{
-  Lisp_Object new;
-  struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons);
-  XSETCONS (new, p);
-  XSETCAR (new, purecopy (car));
-  XSETCDR (new, purecopy (cdr));
-  return new;
-}
-
-
-/* Value is a float object with value NUM allocated from pure space.  */
-
 static Lisp_Object
-make_pure_float (double num)
-{
-  Lisp_Object new;
-  struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float);
-  XSETFLOAT (new, p);
-  XFLOAT_INIT (new, num);
-  return new;
-}
-
-/* Value is a bignum object with value VALUE allocated from pure
-   space.  */
-
-static Lisp_Object
-make_pure_bignum (Lisp_Object value)
-{
-  mpz_t const *n = xbignum_val (value);
-  size_t i, nlimbs = mpz_size (*n);
-  size_t nbytes = nlimbs * sizeof (mp_limb_t);
-  mp_limb_t *pure_limbs;
-  mp_size_t new_size;
-
-  struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike);
-  XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum));
-
-  int limb_alignment = alignof (mp_limb_t);
-  pure_limbs = pure_alloc (nbytes, - limb_alignment);
-  for (i = 0; i < nlimbs; ++i)
-    pure_limbs[i] = mpz_getlimbn (*n, i);
-
-  new_size = nlimbs;
-  if (mpz_sgn (*n) < 0)
-    new_size = -new_size;
-
-  mpz_roinit_n (b->value, pure_limbs, new_size);
-
-  return make_lisp_ptr (b, Lisp_Vectorlike);
-}
-
-/* Return a vector with room for LEN Lisp_Objects allocated from
-   pure space.  */
-
-static Lisp_Object
-make_pure_vector (ptrdiff_t len)
-{
-  Lisp_Object new;
-  size_t size = header_size + len * word_size;
-  struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike);
-  XSETVECTOR (new, p);
-  XVECTOR (new)->header.size = len;
-  return new;
-}
-
-/* Copy all contents and parameters of TABLE to a new table allocated
-   from pure space, return the purified table.  */
-static struct Lisp_Hash_Table *
-purecopy_hash_table (struct Lisp_Hash_Table *table)
-{
-  eassert (NILP (table->weak));
-  eassert (table->purecopy);
-
-  struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
-  struct hash_table_test pure_test = table->test;
-
-  /* Purecopy the hash table test.  */
-  pure_test.name = purecopy (table->test.name);
-  pure_test.user_hash_function = purecopy (table->test.user_hash_function);
-  pure_test.user_cmp_function = purecopy (table->test.user_cmp_function);
-
-  pure->header = table->header;
-  pure->weak = purecopy (Qnil);
-  pure->hash = purecopy (table->hash);
-  pure->next = purecopy (table->next);
-  pure->index = purecopy (table->index);
-  pure->count = table->count;
-  pure->next_free = table->next_free;
-  pure->purecopy = table->purecopy;
-  eassert (!pure->mutable);
-  pure->rehash_threshold = table->rehash_threshold;
-  pure->rehash_size = table->rehash_size;
-  pure->key_and_value = purecopy (table->key_and_value);
-  pure->test = pure_test;
-
-  return pure;
-}
+purecopy (Lisp_Object obj);
 
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
        doc: /* Make a copy of object OBJ in pure storage.
@@ -5514,100 +5174,23 @@ DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
     return purecopy (obj);
 }
 
-/* Pinned objects are marked before every GC cycle.  */
-static struct pinned_object
-{
-  Lisp_Object object;
-  struct pinned_object *next;
-} *pinned_objects;
-
 static Lisp_Object
 purecopy (Lisp_Object obj)
 {
-  if (FIXNUMP (obj)
-      || (! SYMBOLP (obj) && PURE_P (XPNTR (obj)))
-      || SUBRP (obj))
+  if (FIXNUMP (obj) || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
-    message_with_string ("Dropping text-properties while making string `%s' pure",
-			 obj, true);
-
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
     {
       Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
       if (!NILP (tmp))
 	return tmp;
+      Fputhash (obj, obj, Vpurify_flag);
     }
 
-  if (CONSP (obj))
-    obj = pure_cons (XCAR (obj), XCDR (obj));
-  else if (FLOATP (obj))
-    obj = make_pure_float (XFLOAT_DATA (obj));
-  else if (STRINGP (obj))
-    obj = make_pure_string (SSDATA (obj), SCHARS (obj),
-			    SBYTES (obj),
-			    STRING_MULTIBYTE (obj));
-  else if (HASH_TABLE_P (obj))
-    {
-      struct Lisp_Hash_Table *table = XHASH_TABLE (obj);
-      /* Do not purify hash tables which haven't been defined with
-         :purecopy as non-nil or are weak - they aren't guaranteed to
-         not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
-        {
-          /* Instead, add the hash table to the list of pinned objects,
-             so that it will be marked during GC.  */
-          struct pinned_object *o = xmalloc (sizeof *o);
-          o->object = obj;
-          o->next = pinned_objects;
-          pinned_objects = o;
-          return obj; /* Don't hash cons it.  */
-        }
-
-      struct Lisp_Hash_Table *h = purecopy_hash_table (table);
-      XSET_HASH_TABLE (obj, h);
-    }
-  else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
-    {
-      struct Lisp_Vector *objp = XVECTOR (obj);
-      ptrdiff_t nbytes = vector_nbytes (objp);
-      struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
-      register ptrdiff_t i;
-      ptrdiff_t size = ASIZE (obj);
-      if (size & PSEUDOVECTOR_FLAG)
-	size &= PSEUDOVECTOR_SIZE_MASK;
-      memcpy (vec, objp, nbytes);
-      for (i = 0; i < size; i++)
-	vec->contents[i] = purecopy (vec->contents[i]);
-      XSETVECTOR (obj, vec);
-    }
-  else if (SYMBOLP (obj))
-    {
-      if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
-	{ /* We can't purify them, but they appear in many pure objects.
-	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XSYMBOL (obj)->u.s.pinned = true;
-	  symbol_block_pinned = symbol_block;
-	}
-      /* Don't hash-cons it.  */
-      return obj;
-    }
-  else if (BIGNUMP (obj))
-    obj = make_pure_bignum (obj);
-  else
-    {
-      AUTO_STRING (fmt, "Don't know how to purify: %S");
-      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
-    }
-
-  if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
-    Fputhash (obj, obj, Vpurify_flag);
-
   return obj;
 }
 
-
 \f
 /***********************************************************************
 			  Protection from GC
@@ -5798,31 +5381,6 @@ compact_undo_list (Lisp_Object list)
   return list;
 }
 
-static void
-mark_pinned_objects (void)
-{
-  for (struct pinned_object *pobj = pinned_objects; pobj; pobj = pobj->next)
-    mark_object (pobj->object);
-}
-
-static void
-mark_pinned_symbols (void)
-{
-  struct symbol_block *sblk;
-  int lim = (symbol_block_pinned == symbol_block
-	     ? symbol_block_index : SYMBOL_BLOCK_SIZE);
-
-  for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
-    {
-      struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
-      for (; sym < end; ++sym)
-	if (sym->u.s.pinned)
-	  mark_object (make_lisp_symbol (sym));
-
-      lim = SYMBOL_BLOCK_SIZE;
-    }
-}
-
 static void
 visit_vectorlike_root (struct gc_root_visitor visitor,
                        struct Lisp_Vector *ptr,
@@ -6083,8 +5641,6 @@ garbage_collect (void)
   struct gc_root_visitor visitor = { .visit = mark_object_root_visitor };
   visit_static_gc_roots (visitor);
 
-  mark_pinned_objects ();
-  mark_pinned_symbols ();
   mark_terminals ();
   mark_kboards ();
   mark_threads ();
@@ -6193,10 +5749,6 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
   keeps around for future allocations (maybe because it does not know how
   to return them to the OS).
 
-However, if there was overflow in pure space, and Emacs was dumped
-using the 'unexec' method, `garbage-collect' returns nil, because
-real GC can't be done.
-
 Note that calling this function does not guarantee that absolutely all
 unreachable objects will be garbage-collected.  Emacs uses a
 mark-and-sweep garbage collector, but is conservative when it comes to
@@ -6566,7 +6118,6 @@ mark_objects (Lisp_Object *obj, ptrdiff_t n)
 mark_object (Lisp_Object arg)
 {
   register Lisp_Object obj;
-  void *po;
 #if GC_CHECK_MARKED_OBJECTS
   struct mem_node *m = NULL;
 #endif
@@ -6575,10 +6126,6 @@ mark_object (Lisp_Object arg)
   obj = arg;
  loop:
 
-  po = XPNTR (obj);
-  if (PURE_P (po))
-    return;
-
   last_marked[last_marked_index++] = obj;
   last_marked_index &= LAST_MARKED_SIZE - 1;
 
@@ -6771,11 +6318,10 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL()		((void) 0)
 	    break;
 	  default: emacs_abort ();
 	  }
-	if (!PURE_P (XSTRING (ptr->u.s.name)))
-          set_string_marked (XSTRING (ptr->u.s.name));
+	set_string_marked (XSTRING (ptr->u.s.name));
         mark_interval_tree (string_intervals (ptr->u.s.name));
 	/* Inner loop to mark next symbol in this bucket, if any.  */
-	po = ptr = ptr->u.s.next;
+	ptr = ptr->u.s.next;
 	if (ptr)
 	  goto nextsym;
       }
@@ -6886,7 +6432,7 @@ survives_gc_p (Lisp_Object obj)
       emacs_abort ();
     }
 
-  return survives_p || PURE_P (XPNTR (obj));
+  return survives_p;
 }
 
 
@@ -7474,8 +7020,6 @@ init_alloc_once (void)
 static void
 init_alloc_once_for_pdumper (void)
 {
-  purebeg = PUREBEG;
-  pure_size = PURESIZE;
   mem_init ();
 
 #ifdef DOUG_LEA_MALLOC
@@ -7519,7 +7063,7 @@ syms_of_alloc (void)
   Vgc_cons_percentage = make_float (0.1);
 
   DEFVAR_INT ("pure-bytes-used", pure_bytes_used,
-	      doc: /* Number of bytes of shareable Lisp data allocated so far.  */);
+	      doc: /* No longer used.  */);
 
   DEFVAR_INT ("cons-cells-consed", cons_cells_consed,
 	      doc: /* Number of cons cells that have been consed so far.  */);
@@ -7544,10 +7088,7 @@ syms_of_alloc (void)
 	      doc: /* Number of strings that have been consed so far.  */);
 
   DEFVAR_LISP ("purify-flag", Vpurify_flag,
-	       doc: /* Non-nil means loading Lisp code in order to dump an executable.
-This means that certain objects should be allocated in shared (pure) space.
-It can also be set to a hash-table, in which case this table is used to
-do hash-consing of the objects allocated to pure space.  */);
+	       doc: /* No longer used.  */);
 
   DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages,
 	       doc: /* Non-nil means display messages at start and end of garbage collection.  */);
@@ -7563,10 +7104,10 @@ syms_of_alloc (void)
   /* We build this in advance because if we wait until we need it, we might
      not be able to allocate the memory to hold it.  */
   Vmemory_signal_data
-    = pure_list (Qerror,
-		 build_pure_c_string ("Memory exhausted--use"
-				      " M-x save-some-buffers then"
-				      " exit and restart Emacs"));
+    = list (Qerror,
+	    build_string ("Memory exhausted--use"
+			  " M-x save-some-buffers then"
+			  " exit and restart Emacs"));
 
   DEFVAR_LISP ("memory-full", Vmemory_full,
 	       doc: /* Non-nil means Emacs cannot get much more Lisp memory.  */);
diff --git a/src/buffer.c b/src/buffer.c
index 5bd9b37702f3f..69cb1a8e904a4 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5266,8 +5266,8 @@ init_buffer_once (void)
   set_buffer_intervals (&buffer_defaults, NULL);
   set_buffer_intervals (&buffer_local_symbols, NULL);
   /* This is not strictly necessary, but let's make them initialized.  */
-  bset_name (&buffer_defaults, build_pure_c_string (" *buffer-defaults*"));
-  bset_name (&buffer_local_symbols, build_pure_c_string (" *buffer-local-symbols*"));
+  bset_name (&buffer_defaults, build_string (" *buffer-defaults*"));
+  bset_name (&buffer_local_symbols, build_string (" *buffer-local-symbols*"));
   BUFFER_PVEC_INIT (&buffer_defaults);
   BUFFER_PVEC_INIT (&buffer_local_symbols);
 
@@ -5275,7 +5275,7 @@ init_buffer_once (void)
   /* Must do these before making the first buffer! */
 
   /* real setup is done in bindings.el */
-  bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
+  bset_mode_line_format (&buffer_defaults, build_string ("%-"));
   bset_header_line_format (&buffer_defaults, Qnil);
   bset_tab_line_format (&buffer_defaults, Qnil);
   bset_abbrev_mode (&buffer_defaults, Qnil);
@@ -5342,7 +5342,7 @@ init_buffer_once (void)
   current_buffer = 0;
   pdumper_remember_lv_ptr_raw (&current_buffer, Lisp_Vectorlike);
 
-  QSFundamental = build_pure_c_string ("Fundamental");
+  QSFundamental = build_string ("Fundamental");
 
   DEFSYM (Qfundamental_mode, "fundamental-mode");
   bset_major_mode (&buffer_defaults, Qfundamental_mode);
@@ -5356,10 +5356,10 @@ init_buffer_once (void)
 
   /* Super-magic invisible buffer.  */
   Vprin1_to_string_buffer =
-    Fget_buffer_create (build_pure_c_string (" prin1"), Qt);
+    Fget_buffer_create (build_string (" prin1"), Qt);
   Vbuffer_alist = Qnil;
 
-  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*"), Qnil));
+  Fset_buffer (Fget_buffer_create (build_string ("*scratch*"), Qnil));
 
   inhibit_modification_hooks = 0;
 }
@@ -5534,9 +5534,9 @@ syms_of_buffer (void)
 	       Qoverwrite_mode_binary));
 
   Fput (Qprotected_field, Qerror_conditions,
-	pure_list (Qprotected_field, Qerror));
+	list (Qprotected_field, Qerror));
   Fput (Qprotected_field, Qerror_message,
-	build_pure_c_string ("Attempt to modify a protected field"));
+	build_string ("Attempt to modify a protected field"));
 
   DEFVAR_PER_BUFFER ("tab-line-format",
 		     &BVAR (current_buffer, tab_line_format),
diff --git a/src/callint.c b/src/callint.c
index 18624637843f2..8f8a771310557 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -824,10 +824,10 @@ syms_of_callint (void)
   callint_message = Qnil;
   staticpro (&callint_message);
 
-  preserved_fns = pure_list (intern_c_string ("region-beginning"),
-			     intern_c_string ("region-end"),
-			     intern_c_string ("point"),
-			     intern_c_string ("mark"));
+  preserved_fns = list (intern_c_string ("region-beginning"),
+			intern_c_string ("region-end"),
+			intern_c_string ("point"),
+			intern_c_string ("mark"));
   staticpro (&preserved_fns);
 
   DEFSYM (Qlist, "list");
diff --git a/src/category.c b/src/category.c
index ec8f61f7f002f..907db1455778b 100644
--- a/src/category.c
+++ b/src/category.c
@@ -53,7 +53,7 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
       (table, 1,
        make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			Qnil, false));
+			Qnil));
   struct Lisp_Hash_Table *h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
   Lisp_Object hash;
   ptrdiff_t i = hash_lookup (h, category_set, &hash);
@@ -120,8 +120,6 @@ DEFUN ("define-category", Fdefine_category, Sdefine_category, 2, 3, 0,
 
   if (!NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category))))
     error ("Category `%c' is already defined", (int) XFIXNAT (category));
-  if (!NILP (Vpurify_flag))
-    docstring = Fpurecopy (docstring);
   SET_CATEGORY_DOCSTRING (table, XFIXNAT (category), docstring);
 
   return Qnil;
diff --git a/src/coding.c b/src/coding.c
index 739dd6adcb5fc..bf7d492f546c7 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -11650,7 +11650,7 @@ syms_of_coding (void)
   Vcode_conversion_reused_workbuf = Qnil;
 
   staticpro (&Vcode_conversion_workbuf_name);
-  Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
+  Vcode_conversion_workbuf_name = build_string (" *code-conversion-work*");
 
   reused_workbuf_in_use = false;
   PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
@@ -11714,9 +11714,9 @@ syms_of_coding (void)
   /* Error signaled when there's a problem with detecting a coding system.  */
   DEFSYM (Qcoding_system_error, "coding-system-error");
   Fput (Qcoding_system_error, Qerror_conditions,
-	pure_list (Qcoding_system_error, Qerror));
+	list (Qcoding_system_error, Qerror));
   Fput (Qcoding_system_error, Qerror_message,
-	build_pure_c_string ("Invalid coding system"));
+	build_string ("Invalid coding system"));
 
   DEFSYM (Qtranslation_table, "translation-table");
   Fput (Qtranslation_table, Qchar_table_extra_slots, make_fixnum (2));
@@ -11991,22 +11991,22 @@ syms_of_coding (void)
   DEFVAR_LISP ("eol-mnemonic-unix", eol_mnemonic_unix,
 	       doc: /*
 String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
-  eol_mnemonic_unix = build_pure_c_string (":");
+  eol_mnemonic_unix = build_string (":");
 
   DEFVAR_LISP ("eol-mnemonic-dos", eol_mnemonic_dos,
 	       doc: /*
 String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
-  eol_mnemonic_dos = build_pure_c_string ("\\");
+  eol_mnemonic_dos = build_string ("\\");
 
   DEFVAR_LISP ("eol-mnemonic-mac", eol_mnemonic_mac,
 	       doc: /*
 String displayed in mode line for MAC-like (CR) end-of-line format.  */);
-  eol_mnemonic_mac = build_pure_c_string ("/");
+  eol_mnemonic_mac = build_string ("/");
 
   DEFVAR_LISP ("eol-mnemonic-undecided", eol_mnemonic_undecided,
 	       doc: /*
 String displayed in mode line when end-of-line format is not yet determined.  */);
-  eol_mnemonic_undecided = build_pure_c_string (":");
+  eol_mnemonic_undecided = build_string (":");
 
   DEFVAR_LISP ("enable-character-translation", Venable_character_translation,
 	       doc: /*
@@ -12146,7 +12146,7 @@ system (e.g. `iso-2022-7bit').
       intern_c_string (":for-unibyte"),
       args[coding_arg_for_unibyte] = Qt,
       intern_c_string (":docstring"),
-      (build_pure_c_string
+      (build_string
        ("Do no conversion.\n"
 	"\n"
 	"When you visit a file with this coding, the file is read into a\n"
@@ -12166,7 +12166,7 @@ system (e.g. `iso-2022-7bit').
   plist[8] = intern_c_string (":charset-list");
   plist[9] = args[coding_arg_charset_list] = list1 (Qascii);
   plist[11] = args[coding_arg_for_unibyte] = Qnil;
-  plist[13] = build_pure_c_string ("No conversion on encoding, "
+  plist[13] = build_string ("No conversion on encoding, "
 				   "automatic conversion on decoding.");
   plist[15] = args[coding_arg_eol_type] = Qnil;
   args[coding_arg_plist] = CALLMANY (Flist, plist);
diff --git a/src/conf_post.h b/src/conf_post.h
index 176ab28b21ab2..da55a1fb54abc 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -163,41 +163,8 @@ #define emacs_raise(sig) msdos_fatal_signal (sig)
 
 /* DATA_START is needed by vm-limit.c and unexcoff.c. */
 #define DATA_START (&etext + 1)
-
-/* Define one of these for easier conditionals.  */
-#ifdef HAVE_X_WINDOWS
-/* We need a little extra space, see ../../lisp/loadup.el and the
-   commentary below, in the non-X branch.  The 140KB number was
-   measured on GNU/Linux and on MS-Windows.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+140000)
-#else
-/* We need a little extra space, see ../../lisp/loadup.el.
-   As of 20091024, DOS-specific files use up 62KB of pure space.  But
-   overall, we end up wasting 130KB of pure space, because
-   BASE_PURESIZE starts at 1.47MB, while we need only 1.3MB (including
-   non-DOS specific files and load history; the latter is about 55K,
-   but depends on the depth of the top-level Emacs directory in the
-   directory tree).  Given the unknown policy of different DPMI
-   hosts regarding loading of untouched pages, I'm not going to risk
-   enlarging Emacs footprint by another 100+ KBytes.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+90000)
-#endif
 #endif  /* MSDOS */
 
-/* macOS / GNUstep need a bit more pure memory.  Of the existing knobs,
-   SYSTEM_PURESIZE_EXTRA seems like the least likely to cause problems.  */
-#ifdef HAVE_NS
-#if defined NS_IMPL_GNUSTEP
-#  define SYSTEM_PURESIZE_EXTRA 30000
-#elif defined DARWIN_OS
-#  define SYSTEM_PURESIZE_EXTRA 200000
-#endif
-#endif
-
-#ifdef CYGWIN
-#define SYSTEM_PURESIZE_EXTRA 50000
-#endif
-
 #if defined HAVE_NTGUI && !defined DebPrint
 # ifdef EMACSDEBUG
 extern void _DebPrint (const char *fmt, ...);
diff --git a/src/data.c b/src/data.c
index 0fa491b17a114..2a8c7246fae65 100644
--- a/src/data.c
+++ b/src/data.c
@@ -30,7 +30,6 @@
 
 #include "lisp.h"
 #include "bignum.h"
-#include "puresize.h"
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
@@ -149,12 +148,6 @@ wrong_type_argument (Lisp_Object predicate, Lisp_Object value)
   xsignal2 (Qwrong_type_argument, predicate, value);
 }
 
-void
-pure_write_error (Lisp_Object obj)
-{
-  xsignal2 (Qerror, build_string ("Attempt to modify read-only object"), obj);
-}
-
 void
 args_out_of_range (Lisp_Object a1, Lisp_Object a2)
 {
@@ -625,7 +618,6 @@ DEFUN ("setcar", Fsetcar, Ssetcar, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcar)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCAR (cell, newcar);
   return newcar;
 }
@@ -635,7 +627,6 @@ DEFUN ("setcdr", Fsetcdr, Ssetcdr, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcdr)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCDR (cell, newcdr);
   return newcdr;
 }
@@ -798,10 +789,6 @@ DEFUN ("defalias", Fdefalias, Sdefalias, 2, 3, 0,
   (register Lisp_Object symbol, Lisp_Object definition, Lisp_Object docstring)
 {
   CHECK_SYMBOL (symbol);
-  if (!NILP (Vpurify_flag)
-      /* If `definition' is a keymap, immutable (and copying) is wrong.  */
-      && !KEYMAPP (definition))
-    definition = Fpurecopy (definition);
 
   {
     bool autoload = AUTOLOADP (definition);
@@ -2375,7 +2362,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
 
   if (VECTORP (array))
     {
-      CHECK_IMPURE (array, XVECTOR (array));
       if (idxval < 0 || idxval >= ASIZE (array))
 	args_out_of_range (array, idx);
       ASET (array, idxval, newelt);
@@ -2399,7 +2385,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
     }
   else /* STRINGP */
     {
-      CHECK_IMPURE (array, XSTRING (array));
       if (idxval < 0 || idxval >= SCHARS (array))
 	args_out_of_range (array, idx);
       CHECK_CHARACTER (newelt);
@@ -3881,7 +3866,7 @@ syms_of_data (void)
 
   DEFSYM (Qcdr, "cdr");
 
-  error_tail = pure_cons (Qerror, Qnil);
+  error_tail = Fcons (Qerror, Qnil);
 
   /* ERROR is used as a signaler for random errors for which nothing else is
      right.  */
@@ -3889,11 +3874,11 @@ syms_of_data (void)
   Fput (Qerror, Qerror_conditions,
 	error_tail);
   Fput (Qerror, Qerror_message,
-	build_pure_c_string ("error"));
+	build_string ("error"));
 
 #define PUT_ERROR(sym, tail, msg)			\
-  Fput (sym, Qerror_conditions, pure_cons (sym, tail)); \
-  Fput (sym, Qerror_message, build_pure_c_string (msg))
+  Fput (sym, Qerror_conditions, Fcons (sym, tail)); \
+  Fput (sym, Qerror_message, build_string (msg))
 
   PUT_ERROR (Qquit, Qnil, "Quit");
 
@@ -3921,14 +3906,14 @@ #define PUT_ERROR(sym, tail, msg)			\
   PUT_ERROR (Qno_catch, error_tail, "No catch for tag");
   PUT_ERROR (Qend_of_file, error_tail, "End of file during parsing");
 
-  arith_tail = pure_cons (Qarith_error, error_tail);
+  arith_tail = Fcons (Qarith_error, error_tail);
   Fput (Qarith_error, Qerror_conditions, arith_tail);
-  Fput (Qarith_error, Qerror_message, build_pure_c_string ("Arithmetic error"));
+  Fput (Qarith_error, Qerror_message, build_string ("Arithmetic error"));
 
   PUT_ERROR (Qbeginning_of_buffer, error_tail, "Beginning of buffer");
   PUT_ERROR (Qend_of_buffer, error_tail, "End of buffer");
   PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only");
-  PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail),
+  PUT_ERROR (Qtext_read_only, Fcons (Qbuffer_read_only, error_tail),
 	     "Text is read-only");
   PUT_ERROR (Qinhibited_interaction, error_tail,
 	     "User interaction while inhibited");
diff --git a/src/dbusbind.c b/src/dbusbind.c
index c005474d4409f..238142b95606c 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1868,7 +1868,7 @@ syms_of_dbusbind (void)
   Fput (Qdbus_error, Qerror_conditions,
 	list2 (Qdbus_error, Qerror));
   Fput (Qdbus_error, Qerror_message,
-	build_pure_c_string ("D-Bus error"));
+	build_string ("D-Bus error"));
 
   /* Lisp symbols of the system and session buses.  */
   DEFSYM (QCsystem, ":system");
@@ -1911,7 +1911,7 @@ syms_of_dbusbind (void)
 	       Vdbus_compiled_version,
     doc: /* The version of D-Bus Emacs is compiled against.  */);
 #ifdef DBUS_VERSION_STRING
-  Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
+  Vdbus_compiled_version = build_string (DBUS_VERSION_STRING);
 #else
   Vdbus_compiled_version = Qnil;
 #endif
diff --git a/src/deps.mk b/src/deps.mk
index eda2ed6338252..3292cf201cf74 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -132,10 +132,10 @@ insdel.o:
 keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \
    commands.h frame.h window.h macros.h disptab.h keyboard.h syssignal.h \
    systime.h syntax.h $(INTERVALS_H) blockinput.h atimer.h composite.h \
-   xterm.h puresize.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
+   xterm.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
    process.h ../lib/unistd.h gnutls.h lisp.h globals.h $(config_h)
 keymap.o: keymap.c buffer.h commands.h keyboard.h termhooks.h blockinput.h \
-   atimer.h systime.h puresize.h character.h charset.h $(INTERVALS_H) \
+   atimer.h systime.h character.h charset.h $(INTERVALS_H) \
    keymap.h window.h coding.h frame.h lisp.h globals.h $(config_h)
 lastfile.o: lastfile.c $(config_h)
 macros.o: macros.c window.h buffer.h commands.h macros.h keyboard.h msdos.h \
@@ -267,12 +267,12 @@ xsettings.o:
    atimer.h termopts.h globals.h
 
 ## The files of Lisp proper.
-alloc.o: alloc.c process.h frame.h window.h buffer.h  puresize.h syssignal.h \
+alloc.o: alloc.c process.h frame.h window.h buffer.h syssignal.h \
    keyboard.h blockinput.h atimer.h systime.h character.h lisp.h $(config_h) \
    $(INTERVALS_H) termhooks.h gnutls.h coding.h ../lib/unistd.h globals.h
 bytecode.o: bytecode.c buffer.h syntax.h character.h window.h dispextern.h \
   lisp.h globals.h $(config_h) msdos.h
-data.o: data.c buffer.h puresize.h character.h syssignal.h keyboard.h frame.h \
+data.o: data.c buffer.h character.h syssignal.h keyboard.h frame.h \
    termhooks.h systime.h coding.h composite.h dispextern.h font.h ccl.h \
    lisp.h globals.h $(config_h) msdos.h
 eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h frame.h \
@@ -295,7 +295,7 @@ lread.o:
 composite.o: composite.c composite.h buffer.h character.h coding.h font.h \
    ccl.h frame.h termhooks.h $(INTERVALS_H) window.h \
    lisp.h globals.h $(config_h)
-intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h puresize.h \
+intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h \
    keymap.h lisp.h globals.h $(config_h) systime.h coding.h
 textprop.o: textprop.c buffer.h window.h $(INTERVALS_H) \
    lisp.h globals.h $(config_h)
diff --git a/src/doc.c b/src/doc.c
index 1307aa5ee9233..2136f914297dd 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -490,8 +490,6 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
 	{
 	  tem = Fcdr (Fcdr (fun));
 	  if (CONSP (tem) && FIXNUMP (XCAR (tem)))
-	    /* FIXME: This modifies typically pure hash-cons'd data, so its
-	       correctness is quite delicate.  */
 	    XSETCAR (tem, make_fixnum (offset));
 	}
     }
@@ -575,7 +573,6 @@ DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
       int i = ARRAYELTS (buildobj);
       while (0 <= --i)
 	Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
-      Vbuild_files = Fpurecopy (Vbuild_files);
     }
 
   fd = emacs_open (name, O_RDONLY, 0);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index f8fb54c072823..896ae65685e84 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -1600,44 +1600,44 @@ syms_of_module (void)
   Vmodule_refs_hash
     = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 		       DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-		       Qnil, false);
+		       Qnil);
 
   DEFSYM (Qmodule_load_failed, "module-load-failed");
   Fput (Qmodule_load_failed, Qerror_conditions,
-	pure_list (Qmodule_load_failed, Qerror));
+	list (Qmodule_load_failed, Qerror));
   Fput (Qmodule_load_failed, Qerror_message,
-        build_pure_c_string ("Module load failed"));
+        build_string ("Module load failed"));
 
   DEFSYM (Qmodule_open_failed, "module-open-failed");
   Fput (Qmodule_open_failed, Qerror_conditions,
-	pure_list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_open_failed, Qerror_message,
-        build_pure_c_string ("Module could not be opened"));
+        build_string ("Module could not be opened"));
 
   DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible");
   Fput (Qmodule_not_gpl_compatible, Qerror_conditions,
-	pure_list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
+	list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
   Fput (Qmodule_not_gpl_compatible, Qerror_message,
-        build_pure_c_string ("Module is not GPL compatible"));
+        build_string ("Module is not GPL compatible"));
 
   DEFSYM (Qmissing_module_init_function, "missing-module-init-function");
   Fput (Qmissing_module_init_function, Qerror_conditions,
-	pure_list (Qmissing_module_init_function, Qmodule_load_failed,
-		   Qerror));
+	list (Qmissing_module_init_function, Qmodule_load_failed,
+	      Qerror));
   Fput (Qmissing_module_init_function, Qerror_message,
-        build_pure_c_string ("Module does not export an "
+        build_string ("Module does not export an "
                              "initialization function"));
 
   DEFSYM (Qmodule_init_failed, "module-init-failed");
   Fput (Qmodule_init_failed, Qerror_conditions,
-	pure_list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_init_failed, Qerror_message,
-        build_pure_c_string ("Module initialization failed"));
+        build_string ("Module initialization failed"));
 
   DEFSYM (Qinvalid_arity, "invalid-arity");
-  Fput (Qinvalid_arity, Qerror_conditions, pure_list (Qinvalid_arity, Qerror));
+  Fput (Qinvalid_arity, Qerror_conditions, list (Qinvalid_arity, Qerror));
   Fput (Qinvalid_arity, Qerror_message,
-        build_pure_c_string ("Invalid function arity"));
+        build_string ("Invalid function arity"));
 
   DEFSYM (Qmodule_function_p, "module-function-p");
   DEFSYM (Qunicode_string_p, "unicode-string-p");
diff --git a/src/emacs.c b/src/emacs.c
index fd08667f3fd4f..03ec63464daf5 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -88,7 +88,6 @@ #define MAIN_PROGRAM
 #include "syntax.h"
 #include "sysselect.h"
 #include "systime.h"
-#include "puresize.h"
 
 #include "getpagesize.h"
 #include "gnutls.h"
@@ -1544,7 +1543,9 @@ main (int argc, char **argv)
   if (!initialized)
     {
       init_alloc_once ();
+#ifdef HAVE_PDUMPER
       init_pdumper_once ();
+#endif
       init_obarray_once ();
       init_eval_once ();
       init_charset_once ();
@@ -2508,8 +2509,6 @@ DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
   Lisp_Object symbol;
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  check_pure_size ();
-
   if (! noninteractive)
     error ("Dumping Emacs works only in batch mode");
 
diff --git a/src/eval.c b/src/eval.c
index ddaa8edd81706..c0717f8cf124d 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -785,8 +785,6 @@ DEFUN ("internal--define-uninitialized-variable",
   XSYMBOL (symbol)->u.s.declared_special = true;
   if (!NILP (doc))
     {
-      if (!NILP (Vpurify_flag))
-	doc = Fpurecopy (doc);
       Fput (symbol, Qvariable_documentation, doc);
     }
   LOADHIST_ATTACH (symbol);
@@ -903,8 +901,6 @@ DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
 
   Finternal__define_uninitialized_variable (sym, docstring);
   tem = eval_sub (XCAR (XCDR (args)));
-  if (!NILP (Vpurify_flag))
-    tem = Fpurecopy (tem);
   Fset_default (sym, tem);      /* FIXME: set-default-toplevel-value? */
   Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why?  */
   return sym;
@@ -2107,12 +2103,6 @@ DEFUN ("autoload", Fautoload, Sautoload, 2, 5, 0,
       && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_fixnum (0)))
-    /* `read1' in lread.c has found the docstring starting with "\
-       and assumed the docstring will be provided by Snarf-documentation, so it
-       passed us 0 instead.  But that leads to accidental sharing in purecopy's
-       hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_ufixnum (XHASH (function));
   return Fdefalias (function,
 		    list5 (Qautoload, file, docstring, interactive, type),
 		    Qnil);
@@ -4354,7 +4344,7 @@ syms_of_eval (void)
      also use something like Fcons (Qnil, Qnil), but json.c treats any
      cons cell as error data, so use an uninterned symbol instead.  */
   Qcatch_all_memory_full
-    = Fmake_symbol (build_pure_c_string ("catch-all-memory-full"));
+    = Fmake_symbol (build_string ("catch-all-memory-full"));
 
   defsubr (&Sor);
   defsubr (&Sand);
diff --git a/src/fileio.c b/src/fileio.c
index 741e297d29c2c..5d438865e2092 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6294,34 +6294,34 @@ syms_of_fileio (void)
   DEFSYM (Qcar_less_than_car, "car-less-than-car");
 
   Fput (Qfile_error, Qerror_conditions,
-	Fpurecopy (list2 (Qfile_error, Qerror)));
+	list2 (Qfile_error, Qerror));
   Fput (Qfile_error, Qerror_message,
-	build_pure_c_string ("File error"));
+	build_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
+	list3 (Qfile_already_exists, Qfile_error, Qerror));
   Fput (Qfile_already_exists, Qerror_message,
-	build_pure_c_string ("File already exists"));
+	build_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
+	list3 (Qfile_date_error, Qfile_error, Qerror));
   Fput (Qfile_date_error, Qerror_message,
-	build_pure_c_string ("Cannot set file date"));
+	build_string ("Cannot set file date"));
 
   Fput (Qfile_missing, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_missing, Qfile_error, Qerror)));
+	list3 (Qfile_missing, Qfile_error, Qerror));
   Fput (Qfile_missing, Qerror_message,
-	build_pure_c_string ("File is missing"));
+	build_string ("File is missing"));
 
   Fput (Qfile_notify_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_notify_error, Qfile_error, Qerror)));
+	list3 (Qfile_notify_error, Qfile_error, Qerror));
   Fput (Qfile_notify_error, Qerror_message,
-	build_pure_c_string ("File notification error"));
+	build_string ("File notification error"));
 
   Fput (Qremote_file_error, Qerror_conditions,
 	Fpurecopy (list3 (Qremote_file_error, Qfile_error, Qerror)));
   Fput (Qremote_file_error, Qerror_message,
-	build_pure_c_string ("Remote file error"));
+	build_string ("Remote file error"));
 
   DEFVAR_LISP ("file-name-handler-alist", Vfile_name_handler_alist,
 	       doc: /* Alist of elements (REGEXP . HANDLER) for file names handled specially.
diff --git a/src/fns.c b/src/fns.c
index 7914bd47790a9..a22b633ec7386 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -36,7 +36,6 @@ Copyright (C) 1985-1987, 1993-1995, 1997-2021 Free Software Foundation,
 #include "buffer.h"
 #include "intervals.h"
 #include "window.h"
-#include "puresize.h"
 #include "gnutls.h"
 
 static void sort_vector_copy (Lisp_Object, ptrdiff_t,
@@ -2602,7 +2601,6 @@ DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
       size = SCHARS (array);
       if (size != 0)
 	{
-	  CHECK_IMPURE (array, XSTRING (array));
 	  unsigned char str[MAX_MULTIBYTE_LENGTH];
 	  int len;
 	  if (STRING_MULTIBYTE (array))
@@ -2644,7 +2642,6 @@ DEFUN ("clear-string", Fclear_string, Sclear_string,
   ptrdiff_t len = SBYTES (string);
   if (len != 0 || STRING_MULTIBYTE (string))
     {
-      CHECK_IMPURE (string, XSTRING (string));
       memset (SDATA (string), 0, len);
       STRING_SET_CHARS (string, len);
       STRING_SET_UNIBYTE (string);
@@ -4179,16 +4176,12 @@ hash_index_size (struct Lisp_Hash_Table *h, ptrdiff_t size)
    size exceeds REHASH_THRESHOLD.
 
    WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value', `key-or-value', or `key-and-value'.
-
-   If PURECOPY is non-nil, the table can be copied to pure storage via
-   `purecopy' when Emacs is being dumped. Such tables can no longer be
-   changed after purecopy.  */
+   one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
 
 Lisp_Object
 make_hash_table (struct hash_table_test test, EMACS_INT size,
 		 float rehash_size, float rehash_threshold,
-		 Lisp_Object weak, bool purecopy)
+		 Lisp_Object weak)
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
@@ -4217,7 +4210,6 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
   h->next = make_vector (size, make_fixnum (-1));
   h->index = make_vector (hash_index_size (h, size), make_fixnum (-1));
   h->next_weak = NULL;
-  h->purecopy = purecopy;
   h->mutable = true;
 
   /* Set up the free list.  */
@@ -4318,11 +4310,6 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
 	    set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
 	    set_hash_index_slot (h, start_of_bucket, i);
 	  }
-
-#ifdef ENABLE_CHECKING
-      if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h)
-	message ("Growing hash table to: %"pD"d", next_size);
-#endif
     }
 }
 
@@ -4385,7 +4372,6 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h)
 {
   if (!h->mutable)
     signal_error ("hash table test modifies table", obj);
-  eassert (!PURE_P (h));
 }
 
 /* Put an entry into hash table H that associates KEY with VALUE.
@@ -4876,16 +4862,10 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
 WEAK.  WEAK t is equivalent to `key-and-value'.  Default value of WEAK
 is nil.
 
-:purecopy PURECOPY -- If PURECOPY is non-nil, the table can be copied
-to pure storage when Emacs is being dumped, making the contents of the
-table read only. Any further changes to purified tables will result
-in an error.
-
 usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object test, weak;
-  bool purecopy;
   struct hash_table_test testdesc;
   ptrdiff_t i;
   USE_SAFE_ALLOCA;
@@ -4919,9 +4899,8 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       testdesc.cmpfn = cmpfn_user_defined;
     }
 
-  /* See if there's a `:purecopy PURECOPY' argument.  */
-  i = get_key_arg (QCpurecopy, nargs, args, used);
-  purecopy = i && !NILP (args[i]);
+  /* Ignore a `:purecopy PURECOPY' argument.  */
+  get_key_arg (QCpurecopy, nargs, args, used);
   /* See if there's a `:size SIZE' argument.  */
   i = get_key_arg (QCsize, nargs, args, used);
   Lisp_Object size_arg = i ? args[i] : Qnil;
@@ -4971,8 +4950,7 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       signal_error ("Invalid argument list", args[i]);
 
   SAFE_FREE ();
-  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak,
-			  purecopy);
+  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
 }
 
 
diff --git a/src/fontset.c b/src/fontset.c
index 332be6c39d11f..0421ca49c7361 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -2129,7 +2129,7 @@ syms_of_fontset (void)
   set_fontset_id (Vdefault_fontset, make_fixnum (0));
   set_fontset_name
     (Vdefault_fontset,
-     build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
+     build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
   ASET (Vfontset_table, 0, Vdefault_fontset);
   next_fontset_id = 1;
   PDUMPER_REMEMBER_SCALAR (next_fontset_id);
@@ -2187,7 +2187,7 @@ syms_of_fontset (void)
 	       doc: /* Alist of fontset names vs the aliases.  */);
   Vfontset_alias_alist
     = list1 (Fcons (FONTSET_NAME (Vdefault_fontset),
-		    build_pure_c_string ("fontset-default")));
+		    build_string ("fontset-default")));
 
   DEFVAR_LISP ("vertical-centering-font-regexp",
 	       Vvertical_centering_font_regexp,
diff --git a/src/frame.c b/src/frame.c
index a62347c1fb2a9..652d26654390d 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1108,7 +1108,7 @@ make_initial_frame (void)
   Vframe_list = Fcons (frame, Vframe_list);
 
   tty_frame_count = 1;
-  fset_name (f, build_pure_c_string ("F1"));
+  fset_name (f, build_string ("F1"));
 
   SET_FRAME_VISIBLE (f, 1);
 
diff --git a/src/image.c b/src/image.c
index 8137dbea8d7ec..c738548d382a7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -4808,7 +4808,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			  DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			  Qnil, false);
+			  Qnil);
 }
 
 static void
diff --git a/src/intervals.c b/src/intervals.c
index f88a41f254917..5b69af2449a68 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -44,7 +44,6 @@
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "puresize.h"
 #include "keymap.h"
 
 /* Test for membership, allowing for t (actually any non-cons) to mean the
@@ -101,7 +100,6 @@ create_root_interval (Lisp_Object parent)
     }
   else
     {
-      CHECK_IMPURE (parent, XSTRING (parent));
       new->total_length = SCHARS (parent);
       eassert (TOTAL_LENGTH (new) >= 0);
       set_string_intervals (parent, new);
diff --git a/src/json.c b/src/json.c
index 3f1d27ad7fb7f..ccb0405c4e069 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1110,8 +1110,8 @@ define_error (Lisp_Object name, const char *message, Lisp_Object parent)
   eassert (CONSP (parent_conditions));
   eassert (!NILP (Fmemq (parent, parent_conditions)));
   eassert (NILP (Fmemq (name, parent_conditions)));
-  Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
-  Fput (name, Qerror_message, build_pure_c_string (message));
+  Fput (name, Qerror_conditions, Fcons (name, parent_conditions));
+  Fput (name, Qerror_message, build_string (message));
 }
 
 void
diff --git a/src/keyboard.c b/src/keyboard.c
index 9ee4c4f6d6839..1c862a15759af 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1109,8 +1109,6 @@ top_level_1 (Lisp_Object ignore)
   /* On entry to the outer level, run the startup file.  */
   if (!NILP (Vtop_level))
     internal_condition_case (top_level_2, Qerror, cmd_error);
-  else if (!NILP (Vpurify_flag))
-    message1 ("Bare impure Emacs (standard Lisp code not loaded)");
   else
     message1 ("Bare Emacs (standard Lisp code not loaded)");
   return Qnil;
@@ -11458,14 +11456,14 @@ syms_of_keyboard (void)
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
-  Vlispy_mouse_stem = build_pure_c_string ("mouse");
+  Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
-  regular_top_level_message = build_pure_c_string ("Back to top level");
+  regular_top_level_message = build_string ("Back to top level");
   staticpro (&regular_top_level_message);
 #ifdef HAVE_STACK_OVERFLOW_HANDLING
   recover_top_level_message
-    = build_pure_c_string ("Re-entering top level after C stack overflow");
+    = build_string ("Re-entering top level after C stack overflow");
   staticpro (&recover_top_level_message);
 #endif
   DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
diff --git a/src/keymap.c b/src/keymap.c
index 782931fadff6a..dca4fce9b13f8 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -50,7 +50,6 @@
 #include "keyboard.h"
 #include "termhooks.h"
 #include "blockinput.h"
-#include "puresize.h"
 #include "intervals.h"
 #include "keymap.h"
 #include "window.h"
@@ -117,8 +116,6 @@ DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 1, 0,
 {
   if (!NILP (string))
     {
-      if (!NILP (Vpurify_flag))
-	string = Fpurecopy (string);
       return list2 (Qkeymap, string);
     }
   return list1 (Qkeymap);
@@ -296,7 +293,6 @@ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
 	 If we came to the end, add the parent in PREV.  */
       if (!CONSP (list) || KEYMAPP (list))
 	{
-	  CHECK_IMPURE (prev, XCONS (prev));
 	  XSETCDR (prev, parent);
 	  return parent;
 	}
@@ -734,7 +730,7 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 
   /* If we are preparing to dump, and DEF is a menu element
      with a menu item indicator, copy it to ensure it is not pure.  */
-  if (CONSP (def) && PURE_P (XCONS (def))
+  if (CONSP (def)
       && (EQ (XCAR (def), Qmenu_item) || STRINGP (XCAR (def))))
     def = Fcons (XCAR (def), XCDR (def));
 
@@ -778,7 +774,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	  {
 	    if (FIXNATP (idx) && XFIXNAT (idx) < ASIZE (elt))
 	      {
-		CHECK_IMPURE (elt, XVECTOR (elt));
 		ASET (elt, XFIXNAT (idx), def);
 		return def;
 	      }
@@ -831,7 +826,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	      }
 	    else if (EQ (idx, XCAR (elt)))
 	      {
-		CHECK_IMPURE (elt, XCONS (elt));
 		XSETCDR (elt, def);
 		return def;
 	      }
@@ -877,7 +871,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	}
       else
 	elt = Fcons (idx, def);
-      CHECK_IMPURE (insertion_point, XCONS (insertion_point));
       XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
     }
   }
@@ -3121,12 +3114,12 @@ syms_of_keymap (void)
   current_global_map = Qnil;
   staticpro (&current_global_map);
 
-  exclude_keys = pure_list
-    (pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")),
-     pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")),
-     pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")),
-     pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")),
-     pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" ")));
+  exclude_keys = list
+    (Fcons (build_string ("DEL"), build_string ("\\d")),
+     Fcons (build_string ("TAB"), build_string ("\\t")),
+     Fcons (build_string ("RET"), build_string ("\\r")),
+     Fcons (build_string ("ESC"), build_string ("\\e")),
+     Fcons (build_string ("SPC"), build_string (" ")));
   staticpro (&exclude_keys);
 
   DEFVAR_LISP ("minibuffer-local-map", Vminibuffer_local_map,
@@ -3176,13 +3169,12 @@ syms_of_keymap (void)
   DEFSYM (Qmode_line, "mode-line");
 
   staticpro (&Vmouse_events);
-  Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar,
-			     Qtab_line, Qheader_line, Qmode_line,
-			     intern_c_string ("mouse-1"),
-			     intern_c_string ("mouse-2"),
-			     intern_c_string ("mouse-3"),
-			     intern_c_string ("mouse-4"),
-			     intern_c_string ("mouse-5"));
+  Vmouse_events = list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
+			intern_c_string ("mouse-1"),
+			intern_c_string ("mouse-2"),
+			intern_c_string ("mouse-3"),
+			intern_c_string ("mouse-4"),
+			intern_c_string ("mouse-5"));
 
   /* Keymap used for minibuffers when doing completion.  */
   /* Keymap used for minibuffers when doing completion and require a match.  */
diff --git a/src/lisp.h b/src/lisp.h
index b95f389b89024..7580272e5c7f3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -823,9 +823,6 @@ #define XUNTAG(a, type, ctype) ((ctype *) \
 	 special (with `defvar' etc), and shouldn't be lexically bound.  */
       bool_bf declared_special : 1;
 
-      /* True if pointed to from purespace and hence can't be GC'd.  */
-      bool_bf pinned : 1;
-
       /* The symbol's name, as a Lisp string.  */
       Lisp_Object name;
 
@@ -1534,20 +1531,14 @@ #define STRING_BYTES_BOUND  \
 /* Mark STR as a unibyte string.  */
 #define STRING_SET_UNIBYTE(STR)				\
   do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_unibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = -1;		\
+    XSTRING (STR)->u.s.size_byte = -1;			\
   } while (false)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
-#define STRING_SET_MULTIBYTE(STR)			\
-  do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_multibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
+#define STRING_SET_MULTIBYTE(STR)				\
+  do {								\
+    XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size;	\
   } while (false)
 
 /* Convenience functions for dealing with Lisp strings.  */
@@ -2301,12 +2292,8 @@ #define DEFSYM(sym, name) /* empty */
   /* Index of first free entry in free list, or -1 if none.  */
   ptrdiff_t next_free;
 
-  /* True if the table can be purecopied.  The table cannot be
-     changed afterwards.  */
-  bool purecopy;
-
   /* True if the table is mutable.  Ordinarily tables are mutable, but
-     pure tables are not, and while a table is being mutated it is
+     some tables are not, and while a table is being mutated it is
      immutable for recursive attempts to mutate it.  */
   bool mutable;
 
@@ -3599,7 +3586,7 @@ #define CONS_TO_INTEGER(cons, type, var)				\
 Lisp_Object hashfn_equal (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
-                             Lisp_Object, bool);
+                             Lisp_Object);
 ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object *);
 ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
 		    Lisp_Object);
@@ -3755,7 +3742,6 @@ verify (FLT_RADIX == 2 || FLT_RADIX == 16);
 
 /* Defined in alloc.c.  */
 extern void *my_heap_start (void);
-extern void check_pure_size (void);
 unsigned char *resize_string_data (Lisp_Object, ptrdiff_t, int, int);
 extern void malloc_warning (const char *);
 extern AVOID memory_full (size_t);
@@ -3813,11 +3799,8 @@ flush_stack_call_func (void (*func) (void *arg), void *arg)
 extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
 			  Lisp_Object);
 extern Lisp_Object listn (ptrdiff_t, Lisp_Object, ...);
-extern Lisp_Object pure_listn (ptrdiff_t, Lisp_Object, ...);
 #define list(...) \
   listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
-#define pure_list(...) \
-  pure_listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
 
 enum gc_root_type
 {
@@ -3890,17 +3873,6 @@ build_unibyte_string (const char *str)
 extern Lisp_Object make_string_from_bytes (const char *, ptrdiff_t, ptrdiff_t);
 extern Lisp_Object make_specified_string (const char *,
 					  ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_string (const char *, ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_c_string (const char *, ptrdiff_t);
-
-/* Make a string allocated in pure space, use STR as string data.  */
-
-INLINE Lisp_Object
-build_pure_c_string (const char *str)
-{
-  return make_pure_c_string (str, strlen (str));
-}
-
 /* Make a string from the data at STR, treating it as multibyte if the
    data warrants.  */
 
@@ -3910,7 +3882,6 @@ build_string (const char *str)
   return make_string (str, strlen (str));
 }
 
-extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
 extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
 extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
 
diff --git a/src/lread.c b/src/lread.c
index dea1b232fff83..033e9ba41af16 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2098,13 +2098,13 @@ readevalloop (Lisp_Object readcharfun,
 	read_objects_map
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (! HASH_TABLE_P (read_objects_completed)
 	  || XHASH_TABLE (read_objects_completed)->count)
 	read_objects_completed
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (!NILP (Vpurify_flag) && c == '(')
 	{
 	  val = read_list (0, readcharfun);
@@ -2321,12 +2321,12 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
       || XHASH_TABLE (read_objects_map)->count)
     read_objects_map
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (! HASH_TABLE_P (read_objects_completed)
       || XHASH_TABLE (read_objects_completed)->count)
     read_objects_completed
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (EQ (Vread_with_symbol_positions, Qt)
       || EQ (Vread_with_symbol_positions, stream))
     Vread_symbol_positions_list = Qnil;
@@ -2896,11 +2896,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      if (!NILP (params[param_count + 1]))
 		param_count += 2;
 
-              params[param_count] = QCpurecopy;
-              params[param_count + 1] = Fplist_get (tmp, Qpurecopy);
-              if (!NILP (params[param_count + 1]))
-                param_count += 2;
-
 	      /* This is the hash table data.  */
 	      data = Fplist_get (tmp, Qdata);
 
@@ -3210,13 +3205,13 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      /* No symbol character follows, this is the empty
 		 symbol.  */
 	      UNREAD (c);
-	      return Fmake_symbol (empty_unibyte_string);
+	      return Fmake_symbol (build_string (""));
 	    }
 	  goto read_symbol;
 	}
       /* ## is the empty symbol.  */
       if (c == '#')
-	return Fintern (empty_unibyte_string, Qnil);
+	return Fintern (build_string (""), Qnil);
 
       if (c >= '0' && c <= '9')
 	{
@@ -3612,9 +3607,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	  if (uninterned_symbol)
 	    {
 	      Lisp_Object name
-		= ((! NILP (Vpurify_flag)
-		    ? make_pure_string : make_specified_string)
-		   (read_buffer, nchars, nbytes, multibyte));
+		= make_specified_string (read_buffer, nchars, nbytes,
+					 multibyte);
 	      result = Fmake_symbol (name);
 	    }
 	  else
@@ -4204,10 +4198,8 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 
   if (!SYMBOLP (tem))
     {
-      /* Creating a non-pure string from a string literal not implemented yet.
-	 We could just use make_string here and live with the extra copy.  */
       eassert (!NILP (Vpurify_flag));
-      tem = intern_driver (make_pure_c_string (str, len), obarray, tem);
+      tem = intern_driver (make_string (str, len), obarray, tem);
     }
   return tem;
 }
@@ -4216,7 +4208,7 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 define_symbol (Lisp_Object sym, char const *str)
 {
   ptrdiff_t len = strlen (str);
-  Lisp_Object string = make_pure_c_string (str, len);
+  Lisp_Object string = make_string (str, len);
   init_symbol (sym, string);
 
   /* Qunbound is uninterned, so that it's not confused with any symbol
@@ -4243,8 +4235,7 @@ DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
 
   tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
   if (!SYMBOLP (tem))
-    tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
-			 obarray, tem);
+    tem = intern_driver (string, obarray, tem);
   return tem;
 }
 
@@ -4893,23 +4884,23 @@ syms_of_lread (void)
 to the specified file name if a suffix is allowed or required.  */);
 #ifdef HAVE_MODULES
 #ifdef MODULES_SECONDARY_SUFFIX
-  Vload_suffixes = list4 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX),
-                          build_pure_c_string (MODULES_SECONDARY_SUFFIX));
+  Vload_suffixes = list4 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX),
+                          build_string (MODULES_SECONDARY_SUFFIX));
 #else
-  Vload_suffixes = list3 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX));
+  Vload_suffixes = list3 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX));
 #endif
 #else
-  Vload_suffixes = list2 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"));
+  Vload_suffixes = list2 (build_string (".elc"),
+			  build_string (".el"));
 #endif
   DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
 	       doc: /* Suffix of loadable module file, or nil if modules are not supported.  */);
 #ifdef HAVE_MODULES
-  Vmodule_file_suffix = build_pure_c_string (MODULES_SUFFIX);
+  Vmodule_file_suffix = build_string (MODULES_SUFFIX);
 #else
   Vmodule_file_suffix = Qnil;
 #endif
@@ -5052,7 +5043,7 @@ syms_of_lread (void)
 When the regular expression matches, the file is considered to be safe
 to load.  */);
   Vbytecomp_version_regexp
-    = build_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
   DEFSYM (Qlexical_binding, "lexical-binding");
   DEFVAR_LISP ("lexical-binding", Vlexical_binding,
diff --git a/src/pdumper.c b/src/pdumper.c
index 337742fda4ade..a8fbac161a8cf 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2440,7 +2440,6 @@ dump_symbol (struct dump_context *ctx,
   DUMP_FIELD_COPY (&out, symbol, u.s.trapped_write);
   DUMP_FIELD_COPY (&out, symbol, u.s.interned);
   DUMP_FIELD_COPY (&out, symbol, u.s.declared_special);
-  DUMP_FIELD_COPY (&out, symbol, u.s.pinned);
   dump_field_lv (ctx, &out, symbol, &symbol->u.s.name, WEIGHT_STRONG);
   switch (symbol->u.s.redirect)
     {
@@ -2673,7 +2672,6 @@ dump_hash_table (struct dump_context *ctx,
      them as close to the hash table as possible.  */
   DUMP_FIELD_COPY (out, hash, count);
   DUMP_FIELD_COPY (out, hash, next_free);
-  DUMP_FIELD_COPY (out, hash, purecopy);
   DUMP_FIELD_COPY (out, hash, mutable);
   DUMP_FIELD_COPY (out, hash, rehash_threshold);
   DUMP_FIELD_COPY (out, hash, rehash_size);
@@ -5467,8 +5465,6 @@ DEFUN ("pdumper-stats", Fpdumper_stats, Spdumper_stats, 0, 0, 0,
 		Fcons (Qdump_file_name, dump_fn));
 }
 
-#endif /* HAVE_PDUMPER */
-
 \f
 static void
 thaw_hash_tables (void)
@@ -5483,6 +5479,7 @@ init_pdumper_once (void)
 {
   pdumper_do_now_and_after_load (thaw_hash_tables);
 }
+#endif /* HAVE_PDUMPER */
 
 void
 syms_of_pdumper (void)
diff --git a/src/print.c b/src/print.c
index 14af9195475ef..df008cf3b1296 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1581,12 +1581,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 	print_object (Fhash_table_rehash_threshold (obj),
 		      printcharfun, escapeflag);
 
-	if (h->purecopy)
-	  {
-	    print_c_string (" purecopy ", printcharfun);
-	    print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
-	  }
-
 	print_c_string (" data ", printcharfun);
 
 	/* Print the data here as a plist. */
diff --git a/src/process.c b/src/process.c
index b98bc297a3f3f..90a1141ab6564 100644
--- a/src/process.c
+++ b/src/process.c
@@ -8566,7 +8566,7 @@ syms_of_process (void)
    const struct socket_options *sopt;
 
 #define ADD_SUBFEATURE(key, val) \
-  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
+  subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures)
 
    ADD_SUBFEATURE (QCnowait, Qt);
 #ifdef DATAGRAM_SOCKETS
@@ -8588,7 +8588,7 @@ #define ADD_SUBFEATURE(key, val) \
    ADD_SUBFEATURE (QCserver, Qt);
 
    for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
+     subfeatures = Fcons (intern_c_string (sopt->name), subfeatures);
 
    Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
diff --git a/src/profiler.c b/src/profiler.c
index 21ae2447aa4ee..44bf57eba2078 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -63,7 +63,7 @@ make_log (void)
   Lisp_Object log = make_hash_table (hashtest_profiler, heap_size,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
   struct Lisp_Hash_Table *h = XHASH_TABLE (log);
 
   /* What is special about our hash-tables is that the values are pre-filled
diff --git a/src/puresize.h b/src/puresize.h
deleted file mode 100644
index 811d0b4d36952..0000000000000
--- a/src/puresize.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* How much read-only Lisp storage a dumped Emacs needs.
-   Copyright (C) 1993, 2001-2021 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
-
-#ifndef EMACS_PURESIZE_H
-#define EMACS_PURESIZE_H
-
-#include "lisp.h"
-
-INLINE_HEADER_BEGIN
-
-/* Define PURESIZE, the number of bytes of pure Lisp code to leave space for.
-
-   At one point, this was defined in config.h, meaning that changing
-   PURESIZE would make Make recompile all of Emacs.  But only a few
-   files actually use PURESIZE, so we split it out to its own .h file.
-
-   Make sure to include this file after config.h, since that tells us
-   whether we are running X windows, which tells us how much pure
-   storage to allocate.  */
-
-/* First define a measure of the amount of data we have.  */
-
-/* A system configuration file may set this to request a certain extra
-   amount of storage.  This is a lot more update-robust that defining
-   BASE_PURESIZE or even PURESIZE directly.  */
-#ifndef SYSTEM_PURESIZE_EXTRA
-#define SYSTEM_PURESIZE_EXTRA 0
-#endif
-
-#ifndef SITELOAD_PURESIZE_EXTRA
-#define SITELOAD_PURESIZE_EXTRA 0
-#endif
-
-#ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA)
-#endif
-
-/* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
-#ifndef PURESIZE_RATIO
-#if EMACS_INT_MAX >> 31 != 0
-#if PTRDIFF_MAX >> 31 != 0
-#define PURESIZE_RATIO 10 / 6	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_RATIO 8 / 6	/* Don't surround with `()'.  */
-#endif
-#else
-#define PURESIZE_RATIO 1
-#endif
-#endif
-
-#ifdef ENABLE_CHECKING
-/* ENABLE_CHECKING somehow increases the purespace used, probably because
-   it tends to cause some macro arguments to be evaluated twice.  This is
-   a bug, but it's difficult to track it down.  */
-#define PURESIZE_CHECKING_RATIO 12 / 10	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_CHECKING_RATIO 1
-#endif
-
-/* This is the actual size in bytes to allocate.  */
-#ifndef PURESIZE
-#define PURESIZE  (BASE_PURESIZE * PURESIZE_RATIO * PURESIZE_CHECKING_RATIO)
-#endif
-
-extern AVOID pure_write_error (Lisp_Object);
-
-extern EMACS_INT pure[];
-
-/* The puresize_h_* macros are private to this include file.  */
-
-/* True if PTR is pure.  */
-
-#define puresize_h_PURE_P(ptr) \
-  ((uintptr_t) (ptr) - (uintptr_t) pure <= PURESIZE)
-
-INLINE bool
-PURE_P (void *ptr)
-{
-  return puresize_h_PURE_P (ptr);
-}
-
-/* Signal an error if OBJ is pure.  PTR is OBJ untagged.  */
-
-#define puresize_h_CHECK_IMPURE(obj, ptr) \
-  (PURE_P (ptr) ? pure_write_error (obj) : (void) 0)
-
-INLINE void
-CHECK_IMPURE (Lisp_Object obj, void *ptr)
-{
-  puresize_h_CHECK_IMPURE (obj, ptr);
-}
-
-#if DEFINE_KEY_OPS_AS_MACROS
-# define PURE_P(ptr) puresize_h_PURE_P (ptr)
-# define CHECK_IMPURE(obj, ptr) puresize_h_CHECK_IMPURE (obj, ptr)
-#endif
-
-INLINE_HEADER_END
-
-#endif /* EMACS_PURESIZE_H */
diff --git a/src/search.c b/src/search.c
index c757bf3d1f281..5a214db0092d2 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3354,19 +3354,19 @@ syms_of_search (void)
   DEFSYM (Qinvalid_regexp, "invalid-regexp");
 
   Fput (Qsearch_failed, Qerror_conditions,
-	pure_list (Qsearch_failed, Qerror));
+	list (Qsearch_failed, Qerror));
   Fput (Qsearch_failed, Qerror_message,
-	build_pure_c_string ("Search failed"));
+	build_string ("Search failed"));
 
   Fput (Quser_search_failed, Qerror_conditions,
-	pure_list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
+	list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
   Fput (Quser_search_failed, Qerror_message,
-        build_pure_c_string ("Search failed"));
+        build_string ("Search failed"));
 
   Fput (Qinvalid_regexp, Qerror_conditions,
-	pure_list (Qinvalid_regexp, Qerror));
+	list (Qinvalid_regexp, Qerror));
   Fput (Qinvalid_regexp, Qerror_message,
-	build_pure_c_string ("Invalid regexp"));
+	build_string ("Invalid regexp"));
 
   re_match_object = Qnil;
   staticpro (&re_match_object);
diff --git a/src/syntax.c b/src/syntax.c
index 9fbf88535f3ec..993f91af19ac0 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3719,9 +3719,9 @@ syms_of_syntax (void)
 
   DEFSYM (Qscan_error, "scan-error");
   Fput (Qscan_error, Qerror_conditions,
-	pure_list (Qscan_error, Qerror));
+	list (Qscan_error, Qerror));
   Fput (Qscan_error, Qerror_message,
-	build_pure_c_string ("Scan error"));
+	build_string ("Scan error"));
 
   DEFVAR_BOOL ("parse-sexp-ignore-comments", parse_sexp_ignore_comments,
 	       doc: /* Non-nil means `forward-sexp', etc., should treat comments as whitespace.  */);
diff --git a/src/w32fns.c b/src/w32fns.c
index 9db367bfafe75..3b3ad2f55b9aa 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10390,9 +10390,9 @@ syms_of_w32fns (void)
   DEFSYM (Qjson, "json");
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   staticpro (&w32_grabbed_keys);
   w32_grabbed_keys = Qnil;
diff --git a/src/xdisp.c b/src/xdisp.c
index cc0a689ba32e9..38099350d6761 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -34862,7 +34862,7 @@ syms_of_xdisp (void)
   staticpro (&echo_area_buffer[0]);
   staticpro (&echo_area_buffer[1]);
 
-  Vmessages_buffer_name = build_pure_c_string ("*Messages*");
+  Vmessages_buffer_name = build_string ("*Messages*");
   staticpro (&Vmessages_buffer_name);
 
   mode_line_proptrans_alist = Qnil;
@@ -34954,7 +34954,7 @@ syms_of_xdisp (void)
   DEFVAR_LISP ("overlay-arrow-string", Voverlay_arrow_string,
     doc: /* String to display as an arrow in non-window frames.
 See also `overlay-arrow-position'.  */);
-  Voverlay_arrow_string = build_pure_c_string ("=>");
+  Voverlay_arrow_string = build_string ("=>");
 
   DEFVAR_LISP ("overlay-arrow-variable-list", Voverlay_arrow_variable_list,
     doc: /* List of variables (symbols) which hold markers for overlay arrows.
@@ -35079,17 +35079,17 @@ syms_of_xdisp (void)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
 \(see `modify-frame-parameters').  */);
-  /* Do not nest calls to pure_list.  This works around a bug in
+  /* Do not nest calls to list.  This works around a bug in
      Oracle Developer Studio 12.6.  */
   Lisp_Object icon_title_name_format
-    = pure_list (empty_unibyte_string,
-		 build_pure_c_string ("%b - GNU Emacs at "),
-		 intern_c_string ("system-name"));
+    = list (empty_unibyte_string,
+	    build_string ("%b - GNU Emacs at "),
+	    intern_c_string ("system-name"));
   Vicon_title_format
     = Vframe_title_format
-    = pure_list (intern_c_string ("multiple-frames"),
-		 build_pure_c_string ("%b"),
-		 icon_title_name_format);
+    = list (intern_c_string ("multiple-frames"),
+	    build_string ("%b"),
+	    icon_title_name_format);
 
   DEFVAR_LISP ("message-log-max", Vmessage_log_max,
     doc: /* Maximum number of lines to keep in the message log buffer.
diff --git a/src/xfaces.c b/src/xfaces.c
index ab4440f46ad0d..6cb08b0475cba 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -7044,7 +7044,7 @@ syms_of_xfaces (void)
 This stipple pattern is used on monochrome displays
 instead of shades of gray for a face background color.
 See `set-face-stipple' for possible values for this variable.  */);
-  Vface_default_stipple = build_pure_c_string ("gray3");
+  Vface_default_stipple = build_string ("gray3");
 
   DEFVAR_LISP ("tty-defined-color-alist", Vtty_defined_color_alist,
    doc: /* An alist of defined terminal colors and their RGB values.
diff --git a/src/xfns.c b/src/xfns.c
index d90644819b6f5..e9ead35ccccb5 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -7878,9 +7878,9 @@ syms_of_xfns (void)
 #endif
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
     doc: /* The shape of the pointer when over text.
@@ -8091,7 +8091,7 @@ syms_of_xfns (void)
     char gtk_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
     int len = sprintf (gtk_version, "%d.%d.%d",
 		       GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
-    Vgtk_version_string = make_pure_string (gtk_version, len, len, false);
+    Vgtk_version_string = make_specified_string (gtk_version, len, len, false);
   }
 #endif /* USE_GTK */
 
@@ -8105,7 +8105,8 @@ syms_of_xfns (void)
     int len = sprintf (cairo_version, "%d.%d.%d",
 		       CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
                        CAIRO_VERSION_MICRO);
-    Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+    Vcairo_version_string = make_specified_string (cairo_version, len, len,
+						   false);
   }
 #endif
 
diff --git a/src/xterm.c b/src/xterm.c
index 744b80c68a002..437c08b526f60 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13649,7 +13649,7 @@ syms_of_xterm (void)
   DEFSYM (Qlatin_1, "latin-1");
 
 #ifdef USE_GTK
-  xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
+  xg_default_icon_file = build_string ("icons/hicolor/scalable/apps/emacs.svg");
   staticpro (&xg_default_icon_file);
 
   DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
@@ -13770,7 +13770,7 @@ syms_of_xterm (void)
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
 
   DEFVAR_BOOL ("x-frame-normalize-before-maximize",
 	       x_frame_normalize_before_maximize,
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-03 15:34                                             ` Pip Cet
@ 2021-03-04 12:55                                               ` Pip Cet
  2021-03-04 14:56                                                 ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2021-03-04 12:55 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: 36649, larsi, eggert, Andreas Schwab, Andrea Corallo

[-- Attachment #1: Type: text/plain, Size: 335 bytes --]

On Wed, Mar 3, 2021 at 3:34 PM Pip Cet <pipcet@gmail.com> wrote:
> I have time for that now, so here's a revised patch as a first step.

This patch removes pure space from Emacs 28.

Changes:
- now builds with --enable-checking=all

Todo:
- commit message not yet final.
- zero vector handling depends on Qnil being all zero in memory

[-- Attachment #2: 0001-Remove-pure-space-Bug-36649.patch --]
[-- Type: text/x-patch, Size: 88595 bytes --]

From 59bfbc0e18a71f5d9e4714b39befa09896d8eab3 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Wed, 3 Mar 2021 15:27:02 +0000
Subject: [PATCH] Remove pure space (Bug#36649)

* src/lisp.h (struct Lisp_Symbol): Remove `pinned' flag.
(build_pure_c_string, pure_listn): Remove.  All calls removed.
* src/puresize.h: Remove file.
* src/fns.c (Fmake_hash_table): Ignore `:purecopy' argument.
* src/doc.c (store_function_docstring): Remove comment about pure
space.
* src/data.c (pure_write_error): Remove.  All calls removed.
* src/conf_post.h (SYSTEM_PURESIZE_EXTRA): Remove.
* src/fns.c (make_hash_table): Drop `purecopy' argument.  All
callers changed to remove argument.
* src/alloc.c (make_pure_string, make_pure_c_string, pure_cons)
(pure_list): Remove.  All calls removed.
(check_pure_size): Remove.  All calls removed.
(cons_listn): Simplify.
(Fmake_byte_code): Remove comment about pure space.
(pointer_align): Move definition to avoid warning.
* src/Makefile.in: Remove comment about pure space.
---
 src/Makefile.in    |   2 -
 src/alloc.c        | 549 ++++-----------------------------------------
 src/buffer.c       |  16 +-
 src/callint.c      |   8 +-
 src/category.c     |   4 +-
 src/coding.c       |  18 +-
 src/conf_post.h    |  33 ---
 src/data.c         |  29 +--
 src/dbusbind.c     |   4 +-
 src/deps.mk        |  10 +-
 src/doc.c          |   3 -
 src/emacs-module.c |  28 +--
 src/emacs.c        |   5 +-
 src/eval.c         |  12 +-
 src/fileio.c       |  22 +-
 src/fns.c          |  32 +--
 src/fontset.c      |   4 +-
 src/frame.c        |   2 +-
 src/image.c        |   2 +-
 src/intervals.c    |   2 -
 src/json.c         |   4 +-
 src/keyboard.c     |   8 +-
 src/keymap.c       |  34 ++-
 src/lisp.h         |  41 +---
 src/lread.c        |  53 ++---
 src/pdumper.c      |   9 +-
 src/print.c        |   6 -
 src/process.c      |   4 +-
 src/profiler.c     |   2 +-
 src/puresize.h     | 115 ----------
 src/search.c       |  12 +-
 src/syntax.c       |   4 +-
 src/w32fns.c       |   4 +-
 src/xdisp.c        |  18 +-
 src/xfaces.c       |   2 +-
 src/xfns.c         |   9 +-
 src/xterm.c        |   4 +-
 37 files changed, 199 insertions(+), 915 deletions(-)
 delete mode 100644 src/puresize.h

diff --git a/src/Makefile.in b/src/Makefile.in
index 4100edf4712fe..0330b2d354b18 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -406,8 +406,6 @@ .c.o:
 .m.o:
 	$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
 
-## lastfile must follow all files whose initialized data areas should
-## be dumped as pure by dump-emacs.
 base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
 	charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \
 	$(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \
diff --git a/src/alloc.c b/src/alloc.c
index e72fc4c4332de..05c25e10f1441 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -34,7 +34,6 @@ Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2021 Free Software
 #include "bignum.h"
 #include "dispextern.h"
 #include "intervals.h"
-#include "puresize.h"
 #include "sheap.h"
 #include "sysstdio.h"
 #include "systime.h"
@@ -333,33 +332,6 @@ #define HI_THRESHOLD (EMACS_INT_MAX / 2)
 
 #define SPARE_MEMORY (1 << 14)
 
-/* Initialize it to a nonzero value to force it into data space
-   (rather than bss space).  That way unexec will remap it into text
-   space (pure), on some systems.  We have not implemented the
-   remapping on more recent systems because this is less important
-   nowadays than in the days of small memories and timesharing.  */
-
-EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,};
-#define PUREBEG (char *) pure
-
-/* Pointer to the pure area, and its size.  */
-
-static char *purebeg;
-static ptrdiff_t pure_size;
-
-/* Number of bytes of pure storage used before pure storage overflowed.
-   If this is non-zero, this implies that an overflow occurred.  */
-
-static ptrdiff_t pure_bytes_used_before_overflow;
-
-/* Index in pure at which next pure Lisp object will be allocated..  */
-
-static ptrdiff_t pure_bytes_used_lisp;
-
-/* Number of bytes allocated for non-Lisp objects in pure storage.  */
-
-static ptrdiff_t pure_bytes_used_non_lisp;
-
 /* If positive, garbage collection is inhibited.  Otherwise, zero.  */
 
 static intptr_t garbage_collection_inhibited;
@@ -434,7 +406,6 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
 static void unchain_finalizer (struct Lisp_Finalizer *);
 static void mark_terminals (void);
 static void gc_sweep (void);
-static Lisp_Object make_pure_vector (ptrdiff_t);
 static void mark_buffer (struct buffer *);
 
 #if !defined REL_ALLOC || defined SYSTEM_MALLOC || defined HYBRID_MALLOC
@@ -576,16 +547,6 @@ #define MEM_NIL &mem_z
 
 int staticidx;
 
-static void *pure_alloc (size_t, int);
-
-/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
-
-static void *
-pointer_align (void *ptr, int alignment)
-{
-  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
-}
-
 /* Extract the pointer hidden within O.  */
 
 static ATTRIBUTE_NO_SANITIZE_UNDEFINED void *
@@ -1075,6 +1036,15 @@ verify (POWER_OF_2 (BLOCK_ALIGN));
 # elif !defined HYBRID_MALLOC && defined HAVE_POSIX_MEMALIGN
 #  define USE_ALIGNED_ALLOC 1
 #  define aligned_alloc my_aligned_alloc /* Avoid collision with lisp.h.  */
+
+/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
+
+static void *
+pointer_align (void *ptr, int alignment)
+{
+  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
+}
+
 static void *
 aligned_alloc (size_t alignment, size_t size)
 {
@@ -1679,9 +1649,9 @@ #define GC_STRING_EXTRA GC_STRING_OVERRUN_COOKIE_SIZE
 static void
 init_strings (void)
 {
-  empty_unibyte_string = make_pure_string ("", 0, 0, 0);
+  empty_unibyte_string = make_specified_string ("", 0, 0, false);
   staticpro (&empty_unibyte_string);
-  empty_multibyte_string = make_pure_string ("", 0, 0, 1);
+  empty_multibyte_string = make_specified_string ("", 0, 0, true);
   staticpro (&empty_multibyte_string);
 }
 
@@ -1699,7 +1669,7 @@ string_bytes (struct Lisp_String *s)
   ptrdiff_t nbytes =
     (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
 
-  if (!PURE_P (s) && !pdumper_object_p (s) && s->u.s.data
+  if (!pdumper_object_p (s) && s->u.s.data
       && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
     emacs_abort ();
   return nbytes;
@@ -2415,7 +2385,7 @@ make_specified_string (const char *contents,
 {
   Lisp_Object val;
 
-  if (nchars < 0)
+  if (nchars <= 0)
     {
       if (multibyte)
 	nchars = multibyte_chars_in_text ((const unsigned char *) contents,
@@ -2469,8 +2439,6 @@ make_clear_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes, bool clearit)
 
   if (nchars < 0)
     emacs_abort ();
-  if (!nbytes)
-    return empty_multibyte_string;
 
   s = allocate_string ();
   s->u.s.intervals = NULL;
@@ -2751,17 +2719,16 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4,
 }
 
 /* Make a list of COUNT Lisp_Objects, where ARG is the first one.
-   Use CONS to construct the pairs.  AP has any remaining args.  */
+   AP has any remaining args.  */
 static Lisp_Object
-cons_listn (ptrdiff_t count, Lisp_Object arg,
-	    Lisp_Object (*cons) (Lisp_Object, Lisp_Object), va_list ap)
+cons_listn (ptrdiff_t count, Lisp_Object arg, va_list ap)
 {
   eassume (0 < count);
-  Lisp_Object val = cons (arg, Qnil);
+  Lisp_Object val = Fcons (arg, Qnil);
   Lisp_Object tail = val;
   for (ptrdiff_t i = 1; i < count; i++)
     {
-      Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil);
+      Lisp_Object elem = Fcons (va_arg (ap, Lisp_Object), Qnil);
       XSETCDR (tail, elem);
       tail = elem;
     }
@@ -2774,18 +2741,7 @@ listn (ptrdiff_t count, Lisp_Object arg1, ...)
 {
   va_list ap;
   va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, Fcons, ap);
-  va_end (ap);
-  return val;
-}
-
-/* Make a pure list of COUNT Lisp_Objects, where ARG1 is the first one.  */
-Lisp_Object
-pure_listn (ptrdiff_t count, Lisp_Object arg1, ...)
-{
-  va_list ap;
-  va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, pure_cons, ap);
+  Lisp_Object val = cons_listn (count, arg1, ap);
   va_end (ap);
   return val;
 }
@@ -2951,7 +2907,7 @@ large_vector_vec (struct large_vector *p)
 
 static struct large_vector *large_vectors;
 
-/* The only vector with 0 slots, allocated from pure space.  */
+/* The only vector with 0 slots.  */
 
 Lisp_Object zero_vector;
 
@@ -2987,15 +2943,6 @@ allocate_vector_block (void)
   return block;
 }
 
-/* Called once to initialize vector allocation.  */
-
-static void
-init_vectors (void)
-{
-  zero_vector = make_pure_vector (0);
-  staticpro (&zero_vector);
-}
-
 /* Allocate vector from a vector block.  */
 
 static struct Lisp_Vector *
@@ -3268,7 +3215,7 @@ #define VECTOR_ELTS_MAX \
 static struct Lisp_Vector *
 allocate_vectorlike (ptrdiff_t len, bool clearit)
 {
-  eassert (0 < len && len <= VECTOR_ELTS_MAX);
+  eassert (0 <= len && len <= VECTOR_ELTS_MAX);
   ptrdiff_t nbytes = header_size + len * word_size;
   struct Lisp_Vector *p;
 
@@ -3343,6 +3290,18 @@ allocate_nil_vector (ptrdiff_t len)
 }
 
 
+/* Called once to initialize vector allocation.  */
+
+static void
+init_vectors (void)
+{
+  zero_vector =
+    make_lisp_ptr (allocate_vectorlike (8, true), Lisp_Vectorlike);
+  XVECTOR (zero_vector)->header.size = 0;
+  XVECTOR (zero_vector)->contents[0] = Qnil;
+  staticpro (&zero_vector);
+}
+
 /* Allocate other vector-like structures.  */
 
 struct Lisp_Vector *
@@ -3555,13 +3514,6 @@ #define SYMBOL_BLOCK_SIZE \
 
 static struct symbol_block *symbol_block;
 static int symbol_block_index = SYMBOL_BLOCK_SIZE;
-/* Pointer to the first symbol_block that contains pinned symbols.
-   Tests for 24.4 showed that at dump-time, Emacs contains about 15K symbols,
-   10K of which are pinned (and all but 250 of them are interned in obarray),
-   whereas a "typical session" has in the order of 30K symbols.
-   `symbol_block_pinned' lets mark_pinned_symbols scan only 15K symbols rather
-   than 30K to find the 10K symbols we need to mark.  */
-static struct symbol_block *symbol_block_pinned;
 
 /* List of free symbols.  */
 
@@ -3587,7 +3539,6 @@ init_symbol (Lisp_Object val, Lisp_Object name)
   p->u.s.interned = SYMBOL_UNINTERNED;
   p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
   p->u.s.declared_special = false;
-  p->u.s.pinned = false;
 }
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
@@ -5151,8 +5102,6 @@ valid_lisp_object_p (Lisp_Object obj)
     return 1;
 
   void *p = XPNTR (obj);
-  if (PURE_P (p))
-    return 1;
 
   if (SYMBOLP (obj) && c_symbol_p (p))
     return ((char *) p - (char *) lispsym) % sizeof lispsym[0] == 0;
@@ -5208,296 +5157,8 @@ valid_lisp_object_p (Lisp_Object obj)
   return 0;
 }
 
-/***********************************************************************
-		       Pure Storage Management
- ***********************************************************************/
-
-/* Allocate room for SIZE bytes from pure Lisp storage and return a
-   pointer to it.  TYPE is the Lisp type for which the memory is
-   allocated.  TYPE < 0 means it's not used for a Lisp object,
-   and that the result should have an alignment of -TYPE.
-
-   The bytes are initially zero.
-
-   If pure space is exhausted, allocate space from the heap.  This is
-   merely an expedient to let Emacs warn that pure space was exhausted
-   and that Emacs should be rebuilt with a larger pure space.  */
-
-static void *
-pure_alloc (size_t size, int type)
-{
-  void *result;
-
- again:
-  if (type >= 0)
-    {
-      /* Allocate space for a Lisp object from the beginning of the free
-	 space with taking account of alignment.  */
-      result = pointer_align (purebeg + pure_bytes_used_lisp, LISP_ALIGNMENT);
-      pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size;
-    }
-  else
-    {
-      /* Allocate space for a non-Lisp object from the end of the free
-	 space.  */
-      ptrdiff_t unaligned_non_lisp = pure_bytes_used_non_lisp + size;
-      char *unaligned = purebeg + pure_size - unaligned_non_lisp;
-      int decr = (intptr_t) unaligned & (-1 - type);
-      pure_bytes_used_non_lisp = unaligned_non_lisp + decr;
-      result = unaligned - decr;
-    }
-  pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp;
-
-  if (pure_bytes_used <= pure_size)
-    return result;
-
-  /* Don't allocate a large amount here,
-     because it might get mmap'd and then its address
-     might not be usable.  */
-  int small_amount = 10000;
-  eassert (size <= small_amount - LISP_ALIGNMENT);
-  purebeg = xzalloc (small_amount);
-  pure_size = small_amount;
-  pure_bytes_used_before_overflow += pure_bytes_used - size;
-  pure_bytes_used = 0;
-  pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0;
-
-  /* Can't GC if pure storage overflowed because we can't determine
-     if something is a pure object or not.  */
-  garbage_collection_inhibited++;
-  goto again;
-}
-
-
-#ifdef HAVE_UNEXEC
-
-/* Print a warning if PURESIZE is too small.  */
-
-void
-check_pure_size (void)
-{
-  if (pure_bytes_used_before_overflow)
-    message (("emacs:0:Pure Lisp storage overflow (approx. %"pI"d"
-	      " bytes needed)"),
-	     pure_bytes_used + pure_bytes_used_before_overflow);
-}
-#endif
-
-
-/* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
-   the non-Lisp data pool of the pure storage, and return its start
-   address.  Return NULL if not found.  */
-
-static char *
-find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
-{
-  int i;
-  ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max;
-  const unsigned char *p;
-  char *non_lisp_beg;
-
-  if (pure_bytes_used_non_lisp <= nbytes)
-    return NULL;
-
-  /* Set up the Boyer-Moore table.  */
-  skip = nbytes + 1;
-  for (i = 0; i < 256; i++)
-    bm_skip[i] = skip;
-
-  p = (const unsigned char *) data;
-  while (--skip > 0)
-    bm_skip[*p++] = skip;
-
-  last_char_skip = bm_skip['\0'];
-
-  non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp;
-  start_max = pure_bytes_used_non_lisp - (nbytes + 1);
-
-  /* See the comments in the function `boyer_moore' (search.c) for the
-     use of `infinity'.  */
-  infinity = pure_bytes_used_non_lisp + 1;
-  bm_skip['\0'] = infinity;
-
-  p = (const unsigned char *) non_lisp_beg + nbytes;
-  start = 0;
-  do
-    {
-      /* Check the last character (== '\0').  */
-      do
-	{
-	  start += bm_skip[*(p + start)];
-	}
-      while (start <= start_max);
-
-      if (start < infinity)
-	/* Couldn't find the last character.  */
-	return NULL;
-
-      /* No less than `infinity' means we could find the last
-	 character at `p[start - infinity]'.  */
-      start -= infinity;
-
-      /* Check the remaining characters.  */
-      if (memcmp (data, non_lisp_beg + start, nbytes) == 0)
-	/* Found.  */
-	return non_lisp_beg + start;
-
-      start += last_char_skip;
-    }
-  while (start <= start_max);
-
-  return NULL;
-}
-
-
-/* Return a string allocated in pure space.  DATA is a buffer holding
-   NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
-   means make the result string multibyte.
-
-   Must get an error if pure storage is full, since if it cannot hold
-   a large string it may be able to hold conses that point to that
-   string; then the string is not protected from gc.  */
-
-Lisp_Object
-make_pure_string (const char *data,
-		  ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->u.s.data == NULL)
-    {
-      s->u.s.data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->u.s.data, data, nbytes);
-      s->u.s.data[nbytes] = '\0';
-    }
-  s->u.s.size = nchars;
-  s->u.s.size_byte = multibyte ? nbytes : -1;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-/* Return a string allocated in pure space.  Do not
-   allocate the string data, just point to DATA.  */
-
-Lisp_Object
-make_pure_c_string (const char *data, ptrdiff_t nchars)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.size = nchars;
-  s->u.s.size_byte = -2;
-  s->u.s.data = (unsigned char *) data;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-static Lisp_Object purecopy (Lisp_Object obj);
-
-/* Return a cons allocated from pure space.  Give it pure copies
-   of CAR as car and CDR as cdr.  */
-
-Lisp_Object
-pure_cons (Lisp_Object car, Lisp_Object cdr)
-{
-  Lisp_Object new;
-  struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons);
-  XSETCONS (new, p);
-  XSETCAR (new, purecopy (car));
-  XSETCDR (new, purecopy (cdr));
-  return new;
-}
-
-
-/* Value is a float object with value NUM allocated from pure space.  */
-
-static Lisp_Object
-make_pure_float (double num)
-{
-  Lisp_Object new;
-  struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float);
-  XSETFLOAT (new, p);
-  XFLOAT_INIT (new, num);
-  return new;
-}
-
-/* Value is a bignum object with value VALUE allocated from pure
-   space.  */
-
 static Lisp_Object
-make_pure_bignum (Lisp_Object value)
-{
-  mpz_t const *n = xbignum_val (value);
-  size_t i, nlimbs = mpz_size (*n);
-  size_t nbytes = nlimbs * sizeof (mp_limb_t);
-  mp_limb_t *pure_limbs;
-  mp_size_t new_size;
-
-  struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike);
-  XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum));
-
-  int limb_alignment = alignof (mp_limb_t);
-  pure_limbs = pure_alloc (nbytes, - limb_alignment);
-  for (i = 0; i < nlimbs; ++i)
-    pure_limbs[i] = mpz_getlimbn (*n, i);
-
-  new_size = nlimbs;
-  if (mpz_sgn (*n) < 0)
-    new_size = -new_size;
-
-  mpz_roinit_n (b->value, pure_limbs, new_size);
-
-  return make_lisp_ptr (b, Lisp_Vectorlike);
-}
-
-/* Return a vector with room for LEN Lisp_Objects allocated from
-   pure space.  */
-
-static Lisp_Object
-make_pure_vector (ptrdiff_t len)
-{
-  Lisp_Object new;
-  size_t size = header_size + len * word_size;
-  struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike);
-  XSETVECTOR (new, p);
-  XVECTOR (new)->header.size = len;
-  return new;
-}
-
-/* Copy all contents and parameters of TABLE to a new table allocated
-   from pure space, return the purified table.  */
-static struct Lisp_Hash_Table *
-purecopy_hash_table (struct Lisp_Hash_Table *table)
-{
-  eassert (NILP (table->weak));
-  eassert (table->purecopy);
-
-  struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
-  struct hash_table_test pure_test = table->test;
-
-  /* Purecopy the hash table test.  */
-  pure_test.name = purecopy (table->test.name);
-  pure_test.user_hash_function = purecopy (table->test.user_hash_function);
-  pure_test.user_cmp_function = purecopy (table->test.user_cmp_function);
-
-  pure->header = table->header;
-  pure->weak = purecopy (Qnil);
-  pure->hash = purecopy (table->hash);
-  pure->next = purecopy (table->next);
-  pure->index = purecopy (table->index);
-  pure->count = table->count;
-  pure->next_free = table->next_free;
-  pure->purecopy = table->purecopy;
-  eassert (!pure->mutable);
-  pure->rehash_threshold = table->rehash_threshold;
-  pure->rehash_size = table->rehash_size;
-  pure->key_and_value = purecopy (table->key_and_value);
-  pure->test = pure_test;
-
-  return pure;
-}
+purecopy (Lisp_Object obj);
 
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
        doc: /* Make a copy of object OBJ in pure storage.
@@ -5514,100 +5175,23 @@ DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
     return purecopy (obj);
 }
 
-/* Pinned objects are marked before every GC cycle.  */
-static struct pinned_object
-{
-  Lisp_Object object;
-  struct pinned_object *next;
-} *pinned_objects;
-
 static Lisp_Object
 purecopy (Lisp_Object obj)
 {
-  if (FIXNUMP (obj)
-      || (! SYMBOLP (obj) && PURE_P (XPNTR (obj)))
-      || SUBRP (obj))
+  if (FIXNUMP (obj) || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
-    message_with_string ("Dropping text-properties while making string `%s' pure",
-			 obj, true);
-
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
     {
       Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
       if (!NILP (tmp))
 	return tmp;
+      Fputhash (obj, obj, Vpurify_flag);
     }
 
-  if (CONSP (obj))
-    obj = pure_cons (XCAR (obj), XCDR (obj));
-  else if (FLOATP (obj))
-    obj = make_pure_float (XFLOAT_DATA (obj));
-  else if (STRINGP (obj))
-    obj = make_pure_string (SSDATA (obj), SCHARS (obj),
-			    SBYTES (obj),
-			    STRING_MULTIBYTE (obj));
-  else if (HASH_TABLE_P (obj))
-    {
-      struct Lisp_Hash_Table *table = XHASH_TABLE (obj);
-      /* Do not purify hash tables which haven't been defined with
-         :purecopy as non-nil or are weak - they aren't guaranteed to
-         not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
-        {
-          /* Instead, add the hash table to the list of pinned objects,
-             so that it will be marked during GC.  */
-          struct pinned_object *o = xmalloc (sizeof *o);
-          o->object = obj;
-          o->next = pinned_objects;
-          pinned_objects = o;
-          return obj; /* Don't hash cons it.  */
-        }
-
-      struct Lisp_Hash_Table *h = purecopy_hash_table (table);
-      XSET_HASH_TABLE (obj, h);
-    }
-  else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
-    {
-      struct Lisp_Vector *objp = XVECTOR (obj);
-      ptrdiff_t nbytes = vector_nbytes (objp);
-      struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
-      register ptrdiff_t i;
-      ptrdiff_t size = ASIZE (obj);
-      if (size & PSEUDOVECTOR_FLAG)
-	size &= PSEUDOVECTOR_SIZE_MASK;
-      memcpy (vec, objp, nbytes);
-      for (i = 0; i < size; i++)
-	vec->contents[i] = purecopy (vec->contents[i]);
-      XSETVECTOR (obj, vec);
-    }
-  else if (SYMBOLP (obj))
-    {
-      if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
-	{ /* We can't purify them, but they appear in many pure objects.
-	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XSYMBOL (obj)->u.s.pinned = true;
-	  symbol_block_pinned = symbol_block;
-	}
-      /* Don't hash-cons it.  */
-      return obj;
-    }
-  else if (BIGNUMP (obj))
-    obj = make_pure_bignum (obj);
-  else
-    {
-      AUTO_STRING (fmt, "Don't know how to purify: %S");
-      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
-    }
-
-  if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
-    Fputhash (obj, obj, Vpurify_flag);
-
   return obj;
 }
 
-
 \f
 /***********************************************************************
 			  Protection from GC
@@ -5798,31 +5382,6 @@ compact_undo_list (Lisp_Object list)
   return list;
 }
 
-static void
-mark_pinned_objects (void)
-{
-  for (struct pinned_object *pobj = pinned_objects; pobj; pobj = pobj->next)
-    mark_object (pobj->object);
-}
-
-static void
-mark_pinned_symbols (void)
-{
-  struct symbol_block *sblk;
-  int lim = (symbol_block_pinned == symbol_block
-	     ? symbol_block_index : SYMBOL_BLOCK_SIZE);
-
-  for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
-    {
-      struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
-      for (; sym < end; ++sym)
-	if (sym->u.s.pinned)
-	  mark_object (make_lisp_symbol (sym));
-
-      lim = SYMBOL_BLOCK_SIZE;
-    }
-}
-
 static void
 visit_vectorlike_root (struct gc_root_visitor visitor,
                        struct Lisp_Vector *ptr,
@@ -6083,8 +5642,6 @@ garbage_collect (void)
   struct gc_root_visitor visitor = { .visit = mark_object_root_visitor };
   visit_static_gc_roots (visitor);
 
-  mark_pinned_objects ();
-  mark_pinned_symbols ();
   mark_terminals ();
   mark_kboards ();
   mark_threads ();
@@ -6193,10 +5750,6 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
   keeps around for future allocations (maybe because it does not know how
   to return them to the OS).
 
-However, if there was overflow in pure space, and Emacs was dumped
-using the 'unexec' method, `garbage-collect' returns nil, because
-real GC can't be done.
-
 Note that calling this function does not guarantee that absolutely all
 unreachable objects will be garbage-collected.  Emacs uses a
 mark-and-sweep garbage collector, but is conservative when it comes to
@@ -6566,8 +6119,8 @@ mark_objects (Lisp_Object *obj, ptrdiff_t n)
 mark_object (Lisp_Object arg)
 {
   register Lisp_Object obj;
-  void *po;
 #if GC_CHECK_MARKED_OBJECTS
+  void *po;
   struct mem_node *m = NULL;
 #endif
   ptrdiff_t cdr_count = 0;
@@ -6575,10 +6128,6 @@ mark_object (Lisp_Object arg)
   obj = arg;
  loop:
 
-  po = XPNTR (obj);
-  if (PURE_P (po))
-    return;
-
   last_marked[last_marked_index++] = obj;
   last_marked_index &= LAST_MARKED_SIZE - 1;
 
@@ -6587,6 +6136,8 @@ mark_object (Lisp_Object arg)
      by ~80%.  */
 #if GC_CHECK_MARKED_OBJECTS
 
+  po = XPNTR (obj);
+
   /* Check that the object pointed to by PO is known to be a Lisp
      structure allocated from the heap.  */
 #define CHECK_ALLOCATED()			\
@@ -6771,11 +6322,10 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL()		((void) 0)
 	    break;
 	  default: emacs_abort ();
 	  }
-	if (!PURE_P (XSTRING (ptr->u.s.name)))
-          set_string_marked (XSTRING (ptr->u.s.name));
+	set_string_marked (XSTRING (ptr->u.s.name));
         mark_interval_tree (string_intervals (ptr->u.s.name));
 	/* Inner loop to mark next symbol in this bucket, if any.  */
-	po = ptr = ptr->u.s.next;
+	ptr = ptr->u.s.next;
 	if (ptr)
 	  goto nextsym;
       }
@@ -6886,7 +6436,7 @@ survives_gc_p (Lisp_Object obj)
       emacs_abort ();
     }
 
-  return survives_p || PURE_P (XPNTR (obj));
+  return survives_p;
 }
 
 
@@ -7474,8 +7024,6 @@ init_alloc_once (void)
 static void
 init_alloc_once_for_pdumper (void)
 {
-  purebeg = PUREBEG;
-  pure_size = PURESIZE;
   mem_init ();
 
 #ifdef DOUG_LEA_MALLOC
@@ -7519,7 +7067,7 @@ syms_of_alloc (void)
   Vgc_cons_percentage = make_float (0.1);
 
   DEFVAR_INT ("pure-bytes-used", pure_bytes_used,
-	      doc: /* Number of bytes of shareable Lisp data allocated so far.  */);
+	      doc: /* No longer used.  */);
 
   DEFVAR_INT ("cons-cells-consed", cons_cells_consed,
 	      doc: /* Number of cons cells that have been consed so far.  */);
@@ -7544,10 +7092,7 @@ syms_of_alloc (void)
 	      doc: /* Number of strings that have been consed so far.  */);
 
   DEFVAR_LISP ("purify-flag", Vpurify_flag,
-	       doc: /* Non-nil means loading Lisp code in order to dump an executable.
-This means that certain objects should be allocated in shared (pure) space.
-It can also be set to a hash-table, in which case this table is used to
-do hash-consing of the objects allocated to pure space.  */);
+	       doc: /* No longer used.  */);
 
   DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages,
 	       doc: /* Non-nil means display messages at start and end of garbage collection.  */);
@@ -7563,10 +7108,10 @@ syms_of_alloc (void)
   /* We build this in advance because if we wait until we need it, we might
      not be able to allocate the memory to hold it.  */
   Vmemory_signal_data
-    = pure_list (Qerror,
-		 build_pure_c_string ("Memory exhausted--use"
-				      " M-x save-some-buffers then"
-				      " exit and restart Emacs"));
+    = list (Qerror,
+	    build_string ("Memory exhausted--use"
+			  " M-x save-some-buffers then"
+			  " exit and restart Emacs"));
 
   DEFVAR_LISP ("memory-full", Vmemory_full,
 	       doc: /* Non-nil means Emacs cannot get much more Lisp memory.  */);
diff --git a/src/buffer.c b/src/buffer.c
index 5bd9b37702f3f..69cb1a8e904a4 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5266,8 +5266,8 @@ init_buffer_once (void)
   set_buffer_intervals (&buffer_defaults, NULL);
   set_buffer_intervals (&buffer_local_symbols, NULL);
   /* This is not strictly necessary, but let's make them initialized.  */
-  bset_name (&buffer_defaults, build_pure_c_string (" *buffer-defaults*"));
-  bset_name (&buffer_local_symbols, build_pure_c_string (" *buffer-local-symbols*"));
+  bset_name (&buffer_defaults, build_string (" *buffer-defaults*"));
+  bset_name (&buffer_local_symbols, build_string (" *buffer-local-symbols*"));
   BUFFER_PVEC_INIT (&buffer_defaults);
   BUFFER_PVEC_INIT (&buffer_local_symbols);
 
@@ -5275,7 +5275,7 @@ init_buffer_once (void)
   /* Must do these before making the first buffer! */
 
   /* real setup is done in bindings.el */
-  bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
+  bset_mode_line_format (&buffer_defaults, build_string ("%-"));
   bset_header_line_format (&buffer_defaults, Qnil);
   bset_tab_line_format (&buffer_defaults, Qnil);
   bset_abbrev_mode (&buffer_defaults, Qnil);
@@ -5342,7 +5342,7 @@ init_buffer_once (void)
   current_buffer = 0;
   pdumper_remember_lv_ptr_raw (&current_buffer, Lisp_Vectorlike);
 
-  QSFundamental = build_pure_c_string ("Fundamental");
+  QSFundamental = build_string ("Fundamental");
 
   DEFSYM (Qfundamental_mode, "fundamental-mode");
   bset_major_mode (&buffer_defaults, Qfundamental_mode);
@@ -5356,10 +5356,10 @@ init_buffer_once (void)
 
   /* Super-magic invisible buffer.  */
   Vprin1_to_string_buffer =
-    Fget_buffer_create (build_pure_c_string (" prin1"), Qt);
+    Fget_buffer_create (build_string (" prin1"), Qt);
   Vbuffer_alist = Qnil;
 
-  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*"), Qnil));
+  Fset_buffer (Fget_buffer_create (build_string ("*scratch*"), Qnil));
 
   inhibit_modification_hooks = 0;
 }
@@ -5534,9 +5534,9 @@ syms_of_buffer (void)
 	       Qoverwrite_mode_binary));
 
   Fput (Qprotected_field, Qerror_conditions,
-	pure_list (Qprotected_field, Qerror));
+	list (Qprotected_field, Qerror));
   Fput (Qprotected_field, Qerror_message,
-	build_pure_c_string ("Attempt to modify a protected field"));
+	build_string ("Attempt to modify a protected field"));
 
   DEFVAR_PER_BUFFER ("tab-line-format",
 		     &BVAR (current_buffer, tab_line_format),
diff --git a/src/callint.c b/src/callint.c
index 18624637843f2..8f8a771310557 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -824,10 +824,10 @@ syms_of_callint (void)
   callint_message = Qnil;
   staticpro (&callint_message);
 
-  preserved_fns = pure_list (intern_c_string ("region-beginning"),
-			     intern_c_string ("region-end"),
-			     intern_c_string ("point"),
-			     intern_c_string ("mark"));
+  preserved_fns = list (intern_c_string ("region-beginning"),
+			intern_c_string ("region-end"),
+			intern_c_string ("point"),
+			intern_c_string ("mark"));
   staticpro (&preserved_fns);
 
   DEFSYM (Qlist, "list");
diff --git a/src/category.c b/src/category.c
index ec8f61f7f002f..907db1455778b 100644
--- a/src/category.c
+++ b/src/category.c
@@ -53,7 +53,7 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
       (table, 1,
        make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			Qnil, false));
+			Qnil));
   struct Lisp_Hash_Table *h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
   Lisp_Object hash;
   ptrdiff_t i = hash_lookup (h, category_set, &hash);
@@ -120,8 +120,6 @@ DEFUN ("define-category", Fdefine_category, Sdefine_category, 2, 3, 0,
 
   if (!NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category))))
     error ("Category `%c' is already defined", (int) XFIXNAT (category));
-  if (!NILP (Vpurify_flag))
-    docstring = Fpurecopy (docstring);
   SET_CATEGORY_DOCSTRING (table, XFIXNAT (category), docstring);
 
   return Qnil;
diff --git a/src/coding.c b/src/coding.c
index 739dd6adcb5fc..bf7d492f546c7 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -11650,7 +11650,7 @@ syms_of_coding (void)
   Vcode_conversion_reused_workbuf = Qnil;
 
   staticpro (&Vcode_conversion_workbuf_name);
-  Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
+  Vcode_conversion_workbuf_name = build_string (" *code-conversion-work*");
 
   reused_workbuf_in_use = false;
   PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
@@ -11714,9 +11714,9 @@ syms_of_coding (void)
   /* Error signaled when there's a problem with detecting a coding system.  */
   DEFSYM (Qcoding_system_error, "coding-system-error");
   Fput (Qcoding_system_error, Qerror_conditions,
-	pure_list (Qcoding_system_error, Qerror));
+	list (Qcoding_system_error, Qerror));
   Fput (Qcoding_system_error, Qerror_message,
-	build_pure_c_string ("Invalid coding system"));
+	build_string ("Invalid coding system"));
 
   DEFSYM (Qtranslation_table, "translation-table");
   Fput (Qtranslation_table, Qchar_table_extra_slots, make_fixnum (2));
@@ -11991,22 +11991,22 @@ syms_of_coding (void)
   DEFVAR_LISP ("eol-mnemonic-unix", eol_mnemonic_unix,
 	       doc: /*
 String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
-  eol_mnemonic_unix = build_pure_c_string (":");
+  eol_mnemonic_unix = build_string (":");
 
   DEFVAR_LISP ("eol-mnemonic-dos", eol_mnemonic_dos,
 	       doc: /*
 String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
-  eol_mnemonic_dos = build_pure_c_string ("\\");
+  eol_mnemonic_dos = build_string ("\\");
 
   DEFVAR_LISP ("eol-mnemonic-mac", eol_mnemonic_mac,
 	       doc: /*
 String displayed in mode line for MAC-like (CR) end-of-line format.  */);
-  eol_mnemonic_mac = build_pure_c_string ("/");
+  eol_mnemonic_mac = build_string ("/");
 
   DEFVAR_LISP ("eol-mnemonic-undecided", eol_mnemonic_undecided,
 	       doc: /*
 String displayed in mode line when end-of-line format is not yet determined.  */);
-  eol_mnemonic_undecided = build_pure_c_string (":");
+  eol_mnemonic_undecided = build_string (":");
 
   DEFVAR_LISP ("enable-character-translation", Venable_character_translation,
 	       doc: /*
@@ -12146,7 +12146,7 @@ system (e.g. `iso-2022-7bit').
       intern_c_string (":for-unibyte"),
       args[coding_arg_for_unibyte] = Qt,
       intern_c_string (":docstring"),
-      (build_pure_c_string
+      (build_string
        ("Do no conversion.\n"
 	"\n"
 	"When you visit a file with this coding, the file is read into a\n"
@@ -12166,7 +12166,7 @@ system (e.g. `iso-2022-7bit').
   plist[8] = intern_c_string (":charset-list");
   plist[9] = args[coding_arg_charset_list] = list1 (Qascii);
   plist[11] = args[coding_arg_for_unibyte] = Qnil;
-  plist[13] = build_pure_c_string ("No conversion on encoding, "
+  plist[13] = build_string ("No conversion on encoding, "
 				   "automatic conversion on decoding.");
   plist[15] = args[coding_arg_eol_type] = Qnil;
   args[coding_arg_plist] = CALLMANY (Flist, plist);
diff --git a/src/conf_post.h b/src/conf_post.h
index 176ab28b21ab2..da55a1fb54abc 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -163,41 +163,8 @@ #define emacs_raise(sig) msdos_fatal_signal (sig)
 
 /* DATA_START is needed by vm-limit.c and unexcoff.c. */
 #define DATA_START (&etext + 1)
-
-/* Define one of these for easier conditionals.  */
-#ifdef HAVE_X_WINDOWS
-/* We need a little extra space, see ../../lisp/loadup.el and the
-   commentary below, in the non-X branch.  The 140KB number was
-   measured on GNU/Linux and on MS-Windows.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+140000)
-#else
-/* We need a little extra space, see ../../lisp/loadup.el.
-   As of 20091024, DOS-specific files use up 62KB of pure space.  But
-   overall, we end up wasting 130KB of pure space, because
-   BASE_PURESIZE starts at 1.47MB, while we need only 1.3MB (including
-   non-DOS specific files and load history; the latter is about 55K,
-   but depends on the depth of the top-level Emacs directory in the
-   directory tree).  Given the unknown policy of different DPMI
-   hosts regarding loading of untouched pages, I'm not going to risk
-   enlarging Emacs footprint by another 100+ KBytes.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+90000)
-#endif
 #endif  /* MSDOS */
 
-/* macOS / GNUstep need a bit more pure memory.  Of the existing knobs,
-   SYSTEM_PURESIZE_EXTRA seems like the least likely to cause problems.  */
-#ifdef HAVE_NS
-#if defined NS_IMPL_GNUSTEP
-#  define SYSTEM_PURESIZE_EXTRA 30000
-#elif defined DARWIN_OS
-#  define SYSTEM_PURESIZE_EXTRA 200000
-#endif
-#endif
-
-#ifdef CYGWIN
-#define SYSTEM_PURESIZE_EXTRA 50000
-#endif
-
 #if defined HAVE_NTGUI && !defined DebPrint
 # ifdef EMACSDEBUG
 extern void _DebPrint (const char *fmt, ...);
diff --git a/src/data.c b/src/data.c
index 0fa491b17a114..2a8c7246fae65 100644
--- a/src/data.c
+++ b/src/data.c
@@ -30,7 +30,6 @@
 
 #include "lisp.h"
 #include "bignum.h"
-#include "puresize.h"
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
@@ -149,12 +148,6 @@ wrong_type_argument (Lisp_Object predicate, Lisp_Object value)
   xsignal2 (Qwrong_type_argument, predicate, value);
 }
 
-void
-pure_write_error (Lisp_Object obj)
-{
-  xsignal2 (Qerror, build_string ("Attempt to modify read-only object"), obj);
-}
-
 void
 args_out_of_range (Lisp_Object a1, Lisp_Object a2)
 {
@@ -625,7 +618,6 @@ DEFUN ("setcar", Fsetcar, Ssetcar, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcar)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCAR (cell, newcar);
   return newcar;
 }
@@ -635,7 +627,6 @@ DEFUN ("setcdr", Fsetcdr, Ssetcdr, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcdr)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCDR (cell, newcdr);
   return newcdr;
 }
@@ -798,10 +789,6 @@ DEFUN ("defalias", Fdefalias, Sdefalias, 2, 3, 0,
   (register Lisp_Object symbol, Lisp_Object definition, Lisp_Object docstring)
 {
   CHECK_SYMBOL (symbol);
-  if (!NILP (Vpurify_flag)
-      /* If `definition' is a keymap, immutable (and copying) is wrong.  */
-      && !KEYMAPP (definition))
-    definition = Fpurecopy (definition);
 
   {
     bool autoload = AUTOLOADP (definition);
@@ -2375,7 +2362,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
 
   if (VECTORP (array))
     {
-      CHECK_IMPURE (array, XVECTOR (array));
       if (idxval < 0 || idxval >= ASIZE (array))
 	args_out_of_range (array, idx);
       ASET (array, idxval, newelt);
@@ -2399,7 +2385,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
     }
   else /* STRINGP */
     {
-      CHECK_IMPURE (array, XSTRING (array));
       if (idxval < 0 || idxval >= SCHARS (array))
 	args_out_of_range (array, idx);
       CHECK_CHARACTER (newelt);
@@ -3881,7 +3866,7 @@ syms_of_data (void)
 
   DEFSYM (Qcdr, "cdr");
 
-  error_tail = pure_cons (Qerror, Qnil);
+  error_tail = Fcons (Qerror, Qnil);
 
   /* ERROR is used as a signaler for random errors for which nothing else is
      right.  */
@@ -3889,11 +3874,11 @@ syms_of_data (void)
   Fput (Qerror, Qerror_conditions,
 	error_tail);
   Fput (Qerror, Qerror_message,
-	build_pure_c_string ("error"));
+	build_string ("error"));
 
 #define PUT_ERROR(sym, tail, msg)			\
-  Fput (sym, Qerror_conditions, pure_cons (sym, tail)); \
-  Fput (sym, Qerror_message, build_pure_c_string (msg))
+  Fput (sym, Qerror_conditions, Fcons (sym, tail)); \
+  Fput (sym, Qerror_message, build_string (msg))
 
   PUT_ERROR (Qquit, Qnil, "Quit");
 
@@ -3921,14 +3906,14 @@ #define PUT_ERROR(sym, tail, msg)			\
   PUT_ERROR (Qno_catch, error_tail, "No catch for tag");
   PUT_ERROR (Qend_of_file, error_tail, "End of file during parsing");
 
-  arith_tail = pure_cons (Qarith_error, error_tail);
+  arith_tail = Fcons (Qarith_error, error_tail);
   Fput (Qarith_error, Qerror_conditions, arith_tail);
-  Fput (Qarith_error, Qerror_message, build_pure_c_string ("Arithmetic error"));
+  Fput (Qarith_error, Qerror_message, build_string ("Arithmetic error"));
 
   PUT_ERROR (Qbeginning_of_buffer, error_tail, "Beginning of buffer");
   PUT_ERROR (Qend_of_buffer, error_tail, "End of buffer");
   PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only");
-  PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail),
+  PUT_ERROR (Qtext_read_only, Fcons (Qbuffer_read_only, error_tail),
 	     "Text is read-only");
   PUT_ERROR (Qinhibited_interaction, error_tail,
 	     "User interaction while inhibited");
diff --git a/src/dbusbind.c b/src/dbusbind.c
index c005474d4409f..238142b95606c 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1868,7 +1868,7 @@ syms_of_dbusbind (void)
   Fput (Qdbus_error, Qerror_conditions,
 	list2 (Qdbus_error, Qerror));
   Fput (Qdbus_error, Qerror_message,
-	build_pure_c_string ("D-Bus error"));
+	build_string ("D-Bus error"));
 
   /* Lisp symbols of the system and session buses.  */
   DEFSYM (QCsystem, ":system");
@@ -1911,7 +1911,7 @@ syms_of_dbusbind (void)
 	       Vdbus_compiled_version,
     doc: /* The version of D-Bus Emacs is compiled against.  */);
 #ifdef DBUS_VERSION_STRING
-  Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
+  Vdbus_compiled_version = build_string (DBUS_VERSION_STRING);
 #else
   Vdbus_compiled_version = Qnil;
 #endif
diff --git a/src/deps.mk b/src/deps.mk
index eda2ed6338252..3292cf201cf74 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -132,10 +132,10 @@ insdel.o:
 keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \
    commands.h frame.h window.h macros.h disptab.h keyboard.h syssignal.h \
    systime.h syntax.h $(INTERVALS_H) blockinput.h atimer.h composite.h \
-   xterm.h puresize.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
+   xterm.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
    process.h ../lib/unistd.h gnutls.h lisp.h globals.h $(config_h)
 keymap.o: keymap.c buffer.h commands.h keyboard.h termhooks.h blockinput.h \
-   atimer.h systime.h puresize.h character.h charset.h $(INTERVALS_H) \
+   atimer.h systime.h character.h charset.h $(INTERVALS_H) \
    keymap.h window.h coding.h frame.h lisp.h globals.h $(config_h)
 lastfile.o: lastfile.c $(config_h)
 macros.o: macros.c window.h buffer.h commands.h macros.h keyboard.h msdos.h \
@@ -267,12 +267,12 @@ xsettings.o:
    atimer.h termopts.h globals.h
 
 ## The files of Lisp proper.
-alloc.o: alloc.c process.h frame.h window.h buffer.h  puresize.h syssignal.h \
+alloc.o: alloc.c process.h frame.h window.h buffer.h syssignal.h \
    keyboard.h blockinput.h atimer.h systime.h character.h lisp.h $(config_h) \
    $(INTERVALS_H) termhooks.h gnutls.h coding.h ../lib/unistd.h globals.h
 bytecode.o: bytecode.c buffer.h syntax.h character.h window.h dispextern.h \
   lisp.h globals.h $(config_h) msdos.h
-data.o: data.c buffer.h puresize.h character.h syssignal.h keyboard.h frame.h \
+data.o: data.c buffer.h character.h syssignal.h keyboard.h frame.h \
    termhooks.h systime.h coding.h composite.h dispextern.h font.h ccl.h \
    lisp.h globals.h $(config_h) msdos.h
 eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h frame.h \
@@ -295,7 +295,7 @@ lread.o:
 composite.o: composite.c composite.h buffer.h character.h coding.h font.h \
    ccl.h frame.h termhooks.h $(INTERVALS_H) window.h \
    lisp.h globals.h $(config_h)
-intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h puresize.h \
+intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h \
    keymap.h lisp.h globals.h $(config_h) systime.h coding.h
 textprop.o: textprop.c buffer.h window.h $(INTERVALS_H) \
    lisp.h globals.h $(config_h)
diff --git a/src/doc.c b/src/doc.c
index 1307aa5ee9233..2136f914297dd 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -490,8 +490,6 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
 	{
 	  tem = Fcdr (Fcdr (fun));
 	  if (CONSP (tem) && FIXNUMP (XCAR (tem)))
-	    /* FIXME: This modifies typically pure hash-cons'd data, so its
-	       correctness is quite delicate.  */
 	    XSETCAR (tem, make_fixnum (offset));
 	}
     }
@@ -575,7 +573,6 @@ DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
       int i = ARRAYELTS (buildobj);
       while (0 <= --i)
 	Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
-      Vbuild_files = Fpurecopy (Vbuild_files);
     }
 
   fd = emacs_open (name, O_RDONLY, 0);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index f8fb54c072823..896ae65685e84 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -1600,44 +1600,44 @@ syms_of_module (void)
   Vmodule_refs_hash
     = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 		       DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-		       Qnil, false);
+		       Qnil);
 
   DEFSYM (Qmodule_load_failed, "module-load-failed");
   Fput (Qmodule_load_failed, Qerror_conditions,
-	pure_list (Qmodule_load_failed, Qerror));
+	list (Qmodule_load_failed, Qerror));
   Fput (Qmodule_load_failed, Qerror_message,
-        build_pure_c_string ("Module load failed"));
+        build_string ("Module load failed"));
 
   DEFSYM (Qmodule_open_failed, "module-open-failed");
   Fput (Qmodule_open_failed, Qerror_conditions,
-	pure_list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_open_failed, Qerror_message,
-        build_pure_c_string ("Module could not be opened"));
+        build_string ("Module could not be opened"));
 
   DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible");
   Fput (Qmodule_not_gpl_compatible, Qerror_conditions,
-	pure_list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
+	list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
   Fput (Qmodule_not_gpl_compatible, Qerror_message,
-        build_pure_c_string ("Module is not GPL compatible"));
+        build_string ("Module is not GPL compatible"));
 
   DEFSYM (Qmissing_module_init_function, "missing-module-init-function");
   Fput (Qmissing_module_init_function, Qerror_conditions,
-	pure_list (Qmissing_module_init_function, Qmodule_load_failed,
-		   Qerror));
+	list (Qmissing_module_init_function, Qmodule_load_failed,
+	      Qerror));
   Fput (Qmissing_module_init_function, Qerror_message,
-        build_pure_c_string ("Module does not export an "
+        build_string ("Module does not export an "
                              "initialization function"));
 
   DEFSYM (Qmodule_init_failed, "module-init-failed");
   Fput (Qmodule_init_failed, Qerror_conditions,
-	pure_list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_init_failed, Qerror_message,
-        build_pure_c_string ("Module initialization failed"));
+        build_string ("Module initialization failed"));
 
   DEFSYM (Qinvalid_arity, "invalid-arity");
-  Fput (Qinvalid_arity, Qerror_conditions, pure_list (Qinvalid_arity, Qerror));
+  Fput (Qinvalid_arity, Qerror_conditions, list (Qinvalid_arity, Qerror));
   Fput (Qinvalid_arity, Qerror_message,
-        build_pure_c_string ("Invalid function arity"));
+        build_string ("Invalid function arity"));
 
   DEFSYM (Qmodule_function_p, "module-function-p");
   DEFSYM (Qunicode_string_p, "unicode-string-p");
diff --git a/src/emacs.c b/src/emacs.c
index fd08667f3fd4f..03ec63464daf5 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -88,7 +88,6 @@ #define MAIN_PROGRAM
 #include "syntax.h"
 #include "sysselect.h"
 #include "systime.h"
-#include "puresize.h"
 
 #include "getpagesize.h"
 #include "gnutls.h"
@@ -1544,7 +1543,9 @@ main (int argc, char **argv)
   if (!initialized)
     {
       init_alloc_once ();
+#ifdef HAVE_PDUMPER
       init_pdumper_once ();
+#endif
       init_obarray_once ();
       init_eval_once ();
       init_charset_once ();
@@ -2508,8 +2509,6 @@ DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
   Lisp_Object symbol;
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  check_pure_size ();
-
   if (! noninteractive)
     error ("Dumping Emacs works only in batch mode");
 
diff --git a/src/eval.c b/src/eval.c
index ddaa8edd81706..c0717f8cf124d 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -785,8 +785,6 @@ DEFUN ("internal--define-uninitialized-variable",
   XSYMBOL (symbol)->u.s.declared_special = true;
   if (!NILP (doc))
     {
-      if (!NILP (Vpurify_flag))
-	doc = Fpurecopy (doc);
       Fput (symbol, Qvariable_documentation, doc);
     }
   LOADHIST_ATTACH (symbol);
@@ -903,8 +901,6 @@ DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
 
   Finternal__define_uninitialized_variable (sym, docstring);
   tem = eval_sub (XCAR (XCDR (args)));
-  if (!NILP (Vpurify_flag))
-    tem = Fpurecopy (tem);
   Fset_default (sym, tem);      /* FIXME: set-default-toplevel-value? */
   Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why?  */
   return sym;
@@ -2107,12 +2103,6 @@ DEFUN ("autoload", Fautoload, Sautoload, 2, 5, 0,
       && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_fixnum (0)))
-    /* `read1' in lread.c has found the docstring starting with "\
-       and assumed the docstring will be provided by Snarf-documentation, so it
-       passed us 0 instead.  But that leads to accidental sharing in purecopy's
-       hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_ufixnum (XHASH (function));
   return Fdefalias (function,
 		    list5 (Qautoload, file, docstring, interactive, type),
 		    Qnil);
@@ -4354,7 +4344,7 @@ syms_of_eval (void)
      also use something like Fcons (Qnil, Qnil), but json.c treats any
      cons cell as error data, so use an uninterned symbol instead.  */
   Qcatch_all_memory_full
-    = Fmake_symbol (build_pure_c_string ("catch-all-memory-full"));
+    = Fmake_symbol (build_string ("catch-all-memory-full"));
 
   defsubr (&Sor);
   defsubr (&Sand);
diff --git a/src/fileio.c b/src/fileio.c
index 741e297d29c2c..5d438865e2092 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6294,34 +6294,34 @@ syms_of_fileio (void)
   DEFSYM (Qcar_less_than_car, "car-less-than-car");
 
   Fput (Qfile_error, Qerror_conditions,
-	Fpurecopy (list2 (Qfile_error, Qerror)));
+	list2 (Qfile_error, Qerror));
   Fput (Qfile_error, Qerror_message,
-	build_pure_c_string ("File error"));
+	build_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
+	list3 (Qfile_already_exists, Qfile_error, Qerror));
   Fput (Qfile_already_exists, Qerror_message,
-	build_pure_c_string ("File already exists"));
+	build_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
+	list3 (Qfile_date_error, Qfile_error, Qerror));
   Fput (Qfile_date_error, Qerror_message,
-	build_pure_c_string ("Cannot set file date"));
+	build_string ("Cannot set file date"));
 
   Fput (Qfile_missing, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_missing, Qfile_error, Qerror)));
+	list3 (Qfile_missing, Qfile_error, Qerror));
   Fput (Qfile_missing, Qerror_message,
-	build_pure_c_string ("File is missing"));
+	build_string ("File is missing"));
 
   Fput (Qfile_notify_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_notify_error, Qfile_error, Qerror)));
+	list3 (Qfile_notify_error, Qfile_error, Qerror));
   Fput (Qfile_notify_error, Qerror_message,
-	build_pure_c_string ("File notification error"));
+	build_string ("File notification error"));
 
   Fput (Qremote_file_error, Qerror_conditions,
 	Fpurecopy (list3 (Qremote_file_error, Qfile_error, Qerror)));
   Fput (Qremote_file_error, Qerror_message,
-	build_pure_c_string ("Remote file error"));
+	build_string ("Remote file error"));
 
   DEFVAR_LISP ("file-name-handler-alist", Vfile_name_handler_alist,
 	       doc: /* Alist of elements (REGEXP . HANDLER) for file names handled specially.
diff --git a/src/fns.c b/src/fns.c
index 7914bd47790a9..a22b633ec7386 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -36,7 +36,6 @@ Copyright (C) 1985-1987, 1993-1995, 1997-2021 Free Software Foundation,
 #include "buffer.h"
 #include "intervals.h"
 #include "window.h"
-#include "puresize.h"
 #include "gnutls.h"
 
 static void sort_vector_copy (Lisp_Object, ptrdiff_t,
@@ -2602,7 +2601,6 @@ DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
       size = SCHARS (array);
       if (size != 0)
 	{
-	  CHECK_IMPURE (array, XSTRING (array));
 	  unsigned char str[MAX_MULTIBYTE_LENGTH];
 	  int len;
 	  if (STRING_MULTIBYTE (array))
@@ -2644,7 +2642,6 @@ DEFUN ("clear-string", Fclear_string, Sclear_string,
   ptrdiff_t len = SBYTES (string);
   if (len != 0 || STRING_MULTIBYTE (string))
     {
-      CHECK_IMPURE (string, XSTRING (string));
       memset (SDATA (string), 0, len);
       STRING_SET_CHARS (string, len);
       STRING_SET_UNIBYTE (string);
@@ -4179,16 +4176,12 @@ hash_index_size (struct Lisp_Hash_Table *h, ptrdiff_t size)
    size exceeds REHASH_THRESHOLD.
 
    WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value', `key-or-value', or `key-and-value'.
-
-   If PURECOPY is non-nil, the table can be copied to pure storage via
-   `purecopy' when Emacs is being dumped. Such tables can no longer be
-   changed after purecopy.  */
+   one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
 
 Lisp_Object
 make_hash_table (struct hash_table_test test, EMACS_INT size,
 		 float rehash_size, float rehash_threshold,
-		 Lisp_Object weak, bool purecopy)
+		 Lisp_Object weak)
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
@@ -4217,7 +4210,6 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
   h->next = make_vector (size, make_fixnum (-1));
   h->index = make_vector (hash_index_size (h, size), make_fixnum (-1));
   h->next_weak = NULL;
-  h->purecopy = purecopy;
   h->mutable = true;
 
   /* Set up the free list.  */
@@ -4318,11 +4310,6 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
 	    set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
 	    set_hash_index_slot (h, start_of_bucket, i);
 	  }
-
-#ifdef ENABLE_CHECKING
-      if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h)
-	message ("Growing hash table to: %"pD"d", next_size);
-#endif
     }
 }
 
@@ -4385,7 +4372,6 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h)
 {
   if (!h->mutable)
     signal_error ("hash table test modifies table", obj);
-  eassert (!PURE_P (h));
 }
 
 /* Put an entry into hash table H that associates KEY with VALUE.
@@ -4876,16 +4862,10 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
 WEAK.  WEAK t is equivalent to `key-and-value'.  Default value of WEAK
 is nil.
 
-:purecopy PURECOPY -- If PURECOPY is non-nil, the table can be copied
-to pure storage when Emacs is being dumped, making the contents of the
-table read only. Any further changes to purified tables will result
-in an error.
-
 usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object test, weak;
-  bool purecopy;
   struct hash_table_test testdesc;
   ptrdiff_t i;
   USE_SAFE_ALLOCA;
@@ -4919,9 +4899,8 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       testdesc.cmpfn = cmpfn_user_defined;
     }
 
-  /* See if there's a `:purecopy PURECOPY' argument.  */
-  i = get_key_arg (QCpurecopy, nargs, args, used);
-  purecopy = i && !NILP (args[i]);
+  /* Ignore a `:purecopy PURECOPY' argument.  */
+  get_key_arg (QCpurecopy, nargs, args, used);
   /* See if there's a `:size SIZE' argument.  */
   i = get_key_arg (QCsize, nargs, args, used);
   Lisp_Object size_arg = i ? args[i] : Qnil;
@@ -4971,8 +4950,7 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       signal_error ("Invalid argument list", args[i]);
 
   SAFE_FREE ();
-  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak,
-			  purecopy);
+  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
 }
 
 
diff --git a/src/fontset.c b/src/fontset.c
index 332be6c39d11f..0421ca49c7361 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -2129,7 +2129,7 @@ syms_of_fontset (void)
   set_fontset_id (Vdefault_fontset, make_fixnum (0));
   set_fontset_name
     (Vdefault_fontset,
-     build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
+     build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
   ASET (Vfontset_table, 0, Vdefault_fontset);
   next_fontset_id = 1;
   PDUMPER_REMEMBER_SCALAR (next_fontset_id);
@@ -2187,7 +2187,7 @@ syms_of_fontset (void)
 	       doc: /* Alist of fontset names vs the aliases.  */);
   Vfontset_alias_alist
     = list1 (Fcons (FONTSET_NAME (Vdefault_fontset),
-		    build_pure_c_string ("fontset-default")));
+		    build_string ("fontset-default")));
 
   DEFVAR_LISP ("vertical-centering-font-regexp",
 	       Vvertical_centering_font_regexp,
diff --git a/src/frame.c b/src/frame.c
index a62347c1fb2a9..652d26654390d 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1108,7 +1108,7 @@ make_initial_frame (void)
   Vframe_list = Fcons (frame, Vframe_list);
 
   tty_frame_count = 1;
-  fset_name (f, build_pure_c_string ("F1"));
+  fset_name (f, build_string ("F1"));
 
   SET_FRAME_VISIBLE (f, 1);
 
diff --git a/src/image.c b/src/image.c
index 8137dbea8d7ec..c738548d382a7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -4808,7 +4808,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			  DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			  Qnil, false);
+			  Qnil);
 }
 
 static void
diff --git a/src/intervals.c b/src/intervals.c
index f88a41f254917..5b69af2449a68 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -44,7 +44,6 @@
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "puresize.h"
 #include "keymap.h"
 
 /* Test for membership, allowing for t (actually any non-cons) to mean the
@@ -101,7 +100,6 @@ create_root_interval (Lisp_Object parent)
     }
   else
     {
-      CHECK_IMPURE (parent, XSTRING (parent));
       new->total_length = SCHARS (parent);
       eassert (TOTAL_LENGTH (new) >= 0);
       set_string_intervals (parent, new);
diff --git a/src/json.c b/src/json.c
index 3f1d27ad7fb7f..ccb0405c4e069 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1110,8 +1110,8 @@ define_error (Lisp_Object name, const char *message, Lisp_Object parent)
   eassert (CONSP (parent_conditions));
   eassert (!NILP (Fmemq (parent, parent_conditions)));
   eassert (NILP (Fmemq (name, parent_conditions)));
-  Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
-  Fput (name, Qerror_message, build_pure_c_string (message));
+  Fput (name, Qerror_conditions, Fcons (name, parent_conditions));
+  Fput (name, Qerror_message, build_string (message));
 }
 
 void
diff --git a/src/keyboard.c b/src/keyboard.c
index 9ee4c4f6d6839..1c862a15759af 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1109,8 +1109,6 @@ top_level_1 (Lisp_Object ignore)
   /* On entry to the outer level, run the startup file.  */
   if (!NILP (Vtop_level))
     internal_condition_case (top_level_2, Qerror, cmd_error);
-  else if (!NILP (Vpurify_flag))
-    message1 ("Bare impure Emacs (standard Lisp code not loaded)");
   else
     message1 ("Bare Emacs (standard Lisp code not loaded)");
   return Qnil;
@@ -11458,14 +11456,14 @@ syms_of_keyboard (void)
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
-  Vlispy_mouse_stem = build_pure_c_string ("mouse");
+  Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
-  regular_top_level_message = build_pure_c_string ("Back to top level");
+  regular_top_level_message = build_string ("Back to top level");
   staticpro (&regular_top_level_message);
 #ifdef HAVE_STACK_OVERFLOW_HANDLING
   recover_top_level_message
-    = build_pure_c_string ("Re-entering top level after C stack overflow");
+    = build_string ("Re-entering top level after C stack overflow");
   staticpro (&recover_top_level_message);
 #endif
   DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
diff --git a/src/keymap.c b/src/keymap.c
index 782931fadff6a..dca4fce9b13f8 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -50,7 +50,6 @@
 #include "keyboard.h"
 #include "termhooks.h"
 #include "blockinput.h"
-#include "puresize.h"
 #include "intervals.h"
 #include "keymap.h"
 #include "window.h"
@@ -117,8 +116,6 @@ DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 1, 0,
 {
   if (!NILP (string))
     {
-      if (!NILP (Vpurify_flag))
-	string = Fpurecopy (string);
       return list2 (Qkeymap, string);
     }
   return list1 (Qkeymap);
@@ -296,7 +293,6 @@ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
 	 If we came to the end, add the parent in PREV.  */
       if (!CONSP (list) || KEYMAPP (list))
 	{
-	  CHECK_IMPURE (prev, XCONS (prev));
 	  XSETCDR (prev, parent);
 	  return parent;
 	}
@@ -734,7 +730,7 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 
   /* If we are preparing to dump, and DEF is a menu element
      with a menu item indicator, copy it to ensure it is not pure.  */
-  if (CONSP (def) && PURE_P (XCONS (def))
+  if (CONSP (def)
       && (EQ (XCAR (def), Qmenu_item) || STRINGP (XCAR (def))))
     def = Fcons (XCAR (def), XCDR (def));
 
@@ -778,7 +774,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	  {
 	    if (FIXNATP (idx) && XFIXNAT (idx) < ASIZE (elt))
 	      {
-		CHECK_IMPURE (elt, XVECTOR (elt));
 		ASET (elt, XFIXNAT (idx), def);
 		return def;
 	      }
@@ -831,7 +826,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	      }
 	    else if (EQ (idx, XCAR (elt)))
 	      {
-		CHECK_IMPURE (elt, XCONS (elt));
 		XSETCDR (elt, def);
 		return def;
 	      }
@@ -877,7 +871,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	}
       else
 	elt = Fcons (idx, def);
-      CHECK_IMPURE (insertion_point, XCONS (insertion_point));
       XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
     }
   }
@@ -3121,12 +3114,12 @@ syms_of_keymap (void)
   current_global_map = Qnil;
   staticpro (&current_global_map);
 
-  exclude_keys = pure_list
-    (pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")),
-     pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")),
-     pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")),
-     pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")),
-     pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" ")));
+  exclude_keys = list
+    (Fcons (build_string ("DEL"), build_string ("\\d")),
+     Fcons (build_string ("TAB"), build_string ("\\t")),
+     Fcons (build_string ("RET"), build_string ("\\r")),
+     Fcons (build_string ("ESC"), build_string ("\\e")),
+     Fcons (build_string ("SPC"), build_string (" ")));
   staticpro (&exclude_keys);
 
   DEFVAR_LISP ("minibuffer-local-map", Vminibuffer_local_map,
@@ -3176,13 +3169,12 @@ syms_of_keymap (void)
   DEFSYM (Qmode_line, "mode-line");
 
   staticpro (&Vmouse_events);
-  Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar,
-			     Qtab_line, Qheader_line, Qmode_line,
-			     intern_c_string ("mouse-1"),
-			     intern_c_string ("mouse-2"),
-			     intern_c_string ("mouse-3"),
-			     intern_c_string ("mouse-4"),
-			     intern_c_string ("mouse-5"));
+  Vmouse_events = list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
+			intern_c_string ("mouse-1"),
+			intern_c_string ("mouse-2"),
+			intern_c_string ("mouse-3"),
+			intern_c_string ("mouse-4"),
+			intern_c_string ("mouse-5"));
 
   /* Keymap used for minibuffers when doing completion.  */
   /* Keymap used for minibuffers when doing completion and require a match.  */
diff --git a/src/lisp.h b/src/lisp.h
index b95f389b89024..7580272e5c7f3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -823,9 +823,6 @@ #define XUNTAG(a, type, ctype) ((ctype *) \
 	 special (with `defvar' etc), and shouldn't be lexically bound.  */
       bool_bf declared_special : 1;
 
-      /* True if pointed to from purespace and hence can't be GC'd.  */
-      bool_bf pinned : 1;
-
       /* The symbol's name, as a Lisp string.  */
       Lisp_Object name;
 
@@ -1534,20 +1531,14 @@ #define STRING_BYTES_BOUND  \
 /* Mark STR as a unibyte string.  */
 #define STRING_SET_UNIBYTE(STR)				\
   do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_unibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = -1;		\
+    XSTRING (STR)->u.s.size_byte = -1;			\
   } while (false)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
-#define STRING_SET_MULTIBYTE(STR)			\
-  do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_multibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
+#define STRING_SET_MULTIBYTE(STR)				\
+  do {								\
+    XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size;	\
   } while (false)
 
 /* Convenience functions for dealing with Lisp strings.  */
@@ -2301,12 +2292,8 @@ #define DEFSYM(sym, name) /* empty */
   /* Index of first free entry in free list, or -1 if none.  */
   ptrdiff_t next_free;
 
-  /* True if the table can be purecopied.  The table cannot be
-     changed afterwards.  */
-  bool purecopy;
-
   /* True if the table is mutable.  Ordinarily tables are mutable, but
-     pure tables are not, and while a table is being mutated it is
+     some tables are not, and while a table is being mutated it is
      immutable for recursive attempts to mutate it.  */
   bool mutable;
 
@@ -3599,7 +3586,7 @@ #define CONS_TO_INTEGER(cons, type, var)				\
 Lisp_Object hashfn_equal (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
-                             Lisp_Object, bool);
+                             Lisp_Object);
 ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object *);
 ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
 		    Lisp_Object);
@@ -3755,7 +3742,6 @@ verify (FLT_RADIX == 2 || FLT_RADIX == 16);
 
 /* Defined in alloc.c.  */
 extern void *my_heap_start (void);
-extern void check_pure_size (void);
 unsigned char *resize_string_data (Lisp_Object, ptrdiff_t, int, int);
 extern void malloc_warning (const char *);
 extern AVOID memory_full (size_t);
@@ -3813,11 +3799,8 @@ flush_stack_call_func (void (*func) (void *arg), void *arg)
 extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
 			  Lisp_Object);
 extern Lisp_Object listn (ptrdiff_t, Lisp_Object, ...);
-extern Lisp_Object pure_listn (ptrdiff_t, Lisp_Object, ...);
 #define list(...) \
   listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
-#define pure_list(...) \
-  pure_listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
 
 enum gc_root_type
 {
@@ -3890,17 +3873,6 @@ build_unibyte_string (const char *str)
 extern Lisp_Object make_string_from_bytes (const char *, ptrdiff_t, ptrdiff_t);
 extern Lisp_Object make_specified_string (const char *,
 					  ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_string (const char *, ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_c_string (const char *, ptrdiff_t);
-
-/* Make a string allocated in pure space, use STR as string data.  */
-
-INLINE Lisp_Object
-build_pure_c_string (const char *str)
-{
-  return make_pure_c_string (str, strlen (str));
-}
-
 /* Make a string from the data at STR, treating it as multibyte if the
    data warrants.  */
 
@@ -3910,7 +3882,6 @@ build_string (const char *str)
   return make_string (str, strlen (str));
 }
 
-extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
 extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
 extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
 
diff --git a/src/lread.c b/src/lread.c
index dea1b232fff83..033e9ba41af16 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2098,13 +2098,13 @@ readevalloop (Lisp_Object readcharfun,
 	read_objects_map
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (! HASH_TABLE_P (read_objects_completed)
 	  || XHASH_TABLE (read_objects_completed)->count)
 	read_objects_completed
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (!NILP (Vpurify_flag) && c == '(')
 	{
 	  val = read_list (0, readcharfun);
@@ -2321,12 +2321,12 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
       || XHASH_TABLE (read_objects_map)->count)
     read_objects_map
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (! HASH_TABLE_P (read_objects_completed)
       || XHASH_TABLE (read_objects_completed)->count)
     read_objects_completed
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (EQ (Vread_with_symbol_positions, Qt)
       || EQ (Vread_with_symbol_positions, stream))
     Vread_symbol_positions_list = Qnil;
@@ -2896,11 +2896,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      if (!NILP (params[param_count + 1]))
 		param_count += 2;
 
-              params[param_count] = QCpurecopy;
-              params[param_count + 1] = Fplist_get (tmp, Qpurecopy);
-              if (!NILP (params[param_count + 1]))
-                param_count += 2;
-
 	      /* This is the hash table data.  */
 	      data = Fplist_get (tmp, Qdata);
 
@@ -3210,13 +3205,13 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      /* No symbol character follows, this is the empty
 		 symbol.  */
 	      UNREAD (c);
-	      return Fmake_symbol (empty_unibyte_string);
+	      return Fmake_symbol (build_string (""));
 	    }
 	  goto read_symbol;
 	}
       /* ## is the empty symbol.  */
       if (c == '#')
-	return Fintern (empty_unibyte_string, Qnil);
+	return Fintern (build_string (""), Qnil);
 
       if (c >= '0' && c <= '9')
 	{
@@ -3612,9 +3607,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	  if (uninterned_symbol)
 	    {
 	      Lisp_Object name
-		= ((! NILP (Vpurify_flag)
-		    ? make_pure_string : make_specified_string)
-		   (read_buffer, nchars, nbytes, multibyte));
+		= make_specified_string (read_buffer, nchars, nbytes,
+					 multibyte);
 	      result = Fmake_symbol (name);
 	    }
 	  else
@@ -4204,10 +4198,8 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 
   if (!SYMBOLP (tem))
     {
-      /* Creating a non-pure string from a string literal not implemented yet.
-	 We could just use make_string here and live with the extra copy.  */
       eassert (!NILP (Vpurify_flag));
-      tem = intern_driver (make_pure_c_string (str, len), obarray, tem);
+      tem = intern_driver (make_string (str, len), obarray, tem);
     }
   return tem;
 }
@@ -4216,7 +4208,7 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 define_symbol (Lisp_Object sym, char const *str)
 {
   ptrdiff_t len = strlen (str);
-  Lisp_Object string = make_pure_c_string (str, len);
+  Lisp_Object string = make_string (str, len);
   init_symbol (sym, string);
 
   /* Qunbound is uninterned, so that it's not confused with any symbol
@@ -4243,8 +4235,7 @@ DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
 
   tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
   if (!SYMBOLP (tem))
-    tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
-			 obarray, tem);
+    tem = intern_driver (string, obarray, tem);
   return tem;
 }
 
@@ -4893,23 +4884,23 @@ syms_of_lread (void)
 to the specified file name if a suffix is allowed or required.  */);
 #ifdef HAVE_MODULES
 #ifdef MODULES_SECONDARY_SUFFIX
-  Vload_suffixes = list4 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX),
-                          build_pure_c_string (MODULES_SECONDARY_SUFFIX));
+  Vload_suffixes = list4 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX),
+                          build_string (MODULES_SECONDARY_SUFFIX));
 #else
-  Vload_suffixes = list3 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX));
+  Vload_suffixes = list3 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX));
 #endif
 #else
-  Vload_suffixes = list2 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"));
+  Vload_suffixes = list2 (build_string (".elc"),
+			  build_string (".el"));
 #endif
   DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
 	       doc: /* Suffix of loadable module file, or nil if modules are not supported.  */);
 #ifdef HAVE_MODULES
-  Vmodule_file_suffix = build_pure_c_string (MODULES_SUFFIX);
+  Vmodule_file_suffix = build_string (MODULES_SUFFIX);
 #else
   Vmodule_file_suffix = Qnil;
 #endif
@@ -5052,7 +5043,7 @@ syms_of_lread (void)
 When the regular expression matches, the file is considered to be safe
 to load.  */);
   Vbytecomp_version_regexp
-    = build_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
   DEFSYM (Qlexical_binding, "lexical-binding");
   DEFVAR_LISP ("lexical-binding", Vlexical_binding,
diff --git a/src/pdumper.c b/src/pdumper.c
index 337742fda4ade..dd2486cd1a0e5 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2403,7 +2403,7 @@ dump_symbol (struct dump_context *ctx,
              Lisp_Object object,
              dump_off offset)
 {
-#if CHECK_STRUCTS && !defined HASH_Lisp_Symbol_999DC26DEC
+#if CHECK_STRUCTS && !defined HASH_Lisp_Symbol_DD2E6013B4
 # error "Lisp_Symbol changed. See CHECK_STRUCTS comment in config.h."
 #endif
 #if CHECK_STRUCTS && !defined (HASH_symbol_redirect_ADB4F5B113)
@@ -2440,7 +2440,6 @@ dump_symbol (struct dump_context *ctx,
   DUMP_FIELD_COPY (&out, symbol, u.s.trapped_write);
   DUMP_FIELD_COPY (&out, symbol, u.s.interned);
   DUMP_FIELD_COPY (&out, symbol, u.s.declared_special);
-  DUMP_FIELD_COPY (&out, symbol, u.s.pinned);
   dump_field_lv (ctx, &out, symbol, &symbol->u.s.name, WEIGHT_STRONG);
   switch (symbol->u.s.redirect)
     {
@@ -2657,7 +2656,7 @@ dump_hash_table (struct dump_context *ctx,
                  Lisp_Object object,
                  dump_off offset)
 {
-#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_6D63EDB618
+#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_203821C7EF
 # error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h."
 #endif
   const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object);
@@ -2673,7 +2672,6 @@ dump_hash_table (struct dump_context *ctx,
      them as close to the hash table as possible.  */
   DUMP_FIELD_COPY (out, hash, count);
   DUMP_FIELD_COPY (out, hash, next_free);
-  DUMP_FIELD_COPY (out, hash, purecopy);
   DUMP_FIELD_COPY (out, hash, mutable);
   DUMP_FIELD_COPY (out, hash, rehash_threshold);
   DUMP_FIELD_COPY (out, hash, rehash_size);
@@ -5467,8 +5465,6 @@ DEFUN ("pdumper-stats", Fpdumper_stats, Spdumper_stats, 0, 0, 0,
 		Fcons (Qdump_file_name, dump_fn));
 }
 
-#endif /* HAVE_PDUMPER */
-
 \f
 static void
 thaw_hash_tables (void)
@@ -5483,6 +5479,7 @@ init_pdumper_once (void)
 {
   pdumper_do_now_and_after_load (thaw_hash_tables);
 }
+#endif /* HAVE_PDUMPER */
 
 void
 syms_of_pdumper (void)
diff --git a/src/print.c b/src/print.c
index 14af9195475ef..df008cf3b1296 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1581,12 +1581,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 	print_object (Fhash_table_rehash_threshold (obj),
 		      printcharfun, escapeflag);
 
-	if (h->purecopy)
-	  {
-	    print_c_string (" purecopy ", printcharfun);
-	    print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
-	  }
-
 	print_c_string (" data ", printcharfun);
 
 	/* Print the data here as a plist. */
diff --git a/src/process.c b/src/process.c
index b98bc297a3f3f..90a1141ab6564 100644
--- a/src/process.c
+++ b/src/process.c
@@ -8566,7 +8566,7 @@ syms_of_process (void)
    const struct socket_options *sopt;
 
 #define ADD_SUBFEATURE(key, val) \
-  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
+  subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures)
 
    ADD_SUBFEATURE (QCnowait, Qt);
 #ifdef DATAGRAM_SOCKETS
@@ -8588,7 +8588,7 @@ #define ADD_SUBFEATURE(key, val) \
    ADD_SUBFEATURE (QCserver, Qt);
 
    for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
+     subfeatures = Fcons (intern_c_string (sopt->name), subfeatures);
 
    Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
diff --git a/src/profiler.c b/src/profiler.c
index 21ae2447aa4ee..44bf57eba2078 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -63,7 +63,7 @@ make_log (void)
   Lisp_Object log = make_hash_table (hashtest_profiler, heap_size,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
   struct Lisp_Hash_Table *h = XHASH_TABLE (log);
 
   /* What is special about our hash-tables is that the values are pre-filled
diff --git a/src/puresize.h b/src/puresize.h
deleted file mode 100644
index 811d0b4d36952..0000000000000
--- a/src/puresize.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* How much read-only Lisp storage a dumped Emacs needs.
-   Copyright (C) 1993, 2001-2021 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
-
-#ifndef EMACS_PURESIZE_H
-#define EMACS_PURESIZE_H
-
-#include "lisp.h"
-
-INLINE_HEADER_BEGIN
-
-/* Define PURESIZE, the number of bytes of pure Lisp code to leave space for.
-
-   At one point, this was defined in config.h, meaning that changing
-   PURESIZE would make Make recompile all of Emacs.  But only a few
-   files actually use PURESIZE, so we split it out to its own .h file.
-
-   Make sure to include this file after config.h, since that tells us
-   whether we are running X windows, which tells us how much pure
-   storage to allocate.  */
-
-/* First define a measure of the amount of data we have.  */
-
-/* A system configuration file may set this to request a certain extra
-   amount of storage.  This is a lot more update-robust that defining
-   BASE_PURESIZE or even PURESIZE directly.  */
-#ifndef SYSTEM_PURESIZE_EXTRA
-#define SYSTEM_PURESIZE_EXTRA 0
-#endif
-
-#ifndef SITELOAD_PURESIZE_EXTRA
-#define SITELOAD_PURESIZE_EXTRA 0
-#endif
-
-#ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA)
-#endif
-
-/* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
-#ifndef PURESIZE_RATIO
-#if EMACS_INT_MAX >> 31 != 0
-#if PTRDIFF_MAX >> 31 != 0
-#define PURESIZE_RATIO 10 / 6	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_RATIO 8 / 6	/* Don't surround with `()'.  */
-#endif
-#else
-#define PURESIZE_RATIO 1
-#endif
-#endif
-
-#ifdef ENABLE_CHECKING
-/* ENABLE_CHECKING somehow increases the purespace used, probably because
-   it tends to cause some macro arguments to be evaluated twice.  This is
-   a bug, but it's difficult to track it down.  */
-#define PURESIZE_CHECKING_RATIO 12 / 10	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_CHECKING_RATIO 1
-#endif
-
-/* This is the actual size in bytes to allocate.  */
-#ifndef PURESIZE
-#define PURESIZE  (BASE_PURESIZE * PURESIZE_RATIO * PURESIZE_CHECKING_RATIO)
-#endif
-
-extern AVOID pure_write_error (Lisp_Object);
-
-extern EMACS_INT pure[];
-
-/* The puresize_h_* macros are private to this include file.  */
-
-/* True if PTR is pure.  */
-
-#define puresize_h_PURE_P(ptr) \
-  ((uintptr_t) (ptr) - (uintptr_t) pure <= PURESIZE)
-
-INLINE bool
-PURE_P (void *ptr)
-{
-  return puresize_h_PURE_P (ptr);
-}
-
-/* Signal an error if OBJ is pure.  PTR is OBJ untagged.  */
-
-#define puresize_h_CHECK_IMPURE(obj, ptr) \
-  (PURE_P (ptr) ? pure_write_error (obj) : (void) 0)
-
-INLINE void
-CHECK_IMPURE (Lisp_Object obj, void *ptr)
-{
-  puresize_h_CHECK_IMPURE (obj, ptr);
-}
-
-#if DEFINE_KEY_OPS_AS_MACROS
-# define PURE_P(ptr) puresize_h_PURE_P (ptr)
-# define CHECK_IMPURE(obj, ptr) puresize_h_CHECK_IMPURE (obj, ptr)
-#endif
-
-INLINE_HEADER_END
-
-#endif /* EMACS_PURESIZE_H */
diff --git a/src/search.c b/src/search.c
index c757bf3d1f281..5a214db0092d2 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3354,19 +3354,19 @@ syms_of_search (void)
   DEFSYM (Qinvalid_regexp, "invalid-regexp");
 
   Fput (Qsearch_failed, Qerror_conditions,
-	pure_list (Qsearch_failed, Qerror));
+	list (Qsearch_failed, Qerror));
   Fput (Qsearch_failed, Qerror_message,
-	build_pure_c_string ("Search failed"));
+	build_string ("Search failed"));
 
   Fput (Quser_search_failed, Qerror_conditions,
-	pure_list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
+	list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
   Fput (Quser_search_failed, Qerror_message,
-        build_pure_c_string ("Search failed"));
+        build_string ("Search failed"));
 
   Fput (Qinvalid_regexp, Qerror_conditions,
-	pure_list (Qinvalid_regexp, Qerror));
+	list (Qinvalid_regexp, Qerror));
   Fput (Qinvalid_regexp, Qerror_message,
-	build_pure_c_string ("Invalid regexp"));
+	build_string ("Invalid regexp"));
 
   re_match_object = Qnil;
   staticpro (&re_match_object);
diff --git a/src/syntax.c b/src/syntax.c
index 9fbf88535f3ec..993f91af19ac0 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3719,9 +3719,9 @@ syms_of_syntax (void)
 
   DEFSYM (Qscan_error, "scan-error");
   Fput (Qscan_error, Qerror_conditions,
-	pure_list (Qscan_error, Qerror));
+	list (Qscan_error, Qerror));
   Fput (Qscan_error, Qerror_message,
-	build_pure_c_string ("Scan error"));
+	build_string ("Scan error"));
 
   DEFVAR_BOOL ("parse-sexp-ignore-comments", parse_sexp_ignore_comments,
 	       doc: /* Non-nil means `forward-sexp', etc., should treat comments as whitespace.  */);
diff --git a/src/w32fns.c b/src/w32fns.c
index 9db367bfafe75..3b3ad2f55b9aa 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10390,9 +10390,9 @@ syms_of_w32fns (void)
   DEFSYM (Qjson, "json");
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   staticpro (&w32_grabbed_keys);
   w32_grabbed_keys = Qnil;
diff --git a/src/xdisp.c b/src/xdisp.c
index cc0a689ba32e9..38099350d6761 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -34862,7 +34862,7 @@ syms_of_xdisp (void)
   staticpro (&echo_area_buffer[0]);
   staticpro (&echo_area_buffer[1]);
 
-  Vmessages_buffer_name = build_pure_c_string ("*Messages*");
+  Vmessages_buffer_name = build_string ("*Messages*");
   staticpro (&Vmessages_buffer_name);
 
   mode_line_proptrans_alist = Qnil;
@@ -34954,7 +34954,7 @@ syms_of_xdisp (void)
   DEFVAR_LISP ("overlay-arrow-string", Voverlay_arrow_string,
     doc: /* String to display as an arrow in non-window frames.
 See also `overlay-arrow-position'.  */);
-  Voverlay_arrow_string = build_pure_c_string ("=>");
+  Voverlay_arrow_string = build_string ("=>");
 
   DEFVAR_LISP ("overlay-arrow-variable-list", Voverlay_arrow_variable_list,
     doc: /* List of variables (symbols) which hold markers for overlay arrows.
@@ -35079,17 +35079,17 @@ syms_of_xdisp (void)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
 \(see `modify-frame-parameters').  */);
-  /* Do not nest calls to pure_list.  This works around a bug in
+  /* Do not nest calls to list.  This works around a bug in
      Oracle Developer Studio 12.6.  */
   Lisp_Object icon_title_name_format
-    = pure_list (empty_unibyte_string,
-		 build_pure_c_string ("%b - GNU Emacs at "),
-		 intern_c_string ("system-name"));
+    = list (empty_unibyte_string,
+	    build_string ("%b - GNU Emacs at "),
+	    intern_c_string ("system-name"));
   Vicon_title_format
     = Vframe_title_format
-    = pure_list (intern_c_string ("multiple-frames"),
-		 build_pure_c_string ("%b"),
-		 icon_title_name_format);
+    = list (intern_c_string ("multiple-frames"),
+	    build_string ("%b"),
+	    icon_title_name_format);
 
   DEFVAR_LISP ("message-log-max", Vmessage_log_max,
     doc: /* Maximum number of lines to keep in the message log buffer.
diff --git a/src/xfaces.c b/src/xfaces.c
index ab4440f46ad0d..6cb08b0475cba 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -7044,7 +7044,7 @@ syms_of_xfaces (void)
 This stipple pattern is used on monochrome displays
 instead of shades of gray for a face background color.
 See `set-face-stipple' for possible values for this variable.  */);
-  Vface_default_stipple = build_pure_c_string ("gray3");
+  Vface_default_stipple = build_string ("gray3");
 
   DEFVAR_LISP ("tty-defined-color-alist", Vtty_defined_color_alist,
    doc: /* An alist of defined terminal colors and their RGB values.
diff --git a/src/xfns.c b/src/xfns.c
index d90644819b6f5..e9ead35ccccb5 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -7878,9 +7878,9 @@ syms_of_xfns (void)
 #endif
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
     doc: /* The shape of the pointer when over text.
@@ -8091,7 +8091,7 @@ syms_of_xfns (void)
     char gtk_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
     int len = sprintf (gtk_version, "%d.%d.%d",
 		       GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
-    Vgtk_version_string = make_pure_string (gtk_version, len, len, false);
+    Vgtk_version_string = make_specified_string (gtk_version, len, len, false);
   }
 #endif /* USE_GTK */
 
@@ -8105,7 +8105,8 @@ syms_of_xfns (void)
     int len = sprintf (cairo_version, "%d.%d.%d",
 		       CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
                        CAIRO_VERSION_MICRO);
-    Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+    Vcairo_version_string = make_specified_string (cairo_version, len, len,
+						   false);
   }
 #endif
 
diff --git a/src/xterm.c b/src/xterm.c
index 744b80c68a002..437c08b526f60 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13649,7 +13649,7 @@ syms_of_xterm (void)
   DEFSYM (Qlatin_1, "latin-1");
 
 #ifdef USE_GTK
-  xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
+  xg_default_icon_file = build_string ("icons/hicolor/scalable/apps/emacs.svg");
   staticpro (&xg_default_icon_file);
 
   DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
@@ -13770,7 +13770,7 @@ syms_of_xterm (void)
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
 
   DEFVAR_BOOL ("x-frame-normalize-before-maximize",
 	       x_frame_normalize_before_maximize,
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 12:55                                               ` Pip Cet
@ 2021-03-04 14:56                                                 ` Robert Pluim
  2021-03-04 15:49                                                   ` Eli Zaretskii
  2021-03-04 21:52                                                   ` Paul Eggert
  0 siblings, 2 replies; 125+ messages in thread
From: Robert Pluim @ 2021-03-04 14:56 UTC (permalink / raw)
  To: Pip Cet; +Cc: eggert, Andreas Schwab, Stefan Kangas, 36649, larsi,
	Andrea Corallo

>>>>> On Thu, 4 Mar 2021 12:55:34 +0000, Pip Cet <pipcet@gmail.com> said:

    Pip> On Wed, Mar 3, 2021 at 3:34 PM Pip Cet <pipcet@gmail.com> wrote:
    >> I have time for that now, so here's a revised patch as a first step.

    Pip> This patch removes pure space from Emacs 28.

Cool! Finally! Commit && push, damn the torpedoes.

    Pip> Changes:
    Pip> - now builds with --enable-checking=all

    Pip> Todo:
    Pip> - commit message not yet final.
    Pip> - zero vector handling depends on Qnil being all zero in memory

I think Emacs already assumes Qnil == 0, since there are places that
use ! to check for Qnil rather than using NILP.

Robert
-- 





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 14:56                                                 ` Robert Pluim
@ 2021-03-04 15:49                                                   ` Eli Zaretskii
  2021-03-04 16:42                                                     ` Robert Pluim
                                                                       ` (2 more replies)
  2021-03-04 21:52                                                   ` Paul Eggert
  1 sibling, 3 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-03-04 15:49 UTC (permalink / raw)
  To: Robert Pluim; +Cc: eggert, schwab, stefankangas, pipcet, 36649, larsi, akrl

> From: Robert Pluim <rpluim@gmail.com>
> Date: Thu, 04 Mar 2021 15:56:10 +0100
> Cc: eggert@cs.ucla.edu, Andreas Schwab <schwab@linux-m68k.org>,
>  Stefan Kangas <stefankangas@gmail.com>, 36649@debbugs.gnu.org, larsi@gnus.org,
>  Andrea Corallo <akrl@sdf.org>
> 
> I think Emacs already assumes Qnil == 0, since there are places that
> use ! to check for Qnil rather than using NILP.

Those are bugs that need to be fixed.  Fast.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 15:49                                                   ` Eli Zaretskii
@ 2021-03-04 16:42                                                     ` Robert Pluim
  2021-03-04 17:07                                                       ` Eli Zaretskii
  2021-03-04 16:53                                                     ` martin rudalics
  2021-03-04 17:45                                                     ` Andy Moreton
  2 siblings, 1 reply; 125+ messages in thread
From: Robert Pluim @ 2021-03-04 16:42 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eggert, schwab, stefankangas, pipcet, 36649, larsi, akrl

>>>>> On Thu, 04 Mar 2021 17:49:21 +0200, Eli Zaretskii <eliz@gnu.org> said:

    >> From: Robert Pluim <rpluim@gmail.com>
    >> Date: Thu, 04 Mar 2021 15:56:10 +0100
    >> Cc: eggert@cs.ucla.edu, Andreas Schwab <schwab@linux-m68k.org>,
    >> Stefan Kangas <stefankangas@gmail.com>, 36649@debbugs.gnu.org, larsi@gnus.org,
    >> Andrea Corallo <akrl@sdf.org>
    >> 
    >> I think Emacs already assumes Qnil == 0, since there are places that
    >> use ! to check for Qnil rather than using NILP.

    Eli> Those are bugs that need to be fixed.  Fast.

Hmm,

./configure --enable-check-lisp-object-type

for emacs-master and emacs-27 builds fine, so maybe Iʼm imagining things.

Robert
-- 





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 15:49                                                   ` Eli Zaretskii
  2021-03-04 16:42                                                     ` Robert Pluim
@ 2021-03-04 16:53                                                     ` martin rudalics
  2021-03-04 17:45                                                     ` Andy Moreton
  2 siblings, 0 replies; 125+ messages in thread
From: martin rudalics @ 2021-03-04 16:53 UTC (permalink / raw)
  To: Eli Zaretskii, Robert Pluim
  Cc: eggert, schwab, stefankangas, pipcet, 36649, larsi, akrl

 >> I think Emacs already assumes Qnil == 0, since there are places that
 >> use ! to check for Qnil rather than using NILP.
 >
 > Those are bugs that need to be fixed.  Fast.

Here this would get me

../../src/window.c: In function ‘select_window’:
../../src/window.c:535:7: error: wrong type argument to unary exclamation mark
    if (!norecord || EQ (norecord, Qmark_for_redisplay))
        ^

or

   CC       window.o
../../src/window.c: In function ‘select_window’:
../../src/window.c:535:17: error: invalid operands to binary == (have ‘Lisp_Object’ {aka ‘struct Lisp_Object’} and ‘int’)
    if ((norecord == false) || EQ (norecord, Qmark_for_redisplay))
                  ^~

so I cannot imagine that we really had such bugs.  Unless you mean Lisp
variables explicitly defined via DEFVAR_BOOL.

martin






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 16:42                                                     ` Robert Pluim
@ 2021-03-04 17:07                                                       ` Eli Zaretskii
  2021-03-04 17:18                                                         ` Robert Pluim
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-03-04 17:07 UTC (permalink / raw)
  To: Robert Pluim; +Cc: eggert, schwab, stefankangas, pipcet, 36649, larsi, akrl

> From: Robert Pluim <rpluim@gmail.com>
> Cc: pipcet@gmail.com,  eggert@cs.ucla.edu,  schwab@linux-m68k.org,
>   stefankangas@gmail.com,  36649@debbugs.gnu.org,  larsi@gnus.org,
>   akrl@sdf.org
> Date: Thu, 04 Mar 2021 17:42:56 +0100
> 
>     >> I think Emacs already assumes Qnil == 0, since there are places that
>     >> use ! to check for Qnil rather than using NILP.
> 
>     Eli> Those are bugs that need to be fixed.  Fast.
> 
> Hmm,
> 
> ./configure --enable-check-lisp-object-type
> 
> for emacs-master and emacs-27 builds fine, so maybe Iʼm imagining things.

"Imagination is more important than knowledge".  Albert Einstein.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 17:07                                                       ` Eli Zaretskii
@ 2021-03-04 17:18                                                         ` Robert Pluim
  0 siblings, 0 replies; 125+ messages in thread
From: Robert Pluim @ 2021-03-04 17:18 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eggert, schwab, stefankangas, pipcet, 36649, larsi, akrl

>>>>> On Thu, 04 Mar 2021 19:07:01 +0200, Eli Zaretskii <eliz@gnu.org> said:

    >> From: Robert Pluim <rpluim@gmail.com>
    >> Cc: pipcet@gmail.com,  eggert@cs.ucla.edu,  schwab@linux-m68k.org,
    >> stefankangas@gmail.com,  36649@debbugs.gnu.org,  larsi@gnus.org,
    >> akrl@sdf.org
    >> Date: Thu, 04 Mar 2021 17:42:56 +0100
    >> 
    >> >> I think Emacs already assumes Qnil == 0, since there are places that
    >> >> use ! to check for Qnil rather than using NILP.
    >> 
    Eli> Those are bugs that need to be fixed.  Fast.
    >> 
    >> Hmm,
    >> 
    >> ./configure --enable-check-lisp-object-type
    >> 
    >> for emacs-master and emacs-27 builds fine, so maybe Iʼm imagining things.

    Eli> "Imagination is more important than knowledge".  Albert Einstein.

:-) Tell that to the compiler

Robert
-- 





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 15:49                                                   ` Eli Zaretskii
  2021-03-04 16:42                                                     ` Robert Pluim
  2021-03-04 16:53                                                     ` martin rudalics
@ 2021-03-04 17:45                                                     ` Andy Moreton
  2 siblings, 0 replies; 125+ messages in thread
From: Andy Moreton @ 2021-03-04 17:45 UTC (permalink / raw)
  To: 36649

On Thu 04 Mar 2021, Eli Zaretskii wrote:

>> From: Robert Pluim <rpluim@gmail.com>
>> Date: Thu, 04 Mar 2021 15:56:10 +0100
>> Cc: eggert@cs.ucla.edu, Andreas Schwab <schwab@linux-m68k.org>,
>>  Stefan Kangas <stefankangas@gmail.com>, 36649@debbugs.gnu.org, larsi@gnus.org,
>>  Andrea Corallo <akrl@sdf.org>
>> 
>> I think Emacs already assumes Qnil == 0, since there are places that
>> use ! to check for Qnil rather than using NILP.
>
> Those are bugs that need to be fixed.  Fast.

Agree that they are bugs, but also see NIL_IS_ZERO and memclear() in lisp.h.

    AndyM






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 14:56                                                 ` Robert Pluim
  2021-03-04 15:49                                                   ` Eli Zaretskii
@ 2021-03-04 21:52                                                   ` Paul Eggert
  2021-03-05  3:00                                                     ` Pip Cet
  1 sibling, 1 reply; 125+ messages in thread
From: Paul Eggert @ 2021-03-04 21:52 UTC (permalink / raw)
  To: Robert Pluim, Pip Cet
  Cc: 36649, larsi, Andreas Schwab, Stefan Kangas, Andrea Corallo

On 3/4/21 6:56 AM, Robert Pluim wrote:
>      Pip> - zero vector handling depends on Qnil being all zero in memory
> 
> I think Emacs already assumes Qnil == 0, since there are places that
> use ! to check for Qnil rather than using NILP.

The convention is to put a "verify (NIL_IS_ZERO);" near the rare bits of 
code that assume Qnil is all-bits-zero. This is to help out any 
hypothetical future developer who wants to change Qnil to be some other 
value. Currently there are only two such locations. (There is one other 
location that uses NIL_IS_ZERO for an optimization.)





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-04 21:52                                                   ` Paul Eggert
@ 2021-03-05  3:00                                                     ` Pip Cet
  2021-03-05  7:20                                                       ` Eli Zaretskii
  2021-03-14 22:19                                                       ` Stefan Monnier
  0 siblings, 2 replies; 125+ messages in thread
From: Pip Cet @ 2021-03-05  3:00 UTC (permalink / raw)
  To: Paul Eggert
  Cc: Robert Pluim, Andreas Schwab, Stefan Kangas, 36649, larsi,
	Andrea Corallo

[-- Attachment #1: Type: text/plain, Size: 982 bytes --]

On Thu, Mar 4, 2021 at 9:52 PM Paul Eggert <eggert@cs.ucla.edu> wrote:
> On 3/4/21 6:56 AM, Robert Pluim wrote:
> >      Pip> - zero vector handling depends on Qnil being all zero in memory
> >
> > I think Emacs already assumes Qnil == 0, since there are places that
> > use ! to check for Qnil rather than using NILP.
>
> The convention is to put a "verify (NIL_IS_ZERO);" near the rare bits of
> code that assume Qnil is all-bits-zero.

That would be nice, but I'm quite certain there are places in the code
that rely on this identity without doing that...

> This is to help out any
> hypothetical future developer who wants to change Qnil to be some other
> value. Currently there are only two such locations. (There is one other
> location that uses NIL_IS_ZERO for an optimization.)

When I did the NaN boxing thing, I remember seeing quite a few 0.0s
popping up where I was expecting nil :-)

Anyway, it's easy enough to remove the assumption. Here's the current patch.

Pip

[-- Attachment #2: 0001-Remove-pure-space-Bug-36649.patch --]
[-- Type: text/x-patch, Size: 95097 bytes --]

From 3a4eefc4646e525a720561716923efea44e8104e Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@gmail.com>
Date: Wed, 3 Mar 2021 15:27:02 +0000
Subject: [PATCH] Remove pure space (Bug#36649)

* src/lisp.h (struct Lisp_Symbol): Remove `pinned' flag.
(build_pure_c_string, pure_listn): Remove.  All calls removed.
* src/puresize.h: Remove file.
* src/fns.c (Fmake_hash_table): Ignore `:purecopy' argument.
* src/doc.c (store_function_docstring): Remove comment about pure
space.
* src/data.c (pure_write_error): Remove.  All calls removed.
* src/conf_post.h (SYSTEM_PURESIZE_EXTRA): Remove.
* src/fns.c (make_hash_table): Drop `purecopy' argument.  All
callers changed to remove argument.
* src/alloc.c (make_pure_string, make_pure_c_string, pure_cons)
(pure_list): Remove.  All calls removed.
(check_pure_size): Remove.  All calls removed.
(cons_listn): Simplify.
(Fmake_byte_code): Remove comment about pure space.
(pointer_align): Move definition to avoid warning.
* src/Makefile.in: Remove comment about pure space.
---
 doc/lispref/elisp.texi     |   1 -
 doc/lispref/internals.texi |  78 ------
 doc/lispref/symbols.texi   |   3 +-
 src/Makefile.in            |   2 -
 src/alloc.c                | 549 ++++---------------------------------
 src/buffer.c               |  16 +-
 src/callint.c              |   8 +-
 src/category.c             |   4 +-
 src/coding.c               |  18 +-
 src/conf_post.h            |  33 ---
 src/data.c                 |  29 +-
 src/dbusbind.c             |   4 +-
 src/deps.mk                |  10 +-
 src/doc.c                  |   3 -
 src/emacs-module.c         |  28 +-
 src/emacs.c                |   5 +-
 src/eval.c                 |  12 +-
 src/fileio.c               |  22 +-
 src/fns.c                  |  32 +--
 src/fontset.c              |   4 +-
 src/frame.c                |   2 +-
 src/image.c                |   2 +-
 src/intervals.c            |   2 -
 src/json.c                 |   4 +-
 src/keyboard.c             |   8 +-
 src/keymap.c               |  34 +--
 src/lisp.h                 |  41 +--
 src/lread.c                |  53 ++--
 src/pdumper.c              |   9 +-
 src/print.c                |   6 -
 src/process.c              |   4 +-
 src/profiler.c             |   2 +-
 src/puresize.h             | 115 --------
 src/search.c               |  12 +-
 src/syntax.c               |   4 +-
 src/w32fns.c               |   4 +-
 src/xdisp.c                |  18 +-
 src/xfaces.c               |   2 +-
 src/xfns.c                 |   9 +-
 src/xterm.c                |   4 +-
 40 files changed, 201 insertions(+), 995 deletions(-)
 delete mode 100644 src/puresize.h

diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 12255d122f9fe..2014292028b26 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -1601,7 +1601,6 @@ Top
 GNU Emacs Internals
 
 * Building Emacs::          How the dumped Emacs is made.
-* Pure Storage::            Kludge to make preloaded Lisp functions shareable.
 * Garbage Collection::      Reclaiming space for Lisp objects no longer used.
 * Stack-allocated Objects:: Temporary conses and strings on C stack.
 * Memory Usage::            Info about total size of Lisp objects made so far.
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index 4150a2b21b8fb..b684933887b80 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -12,7 +12,6 @@ GNU Emacs Internals
 
 @menu
 * Building Emacs::      How the dumped Emacs is made.
-* Pure Storage::        Kludge to make preloaded Lisp functions shareable.
 * Garbage Collection::  Reclaiming space for Lisp objects no longer used.
 * Stack-allocated Objects::    Temporary conses and strings on C stack.
 * Memory Usage::        Info about total size of Lisp objects made so far.
@@ -243,71 +242,6 @@ Building Emacs
 value is nil.
 @end defun
 
-@node Pure Storage
-@section Pure Storage
-@cindex pure storage
-
-  Emacs Lisp uses two kinds of storage for user-created Lisp objects:
-@dfn{normal storage} and @dfn{pure storage}.  Normal storage is where
-all the new data created during an Emacs session are kept
-(@pxref{Garbage Collection}).  Pure storage is used for certain data
-in the preloaded standard Lisp files---data that should never change
-during actual use of Emacs.
-
-  Pure storage is allocated only while @command{temacs} is loading the
-standard preloaded Lisp libraries.  In the file @file{emacs}, it is
-marked as read-only (on operating systems that permit this), so that
-the memory space can be shared by all the Emacs jobs running on the
-machine at once.  Pure storage is not expandable; a fixed amount is
-allocated when Emacs is compiled, and if that is not sufficient for
-the preloaded libraries, @file{temacs} allocates dynamic memory for
-the part that didn't fit.  If Emacs will be dumped using the
-@code{pdump} method (@pxref{Building Emacs}), the pure-space overflow
-is of no special importance (it just means some of the preloaded stuff
-cannot be shared with other Emacs jobs).  However, if Emacs will be
-dumped using the now obsolete @code{unexec} method, the resulting
-image will work, but garbage collection (@pxref{Garbage Collection})
-is disabled in this situation, causing a memory leak.  Such an
-overflow normally won't happen unless you try to preload additional
-libraries or add features to the standard ones.  Emacs will display a
-warning about the overflow when it starts, if it was dumped using
-@code{unexec}.  If this happens, you should increase the compilation
-parameter @code{SYSTEM_PURESIZE_EXTRA} in the file
-@file{src/puresize.h} and rebuild Emacs.
-
-@defun purecopy object
-This function makes a copy in pure storage of @var{object}, and returns
-it.  It copies a string by simply making a new string with the same
-characters, but without text properties, in pure storage.  It
-recursively copies the contents of vectors and cons cells.  It does
-not make copies of other objects such as symbols, but just returns
-them unchanged.  It signals an error if asked to copy markers.
-
-This function is a no-op except while Emacs is being built and dumped;
-it is usually called only in preloaded Lisp files.
-@end defun
-
-@defvar pure-bytes-used
-The value of this variable is the number of bytes of pure storage
-allocated so far.  Typically, in a dumped Emacs, this number is very
-close to the total amount of pure storage available---if it were not,
-we would preallocate less.
-@end defvar
-
-@defvar purify-flag
-This variable determines whether @code{defun} should make a copy of the
-function definition in pure storage.  If it is non-@code{nil}, then the
-function definition is copied into pure storage.
-
-This flag is @code{t} while loading all of the basic functions for
-building Emacs initially (allowing those functions to be shareable and
-non-collectible).  Dumping Emacs as an executable always writes
-@code{nil} in this variable, regardless of the value it actually has
-before and after dumping.
-
-You should not change this flag in a running Emacs.
-@end defvar
-
 @node Garbage Collection
 @section Garbage Collection
 
@@ -514,12 +448,6 @@ Garbage Collection
 @item free-size
 Heap space which is not currently used, in @var{unit-size} units.
 @end table
-
-If there was overflow in pure space (@pxref{Pure Storage}), and Emacs
-was dumped using the (now obsolete) @code{unexec} method
-(@pxref{Building Emacs}), then @code{garbage-collect} returns
-@code{nil}, because a real garbage collection cannot be done in that
-case.
 @end deffn
 
 @defopt garbage-collection-messages
@@ -934,12 +862,6 @@ Writing Emacs Primitives
 arguments could be very long.  This increases Emacs responsiveness and
 improves user experience.
 
-  You must not use C initializers for static or global variables unless
-the variables are never written once Emacs is dumped.  These variables
-with initializers are allocated in an area of memory that becomes
-read-only (on certain operating systems) as a result of dumping Emacs.
-@xref{Pure Storage}.
-
 @cindex @code{defsubr}, Lisp symbol for a primitive
   Defining the C function is not enough to make a Lisp primitive
 available; you must also create the Lisp symbol for the primitive and
diff --git a/doc/lispref/symbols.texi b/doc/lispref/symbols.texi
index ed36f5139a856..11247cd612128 100644
--- a/doc/lispref/symbols.texi
+++ b/doc/lispref/symbols.texi
@@ -562,8 +562,7 @@ Standard Properties
 If the value is non-@code{nil}, the named function is considered to be
 pure (@pxref{What Is a Function}).  Calls with constant arguments can
 be evaluated at compile time.  This may shift run time errors to
-compile time.  Not to be confused with pure storage (@pxref{Pure
-Storage}).
+compile time.
 
 @item risky-local-variable
 If the value is non-@code{nil}, the named variable is considered risky
diff --git a/src/Makefile.in b/src/Makefile.in
index 4100edf4712fe..0330b2d354b18 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -406,8 +406,6 @@ .c.o:
 .m.o:
 	$(AM_V_CC)$(CC) -c $(CPPFLAGS) $(ALL_OBJC_CFLAGS) $(PROFILING_CFLAGS) $<
 
-## lastfile must follow all files whose initialized data areas should
-## be dumped as pure by dump-emacs.
 base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
 	charset.o coding.o category.o ccl.o character.o chartab.o bidi.o \
 	$(CM_OBJ) term.o terminal.o xfaces.o $(XOBJ) $(GTK_OBJ) $(DBUS_OBJ) \
diff --git a/src/alloc.c b/src/alloc.c
index e72fc4c4332de..bee702e92168c 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -34,7 +34,6 @@ Copyright (C) 1985-1986, 1988, 1993-1995, 1997-2021 Free Software
 #include "bignum.h"
 #include "dispextern.h"
 #include "intervals.h"
-#include "puresize.h"
 #include "sheap.h"
 #include "sysstdio.h"
 #include "systime.h"
@@ -333,33 +332,6 @@ #define HI_THRESHOLD (EMACS_INT_MAX / 2)
 
 #define SPARE_MEMORY (1 << 14)
 
-/* Initialize it to a nonzero value to force it into data space
-   (rather than bss space).  That way unexec will remap it into text
-   space (pure), on some systems.  We have not implemented the
-   remapping on more recent systems because this is less important
-   nowadays than in the days of small memories and timesharing.  */
-
-EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,};
-#define PUREBEG (char *) pure
-
-/* Pointer to the pure area, and its size.  */
-
-static char *purebeg;
-static ptrdiff_t pure_size;
-
-/* Number of bytes of pure storage used before pure storage overflowed.
-   If this is non-zero, this implies that an overflow occurred.  */
-
-static ptrdiff_t pure_bytes_used_before_overflow;
-
-/* Index in pure at which next pure Lisp object will be allocated..  */
-
-static ptrdiff_t pure_bytes_used_lisp;
-
-/* Number of bytes allocated for non-Lisp objects in pure storage.  */
-
-static ptrdiff_t pure_bytes_used_non_lisp;
-
 /* If positive, garbage collection is inhibited.  Otherwise, zero.  */
 
 static intptr_t garbage_collection_inhibited;
@@ -434,7 +406,6 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
 static void unchain_finalizer (struct Lisp_Finalizer *);
 static void mark_terminals (void);
 static void gc_sweep (void);
-static Lisp_Object make_pure_vector (ptrdiff_t);
 static void mark_buffer (struct buffer *);
 
 #if !defined REL_ALLOC || defined SYSTEM_MALLOC || defined HYBRID_MALLOC
@@ -576,16 +547,6 @@ #define MEM_NIL &mem_z
 
 int staticidx;
 
-static void *pure_alloc (size_t, int);
-
-/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
-
-static void *
-pointer_align (void *ptr, int alignment)
-{
-  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
-}
-
 /* Extract the pointer hidden within O.  */
 
 static ATTRIBUTE_NO_SANITIZE_UNDEFINED void *
@@ -1075,6 +1036,15 @@ verify (POWER_OF_2 (BLOCK_ALIGN));
 # elif !defined HYBRID_MALLOC && defined HAVE_POSIX_MEMALIGN
 #  define USE_ALIGNED_ALLOC 1
 #  define aligned_alloc my_aligned_alloc /* Avoid collision with lisp.h.  */
+
+/* Return PTR rounded up to the next multiple of ALIGNMENT.  */
+
+static void *
+pointer_align (void *ptr, int alignment)
+{
+  return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
+}
+
 static void *
 aligned_alloc (size_t alignment, size_t size)
 {
@@ -1679,9 +1649,9 @@ #define GC_STRING_EXTRA GC_STRING_OVERRUN_COOKIE_SIZE
 static void
 init_strings (void)
 {
-  empty_unibyte_string = make_pure_string ("", 0, 0, 0);
+  empty_unibyte_string = make_specified_string ("", 0, 0, false);
   staticpro (&empty_unibyte_string);
-  empty_multibyte_string = make_pure_string ("", 0, 0, 1);
+  empty_multibyte_string = make_specified_string ("", 0, 0, true);
   staticpro (&empty_multibyte_string);
 }
 
@@ -1699,7 +1669,7 @@ string_bytes (struct Lisp_String *s)
   ptrdiff_t nbytes =
     (s->u.s.size_byte < 0 ? s->u.s.size & ~ARRAY_MARK_FLAG : s->u.s.size_byte);
 
-  if (!PURE_P (s) && !pdumper_object_p (s) && s->u.s.data
+  if (!pdumper_object_p (s) && s->u.s.data
       && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
     emacs_abort ();
   return nbytes;
@@ -2415,7 +2385,7 @@ make_specified_string (const char *contents,
 {
   Lisp_Object val;
 
-  if (nchars < 0)
+  if (nchars <= 0)
     {
       if (multibyte)
 	nchars = multibyte_chars_in_text ((const unsigned char *) contents,
@@ -2469,8 +2439,6 @@ make_clear_multibyte_string (EMACS_INT nchars, EMACS_INT nbytes, bool clearit)
 
   if (nchars < 0)
     emacs_abort ();
-  if (!nbytes)
-    return empty_multibyte_string;
 
   s = allocate_string ();
   s->u.s.intervals = NULL;
@@ -2751,17 +2719,16 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4,
 }
 
 /* Make a list of COUNT Lisp_Objects, where ARG is the first one.
-   Use CONS to construct the pairs.  AP has any remaining args.  */
+   AP has any remaining args.  */
 static Lisp_Object
-cons_listn (ptrdiff_t count, Lisp_Object arg,
-	    Lisp_Object (*cons) (Lisp_Object, Lisp_Object), va_list ap)
+cons_listn (ptrdiff_t count, Lisp_Object arg, va_list ap)
 {
   eassume (0 < count);
-  Lisp_Object val = cons (arg, Qnil);
+  Lisp_Object val = Fcons (arg, Qnil);
   Lisp_Object tail = val;
   for (ptrdiff_t i = 1; i < count; i++)
     {
-      Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil);
+      Lisp_Object elem = Fcons (va_arg (ap, Lisp_Object), Qnil);
       XSETCDR (tail, elem);
       tail = elem;
     }
@@ -2774,18 +2741,7 @@ listn (ptrdiff_t count, Lisp_Object arg1, ...)
 {
   va_list ap;
   va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, Fcons, ap);
-  va_end (ap);
-  return val;
-}
-
-/* Make a pure list of COUNT Lisp_Objects, where ARG1 is the first one.  */
-Lisp_Object
-pure_listn (ptrdiff_t count, Lisp_Object arg1, ...)
-{
-  va_list ap;
-  va_start (ap, arg1);
-  Lisp_Object val = cons_listn (count, arg1, pure_cons, ap);
+  Lisp_Object val = cons_listn (count, arg1, ap);
   va_end (ap);
   return val;
 }
@@ -2951,7 +2907,7 @@ large_vector_vec (struct large_vector *p)
 
 static struct large_vector *large_vectors;
 
-/* The only vector with 0 slots, allocated from pure space.  */
+/* The only vector with 0 slots.  */
 
 Lisp_Object zero_vector;
 
@@ -2987,15 +2943,6 @@ allocate_vector_block (void)
   return block;
 }
 
-/* Called once to initialize vector allocation.  */
-
-static void
-init_vectors (void)
-{
-  zero_vector = make_pure_vector (0);
-  staticpro (&zero_vector);
-}
-
 /* Allocate vector from a vector block.  */
 
 static struct Lisp_Vector *
@@ -3086,6 +3033,8 @@ vectorlike_nbytes (const union vectorlike_header *hdr)
     }
   else
     nwords = size;
+  if (nwords == 0)
+    nwords = 1;
   return vroundup (header_size + word_size * nwords);
 }
 
@@ -3343,6 +3292,18 @@ allocate_nil_vector (ptrdiff_t len)
 }
 
 
+/* Called once to initialize vector allocation.  */
+
+static void
+init_vectors (void)
+{
+  zero_vector =
+    make_lisp_ptr (allocate_vectorlike (1, true), Lisp_Vectorlike);
+  XVECTOR (zero_vector)->header.size = 0;
+  XVECTOR (zero_vector)->contents[0] = Qnil;
+  staticpro (&zero_vector);
+}
+
 /* Allocate other vector-like structures.  */
 
 struct Lisp_Vector *
@@ -3555,13 +3516,6 @@ #define SYMBOL_BLOCK_SIZE \
 
 static struct symbol_block *symbol_block;
 static int symbol_block_index = SYMBOL_BLOCK_SIZE;
-/* Pointer to the first symbol_block that contains pinned symbols.
-   Tests for 24.4 showed that at dump-time, Emacs contains about 15K symbols,
-   10K of which are pinned (and all but 250 of them are interned in obarray),
-   whereas a "typical session" has in the order of 30K symbols.
-   `symbol_block_pinned' lets mark_pinned_symbols scan only 15K symbols rather
-   than 30K to find the 10K symbols we need to mark.  */
-static struct symbol_block *symbol_block_pinned;
 
 /* List of free symbols.  */
 
@@ -3587,7 +3541,6 @@ init_symbol (Lisp_Object val, Lisp_Object name)
   p->u.s.interned = SYMBOL_UNINTERNED;
   p->u.s.trapped_write = SYMBOL_UNTRAPPED_WRITE;
   p->u.s.declared_special = false;
-  p->u.s.pinned = false;
 }
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
@@ -5151,8 +5104,6 @@ valid_lisp_object_p (Lisp_Object obj)
     return 1;
 
   void *p = XPNTR (obj);
-  if (PURE_P (p))
-    return 1;
 
   if (SYMBOLP (obj) && c_symbol_p (p))
     return ((char *) p - (char *) lispsym) % sizeof lispsym[0] == 0;
@@ -5208,296 +5159,8 @@ valid_lisp_object_p (Lisp_Object obj)
   return 0;
 }
 
-/***********************************************************************
-		       Pure Storage Management
- ***********************************************************************/
-
-/* Allocate room for SIZE bytes from pure Lisp storage and return a
-   pointer to it.  TYPE is the Lisp type for which the memory is
-   allocated.  TYPE < 0 means it's not used for a Lisp object,
-   and that the result should have an alignment of -TYPE.
-
-   The bytes are initially zero.
-
-   If pure space is exhausted, allocate space from the heap.  This is
-   merely an expedient to let Emacs warn that pure space was exhausted
-   and that Emacs should be rebuilt with a larger pure space.  */
-
-static void *
-pure_alloc (size_t size, int type)
-{
-  void *result;
-
- again:
-  if (type >= 0)
-    {
-      /* Allocate space for a Lisp object from the beginning of the free
-	 space with taking account of alignment.  */
-      result = pointer_align (purebeg + pure_bytes_used_lisp, LISP_ALIGNMENT);
-      pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size;
-    }
-  else
-    {
-      /* Allocate space for a non-Lisp object from the end of the free
-	 space.  */
-      ptrdiff_t unaligned_non_lisp = pure_bytes_used_non_lisp + size;
-      char *unaligned = purebeg + pure_size - unaligned_non_lisp;
-      int decr = (intptr_t) unaligned & (-1 - type);
-      pure_bytes_used_non_lisp = unaligned_non_lisp + decr;
-      result = unaligned - decr;
-    }
-  pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp;
-
-  if (pure_bytes_used <= pure_size)
-    return result;
-
-  /* Don't allocate a large amount here,
-     because it might get mmap'd and then its address
-     might not be usable.  */
-  int small_amount = 10000;
-  eassert (size <= small_amount - LISP_ALIGNMENT);
-  purebeg = xzalloc (small_amount);
-  pure_size = small_amount;
-  pure_bytes_used_before_overflow += pure_bytes_used - size;
-  pure_bytes_used = 0;
-  pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0;
-
-  /* Can't GC if pure storage overflowed because we can't determine
-     if something is a pure object or not.  */
-  garbage_collection_inhibited++;
-  goto again;
-}
-
-
-#ifdef HAVE_UNEXEC
-
-/* Print a warning if PURESIZE is too small.  */
-
-void
-check_pure_size (void)
-{
-  if (pure_bytes_used_before_overflow)
-    message (("emacs:0:Pure Lisp storage overflow (approx. %"pI"d"
-	      " bytes needed)"),
-	     pure_bytes_used + pure_bytes_used_before_overflow);
-}
-#endif
-
-
-/* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
-   the non-Lisp data pool of the pure storage, and return its start
-   address.  Return NULL if not found.  */
-
-static char *
-find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
-{
-  int i;
-  ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max;
-  const unsigned char *p;
-  char *non_lisp_beg;
-
-  if (pure_bytes_used_non_lisp <= nbytes)
-    return NULL;
-
-  /* Set up the Boyer-Moore table.  */
-  skip = nbytes + 1;
-  for (i = 0; i < 256; i++)
-    bm_skip[i] = skip;
-
-  p = (const unsigned char *) data;
-  while (--skip > 0)
-    bm_skip[*p++] = skip;
-
-  last_char_skip = bm_skip['\0'];
-
-  non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp;
-  start_max = pure_bytes_used_non_lisp - (nbytes + 1);
-
-  /* See the comments in the function `boyer_moore' (search.c) for the
-     use of `infinity'.  */
-  infinity = pure_bytes_used_non_lisp + 1;
-  bm_skip['\0'] = infinity;
-
-  p = (const unsigned char *) non_lisp_beg + nbytes;
-  start = 0;
-  do
-    {
-      /* Check the last character (== '\0').  */
-      do
-	{
-	  start += bm_skip[*(p + start)];
-	}
-      while (start <= start_max);
-
-      if (start < infinity)
-	/* Couldn't find the last character.  */
-	return NULL;
-
-      /* No less than `infinity' means we could find the last
-	 character at `p[start - infinity]'.  */
-      start -= infinity;
-
-      /* Check the remaining characters.  */
-      if (memcmp (data, non_lisp_beg + start, nbytes) == 0)
-	/* Found.  */
-	return non_lisp_beg + start;
-
-      start += last_char_skip;
-    }
-  while (start <= start_max);
-
-  return NULL;
-}
-
-
-/* Return a string allocated in pure space.  DATA is a buffer holding
-   NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
-   means make the result string multibyte.
-
-   Must get an error if pure storage is full, since if it cannot hold
-   a large string it may be able to hold conses that point to that
-   string; then the string is not protected from gc.  */
-
-Lisp_Object
-make_pure_string (const char *data,
-		  ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->u.s.data == NULL)
-    {
-      s->u.s.data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->u.s.data, data, nbytes);
-      s->u.s.data[nbytes] = '\0';
-    }
-  s->u.s.size = nchars;
-  s->u.s.size_byte = multibyte ? nbytes : -1;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-/* Return a string allocated in pure space.  Do not
-   allocate the string data, just point to DATA.  */
-
-Lisp_Object
-make_pure_c_string (const char *data, ptrdiff_t nchars)
-{
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.size = nchars;
-  s->u.s.size_byte = -2;
-  s->u.s.data = (unsigned char *) data;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
-}
-
-static Lisp_Object purecopy (Lisp_Object obj);
-
-/* Return a cons allocated from pure space.  Give it pure copies
-   of CAR as car and CDR as cdr.  */
-
-Lisp_Object
-pure_cons (Lisp_Object car, Lisp_Object cdr)
-{
-  Lisp_Object new;
-  struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons);
-  XSETCONS (new, p);
-  XSETCAR (new, purecopy (car));
-  XSETCDR (new, purecopy (cdr));
-  return new;
-}
-
-
-/* Value is a float object with value NUM allocated from pure space.  */
-
-static Lisp_Object
-make_pure_float (double num)
-{
-  Lisp_Object new;
-  struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float);
-  XSETFLOAT (new, p);
-  XFLOAT_INIT (new, num);
-  return new;
-}
-
-/* Value is a bignum object with value VALUE allocated from pure
-   space.  */
-
 static Lisp_Object
-make_pure_bignum (Lisp_Object value)
-{
-  mpz_t const *n = xbignum_val (value);
-  size_t i, nlimbs = mpz_size (*n);
-  size_t nbytes = nlimbs * sizeof (mp_limb_t);
-  mp_limb_t *pure_limbs;
-  mp_size_t new_size;
-
-  struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike);
-  XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum));
-
-  int limb_alignment = alignof (mp_limb_t);
-  pure_limbs = pure_alloc (nbytes, - limb_alignment);
-  for (i = 0; i < nlimbs; ++i)
-    pure_limbs[i] = mpz_getlimbn (*n, i);
-
-  new_size = nlimbs;
-  if (mpz_sgn (*n) < 0)
-    new_size = -new_size;
-
-  mpz_roinit_n (b->value, pure_limbs, new_size);
-
-  return make_lisp_ptr (b, Lisp_Vectorlike);
-}
-
-/* Return a vector with room for LEN Lisp_Objects allocated from
-   pure space.  */
-
-static Lisp_Object
-make_pure_vector (ptrdiff_t len)
-{
-  Lisp_Object new;
-  size_t size = header_size + len * word_size;
-  struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike);
-  XSETVECTOR (new, p);
-  XVECTOR (new)->header.size = len;
-  return new;
-}
-
-/* Copy all contents and parameters of TABLE to a new table allocated
-   from pure space, return the purified table.  */
-static struct Lisp_Hash_Table *
-purecopy_hash_table (struct Lisp_Hash_Table *table)
-{
-  eassert (NILP (table->weak));
-  eassert (table->purecopy);
-
-  struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
-  struct hash_table_test pure_test = table->test;
-
-  /* Purecopy the hash table test.  */
-  pure_test.name = purecopy (table->test.name);
-  pure_test.user_hash_function = purecopy (table->test.user_hash_function);
-  pure_test.user_cmp_function = purecopy (table->test.user_cmp_function);
-
-  pure->header = table->header;
-  pure->weak = purecopy (Qnil);
-  pure->hash = purecopy (table->hash);
-  pure->next = purecopy (table->next);
-  pure->index = purecopy (table->index);
-  pure->count = table->count;
-  pure->next_free = table->next_free;
-  pure->purecopy = table->purecopy;
-  eassert (!pure->mutable);
-  pure->rehash_threshold = table->rehash_threshold;
-  pure->rehash_size = table->rehash_size;
-  pure->key_and_value = purecopy (table->key_and_value);
-  pure->test = pure_test;
-
-  return pure;
-}
+purecopy (Lisp_Object obj);
 
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
        doc: /* Make a copy of object OBJ in pure storage.
@@ -5514,100 +5177,23 @@ DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
     return purecopy (obj);
 }
 
-/* Pinned objects are marked before every GC cycle.  */
-static struct pinned_object
-{
-  Lisp_Object object;
-  struct pinned_object *next;
-} *pinned_objects;
-
 static Lisp_Object
 purecopy (Lisp_Object obj)
 {
-  if (FIXNUMP (obj)
-      || (! SYMBOLP (obj) && PURE_P (XPNTR (obj)))
-      || SUBRP (obj))
+  if (FIXNUMP (obj) || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
-    message_with_string ("Dropping text-properties while making string `%s' pure",
-			 obj, true);
-
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
     {
       Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
       if (!NILP (tmp))
 	return tmp;
+      Fputhash (obj, obj, Vpurify_flag);
     }
 
-  if (CONSP (obj))
-    obj = pure_cons (XCAR (obj), XCDR (obj));
-  else if (FLOATP (obj))
-    obj = make_pure_float (XFLOAT_DATA (obj));
-  else if (STRINGP (obj))
-    obj = make_pure_string (SSDATA (obj), SCHARS (obj),
-			    SBYTES (obj),
-			    STRING_MULTIBYTE (obj));
-  else if (HASH_TABLE_P (obj))
-    {
-      struct Lisp_Hash_Table *table = XHASH_TABLE (obj);
-      /* Do not purify hash tables which haven't been defined with
-         :purecopy as non-nil or are weak - they aren't guaranteed to
-         not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
-        {
-          /* Instead, add the hash table to the list of pinned objects,
-             so that it will be marked during GC.  */
-          struct pinned_object *o = xmalloc (sizeof *o);
-          o->object = obj;
-          o->next = pinned_objects;
-          pinned_objects = o;
-          return obj; /* Don't hash cons it.  */
-        }
-
-      struct Lisp_Hash_Table *h = purecopy_hash_table (table);
-      XSET_HASH_TABLE (obj, h);
-    }
-  else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
-    {
-      struct Lisp_Vector *objp = XVECTOR (obj);
-      ptrdiff_t nbytes = vector_nbytes (objp);
-      struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
-      register ptrdiff_t i;
-      ptrdiff_t size = ASIZE (obj);
-      if (size & PSEUDOVECTOR_FLAG)
-	size &= PSEUDOVECTOR_SIZE_MASK;
-      memcpy (vec, objp, nbytes);
-      for (i = 0; i < size; i++)
-	vec->contents[i] = purecopy (vec->contents[i]);
-      XSETVECTOR (obj, vec);
-    }
-  else if (SYMBOLP (obj))
-    {
-      if (!XSYMBOL (obj)->u.s.pinned && !c_symbol_p (XSYMBOL (obj)))
-	{ /* We can't purify them, but they appear in many pure objects.
-	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XSYMBOL (obj)->u.s.pinned = true;
-	  symbol_block_pinned = symbol_block;
-	}
-      /* Don't hash-cons it.  */
-      return obj;
-    }
-  else if (BIGNUMP (obj))
-    obj = make_pure_bignum (obj);
-  else
-    {
-      AUTO_STRING (fmt, "Don't know how to purify: %S");
-      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
-    }
-
-  if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
-    Fputhash (obj, obj, Vpurify_flag);
-
   return obj;
 }
 
-
 \f
 /***********************************************************************
 			  Protection from GC
@@ -5798,31 +5384,6 @@ compact_undo_list (Lisp_Object list)
   return list;
 }
 
-static void
-mark_pinned_objects (void)
-{
-  for (struct pinned_object *pobj = pinned_objects; pobj; pobj = pobj->next)
-    mark_object (pobj->object);
-}
-
-static void
-mark_pinned_symbols (void)
-{
-  struct symbol_block *sblk;
-  int lim = (symbol_block_pinned == symbol_block
-	     ? symbol_block_index : SYMBOL_BLOCK_SIZE);
-
-  for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
-    {
-      struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
-      for (; sym < end; ++sym)
-	if (sym->u.s.pinned)
-	  mark_object (make_lisp_symbol (sym));
-
-      lim = SYMBOL_BLOCK_SIZE;
-    }
-}
-
 static void
 visit_vectorlike_root (struct gc_root_visitor visitor,
                        struct Lisp_Vector *ptr,
@@ -6083,8 +5644,6 @@ garbage_collect (void)
   struct gc_root_visitor visitor = { .visit = mark_object_root_visitor };
   visit_static_gc_roots (visitor);
 
-  mark_pinned_objects ();
-  mark_pinned_symbols ();
   mark_terminals ();
   mark_kboards ();
   mark_threads ();
@@ -6193,10 +5752,6 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
   keeps around for future allocations (maybe because it does not know how
   to return them to the OS).
 
-However, if there was overflow in pure space, and Emacs was dumped
-using the 'unexec' method, `garbage-collect' returns nil, because
-real GC can't be done.
-
 Note that calling this function does not guarantee that absolutely all
 unreachable objects will be garbage-collected.  Emacs uses a
 mark-and-sweep garbage collector, but is conservative when it comes to
@@ -6566,8 +6121,8 @@ mark_objects (Lisp_Object *obj, ptrdiff_t n)
 mark_object (Lisp_Object arg)
 {
   register Lisp_Object obj;
-  void *po;
 #if GC_CHECK_MARKED_OBJECTS
+  void *po;
   struct mem_node *m = NULL;
 #endif
   ptrdiff_t cdr_count = 0;
@@ -6575,10 +6130,6 @@ mark_object (Lisp_Object arg)
   obj = arg;
  loop:
 
-  po = XPNTR (obj);
-  if (PURE_P (po))
-    return;
-
   last_marked[last_marked_index++] = obj;
   last_marked_index &= LAST_MARKED_SIZE - 1;
 
@@ -6587,6 +6138,8 @@ mark_object (Lisp_Object arg)
      by ~80%.  */
 #if GC_CHECK_MARKED_OBJECTS
 
+  po = XPNTR (obj);
+
   /* Check that the object pointed to by PO is known to be a Lisp
      structure allocated from the heap.  */
 #define CHECK_ALLOCATED()			\
@@ -6771,11 +6324,10 @@ #define CHECK_ALLOCATED_AND_LIVE_SYMBOL()		((void) 0)
 	    break;
 	  default: emacs_abort ();
 	  }
-	if (!PURE_P (XSTRING (ptr->u.s.name)))
-          set_string_marked (XSTRING (ptr->u.s.name));
+	set_string_marked (XSTRING (ptr->u.s.name));
         mark_interval_tree (string_intervals (ptr->u.s.name));
 	/* Inner loop to mark next symbol in this bucket, if any.  */
-	po = ptr = ptr->u.s.next;
+	ptr = ptr->u.s.next;
 	if (ptr)
 	  goto nextsym;
       }
@@ -6886,7 +6438,7 @@ survives_gc_p (Lisp_Object obj)
       emacs_abort ();
     }
 
-  return survives_p || PURE_P (XPNTR (obj));
+  return survives_p;
 }
 
 
@@ -7474,8 +7026,6 @@ init_alloc_once (void)
 static void
 init_alloc_once_for_pdumper (void)
 {
-  purebeg = PUREBEG;
-  pure_size = PURESIZE;
   mem_init ();
 
 #ifdef DOUG_LEA_MALLOC
@@ -7519,7 +7069,7 @@ syms_of_alloc (void)
   Vgc_cons_percentage = make_float (0.1);
 
   DEFVAR_INT ("pure-bytes-used", pure_bytes_used,
-	      doc: /* Number of bytes of shareable Lisp data allocated so far.  */);
+	      doc: /* No longer used.  */);
 
   DEFVAR_INT ("cons-cells-consed", cons_cells_consed,
 	      doc: /* Number of cons cells that have been consed so far.  */);
@@ -7544,10 +7094,7 @@ syms_of_alloc (void)
 	      doc: /* Number of strings that have been consed so far.  */);
 
   DEFVAR_LISP ("purify-flag", Vpurify_flag,
-	       doc: /* Non-nil means loading Lisp code in order to dump an executable.
-This means that certain objects should be allocated in shared (pure) space.
-It can also be set to a hash-table, in which case this table is used to
-do hash-consing of the objects allocated to pure space.  */);
+	       doc: /* No longer used.  */);
 
   DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages,
 	       doc: /* Non-nil means display messages at start and end of garbage collection.  */);
@@ -7563,10 +7110,10 @@ syms_of_alloc (void)
   /* We build this in advance because if we wait until we need it, we might
      not be able to allocate the memory to hold it.  */
   Vmemory_signal_data
-    = pure_list (Qerror,
-		 build_pure_c_string ("Memory exhausted--use"
-				      " M-x save-some-buffers then"
-				      " exit and restart Emacs"));
+    = list (Qerror,
+	    build_string ("Memory exhausted--use"
+			  " M-x save-some-buffers then"
+			  " exit and restart Emacs"));
 
   DEFVAR_LISP ("memory-full", Vmemory_full,
 	       doc: /* Non-nil means Emacs cannot get much more Lisp memory.  */);
diff --git a/src/buffer.c b/src/buffer.c
index 5bd9b37702f3f..69cb1a8e904a4 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5266,8 +5266,8 @@ init_buffer_once (void)
   set_buffer_intervals (&buffer_defaults, NULL);
   set_buffer_intervals (&buffer_local_symbols, NULL);
   /* This is not strictly necessary, but let's make them initialized.  */
-  bset_name (&buffer_defaults, build_pure_c_string (" *buffer-defaults*"));
-  bset_name (&buffer_local_symbols, build_pure_c_string (" *buffer-local-symbols*"));
+  bset_name (&buffer_defaults, build_string (" *buffer-defaults*"));
+  bset_name (&buffer_local_symbols, build_string (" *buffer-local-symbols*"));
   BUFFER_PVEC_INIT (&buffer_defaults);
   BUFFER_PVEC_INIT (&buffer_local_symbols);
 
@@ -5275,7 +5275,7 @@ init_buffer_once (void)
   /* Must do these before making the first buffer! */
 
   /* real setup is done in bindings.el */
-  bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
+  bset_mode_line_format (&buffer_defaults, build_string ("%-"));
   bset_header_line_format (&buffer_defaults, Qnil);
   bset_tab_line_format (&buffer_defaults, Qnil);
   bset_abbrev_mode (&buffer_defaults, Qnil);
@@ -5342,7 +5342,7 @@ init_buffer_once (void)
   current_buffer = 0;
   pdumper_remember_lv_ptr_raw (&current_buffer, Lisp_Vectorlike);
 
-  QSFundamental = build_pure_c_string ("Fundamental");
+  QSFundamental = build_string ("Fundamental");
 
   DEFSYM (Qfundamental_mode, "fundamental-mode");
   bset_major_mode (&buffer_defaults, Qfundamental_mode);
@@ -5356,10 +5356,10 @@ init_buffer_once (void)
 
   /* Super-magic invisible buffer.  */
   Vprin1_to_string_buffer =
-    Fget_buffer_create (build_pure_c_string (" prin1"), Qt);
+    Fget_buffer_create (build_string (" prin1"), Qt);
   Vbuffer_alist = Qnil;
 
-  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*"), Qnil));
+  Fset_buffer (Fget_buffer_create (build_string ("*scratch*"), Qnil));
 
   inhibit_modification_hooks = 0;
 }
@@ -5534,9 +5534,9 @@ syms_of_buffer (void)
 	       Qoverwrite_mode_binary));
 
   Fput (Qprotected_field, Qerror_conditions,
-	pure_list (Qprotected_field, Qerror));
+	list (Qprotected_field, Qerror));
   Fput (Qprotected_field, Qerror_message,
-	build_pure_c_string ("Attempt to modify a protected field"));
+	build_string ("Attempt to modify a protected field"));
 
   DEFVAR_PER_BUFFER ("tab-line-format",
 		     &BVAR (current_buffer, tab_line_format),
diff --git a/src/callint.c b/src/callint.c
index 18624637843f2..8f8a771310557 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -824,10 +824,10 @@ syms_of_callint (void)
   callint_message = Qnil;
   staticpro (&callint_message);
 
-  preserved_fns = pure_list (intern_c_string ("region-beginning"),
-			     intern_c_string ("region-end"),
-			     intern_c_string ("point"),
-			     intern_c_string ("mark"));
+  preserved_fns = list (intern_c_string ("region-beginning"),
+			intern_c_string ("region-end"),
+			intern_c_string ("point"),
+			intern_c_string ("mark"));
   staticpro (&preserved_fns);
 
   DEFSYM (Qlist, "list");
diff --git a/src/category.c b/src/category.c
index ec8f61f7f002f..907db1455778b 100644
--- a/src/category.c
+++ b/src/category.c
@@ -53,7 +53,7 @@ hash_get_category_set (Lisp_Object table, Lisp_Object category_set)
       (table, 1,
        make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			Qnil, false));
+			Qnil));
   struct Lisp_Hash_Table *h = XHASH_TABLE (XCHAR_TABLE (table)->extras[1]);
   Lisp_Object hash;
   ptrdiff_t i = hash_lookup (h, category_set, &hash);
@@ -120,8 +120,6 @@ DEFUN ("define-category", Fdefine_category, Sdefine_category, 2, 3, 0,
 
   if (!NILP (CATEGORY_DOCSTRING (table, XFIXNAT (category))))
     error ("Category `%c' is already defined", (int) XFIXNAT (category));
-  if (!NILP (Vpurify_flag))
-    docstring = Fpurecopy (docstring);
   SET_CATEGORY_DOCSTRING (table, XFIXNAT (category), docstring);
 
   return Qnil;
diff --git a/src/coding.c b/src/coding.c
index 739dd6adcb5fc..bf7d492f546c7 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -11650,7 +11650,7 @@ syms_of_coding (void)
   Vcode_conversion_reused_workbuf = Qnil;
 
   staticpro (&Vcode_conversion_workbuf_name);
-  Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
+  Vcode_conversion_workbuf_name = build_string (" *code-conversion-work*");
 
   reused_workbuf_in_use = false;
   PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
@@ -11714,9 +11714,9 @@ syms_of_coding (void)
   /* Error signaled when there's a problem with detecting a coding system.  */
   DEFSYM (Qcoding_system_error, "coding-system-error");
   Fput (Qcoding_system_error, Qerror_conditions,
-	pure_list (Qcoding_system_error, Qerror));
+	list (Qcoding_system_error, Qerror));
   Fput (Qcoding_system_error, Qerror_message,
-	build_pure_c_string ("Invalid coding system"));
+	build_string ("Invalid coding system"));
 
   DEFSYM (Qtranslation_table, "translation-table");
   Fput (Qtranslation_table, Qchar_table_extra_slots, make_fixnum (2));
@@ -11991,22 +11991,22 @@ syms_of_coding (void)
   DEFVAR_LISP ("eol-mnemonic-unix", eol_mnemonic_unix,
 	       doc: /*
 String displayed in mode line for UNIX-like (LF) end-of-line format.  */);
-  eol_mnemonic_unix = build_pure_c_string (":");
+  eol_mnemonic_unix = build_string (":");
 
   DEFVAR_LISP ("eol-mnemonic-dos", eol_mnemonic_dos,
 	       doc: /*
 String displayed in mode line for DOS-like (CRLF) end-of-line format.  */);
-  eol_mnemonic_dos = build_pure_c_string ("\\");
+  eol_mnemonic_dos = build_string ("\\");
 
   DEFVAR_LISP ("eol-mnemonic-mac", eol_mnemonic_mac,
 	       doc: /*
 String displayed in mode line for MAC-like (CR) end-of-line format.  */);
-  eol_mnemonic_mac = build_pure_c_string ("/");
+  eol_mnemonic_mac = build_string ("/");
 
   DEFVAR_LISP ("eol-mnemonic-undecided", eol_mnemonic_undecided,
 	       doc: /*
 String displayed in mode line when end-of-line format is not yet determined.  */);
-  eol_mnemonic_undecided = build_pure_c_string (":");
+  eol_mnemonic_undecided = build_string (":");
 
   DEFVAR_LISP ("enable-character-translation", Venable_character_translation,
 	       doc: /*
@@ -12146,7 +12146,7 @@ system (e.g. `iso-2022-7bit').
       intern_c_string (":for-unibyte"),
       args[coding_arg_for_unibyte] = Qt,
       intern_c_string (":docstring"),
-      (build_pure_c_string
+      (build_string
        ("Do no conversion.\n"
 	"\n"
 	"When you visit a file with this coding, the file is read into a\n"
@@ -12166,7 +12166,7 @@ system (e.g. `iso-2022-7bit').
   plist[8] = intern_c_string (":charset-list");
   plist[9] = args[coding_arg_charset_list] = list1 (Qascii);
   plist[11] = args[coding_arg_for_unibyte] = Qnil;
-  plist[13] = build_pure_c_string ("No conversion on encoding, "
+  plist[13] = build_string ("No conversion on encoding, "
 				   "automatic conversion on decoding.");
   plist[15] = args[coding_arg_eol_type] = Qnil;
   args[coding_arg_plist] = CALLMANY (Flist, plist);
diff --git a/src/conf_post.h b/src/conf_post.h
index 176ab28b21ab2..da55a1fb54abc 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -163,41 +163,8 @@ #define emacs_raise(sig) msdos_fatal_signal (sig)
 
 /* DATA_START is needed by vm-limit.c and unexcoff.c. */
 #define DATA_START (&etext + 1)
-
-/* Define one of these for easier conditionals.  */
-#ifdef HAVE_X_WINDOWS
-/* We need a little extra space, see ../../lisp/loadup.el and the
-   commentary below, in the non-X branch.  The 140KB number was
-   measured on GNU/Linux and on MS-Windows.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+140000)
-#else
-/* We need a little extra space, see ../../lisp/loadup.el.
-   As of 20091024, DOS-specific files use up 62KB of pure space.  But
-   overall, we end up wasting 130KB of pure space, because
-   BASE_PURESIZE starts at 1.47MB, while we need only 1.3MB (including
-   non-DOS specific files and load history; the latter is about 55K,
-   but depends on the depth of the top-level Emacs directory in the
-   directory tree).  Given the unknown policy of different DPMI
-   hosts regarding loading of untouched pages, I'm not going to risk
-   enlarging Emacs footprint by another 100+ KBytes.  */
-#define SYSTEM_PURESIZE_EXTRA (-170000+90000)
-#endif
 #endif  /* MSDOS */
 
-/* macOS / GNUstep need a bit more pure memory.  Of the existing knobs,
-   SYSTEM_PURESIZE_EXTRA seems like the least likely to cause problems.  */
-#ifdef HAVE_NS
-#if defined NS_IMPL_GNUSTEP
-#  define SYSTEM_PURESIZE_EXTRA 30000
-#elif defined DARWIN_OS
-#  define SYSTEM_PURESIZE_EXTRA 200000
-#endif
-#endif
-
-#ifdef CYGWIN
-#define SYSTEM_PURESIZE_EXTRA 50000
-#endif
-
 #if defined HAVE_NTGUI && !defined DebPrint
 # ifdef EMACSDEBUG
 extern void _DebPrint (const char *fmt, ...);
diff --git a/src/data.c b/src/data.c
index 0fa491b17a114..2a8c7246fae65 100644
--- a/src/data.c
+++ b/src/data.c
@@ -30,7 +30,6 @@
 
 #include "lisp.h"
 #include "bignum.h"
-#include "puresize.h"
 #include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
@@ -149,12 +148,6 @@ wrong_type_argument (Lisp_Object predicate, Lisp_Object value)
   xsignal2 (Qwrong_type_argument, predicate, value);
 }
 
-void
-pure_write_error (Lisp_Object obj)
-{
-  xsignal2 (Qerror, build_string ("Attempt to modify read-only object"), obj);
-}
-
 void
 args_out_of_range (Lisp_Object a1, Lisp_Object a2)
 {
@@ -625,7 +618,6 @@ DEFUN ("setcar", Fsetcar, Ssetcar, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcar)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCAR (cell, newcar);
   return newcar;
 }
@@ -635,7 +627,6 @@ DEFUN ("setcdr", Fsetcdr, Ssetcdr, 2, 2, 0,
   (register Lisp_Object cell, Lisp_Object newcdr)
 {
   CHECK_CONS (cell);
-  CHECK_IMPURE (cell, XCONS (cell));
   XSETCDR (cell, newcdr);
   return newcdr;
 }
@@ -798,10 +789,6 @@ DEFUN ("defalias", Fdefalias, Sdefalias, 2, 3, 0,
   (register Lisp_Object symbol, Lisp_Object definition, Lisp_Object docstring)
 {
   CHECK_SYMBOL (symbol);
-  if (!NILP (Vpurify_flag)
-      /* If `definition' is a keymap, immutable (and copying) is wrong.  */
-      && !KEYMAPP (definition))
-    definition = Fpurecopy (definition);
 
   {
     bool autoload = AUTOLOADP (definition);
@@ -2375,7 +2362,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
 
   if (VECTORP (array))
     {
-      CHECK_IMPURE (array, XVECTOR (array));
       if (idxval < 0 || idxval >= ASIZE (array))
 	args_out_of_range (array, idx);
       ASET (array, idxval, newelt);
@@ -2399,7 +2385,6 @@ DEFUN ("aset", Faset, Saset, 3, 3, 0,
     }
   else /* STRINGP */
     {
-      CHECK_IMPURE (array, XSTRING (array));
       if (idxval < 0 || idxval >= SCHARS (array))
 	args_out_of_range (array, idx);
       CHECK_CHARACTER (newelt);
@@ -3881,7 +3866,7 @@ syms_of_data (void)
 
   DEFSYM (Qcdr, "cdr");
 
-  error_tail = pure_cons (Qerror, Qnil);
+  error_tail = Fcons (Qerror, Qnil);
 
   /* ERROR is used as a signaler for random errors for which nothing else is
      right.  */
@@ -3889,11 +3874,11 @@ syms_of_data (void)
   Fput (Qerror, Qerror_conditions,
 	error_tail);
   Fput (Qerror, Qerror_message,
-	build_pure_c_string ("error"));
+	build_string ("error"));
 
 #define PUT_ERROR(sym, tail, msg)			\
-  Fput (sym, Qerror_conditions, pure_cons (sym, tail)); \
-  Fput (sym, Qerror_message, build_pure_c_string (msg))
+  Fput (sym, Qerror_conditions, Fcons (sym, tail)); \
+  Fput (sym, Qerror_message, build_string (msg))
 
   PUT_ERROR (Qquit, Qnil, "Quit");
 
@@ -3921,14 +3906,14 @@ #define PUT_ERROR(sym, tail, msg)			\
   PUT_ERROR (Qno_catch, error_tail, "No catch for tag");
   PUT_ERROR (Qend_of_file, error_tail, "End of file during parsing");
 
-  arith_tail = pure_cons (Qarith_error, error_tail);
+  arith_tail = Fcons (Qarith_error, error_tail);
   Fput (Qarith_error, Qerror_conditions, arith_tail);
-  Fput (Qarith_error, Qerror_message, build_pure_c_string ("Arithmetic error"));
+  Fput (Qarith_error, Qerror_message, build_string ("Arithmetic error"));
 
   PUT_ERROR (Qbeginning_of_buffer, error_tail, "Beginning of buffer");
   PUT_ERROR (Qend_of_buffer, error_tail, "End of buffer");
   PUT_ERROR (Qbuffer_read_only, error_tail, "Buffer is read-only");
-  PUT_ERROR (Qtext_read_only, pure_cons (Qbuffer_read_only, error_tail),
+  PUT_ERROR (Qtext_read_only, Fcons (Qbuffer_read_only, error_tail),
 	     "Text is read-only");
   PUT_ERROR (Qinhibited_interaction, error_tail,
 	     "User interaction while inhibited");
diff --git a/src/dbusbind.c b/src/dbusbind.c
index c005474d4409f..238142b95606c 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -1868,7 +1868,7 @@ syms_of_dbusbind (void)
   Fput (Qdbus_error, Qerror_conditions,
 	list2 (Qdbus_error, Qerror));
   Fput (Qdbus_error, Qerror_message,
-	build_pure_c_string ("D-Bus error"));
+	build_string ("D-Bus error"));
 
   /* Lisp symbols of the system and session buses.  */
   DEFSYM (QCsystem, ":system");
@@ -1911,7 +1911,7 @@ syms_of_dbusbind (void)
 	       Vdbus_compiled_version,
     doc: /* The version of D-Bus Emacs is compiled against.  */);
 #ifdef DBUS_VERSION_STRING
-  Vdbus_compiled_version = build_pure_c_string (DBUS_VERSION_STRING);
+  Vdbus_compiled_version = build_string (DBUS_VERSION_STRING);
 #else
   Vdbus_compiled_version = Qnil;
 #endif
diff --git a/src/deps.mk b/src/deps.mk
index eda2ed6338252..3292cf201cf74 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -132,10 +132,10 @@ insdel.o:
 keyboard.o: keyboard.c termchar.h termhooks.h termopts.h buffer.h character.h \
    commands.h frame.h window.h macros.h disptab.h keyboard.h syssignal.h \
    systime.h syntax.h $(INTERVALS_H) blockinput.h atimer.h composite.h \
-   xterm.h puresize.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
+   xterm.h msdos.h keymap.h w32term.h nsterm.h nsgui.h coding.h \
    process.h ../lib/unistd.h gnutls.h lisp.h globals.h $(config_h)
 keymap.o: keymap.c buffer.h commands.h keyboard.h termhooks.h blockinput.h \
-   atimer.h systime.h puresize.h character.h charset.h $(INTERVALS_H) \
+   atimer.h systime.h character.h charset.h $(INTERVALS_H) \
    keymap.h window.h coding.h frame.h lisp.h globals.h $(config_h)
 lastfile.o: lastfile.c $(config_h)
 macros.o: macros.c window.h buffer.h commands.h macros.h keyboard.h msdos.h \
@@ -267,12 +267,12 @@ xsettings.o:
    atimer.h termopts.h globals.h
 
 ## The files of Lisp proper.
-alloc.o: alloc.c process.h frame.h window.h buffer.h  puresize.h syssignal.h \
+alloc.o: alloc.c process.h frame.h window.h buffer.h syssignal.h \
    keyboard.h blockinput.h atimer.h systime.h character.h lisp.h $(config_h) \
    $(INTERVALS_H) termhooks.h gnutls.h coding.h ../lib/unistd.h globals.h
 bytecode.o: bytecode.c buffer.h syntax.h character.h window.h dispextern.h \
   lisp.h globals.h $(config_h) msdos.h
-data.o: data.c buffer.h puresize.h character.h syssignal.h keyboard.h frame.h \
+data.o: data.c buffer.h character.h syssignal.h keyboard.h frame.h \
    termhooks.h systime.h coding.h composite.h dispextern.h font.h ccl.h \
    lisp.h globals.h $(config_h) msdos.h
 eval.o: eval.c commands.h keyboard.h blockinput.h atimer.h systime.h frame.h \
@@ -295,7 +295,7 @@ lread.o:
 composite.o: composite.c composite.h buffer.h character.h coding.h font.h \
    ccl.h frame.h termhooks.h $(INTERVALS_H) window.h \
    lisp.h globals.h $(config_h)
-intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h puresize.h \
+intervals.o: intervals.c buffer.h $(INTERVALS_H) keyboard.h \
    keymap.h lisp.h globals.h $(config_h) systime.h coding.h
 textprop.o: textprop.c buffer.h window.h $(INTERVALS_H) \
    lisp.h globals.h $(config_h)
diff --git a/src/doc.c b/src/doc.c
index 1307aa5ee9233..2136f914297dd 100644
--- a/src/doc.c
+++ b/src/doc.c
@@ -490,8 +490,6 @@ store_function_docstring (Lisp_Object obj, EMACS_INT offset)
 	{
 	  tem = Fcdr (Fcdr (fun));
 	  if (CONSP (tem) && FIXNUMP (XCAR (tem)))
-	    /* FIXME: This modifies typically pure hash-cons'd data, so its
-	       correctness is quite delicate.  */
 	    XSETCAR (tem, make_fixnum (offset));
 	}
     }
@@ -575,7 +573,6 @@ DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
       int i = ARRAYELTS (buildobj);
       while (0 <= --i)
 	Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
-      Vbuild_files = Fpurecopy (Vbuild_files);
     }
 
   fd = emacs_open (name, O_RDONLY, 0);
diff --git a/src/emacs-module.c b/src/emacs-module.c
index f8fb54c072823..896ae65685e84 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -1600,44 +1600,44 @@ syms_of_module (void)
   Vmodule_refs_hash
     = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 		       DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-		       Qnil, false);
+		       Qnil);
 
   DEFSYM (Qmodule_load_failed, "module-load-failed");
   Fput (Qmodule_load_failed, Qerror_conditions,
-	pure_list (Qmodule_load_failed, Qerror));
+	list (Qmodule_load_failed, Qerror));
   Fput (Qmodule_load_failed, Qerror_message,
-        build_pure_c_string ("Module load failed"));
+        build_string ("Module load failed"));
 
   DEFSYM (Qmodule_open_failed, "module-open-failed");
   Fput (Qmodule_open_failed, Qerror_conditions,
-	pure_list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_open_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_open_failed, Qerror_message,
-        build_pure_c_string ("Module could not be opened"));
+        build_string ("Module could not be opened"));
 
   DEFSYM (Qmodule_not_gpl_compatible, "module-not-gpl-compatible");
   Fput (Qmodule_not_gpl_compatible, Qerror_conditions,
-	pure_list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
+	list (Qmodule_not_gpl_compatible, Qmodule_load_failed, Qerror));
   Fput (Qmodule_not_gpl_compatible, Qerror_message,
-        build_pure_c_string ("Module is not GPL compatible"));
+        build_string ("Module is not GPL compatible"));
 
   DEFSYM (Qmissing_module_init_function, "missing-module-init-function");
   Fput (Qmissing_module_init_function, Qerror_conditions,
-	pure_list (Qmissing_module_init_function, Qmodule_load_failed,
-		   Qerror));
+	list (Qmissing_module_init_function, Qmodule_load_failed,
+	      Qerror));
   Fput (Qmissing_module_init_function, Qerror_message,
-        build_pure_c_string ("Module does not export an "
+        build_string ("Module does not export an "
                              "initialization function"));
 
   DEFSYM (Qmodule_init_failed, "module-init-failed");
   Fput (Qmodule_init_failed, Qerror_conditions,
-	pure_list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
+	list (Qmodule_init_failed, Qmodule_load_failed, Qerror));
   Fput (Qmodule_init_failed, Qerror_message,
-        build_pure_c_string ("Module initialization failed"));
+        build_string ("Module initialization failed"));
 
   DEFSYM (Qinvalid_arity, "invalid-arity");
-  Fput (Qinvalid_arity, Qerror_conditions, pure_list (Qinvalid_arity, Qerror));
+  Fput (Qinvalid_arity, Qerror_conditions, list (Qinvalid_arity, Qerror));
   Fput (Qinvalid_arity, Qerror_message,
-        build_pure_c_string ("Invalid function arity"));
+        build_string ("Invalid function arity"));
 
   DEFSYM (Qmodule_function_p, "module-function-p");
   DEFSYM (Qunicode_string_p, "unicode-string-p");
diff --git a/src/emacs.c b/src/emacs.c
index fd08667f3fd4f..03ec63464daf5 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -88,7 +88,6 @@ #define MAIN_PROGRAM
 #include "syntax.h"
 #include "sysselect.h"
 #include "systime.h"
-#include "puresize.h"
 
 #include "getpagesize.h"
 #include "gnutls.h"
@@ -1544,7 +1543,9 @@ main (int argc, char **argv)
   if (!initialized)
     {
       init_alloc_once ();
+#ifdef HAVE_PDUMPER
       init_pdumper_once ();
+#endif
       init_obarray_once ();
       init_eval_once ();
       init_charset_once ();
@@ -2508,8 +2509,6 @@ DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
   Lisp_Object symbol;
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  check_pure_size ();
-
   if (! noninteractive)
     error ("Dumping Emacs works only in batch mode");
 
diff --git a/src/eval.c b/src/eval.c
index ddaa8edd81706..c0717f8cf124d 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -785,8 +785,6 @@ DEFUN ("internal--define-uninitialized-variable",
   XSYMBOL (symbol)->u.s.declared_special = true;
   if (!NILP (doc))
     {
-      if (!NILP (Vpurify_flag))
-	doc = Fpurecopy (doc);
       Fput (symbol, Qvariable_documentation, doc);
     }
   LOADHIST_ATTACH (symbol);
@@ -903,8 +901,6 @@ DEFUN ("defconst", Fdefconst, Sdefconst, 2, UNEVALLED, 0,
 
   Finternal__define_uninitialized_variable (sym, docstring);
   tem = eval_sub (XCAR (XCDR (args)));
-  if (!NILP (Vpurify_flag))
-    tem = Fpurecopy (tem);
   Fset_default (sym, tem);      /* FIXME: set-default-toplevel-value? */
   Fput (sym, Qrisky_local_variable, Qt); /* FIXME: Why?  */
   return sym;
@@ -2107,12 +2103,6 @@ DEFUN ("autoload", Fautoload, Sautoload, 2, 5, 0,
       && !AUTOLOADP (XSYMBOL (function)->u.s.function))
     return Qnil;
 
-  if (!NILP (Vpurify_flag) && EQ (docstring, make_fixnum (0)))
-    /* `read1' in lread.c has found the docstring starting with "\
-       and assumed the docstring will be provided by Snarf-documentation, so it
-       passed us 0 instead.  But that leads to accidental sharing in purecopy's
-       hash-consing, so we use a (hopefully) unique integer instead.  */
-    docstring = make_ufixnum (XHASH (function));
   return Fdefalias (function,
 		    list5 (Qautoload, file, docstring, interactive, type),
 		    Qnil);
@@ -4354,7 +4344,7 @@ syms_of_eval (void)
      also use something like Fcons (Qnil, Qnil), but json.c treats any
      cons cell as error data, so use an uninterned symbol instead.  */
   Qcatch_all_memory_full
-    = Fmake_symbol (build_pure_c_string ("catch-all-memory-full"));
+    = Fmake_symbol (build_string ("catch-all-memory-full"));
 
   defsubr (&Sor);
   defsubr (&Sand);
diff --git a/src/fileio.c b/src/fileio.c
index 741e297d29c2c..5d438865e2092 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6294,34 +6294,34 @@ syms_of_fileio (void)
   DEFSYM (Qcar_less_than_car, "car-less-than-car");
 
   Fput (Qfile_error, Qerror_conditions,
-	Fpurecopy (list2 (Qfile_error, Qerror)));
+	list2 (Qfile_error, Qerror));
   Fput (Qfile_error, Qerror_message,
-	build_pure_c_string ("File error"));
+	build_string ("File error"));
 
   Fput (Qfile_already_exists, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_already_exists, Qfile_error, Qerror)));
+	list3 (Qfile_already_exists, Qfile_error, Qerror));
   Fput (Qfile_already_exists, Qerror_message,
-	build_pure_c_string ("File already exists"));
+	build_string ("File already exists"));
 
   Fput (Qfile_date_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_date_error, Qfile_error, Qerror)));
+	list3 (Qfile_date_error, Qfile_error, Qerror));
   Fput (Qfile_date_error, Qerror_message,
-	build_pure_c_string ("Cannot set file date"));
+	build_string ("Cannot set file date"));
 
   Fput (Qfile_missing, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_missing, Qfile_error, Qerror)));
+	list3 (Qfile_missing, Qfile_error, Qerror));
   Fput (Qfile_missing, Qerror_message,
-	build_pure_c_string ("File is missing"));
+	build_string ("File is missing"));
 
   Fput (Qfile_notify_error, Qerror_conditions,
-	Fpurecopy (list3 (Qfile_notify_error, Qfile_error, Qerror)));
+	list3 (Qfile_notify_error, Qfile_error, Qerror));
   Fput (Qfile_notify_error, Qerror_message,
-	build_pure_c_string ("File notification error"));
+	build_string ("File notification error"));
 
   Fput (Qremote_file_error, Qerror_conditions,
 	Fpurecopy (list3 (Qremote_file_error, Qfile_error, Qerror)));
   Fput (Qremote_file_error, Qerror_message,
-	build_pure_c_string ("Remote file error"));
+	build_string ("Remote file error"));
 
   DEFVAR_LISP ("file-name-handler-alist", Vfile_name_handler_alist,
 	       doc: /* Alist of elements (REGEXP . HANDLER) for file names handled specially.
diff --git a/src/fns.c b/src/fns.c
index 7914bd47790a9..a22b633ec7386 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -36,7 +36,6 @@ Copyright (C) 1985-1987, 1993-1995, 1997-2021 Free Software Foundation,
 #include "buffer.h"
 #include "intervals.h"
 #include "window.h"
-#include "puresize.h"
 #include "gnutls.h"
 
 static void sort_vector_copy (Lisp_Object, ptrdiff_t,
@@ -2602,7 +2601,6 @@ DEFUN ("fillarray", Ffillarray, Sfillarray, 2, 2, 0,
       size = SCHARS (array);
       if (size != 0)
 	{
-	  CHECK_IMPURE (array, XSTRING (array));
 	  unsigned char str[MAX_MULTIBYTE_LENGTH];
 	  int len;
 	  if (STRING_MULTIBYTE (array))
@@ -2644,7 +2642,6 @@ DEFUN ("clear-string", Fclear_string, Sclear_string,
   ptrdiff_t len = SBYTES (string);
   if (len != 0 || STRING_MULTIBYTE (string))
     {
-      CHECK_IMPURE (string, XSTRING (string));
       memset (SDATA (string), 0, len);
       STRING_SET_CHARS (string, len);
       STRING_SET_UNIBYTE (string);
@@ -4179,16 +4176,12 @@ hash_index_size (struct Lisp_Hash_Table *h, ptrdiff_t size)
    size exceeds REHASH_THRESHOLD.
 
    WEAK specifies the weakness of the table.  If non-nil, it must be
-   one of the symbols `key', `value', `key-or-value', or `key-and-value'.
-
-   If PURECOPY is non-nil, the table can be copied to pure storage via
-   `purecopy' when Emacs is being dumped. Such tables can no longer be
-   changed after purecopy.  */
+   one of the symbols `key', `value', `key-or-value', or `key-and-value'. */
 
 Lisp_Object
 make_hash_table (struct hash_table_test test, EMACS_INT size,
 		 float rehash_size, float rehash_threshold,
-		 Lisp_Object weak, bool purecopy)
+		 Lisp_Object weak)
 {
   struct Lisp_Hash_Table *h;
   Lisp_Object table;
@@ -4217,7 +4210,6 @@ make_hash_table (struct hash_table_test test, EMACS_INT size,
   h->next = make_vector (size, make_fixnum (-1));
   h->index = make_vector (hash_index_size (h, size), make_fixnum (-1));
   h->next_weak = NULL;
-  h->purecopy = purecopy;
   h->mutable = true;
 
   /* Set up the free list.  */
@@ -4318,11 +4310,6 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h)
 	    set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket));
 	    set_hash_index_slot (h, start_of_bucket, i);
 	  }
-
-#ifdef ENABLE_CHECKING
-      if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h)
-	message ("Growing hash table to: %"pD"d", next_size);
-#endif
     }
 }
 
@@ -4385,7 +4372,6 @@ check_mutable_hash_table (Lisp_Object obj, struct Lisp_Hash_Table *h)
 {
   if (!h->mutable)
     signal_error ("hash table test modifies table", obj);
-  eassert (!PURE_P (h));
 }
 
 /* Put an entry into hash table H that associates KEY with VALUE.
@@ -4876,16 +4862,10 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
 WEAK.  WEAK t is equivalent to `key-and-value'.  Default value of WEAK
 is nil.
 
-:purecopy PURECOPY -- If PURECOPY is non-nil, the table can be copied
-to pure storage when Emacs is being dumped, making the contents of the
-table read only. Any further changes to purified tables will result
-in an error.
-
 usage: (make-hash-table &rest KEYWORD-ARGS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
   Lisp_Object test, weak;
-  bool purecopy;
   struct hash_table_test testdesc;
   ptrdiff_t i;
   USE_SAFE_ALLOCA;
@@ -4919,9 +4899,8 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       testdesc.cmpfn = cmpfn_user_defined;
     }
 
-  /* See if there's a `:purecopy PURECOPY' argument.  */
-  i = get_key_arg (QCpurecopy, nargs, args, used);
-  purecopy = i && !NILP (args[i]);
+  /* Ignore a `:purecopy PURECOPY' argument.  */
+  get_key_arg (QCpurecopy, nargs, args, used);
   /* See if there's a `:size SIZE' argument.  */
   i = get_key_arg (QCsize, nargs, args, used);
   Lisp_Object size_arg = i ? args[i] : Qnil;
@@ -4971,8 +4950,7 @@ DEFUN ("make-hash-table", Fmake_hash_table, Smake_hash_table, 0, MANY, 0,
       signal_error ("Invalid argument list", args[i]);
 
   SAFE_FREE ();
-  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak,
-			  purecopy);
+  return make_hash_table (testdesc, size, rehash_size, rehash_threshold, weak);
 }
 
 
diff --git a/src/fontset.c b/src/fontset.c
index 332be6c39d11f..0421ca49c7361 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -2129,7 +2129,7 @@ syms_of_fontset (void)
   set_fontset_id (Vdefault_fontset, make_fixnum (0));
   set_fontset_name
     (Vdefault_fontset,
-     build_pure_c_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
+     build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default"));
   ASET (Vfontset_table, 0, Vdefault_fontset);
   next_fontset_id = 1;
   PDUMPER_REMEMBER_SCALAR (next_fontset_id);
@@ -2187,7 +2187,7 @@ syms_of_fontset (void)
 	       doc: /* Alist of fontset names vs the aliases.  */);
   Vfontset_alias_alist
     = list1 (Fcons (FONTSET_NAME (Vdefault_fontset),
-		    build_pure_c_string ("fontset-default")));
+		    build_string ("fontset-default")));
 
   DEFVAR_LISP ("vertical-centering-font-regexp",
 	       Vvertical_centering_font_regexp,
diff --git a/src/frame.c b/src/frame.c
index a62347c1fb2a9..652d26654390d 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1108,7 +1108,7 @@ make_initial_frame (void)
   Vframe_list = Fcons (frame, Vframe_list);
 
   tty_frame_count = 1;
-  fset_name (f, build_pure_c_string ("F1"));
+  fset_name (f, build_string ("F1"));
 
   SET_FRAME_VISIBLE (f, 1);
 
diff --git a/src/image.c b/src/image.c
index 8137dbea8d7ec..c738548d382a7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -4808,7 +4808,7 @@ xpm_make_color_table_h (void (**put_func) (Lisp_Object, const char *, int,
   *get_func = xpm_get_color_table_h;
   return make_hash_table (hashtest_equal, DEFAULT_HASH_SIZE,
 			  DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			  Qnil, false);
+			  Qnil);
 }
 
 static void
diff --git a/src/intervals.c b/src/intervals.c
index f88a41f254917..5b69af2449a68 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -44,7 +44,6 @@
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "puresize.h"
 #include "keymap.h"
 
 /* Test for membership, allowing for t (actually any non-cons) to mean the
@@ -101,7 +100,6 @@ create_root_interval (Lisp_Object parent)
     }
   else
     {
-      CHECK_IMPURE (parent, XSTRING (parent));
       new->total_length = SCHARS (parent);
       eassert (TOTAL_LENGTH (new) >= 0);
       set_string_intervals (parent, new);
diff --git a/src/json.c b/src/json.c
index 3f1d27ad7fb7f..ccb0405c4e069 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1110,8 +1110,8 @@ define_error (Lisp_Object name, const char *message, Lisp_Object parent)
   eassert (CONSP (parent_conditions));
   eassert (!NILP (Fmemq (parent, parent_conditions)));
   eassert (NILP (Fmemq (name, parent_conditions)));
-  Fput (name, Qerror_conditions, pure_cons (name, parent_conditions));
-  Fput (name, Qerror_message, build_pure_c_string (message));
+  Fput (name, Qerror_conditions, Fcons (name, parent_conditions));
+  Fput (name, Qerror_message, build_string (message));
 }
 
 void
diff --git a/src/keyboard.c b/src/keyboard.c
index 9ee4c4f6d6839..1c862a15759af 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1109,8 +1109,6 @@ top_level_1 (Lisp_Object ignore)
   /* On entry to the outer level, run the startup file.  */
   if (!NILP (Vtop_level))
     internal_condition_case (top_level_2, Qerror, cmd_error);
-  else if (!NILP (Vpurify_flag))
-    message1 ("Bare impure Emacs (standard Lisp code not loaded)");
   else
     message1 ("Bare Emacs (standard Lisp code not loaded)");
   return Qnil;
@@ -11458,14 +11456,14 @@ syms_of_keyboard (void)
   pending_funcalls = Qnil;
   staticpro (&pending_funcalls);
 
-  Vlispy_mouse_stem = build_pure_c_string ("mouse");
+  Vlispy_mouse_stem = build_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
-  regular_top_level_message = build_pure_c_string ("Back to top level");
+  regular_top_level_message = build_string ("Back to top level");
   staticpro (&regular_top_level_message);
 #ifdef HAVE_STACK_OVERFLOW_HANDLING
   recover_top_level_message
-    = build_pure_c_string ("Re-entering top level after C stack overflow");
+    = build_string ("Re-entering top level after C stack overflow");
   staticpro (&recover_top_level_message);
 #endif
   DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
diff --git a/src/keymap.c b/src/keymap.c
index 782931fadff6a..dca4fce9b13f8 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -50,7 +50,6 @@
 #include "keyboard.h"
 #include "termhooks.h"
 #include "blockinput.h"
-#include "puresize.h"
 #include "intervals.h"
 #include "keymap.h"
 #include "window.h"
@@ -117,8 +116,6 @@ DEFUN ("make-sparse-keymap", Fmake_sparse_keymap, Smake_sparse_keymap, 0, 1, 0,
 {
   if (!NILP (string))
     {
-      if (!NILP (Vpurify_flag))
-	string = Fpurecopy (string);
       return list2 (Qkeymap, string);
     }
   return list1 (Qkeymap);
@@ -296,7 +293,6 @@ DEFUN ("set-keymap-parent", Fset_keymap_parent, Sset_keymap_parent, 2, 2, 0,
 	 If we came to the end, add the parent in PREV.  */
       if (!CONSP (list) || KEYMAPP (list))
 	{
-	  CHECK_IMPURE (prev, XCONS (prev));
 	  XSETCDR (prev, parent);
 	  return parent;
 	}
@@ -734,7 +730,7 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 
   /* If we are preparing to dump, and DEF is a menu element
      with a menu item indicator, copy it to ensure it is not pure.  */
-  if (CONSP (def) && PURE_P (XCONS (def))
+  if (CONSP (def)
       && (EQ (XCAR (def), Qmenu_item) || STRINGP (XCAR (def))))
     def = Fcons (XCAR (def), XCDR (def));
 
@@ -778,7 +774,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	  {
 	    if (FIXNATP (idx) && XFIXNAT (idx) < ASIZE (elt))
 	      {
-		CHECK_IMPURE (elt, XVECTOR (elt));
 		ASET (elt, XFIXNAT (idx), def);
 		return def;
 	      }
@@ -831,7 +826,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	      }
 	    else if (EQ (idx, XCAR (elt)))
 	      {
-		CHECK_IMPURE (elt, XCONS (elt));
 		XSETCDR (elt, def);
 		return def;
 	      }
@@ -877,7 +871,6 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
 	}
       else
 	elt = Fcons (idx, def);
-      CHECK_IMPURE (insertion_point, XCONS (insertion_point));
       XSETCDR (insertion_point, Fcons (elt, XCDR (insertion_point)));
     }
   }
@@ -3121,12 +3114,12 @@ syms_of_keymap (void)
   current_global_map = Qnil;
   staticpro (&current_global_map);
 
-  exclude_keys = pure_list
-    (pure_cons (build_pure_c_string ("DEL"), build_pure_c_string ("\\d")),
-     pure_cons (build_pure_c_string ("TAB"), build_pure_c_string ("\\t")),
-     pure_cons (build_pure_c_string ("RET"), build_pure_c_string ("\\r")),
-     pure_cons (build_pure_c_string ("ESC"), build_pure_c_string ("\\e")),
-     pure_cons (build_pure_c_string ("SPC"), build_pure_c_string (" ")));
+  exclude_keys = list
+    (Fcons (build_string ("DEL"), build_string ("\\d")),
+     Fcons (build_string ("TAB"), build_string ("\\t")),
+     Fcons (build_string ("RET"), build_string ("\\r")),
+     Fcons (build_string ("ESC"), build_string ("\\e")),
+     Fcons (build_string ("SPC"), build_string (" ")));
   staticpro (&exclude_keys);
 
   DEFVAR_LISP ("minibuffer-local-map", Vminibuffer_local_map,
@@ -3176,13 +3169,12 @@ syms_of_keymap (void)
   DEFSYM (Qmode_line, "mode-line");
 
   staticpro (&Vmouse_events);
-  Vmouse_events = pure_list (Qmenu_bar, Qtab_bar, Qtool_bar,
-			     Qtab_line, Qheader_line, Qmode_line,
-			     intern_c_string ("mouse-1"),
-			     intern_c_string ("mouse-2"),
-			     intern_c_string ("mouse-3"),
-			     intern_c_string ("mouse-4"),
-			     intern_c_string ("mouse-5"));
+  Vmouse_events = list (Qmenu_bar, Qtool_bar, Qheader_line, Qmode_line,
+			intern_c_string ("mouse-1"),
+			intern_c_string ("mouse-2"),
+			intern_c_string ("mouse-3"),
+			intern_c_string ("mouse-4"),
+			intern_c_string ("mouse-5"));
 
   /* Keymap used for minibuffers when doing completion.  */
   /* Keymap used for minibuffers when doing completion and require a match.  */
diff --git a/src/lisp.h b/src/lisp.h
index b95f389b89024..7580272e5c7f3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -823,9 +823,6 @@ #define XUNTAG(a, type, ctype) ((ctype *) \
 	 special (with `defvar' etc), and shouldn't be lexically bound.  */
       bool_bf declared_special : 1;
 
-      /* True if pointed to from purespace and hence can't be GC'd.  */
-      bool_bf pinned : 1;
-
       /* The symbol's name, as a Lisp string.  */
       Lisp_Object name;
 
@@ -1534,20 +1531,14 @@ #define STRING_BYTES_BOUND  \
 /* Mark STR as a unibyte string.  */
 #define STRING_SET_UNIBYTE(STR)				\
   do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_unibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = -1;		\
+    XSTRING (STR)->u.s.size_byte = -1;			\
   } while (false)
 
 /* Mark STR as a multibyte string.  Assure that STR contains only
    ASCII characters in advance.  */
-#define STRING_SET_MULTIBYTE(STR)			\
-  do {							\
-    if (XSTRING (STR)->u.s.size == 0)			\
-      (STR) = empty_multibyte_string;			\
-    else						\
-      XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size; \
+#define STRING_SET_MULTIBYTE(STR)				\
+  do {								\
+    XSTRING (STR)->u.s.size_byte = XSTRING (STR)->u.s.size;	\
   } while (false)
 
 /* Convenience functions for dealing with Lisp strings.  */
@@ -2301,12 +2292,8 @@ #define DEFSYM(sym, name) /* empty */
   /* Index of first free entry in free list, or -1 if none.  */
   ptrdiff_t next_free;
 
-  /* True if the table can be purecopied.  The table cannot be
-     changed afterwards.  */
-  bool purecopy;
-
   /* True if the table is mutable.  Ordinarily tables are mutable, but
-     pure tables are not, and while a table is being mutated it is
+     some tables are not, and while a table is being mutated it is
      immutable for recursive attempts to mutate it.  */
   bool mutable;
 
@@ -3599,7 +3586,7 @@ #define CONS_TO_INTEGER(cons, type, var)				\
 Lisp_Object hashfn_equal (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object hashfn_user_defined (Lisp_Object, struct Lisp_Hash_Table *);
 Lisp_Object make_hash_table (struct hash_table_test, EMACS_INT, float, float,
-                             Lisp_Object, bool);
+                             Lisp_Object);
 ptrdiff_t hash_lookup (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object *);
 ptrdiff_t hash_put (struct Lisp_Hash_Table *, Lisp_Object, Lisp_Object,
 		    Lisp_Object);
@@ -3755,7 +3742,6 @@ verify (FLT_RADIX == 2 || FLT_RADIX == 16);
 
 /* Defined in alloc.c.  */
 extern void *my_heap_start (void);
-extern void check_pure_size (void);
 unsigned char *resize_string_data (Lisp_Object, ptrdiff_t, int, int);
 extern void malloc_warning (const char *);
 extern AVOID memory_full (size_t);
@@ -3813,11 +3799,8 @@ flush_stack_call_func (void (*func) (void *arg), void *arg)
 extern Lisp_Object list5 (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object,
 			  Lisp_Object);
 extern Lisp_Object listn (ptrdiff_t, Lisp_Object, ...);
-extern Lisp_Object pure_listn (ptrdiff_t, Lisp_Object, ...);
 #define list(...) \
   listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
-#define pure_list(...) \
-  pure_listn (ARRAYELTS (((Lisp_Object []) {__VA_ARGS__})), __VA_ARGS__)
 
 enum gc_root_type
 {
@@ -3890,17 +3873,6 @@ build_unibyte_string (const char *str)
 extern Lisp_Object make_string_from_bytes (const char *, ptrdiff_t, ptrdiff_t);
 extern Lisp_Object make_specified_string (const char *,
 					  ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_string (const char *, ptrdiff_t, ptrdiff_t, bool);
-extern Lisp_Object make_pure_c_string (const char *, ptrdiff_t);
-
-/* Make a string allocated in pure space, use STR as string data.  */
-
-INLINE Lisp_Object
-build_pure_c_string (const char *str)
-{
-  return make_pure_c_string (str, strlen (str));
-}
-
 /* Make a string from the data at STR, treating it as multibyte if the
    data warrants.  */
 
@@ -3910,7 +3882,6 @@ build_string (const char *str)
   return make_string (str, strlen (str));
 }
 
-extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
 extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
 extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
 
diff --git a/src/lread.c b/src/lread.c
index dea1b232fff83..033e9ba41af16 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2098,13 +2098,13 @@ readevalloop (Lisp_Object readcharfun,
 	read_objects_map
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (! HASH_TABLE_P (read_objects_completed)
 	  || XHASH_TABLE (read_objects_completed)->count)
 	read_objects_completed
 	  = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE,
 			     DEFAULT_REHASH_SIZE, DEFAULT_REHASH_THRESHOLD,
-			     Qnil, false);
+			     Qnil);
       if (!NILP (Vpurify_flag) && c == '(')
 	{
 	  val = read_list (0, readcharfun);
@@ -2321,12 +2321,12 @@ read_internal_start (Lisp_Object stream, Lisp_Object start, Lisp_Object end)
       || XHASH_TABLE (read_objects_map)->count)
     read_objects_map
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (! HASH_TABLE_P (read_objects_completed)
       || XHASH_TABLE (read_objects_completed)->count)
     read_objects_completed
       = make_hash_table (hashtest_eq, DEFAULT_HASH_SIZE, DEFAULT_REHASH_SIZE,
-			 DEFAULT_REHASH_THRESHOLD, Qnil, false);
+			 DEFAULT_REHASH_THRESHOLD, Qnil);
   if (EQ (Vread_with_symbol_positions, Qt)
       || EQ (Vread_with_symbol_positions, stream))
     Vread_symbol_positions_list = Qnil;
@@ -2896,11 +2896,6 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      if (!NILP (params[param_count + 1]))
 		param_count += 2;
 
-              params[param_count] = QCpurecopy;
-              params[param_count + 1] = Fplist_get (tmp, Qpurecopy);
-              if (!NILP (params[param_count + 1]))
-                param_count += 2;
-
 	      /* This is the hash table data.  */
 	      data = Fplist_get (tmp, Qdata);
 
@@ -3210,13 +3205,13 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	      /* No symbol character follows, this is the empty
 		 symbol.  */
 	      UNREAD (c);
-	      return Fmake_symbol (empty_unibyte_string);
+	      return Fmake_symbol (build_string (""));
 	    }
 	  goto read_symbol;
 	}
       /* ## is the empty symbol.  */
       if (c == '#')
-	return Fintern (empty_unibyte_string, Qnil);
+	return Fintern (build_string (""), Qnil);
 
       if (c >= '0' && c <= '9')
 	{
@@ -3612,9 +3607,8 @@ read1 (Lisp_Object readcharfun, int *pch, bool first_in_list)
 	  if (uninterned_symbol)
 	    {
 	      Lisp_Object name
-		= ((! NILP (Vpurify_flag)
-		    ? make_pure_string : make_specified_string)
-		   (read_buffer, nchars, nbytes, multibyte));
+		= make_specified_string (read_buffer, nchars, nbytes,
+					 multibyte);
 	      result = Fmake_symbol (name);
 	    }
 	  else
@@ -4204,10 +4198,8 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 
   if (!SYMBOLP (tem))
     {
-      /* Creating a non-pure string from a string literal not implemented yet.
-	 We could just use make_string here and live with the extra copy.  */
       eassert (!NILP (Vpurify_flag));
-      tem = intern_driver (make_pure_c_string (str, len), obarray, tem);
+      tem = intern_driver (make_string (str, len), obarray, tem);
     }
   return tem;
 }
@@ -4216,7 +4208,7 @@ intern_c_string_1 (const char *str, ptrdiff_t len)
 define_symbol (Lisp_Object sym, char const *str)
 {
   ptrdiff_t len = strlen (str);
-  Lisp_Object string = make_pure_c_string (str, len);
+  Lisp_Object string = make_string (str, len);
   init_symbol (sym, string);
 
   /* Qunbound is uninterned, so that it's not confused with any symbol
@@ -4243,8 +4235,7 @@ DEFUN ("intern", Fintern, Sintern, 1, 2, 0,
 
   tem = oblookup (obarray, SSDATA (string), SCHARS (string), SBYTES (string));
   if (!SYMBOLP (tem))
-    tem = intern_driver (NILP (Vpurify_flag) ? string : Fpurecopy (string),
-			 obarray, tem);
+    tem = intern_driver (string, obarray, tem);
   return tem;
 }
 
@@ -4893,23 +4884,23 @@ syms_of_lread (void)
 to the specified file name if a suffix is allowed or required.  */);
 #ifdef HAVE_MODULES
 #ifdef MODULES_SECONDARY_SUFFIX
-  Vload_suffixes = list4 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX),
-                          build_pure_c_string (MODULES_SECONDARY_SUFFIX));
+  Vload_suffixes = list4 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX),
+                          build_string (MODULES_SECONDARY_SUFFIX));
 #else
-  Vload_suffixes = list3 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"),
-			  build_pure_c_string (MODULES_SUFFIX));
+  Vload_suffixes = list3 (build_string (".elc"),
+			  build_string (".el"),
+			  build_string (MODULES_SUFFIX));
 #endif
 #else
-  Vload_suffixes = list2 (build_pure_c_string (".elc"),
-			  build_pure_c_string (".el"));
+  Vload_suffixes = list2 (build_string (".elc"),
+			  build_string (".el"));
 #endif
   DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
 	       doc: /* Suffix of loadable module file, or nil if modules are not supported.  */);
 #ifdef HAVE_MODULES
-  Vmodule_file_suffix = build_pure_c_string (MODULES_SUFFIX);
+  Vmodule_file_suffix = build_string (MODULES_SUFFIX);
 #else
   Vmodule_file_suffix = Qnil;
 #endif
@@ -5052,7 +5043,7 @@ syms_of_lread (void)
 When the regular expression matches, the file is considered to be safe
 to load.  */);
   Vbytecomp_version_regexp
-    = build_pure_c_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
+    = build_string ("^;;;.\\(in Emacs version\\|bytecomp version FSF\\)");
 
   DEFSYM (Qlexical_binding, "lexical-binding");
   DEFVAR_LISP ("lexical-binding", Vlexical_binding,
diff --git a/src/pdumper.c b/src/pdumper.c
index 337742fda4ade..dd2486cd1a0e5 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2403,7 +2403,7 @@ dump_symbol (struct dump_context *ctx,
              Lisp_Object object,
              dump_off offset)
 {
-#if CHECK_STRUCTS && !defined HASH_Lisp_Symbol_999DC26DEC
+#if CHECK_STRUCTS && !defined HASH_Lisp_Symbol_DD2E6013B4
 # error "Lisp_Symbol changed. See CHECK_STRUCTS comment in config.h."
 #endif
 #if CHECK_STRUCTS && !defined (HASH_symbol_redirect_ADB4F5B113)
@@ -2440,7 +2440,6 @@ dump_symbol (struct dump_context *ctx,
   DUMP_FIELD_COPY (&out, symbol, u.s.trapped_write);
   DUMP_FIELD_COPY (&out, symbol, u.s.interned);
   DUMP_FIELD_COPY (&out, symbol, u.s.declared_special);
-  DUMP_FIELD_COPY (&out, symbol, u.s.pinned);
   dump_field_lv (ctx, &out, symbol, &symbol->u.s.name, WEIGHT_STRONG);
   switch (symbol->u.s.redirect)
     {
@@ -2657,7 +2656,7 @@ dump_hash_table (struct dump_context *ctx,
                  Lisp_Object object,
                  dump_off offset)
 {
-#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_6D63EDB618
+#if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_203821C7EF
 # error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h."
 #endif
   const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object);
@@ -2673,7 +2672,6 @@ dump_hash_table (struct dump_context *ctx,
      them as close to the hash table as possible.  */
   DUMP_FIELD_COPY (out, hash, count);
   DUMP_FIELD_COPY (out, hash, next_free);
-  DUMP_FIELD_COPY (out, hash, purecopy);
   DUMP_FIELD_COPY (out, hash, mutable);
   DUMP_FIELD_COPY (out, hash, rehash_threshold);
   DUMP_FIELD_COPY (out, hash, rehash_size);
@@ -5467,8 +5465,6 @@ DEFUN ("pdumper-stats", Fpdumper_stats, Spdumper_stats, 0, 0, 0,
 		Fcons (Qdump_file_name, dump_fn));
 }
 
-#endif /* HAVE_PDUMPER */
-
 \f
 static void
 thaw_hash_tables (void)
@@ -5483,6 +5479,7 @@ init_pdumper_once (void)
 {
   pdumper_do_now_and_after_load (thaw_hash_tables);
 }
+#endif /* HAVE_PDUMPER */
 
 void
 syms_of_pdumper (void)
diff --git a/src/print.c b/src/print.c
index 14af9195475ef..df008cf3b1296 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1581,12 +1581,6 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
 	print_object (Fhash_table_rehash_threshold (obj),
 		      printcharfun, escapeflag);
 
-	if (h->purecopy)
-	  {
-	    print_c_string (" purecopy ", printcharfun);
-	    print_object (h->purecopy ? Qt : Qnil, printcharfun, escapeflag);
-	  }
-
 	print_c_string (" data ", printcharfun);
 
 	/* Print the data here as a plist. */
diff --git a/src/process.c b/src/process.c
index b98bc297a3f3f..90a1141ab6564 100644
--- a/src/process.c
+++ b/src/process.c
@@ -8566,7 +8566,7 @@ syms_of_process (void)
    const struct socket_options *sopt;
 
 #define ADD_SUBFEATURE(key, val) \
-  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
+  subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures)
 
    ADD_SUBFEATURE (QCnowait, Qt);
 #ifdef DATAGRAM_SOCKETS
@@ -8588,7 +8588,7 @@ #define ADD_SUBFEATURE(key, val) \
    ADD_SUBFEATURE (QCserver, Qt);
 
    for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
+     subfeatures = Fcons (intern_c_string (sopt->name), subfeatures);
 
    Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
diff --git a/src/profiler.c b/src/profiler.c
index 21ae2447aa4ee..44bf57eba2078 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -63,7 +63,7 @@ make_log (void)
   Lisp_Object log = make_hash_table (hashtest_profiler, heap_size,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
   struct Lisp_Hash_Table *h = XHASH_TABLE (log);
 
   /* What is special about our hash-tables is that the values are pre-filled
diff --git a/src/puresize.h b/src/puresize.h
deleted file mode 100644
index 811d0b4d36952..0000000000000
--- a/src/puresize.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* How much read-only Lisp storage a dumped Emacs needs.
-   Copyright (C) 1993, 2001-2021 Free Software Foundation, Inc.
-
-This file is part of GNU Emacs.
-
-GNU Emacs is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or (at
-your option) any later version.
-
-GNU Emacs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
-
-#ifndef EMACS_PURESIZE_H
-#define EMACS_PURESIZE_H
-
-#include "lisp.h"
-
-INLINE_HEADER_BEGIN
-
-/* Define PURESIZE, the number of bytes of pure Lisp code to leave space for.
-
-   At one point, this was defined in config.h, meaning that changing
-   PURESIZE would make Make recompile all of Emacs.  But only a few
-   files actually use PURESIZE, so we split it out to its own .h file.
-
-   Make sure to include this file after config.h, since that tells us
-   whether we are running X windows, which tells us how much pure
-   storage to allocate.  */
-
-/* First define a measure of the amount of data we have.  */
-
-/* A system configuration file may set this to request a certain extra
-   amount of storage.  This is a lot more update-robust that defining
-   BASE_PURESIZE or even PURESIZE directly.  */
-#ifndef SYSTEM_PURESIZE_EXTRA
-#define SYSTEM_PURESIZE_EXTRA 0
-#endif
-
-#ifndef SITELOAD_PURESIZE_EXTRA
-#define SITELOAD_PURESIZE_EXTRA 0
-#endif
-
-#ifndef BASE_PURESIZE
-#define BASE_PURESIZE (2000000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA)
-#endif
-
-/* Increase BASE_PURESIZE by a ratio depending on the machine's word size.  */
-#ifndef PURESIZE_RATIO
-#if EMACS_INT_MAX >> 31 != 0
-#if PTRDIFF_MAX >> 31 != 0
-#define PURESIZE_RATIO 10 / 6	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_RATIO 8 / 6	/* Don't surround with `()'.  */
-#endif
-#else
-#define PURESIZE_RATIO 1
-#endif
-#endif
-
-#ifdef ENABLE_CHECKING
-/* ENABLE_CHECKING somehow increases the purespace used, probably because
-   it tends to cause some macro arguments to be evaluated twice.  This is
-   a bug, but it's difficult to track it down.  */
-#define PURESIZE_CHECKING_RATIO 12 / 10	/* Don't surround with `()'.  */
-#else
-#define PURESIZE_CHECKING_RATIO 1
-#endif
-
-/* This is the actual size in bytes to allocate.  */
-#ifndef PURESIZE
-#define PURESIZE  (BASE_PURESIZE * PURESIZE_RATIO * PURESIZE_CHECKING_RATIO)
-#endif
-
-extern AVOID pure_write_error (Lisp_Object);
-
-extern EMACS_INT pure[];
-
-/* The puresize_h_* macros are private to this include file.  */
-
-/* True if PTR is pure.  */
-
-#define puresize_h_PURE_P(ptr) \
-  ((uintptr_t) (ptr) - (uintptr_t) pure <= PURESIZE)
-
-INLINE bool
-PURE_P (void *ptr)
-{
-  return puresize_h_PURE_P (ptr);
-}
-
-/* Signal an error if OBJ is pure.  PTR is OBJ untagged.  */
-
-#define puresize_h_CHECK_IMPURE(obj, ptr) \
-  (PURE_P (ptr) ? pure_write_error (obj) : (void) 0)
-
-INLINE void
-CHECK_IMPURE (Lisp_Object obj, void *ptr)
-{
-  puresize_h_CHECK_IMPURE (obj, ptr);
-}
-
-#if DEFINE_KEY_OPS_AS_MACROS
-# define PURE_P(ptr) puresize_h_PURE_P (ptr)
-# define CHECK_IMPURE(obj, ptr) puresize_h_CHECK_IMPURE (obj, ptr)
-#endif
-
-INLINE_HEADER_END
-
-#endif /* EMACS_PURESIZE_H */
diff --git a/src/search.c b/src/search.c
index c757bf3d1f281..5a214db0092d2 100644
--- a/src/search.c
+++ b/src/search.c
@@ -3354,19 +3354,19 @@ syms_of_search (void)
   DEFSYM (Qinvalid_regexp, "invalid-regexp");
 
   Fput (Qsearch_failed, Qerror_conditions,
-	pure_list (Qsearch_failed, Qerror));
+	list (Qsearch_failed, Qerror));
   Fput (Qsearch_failed, Qerror_message,
-	build_pure_c_string ("Search failed"));
+	build_string ("Search failed"));
 
   Fput (Quser_search_failed, Qerror_conditions,
-	pure_list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
+	list (Quser_search_failed, Quser_error, Qsearch_failed, Qerror));
   Fput (Quser_search_failed, Qerror_message,
-        build_pure_c_string ("Search failed"));
+        build_string ("Search failed"));
 
   Fput (Qinvalid_regexp, Qerror_conditions,
-	pure_list (Qinvalid_regexp, Qerror));
+	list (Qinvalid_regexp, Qerror));
   Fput (Qinvalid_regexp, Qerror_message,
-	build_pure_c_string ("Invalid regexp"));
+	build_string ("Invalid regexp"));
 
   re_match_object = Qnil;
   staticpro (&re_match_object);
diff --git a/src/syntax.c b/src/syntax.c
index 9fbf88535f3ec..993f91af19ac0 100644
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -3719,9 +3719,9 @@ syms_of_syntax (void)
 
   DEFSYM (Qscan_error, "scan-error");
   Fput (Qscan_error, Qerror_conditions,
-	pure_list (Qscan_error, Qerror));
+	list (Qscan_error, Qerror));
   Fput (Qscan_error, Qerror_message,
-	build_pure_c_string ("Scan error"));
+	build_string ("Scan error"));
 
   DEFVAR_BOOL ("parse-sexp-ignore-comments", parse_sexp_ignore_comments,
 	       doc: /* Non-nil means `forward-sexp', etc., should treat comments as whitespace.  */);
diff --git a/src/w32fns.c b/src/w32fns.c
index 9db367bfafe75..3b3ad2f55b9aa 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -10390,9 +10390,9 @@ syms_of_w32fns (void)
   DEFSYM (Qjson, "json");
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   staticpro (&w32_grabbed_keys);
   w32_grabbed_keys = Qnil;
diff --git a/src/xdisp.c b/src/xdisp.c
index cc0a689ba32e9..38099350d6761 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -34862,7 +34862,7 @@ syms_of_xdisp (void)
   staticpro (&echo_area_buffer[0]);
   staticpro (&echo_area_buffer[1]);
 
-  Vmessages_buffer_name = build_pure_c_string ("*Messages*");
+  Vmessages_buffer_name = build_string ("*Messages*");
   staticpro (&Vmessages_buffer_name);
 
   mode_line_proptrans_alist = Qnil;
@@ -34954,7 +34954,7 @@ syms_of_xdisp (void)
   DEFVAR_LISP ("overlay-arrow-string", Voverlay_arrow_string,
     doc: /* String to display as an arrow in non-window frames.
 See also `overlay-arrow-position'.  */);
-  Voverlay_arrow_string = build_pure_c_string ("=>");
+  Voverlay_arrow_string = build_string ("=>");
 
   DEFVAR_LISP ("overlay-arrow-variable-list", Voverlay_arrow_variable_list,
     doc: /* List of variables (symbols) which hold markers for overlay arrows.
@@ -35079,17 +35079,17 @@ syms_of_xdisp (void)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
 \(see `modify-frame-parameters').  */);
-  /* Do not nest calls to pure_list.  This works around a bug in
+  /* Do not nest calls to list.  This works around a bug in
      Oracle Developer Studio 12.6.  */
   Lisp_Object icon_title_name_format
-    = pure_list (empty_unibyte_string,
-		 build_pure_c_string ("%b - GNU Emacs at "),
-		 intern_c_string ("system-name"));
+    = list (empty_unibyte_string,
+	    build_string ("%b - GNU Emacs at "),
+	    intern_c_string ("system-name"));
   Vicon_title_format
     = Vframe_title_format
-    = pure_list (intern_c_string ("multiple-frames"),
-		 build_pure_c_string ("%b"),
-		 icon_title_name_format);
+    = list (intern_c_string ("multiple-frames"),
+	    build_string ("%b"),
+	    icon_title_name_format);
 
   DEFVAR_LISP ("message-log-max", Vmessage_log_max,
     doc: /* Maximum number of lines to keep in the message log buffer.
diff --git a/src/xfaces.c b/src/xfaces.c
index ab4440f46ad0d..6cb08b0475cba 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -7044,7 +7044,7 @@ syms_of_xfaces (void)
 This stipple pattern is used on monochrome displays
 instead of shades of gray for a face background color.
 See `set-face-stipple' for possible values for this variable.  */);
-  Vface_default_stipple = build_pure_c_string ("gray3");
+  Vface_default_stipple = build_string ("gray3");
 
   DEFVAR_LISP ("tty-defined-color-alist", Vtty_defined_color_alist,
    doc: /* An alist of defined terminal colors and their RGB values.
diff --git a/src/xfns.c b/src/xfns.c
index d90644819b6f5..e9ead35ccccb5 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -7878,9 +7878,9 @@ syms_of_xfns (void)
 #endif
 
   Fput (Qundefined_color, Qerror_conditions,
-	pure_list (Qundefined_color, Qerror));
+	list (Qundefined_color, Qerror));
   Fput (Qundefined_color, Qerror_message,
-	build_pure_c_string ("Undefined color"));
+	build_string ("Undefined color"));
 
   DEFVAR_LISP ("x-pointer-shape", Vx_pointer_shape,
     doc: /* The shape of the pointer when over text.
@@ -8091,7 +8091,7 @@ syms_of_xfns (void)
     char gtk_version[sizeof ".." + 3 * INT_STRLEN_BOUND (int)];
     int len = sprintf (gtk_version, "%d.%d.%d",
 		       GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
-    Vgtk_version_string = make_pure_string (gtk_version, len, len, false);
+    Vgtk_version_string = make_specified_string (gtk_version, len, len, false);
   }
 #endif /* USE_GTK */
 
@@ -8105,7 +8105,8 @@ syms_of_xfns (void)
     int len = sprintf (cairo_version, "%d.%d.%d",
 		       CAIRO_VERSION_MAJOR, CAIRO_VERSION_MINOR,
                        CAIRO_VERSION_MICRO);
-    Vcairo_version_string = make_pure_string (cairo_version, len, len, false);
+    Vcairo_version_string = make_specified_string (cairo_version, len, len,
+						   false);
   }
 #endif
 
diff --git a/src/xterm.c b/src/xterm.c
index 744b80c68a002..437c08b526f60 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13649,7 +13649,7 @@ syms_of_xterm (void)
   DEFSYM (Qlatin_1, "latin-1");
 
 #ifdef USE_GTK
-  xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
+  xg_default_icon_file = build_string ("icons/hicolor/scalable/apps/emacs.svg");
   staticpro (&xg_default_icon_file);
 
   DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
@@ -13770,7 +13770,7 @@ syms_of_xterm (void)
   Vx_keysym_table = make_hash_table (hashtest_eql, 900,
 				     DEFAULT_REHASH_SIZE,
 				     DEFAULT_REHASH_THRESHOLD,
-				     Qnil, false);
+				     Qnil);
 
   DEFVAR_BOOL ("x-frame-normalize-before-maximize",
 	       x_frame_normalize_before_maximize,
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-05  3:00                                                     ` Pip Cet
@ 2021-03-05  7:20                                                       ` Eli Zaretskii
  2021-03-14 22:19                                                       ` Stefan Monnier
  1 sibling, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-03-05  7:20 UTC (permalink / raw)
  To: Pip Cet; +Cc: eggert, rpluim, schwab, stefankangas, 36649, larsi, akrl

> From: Pip Cet <pipcet@gmail.com>
> Date: Fri, 5 Mar 2021 03:00:03 +0000
> Cc: Robert Pluim <rpluim@gmail.com>, Andreas Schwab <schwab@linux-m68k.org>,
>  Stefan Kangas <stefankangas@gmail.com>, 36649@debbugs.gnu.org, larsi@gnus.org,
>  Andrea Corallo <akrl@sdf.org>
> 
> > The convention is to put a "verify (NIL_IS_ZERO);" near the rare bits of
> > code that assume Qnil is all-bits-zero.
> 
> That would be nice, but I'm quite certain there are places in the code
> that rely on this identity without doing that...

There shouldn't be.  If you find them, please report them.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-05  3:00                                                     ` Pip Cet
  2021-03-05  7:20                                                       ` Eli Zaretskii
@ 2021-03-14 22:19                                                       ` Stefan Monnier
  2021-05-12 14:50                                                         ` Lars Ingebrigtsen
  1 sibling, 1 reply; 125+ messages in thread
From: Stefan Monnier @ 2021-03-14 22:19 UTC (permalink / raw)
  To: Pip Cet
  Cc: Paul Eggert, Robert Pluim, Andreas Schwab, Stefan Kangas, 36649,
	larsi, Andrea Corallo

> Anyway, it's easy enough to remove the assumption. Here's the current patch.

Is anything still blocking this patch or can it go in?


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-03-14 22:19                                                       ` Stefan Monnier
@ 2021-05-12 14:50                                                         ` Lars Ingebrigtsen
  2021-05-12 15:01                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 14:50 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Paul Eggert, Robert Pluim, Andreas Schwab, Stefan Kangas, Pip Cet,
	36649, Andrea Corallo

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Anyway, it's easy enough to remove the assumption. Here's the current patch.
>
> Is anything still blocking this patch or can it go in?

Skimming this thread, it seems like most people were very enthusiastic
about removing pure space, but this patch was never applied.

Eli, did you have any objections?  If not, it sounds like a good idea to
me, too.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 14:50                                                         ` Lars Ingebrigtsen
@ 2021-05-12 15:01                                                           ` Eli Zaretskii
  2021-05-12 17:03                                                             ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 15:01 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefankangas, schwab, monnier, pipcet, 36649,
	akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: Pip Cet <pipcet@gmail.com>,  Paul Eggert <eggert@cs.ucla.edu>,  Robert
>  Pluim <rpluim@gmail.com>,  Andreas Schwab <schwab@linux-m68k.org>,  Stefan
>  Kangas <stefankangas@gmail.com>,  36649@debbugs.gnu.org,  Andrea Corallo
>  <akrl@sdf.org>, Eli Zaretskii <eliz@gnu.org>
> Date: Wed, 12 May 2021 16:50:46 +0200
> 
> Eli, did you have any objections?  If not, it sounds like a good idea to
> me, too.

I don't have any objections, but there was one issue on which we
didn't reach any agreed conclusions:

  https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36649#68





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 15:01                                                           ` Eli Zaretskii
@ 2021-05-12 17:03                                                             ` Lars Ingebrigtsen
  2021-05-12 17:06                                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-12 17:10                                                               ` Eli Zaretskii
  0 siblings, 2 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 17:03 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefankangas, schwab, monnier, pipcet, 36649,
	akrl

Eli Zaretskii <eliz@gnu.org> writes:

> I don't have any objections, but there was one issue on which we
> didn't reach any agreed conclusions:
>
>   https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36649#68

Right -- what to do about unexec builds?  Was the plan to stop
supporting that in this cycle or the next?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:03                                                             ` Lars Ingebrigtsen
@ 2021-05-12 17:06                                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-12 17:11                                                                 ` Lars Ingebrigtsen
  2021-05-12 17:19                                                                 ` Eli Zaretskii
  2021-05-12 17:10                                                               ` Eli Zaretskii
  1 sibling, 2 replies; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-05-12 17:06 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, Eli Zaretskii,
	akrl

Lars Ingebrigtsen [2021-05-12 19:03:19] wrote:
> Eli Zaretskii <eliz@gnu.org> writes:
>> I don't have any objections, but there was one issue on which we
>> didn't reach any agreed conclusions:
>>
>>   https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36649#68
>
> Right -- what to do about unexec builds?  Was the plan to stop
> supporting that in this cycle or the next?

I thought the question was not directly relevant because removal of the
pure space does not imply removing unexec.


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:03                                                             ` Lars Ingebrigtsen
  2021-05-12 17:06                                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-05-12 17:10                                                               ` Eli Zaretskii
  2021-05-12 17:24                                                                 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 17:10 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefankangas, schwab, monnier, pipcet, 36649,
	akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: monnier@iro.umontreal.ca,  pipcet@gmail.com,  eggert@cs.ucla.edu,
>   rpluim@gmail.com,  schwab@linux-m68k.org,  stefankangas@gmail.com,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 19:03:19 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > I don't have any objections, but there was one issue on which we
> > didn't reach any agreed conclusions:
> >
> >   https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36649#68
> 
> Right -- what to do about unexec builds?  Was the plan to stop
> supporting that in this cycle or the next?

I think we should keep unexec in Emacs 28 and remove it in Emacs 29.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:06                                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-05-12 17:11                                                                 ` Lars Ingebrigtsen
  2021-05-12 17:28                                                                   ` Eli Zaretskii
  2021-05-12 17:19                                                                 ` Eli Zaretskii
  1 sibling, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 17:11 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, akrl

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> I thought the question was not directly relevant because removal of the
> pure space does not imply removing unexec.

It just makes unexec Emacs a little less efficient?  In which case I say
we should just ignore the issue and apply the patch.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:06                                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-12 17:11                                                                 ` Lars Ingebrigtsen
@ 2021-05-12 17:19                                                                 ` Eli Zaretskii
  1 sibling, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 17:19 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, larsi, akrl

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>,  pipcet@gmail.com,  eggert@cs.ucla.edu,
>   rpluim@gmail.com,  schwab@linux-m68k.org,  stefan@marxist.se,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 13:06:24 -0400
> 
> >>   https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36649#68
> >
> > Right -- what to do about unexec builds?  Was the plan to stop
> > supporting that in this cycle or the next?
> 
> I thought the question was not directly relevant because removal of the
> pure space does not imply removing unexec.

The beginning of the bug discussion explains why they are related.
Specifically: (a) the motivation for removing purespace comes from the
pdumper build, and (b) we don't want to waste efforts on fixing
possible breakage of the unexec build as result of this change.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:10                                                               ` Eli Zaretskii
@ 2021-05-12 17:24                                                                 ` Lars Ingebrigtsen
  0 siblings, 0 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 17:24 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefankangas, schwab, monnier, pipcet, 36649,
	akrl

I had a look at the patch to see whether it had diverged from the
current code base a lot -- and it mostly applies.  The major thing
that's changed, though, is that comp.c has a lot of code to handle
purespace, and those bits have to be removed, too.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:11                                                                 ` Lars Ingebrigtsen
@ 2021-05-12 17:28                                                                   ` Eli Zaretskii
  2021-05-12 17:32                                                                     ` Lars Ingebrigtsen
  2021-05-12 17:37                                                                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 17:28 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: Eli Zaretskii <eliz@gnu.org>,  pipcet@gmail.com,  eggert@cs.ucla.edu,
>   rpluim@gmail.com,  schwab@linux-m68k.org,  stefan@marxist.se,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 19:11:21 +0200
> 
> Stefan Monnier <monnier@iro.umontreal.ca> writes:
> 
> > I thought the question was not directly relevant because removal of the
> > pure space does not imply removing unexec.
> 
> It just makes unexec Emacs a little less efficient?  In which case I say
> we should just ignore the issue and apply the patch.

Keeping unexec doesn't mean breaking it .  If we believe someone might
need that configuration, then we should give them a full-fledged
Emacs, not a crippled one.

The patch can easily be tweaked to make the changes conditioned by
HAVE_PDUMPER, so I believe there's no need to argue about this nit:
let's simply remove purespace from the pdumper builds, and leave it
alone in the unexec builds.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:28                                                                   ` Eli Zaretskii
@ 2021-05-12 17:32                                                                     ` Lars Ingebrigtsen
  2021-05-12 17:42                                                                       ` Eli Zaretskii
  2021-05-12 18:02                                                                       ` Paul Eggert
  2021-05-12 17:37                                                                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 2 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 17:32 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Eli Zaretskii <eliz@gnu.org> writes:

> Keeping unexec doesn't mean breaking it .  If we believe someone might
> need that configuration, then we should give them a full-fledged
> Emacs, not a crippled one.

How crippled are we talking?

> The patch can easily be tweaked to make the changes conditioned by
> HAVE_PDUMPER, so I believe there's no need to argue about this nit:
> let's simply remove purespace from the pdumper builds, and leave it
> alone in the unexec builds.

That would be a whole lot of #ifs in the code, and wouldn't make the
change worth it -- in that case, I'd rather wait until we get rid of 
unexec before getting rid of pure space.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:28                                                                   ` Eli Zaretskii
  2021-05-12 17:32                                                                     ` Lars Ingebrigtsen
@ 2021-05-12 17:37                                                                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-12 17:44                                                                       ` Eli Zaretskii
  1 sibling, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-05-12 17:37 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, Lars Ingebrigtsen,
	akrl

> Keeping unexec doesn't mean breaking it.  If we believe someone might
> need that configuration, then we should give them a full-fledged
> Emacs, not a crippled one.

Removing pure space from unexec builds doesn't make them
crippled, AFAIK.


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:32                                                                     ` Lars Ingebrigtsen
@ 2021-05-12 17:42                                                                       ` Eli Zaretskii
  2021-05-12 17:58                                                                         ` Lars Ingebrigtsen
  2021-05-12 18:02                                                                       ` Paul Eggert
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 17:42 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: monnier@iro.umontreal.ca,  pipcet@gmail.com,  eggert@cs.ucla.edu,
>   rpluim@gmail.com,  schwab@linux-m68k.org,  stefan@marxist.se,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 19:32:13 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Keeping unexec doesn't mean breaking it .  If we believe someone might
> > need that configuration, then we should give them a full-fledged
> > Emacs, not a crippled one.
> 
> How crippled are we talking?

As in "less efficient".

> > The patch can easily be tweaked to make the changes conditioned by
> > HAVE_PDUMPER, so I believe there's no need to argue about this nit:
> > let's simply remove purespace from the pdumper builds, and leave it
> > alone in the unexec builds.
> 
> That would be a whole lot of #ifs in the code, and wouldn't make the
> change worth it -- in that case, I'd rather wait until we get rid of 
> unexec before getting rid of pure space.

I don't think it will be so ugly as being prohibitive: we already have
quite a few of "#if HAVE_PDUMPER" in the sources.  But if you prefer
to wait with purespace removal until after unexec is removed, I don't
mind too much: Emacs 28 will have quite a lot of important changes
even without that.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:37                                                                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-05-12 17:44                                                                       ` Eli Zaretskii
  2021-05-12 19:07                                                                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 17:44 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, larsi, akrl

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>,  pipcet@gmail.com,
>   eggert@cs.ucla.edu,  rpluim@gmail.com,  schwab@linux-m68k.org,
>   stefan@marxist.se,  36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 13:37:43 -0400
> 
> > Keeping unexec doesn't mean breaking it.  If we believe someone might
> > need that configuration, then we should give them a full-fledged
> > Emacs, not a crippled one.
> 
> Removing pure space from unexec builds doesn't make them
> crippled, AFAIK.

I just don't want to risk that, not at all.  Because if we are missing
something, it will require efforts I'd rather put elsewhere.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:42                                                                       ` Eli Zaretskii
@ 2021-05-12 17:58                                                                         ` Lars Ingebrigtsen
  2021-05-12 18:25                                                                           ` Lars Ingebrigtsen
  2021-05-12 19:12                                                                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 17:58 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Eli Zaretskii <eliz@gnu.org> writes:

>> How crippled are we talking?
>
> As in "less efficient".

As long as it doesn't render the unexec Emacs unusably slow, I think
that's OK for a thing that's on its way out.

Hm...  I wonder whether it would be easy to get some numbers.  I'll try
to get an unexec build (without purespace) running and see how bad it is.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:32                                                                     ` Lars Ingebrigtsen
  2021-05-12 17:42                                                                       ` Eli Zaretskii
@ 2021-05-12 18:02                                                                       ` Paul Eggert
  1 sibling, 0 replies; 125+ messages in thread
From: Paul Eggert @ 2021-05-12 18:02 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Eli Zaretskii
  Cc: rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

On 5/12/21 10:32 AM, Lars Ingebrigtsen wrote:
> That would be a whole lot of #ifs in the code, and wouldn't make the
> change worth it -- in that case, I'd rather wait until we get rid of
> unexec before getting rid of pure space.

+1. It's not worth the hassle. Just wait. We've got time.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:58                                                                         ` Lars Ingebrigtsen
@ 2021-05-12 18:25                                                                           ` Lars Ingebrigtsen
  2021-05-12 18:37                                                                             ` Eli Zaretskii
  2021-05-12 19:12                                                                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 18:25 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Hm...  I wonder whether it would be easy to get some numbers.  I'll try
> to get an unexec build (without purespace) running and see how bad it is.

Easier said than done.  Is this how it's supposed to be done?

./configure --with-unexec=yes --with-dumping=unexec

In that case, Emacs just segfaults:

make[2]: Entering directory '/home/larsi/src/emacs/pure/lisp'
  ELC      international/titdic-cnv.elc
Fatal error 11: Segmentation fault
Backtrace:
../src/bootstrap-emacs[0x525571]
../src/bootstrap-emacs[0x4203b6]
../src/bootstrap-emacs[0x420889]
../src/bootstrap-emacs[0x523b5d]
../src/bootstrap-emacs[0x523bd9]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x14140)[0x7f3d1517c140]

So I'm not able to build an unexec build on GNU/Linux at all.

If this is the case in general, and not just here on this
Debian/bullseye system, then I think we should consider getting rid of
both unexec and pure space now, and not wait any longer.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 18:25                                                                           ` Lars Ingebrigtsen
@ 2021-05-12 18:37                                                                             ` Eli Zaretskii
  2021-05-12 18:48                                                                               ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 18:37 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: eggert@cs.ucla.edu,  rpluim@gmail.com,  stefan@marxist.se,
>   schwab@linux-m68k.org,  monnier@iro.umontreal.ca,  pipcet@gmail.com,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 20:25:21 +0200
> 
> make[2]: Entering directory '/home/larsi/src/emacs/pure/lisp'
>   ELC      international/titdic-cnv.elc
> Fatal error 11: Segmentation fault
> Backtrace:
> ../src/bootstrap-emacs[0x525571]
> ../src/bootstrap-emacs[0x4203b6]
> ../src/bootstrap-emacs[0x420889]
> ../src/bootstrap-emacs[0x523b5d]
> ../src/bootstrap-emacs[0x523bd9]
> /lib/x86_64-linux-gnu/libpthread.so.0(+0x14140)[0x7f3d1517c140]
> 
> So I'm not able to build an unexec build on GNU/Linux at all.
> 
> If this is the case in general, and not just here on this
> Debian/bullseye system, then I think we should consider getting rid of
> both unexec and pure space now, and not wait any longer.

Someone built the master branch with unexec just a few days ago, see

  https://lists.gnu.org/archive/html/emacs-devel/2021-05/msg00060.html





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 18:37                                                                             ` Eli Zaretskii
@ 2021-05-12 18:48                                                                               ` Lars Ingebrigtsen
  2021-05-12 18:52                                                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 18:48 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Eli Zaretskii <eliz@gnu.org> writes:

> Someone built the master branch with unexec just a few days ago, see
>
>   https://lists.gnu.org/archive/html/emacs-devel/2021-05/msg00060.html

That's on Windows, though, and I seem to recall you fixing unexec on
Windows a couple weeks ago?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 18:48                                                                               ` Lars Ingebrigtsen
@ 2021-05-12 18:52                                                                                 ` Eli Zaretskii
  2021-05-12 19:07                                                                                   ` Lars Ingebrigtsen
  2021-05-13 14:08                                                                                   ` Eli Zaretskii
  0 siblings, 2 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 18:52 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: eggert@cs.ucla.edu,  rpluim@gmail.com,  stefan@marxist.se,
>   schwab@linux-m68k.org,  monnier@iro.umontreal.ca,  pipcet@gmail.com,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 20:48:28 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Someone built the master branch with unexec just a few days ago, see
> >
> >   https://lists.gnu.org/archive/html/emacs-devel/2021-05/msg00060.html
> 
> That's on Windows, though, and I seem to recall you fixing unexec on
> Windows a couple weeks ago?

I worked with him to fix it, yes.  But the problem and the fix were
not Windows specific, AFAIR.  I guess there's more, and perhaps it
happens only on systems which don't use mmap for buffer text.  I will
try to take a look when I have time.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 18:52                                                                                 ` Eli Zaretskii
@ 2021-05-12 19:07                                                                                   ` Lars Ingebrigtsen
  2021-05-12 19:12                                                                                     ` Eli Zaretskii
  2021-05-13 14:08                                                                                   ` Eli Zaretskii
  1 sibling, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 19:07 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Or...  is this the way do get an unexec build these days?

./configure --with-unexec=yes --with-dumping=none

This does not segfault here.  I'll try to get some timings done with the
pure space removal + unexec, then...

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:44                                                                       ` Eli Zaretskii
@ 2021-05-12 19:07                                                                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-12 19:17                                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-05-12 19:07 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, larsi, akrl

>> > Keeping unexec doesn't mean breaking it.  If we believe someone might
>> > need that configuration, then we should give them a full-fledged
>> > Emacs, not a crippled one.
>> 
>> Removing pure space from unexec builds doesn't make them
>> crippled, AFAIK.
>
> I just don't want to risk that, not at all.  Because if we are missing
> something, it will require efforts I'd rather put elsewhere.

I can see a risk that removing purespace will break unexec because of
some oversight of some detail somewhere (simply because it's
a configuration that's basically never tested), but I can't imagine the
breakage to be hard to fix: running without purespace has been used
during the bootstrap for many many years, both with pdump and with
unexec, so it's really not "special".

The only real consequence will be a slightly worse performance, but no
worse than what we get with pdump anyway ;-)


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 19:07                                                                                   ` Lars Ingebrigtsen
@ 2021-05-12 19:12                                                                                     ` Eli Zaretskii
  2021-05-12 19:44                                                                                       ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 19:12 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: eggert@cs.ucla.edu,  rpluim@gmail.com,  stefan@marxist.se,
>   schwab@linux-m68k.org,  monnier@iro.umontreal.ca,  pipcet@gmail.com,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 21:07:00 +0200
> 
> Or...  is this the way do get an unexec build these days?
> 
> ./configure --with-unexec=yes --with-dumping=none
> 
> This does not segfault here.  I'll try to get some timings done with the
> pure space removal + unexec, then...

I don't know if this is an interesting configuration.  AFAIU,
"--with-dumping=none" means you run the CANNOT_DUMP version, which
doesn't dump Emacs at all.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 17:58                                                                         ` Lars Ingebrigtsen
  2021-05-12 18:25                                                                           ` Lars Ingebrigtsen
@ 2021-05-12 19:12                                                                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 0 replies; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-05-12 19:12 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, Eli Zaretskii,
	akrl

Lars Ingebrigtsen [2021-05-12 19:58:46] wrote:
> Eli Zaretskii <eliz@gnu.org> writes:
>>> How crippled are we talking?
>> As in "less efficient".

It will be less efficient, indeed, because the GC will take longer
because it will also traverse the part of the heap that used to live in
the purespace.  This effect is more noticeable in sessions where the
heap is small (and hence what used to be purespace represents a more
significant fraction of the total) and becomes unmeasurable once the
heap becomes large enough to dwarf the purespace.

But please note that we have all been living with exactly this
inefficiency ever since we started using pdump.  So while it will be
slightly less efficient, it will still be as efficient as what we get
with pdump, which I believe we all consider as acceptable.


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 19:07                                                                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-05-12 19:17                                                                           ` Eli Zaretskii
  0 siblings, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-12 19:17 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: eggert, rpluim, stefan, schwab, pipcet, 36649, larsi, akrl

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: larsi@gnus.org,  pipcet@gmail.com,  eggert@cs.ucla.edu,
>   rpluim@gmail.com,  schwab@linux-m68k.org,  stefan@marxist.se,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Wed, 12 May 2021 15:07:42 -0400
> 
> > I just don't want to risk that, not at all.  Because if we are missing
> > something, it will require efforts I'd rather put elsewhere.
> 
> I can see a risk that removing purespace will break unexec because of
> some oversight of some detail somewhere (simply because it's
> a configuration that's basically never tested), but I can't imagine the
> breakage to be hard to fix: running without purespace has been used
> during the bootstrap for many many years, both with pdump and with
> unexec, so it's really not "special".

Last time I needed to fix a breakage in the unexec build it took a
non-trivial effort, and would have probably taken even more, had I not
been fortunate to have a user who could investigate the problems on
his own and present clear and correct causes of the problems.

So my bitter experience doesn't confirm your optimism.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 19:12                                                                                     ` Eli Zaretskii
@ 2021-05-12 19:44                                                                                       ` Lars Ingebrigtsen
  2021-05-13 14:44                                                                                         ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-12 19:44 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Eli Zaretskii <eliz@gnu.org> writes:

> I don't know if this is an interesting configuration.  AFAIU,
> "--with-dumping=none" means you run the CANNOT_DUMP version, which
> doesn't dump Emacs at all.

Ah, yes...  and in that case I guess there is no pure space?  Oh well, I
guess somebody has to look into getting unexec working on Linux if we're
to, er, see what the impact of pure space unexec would have been.  If it
was working.  :-)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 18:52                                                                                 ` Eli Zaretskii
  2021-05-12 19:07                                                                                   ` Lars Ingebrigtsen
@ 2021-05-13 14:08                                                                                   ` Eli Zaretskii
  2021-05-16 13:38                                                                                     ` Lars Ingebrigtsen
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-13 14:08 UTC (permalink / raw)
  To: larsi; +Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> Date: Wed, 12 May 2021 21:52:31 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: eggert@cs.ucla.edu, rpluim@gmail.com, stefan@marxist.se,
>  schwab@linux-m68k.org, monnier@iro.umontreal.ca, pipcet@gmail.com,
>  36649@debbugs.gnu.org, akrl@sdf.org
> 
> I worked with him to fix it, yes.  But the problem and the fix were
> not Windows specific, AFAIR.  I guess there's more, and perhaps it
> happens only on systems which don't use mmap for buffer text.  I will
> try to take a look when I have time.

Looks like some memory problem: xrealloc segfaults.

Don't we need to disable ASLR for unexec to work?  And doesn't that
require setfattr or paxctl commands to be available?  If not, how do
we disable ASLR in bootstrap-emacs and emacs binaries on GNU/Linux?

Here's the backtrace from the crash I see:

  Thread 1 "bootstrap-emacs" received signal SIGSEGV, Segmentation fault.
  0x00007ffff21f4917 in _int_realloc (av=av@entry=0x7ffff254ac40 <main_arena>,
      oldp=oldp@entry=0x24a73b0, oldsize=oldsize@entry=32, nb=nb@entry=144)
      at malloc.c:4589
  4589    malloc.c: No such file or directory.
  (gdb) bt
  #0  0x00007ffff21f4917 in _int_realloc (av=av@entry=0x7ffff254ac40 <main_arena>, oldp=oldp@entry=0x24a73b0, oldsize=oldsize@entry=32, nb=nb@entry=144)
      at malloc.c:4589
  #1  0x00007ffff21f80db in __GI___libc_realloc (oldmem=0x24a73c0, bytes=128)
      at malloc.c:3240
  #2  0x0000000000664a28 in lrealloc (p=0x24a73c0, size=128) at alloc.c:1378
  #3  0x0000000000663e46 in xrealloc (block=0x24a73c0, size=128) at alloc.c:804
  #4  0x00000000006641f9 in xpalloc (pa=0x24a73c0, nitems=0xed8450 <searchbufs+1840>, nitems_incr_min=1, nitems_max=32768, item_size=1) at alloc.c:928
  #5  0x0000000000658823 in regex_compile (pattern=0x8011b8 "^;;;.\\(in Emacs version\\|bytecomp version FSF\\)", size=47, posix_backtracking=false, whitespace_regexp=0x0, bufp=0xed8448 <searchbufs+1832>) at regex-emacs.c:2617
  #6  0x0000000000660493 in rpl_re_compile_pattern (pattern=0x8011b8 "^;;;.\\(in Emacs version\\|bytecomp version FSF\\)", length=47, posix_backtracking=false, whitespace_regexp=0x0, bufp=0xed8448 <searchbufs+1832>) at regex-emacs.c:5116
  #7  0x00000000006456eb in compile_pattern_1 (cp=0xed8428 <searchbufs+1800>, pattern=XIL(0xaa125c), translate=XIL(0x19b7125), posix=false) at search.c:123
  #8  0x0000000000645b2f in compile_pattern (pattern=XIL(0xaa125c), regp=0x0, translate=XIL(0x19b7125), posix=false, multibyte=false) at search.c:237
  #9  0x0000000000646707 in fast_c_string_match_ignore_case (regexp=XIL(0xaa125c), string=0x7fffffffd09d "\n;; certain of its subdirectories.  Here we specify them.\n(normal-top-level-add-to-load-path '(\"vc\" \"url\" \"textmodes\" \"progmodes\" \"play\" \"org\" \"nxml\" \"net\" \"mh-e\" \"mail\" \"leim\" \"language\" \"internation"..., len=401) at search.c:497
  #10 0x00000000006dc284 in safe_to_load_version (fd=5) at lread.c:1060
  #11 0x00000000006dd06b in Fload (file=XIL(0x2556774), noerror=XIL(0x30), nomessage=XIL(0x30), nosuffix=XIL(0x30), must_suffix=XIL(0)) at lread.c:1398
  #12 0x000000000069b971 in eval_sub (form=XIL(0x1e70b03)) at eval.c:2525
  #13 0x0000000000695602 in Fprogn (body=XIL(0)) at eval.c:471
  #14 0x0000000000697784 in Flet (args=XIL(0x1e70b13)) at eval.c:1057
  #15 0x000000000069b451 in eval_sub (form=XIL(0x1e70b83)) at eval.c:2464
  #16 0x0000000000695602 in Fprogn (body=XIL(0x1e70863)) at eval.c:471
  #17 0x0000000000695636 in prog_ignore (body=XIL(0x1e70b93)) at eval.c:482
  #18 0x000000000069785a in Fwhile (args=XIL(0x1e71553)) at eval.c:1078
  #19 0x000000000069b451 in eval_sub (form=XIL(0x1e71563)) at eval.c:2464
  #20 0x0000000000695602 in Fprogn (body=XIL(0)) at eval.c:471
  #21 0x0000000000697784 in Flet (args=XIL(0x1e71573)) at eval.c:1057
  ---Type <return> to continue, or q <return> to quit---
  #22 0x000000000069b451 in eval_sub (form=XIL(0x1e71653)) at eval.c:2464
  #23 0x0000000000695602 in Fprogn (body=XIL(0x1d26063)) at eval.c:471
  #24 0x00000000006953c9 in Fif (args=XIL(0x1e41753)) at eval.c:427
  #25 0x000000000069b451 in eval_sub (form=XIL(0x1e41763)) at eval.c:2464
  #26 0x0000000000695602 in Fprogn (body=XIL(0)) at eval.c:471
  #27 0x000000000069e40b in funcall_lambda (fun=XIL(0x1d03ba3), nargs=0, arg_vector=0x7fffffffde00) at eval.c:3313
  #28 0x000000000069dc30 in apply_lambda (fun=XIL(0x1d03b93), args=XIL(0), count=4) at eval.c:3185
  #29 0x000000000069bcd4 in eval_sub (form=XIL(0x17d0813)) at eval.c:2588
  #30 0x000000000069ad2b in Feval (form=XIL(0x17d0813), lexical=XIL(0))
      at eval.c:2340
  #31 0x00000000005c4a3e in top_level_2 () at keyboard.c:1103
  #32 0x0000000000698abb in internal_condition_case (bfun=0x5c4a1b <top_level_2>, handlers=XIL(0x90), hfun=0x5c43dd <cmd_error>) at eval.c:1475
  #33 0x00000000005c4a86 in top_level_1 (ignore=XIL(0)) at keyboard.c:1111
  #34 0x0000000000697c09 in internal_catch (tag=XIL(0xe0d0), func=0x5c4a40 <top_level_1>, arg=XIL(0)) at eval.c:1198
  #35 0x00000000005c4967 in command_loop () at keyboard.c:1072
  #36 0x00000000005c3ec4 in recursive_edit_1 () at keyboard.c:720
  #37 0x00000000005c40bc in Frecursive_edit () at keyboard.c:789
  #38 0x00000000005bfb4b in main (argc=9, argv=0x7fffffffe368) at emacs.c:2297

  Lisp Backtrace:
  "load" (0xffffd570)
  "let" (0xffffd6f0)
  "while" (0xffffd8a0)
  "let" (0xffffdac0)
  "if" (0xffffdc40)
  "normal-top-level" (0xffffde00)
  (gdb)





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-12 19:44                                                                                       ` Lars Ingebrigtsen
@ 2021-05-13 14:44                                                                                         ` Pip Cet
  2021-05-13 21:23                                                                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2021-05-13 14:44 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, Stefan Monnier, 36649,
	Andrea Corallo

On Wed, May 12, 2021 at 7:44 PM Lars Ingebrigtsen <larsi@gnus.org> wrote:
> Eli Zaretskii <eliz@gnu.org> writes:
>
> > I don't know if this is an interesting configuration.  AFAIU,
> > "--with-dumping=none" means you run the CANNOT_DUMP version, which
> > doesn't dump Emacs at all.
>
> Ah, yes...  and in that case I guess there is no pure space?  Oh well, I
> guess somebody has to look into getting unexec working on Linux if we're
> to, er, see what the impact of pure space unexec would have been.  If it
> was working.  :-)

I had it working a while ago, just not using libc malloc(). AFAIU,
that's just incompatible with unexec() now.

(And it's still slightly but significantly faster building with
unexec() on Linux than building with pdumper, at least in contrived
benchmarks).

So, yes, I'd misunderstood Eli and thought he had objections to this
patch; if he doesn't, we should look into fixing the native-comp parts
and apply it :-)

Pip





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-13 14:44                                                                                         ` Pip Cet
@ 2021-05-13 21:23                                                                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-14  6:26                                                                                             ` Eli Zaretskii
  2021-05-16 13:46                                                                                             ` Lars Ingebrigtsen
  0 siblings, 2 replies; 125+ messages in thread
From: Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-05-13 21:23 UTC (permalink / raw)
  To: Pip Cet
  Cc: eggert, rpluim, stefan, schwab, Stefan Monnier, 36649,
	Lars Ingebrigtsen, Eli Zaretskii

Pip Cet <pipcet@gmail.com> writes:

> On Wed, May 12, 2021 at 7:44 PM Lars Ingebrigtsen <larsi@gnus.org> wrote:
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>> > I don't know if this is an interesting configuration.  AFAIU,
>> > "--with-dumping=none" means you run the CANNOT_DUMP version, which
>> > doesn't dump Emacs at all.
>>
>> Ah, yes...  and in that case I guess there is no pure space?  Oh well, I
>> guess somebody has to look into getting unexec working on Linux if we're
>> to, er, see what the impact of pure space unexec would have been.  If it
>> was working.  :-)
>
> I had it working a while ago, just not using libc malloc(). AFAIU,
> that's just incompatible with unexec() now.
>
> (And it's still slightly but significantly faster building with
> unexec() on Linux than building with pdumper, at least in contrived
> benchmarks).
>
> So, yes, I'd misunderstood Eli and thought he had objections to this
> patch; if he doesn't, we should look into fixing the native-comp parts
> and apply it :-)

Right, if you like me to have a look to the native-comp side would be
handy to have this patch pushed as a git branch on our repo.

  Andrea





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-13 21:23                                                                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-05-14  6:26                                                                                             ` Eli Zaretskii
  2021-05-14  6:35                                                                                               ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-16 13:46                                                                                             ` Lars Ingebrigtsen
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-14  6:26 UTC (permalink / raw)
  To: Andrea Corallo
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, larsi

> From: Andrea Corallo <akrl@sdf.org>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>, Eli Zaretskii <eliz@gnu.org>,
>         eggert@cs.ucla.edu, rpluim@gmail.com, stefan@marxist.se,
>         schwab@linux-m68k.org, Stefan Monnier <monnier@iro.umontreal.ca>,
>         36649@debbugs.gnu.org
> Date: Thu, 13 May 2021 21:23:10 +0000
> 
> > So, yes, I'd misunderstood Eli and thought he had objections to this
> > patch; if he doesn't, we should look into fixing the native-comp parts
> > and apply it :-)
> 
> Right, if you like me to have a look to the native-comp side would be
> handy to have this patch pushed as a git branch on our repo.

I'm not sure what native-comp has to do with this: AFAIK native-comp
doesn't support unexec at all, so any unexec build will not have
native compilation enabled.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-14  6:26                                                                                             ` Eli Zaretskii
@ 2021-05-14  6:35                                                                                               ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-14  7:07                                                                                                 ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2021-05-14  6:35 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, larsi

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Andrea Corallo <akrl@sdf.org>
>> Cc: Lars Ingebrigtsen <larsi@gnus.org>, Eli Zaretskii <eliz@gnu.org>,
>>         eggert@cs.ucla.edu, rpluim@gmail.com, stefan@marxist.se,
>>         schwab@linux-m68k.org, Stefan Monnier <monnier@iro.umontreal.ca>,
>>         36649@debbugs.gnu.org
>> Date: Thu, 13 May 2021 21:23:10 +0000
>> 
>> > So, yes, I'd misunderstood Eli and thought he had objections to this
>> > patch; if he doesn't, we should look into fixing the native-comp parts
>> > and apply it :-)
>> 
>> Right, if you like me to have a look to the native-comp side would be
>> handy to have this patch pushed as a git branch on our repo.
>
> I'm not sure what native-comp has to do with this: AFAIK native-comp
> doesn't support unexec at all, so any unexec build will not have
> native compilation enabled.

Yes is not unexec related, native comp classifies immediates that
originally went into pure space or not before hash consing then in order
to retain compatibility.  We should just remove this distinction if we
remove pure space.

  Andrea





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-14  6:35                                                                                               ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2021-05-14  7:07                                                                                                 ` Eli Zaretskii
  0 siblings, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-14  7:07 UTC (permalink / raw)
  To: Andrea Corallo
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, larsi

> From: Andrea Corallo <akrl@sdf.org>
> Cc: pipcet@gmail.com, larsi@gnus.org, eggert@cs.ucla.edu, rpluim@gmail.com,
>         stefan@marxist.se, schwab@linux-m68k.org, monnier@iro.umontreal.ca,
>         36649@debbugs.gnu.org
> Date: Fri, 14 May 2021 06:35:46 +0000
> 
> > I'm not sure what native-comp has to do with this: AFAIK native-comp
> > doesn't support unexec at all, so any unexec build will not have
> > native compilation enabled.
> 
> Yes is not unexec related, native comp classifies immediates that
> originally went into pure space or not before hash consing then in order
> to retain compatibility.  We should just remove this distinction if we
> remove pure space.

Ah, okay.  If you ask me, this is one more reason to wait with
removing the purespace.  But that's me.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-13 14:08                                                                                   ` Eli Zaretskii
@ 2021-05-16 13:38                                                                                     ` Lars Ingebrigtsen
  2021-05-17  8:43                                                                                       ` Paul Eggert
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-16 13:38 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Eli Zaretskii <eliz@gnu.org> writes:

> Looks like some memory problem: xrealloc segfaults.
>
> Don't we need to disable ASLR for unexec to work?  And doesn't that
> require setfattr or paxctl commands to be available?  If not, how do
> we disable ASLR in bootstrap-emacs and emacs binaries on GNU/Linux?

Hm...  the PROBLEMS file has this:

----
These segfaults should not occur on most modern systems, because the
Emacs build procedure uses the command 'setfattr' or 'paxctl' to mark
the Emacs executable as requiring non-randomized address space, and
Emacs uses the 'personality' system call to disable address space
randomization when dumping.
----

Is that correct?  I thought we had ASLR switched on on GNU/Linux builds?

----
To work around the ASLR problem in either an older or a newer kernel,
you can temporarily disable the feature while building Emacs.  On
GNU/Linux you can do so using the following command (as root).

    echo 0 > /proc/sys/kernel/randomize_va_space
----

I tried this recipe now on Debian/bullseye, but the unexec build still
segfaults.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-13 21:23                                                                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2021-05-14  6:26                                                                                             ` Eli Zaretskii
@ 2021-05-16 13:46                                                                                             ` Lars Ingebrigtsen
  1 sibling, 0 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-16 13:46 UTC (permalink / raw)
  To: Andrea Corallo
  Cc: eggert, rpluim, stefan, schwab, Stefan Monnier, Pip Cet, 36649

Andrea Corallo <akrl@sdf.org> writes:

> Right, if you like me to have a look to the native-comp side would be
> handy to have this patch pushed as a git branch on our repo.

I've now pushed a new branch called scratch/no-purespace which has Pip's
patch with some merge fix-ups from me.  It builds fine without
native-comp, but has many errors in comp.c if enabled.  So feel free to
fix that up.  :-)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-16 13:38                                                                                     ` Lars Ingebrigtsen
@ 2021-05-17  8:43                                                                                       ` Paul Eggert
  2021-05-17 10:25                                                                                         ` Eli Zaretskii
  2021-05-17 14:13                                                                                         ` Lars Ingebrigtsen
  0 siblings, 2 replies; 125+ messages in thread
From: Paul Eggert @ 2021-05-17  8:43 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Eli Zaretskii
  Cc: rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

On 5/16/21 6:38 AM, Lars Ingebrigtsen wrote:

> I thought we had ASLR switched on on GNU/Linux builds?

If unexec is used on GNU/Linux, Emacs is supposed to switch ASLR off by 
using "setfattr -n user.pax.flags -v er temacs", and if that doesn't 
work by using the personality syscall and then re-execing itself (see 
maybe_disable_address_randomization).

I doubt whether it's worth spending much time debugging the problem, 
since nobody uses unexec on GNU/Linux any more.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17  8:43                                                                                       ` Paul Eggert
@ 2021-05-17 10:25                                                                                         ` Eli Zaretskii
  2021-05-17 14:15                                                                                           ` Lars Ingebrigtsen
  2021-10-20 17:41                                                                                           ` Stefan Kangas
  2021-05-17 14:13                                                                                         ` Lars Ingebrigtsen
  1 sibling, 2 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-17 10:25 UTC (permalink / raw)
  To: Paul Eggert; +Cc: rpluim, stefan, schwab, monnier, pipcet, 36649, larsi, akrl

> Cc: rpluim@gmail.com, stefan@marxist.se, schwab@linux-m68k.org,
>  monnier@iro.umontreal.ca, pipcet@gmail.com, 36649@debbugs.gnu.org,
>  akrl@sdf.org
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Mon, 17 May 2021 01:43:31 -0700
> 
> I doubt whether it's worth spending much time debugging the problem, 
> since nobody uses unexec on GNU/Linux any more.

Since we decided not to remove unexec in Emacs 28, we do need to keep
the unexec configuration working.  So I find it unfortunate that you
keep saying that, because the result is a direct contradiction of what
we decided.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17  8:43                                                                                       ` Paul Eggert
  2021-05-17 10:25                                                                                         ` Eli Zaretskii
@ 2021-05-17 14:13                                                                                         ` Lars Ingebrigtsen
  1 sibling, 0 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-17 14:13 UTC (permalink / raw)
  To: Paul Eggert; +Cc: rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Paul Eggert <eggert@cs.ucla.edu> writes:

> If unexec is used on GNU/Linux, Emacs is supposed to switch ASLR off
> by using "setfattr -n user.pax.flags -v er temacs", and if that
> doesn't work by using the personality syscall and then re-execing
> itself (see maybe_disable_address_randomization).

Ah, thanks.  My src/Makefile had

## If needed, the names of the paxctl and setfattr programs.
## On grsecurity/PaX systems, unexec will fail due to a gap between
## the bss section and the heap.  Older versions need paxctl to work
## around this, newer ones setfattr.  See Bug#11398 and Bug#16343.
PAXCTL = 
SETFATTR = 
## Commands to set PaX flags on dumped and not-dumped instances of Emacs.
PAXCTL_dumped = 
PAXCTL_notdumped = 

because the "attr" package wasn't installed, so there was no setfattr
executable. 

(So if we want to continue supporting unexec, we should probably add
that as a configure requirement, perhaps.)

With that, Emacs now fails in a different way -- instead of segfaulting,
I get to:

make[2]: Entering directory '/home/larsi/src/emacs/xo/lisp'
  ELC      international/titdic-cnv.elc
corrupted double-linked list
Fatal error 6: Aborted
Backtrace:
../src/bootstrap-emacs[0x525571]
../src/bootstrap-emacs[0x4203b6]
../src/bootstrap-emacs[0x420889]

But as you say, debugging this is pretty much a waste of time.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17 10:25                                                                                         ` Eli Zaretskii
@ 2021-05-17 14:15                                                                                           ` Lars Ingebrigtsen
  2021-05-17 14:23                                                                                             ` Eli Zaretskii
  2021-05-17 14:32                                                                                             ` Andreas Schwab
  2021-10-20 17:41                                                                                           ` Stefan Kangas
  1 sibling, 2 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-17 14:15 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: Paul Eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

Eli Zaretskii <eliz@gnu.org> writes:

> Since we decided not to remove unexec in Emacs 28, we do need to keep
> the unexec configuration working.  So I find it unfortunate that you
> keep saying that, because the result is a direct contradiction of what
> we decided.

Well, if we decided something at one point, we can decide something else
now.

The question is whether it makes sense to spend time trying to fix
something that's not being used.  Keeping unexec around in a broken
state isn't very satisfying, and worries about unexec is what's stalling
the removal of pure space, too.

So at this point I think I'd rather just remove unexec now instead of
waiting until Emacs 29.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17 14:15                                                                                           ` Lars Ingebrigtsen
@ 2021-05-17 14:23                                                                                             ` Eli Zaretskii
  2021-05-19 15:11                                                                                               ` Eli Zaretskii
  2021-05-17 14:32                                                                                             ` Andreas Schwab
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-17 14:23 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: eggert, rpluim, stefan, schwab, monnier, pipcet, 36649, akrl

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: Paul Eggert <eggert@cs.ucla.edu>,  rpluim@gmail.com,  stefan@marxist.se,
>   schwab@linux-m68k.org,  monnier@iro.umontreal.ca,  pipcet@gmail.com,
>   36649@debbugs.gnu.org,  akrl@sdf.org
> Date: Mon, 17 May 2021 16:15:46 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Since we decided not to remove unexec in Emacs 28, we do need to keep
> > the unexec configuration working.  So I find it unfortunate that you
> > keep saying that, because the result is a direct contradiction of what
> > we decided.
> 
> Well, if we decided something at one point, we can decide something else
> now.

We can, but we really shouldn't in this case.  We never remove
obsolete features so quickly, and I see no reason to do this now.

> The question is whether it makes sense to spend time trying to fix
> something that's not being used.  Keeping unexec around in a broken
> state isn't very satisfying, and worries about unexec is what's stalling
> the removal of pure space, too.
> 
> So at this point I think I'd rather just remove unexec now instead of
> waiting until Emacs 29.

I see no reason for the rush, Emacs 28 is not around the corner
anyway.  We have enough new and important features there that will
take us time to shake out all the bugs and stabilize the codebase.

If no one else is willing to debug the unexec problems, I will do it
myself, at my own pace.  Just leave it to me.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17 14:15                                                                                           ` Lars Ingebrigtsen
  2021-05-17 14:23                                                                                             ` Eli Zaretskii
@ 2021-05-17 14:32                                                                                             ` Andreas Schwab
  2021-05-18 13:33                                                                                               ` Lars Ingebrigtsen
  1 sibling, 1 reply; 125+ messages in thread
From: Andreas Schwab @ 2021-05-17 14:32 UTC (permalink / raw)
  To: Lars Ingebrigtsen
  Cc: Paul Eggert, rpluim, stefan, monnier, pipcet, 36649, akrl

On Mai 17 2021, Lars Ingebrigtsen wrote:

> worries about unexec is what's stalling the removal of pure space,
> too.

unexec does not really depend on pure space.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17 14:32                                                                                             ` Andreas Schwab
@ 2021-05-18 13:33                                                                                               ` Lars Ingebrigtsen
  0 siblings, 0 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-18 13:33 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Paul Eggert, rpluim, stefan, monnier, pipcet, 36649, akrl

Andreas Schwab <schwab@linux-m68k.org> writes:

> On Mai 17 2021, Lars Ingebrigtsen wrote:
>
>> worries about unexec is what's stalling the removal of pure space,
>> too.
>
> unexec does not really depend on pure space.

No, but Eli was worried that applying this patch would further
destabilise the unexec code, which I think is fair.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17 14:23                                                                                             ` Eli Zaretskii
@ 2021-05-19 15:11                                                                                               ` Eli Zaretskii
  2021-05-19 17:29                                                                                                 ` Paul Eggert
  2021-05-19 18:55                                                                                                 ` Lars Ingebrigtsen
  0 siblings, 2 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-19 15:11 UTC (permalink / raw)
  To: larsi, eggert; +Cc: stefan, rpluim, schwab, monnier, 36649

> Date: Mon, 17 May 2021 17:23:50 +0300
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: eggert@cs.ucla.edu, rpluim@gmail.com, stefan@marxist.se,
>  schwab@linux-m68k.org, monnier@iro.umontreal.ca, pipcet@gmail.com,
>  36649@debbugs.gnu.org, akrl@sdf.org
> 
> If no one else is willing to debug the unexec problems, I will do it
> myself, at my own pace.

Now done.  At least the unoptimized build with unexec runs cleanly to
completion on GNU/Linux.  Turns out we broke this about 1.5 year ago,
when an unrelated change inadvertently disabled the use of
HYBRID_MALLOC in this build, which is a must for unexec to work on
this platform.

There's one aspect of the changeset I pushed that I'm uneasy about.
It is this part in configure.ac:

  diff --git a/configure.ac b/configure.ac
  index 3df4359..d35ac6d 100644
  --- a/configure.ac
  +++ b/configure.ac
  @@ -2306,6 +2309,9 @@ AC_DEFUN
     GNU_MALLOC_reason=" (only before dumping)"
     GMALLOC_OBJ=gmalloc.o
     VMLIMIT_OBJ=
  +  # FIXME: This is to prevent Gnulib from redirecting 'free' to its
  +  # replacement, instead of 'hybrid_free' in gmalloc.c.
  +  gl_cv_func_free_preserves_errno=yes
   else
     test "$doug_lea_malloc" != "yes" && GMALLOC_OBJ=gmalloc.o
     VMLIMIT_OBJ=vm-limit.o

The problem here is that Gnulib wants to redirect 'free' to its
replacement 'rpl_free', and that breaks our own redirection, in
conf_post.h, to 'hybrid_free' (of gmalloc.c), which we _must_ use in
this configuration.  I couldn't find a clean fix, so for now the
unexec build will not use the Gnulib replacement for 'free'.

Paul, if this kludge annoys you enough (I hope it will), please
suggest a cleaner way out of this conundrum.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-19 15:11                                                                                               ` Eli Zaretskii
@ 2021-05-19 17:29                                                                                                 ` Paul Eggert
  2021-05-19 17:38                                                                                                   ` Eli Zaretskii
  2021-05-19 18:55                                                                                                 ` Lars Ingebrigtsen
  1 sibling, 1 reply; 125+ messages in thread
From: Paul Eggert @ 2021-05-19 17:29 UTC (permalink / raw)
  To: Eli Zaretskii, larsi; +Cc: stefan, rpluim, schwab, monnier, 36649

On 5/19/21 8:11 AM, Eli Zaretskii wrote:
> Paul, if this kludge annoys you enough (I hope it will), please
> suggest a cleaner way out of this conundrum.

configure.ac can define a macro that tells gmalloc.c about the kludge 
situation, and gmalloc.c can refer to that macro to decide whether to 
call rpl_free instead of plain 'free'.

Also, make sure that hybrid_free preserves errno.

Without these fixes some Gnulib code will possibly stop working, since 
the rest of Gnulib assumes 'free' preserves errno.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-19 17:29                                                                                                 ` Paul Eggert
@ 2021-05-19 17:38                                                                                                   ` Eli Zaretskii
  2021-05-19 17:43                                                                                                     ` Paul Eggert
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-19 17:38 UTC (permalink / raw)
  To: Paul Eggert; +Cc: rpluim, stefan, schwab, monnier, 36649, larsi

> Cc: rpluim@gmail.com, stefan@marxist.se, schwab@linux-m68k.org,
>  monnier@iro.umontreal.ca, 36649@debbugs.gnu.org
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Wed, 19 May 2021 10:29:06 -0700
> 
> On 5/19/21 8:11 AM, Eli Zaretskii wrote:
> > Paul, if this kludge annoys you enough (I hope it will), please
> > suggest a cleaner way out of this conundrum.
> 
> configure.ac can define a macro that tells gmalloc.c about the kludge 
> situation, and gmalloc.c can refer to that macro to decide whether to 
> call rpl_free instead of plain 'free'.

The problem is not in gmalloc.c, the problem is in every src/*.c file
that calls 'free'.  That's because we redirect to hybrid_free in
conf_post.h, but Gnulib's stdlib.h is included after that, and it
undoes that redirection:

  #if @GNULIB_FREE_POSIX@
  # if @REPLACE_FREE@
  #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
  #   undef free
  #   define free rpl_free
  #  endif

Then the linker errors out due to unresolved externals, because
there's no rpl_free.

Would it work to add rpl_free to gmalloc.c, perhaps?

> Also, make sure that hybrid_free preserves errno.

If this is the best solution, then okay, will do.  I hoped something
cleaner could be possible.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-19 17:38                                                                                                   ` Eli Zaretskii
@ 2021-05-19 17:43                                                                                                     ` Paul Eggert
  2021-05-20  8:46                                                                                                       ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Paul Eggert @ 2021-05-19 17:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rpluim, stefan, schwab, monnier, 36649, larsi

On 5/19/21 10:38 AM, Eli Zaretskii wrote:
> The problem is not in gmalloc.c, the problem is in every src/*.c file
> that calls 'free'.  That's because we redirect to hybrid_free in
> conf_post.h, but Gnulib's stdlib.h is included after that,

Have conf_post.h include stdlib.h before it redefines 'free'. It should 
do that anyway, since POSIX stdlib.h is allowed to define 'free' as a macro.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-19 15:11                                                                                               ` Eli Zaretskii
  2021-05-19 17:29                                                                                                 ` Paul Eggert
@ 2021-05-19 18:55                                                                                                 ` Lars Ingebrigtsen
  1 sibling, 0 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2021-05-19 18:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: eggert, rpluim, stefan, schwab, monnier, 36649

Eli Zaretskii <eliz@gnu.org> writes:

>> If no one else is willing to debug the unexec problems, I will do it
>> myself, at my own pace.
>
> Now done.  At least the unoptimized build with unexec runs cleanly to
> completion on GNU/Linux.

Yup; I can confirm that the following works here on this Debian/bullseye
system:

./configure --with-unexec=yes --with-dumping=unexec; make bootstrap

I'll try to get the previously discussed benchmarking done later this
week.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-19 17:43                                                                                                     ` Paul Eggert
@ 2021-05-20  8:46                                                                                                       ` Eli Zaretskii
  0 siblings, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-05-20  8:46 UTC (permalink / raw)
  To: Paul Eggert; +Cc: rpluim, stefan, schwab, monnier, 36649, larsi

> Cc: larsi@gnus.org, rpluim@gmail.com, stefan@marxist.se,
>  schwab@linux-m68k.org, monnier@iro.umontreal.ca, 36649@debbugs.gnu.org
> From: Paul Eggert <eggert@cs.ucla.edu>
> Date: Wed, 19 May 2021 10:43:24 -0700
> 
> On 5/19/21 10:38 AM, Eli Zaretskii wrote:
> > The problem is not in gmalloc.c, the problem is in every src/*.c file
> > that calls 'free'.  That's because we redirect to hybrid_free in
> > conf_post.h, but Gnulib's stdlib.h is included after that,
> 
> Have conf_post.h include stdlib.h before it redefines 'free'. It should 
> do that anyway, since POSIX stdlib.h is allowed to define 'free' as a macro.

Thanks, this does work and looks much cleaner, so I've now made that
change.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-05-17 10:25                                                                                         ` Eli Zaretskii
  2021-05-17 14:15                                                                                           ` Lars Ingebrigtsen
@ 2021-10-20 17:41                                                                                           ` Stefan Kangas
  2021-10-20 18:18                                                                                             ` Eli Zaretskii
  1 sibling, 1 reply; 125+ messages in thread
From: Stefan Kangas @ 2021-10-20 17:41 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: Paul Eggert, rpluim, schwab, monnier, pipcet, 36649, larsi, akrl

Eli Zaretskii <eliz@gnu.org> writes:

>> I doubt whether it's worth spending much time debugging the problem,
>> since nobody uses unexec on GNU/Linux any more.
>
> Since we decided not to remove unexec in Emacs 28, we do need to keep
> the unexec configuration working.

Should we consider removing unexec in Emacs 29?





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2021-10-20 17:41                                                                                           ` Stefan Kangas
@ 2021-10-20 18:18                                                                                             ` Eli Zaretskii
  0 siblings, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2021-10-20 18:18 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: eggert, rpluim, schwab, monnier, pipcet, 36649, larsi, akrl

> From: Stefan Kangas <stefan@marxist.se>
> Date: Wed, 20 Oct 2021 10:41:28 -0700
> Cc: Paul Eggert <eggert@cs.ucla.edu>, rpluim@gmail.com, schwab@linux-m68k.org, 
> 	monnier@iro.umontreal.ca, pipcet@gmail.com, 36649@debbugs.gnu.org, 
> 	larsi@gnus.org, akrl@sdf.org
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> I doubt whether it's worth spending much time debugging the problem,
> >> since nobody uses unexec on GNU/Linux any more.
> >
> > Since we decided not to remove unexec in Emacs 28, we do need to keep
> > the unexec configuration working.
> 
> Should we consider removing unexec in Emacs 29?

That's possible, but we still have plenty of time before we get to the
decision point, and have no information at all regarding whether
unexec is still used with Emacs 28 (because it wasn't released yet).
So it's too early to make the decision, and we have no data on which
to base the decision.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-14 14:26 bug#36649: 27.0.50; pure space and pdumper Pip Cet
  2019-07-21  7:28 ` Paul Eggert
@ 2022-07-01 13:46 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-01 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-03  7:14 ` Gerd Möllmann
  2 siblings, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-01 13:46 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649

I rebased the `scratch/no-purespace` on top of `master`.


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-01 13:46 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-01 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-01 16:03     ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-01 15:51 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649

Stefan Monnier [2022-07-01 09:46:10] wrote:
> I rebased the `scratch/no-purespace` on top of `master`.

It seems to work fine, both with pdump and with unexec (only tried
under Debian testing).
Should I clean it up and push it to `master`?


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-01 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-01 16:03     ` Eli Zaretskii
  2022-07-01 16:33       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-01 16:03 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 36649, pipcet

> Cc: 36649@debbugs.gnu.org
> Date: Fri, 01 Jul 2022 11:51:25 -0400
> From:  Stefan Monnier via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
> 
> Stefan Monnier [2022-07-01 09:46:10] wrote:
> > I rebased the `scratch/no-purespace` on top of `master`.
> 
> It seems to work fine, both with pdump and with unexec (only tried
> under Debian testing).
> Should I clean it up and push it to `master`?

Only for pdumper, I think.  AFAIR, we didn't want to remove pure space
in the unexec build.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-01 16:03     ` Eli Zaretskii
@ 2022-07-01 16:33       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-01 18:12         ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-01 16:33 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, pipcet

> Only for pdumper, I think.  AFAIR, we didn't want to remove pure space
> in the unexec build.

That means keeping purespace and hence not applying the patch.
Why would we want to keep purespace in the unexec build?


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-01 16:33       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-01 18:12         ` Eli Zaretskii
  2022-07-01 18:58           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-01 18:12 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 36649, pipcet

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: pipcet@gmail.com,  36649@debbugs.gnu.org
> Date: Fri, 01 Jul 2022 12:33:13 -0400
> 
> > Only for pdumper, I think.  AFAIR, we didn't want to remove pure space
> > in the unexec build.
> 
> That means keeping purespace and hence not applying the patch.
> Why would we want to keep purespace in the unexec build?

This was discussed at length, I think in this bug as well.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-01 18:12         ` Eli Zaretskii
@ 2022-07-01 18:58           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02  8:55             ` Pip Cet
  0 siblings, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-01 18:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, pipcet

>> That means keeping purespace and hence not applying the patch.
>> Why would we want to keep purespace in the unexec build?
> This was discussed at length, I think in this bug as well.
I've seen it stated in this thread, but never explained, no.

The only "explanation" I've seen is quotes of me saying that it has
a performance impact (I guess it wasn't my brightest moment: it does
have a performance impact, but that impact is the same that's paid by
all users of the pdumper, so it can't be significant enough to stop
installing this patch).


        Stefan






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-01 18:58           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02  8:55             ` Pip Cet
  2022-07-02  9:06               ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Pip Cet @ 2022-07-02  8:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 36649, Eli Zaretskii

On Fri, Jul 1, 2022 at 6:58 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> >> That means keeping purespace and hence not applying the patch.
> >> Why would we want to keep purespace in the unexec build?
> > This was discussed at length, I think in this bug as well.
> I've seen it stated in this thread, but never explained, no.

FWIW, I don't recall any reason why it shouldn't work with unexec,
either. To the best of my recollection, unexec was generally broken at
the time I wrote the patch; I fixed unexec and then it worked without
purespace, but the unexec fixes never made it into master until Eli
re-did them a while later.

(IIRC, this patch predates the nativecomp merge and that affected pure
space a little, so that probably needs to be kept in mind.)

Pip





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02  8:55             ` Pip Cet
@ 2022-07-02  9:06               ` Eli Zaretskii
  2022-07-02  9:16                 ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02  9:06 UTC (permalink / raw)
  To: Pip Cet; +Cc: 36649, monnier

> From: Pip Cet <pipcet@gmail.com>
> Date: Sat, 2 Jul 2022 08:55:46 +0000
> Cc: Eli Zaretskii <eliz@gnu.org>, 36649@debbugs.gnu.org
> 
> On Fri, Jul 1, 2022 at 6:58 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> > >> That means keeping purespace and hence not applying the patch.
> > >> Why would we want to keep purespace in the unexec build?
> > > This was discussed at length, I think in this bug as well.
> > I've seen it stated in this thread, but never explained, no.
> 
> FWIW, I don't recall any reason why it shouldn't work with unexec,
> either. To the best of my recollection, unexec was generally broken at
> the time I wrote the patch; I fixed unexec and then it worked without
> purespace, but the unexec fixes never made it into master until Eli
> re-did them a while later.

Basically, I don't want us to drop the pure space in the unexec
builds, whether it makes sense to the rest of you or not.  So there
are two alternatives: either drop pure space only for the pdumper
build, or wait for us to remove the unexec support and drop pure space
then.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02  9:06               ` Eli Zaretskii
@ 2022-07-02  9:16                 ` Lars Ingebrigtsen
  2022-07-02  9:22                   ` Eli Zaretskii
  2022-07-02 10:28                   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 2 replies; 125+ messages in thread
From: Lars Ingebrigtsen @ 2022-07-02  9:16 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Po Lu, 36649, monnier, Pip Cet

Eli Zaretskii <eliz@gnu.org> writes:

> Basically, I don't want us to drop the pure space in the unexec
> builds, whether it makes sense to the rest of you or not.

Could you explain why?  Skimming this thread, I must have missed the
rationale.  (But it's a long thread.)

> So there are two alternatives: either drop pure space only for the
> pdumper build, or wait for us to remove the unexec support and drop
> pure space then.

If I understand correctly, dropping pure space would make Po's work on
improving the garbage collector easier -- and improving gc is important,
so it seems to make sense to get rid of pure space just for that reason.

But I'm not against dropping unexec now, too -- we can drop both unexec
and pure space now.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02  9:16                 ` Lars Ingebrigtsen
@ 2022-07-02  9:22                   ` Eli Zaretskii
  2022-07-02 10:30                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 16:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 10:28                   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 2 replies; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02  9:22 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, 36649, monnier, pipcet

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: Pip Cet <pipcet@gmail.com>,  36649@debbugs.gnu.org,
>   monnier@iro.umontreal.ca, Po Lu <luangruo@yahoo.com>
> Date: Sat, 02 Jul 2022 11:16:05 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Basically, I don't want us to drop the pure space in the unexec
> > builds, whether it makes sense to the rest of you or not.
> 
> Could you explain why?

Because I don't want to invest any significant effort in maintaining
the unexec build.  It should remain as close to its original shape as
possible, until it's gone.

> > So there are two alternatives: either drop pure space only for the
> > pdumper build, or wait for us to remove the unexec support and drop
> > pure space then.
> 
> If I understand correctly, dropping pure space would make Po's work on
> improving the garbage collector easier -- and improving gc is important,
> so it seems to make sense to get rid of pure space just for that reason.

He said he already dropped that in the branch where he works, so that
is AFAIU a moot point.  (And if he didn't drop it already, he can drop
it now in that branch.)

> But I'm not against dropping unexec now, too -- we can drop both unexec
> and pure space now.

Not yet, we don't have enough experience without it.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02  9:16                 ` Lars Ingebrigtsen
  2022-07-02  9:22                   ` Eli Zaretskii
@ 2022-07-02 10:28                   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 10:32                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 10:40                     ` Eli Zaretskii
  1 sibling, 2 replies; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 10:28 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 36649, Eli Zaretskii, monnier, Pip Cet

Lars Ingebrigtsen <larsi@gnus.org> writes:

> If I understand correctly, dropping pure space would make Po's work on
> improving the garbage collector easier -- and improving gc is important,
> so it seems to make sense to get rid of pure space just for that reason.
>
> But I'm not against dropping unexec now, too -- we can drop both unexec
> and pure space now.

FWIW none of the dumping mechanisms work with the new garbage collector,
but it will be optional, since I don't see how to make it work on MS-DOS
(which AFAIU has no equivalent of `mprotect').  The current
implementation also assumes 4K pages.

So in my work, pure space and incremental GC are both conditional, under
#ifdef HAVE_MPROTECT.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02  9:22                   ` Eli Zaretskii
@ 2022-07-02 10:30                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 10:41                       ` Eli Zaretskii
  2022-07-02 16:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 10:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, Lars Ingebrigtsen, monnier, pipcet

Eli Zaretskii <eliz@gnu.org> writes:

> Not yet, we don't have enough experience without it.

Not to mention that the pdumper currently doesn't work on Windows 9x,
MS-DOS, and GNU/Linux on m68k.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 10:28                   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 10:32                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 10:40                     ` Eli Zaretskii
  1 sibling, 0 replies; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 10:32 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 36649, Eli Zaretskii, monnier, Pip Cet

Po Lu <luangruo@yahoo.com> writes:

> FWIW none of the dumping mechanisms work with the new garbage collector,
> but it will be optional, since I don't see how to make it work on MS-DOS
> (which AFAIU has no equivalent of `mprotect').  The current
> implementation also assumes 4K pages.
>
> So in my work, pure space and incremental GC are both conditional, under
> #ifdef HAVE_MPROTECT.

Sorry, I meant pure space is conditional when not HAVE_MPROTECT, while
incremental GC is enabled when it is defined.  Or rather, will be, since
so far I've only made blind, half hearted attempts to keep the regular
GC building.  It probably won't build or work.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 10:28                   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 10:32                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 10:40                     ` Eli Zaretskii
  2022-07-02 10:55                       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  1 sibling, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02 10:40 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, larsi, monnier, pipcet

> From: Po Lu <luangruo@yahoo.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  Pip Cet <pipcet@gmail.com>,
>   36649@debbugs.gnu.org,  monnier@iro.umontreal.ca
> Date: Sat, 02 Jul 2022 18:28:40 +0800
> 
> Lars Ingebrigtsen <larsi@gnus.org> writes:
> 
> > If I understand correctly, dropping pure space would make Po's work on
> > improving the garbage collector easier -- and improving gc is important,
> > so it seems to make sense to get rid of pure space just for that reason.
> >
> > But I'm not against dropping unexec now, too -- we can drop both unexec
> > and pure space now.
> 
> FWIW none of the dumping mechanisms work with the new garbage collector,
> but it will be optional, since I don't see how to make it work on MS-DOS
> (which AFAIU has no equivalent of `mprotect').

The C library and the environment used by the MS-DOS port do have
mprotect, but it is only supported with some DPMI servers, and the
MS-Windows DPMI server is not one of them.

But I don't think this is too relevant, since memory protection in
MS-DOS is more or less a no-op.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 10:30                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 10:41                       ` Eli Zaretskii
  2022-07-02 10:51                         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02 10:41 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, larsi, monnier, pipcet

> From: Po Lu <luangruo@yahoo.com>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>,  pipcet@gmail.com,
>   36649@debbugs.gnu.org,  monnier@iro.umontreal.ca
> Date: Sat, 02 Jul 2022 18:30:10 +0800
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > Not yet, we don't have enough experience without it.
> 
> Not to mention that the pdumper currently doesn't work on Windows 9x,
> MS-DOS, and GNU/Linux on m68k.

The latter case is the reason why we cannot yet remove unexec.

Is m68k a live platform, or is it also dying?





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 10:41                       ` Eli Zaretskii
@ 2022-07-02 10:51                         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 12:07                           ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 10:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, larsi, monnier, pipcet

Eli Zaretskii <eliz@gnu.org> writes:

> The latter case is the reason why we cannot yet remove unexec.
>
> Is m68k a live platform, or is it also dying?

It's still supported by at least one major GNU/Linux distribution, and
there was recent activity on bug#44531, so it's still being used enough
for users to complain when something goes wrong.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 10:40                     ` Eli Zaretskii
@ 2022-07-02 10:55                       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 10:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 36649, larsi, monnier, pipcet

Eli Zaretskii <eliz@gnu.org> writes:

> The C library and the environment used by the MS-DOS port do have
> mprotect, but it is only supported with some DPMI servers, and the
> MS-Windows DPMI server is not one of them.

Too bad.  That means MS-DOS will have to do with the old garbage
collector.

> But I don't think this is too relevant, since memory protection in
> MS-DOS is more or less a no-op.

For incremental garbage collection to work, Emacs needs to be able to
place memory protection on "blocks" of objects allocated to align with a
page start, in order to receive a signal when a write to an object in
such a block happens.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 10:51                         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 12:07                           ` Lars Ingebrigtsen
  2022-07-02 12:22                             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2022-07-02 12:07 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, Eli Zaretskii, monnier, pipcet

Po Lu <luangruo@yahoo.com> writes:

>> The latter case is the reason why we cannot yet remove unexec.
>>
>> Is m68k a live platform, or is it also dying?
>
> It's still supported by at least one major GNU/Linux distribution, and
> there was recent activity on bug#44531, so it's still being used enough
> for users to complain when something goes wrong.

Which GNU/Linux distribution is that?

Anyway, I don't feel that carrying around unexec just for m68k is
warranted -- it's a super duper marginal platform, and probably isn't
used for real work by anybody.  (So they can use older Emacs versions if
they absolutely have to.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 12:07                           ` Lars Ingebrigtsen
@ 2022-07-02 12:22                             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 12:41                               ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 12:22 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 36649, Eli Zaretskii, monnier, pipcet

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Which GNU/Linux distribution is that?

The reporter used Debian.

> Anyway, I don't feel that carrying around unexec just for m68k is
> warranted -- it's a super duper marginal platform, and probably isn't
> used for real work by anybody.  (So they can use older Emacs versions if
> they absolutely have to.)

unexec isn't doing any harm by itself, so there's no reason to not keep
it.  I don't forsee much trouble in keeping pure space behind a few
ifdefs; it should be a mostly mechanical job.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 12:22                             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 12:41                               ` Lars Ingebrigtsen
  2022-07-02 12:45                                 ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2022-07-02 12:41 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, Eli Zaretskii, monnier, pipcet

Po Lu <luangruo@yahoo.com> writes:

> Lars Ingebrigtsen <larsi@gnus.org> writes:
>
>> Which GNU/Linux distribution is that?
>
> The reporter used Debian.

According to:

  https://www.debian.org/ports/m68k/

  The Debian m68k port was first officially released with Debian 2.0
  (hamm) and was an official port until Debian 4.0 (etch). There's now
  an effort to revive this port.

Debian 4.0 was over a decade ago, so either they were using Debian from
2010, or they're part of the effort to revive the port.

Hm...  Ah!

  https://buildd.debian.org/status/fetch.php?pkg=emacs&arch=m68k&ver=1%3A27.1%2B1-3&stamp=1604857999&raw=0

This isn't a report from somebody using Emacs on m68k, but a Debian
developer trying to revive the port.  (Which has not happened.)

So it seems safe to assume that nobody uses Emacs on m68k.

>> Anyway, I don't feel that carrying around unexec just for m68k is
>> warranted -- it's a super duper marginal platform, and probably isn't
>> used for real work by anybody.  (So they can use older Emacs versions if
>> they absolutely have to.)
>
> unexec isn't doing any harm by itself, so there's no reason to not keep
> it.  I don't forsee much trouble in keeping pure space behind a few
> ifdefs; it should be a mostly mechanical job.

But Eli doesn't want to get rid of purespace (which we do want to) until
we get rid of unexec, so unexec is blocking progress in that sense.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 12:41                               ` Lars Ingebrigtsen
@ 2022-07-02 12:45                                 ` Eli Zaretskii
  2022-07-02 17:23                                   ` Lars Ingebrigtsen
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02 12:45 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, 36649, monnier, pipcet

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: Eli Zaretskii <eliz@gnu.org>,  pipcet@gmail.com,  36649@debbugs.gnu.org,
>   monnier@iro.umontreal.ca
> Date: Sat, 02 Jul 2022 14:41:01 +0200
> 
> > unexec isn't doing any harm by itself, so there's no reason to not keep
> > it.  I don't forsee much trouble in keeping pure space behind a few
> > ifdefs; it should be a mostly mechanical job.
> 
> But Eli doesn't want to get rid of purespace (which we do want to) until
> we get rid of unexec, so unexec is blocking progress in that sense.

No, I'm okay with having the purespace removed from the pdumper
builds, if the unexec build can still use it.  AFAIU, that's the
"behind several ifdefs" alternative.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02  9:22                   ` Eli Zaretskii
  2022-07-02 10:30                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 16:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 17:11                       ` Eli Zaretskii
  1 sibling, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 16:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, 36649, Lars Ingebrigtsen, pipcet

[-- Attachment #1: Type: text/plain, Size: 1013 bytes --]

>> > Basically, I don't want us to drop the pure space in the unexec
>> > builds, whether it makes sense to the rest of you or not.
>> Could you explain why?
> Because I don't want to invest any significant effort in maintaining
> the unexec build.

The patch does not touch the unexec code at all.

If anything, it should make unexec simpler to maintain, since there's
one less issue to worry about (the current code might have to worry
about dumping the normal heap plus the purespace, whereas the new code
only has to worry about the normal heap), but `grep -i pur src/unex*.c`
suggests that the purespace has never had any impact on unexec.

> No, I'm okay with having the purespace removed from the pdumper
> builds, if the unexec build can still use it.  AFAIU, that's the
> "behind several ifdefs" alternative.

I don't know how to remove the purespace in pdump builds and not in
unexec builds.  I don't even know what that would mean and/or look like.
Would the patch below be acceptable?


        Stefan

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: purespace.diff --]
[-- Type: text/x-diff, Size: 13228 bytes --]

commit 3daf833ff3f3e99b44731808cb197c0912649997
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Date:   Fri Jul 1 14:36:49 2022 -0400

    src/alloc.c: Remove all uses of `pure_alloc`
    
    First step of removal of the purespace: stop using it.
    The more delicate parts are the handling of 0-length strings and
    vectors which we used to allocate in purespace but now need to be
    allocated elsewhere, but the existing code makes us work harder to
    allocate them in the normal way.
    
    * src/alloc.c: Remove all uses of `pure_alloc`.
    (init_strings): Alloc empty strings in the normal heap.
    (init_vectors): Allocate the zero_vector in the normal heap.
    (make_pure_string, make_pure_c_string, pure_cons): Rewrite to create
    normal heap objects.
    (find_string_data_in_pure, make_pure_float, make_pure_bignum)
    (make_pure_vector, purecopy_hash_table): Delete functions.
    (purecopy): Return without purecopying.

diff --git a/src/alloc.c b/src/alloc.c
index f115a3cebaa..522547661a5 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -435,7 +435,6 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
 static void unchain_finalizer (struct Lisp_Finalizer *);
 static void mark_terminals (void);
 static void gc_sweep (void);
-static Lisp_Object make_pure_vector (ptrdiff_t);
 static void mark_buffer (struct buffer *);
 
 #if !defined REL_ALLOC || defined SYSTEM_MALLOC || defined HYBRID_MALLOC
@@ -1674,12 +1673,30 @@ #define GC_STRING_EXTRA GC_STRING_OVERRUN_COOKIE_SIZE
 
 /* Initialize string allocation.  Called from init_alloc_once.  */
 
+static struct Lisp_String *allocate_string (void);
+static void
+allocate_string_data (struct Lisp_String *s,
+		      EMACS_INT nchars, EMACS_INT nbytes, bool clearit,
+		      bool immovable);
+
 static void
 init_strings (void)
 {
-  empty_unibyte_string = make_pure_string ("", 0, 0, 0);
+  /* String allocation code will return one of 'empty_*ibyte_string'
+     when asked to construct a new 0-length string, so in order to build
+     those special cases, we have to do it "by hand".  */
+  struct Lisp_String *ems = allocate_string ();
+  struct Lisp_String *eus = allocate_string ();
+  ems->u.s.intervals = NULL;
+  eus->u.s.intervals = NULL;
+  allocate_string_data (ems, 0, 0, false, false);
+  allocate_string_data (eus, 0, 0, false, false);
+  /* We can't use 'STRING_SET_UNIBYTE' because this one includes a hack
+   * to redirect its arg to 'empty_unibyte_string' when nbytes == 0. */
+  eus->u.s.size_byte = -1;
+  XSETSTRING (empty_multibyte_string, ems);
+  XSETSTRING (empty_unibyte_string, eus);
   staticpro (&empty_unibyte_string);
-  empty_multibyte_string = make_pure_string ("", 0, 0, 1);
   staticpro (&empty_multibyte_string);
 }
 
@@ -3008,12 +3025,25 @@ allocate_vector_block (void)
   return block;
 }
 
+static struct Lisp_Vector *
+allocate_vector_from_block (ptrdiff_t nbytes);
+
 /* Called once to initialize vector allocation.  */
 
 static void
 init_vectors (void)
 {
-  zero_vector = make_pure_vector (0);
+  /* The normal vector allocation code refuses to allocate a 0-length vector
+     because we use the first field of vectors internally when they're on
+     the free list, so we can't put a zero-length vector on the free list.
+     This is not a problem for 'zero_vector' since it's always reachable.
+     An alternative approach would be to allocate zero_vector outside of the
+     normal heap, e.g. as a static object, and then to "hide" it from the GC,
+     for example by marking it by hand at the beginning of the GC and unmarking
+     it by hand at the end.  */
+  struct Lisp_Vector *zv = allocate_vector_from_block (vroundup (header_size));
+  zv->header.size = 0;
+  zero_vector = make_lisp_ptr (zv, Lisp_Vectorlike);
   staticpro (&zero_vector);
 }
 
@@ -5371,72 +5401,6 @@ check_pure_size (void)
 #endif
 
 
-/* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from
-   the non-Lisp data pool of the pure storage, and return its start
-   address.  Return NULL if not found.  */
-
-static char *
-find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
-{
-  int i;
-  ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max;
-  const unsigned char *p;
-  char *non_lisp_beg;
-
-  if (pure_bytes_used_non_lisp <= nbytes)
-    return NULL;
-
-  /* Set up the Boyer-Moore table.  */
-  skip = nbytes + 1;
-  for (i = 0; i < 256; i++)
-    bm_skip[i] = skip;
-
-  p = (const unsigned char *) data;
-  while (--skip > 0)
-    bm_skip[*p++] = skip;
-
-  last_char_skip = bm_skip['\0'];
-
-  non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp;
-  start_max = pure_bytes_used_non_lisp - (nbytes + 1);
-
-  /* See the comments in the function `boyer_moore' (search.c) for the
-     use of `infinity'.  */
-  infinity = pure_bytes_used_non_lisp + 1;
-  bm_skip['\0'] = infinity;
-
-  p = (const unsigned char *) non_lisp_beg + nbytes;
-  start = 0;
-  do
-    {
-      /* Check the last character (== '\0').  */
-      do
-	{
-	  start += bm_skip[*(p + start)];
-	}
-      while (start <= start_max);
-
-      if (start < infinity)
-	/* Couldn't find the last character.  */
-	return NULL;
-
-      /* No less than `infinity' means we could find the last
-	 character at `p[start - infinity]'.  */
-      start -= infinity;
-
-      /* Check the remaining characters.  */
-      if (memcmp (data, non_lisp_beg + start, nbytes) == 0)
-	/* Found.  */
-	return non_lisp_beg + start;
-
-      start += last_char_skip;
-    }
-  while (start <= start_max);
-
-  return NULL;
-}
-
-
 /* Return a string allocated in pure space.  DATA is a buffer holding
    NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
    means make the result string multibyte.
@@ -5449,20 +5413,10 @@ find_string_data_in_pure (const char *data, ptrdiff_t nbytes)
 make_pure_string (const char *data,
 		  ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte)
 {
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes);
-  if (s->u.s.data == NULL)
-    {
-      s->u.s.data = pure_alloc (nbytes + 1, -1);
-      memcpy (s->u.s.data, data, nbytes);
-      s->u.s.data[nbytes] = '\0';
-    }
-  s->u.s.size = nchars;
-  s->u.s.size_byte = multibyte ? nbytes : -1;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
+  if (multibyte)
+    return make_multibyte_string (data, nchars, nbytes);
+  else
+    return make_unibyte_string (data, nchars);
 }
 
 /* Return a string allocated in pure space.  Do not
@@ -5471,14 +5425,7 @@ make_pure_string (const char *data,
 Lisp_Object
 make_pure_c_string (const char *data, ptrdiff_t nchars)
 {
-  Lisp_Object string;
-  struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String);
-  s->u.s.size = nchars;
-  s->u.s.size_byte = -2;
-  s->u.s.data = (unsigned char *) data;
-  s->u.s.intervals = NULL;
-  XSETSTRING (string, s);
-  return string;
+  return make_unibyte_string (data, nchars);
 }
 
 static Lisp_Object purecopy (Lisp_Object obj);
@@ -5489,103 +5436,10 @@ make_pure_c_string (const char *data, ptrdiff_t nchars)
 Lisp_Object
 pure_cons (Lisp_Object car, Lisp_Object cdr)
 {
-  Lisp_Object new;
-  struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons);
-  XSETCONS (new, p);
-  XSETCAR (new, purecopy (car));
-  XSETCDR (new, purecopy (cdr));
-  return new;
+  return Fcons (car, cdr);
 }
 
 
-/* Value is a float object with value NUM allocated from pure space.  */
-
-static Lisp_Object
-make_pure_float (double num)
-{
-  Lisp_Object new;
-  struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float);
-  XSETFLOAT (new, p);
-  XFLOAT_INIT (new, num);
-  return new;
-}
-
-/* Value is a bignum object with value VALUE allocated from pure
-   space.  */
-
-static Lisp_Object
-make_pure_bignum (Lisp_Object value)
-{
-  mpz_t const *n = xbignum_val (value);
-  size_t i, nlimbs = mpz_size (*n);
-  size_t nbytes = nlimbs * sizeof (mp_limb_t);
-  mp_limb_t *pure_limbs;
-  mp_size_t new_size;
-
-  struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike);
-  XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum));
-
-  int limb_alignment = alignof (mp_limb_t);
-  pure_limbs = pure_alloc (nbytes, - limb_alignment);
-  for (i = 0; i < nlimbs; ++i)
-    pure_limbs[i] = mpz_getlimbn (*n, i);
-
-  new_size = nlimbs;
-  if (mpz_sgn (*n) < 0)
-    new_size = -new_size;
-
-  mpz_roinit_n (b->value, pure_limbs, new_size);
-
-  return make_lisp_ptr (b, Lisp_Vectorlike);
-}
-
-/* Return a vector with room for LEN Lisp_Objects allocated from
-   pure space.  */
-
-static Lisp_Object
-make_pure_vector (ptrdiff_t len)
-{
-  Lisp_Object new;
-  size_t size = header_size + len * word_size;
-  struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike);
-  XSETVECTOR (new, p);
-  XVECTOR (new)->header.size = len;
-  return new;
-}
-
-/* Copy all contents and parameters of TABLE to a new table allocated
-   from pure space, return the purified table.  */
-static struct Lisp_Hash_Table *
-purecopy_hash_table (struct Lisp_Hash_Table *table)
-{
-  eassert (NILP (table->weak));
-  eassert (table->purecopy);
-
-  struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike);
-  struct hash_table_test pure_test = table->test;
-
-  /* Purecopy the hash table test.  */
-  pure_test.name = purecopy (table->test.name);
-  pure_test.user_hash_function = purecopy (table->test.user_hash_function);
-  pure_test.user_cmp_function = purecopy (table->test.user_cmp_function);
-
-  pure->header = table->header;
-  pure->weak = purecopy (Qnil);
-  pure->hash = purecopy (table->hash);
-  pure->next = purecopy (table->next);
-  pure->index = purecopy (table->index);
-  pure->count = table->count;
-  pure->next_free = table->next_free;
-  pure->purecopy = table->purecopy;
-  eassert (!pure->mutable);
-  pure->rehash_threshold = table->rehash_threshold;
-  pure->rehash_size = table->rehash_size;
-  pure->key_and_value = purecopy (table->key_and_value);
-  pure->test = pure_test;
-
-  return pure;
-}
-
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
        doc: /* Make a copy of object OBJ in pure storage.
 Recursively copies contents of vectors and cons cells.
@@ -5616,10 +5470,6 @@ purecopy (Lisp_Object obj)
       || SUBRP (obj))
     return obj;    /* Already pure.  */
 
-  if (STRINGP (obj) && XSTRING (obj)->u.s.intervals)
-    message_with_string ("Dropping text-properties while making string `%s' pure",
-			 obj, true);
-
   if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
     {
       Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil);
@@ -5627,74 +5477,6 @@ purecopy (Lisp_Object obj)
 	return tmp;
     }
 
-  if (CONSP (obj))
-    obj = pure_cons (XCAR (obj), XCDR (obj));
-  else if (FLOATP (obj))
-    obj = make_pure_float (XFLOAT_DATA (obj));
-  else if (STRINGP (obj))
-    obj = make_pure_string (SSDATA (obj), SCHARS (obj),
-			    SBYTES (obj),
-			    STRING_MULTIBYTE (obj));
-  else if (HASH_TABLE_P (obj))
-    {
-      struct Lisp_Hash_Table *table = XHASH_TABLE (obj);
-      /* Do not purify hash tables which haven't been defined with
-         :purecopy as non-nil or are weak - they aren't guaranteed to
-         not change.  */
-      if (!NILP (table->weak) || !table->purecopy)
-        {
-          /* Instead, add the hash table to the list of pinned objects,
-             so that it will be marked during GC.  */
-          struct pinned_object *o = xmalloc (sizeof *o);
-          o->object = obj;
-          o->next = pinned_objects;
-          pinned_objects = o;
-          return obj; /* Don't hash cons it.  */
-        }
-
-      struct Lisp_Hash_Table *h = purecopy_hash_table (table);
-      XSET_HASH_TABLE (obj, h);
-    }
-  else if (COMPILEDP (obj) || VECTORP (obj) || RECORDP (obj))
-    {
-      struct Lisp_Vector *objp = XVECTOR (obj);
-      ptrdiff_t nbytes = vector_nbytes (objp);
-      struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
-      register ptrdiff_t i;
-      ptrdiff_t size = ASIZE (obj);
-      if (size & PSEUDOVECTOR_FLAG)
-	size &= PSEUDOVECTOR_SIZE_MASK;
-      memcpy (vec, objp, nbytes);
-      for (i = 0; i < size; i++)
-	vec->contents[i] = purecopy (vec->contents[i]);
-      // Byte code strings must be pinned.
-      if (COMPILEDP (obj) && size >= 2 && STRINGP (vec->contents[1])
-	  && !STRING_MULTIBYTE (vec->contents[1]))
-	pin_string (vec->contents[1]);
-      XSETVECTOR (obj, vec);
-    }
-  else if (BARE_SYMBOL_P (obj))
-    {
-      if (!XBARE_SYMBOL (obj)->u.s.pinned && !c_symbol_p (XBARE_SYMBOL (obj)))
-	{ /* We can't purify them, but they appear in many pure objects.
-	     Mark them as `pinned' so we know to mark them at every GC cycle.  */
-	  XBARE_SYMBOL (obj)->u.s.pinned = true;
-	  symbol_block_pinned = symbol_block;
-	}
-      /* Don't hash-cons it.  */
-      return obj;
-    }
-  else if (BIGNUMP (obj))
-    obj = make_pure_bignum (obj);
-  else
-    {
-      AUTO_STRING (fmt, "Don't know how to purify: %S");
-      Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
-    }
-
-  if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing.  */
-    Fputhash (obj, obj, Vpurify_flag);
-
   return obj;
 }
 

^ permalink raw reply related	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 16:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 17:11                       ` Eli Zaretskii
  2022-07-02 18:03                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02 17:11 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: luangruo, 36649, larsi, pipcet

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Lars Ingebrigtsen <larsi@gnus.org>,  pipcet@gmail.com,
>   36649@debbugs.gnu.org,  luangruo@yahoo.com
> Date: Sat, 02 Jul 2022 12:57:09 -0400
> 
> >> > Basically, I don't want us to drop the pure space in the unexec
> >> > builds, whether it makes sense to the rest of you or not.
> >> Could you explain why?
> > Because I don't want to invest any significant effort in maintaining
> > the unexec build.
> 
> The patch does not touch the unexec code at all.

It "touches" the unexec code in that it removes purespace, and thus
changes the behavior of the unexec build.  I don't want to deal with
consequences of such a change.

> If anything, it should make unexec simpler to maintain, since there's
> one less issue to worry about (the current code might have to worry
> about dumping the normal heap plus the purespace, whereas the new code
> only has to worry about the normal heap), but `grep -i pur src/unex*.c`
> suggests that the purespace has never had any impact on unexec.

I'm not convinced, sorry.

> > No, I'm okay with having the purespace removed from the pdumper
> > builds, if the unexec build can still use it.  AFAIU, that's the
> > "behind several ifdefs" alternative.
> 
> I don't know how to remove the purespace in pdump builds and not in
> unexec builds.  I don't even know what that would mean and/or look
> like.

Po Lu said it should be simple, so maybe he will propose a patch?

> Would the patch below be acceptable?

No, because it removes purespace unconditionally.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 12:45                                 ` Eli Zaretskii
@ 2022-07-02 17:23                                   ` Lars Ingebrigtsen
  2022-07-02 17:31                                     ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Lars Ingebrigtsen @ 2022-07-02 17:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, 36649, monnier, pipcet

Eli Zaretskii <eliz@gnu.org> writes:

> No, I'm okay with having the purespace removed from the pdumper
> builds, if the unexec build can still use it.  AFAIU, that's the
> "behind several ifdefs" alternative.

One reason to get rid of pure space is to get rid of all the calls to
build_pure_c_string etc etc that litter the code, but just disabling
pure space in pdump doesn't help us with that.  (And the reason we want
to do that is to make the code easier to approach for people.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 17:23                                   ` Lars Ingebrigtsen
@ 2022-07-02 17:31                                     ` Eli Zaretskii
  0 siblings, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02 17:31 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: luangruo, 36649, monnier, pipcet

> From: Lars Ingebrigtsen <larsi@gnus.org>
> Cc: luangruo@yahoo.com,  pipcet@gmail.com,  36649@debbugs.gnu.org,
>   monnier@iro.umontreal.ca
> Date: Sat, 02 Jul 2022 19:23:24 +0200
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> > No, I'm okay with having the purespace removed from the pdumper
> > builds, if the unexec build can still use it.  AFAIU, that's the
> > "behind several ifdefs" alternative.
> 
> One reason to get rid of pure space is to get rid of all the calls to
> build_pure_c_string etc etc that litter the code, but just disabling
> pure space in pdump doesn't help us with that.  (And the reason we want
> to do that is to make the code easier to approach for people.)

Yes, I understand that this change has 2 parts: the syntactic part
(removing the calls to *pure* functions from our sources) and the part
that removes the use of purespace.  The first part will have to wait
until we remove the unexec support; the second part can either wait
till then, or we can stop using purespace in the pdumper builds now.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 17:11                       ` Eli Zaretskii
@ 2022-07-02 18:03                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-02 18:32                           ` Eli Zaretskii
  0 siblings, 1 reply; 125+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-02 18:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, 36649, larsi, pipcet

>> Would the patch below be acceptable?
> No, because it removes purespace unconditionally.

It does not remove purespace, it just stops using it.
IOW, it seems to match your description:

> until we remove the unexec support; the second part can either wait
> till then, or we can stop using purespace in the pdumper builds now.


        Stfean






^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-02 18:03                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-02 18:32                           ` Eli Zaretskii
  0 siblings, 0 replies; 125+ messages in thread
From: Eli Zaretskii @ 2022-07-02 18:32 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: luangruo, 36649, larsi, pipcet

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: larsi@gnus.org,  pipcet@gmail.com,  36649@debbugs.gnu.org,
>   luangruo@yahoo.com
> Date: Sat, 02 Jul 2022 14:03:29 -0400
> 
> >> Would the patch below be acceptable?
> > No, because it removes purespace unconditionally.
> 
> It does not remove purespace, it just stops using it.

It does that in all builds.  Which is not what I agreed to.  The
unexec build should continue using the purespace.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2019-07-14 14:26 bug#36649: 27.0.50; pure space and pdumper Pip Cet
  2019-07-21  7:28 ` Paul Eggert
  2022-07-01 13:46 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-03  7:14 ` Gerd Möllmann
  2022-07-03  7:42   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2 siblings, 1 reply; 125+ messages in thread
From: Gerd Möllmann @ 2022-07-03  7:14 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, monnier

[-- Attachment #1: Type: text/plain, Size: 434 bytes --]

> FWIW none of the dumping mechanisms work with the new garbage collector,

Interesting!

Is there something I could read about your new GC?

I'm asking because I once also had plans to rewrite Emacs' GC (to be incremental and generational).  But hat was >20 years ago, and it never took off because the algorithm I used was patented.  Which it no longer is, I think.

CC'ing Stefan because he reminded me of this, recently.

[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 874 bytes --]

^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-03  7:14 ` Gerd Möllmann
@ 2022-07-03  7:42   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-03  8:21     ` Gerd Möllmann
  0 siblings, 1 reply; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-03  7:42 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 36649, monnier

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Interesting!
>
> Is there something I could read about your new GC?

Not exactly.  It's a very simple 3 color incremental mark-and-sweep
collector (which is not generational or moving) using hardware write
barriers to keep track of changes made by the mutator.  I tried to keep
the design of the existing garbage collector intact as much as possible.

The motive was to get rid of the noticeable freeze during garbage
collection instead of making GC itself fast.

> I'm asking because I once also had plans to rewrite Emacs' GC (to be
> incremental and generational).  But hat was >20 years ago, and it
> never took off because the algorithm I used was patented.  Which it no
> longer is, I think.

Which algorithm(s) were you considering?  I think that information might
be useful.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-03  7:42   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-03  8:21     ` Gerd Möllmann
  2022-07-03  9:38       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Gerd Möllmann @ 2022-07-03  8:21 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, monnier

[-- Attachment #1: Type: text/plain, Size: 1254 bytes --]



> On 2022-07-03,, at 9:42 , Po Lu <luangruo@yahoo.com> wrote:
> 
> Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> 
>> Interesting!
>> 
>> Is there something I could read about your new GC?
> 
> Not exactly.  It's a very simple 3 color incremental mark-and-sweep
> collector (which is not generational or moving) using hardware write
> barriers to keep track of changes made by the mutator.  I tried to keep
> the design of the existing garbage collector intact as much as possible.

I understand.  I think I know the 3-color algorithm.  Details don't matter that much.

> 
> Which algorithm(s) were you considering?  I think that information might
> be useful.

It's a mostly-copying GC, using VM pages and VM page protection.  The mostly-copying part was patented at the time, which I noticed too late.  AFAIU, that patent has expired, but that's a question for someone knowing US law better than me.

I can send you a C file if you want (also everyone else who wants it).  Stefan already has it.  I sent it around in 2001 or so, in the hope that it might be of some use in the future.

The C file even has some large explanatory comments, albeit I have to admit I wrote them years after the code, for sending it out.


[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 874 bytes --]

^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-03  8:21     ` Gerd Möllmann
@ 2022-07-03  9:38       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-07-03  9:42         ` Gerd Möllmann
  0 siblings, 1 reply; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-03  9:38 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 36649, monnier

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> I understand.  I think I know the 3-color algorithm.  Details don't
> matter that much.

Thanks.

> I can send you a C file if you want (also everyone else who wants it).
> Stefan already has it.  I sent it around in 2001 or so, in the hope
> that it might be of some use in the future.
>
> The C file even has some large explanatory comments, albeit I have to
> admit I wrote them years after the code, for sending it out.

Sure, that would be useful.  You're not the only person who has tried to
rewrite the garbage collector: Daniel Colascione recently took a stab at
a similar garbage collector too.





^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-03  9:38       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-07-03  9:42         ` Gerd Möllmann
  2022-07-03 10:01           ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 125+ messages in thread
From: Gerd Möllmann @ 2022-07-03  9:42 UTC (permalink / raw)
  To: Po Lu; +Cc: 36649, monnier

[-- Attachment #1: Type: text/plain, Size: 331 bytes --]



> On 2022-07-03,, at 11:38 , Po Lu <luangruo@yahoo.com> wrote:
> 
> Sure, that would be useful.

Sent off-list.

> You're not the only person who has tried to
> rewrite the garbage collector: Daniel Colascione recently took a stab at
> a similar garbage collector too.

Can I ask what the result was?  Is he still working on it?

[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 874 bytes --]

^ permalink raw reply	[flat|nested] 125+ messages in thread

* bug#36649: 27.0.50; pure space and pdumper
  2022-07-03  9:42         ` Gerd Möllmann
@ 2022-07-03 10:01           ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 0 replies; 125+ messages in thread
From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-07-03 10:01 UTC (permalink / raw)
  To: Gerd Möllmann; +Cc: 36649, monnier

Gerd Möllmann <gerd.moellmann@gmail.com> writes:

> Can I ask what the result was?  Is he still working on it?

I think he doesn't have the time to continue working on it, so no, it's
not being worked on anymore.





^ permalink raw reply	[flat|nested] 125+ messages in thread

end of thread, other threads:[~2022-07-03 10:01 UTC | newest]

Thread overview: 125+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-14 14:26 bug#36649: 27.0.50; pure space and pdumper Pip Cet
2019-07-21  7:28 ` Paul Eggert
2019-07-21 12:53   ` Pip Cet
2019-07-21 13:44     ` Robert Pluim
2019-07-21 14:36       ` Pip Cet
2019-07-21 15:06         ` Robert Pluim
2019-07-21 17:43           ` Pip Cet
2019-07-21 17:56             ` Robert Pluim
2019-07-21 18:07               ` Pip Cet
2019-07-21 19:12                 ` Robert Pluim
2019-07-21 19:35                   ` Pip Cet
2019-07-21 20:20                     ` Robert Pluim
2019-07-22  3:58                       ` Pip Cet
2019-07-22  8:14                         ` Robert Pluim
2019-07-22 14:30                           ` Eli Zaretskii
2019-07-22 15:46                             ` Robert Pluim
2019-07-22 15:03                           ` Pip Cet
2019-07-22 18:45                             ` Robert Pluim
2020-08-21 12:51                               ` Lars Ingebrigtsen
2020-08-21 13:04                                 ` Pip Cet
2020-08-21 13:47                                   ` Eli Zaretskii
2020-08-21 15:26                                     ` Andreas Schwab
2020-08-21 21:41                                     ` Paul Eggert
2020-08-22  3:51                                     ` Richard Stallman
2020-08-22  8:55                                     ` Pip Cet
2020-08-22  9:59                                       ` Andreas Schwab
2020-08-28 12:32                                         ` Pip Cet
2020-08-28 14:24                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
2020-11-15 15:19                                           ` Stefan Kangas
2021-03-03 15:34                                             ` Pip Cet
2021-03-04 12:55                                               ` Pip Cet
2021-03-04 14:56                                                 ` Robert Pluim
2021-03-04 15:49                                                   ` Eli Zaretskii
2021-03-04 16:42                                                     ` Robert Pluim
2021-03-04 17:07                                                       ` Eli Zaretskii
2021-03-04 17:18                                                         ` Robert Pluim
2021-03-04 16:53                                                     ` martin rudalics
2021-03-04 17:45                                                     ` Andy Moreton
2021-03-04 21:52                                                   ` Paul Eggert
2021-03-05  3:00                                                     ` Pip Cet
2021-03-05  7:20                                                       ` Eli Zaretskii
2021-03-14 22:19                                                       ` Stefan Monnier
2021-05-12 14:50                                                         ` Lars Ingebrigtsen
2021-05-12 15:01                                                           ` Eli Zaretskii
2021-05-12 17:03                                                             ` Lars Ingebrigtsen
2021-05-12 17:06                                                               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-05-12 17:11                                                                 ` Lars Ingebrigtsen
2021-05-12 17:28                                                                   ` Eli Zaretskii
2021-05-12 17:32                                                                     ` Lars Ingebrigtsen
2021-05-12 17:42                                                                       ` Eli Zaretskii
2021-05-12 17:58                                                                         ` Lars Ingebrigtsen
2021-05-12 18:25                                                                           ` Lars Ingebrigtsen
2021-05-12 18:37                                                                             ` Eli Zaretskii
2021-05-12 18:48                                                                               ` Lars Ingebrigtsen
2021-05-12 18:52                                                                                 ` Eli Zaretskii
2021-05-12 19:07                                                                                   ` Lars Ingebrigtsen
2021-05-12 19:12                                                                                     ` Eli Zaretskii
2021-05-12 19:44                                                                                       ` Lars Ingebrigtsen
2021-05-13 14:44                                                                                         ` Pip Cet
2021-05-13 21:23                                                                                           ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-05-14  6:26                                                                                             ` Eli Zaretskii
2021-05-14  6:35                                                                                               ` Andrea Corallo via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-05-14  7:07                                                                                                 ` Eli Zaretskii
2021-05-16 13:46                                                                                             ` Lars Ingebrigtsen
2021-05-13 14:08                                                                                   ` Eli Zaretskii
2021-05-16 13:38                                                                                     ` Lars Ingebrigtsen
2021-05-17  8:43                                                                                       ` Paul Eggert
2021-05-17 10:25                                                                                         ` Eli Zaretskii
2021-05-17 14:15                                                                                           ` Lars Ingebrigtsen
2021-05-17 14:23                                                                                             ` Eli Zaretskii
2021-05-19 15:11                                                                                               ` Eli Zaretskii
2021-05-19 17:29                                                                                                 ` Paul Eggert
2021-05-19 17:38                                                                                                   ` Eli Zaretskii
2021-05-19 17:43                                                                                                     ` Paul Eggert
2021-05-20  8:46                                                                                                       ` Eli Zaretskii
2021-05-19 18:55                                                                                                 ` Lars Ingebrigtsen
2021-05-17 14:32                                                                                             ` Andreas Schwab
2021-05-18 13:33                                                                                               ` Lars Ingebrigtsen
2021-10-20 17:41                                                                                           ` Stefan Kangas
2021-10-20 18:18                                                                                             ` Eli Zaretskii
2021-05-17 14:13                                                                                         ` Lars Ingebrigtsen
2021-05-12 19:12                                                                           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-05-12 18:02                                                                       ` Paul Eggert
2021-05-12 17:37                                                                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-05-12 17:44                                                                       ` Eli Zaretskii
2021-05-12 19:07                                                                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-05-12 19:17                                                                           ` Eli Zaretskii
2021-05-12 17:19                                                                 ` Eli Zaretskii
2021-05-12 17:10                                                               ` Eli Zaretskii
2021-05-12 17:24                                                                 ` Lars Ingebrigtsen
2020-08-22 17:36                                       ` Paul Eggert
2019-07-21 18:14               ` Eli Zaretskii
2022-07-01 13:46 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-01 15:51   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-01 16:03     ` Eli Zaretskii
2022-07-01 16:33       ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-01 18:12         ` Eli Zaretskii
2022-07-01 18:58           ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02  8:55             ` Pip Cet
2022-07-02  9:06               ` Eli Zaretskii
2022-07-02  9:16                 ` Lars Ingebrigtsen
2022-07-02  9:22                   ` Eli Zaretskii
2022-07-02 10:30                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 10:41                       ` Eli Zaretskii
2022-07-02 10:51                         ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 12:07                           ` Lars Ingebrigtsen
2022-07-02 12:22                             ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 12:41                               ` Lars Ingebrigtsen
2022-07-02 12:45                                 ` Eli Zaretskii
2022-07-02 17:23                                   ` Lars Ingebrigtsen
2022-07-02 17:31                                     ` Eli Zaretskii
2022-07-02 16:57                     ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 17:11                       ` Eli Zaretskii
2022-07-02 18:03                         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 18:32                           ` Eli Zaretskii
2022-07-02 10:28                   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 10:32                     ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-02 10:40                     ` Eli Zaretskii
2022-07-02 10:55                       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-03  7:14 ` Gerd Möllmann
2022-07-03  7:42   ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-03  8:21     ` Gerd Möllmann
2022-07-03  9:38       ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-07-03  9:42         ` Gerd Möllmann
2022-07-03 10:01           ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).