(mark_stack) [!GC_LISP_OBJECT_ALIGNMENT && __GNUC__]:
[bpt/emacs.git] / src / alloc.c
index 678bdfa..fb15f88 100644 (file)
@@ -1,5 +1,5 @@
 /* Storage allocation and gc for GNU Emacs Lisp interpreter.
-   Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000
+   Copyright (C) 1985, 86, 88, 93, 94, 95, 97, 98, 1999, 2000, 2001, 2002, 2003
       Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -22,16 +22,28 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 #include <stdio.h>
 
+#ifdef ALLOC_DEBUG
+#undef INLINE
+#endif
+
 /* Note that this declares bzero on OSF/1.  How dumb.  */
 
 #include <signal.h>
 
+/* GC_MALLOC_CHECK defined means perform validity checks of malloc'd
+   memory.  Can do this only if using gmalloc.c.  */
+
+#if defined SYSTEM_MALLOC || defined DOUG_LEA_MALLOC
+#undef GC_MALLOC_CHECK
+#endif
+
 /* This file is part of the core Lisp implementation, and thus must
    deal with the real data structures.  If the Lisp implementation is
    replaced, this file likely will not be used.  */
 
 #undef HIDE_LISP_IMPLEMENTATION
 #include "lisp.h"
+#include "process.h"
 #include "intervals.h"
 #include "puresize.h"
 #include "buffer.h"
@@ -52,7 +64,10 @@ extern POINTER_TYPE *sbrk ();
 #ifdef DOUG_LEA_MALLOC
 
 #include <malloc.h>
+/* malloc.h #defines this as size_t, at least in glibc2.  */
+#ifndef __malloc_size_t
 #define __malloc_size_t int
+#endif
 
 /* Specify maximum number of areas to mmap.  It would be nice to use a
    value that explicitly means "no limit".  */
@@ -63,20 +78,12 @@ extern POINTER_TYPE *sbrk ();
 
 /* The following come from gmalloc.c.  */
 
-#if defined (STDC_HEADERS)
-#include <stddef.h>
 #define        __malloc_size_t         size_t
-#else
-#define        __malloc_size_t         unsigned int
-#endif
 extern __malloc_size_t _bytes_used;
-extern int __malloc_extra_blocks;
+extern __malloc_size_t __malloc_extra_blocks;
 
 #endif /* not DOUG_LEA_MALLOC */
 
-#define max(A,B) ((A) > (B) ? (A) : (B))
-#define min(A,B) ((A) < (B) ? (A) : (B))
-
 /* Macro to verify that storage intended for Lisp objects is not
    out of range to fit in the space for a pointer.
    ADDRESS is the start of the block, and SIZE
@@ -119,18 +126,18 @@ int consing_since_gc;
 
 /* Count the amount of consing of various sorts of space.  */
 
-int cons_cells_consed;
-int floats_consed;
-int vector_cells_consed;
-int symbols_consed;
-int string_chars_consed;
-int misc_objects_consed;
-int intervals_consed;
-int strings_consed;
+EMACS_INT cons_cells_consed;
+EMACS_INT floats_consed;
+EMACS_INT vector_cells_consed;
+EMACS_INT symbols_consed;
+EMACS_INT string_chars_consed;
+EMACS_INT misc_objects_consed;
+EMACS_INT intervals_consed;
+EMACS_INT strings_consed;
 
 /* Number of bytes of consing since GC before another GC should be done. */
 
-int gc_cons_threshold;
+EMACS_INT gc_cons_threshold;
 
 /* Nonzero during GC.  */
 
@@ -152,8 +159,8 @@ int malloc_sbrk_unused;
 
 /* Two limits controlling how much undo information to keep.  */
 
-int undo_limit;
-int undo_strong_limit;
+EMACS_INT undo_limit;
+EMACS_INT undo_strong_limit;
 
 /* Number of live and free conses etc.  */
 
@@ -178,6 +185,10 @@ static int malloc_hysteresis;
 
 Lisp_Object Vpurify_flag;
 
+/* Non-nil means we are handling a memory-full error.  */
+
+Lisp_Object Vmemory_full;
+
 #ifndef HAVE_SHM
 
 /* Force it into data space! */
@@ -185,33 +196,34 @@ Lisp_Object Vpurify_flag;
 EMACS_INT pure[PURESIZE / sizeof (EMACS_INT)] = {0,};
 #define PUREBEG (char *) pure
 
-#else /* not HAVE_SHM */
+#else /* HAVE_SHM */
 
 #define pure PURE_SEG_BITS   /* Use shared memory segment */
 #define PUREBEG (char *)PURE_SEG_BITS
 
-/* This variable is used only by the XPNTR macro when HAVE_SHM is
-   defined.  If we used the PURESIZE macro directly there, that would
-   make most of Emacs dependent on puresize.h, which we don't want -
-   you should be able to change that without too much recompilation.
-   So map_in_data initializes pure_size, and the dependencies work
-   out.  */
+#endif /* HAVE_SHM */
+
+/* Pointer to the pure area, and its size.  */
 
-EMACS_INT pure_size;
+static char *purebeg;
+static size_t pure_size;
 
-#endif /* not HAVE_SHM */
+/* Number of bytes of pure storage used before pure storage overflowed.
+   If this is non-zero, this implies that an overflow occurred.  */
+
+static size_t pure_bytes_used_before_overflow;
 
 /* Value is non-zero if P points into pure space.  */
 
 #define PURE_POINTER_P(P)                                      \
      (((PNTR_COMPARISON_TYPE) (P)                              \
-       < (PNTR_COMPARISON_TYPE) ((char *) pure + PURESIZE))    \
+       < (PNTR_COMPARISON_TYPE) ((char *) purebeg + pure_size))        \
       && ((PNTR_COMPARISON_TYPE) (P)                           \
-         >= (PNTR_COMPARISON_TYPE) pure))
+         >= (PNTR_COMPARISON_TYPE) purebeg))
 
 /* Index in pure at which next pure object will be allocated.. */
 
-int pureptr;
+EMACS_INT pure_bytes_used;
 
 /* If nonzero, this is a warning delivered by malloc and not yet
    displayed.  */
@@ -220,7 +232,7 @@ char *pending_malloc_warning;
 
 /* Pre-computed signal argument for use when memory is exhausted.  */
 
-Lisp_Object memory_signal_data;
+Lisp_Object Vmemory_signal_data;
 
 /* Maximum amount of C stack to save when a GC happens.  */
 
@@ -240,6 +252,10 @@ int ignore_warnings;
 
 Lisp_Object Qgc_cons_threshold, Qchar_table_extra_slots;
 
+/* Hook run after GC has finished.  */
+
+Lisp_Object Vpost_gc_hook, Qpost_gc_hook;
+
 static void mark_buffer P_ ((Lisp_Object));
 static void mark_kboards P_ ((void));
 static void gc_sweep P_ ((void));
@@ -271,10 +287,17 @@ enum mem_type
   MEM_TYPE_MISC,
   MEM_TYPE_SYMBOL,
   MEM_TYPE_FLOAT,
-  MEM_TYPE_VECTOR
+  /* Keep the following vector-like types together, with
+     MEM_TYPE_WINDOW being the last, and MEM_TYPE_VECTOR the
+     first.  Or change the code of live_vector_p, for instance.  */
+  MEM_TYPE_VECTOR,
+  MEM_TYPE_PROCESS,
+  MEM_TYPE_HASH_TABLE,
+  MEM_TYPE_FRAME,
+  MEM_TYPE_WINDOW
 };
 
-#if GC_MARK_STACK
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
 #include <stdio.h>             /* For fprintf.  */
@@ -285,11 +308,77 @@ enum mem_type
 
 Lisp_Object Vdead;
 
-struct mem_node;
+#ifdef GC_MALLOC_CHECK
+
+enum mem_type allocated_mem_type;
+int dont_register_blocks;
+
+#endif /* GC_MALLOC_CHECK */
+
+/* A node in the red-black tree describing allocated memory containing
+   Lisp data.  Each such block is recorded with its start and end
+   address when it is allocated, and removed from the tree when it
+   is freed.
+
+   A red-black tree is a balanced binary tree with the following
+   properties:
+
+   1. Every node is either red or black.
+   2. Every leaf is black.
+   3. If a node is red, then both of its children are black.
+   4. Every simple path from a node to a descendant leaf contains
+   the same number of black nodes.
+   5. The root is always black.
+
+   When nodes are inserted into the tree, or deleted from the tree,
+   the tree is "fixed" so that these properties are always true.
+
+   A red-black tree with N internal nodes has height at most 2
+   log(N+1).  Searches, insertions and deletions are done in O(log N).
+   Please see a text book about data structures for a detailed
+   description of red-black trees.  Any book worth its salt should
+   describe them.  */
+
+struct mem_node
+{
+  /* Children of this node.  These pointers are never NULL.  When there
+     is no child, the value is MEM_NIL, which points to a dummy node.  */
+  struct mem_node *left, *right;
+
+  /* The parent of this node.  In the root node, this is NULL.  */
+  struct mem_node *parent;
+
+  /* Start and end of allocated region.  */
+  void *start, *end;
+
+  /* Node color.  */
+  enum {MEM_BLACK, MEM_RED} color;
+  
+  /* Memory type.  */
+  enum mem_type type;
+};
+
+/* Base address of stack.  Set in main.  */
+
+Lisp_Object *stack_base;
+
+/* Root of the tree describing allocated Lisp memory.  */
+
+static struct mem_node *mem_root;
+
+/* Lowest and highest known address in the heap.  */
+
+static void *min_heap_address, *max_heap_address;
+
+/* Sentinel node of the tree.  */
+
+static struct mem_node mem_z;
+#define MEM_NIL &mem_z
+
 static POINTER_TYPE *lisp_malloc P_ ((size_t, enum mem_type));
+static struct Lisp_Vector *allocate_vectorlike P_ ((EMACS_INT, enum mem_type));
 static void lisp_free P_ ((POINTER_TYPE *));
 static void mark_stack P_ ((void));
-static void init_stack P_ ((Lisp_Object *));
 static int live_vector_p P_ ((struct mem_node *, void *));
 static int live_buffer_p P_ ((struct mem_node *, void *));
 static int live_string_p P_ ((struct mem_node *, void *));
@@ -312,30 +401,37 @@ static INLINE struct mem_node *mem_find P_ ((void *));
 static void check_gcpros P_ ((void));
 #endif
 
-#endif /* GC_MARK_STACK != 0 */
+#endif /* GC_MARK_STACK || GC_MALLOC_CHECK */
+
+/* Recording what needs to be marked for gc.  */
+
+struct gcpro *gcprolist;
+
+/* Addresses of staticpro'd variables.  */
+
+#define NSTATICS 1280
+Lisp_Object *staticvec[NSTATICS] = {0};
+
+/* Index of next unused slot in staticvec.  */
+
+int staticidx = 0;
+
+static POINTER_TYPE *pure_alloc P_ ((size_t, int));
+
+
+/* Value is SZ rounded up to the next multiple of ALIGNMENT.
+   ALIGNMENT must be a power of 2.  */
+
+#define ALIGN(SZ, ALIGNMENT) \
+  (((SZ) + (ALIGNMENT) - 1) & ~((ALIGNMENT) - 1))
+
 
 \f
 /************************************************************************
                                Malloc
  ************************************************************************/
 
-/* Write STR to Vstandard_output plus some advice on how to free some
-   memory.  Called when memory gets low.  */
-
-Lisp_Object
-malloc_warning_1 (str)
-     Lisp_Object str;
-{
-  Fprinc (str, Vstandard_output);
-  write_string ("\nKilling some buffers may delay running out of memory.\n", -1);
-  write_string ("However, certainly by the time you receive the 95% warning,\n", -1);
-  write_string ("you should clean up, kill this Emacs, and start a new one.", -1);
-  return Qnil;
-}
-
-
-/* Function malloc calls this if it finds we are near exhausting
-   storage.  */
+/* Function malloc calls this if it finds we are near exhausting storage.  */
 
 void
 malloc_warning (str)
@@ -345,16 +441,16 @@ malloc_warning (str)
 }
 
 
-/* Display a malloc warning in buffer *Danger*.  */
+/* Display an already-pending malloc warning.  */
 
 void
 display_malloc_warning ()
 {
-  register Lisp_Object val;
-
-  val = build_string (pending_malloc_warning);
+  call3 (intern ("display-warning"),
+        intern ("alloc"),
+        build_string (pending_malloc_warning),
+        intern ("emergency"));
   pending_malloc_warning = 0;
-  internal_with_output_to_temp_buffer (" *Danger*", malloc_warning_1, val);
 }
 
 
@@ -370,6 +466,8 @@ display_malloc_warning ()
 void
 memory_full ()
 {
+  Vmemory_full = Qt;
+
 #ifndef SYSTEM_MALLOC
   bytes_used_when_full = BYTES_USED;
 #endif
@@ -384,7 +482,7 @@ memory_full ()
   /* This used to call error, but if we've run out of memory, we could
      get infinite recursion trying to build the string.  */
   while (1)
-    Fsignal (Qnil, memory_signal_data);
+    Fsignal (Qnil, Vmemory_signal_data);
 }
 
 
@@ -404,10 +502,12 @@ buffer_memory_full ()
   memory_full ();
 #endif
 
+  Vmemory_full = Qt;
+
   /* This used to call error, but if we've run out of memory, we could
      get infinite recursion trying to build the string.  */
   while (1)
-    Fsignal (Qerror, memory_signal_data);
+    Fsignal (Qnil, Vmemory_signal_data);
 }
 
 
@@ -468,7 +568,7 @@ xfree (block)
 
 char *
 xstrdup (s)
-     char *s;
+     const char *s;
 {
   size_t len = strlen (s) + 1;
   char *p = (char *) xmalloc (len);
@@ -489,13 +589,18 @@ lisp_malloc (nbytes, type)
   register void *val;
 
   BLOCK_INPUT;
+
+#ifdef GC_MALLOC_CHECK
+  allocated_mem_type = type;
+#endif
+  
   val = (void *) malloc (nbytes);
 
-#if GC_MARK_STACK
+#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
   if (val && type != MEM_TYPE_NON_LISP)
     mem_insert (val, (char *) val + nbytes, type);
 #endif
-  
+   
   UNBLOCK_INPUT;
   if (!val && nbytes)
     memory_full ();
@@ -509,8 +614,11 @@ lisp_malloc (nbytes, type)
 struct buffer *
 allocate_buffer ()
 {
-  return (struct buffer *) lisp_malloc (sizeof (struct buffer),
-                                       MEM_TYPE_BUFFER);
+  struct buffer *b 
+    = (struct buffer *) lisp_malloc (sizeof (struct buffer),
+                                    MEM_TYPE_BUFFER);
+  VALIDATE_LISP_STORAGE (b, sizeof *b);
+  return b;
 }
 
 
@@ -523,7 +631,7 @@ lisp_free (block)
 {
   BLOCK_INPUT;
   free (block);
-#if GC_MARK_STACK
+#if GC_MARK_STACK && !defined GC_MALLOC_CHECK
   mem_delete (mem_find (block));
 #endif
   UNBLOCK_INPUT;
@@ -558,8 +666,30 @@ emacs_blocked_free (ptr)
      void *ptr;
 {
   BLOCK_INPUT;
+
+#ifdef GC_MALLOC_CHECK
+  if (ptr)
+    {
+      struct mem_node *m;
+  
+      m = mem_find (ptr);
+      if (m == MEM_NIL || m->start != ptr)
+       {
+         fprintf (stderr,
+                  "Freeing `%p' which wasn't allocated with malloc\n", ptr);
+         abort ();
+       }
+      else
+       {
+         /* fprintf (stderr, "free %p...%p (%p)\n", m->start, m->end, ptr); */
+         mem_delete (m);
+       }
+    }
+#endif /* GC_MALLOC_CHECK */
+  
   __free_hook = old_free_hook;
   free (ptr);
+  
   /* If we released our reserve (due to running out of memory),
      and we have a fair amount free once again,
      try to set aside another reserve in case we run out once more.  */
@@ -606,10 +736,34 @@ emacs_blocked_malloc (size)
 #else
     __malloc_extra_blocks = malloc_hysteresis;
 #endif
+
   value = (void *) malloc (size);
+
+#ifdef GC_MALLOC_CHECK
+  {
+    struct mem_node *m = mem_find (value);
+    if (m != MEM_NIL)
+      {
+       fprintf (stderr, "Malloc returned %p which is already in use\n",
+                value);
+       fprintf (stderr, "Region in use is %p...%p, %u bytes, type %d\n",
+                m->start, m->end, (char *) m->end - (char *) m->start,
+                m->type);
+       abort ();
+      }
+
+    if (!dont_register_blocks)
+      {
+       mem_insert (value, (char *) value + max (1, size), allocated_mem_type);
+       allocated_mem_type = MEM_TYPE_NON_LISP;
+      }
+  }
+#endif /* GC_MALLOC_CHECK */
+  
   __malloc_hook = emacs_blocked_malloc;
   UNBLOCK_INPUT;
 
+  /* fprintf (stderr, "%p malloc\n", value); */
   return value;
 }
 
@@ -625,7 +779,48 @@ emacs_blocked_realloc (ptr, size)
 
   BLOCK_INPUT;
   __realloc_hook = old_realloc_hook;
+
+#ifdef GC_MALLOC_CHECK
+  if (ptr)
+    {
+      struct mem_node *m = mem_find (ptr);
+      if (m == MEM_NIL || m->start != ptr)
+       {
+         fprintf (stderr,
+                  "Realloc of %p which wasn't allocated with malloc\n",
+                  ptr);
+         abort ();
+       }
+
+      mem_delete (m);
+    }
+  
+  /* fprintf (stderr, "%p -> realloc\n", ptr); */
+  
+  /* Prevent malloc from registering blocks.  */
+  dont_register_blocks = 1;
+#endif /* GC_MALLOC_CHECK */
+
   value = (void *) realloc (ptr, size);
+
+#ifdef GC_MALLOC_CHECK
+  dont_register_blocks = 0;
+
+  {
+    struct mem_node *m = mem_find (value);
+    if (m != MEM_NIL)
+      {
+       fprintf (stderr, "Realloc returns memory that is already in use\n");
+       abort ();
+      }
+
+    /* Can't handle zero size regions in the red-black tree.  */
+    mem_insert (value, (char *) value + max (size, 1), MEM_TYPE_NON_LISP);
+  }
+  
+  /* fprintf (stderr, "%p <- realloc\n", value); */
+#endif /* GC_MALLOC_CHECK */
+  
   __realloc_hook = emacs_blocked_realloc;
   UNBLOCK_INPUT;
 
@@ -778,7 +973,7 @@ mark_interval_tree (tree)
      a cast.  */
   XMARK (tree->up.obj);
 
-  traverse_intervals (tree, 1, 0, mark_interval, Qnil);
+  traverse_intervals_noorder (tree, mark_interval, Qnil);
 }
 
 
@@ -826,7 +1021,7 @@ make_number (n)
 
 /* Lisp_Strings are allocated in string_block structures.  When a new
    string_block is allocated, all the Lisp_Strings it contains are
-   added to a free-list stiing_free_list.  When a new Lisp_String is
+   added to a free-list string_free_list.  When a new Lisp_String is
    needed, it is taken from that list.  During the sweep phase of GC,
    string_blocks that are entirely free are freed, except two which
    we keep.
@@ -870,6 +1065,16 @@ struct sdata
      contents.  */
   struct Lisp_String *string;
 
+#ifdef GC_CHECK_STRING_BYTES
+  
+  EMACS_INT nbytes;
+  unsigned char data[1];
+  
+#define SDATA_NBYTES(S)        (S)->nbytes
+#define SDATA_DATA(S)  (S)->data
+  
+#else /* not GC_CHECK_STRING_BYTES */
+
   union
   {
     /* When STRING in non-null.  */
@@ -878,8 +1083,15 @@ struct sdata
     /* When STRING is null.  */
     EMACS_INT nbytes;
   } u;
+  
+
+#define SDATA_NBYTES(S)        (S)->u.nbytes
+#define SDATA_DATA(S)  (S)->u.data
+
+#endif /* not GC_CHECK_STRING_BYTES */
 };
 
+
 /* Structure describing a block of memory which is sub-allocated to
    obtain string data memory for strings.  Blocks for small strings
    are of fixed size SBLOCK_SIZE.  Blocks for large strings are made
@@ -951,19 +1163,41 @@ static int total_string_size;
    a pointer to the `u.data' member of its sdata structure; the
    structure starts at a constant offset in front of that.  */
    
+#ifdef GC_CHECK_STRING_BYTES
+
+#define SDATA_OF_STRING(S) \
+     ((struct sdata *) ((S)->data - sizeof (struct Lisp_String *) \
+                       - sizeof (EMACS_INT)))
+
+#else /* not GC_CHECK_STRING_BYTES */
+
 #define SDATA_OF_STRING(S) \
      ((struct sdata *) ((S)->data - sizeof (struct Lisp_String *)))
 
+#endif /* not GC_CHECK_STRING_BYTES */
+
 /* Value is the size of an sdata structure large enough to hold NBYTES
    bytes of string data.  The value returned includes a terminating
    NUL byte, the size of the sdata structure, and padding.  */
 
+#ifdef GC_CHECK_STRING_BYTES
+
 #define SDATA_SIZE(NBYTES)                     \
      ((sizeof (struct Lisp_String *)           \
        + (NBYTES) + 1                          \
+       + sizeof (EMACS_INT)                    \
        + sizeof (EMACS_INT) - 1)               \
       & ~(sizeof (EMACS_INT) - 1))
 
+#else /* not GC_CHECK_STRING_BYTES */
+
+#define SDATA_SIZE(NBYTES)                     \
+     ((sizeof (struct Lisp_String *)           \
+       + (NBYTES) + 1                          \
+       + sizeof (EMACS_INT) - 1)               \
+      & ~(sizeof (EMACS_INT) - 1))
+
+#endif /* not GC_CHECK_STRING_BYTES */
 
 /* Initialize string allocation.  Called from init_alloc_once.  */
 
@@ -978,6 +1212,91 @@ init_strings ()
 }
 
 
+#ifdef GC_CHECK_STRING_BYTES
+
+static int check_string_bytes_count;
+
+void check_string_bytes P_ ((int));
+void check_sblock P_ ((struct sblock *));
+
+#define CHECK_STRING_BYTES(S)  STRING_BYTES (S)
+
+
+/* Like GC_STRING_BYTES, but with debugging check.  */
+
+int
+string_bytes (s)
+     struct Lisp_String *s;
+{
+  int nbytes = (s->size_byte < 0 ? s->size : s->size_byte) & ~MARKBIT;
+  if (!PURE_POINTER_P (s)
+      && s->data
+      && nbytes != SDATA_NBYTES (SDATA_OF_STRING (s)))
+    abort ();
+  return nbytes;
+}
+    
+/* Check validity Lisp strings' string_bytes member in B.  */
+
+void
+check_sblock (b)
+     struct sblock *b;
+{
+  struct sdata *from, *end, *from_end;
+      
+  end = b->next_free;
+      
+  for (from = &b->first_data; from < end; from = from_end)
+    {
+      /* Compute the next FROM here because copying below may
+        overwrite data we need to compute it.  */
+      int nbytes;
+      
+      /* Check that the string size recorded in the string is the
+        same as the one recorded in the sdata structure. */
+      if (from->string)
+       CHECK_STRING_BYTES (from->string);
+      
+      if (from->string)
+       nbytes = GC_STRING_BYTES (from->string);
+      else
+       nbytes = SDATA_NBYTES (from);
+      
+      nbytes = SDATA_SIZE (nbytes);
+      from_end = (struct sdata *) ((char *) from + nbytes);
+    }
+}
+
+
+/* Check validity of Lisp strings' string_bytes member.  ALL_P
+   non-zero means check all strings, otherwise check only most
+   recently allocated strings.  Used for hunting a bug.  */
+
+void
+check_string_bytes (all_p)
+     int all_p;
+{
+  if (all_p)
+    {
+      struct sblock *b;
+
+      for (b = large_sblocks; b; b = b->next)
+       {
+         struct Lisp_String *s = b->first_data.string;
+         if (s)
+           CHECK_STRING_BYTES (s);
+       }
+      
+      for (b = oldest_sblock; b; b = b->next)
+       check_sblock (b);
+    }
+  else
+    check_sblock (current_sblock);
+}
+
+#endif /* GC_CHECK_STRING_BYTES */
+
+
 /* Return a new Lisp_String.  */
 
 static struct Lisp_String *
@@ -1021,6 +1340,23 @@ allocate_string ()
   ++strings_consed;
   consing_since_gc += sizeof *s;
 
+#ifdef GC_CHECK_STRING_BYTES
+  if (!noninteractive
+#ifdef MAC_OS8
+      && current_sblock
+#endif
+     )
+    {
+      if (++check_string_bytes_count == 200)
+       {
+         check_string_bytes_count = 0;
+         check_string_bytes (1);
+       }
+      else
+       check_string_bytes (0);
+    }
+#endif /* GC_CHECK_STRING_BYTES */
+
   return s;
 }
 
@@ -1092,7 +1428,10 @@ allocate_string_data (s, nchars, nbytes)
   
   data = b->next_free;
   data->string = s;
-  s->data = data->u.data;
+  s->data = SDATA_DATA (data);
+#ifdef GC_CHECK_STRING_BYTES
+  SDATA_NBYTES (data) = nbytes;
+#endif
   s->size = nchars;
   s->size_byte = nbytes;
   s->data[nbytes] = '\0';
@@ -1103,7 +1442,7 @@ allocate_string_data (s, nchars, nbytes)
      in it.  */
   if (old_data)
     {
-      old_data->u.nbytes = old_nbytes;
+      SDATA_NBYTES (old_data) = old_nbytes;
       old_data->string = NULL;
     }
 
@@ -1157,7 +1496,12 @@ sweep_strings ()
                  /* Save the size of S in its sdata so that we know
                     how large that is.  Reset the sdata's string
                     back-pointer so that we know it's free.  */
+#ifdef GC_CHECK_STRING_BYTES
+                 if (GC_STRING_BYTES (s) != SDATA_NBYTES (data))
+                   abort ();
+#else
                  data->u.nbytes = GC_STRING_BYTES (s);
+#endif
                  data->string = NULL;
 
                  /* Reset the strings's `data' member so that we
@@ -1257,10 +1601,18 @@ compact_small_strings ()
             overwrite data we need to compute it.  */
          int nbytes;
 
+#ifdef GC_CHECK_STRING_BYTES
+         /* Check that the string size recorded in the string is the
+            same as the one recorded in the sdata structure. */
+         if (from->string
+             && GC_STRING_BYTES (from->string) != SDATA_NBYTES (from))
+           abort ();
+#endif /* GC_CHECK_STRING_BYTES */
+         
          if (from->string)
            nbytes = GC_STRING_BYTES (from->string);
          else
-           nbytes = from->u.nbytes;
+           nbytes = SDATA_NBYTES (from);
          
          nbytes = SDATA_SIZE (nbytes);
          from_end = (struct sdata *) ((char *) from + nbytes);
@@ -1284,7 +1636,7 @@ compact_small_strings ()
                {
                  xassert (tb != b || to <= from);
                  safe_bcopy ((char *) from, (char *) to, nbytes);
-                 to->string->data = to->u.data;
+                 to->string->data = SDATA_DATA (to);
                }
 
              /* Advance past the sdata we copied to.  */
@@ -1308,36 +1660,36 @@ compact_small_strings ()
 
 
 DEFUN ("make-string", Fmake_string, Smake_string, 2, 2, 0,
-  "Return a newly created string of length LENGTH, with each element being INIT.\n\
-Both LENGTH and INIT must be numbers.")
-  (length, init)
+       doc: /* Return a newly created string of length LENGTH, with each element being INIT.
+Both LENGTH and INIT must be numbers.  */)
+     (length, init)
      Lisp_Object length, init;
 {
   register Lisp_Object val;
   register unsigned char *p, *end;
   int c, nbytes;
 
-  CHECK_NATNUM (length, 0);
-  CHECK_NUMBER (init, 1);
+  CHECK_NATNUM (length);
+  CHECK_NUMBER (init);
 
   c = XINT (init);
   if (SINGLE_BYTE_CHAR_P (c))
     {
       nbytes = XINT (length);
       val = make_uninit_string (nbytes);
-      p = XSTRING (val)->data;
-      end = p + XSTRING (val)->size;
+      p = SDATA (val);
+      end = p + SCHARS (val);
       while (p != end)
        *p++ = c;
     }
   else
     {
-      unsigned char str[4];
+      unsigned char str[MAX_MULTIBYTE_LENGTH];
       int len = CHAR_STRING (c, str);
 
       nbytes = len * XINT (length);
       val = make_uninit_multibyte_string (XINT (length), nbytes);
-      p = XSTRING (val)->data;
+      p = SDATA (val);
       end = p + nbytes;
       while (p != end)
        {
@@ -1352,9 +1704,9 @@ Both LENGTH and INIT must be numbers.")
 
 
 DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
-  "Return a new bool-vector of length LENGTH, using INIT for as each element.\n\
-LENGTH must be a number.  INIT matters only in whether it is t or nil.")
-  (length, init)
+       doc: /* Return a new bool-vector of length LENGTH, using INIT for as each element.
+LENGTH must be a number.  INIT matters only in whether it is t or nil.  */)
+     (length, init)
      Lisp_Object length, init;
 {
   register Lisp_Object val;
@@ -1362,7 +1714,7 @@ LENGTH must be a number.  INIT matters only in whether it is t or nil.")
   int real_init, i;
   int length_in_chars, length_in_elts, bits_per_value;
 
-  CHECK_NATNUM (length, 0);
+  CHECK_NATNUM (length);
 
   bits_per_value = sizeof (EMACS_INT) * BITS_PER_CHAR;
 
@@ -1398,19 +1750,19 @@ LENGTH must be a number.  INIT matters only in whether it is t or nil.")
 
 Lisp_Object
 make_string (contents, nbytes)
-     char *contents;
+     const char *contents;
      int nbytes;
 {
   register Lisp_Object val;
   int nchars, multibyte_nbytes;
 
   parse_str_as_multibyte (contents, nbytes, &nchars, &multibyte_nbytes);
-  val = make_uninit_multibyte_string (nchars, nbytes);
-  bcopy (contents, XSTRING (val)->data, nbytes);
   if (nbytes == nchars || nbytes != multibyte_nbytes)
     /* CONTENTS contains no multibyte sequences or contains an invalid
        multibyte sequence.  We must make unibyte string.  */
-    SET_STRING_BYTES (XSTRING (val), -1);
+    val = make_unibyte_string (contents, nbytes);
+  else
+    val = make_multibyte_string (contents, nchars, nbytes);
   return val;
 }
 
@@ -1419,13 +1771,13 @@ make_string (contents, nbytes)
 
 Lisp_Object
 make_unibyte_string (contents, length)
-     char *contents;
+     const char *contents;
      int length;
 {
   register Lisp_Object val;
   val = make_uninit_string (length);
-  bcopy (contents, XSTRING (val)->data, length);
-  SET_STRING_BYTES (XSTRING (val), -1);
+  bcopy (contents, SDATA (val), length);
+  STRING_SET_UNIBYTE (val);
   return val;
 }
 
@@ -1435,12 +1787,12 @@ make_unibyte_string (contents, length)
 
 Lisp_Object
 make_multibyte_string (contents, nchars, nbytes)
-     char *contents;
+     const char *contents;
      int nchars, nbytes;
 {
   register Lisp_Object val;
   val = make_uninit_multibyte_string (nchars, nbytes);
-  bcopy (contents, XSTRING (val)->data, nbytes);
+  bcopy (contents, SDATA (val), nbytes);
   return val;
 }
 
@@ -1455,9 +1807,9 @@ make_string_from_bytes (contents, nchars, nbytes)
 {
   register Lisp_Object val;
   val = make_uninit_multibyte_string (nchars, nbytes);
-  bcopy (contents, XSTRING (val)->data, nbytes);
-  if (STRING_BYTES (XSTRING (val)) == XSTRING (val)->size)
-    SET_STRING_BYTES (XSTRING (val), -1);
+  bcopy (contents, SDATA (val), nbytes);
+  if (SBYTES (val) == SCHARS (val))
+    STRING_SET_UNIBYTE (val);
   return val;
 }
 
@@ -1474,9 +1826,9 @@ make_specified_string (contents, nchars, nbytes, multibyte)
 {
   register Lisp_Object val;
   val = make_uninit_multibyte_string (nchars, nbytes);
-  bcopy (contents, XSTRING (val)->data, nbytes);
+  bcopy (contents, SDATA (val), nbytes);
   if (!multibyte)
-    SET_STRING_BYTES (XSTRING (val), -1);
+    STRING_SET_UNIBYTE (val);
   return val;
 }
 
@@ -1486,7 +1838,7 @@ make_specified_string (contents, nchars, nbytes, multibyte)
 
 Lisp_Object
 build_string (str)
-     char *str;
+     const char *str;
 {
   return make_string (str, strlen (str));
 }
@@ -1501,7 +1853,7 @@ make_uninit_string (length)
 {
   Lisp_Object val;
   val = make_uninit_multibyte_string (length, length);
-  SET_STRING_BYTES (XSTRING (val), -1);
+  STRING_SET_UNIBYTE (val);
   return val;
 }
 
@@ -1567,7 +1919,7 @@ int n_float_blocks;
 struct Lisp_Float *float_free_list;
 
 
-/* Initialze float allocation.  */
+/* Initialize float allocation.  */
 
 void
 init_float ()
@@ -1706,8 +2058,8 @@ free_cons (ptr)
 
 
 DEFUN ("cons", Fcons, Scons, 2, 2, 0,
-  "Create a new cons, give it CAR and CDR as components, and return it.")
-  (car, cdr)
+       doc: /* Create a new cons, give it CAR and CDR as components, and return it.  */)
+     (car, cdr)
      Lisp_Object car, cdr;
 {
   register Lisp_Object val;
@@ -1735,8 +2087,8 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
       XSETCONS (val, &cons_block->conses[cons_block_index++]);
     }
   
-  XCAR (val) = car;
-  XCDR (val) = cdr;
+  XSETCAR (val, car);
+  XSETCDR (val, cdr);
   consing_since_gc += sizeof (struct Lisp_Cons);
   cons_cells_consed++;
   return val;
@@ -1779,9 +2131,10 @@ list5 (arg1, arg2, arg3, arg4, arg5)
 
 
 DEFUN ("list", Flist, Slist, 0, MANY, 0,
-  "Return a newly created list with specified arguments as elements.\n\
-Any number of arguments, even zero arguments, are allowed.")
-  (nargs, args)
+       doc: /* Return a newly created list with specified arguments as elements.
+Any number of arguments, even zero arguments, are allowed.
+usage: (list &rest OBJECTS)  */)
+     (nargs, args)
      int nargs;
      register Lisp_Object *args;
 {
@@ -1798,19 +2151,49 @@ Any number of arguments, even zero arguments, are allowed.")
 
 
 DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
-  "Return a newly created list of length LENGTH, with each element being INIT.")
-  (length, init)
+       doc: /* Return a newly created list of length LENGTH, with each element being INIT.  */)
+     (length, init)
      register Lisp_Object length, init;
 {
   register Lisp_Object val;
   register int size;
 
-  CHECK_NATNUM (length, 0);
+  CHECK_NATNUM (length);
   size = XFASTINT (length);
 
   val = Qnil;
-  while (size-- > 0)
-    val = Fcons (init, val);
+  while (size > 0)
+    {
+      val = Fcons (init, val);
+      --size;
+
+      if (size > 0)
+       {
+         val = Fcons (init, val);
+         --size;
+      
+         if (size > 0)
+           {
+             val = Fcons (init, val);
+             --size;
+      
+             if (size > 0)
+               {
+                 val = Fcons (init, val);
+                 --size;
+      
+                 if (size > 0)
+                   {
+                     val = Fcons (init, val);
+                     --size;
+                   }
+               }
+           }
+       }
+
+      QUIT;
+    }
+  
   return val;
 }
 
@@ -1832,9 +2215,10 @@ int n_vectors;
 /* Value is a pointer to a newly allocated Lisp_Vector structure
    with room for LEN Lisp_Objects.  */
 
-struct Lisp_Vector *
-allocate_vectorlike (len)
+static struct Lisp_Vector *
+allocate_vectorlike (len, type)
      EMACS_INT len;
+     enum mem_type type;
 {
   struct Lisp_Vector *p;
   size_t nbytes;
@@ -1847,7 +2231,7 @@ allocate_vectorlike (len)
 #endif
   
   nbytes = sizeof *p + (len - 1) * sizeof p->contents[0];
-  p = (struct Lisp_Vector *) lisp_malloc (nbytes, MEM_TYPE_VECTOR);
+  p = (struct Lisp_Vector *) lisp_malloc (nbytes, type);
   
 #ifdef DOUG_LEA_MALLOC
   /* Back to a reasonable maximum of mmap'ed areas.  */
@@ -1865,10 +2249,98 @@ allocate_vectorlike (len)
 }
 
 
+/* Allocate a vector with NSLOTS slots.  */
+
+struct Lisp_Vector *
+allocate_vector (nslots)
+     EMACS_INT nslots;
+{
+  struct Lisp_Vector *v = allocate_vectorlike (nslots, MEM_TYPE_VECTOR);
+  v->size = nslots;
+  return v;
+}
+
+
+/* Allocate other vector-like structures.  */
+
+struct Lisp_Hash_Table *
+allocate_hash_table ()
+{
+  EMACS_INT len = VECSIZE (struct Lisp_Hash_Table);
+  struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_HASH_TABLE);
+  EMACS_INT i;
+  
+  v->size = len;
+  for (i = 0; i < len; ++i)
+    v->contents[i] = Qnil;
+  
+  return (struct Lisp_Hash_Table *) v;
+}
+
+
+struct window *
+allocate_window ()
+{
+  EMACS_INT len = VECSIZE (struct window);
+  struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_WINDOW);
+  EMACS_INT i;
+  
+  for (i = 0; i < len; ++i)
+    v->contents[i] = Qnil;
+  v->size = len;
+  
+  return (struct window *) v;
+}
+
+
+struct frame *
+allocate_frame ()
+{
+  EMACS_INT len = VECSIZE (struct frame);
+  struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_FRAME);
+  EMACS_INT i;
+  
+  for (i = 0; i < len; ++i)
+    v->contents[i] = make_number (0);
+  v->size = len;
+  return (struct frame *) v;
+}
+
+
+struct Lisp_Process *
+allocate_process ()
+{
+  EMACS_INT len = VECSIZE (struct Lisp_Process);
+  struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_PROCESS);
+  EMACS_INT i;
+  
+  for (i = 0; i < len; ++i)
+    v->contents[i] = Qnil;
+  v->size = len;
+  
+  return (struct Lisp_Process *) v;
+}
+
+
+struct Lisp_Vector *
+allocate_other_vector (len)
+     EMACS_INT len;
+{
+  struct Lisp_Vector *v = allocate_vectorlike (len, MEM_TYPE_VECTOR);
+  EMACS_INT i;
+  
+  for (i = 0; i < len; ++i)
+    v->contents[i] = Qnil;
+  v->size = len;
+  
+  return v;
+}
+
+
 DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0,
-  "Return a newly created vector of length LENGTH, with each element being INIT.\n\
-See also the function `vector'.")
-  (length, init)
+       doc: /* Return a newly created vector of length LENGTH, with each element being INIT.
+See also the function `vector'.  */)
+     (length, init)
      register Lisp_Object length, init;
 {
   Lisp_Object vector;
@@ -1876,11 +2348,10 @@ See also the function `vector'.")
   register int index;
   register struct Lisp_Vector *p;
 
-  CHECK_NATNUM (length, 0);
+  CHECK_NATNUM (length);
   sizei = XFASTINT (length);
 
-  p = allocate_vectorlike (sizei);
-  p->size = sizei;
+  p = allocate_vector (sizei);
   for (index = 0; index < sizei; index++)
     p->contents[index] = init;
 
@@ -1890,18 +2361,18 @@ See also the function `vector'.")
 
 
 DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0,
-  "Return a newly created char-table, with purpose PURPOSE.\n\
-Each element is initialized to INIT, which defaults to nil.\n\
-PURPOSE should be a symbol which has a `char-table-extra-slots' property.\n\
-The property's value should be an integer between 0 and 10.")
-  (purpose, init)
+       doc: /* Return a newly created char-table, with purpose PURPOSE.
+Each element is initialized to INIT, which defaults to nil.
+PURPOSE should be a symbol which has a `char-table-extra-slots' property.
+The property's value should be an integer between 0 and 10.  */)
+     (purpose, init)
      register Lisp_Object purpose, init;
 {
   Lisp_Object vector;
   Lisp_Object n;
-  CHECK_SYMBOL (purpose, 1);
+  CHECK_SYMBOL (purpose);
   n = Fget (purpose, Qchar_table_extra_slots);
-  CHECK_NUMBER (n, 0);
+  CHECK_NUMBER (n);
   if (XINT (n) < 0 || XINT (n) > 10)
     args_out_of_range (n, Qnil);
   /* Add 2 to the size for the defalt and parent slots.  */
@@ -1933,9 +2404,10 @@ make_sub_char_table (defalt)
 
 
 DEFUN ("vector", Fvector, Svector, 0, MANY, 0,
-  "Return a newly created vector with specified arguments as elements.\n\
-Any number of arguments, even zero arguments, are allowed.")
-  (nargs, args)
+       doc: /* Return a newly created vector with specified arguments as elements.
+Any number of arguments, even zero arguments, are allowed.
+usage: (vector &rest OBJECTS)  */)
+     (nargs, args)
      register int nargs;
      Lisp_Object *args;
 {
@@ -1953,12 +2425,13 @@ Any number of arguments, even zero arguments, are allowed.")
 
 
 DEFUN ("make-byte-code", Fmake_byte_code, Smake_byte_code, 4, MANY, 0,
-  "Create a byte-code object with specified arguments as elements.\n\
-The arguments should be the arglist, bytecode-string, constant vector,\n\
-stack size, (optional) doc string, and (optional) interactive spec.\n\
-The first four arguments are required; at most six have any\n\
-significance.")
-  (nargs, args)
+       doc: /* Create a byte-code object with specified arguments as elements.
+The arguments should be the arglist, bytecode-string, constant vector,
+stack size, (optional) doc string, and (optional) interactive spec.
+The first four arguments are required; at most six have any
+significance.
+usage: (make-byte-code &rest ELEMENTS)  */)
+     (nargs, args)
      register int nargs;
      Lisp_Object *args;
 {
@@ -2041,15 +2514,15 @@ init_symbol ()
 
 
 DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
-  "Return a newly allocated uninterned symbol whose name is NAME.\n\
-Its value and function definition are void, and its property list is nil.")
-  (name)
+       doc: /* Return a newly allocated uninterned symbol whose name is NAME.
+Its value and function definition are void, and its property list is nil.  */)
+     (name)
      Lisp_Object name;
 {
   register Lisp_Object val;
   register struct Lisp_Symbol *p;
 
-  CHECK_STRING (name, 0);
+  CHECK_STRING (name);
 
   if (symbol_free_list)
     {
@@ -2073,12 +2546,14 @@ Its value and function definition are void, and its property list is nil.")
     }
   
   p = XSYMBOL (val);
-  p->name = XSTRING (name);
-  p->obarray = Qnil;
+  p->xname = name;
   p->plist = Qnil;
   p->value = Qunbound;
   p->function = Qunbound;
-  p->next = 0;
+  p->next = NULL;
+  p->interned = SYMBOL_UNINTERNED;
+  p->constant = 0;
+  p->indirect_variable = 0;
   consing_since_gc += sizeof (struct Lisp_Symbol);
   symbols_consed++;
   return val;
@@ -2156,9 +2631,29 @@ allocate_misc ()
   return val;
 }
 
+/* Return a Lisp_Misc_Save_Value object containing POINTER and
+   INTEGER.  This is used to package C values to call record_unwind_protect.
+   The unwind function can get the C values back using XSAVE_VALUE.  */
+
+Lisp_Object
+make_save_value (pointer, integer)
+     void *pointer;
+     int integer;
+{
+  register Lisp_Object val;
+  register struct Lisp_Save_Value *p;
+
+  val = allocate_misc ();
+  XMISCTYPE (val) = Lisp_Misc_Save_Value;
+  p = XSAVE_VALUE (val);
+  p->pointer = pointer;
+  p->integer = integer;
+  return val;
+}
+
 DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
-  "Return a newly allocated marker which does not point at any place.")
-  ()
+       doc: /* Return a newly allocated marker which does not point at any place.  */)
+     ()
 {
   register Lisp_Object val;
   register struct Lisp_Marker *p;
@@ -2219,10 +2714,10 @@ make_event_array (nargs, args)
     result = Fmake_string (make_number (nargs), make_number (0));
     for (i = 0; i < nargs; i++)
       {
-       XSTRING (result)->data[i] = XINT (args[i]);
+       SSET (result, i, XINT (args[i]));
        /* Move the meta bit to the right place for a string char.  */
        if (XINT (args[i]) & CHAR_META)
-         XSTRING (result)->data[i] |= 0x80;
+         SSET (result, i, SREF (result, i) | 0x80);
       }
     
     return result;
@@ -2235,60 +2730,18 @@ make_event_array (nargs, args)
                           C Stack Marking
  ************************************************************************/
 
-#if GC_MARK_STACK
-
-
-/* Base address of stack.  Set in main.  */
-
-Lisp_Object *stack_base;
-
-/* A node in the red-black tree describing allocated memory containing
-   Lisp data.  Each such block is recorded with its start and end
-   address when it is allocated, and removed from the tree when it
-   is freed.
-
-   A red-black tree is a balanced binary tree with the following
-   properties:
-
-   1. Every node is either red or black.
-   2. Every leaf is black.
-   3. If a node is red, then both of its children are black.
-   4. Every simple path from a node to a descendant leaf contains
-   the same number of black nodes.
-   5. The root is always black.
-
-   When nodes are inserted into the tree, or deleted from the tree,
-   the tree is "fixed" so that these properties are always true.
-
-   A red-black tree with N internal nodes has height at most 2
-   log(N+1).  Searches, insertions and deletions are done in O(log N).
-   Please see a text book about data structures for a detailed
-   description of red-black trees.  Any book worth its salt should
-   describe them.  */
-
-struct mem_node
-{
-  struct mem_node *left, *right, *parent;
-
-  /* Start and end of allocated region.  */
-  void *start, *end;
-
-  /* Node color.  */
-  enum {MEM_BLACK, MEM_RED} color;
-  
-  /* Memory type.  */
-  enum mem_type type;
-};
-
-/* Root of the tree describing allocated Lisp memory.  */
-
-static struct mem_node *mem_root;
-
-/* Sentinel node of the tree.  */
-
-static struct mem_node mem_z;
-#define MEM_NIL &mem_z
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
 
+/* Conservative C stack marking requires a method to identify possibly
+   live Lisp objects given a pointer value.  We do this by keeping
+   track of blocks of Lisp data that are allocated in a red-black tree
+   (see also the comment of mem_node which is the type of nodes in
+   that tree).  Function lisp_malloc adds information for an allocated
+   block to the red-black tree with calls to mem_insert, and function
+   lisp_free removes it with mem_delete.  Functions live_string_p etc
+   call mem_find to lookup information about a given pointer in the
+   tree, and use that to determine if the pointer points to a Lisp
+   object or not.  */
 
 /* Initialize this part of alloc.c.  */
 
@@ -2312,6 +2765,9 @@ mem_find (start)
 {
   struct mem_node *p;
 
+  if (start < min_heap_address || start > max_heap_address)
+    return MEM_NIL;
+
   /* Make the search always successful to speed up the loop below.  */
   mem_z.start = start;
   mem_z.end = (char *) start + 1;
@@ -2334,6 +2790,11 @@ mem_insert (start, end, type)
 {
   struct mem_node *c, *parent, *x;
 
+  if (start < min_heap_address)
+    min_heap_address = start;
+  if (end > max_heap_address)
+    max_heap_address = end;
+
   /* See where in the tree a node for START belongs.  In this
      particular application, it shouldn't happen that a node is already
      present.  For debugging purposes, let's check that.  */
@@ -2361,7 +2822,13 @@ mem_insert (start, end, type)
 #endif /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */
 
   /* Create a new node.  */
+#ifdef GC_MALLOC_CHECK
+  x = (struct mem_node *) _malloc_internal (sizeof *x);
+  if (x == NULL)
+    abort ();
+#else
   x = (struct mem_node *) xmalloc (sizeof *x);
+#endif
   x->start = start;
   x->end = end;
   x->type = type;
@@ -2382,6 +2849,7 @@ mem_insert (start, end, type)
 
   /* Re-establish red-black tree properties.  */
   mem_insert_fixup (x);
+
   return x;
 }
 
@@ -2581,7 +3049,12 @@ mem_delete (z)
   
   if (y->color == MEM_BLACK)
     mem_delete_fixup (x);
+
+#ifdef GC_MALLOC_CHECK
+  _free_internal (y);
+#else
   xfree (y);
+#endif
 }
 
 
@@ -2682,7 +3155,8 @@ live_string_p (m, p)
 
       /* P must point to the start of a Lisp_String structure, and it
         must not be on the free-list.  */
-      return (offset % sizeof b->strings[0] == 0
+      return (offset >= 0
+             && offset % sizeof b->strings[0] == 0
              && ((struct Lisp_String *) p)->data != NULL);
     }
   else
@@ -2706,7 +3180,8 @@ live_cons_p (m, p)
       /* P must point to the start of a Lisp_Cons, not be
         one of the unused cells in the current cons block,
         and not be on the free-list.  */
-      return (offset % sizeof b->conses[0] == 0
+      return (offset >= 0
+             && offset % sizeof b->conses[0] == 0
              && (b != cons_block
                  || offset / sizeof b->conses[0] < cons_block_index)
              && !EQ (((struct Lisp_Cons *) p)->car, Vdead));
@@ -2732,7 +3207,8 @@ live_symbol_p (m, p)
       /* P must point to the start of a Lisp_Symbol, not be
         one of the unused cells in the current symbol block,
         and not be on the free-list.  */
-      return (offset % sizeof b->symbols[0] == 0
+      return (offset >= 0
+             && offset % sizeof b->symbols[0] == 0
              && (b != symbol_block
                  || offset / sizeof b->symbols[0] < symbol_block_index)
              && !EQ (((struct Lisp_Symbol *) p)->function, Vdead));
@@ -2758,7 +3234,8 @@ live_float_p (m, p)
       /* P must point to the start of a Lisp_Float, not be
         one of the unused cells in the current float block,
         and not be on the free-list.  */
-      return (offset % sizeof b->floats[0] == 0
+      return (offset >= 0
+             && offset % sizeof b->floats[0] == 0
              && (b != float_block
                  || offset / sizeof b->floats[0] < float_block_index)
              && !EQ (((struct Lisp_Float *) p)->type, Vdead));
@@ -2784,7 +3261,8 @@ live_misc_p (m, p)
       /* P must point to the start of a Lisp_Misc, not be
         one of the unused cells in the current misc block,
         and not be on the free-list.  */
-      return (offset % sizeof b->markers[0] == 0
+      return (offset >= 0
+             && offset % sizeof b->markers[0] == 0
              && (b != marker_block
                  || offset / sizeof b->markers[0] < marker_block_index)
              && ((union Lisp_Misc *) p)->u_marker.type != Lisp_Misc_Free);
@@ -2802,7 +3280,9 @@ live_vector_p (m, p)
      struct mem_node *m;
      void *p;
 {
-  return m->type == MEM_TYPE_VECTOR && p == m->start;
+  return (p == m->start
+         && m->type >= MEM_TYPE_VECTOR
+         && m->type <= MEM_TYPE_WINDOW);
 }
 
 
@@ -2821,6 +3301,9 @@ live_buffer_p (m, p)
          && !NILP (((struct buffer *) p)->name));
 }
 
+#endif /* GC_MARK_STACK || defined GC_MALLOC_CHECK */
+
+#if GC_MARK_STACK
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
 
@@ -2851,18 +3334,22 @@ static int max_live, max_zombies;
 static double avg_live;
 
 DEFUN ("gc-status", Fgc_status, Sgc_status, 0, 0, "",
-  "Show information about live and zombie objects.")
+       doc: /* Show information about live and zombie objects.  */)
      ()
 {
-  Lisp_Object args[7];
-  args[0] = build_string ("%d GCs, avg live/zombies = %.2f/%.2f (%f%%), max %d/%d");
+  Lisp_Object args[8], zombie_list = Qnil;
+  int i;
+  for (i = 0; i < nzombies; i++)
+    zombie_list = Fcons (zombies[i], zombie_list);
+  args[0] = build_string ("%d GCs, avg live/zombies = %.2f/%.2f (%f%%), max %d/%d\nzombies: %S");
   args[1] = make_number (ngcs);
   args[2] = make_float (avg_live);
   args[3] = make_float (avg_zombies);
   args[4] = make_float (avg_zombies / avg_live / 100);
   args[5] = make_number (max_live);
   args[6] = make_number (max_zombies);
-  return Fmessage (7, args);
+  args[7] = zombie_list;
+  return Fmessage (8, args);
 }
 
 #endif /* GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES */
@@ -2934,27 +3421,140 @@ mark_maybe_object (obj)
                }
            }
          break;
+
+       case Lisp_Int:
+       case Lisp_Type_Limit:
+         break;
        }
 
       if (mark_p)
        {
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
          if (nzombies < MAX_ZOMBIES)
-           zombies[nzombies] = *p;
+           zombies[nzombies] = obj;
          ++nzombies;
 #endif
          mark_object (&obj);
        }
     }
 }
+
+
+/* If P points to Lisp data, mark that as live if it isn't already
+   marked.  */
+
+static INLINE void
+mark_maybe_pointer (p)
+     void *p;
+{
+  struct mem_node *m;
+
+  /* Quickly rule out some values which can't point to Lisp data.  We
+     assume that Lisp data is aligned on even addresses.  */
+  if ((EMACS_INT) p & 1)
+    return;
+      
+  m = mem_find (p);
+  if (m != MEM_NIL)
+    {
+      Lisp_Object obj = Qnil;
+      
+      switch (m->type)
+       {
+       case MEM_TYPE_NON_LISP:
+         /* Nothing to do; not a pointer to Lisp memory.  */
+         break;
          
-/* Mark Lisp objects in the address range START..END.  */
+       case MEM_TYPE_BUFFER:
+         if (live_buffer_p (m, p)
+             && !XMARKBIT (((struct buffer *) p)->name))
+           XSETVECTOR (obj, p);
+         break;
+         
+       case MEM_TYPE_CONS:
+         if (live_cons_p (m, p)
+             && !XMARKBIT (((struct Lisp_Cons *) p)->car))
+           XSETCONS (obj, p);
+         break;
+         
+       case MEM_TYPE_STRING:
+         if (live_string_p (m, p)
+             && !STRING_MARKED_P ((struct Lisp_String *) p))
+           XSETSTRING (obj, p);
+         break;
+
+       case MEM_TYPE_MISC:
+         if (live_misc_p (m, p))
+           {
+             Lisp_Object tem;
+             XSETMISC (tem, p);
+             
+             switch (XMISCTYPE (tem))
+               {
+               case Lisp_Misc_Marker:
+                 if (!XMARKBIT (XMARKER (tem)->chain))
+                   obj = tem;
+                 break;
+                     
+               case Lisp_Misc_Buffer_Local_Value:
+               case Lisp_Misc_Some_Buffer_Local_Value:
+                 if (!XMARKBIT (XBUFFER_LOCAL_VALUE (tem)->realvalue))
+                   obj = tem;
+                 break;
+                     
+               case Lisp_Misc_Overlay:
+                 if (!XMARKBIT (XOVERLAY (tem)->plist))
+                   obj = tem;
+                 break;
+               }
+           }
+         break;
+         
+       case MEM_TYPE_SYMBOL:
+         if (live_symbol_p (m, p)
+             && !XMARKBIT (((struct Lisp_Symbol *) p)->plist))
+           XSETSYMBOL (obj, p);
+         break;
+         
+       case MEM_TYPE_FLOAT:
+         if (live_float_p (m, p)
+             && !XMARKBIT (((struct Lisp_Float *) p)->type))
+           XSETFLOAT (obj, p);
+         break;
+         
+       case MEM_TYPE_VECTOR:
+       case MEM_TYPE_PROCESS:
+       case MEM_TYPE_HASH_TABLE:
+       case MEM_TYPE_FRAME:
+       case MEM_TYPE_WINDOW:
+         if (live_vector_p (m, p))
+           {
+             Lisp_Object tem;
+             XSETVECTOR (tem, p);
+             if (!GC_SUBRP (tem)
+                 && !(XVECTOR (tem)->size & ARRAY_MARK_FLAG))
+               obj = tem;
+           }
+         break;
+
+       default:
+         abort ();
+       }
+
+      if (!GC_NILP (obj))
+       mark_object (&obj);
+    }
+}
+
+
+/* Mark Lisp objects referenced from the address range START..END.  */
 
 static void 
 mark_memory (start, end)
      void *start, *end;
 {
   Lisp_Object *p;
+  void **pp;
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
   nzombies = 0;
@@ -2968,11 +3568,37 @@ mark_memory (start, end)
       start = end;
       end = tem;
     }
-  
+
+  /* Mark Lisp_Objects.  */
   for (p = (Lisp_Object *) start; (void *) p < end; ++p)
     mark_maybe_object (*p);
+
+  /* Mark Lisp data pointed to.  This is necessary because, in some
+     situations, the C compiler optimizes Lisp objects away, so that
+     only a pointer to them remains.  Example:
+
+     DEFUN ("testme", Ftestme, Stestme, 0, 0, 0, "")
+     ()
+     {
+       Lisp_Object obj = build_string ("test");
+       struct Lisp_String *s = XSTRING (obj);
+       Fgarbage_collect ();
+       fprintf (stderr, "test `%s'\n", s->data);
+       return Qnil;
+     }
+
+     Here, `obj' isn't really used, and the compiler optimizes it
+     away.  The only reference to the life string is through the
+     pointer `s'.  */
+  
+  for (pp = (void **) start; (void *) pp < end; ++pp)
+    mark_maybe_pointer (*pp);
 }
 
+/* setjmp will work with GCC unless NON_SAVING_SETJMP is defined in
+   the GCC system configuration.  In gcc 3.2, the only systems for
+   which this is so are i386-sco5 non-ELF, i386-sysv3 (maybe included
+   by others?) and ns32k-pc532-min.  */
 
 #if !defined GC_SAVE_REGISTERS_ON_STACK && !defined GC_SETJMP_WORKS
 
@@ -2988,7 +3614,7 @@ If you are a system-programmer, or can get the help of a local wizard\n\
 who is, please take a look at the function mark_stack in alloc.c, and\n\
 verify that the methods used are appropriate for your system.\n\
 \n\
-Please mail the result to <gerd@gnu.org>.\n\
+Please mail the result to <emacs-devel@gnu.org>.\n\
 "
 
 #define SETJMP_WILL_NOT_WORK "\
@@ -3000,7 +3626,11 @@ solution for your system.\n\
 \n\
 Please take a look at the function mark_stack in alloc.c, and\n\
 try to find a way to make it work on your system.\n\
-Please mail the result to <gerd@gnu.org>.\n\
+\n\
+Note that you may get false negatives, depending on the compiler.\n\
+In particular, you need to use -O with GCC for this test.\n\
+\n\
+Please mail the result to <emacs-devel@gnu.org>.\n\
 "
 
 
@@ -3137,12 +3767,16 @@ dump_zombies ()
 static void
 mark_stack ()
 {
+  int i;
   jmp_buf j;
-  int stack_grows_down_p = (char *) &j > (char *) stack_base;
+  volatile int stack_grows_down_p = (char *) &j > (char *) stack_base;
   void *end;
 
   /* This trick flushes the register windows so that all the state of
      the process is contained in the stack.  */
+  /* Fixme: Code in the Boehm GC sugests flushing (with `flushrs') is
+     needed on ia64 too.  See mach_dep.c, where it also says inline
+     assembler doesn't work with relevant proprietary compilers.  */
 #ifdef sparc
   asm ("ta 3");
 #endif
@@ -3172,17 +3806,15 @@ mark_stack ()
   /* This assumes that the stack is a contiguous region in memory.  If
      that's not the case, something has to be done here to iterate
      over the stack segments.  */
-#if GC_LISP_OBJECT_ALIGNMENT == 1
-  mark_memory (stack_base, end);
-  mark_memory ((char *) stack_base + 1, end);
-  mark_memory ((char *) stack_base + 2, end);
-  mark_memory ((char *) stack_base + 3, end);
-#elif GC_LISP_OBJECT_ALIGNMENT == 2
-  mark_memory (stack_base, end);
-  mark_memory ((char *) stack_base + 2, end);
+#ifndef GC_LISP_OBJECT_ALIGNMENT
+#ifdef __GNUC__
+#define GC_LISP_OBJECT_ALIGNMENT __alignof__ (Lisp_Object)
 #else
-  mark_memory (stack_base, end);
+#define GC_LISP_OBJECT_ALIGNMENT sizeof (Lisp_Object)
 #endif
+#endif
+  for (i = 0; i < sizeof (Lisp_Object); i += GC_LISP_OBJECT_ALIGNMENT)
+    mark_memory ((char *) stack_base + i, end);
 
 #if GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS
   check_gcpros ();
@@ -3198,6 +3830,60 @@ mark_stack ()
                       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.
+
+   If store_pure_type_info is set and TYPE is >= 0, the type of
+   the allocated object is recorded in pure_types.  */
+
+static POINTER_TYPE *
+pure_alloc (size, type)
+     size_t size;
+     int type;
+{
+  POINTER_TYPE *result;
+  size_t alignment = sizeof (EMACS_INT);
+
+  /* Give Lisp_Floats an extra alignment.  */
+  if (type == Lisp_Float)
+    {
+#if defined __GNUC__ && __GNUC__ >= 2
+      alignment = __alignof (struct Lisp_Float);
+#else
+      alignment = sizeof (struct Lisp_Float);
+#endif
+    }
+
+ again:
+  result = (POINTER_TYPE *) ALIGN ((EMACS_UINT)purebeg + pure_bytes_used, alignment);
+  pure_bytes_used = ((char *)result - (char *)purebeg) + size;
+
+  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.  */
+  purebeg = (char *) xmalloc (10000);
+  pure_size = 10000;
+  pure_bytes_used_before_overflow += pure_bytes_used - size;
+  pure_bytes_used = 0;
+  goto again;
+}
+
+
+/* Print a warning if PURESIZE is too small.  */
+
+void
+check_pure_size ()
+{
+  if (pure_bytes_used_before_overflow)
+    message ("Pure Lisp storage overflow (approx. %d bytes needed)",
+            (int) (pure_bytes_used + pure_bytes_used_before_overflow));
+}
+
+
 /* Return a string allocated in pure space.  DATA is a buffer holding
    NCHARS characters, and NBYTES bytes of string data.  MULTIBYTE
    non-zero means make the result string multibyte.
@@ -3214,29 +3900,14 @@ make_pure_string (data, nchars, nbytes, multibyte)
 {
   Lisp_Object string;
   struct Lisp_String *s;
-  int string_size, data_size;
 
-#define PAD(SZ) (((SZ) + sizeof (EMACS_INT) - 1) & ~(sizeof (EMACS_INT) - 1))
-
-  string_size = PAD (sizeof (struct Lisp_String));
-  data_size = PAD (nbytes + 1);
-
-#undef PAD
-  
-  if (pureptr + string_size + data_size > PURESIZE)
-    error ("Pure Lisp storage exhausted");
-
-  s = (struct Lisp_String *) (PUREBEG + pureptr);
-  pureptr += string_size;
-  s->data = (unsigned char *) (PUREBEG + pureptr);
-  pureptr += data_size;
-  
+  s = (struct Lisp_String *) pure_alloc (sizeof *s, Lisp_String);
+  s->data = (unsigned char *) pure_alloc (nbytes + 1, -1);
   s->size = nchars;
   s->size_byte = multibyte ? nbytes : -1;
   bcopy (data, s->data, nbytes);
   s->data[nbytes] = '\0';
   s->intervals = NULL_INTERVAL;
-  
   XSETSTRING (string, s);
   return string;
 }
@@ -3250,13 +3921,12 @@ pure_cons (car, cdr)
      Lisp_Object car, cdr;
 {
   register Lisp_Object new;
+  struct Lisp_Cons *p;
 
-  if (pureptr + sizeof (struct Lisp_Cons) > PURESIZE)
-    error ("Pure Lisp storage exhausted");
-  XSETCONS (new, PUREBEG + pureptr);
-  pureptr += sizeof (struct Lisp_Cons);
-  XCAR (new) = Fpurecopy (car);
-  XCDR (new) = Fpurecopy (cdr);
+  p = (struct Lisp_Cons *) pure_alloc (sizeof *p, Lisp_Cons);
+  XSETCONS (new, p);
+  XSETCAR (new, Fpurecopy (car));
+  XSETCDR (new, Fpurecopy (cdr));
   return new;
 }
 
@@ -3268,34 +3938,11 @@ make_pure_float (num)
      double num;
 {
   register Lisp_Object new;
+  struct Lisp_Float *p;
 
-  /* Make sure that PUREBEG + pureptr is aligned on at least a sizeof
-     (double) boundary.  Some architectures (like the sparc) require
-     this, and I suspect that floats are rare enough that it's no
-     tragedy for those that do.  */
-  {
-    size_t alignment;
-    char *p = PUREBEG + pureptr;
-
-#ifdef __GNUC__
-#if __GNUC__ >= 2
-    alignment = __alignof (struct Lisp_Float);
-#else
-    alignment = sizeof (struct Lisp_Float);
-#endif
-#else
-    alignment = sizeof (struct Lisp_Float);
-#endif  
-    p = (char *) (((unsigned long) p + alignment - 1) & - alignment);
-    pureptr = p - PUREBEG;
-  }
-
-  if (pureptr + sizeof (struct Lisp_Float) > PURESIZE)
-    error ("Pure Lisp storage exhausted");
-  XSETFLOAT (new, PUREBEG + pureptr);
-  pureptr += sizeof (struct Lisp_Float);
+  p = (struct Lisp_Float *) pure_alloc (sizeof *p, Lisp_Float);
+  XSETFLOAT (new, p);
   XFLOAT_DATA (new) = num;
-  XSETFASTINT (XFLOAT (new)->type, 0); /* bug chasing -wsr */
   return new;
 }
 
@@ -3307,32 +3954,28 @@ Lisp_Object
 make_pure_vector (len)
      EMACS_INT len;
 {
-  register Lisp_Object new;
-  register EMACS_INT size = (sizeof (struct Lisp_Vector)
-                            + (len - 1) * sizeof (Lisp_Object));
-
-  if (pureptr + size > PURESIZE)
-    error ("Pure Lisp storage exhausted");
+  Lisp_Object new;
+  struct Lisp_Vector *p;
+  size_t size = sizeof *p + (len - 1) * sizeof (Lisp_Object);
 
-  XSETVECTOR (new, PUREBEG + pureptr);
-  pureptr += size;
+  p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike);
+  XSETVECTOR (new, p);
   XVECTOR (new)->size = len;
   return new;
 }
 
 
 DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
-  "Make a copy of OBJECT in pure storage.\n\
-Recursively copies contents of vectors and cons cells.\n\
-Does not copy symbols.  Copies strings without text properties.")
-  (obj)
+       doc: /* Make a copy of OBJECT in pure storage.
+Recursively copies contents of vectors and cons cells.
+Does not copy symbols.  Copies strings without text properties.  */)
+     (obj)
      register Lisp_Object obj;
 {
   if (NILP (Vpurify_flag))
     return obj;
 
-  if ((PNTR_COMPARISON_TYPE) XPNTR (obj) < (PNTR_COMPARISON_TYPE) ((char *) pure + PURESIZE)
-      && (PNTR_COMPARISON_TYPE) XPNTR (obj) >= (PNTR_COMPARISON_TYPE) pure)
+  if (PURE_POINTER_P (XPNTR (obj)))
     return obj;
 
   if (CONSP (obj))
@@ -3340,8 +3983,8 @@ Does not copy symbols.  Copies strings without text properties.")
   else if (FLOATP (obj))
     return make_pure_float (XFLOAT_DATA (obj));
   else if (STRINGP (obj))
-    return make_pure_string (XSTRING (obj)->data, XSTRING (obj)->size,
-                            STRING_BYTES (XSTRING (obj)),
+    return make_pure_string (SDATA (obj), SCHARS (obj),
+                            SBYTES (obj),
                             STRING_MULTIBYTE (obj));
   else if (COMPILEDP (obj) || VECTORP (obj))
     {
@@ -3362,8 +4005,8 @@ Does not copy symbols.  Copies strings without text properties.")
     }
   else if (MARKERP (obj))
     error ("Attempt to copy a marker to pure storage");
-  else
-    return obj;
+
+  return obj;
 }
 
 
@@ -3372,20 +4015,6 @@ Does not copy symbols.  Copies strings without text properties.")
                          Protection from GC
  ***********************************************************************/
 
-/* Recording what needs to be marked for gc.  */
-
-struct gcpro *gcprolist;
-
-/* Addresses of staticpro'd variables.  */
-
-#define NSTATICS 1024
-Lisp_Object *staticvec[NSTATICS] = {0};
-
-/* Index of next unused slot in staticvec.  */
-
-int staticidx = 0;
-
-
 /* Put an entry in staticvec, pointing at the variable with address
    VARADDRESS.  */
 
@@ -3427,28 +4056,24 @@ struct backtrace
 int
 inhibit_garbage_collection ()
 {
-  int count = specpdl_ptr - specpdl;
-  Lisp_Object number;
+  int count = SPECPDL_INDEX ();
   int nbits = min (VALBITS, BITS_PER_INT);
 
-  XSETINT (number, ((EMACS_INT) 1 << (nbits - 1)) - 1);
-
-  specbind (Qgc_cons_threshold, number);
-
+  specbind (Qgc_cons_threshold, make_number (((EMACS_INT) 1 << (nbits - 1)) - 1));
   return count;
 }
 
 
 DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
-  "Reclaim storage for Lisp objects no longer needed.\n\
-Returns info on amount of space in use:\n\
- ((USED-CONSES . FREE-CONSES) (USED-SYMS . FREE-SYMS)\n\
-  (USED-MARKERS . FREE-MARKERS) USED-STRING-CHARS USED-VECTOR-SLOTS\n\
-  (USED-FLOATS . FREE-FLOATS) (USED-INTERVALS . FREE-INTERVALS\n\
-  (USED-STRINGS . FREE-STRINGS))\n\
-Garbage collection happens automatically if you cons more than\n\
-`gc-cons-threshold' bytes of Lisp data since previous garbage collection.")
-  ()
+       doc: /* Reclaim storage for Lisp objects no longer needed.
+Returns info on amount of space in use:
+ ((USED-CONSES . FREE-CONSES) (USED-SYMS . FREE-SYMS)
+  (USED-MARKERS . FREE-MARKERS) USED-STRING-CHARS USED-VECTOR-SLOTS
+  (USED-FLOATS . FREE-FLOATS) (USED-INTERVALS . FREE-INTERVALS)
+  (USED-STRINGS . FREE-STRINGS))
+Garbage collection happens automatically if you cons more than
+`gc-cons-threshold' bytes of Lisp data since previous garbage collection.  */)
+     ()
 {
   register struct gcpro *tail;
   register struct specbinding *bind;
@@ -3458,7 +4083,13 @@ Garbage collection happens automatically if you cons more than\n\
   char stack_top_variable;
   register int i;
   int message_p;
-  Lisp_Object total[7];
+  Lisp_Object total[8];
+  int count = SPECPDL_INDEX ();
+
+  /* Can't GC if pure storage overflowed because we can't determine
+     if something is a pure object or not.  */
+  if (pure_bytes_used_before_overflow)
+    return Qnil;
 
   /* In case user calls debug_print during GC,
      don't let that cause a recursive GC.  */
@@ -3466,6 +4097,7 @@ Garbage collection happens automatically if you cons more than\n\
 
   /* Save what's currently displayed in the echo area.  */
   message_p = push_message ();
+  record_unwind_protect (pop_message_unwind, Qnil);
 
   /* Save a copy of the contents of the stack, for debugging.  */
 #if MAX_SAVE_STACK > 0
@@ -3511,6 +4143,24 @@ Garbage collection happens automatically if you cons more than\n\
          nextb->undo_list 
            = truncate_undo_list (nextb->undo_list, undo_limit,
                                  undo_strong_limit);
+
+       /* Shrink buffer gaps, but skip indirect and dead buffers.  */
+       if (nextb->base_buffer == 0 && !NILP (nextb->name))
+         {
+           /* If a buffer's gap size is more than 10% of the buffer
+              size, or larger than 2000 bytes, then shrink it
+              accordingly.  Keep a minimum size of 20 bytes.  */
+           int size = min (2000, max (20, (nextb->text->z_byte / 10)));
+
+           if (nextb->text->gap_size > size)
+             {
+               struct buffer *save_current = current_buffer;
+               current_buffer = nextb;
+               make_gap (-(nextb->text->gap_size - size));
+               current_buffer = save_current;
+             }
+         }
+
        nextb = nextb->next;
       }
   }
@@ -3537,7 +4187,9 @@ Garbage collection happens automatically if you cons more than\n\
     for (i = 0; i < tail->nvars; i++)
       if (!XMARKBIT (tail->var[i]))
        {
-         mark_object (&tail->var[i]);
+         /* Explicit casting prevents compiler warning about
+            discarding the `volatile' qualifier.  */
+         mark_object ((Lisp_Object *)&tail->var[i]);
          XMARK (tail->var[i]);
        }
 #endif
@@ -3604,7 +4256,10 @@ Garbage collection happens automatically if you cons more than\n\
                    if (NILP (prev))
                      nextb->undo_list = tail = XCDR (tail);
                    else
-                     tail = XCDR (prev) = XCDR (tail);
+                     {
+                       tail = XCDR (tail);
+                       XSETCDR (prev, tail);
+                     }
                  }
                else
                  {
@@ -3622,6 +4277,13 @@ Garbage collection happens automatically if you cons more than\n\
   mark_stack ();
 #endif
 
+#ifdef USE_GTK
+  {
+    extern void xg_mark_data ();
+    xg_mark_data ();
+  }
+#endif
+
   gc_sweep ();
 
   /* Clear the mark bits that we set in certain root slots.  */
@@ -3668,7 +4330,7 @@ Garbage collection happens automatically if you cons more than\n\
        message1_nolog ("Garbage collecting...done");
     }
 
-  pop_message ();
+  unbind_to (count, Qnil);
 
   total[0] = Fcons (make_number (total_conses),
                    make_number (total_free_conses));
@@ -3676,13 +4338,13 @@ Garbage collection happens automatically if you cons more than\n\
                    make_number (total_free_symbols));
   total[2] = Fcons (make_number (total_markers),
                    make_number (total_free_markers));
-  total[3] = Fcons (make_number (total_string_size),
-                   make_number (total_vector_size));
-  total[4] = Fcons (make_number (total_floats),
+  total[3] = make_number (total_string_size);
+  total[4] = make_number (total_vector_size);
+  total[5] = Fcons (make_number (total_floats),
                    make_number (total_free_floats));
-  total[5] = Fcons (make_number (total_intervals),
+  total[6] = Fcons (make_number (total_intervals),
                    make_number (total_free_intervals));
-  total[6] = Fcons (make_number (total_strings),
+  total[7] = Fcons (make_number (total_strings),
                    make_number (total_free_strings));
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
@@ -3691,7 +4353,8 @@ Garbage collection happens automatically if you cons more than\n\
     double nlive = 0;
       
     for (i = 0; i < 7; ++i)
-      nlive += XFASTINT (XCAR (total[i]));
+      if (CONSP (total[i]))
+       nlive += XFASTINT (XCAR (total[i]));
 
     avg_live = (avg_live * ngcs + nlive) / (ngcs + 1);
     max_live = max (nlive, max_live);
@@ -3701,7 +4364,14 @@ Garbage collection happens automatically if you cons more than\n\
     }
 #endif
 
-  return Flist (7, total);
+  if (!NILP (Vpost_gc_hook))
+    {
+      int count = inhibit_garbage_collection ();
+      safe_run_hooks (Qpost_gc_hook);
+      unbind_to (count, Qnil);
+    }
+  
+  return Flist (sizeof total / sizeof *total, total);
 }
 
 
@@ -3793,6 +4463,12 @@ mark_image_cache (f)
 Lisp_Object *last_marked[LAST_MARKED_SIZE];
 int last_marked_index;
 
+/* For debugging--call abort when we cdr down this many
+   links of a list, in mark_object.  In debugging,
+   the call to abort will hit a breakpoint.
+   Normally this is zero and the check never goes off.  */
+int mark_object_loop_halt;
+
 void
 mark_object (argptr)
      Lisp_Object *argptr;
@@ -3803,13 +4479,14 @@ mark_object (argptr)
   void *po;
   struct mem_node *m;
 #endif
+  int cdr_count = 0;
 
  loop:
   obj = *objptr;
  loop2:
   XUNMARK (obj);
 
-  if (PURE_POINTER_P ((PNTR_COMPARISON_TYPE) XPNTR (obj)))
+  if (PURE_POINTER_P (XPNTR (obj)))
     return;
 
   last_marked[last_marked_index++] = objptr;
@@ -3863,6 +4540,11 @@ mark_object (argptr)
        CHECK_ALLOCATED_AND_LIVE (live_string_p);
        MARK_INTERVAL_TREE (ptr->intervals);
        MARK_STRING (ptr);
+#ifdef GC_CHECK_STRING_BYTES
+       /* Check that the string size recorded in the string is the
+          same as the one recorded in the sdata structure. */
+       CHECK_STRING_BYTES (ptr);
+#endif /* GC_CHECK_STRING_BYTES */
       }
       break;
 
@@ -3901,8 +4583,6 @@ mark_object (argptr)
        {
          register struct Lisp_Vector *ptr = XVECTOR (obj);
          register EMACS_INT size = ptr->size;
-         /* See comment above under Lisp_Vector.  */
-         struct Lisp_Vector *volatile ptr1 = ptr;
          register int i;
 
          if (size & ARRAY_MARK_FLAG)
@@ -3914,17 +4594,16 @@ mark_object (argptr)
          for (i = 0; i < size; i++) /* and then mark its elements */
            {
              if (i != COMPILED_CONSTANTS)
-               mark_object (&ptr1->contents[i]);
+               mark_object (&ptr->contents[i]);
            }
          /* This cast should be unnecessary, but some Mips compiler complains
             (MIPS-ABI + SysVR4, DC/OSx, etc).  */
-         objptr = (Lisp_Object *) &ptr1->contents[COMPILED_CONSTANTS];
+         objptr = (Lisp_Object *) &ptr->contents[COMPILED_CONSTANTS];
          goto loop;
        }
       else if (GC_FRAMEP (obj))
        {
-         /* See comment above under Lisp_Vector for why this is volatile.  */
-         register struct frame *volatile ptr = XFRAME (obj);
+         register struct frame *ptr = XFRAME (obj);
          register EMACS_INT size = ptr->size;
 
          if (size & ARRAY_MARK_FLAG) break;   /* Already marked */
@@ -3950,8 +4629,7 @@ mark_object (argptr)
          mark_face_cache (ptr->face_cache);
 #ifdef HAVE_WINDOW_SYSTEM
          mark_image_cache (ptr);
-         mark_object (&ptr->desired_tool_bar_items);
-         mark_object (&ptr->current_tool_bar_items);
+         mark_object (&ptr->tool_bar_items);
          mark_object (&ptr->desired_tool_bar_string);
          mark_object (&ptr->current_tool_bar_string);
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -3970,13 +4648,6 @@ mark_object (argptr)
          register struct Lisp_Vector *ptr = XVECTOR (obj);
          struct window *w = XWINDOW (obj);
          register EMACS_INT size = ptr->size;
-         /* The reason we use ptr1 is to avoid an apparent hardware bug
-            that happens occasionally on the FSF's HP 300s.
-            The bug is that a2 gets clobbered by recursive calls to mark_object.
-            The clobberage seems to happen during function entry,
-            perhaps in the moveml instruction.
-            Yes, this is a crock, but we have to do it.  */
-         struct Lisp_Vector *volatile ptr1 = ptr;
          register int i;
 
          /* Stop if already marked.  */
@@ -3990,9 +4661,9 @@ mark_object (argptr)
          /* There is no Lisp data above The member CURRENT_MATRIX in
             struct WINDOW.  Stop marking when that slot is reached.  */
          for (i = 0;
-              (char *) &ptr1->contents[i] < (char *) &w->current_matrix;
+              (char *) &ptr->contents[i] < (char *) &w->current_matrix;
               i++)
-           mark_object (&ptr1->contents[i]);
+           mark_object (&ptr->contents[i]);
 
          /* Mark glyphs for leaf windows.  Marking window matrices is
             sufficient because frame matrices use the same glyph
@@ -4019,6 +4690,10 @@ mark_object (argptr)
          h->size |= ARRAY_MARK_FLAG;
 
          /* Mark contents.  */
+         /* Do not mark next_free or next_weak.
+            Being in the next_weak chain 
+            should not keep the hash table alive.
+            No need to mark `count' since it is an integer.  */
          mark_object (&h->test);
          mark_object (&h->weak);
          mark_object (&h->rehash_size);
@@ -4041,13 +4716,6 @@ mark_object (argptr)
        {
          register struct Lisp_Vector *ptr = XVECTOR (obj);
          register EMACS_INT size = ptr->size;
-         /* The reason we use ptr1 is to avoid an apparent hardware bug
-            that happens occasionally on the FSF's HP 300s.
-            The bug is that a2 gets clobbered by recursive calls to mark_object.
-            The clobberage seems to happen during function entry,
-            perhaps in the moveml instruction.
-            Yes, this is a crock, but we have to do it.  */
-         struct Lisp_Vector *volatile ptr1 = ptr;
          register int i;
 
          if (size & ARRAY_MARK_FLAG) break; /* Already marked */
@@ -4057,14 +4725,13 @@ mark_object (argptr)
            size &= PSEUDOVECTOR_SIZE_MASK;
 
          for (i = 0; i < size; i++) /* and then mark its elements */
-           mark_object (&ptr1->contents[i]);
+           mark_object (&ptr->contents[i]);
        }
       break;
 
     case Lisp_Symbol:
       {
-       /* See comment above under Lisp_Vector for why this is volatile.  */
-       register struct Lisp_Symbol *volatile ptr = XSYMBOL (obj);
+       register struct Lisp_Symbol *ptr = XSYMBOL (obj);
        struct Lisp_Symbol *ptrx;
 
        if (XMARKBIT (ptr->plist)) break;
@@ -4074,9 +4741,9 @@ mark_object (argptr)
        mark_object (&ptr->function);
        mark_object (&ptr->plist);
 
-       if (!PURE_POINTER_P (ptr->name))
-         MARK_STRING (ptr->name);
-       MARK_INTERVAL_TREE (ptr->name->intervals);
+       if (!PURE_POINTER_P (XSTRING (ptr->xname)))
+         MARK_STRING (XSTRING (ptr->xname));
+       MARK_INTERVAL_TREE (STRING_INTERVALS (ptr->xname));
        
        /* Note that we do not mark the obarray of the symbol.
           It is safe not to do so because nothing accesses that
@@ -4122,8 +4789,7 @@ mark_object (argptr)
            mark_object (&ptr->realvalue);
            mark_object (&ptr->buffer);
            mark_object (&ptr->frame);
-           /* See comment above under Lisp_Vector for why not use ptr here.  */
-           objptr = &XBUFFER_LOCAL_VALUE (obj)->cdr;
+           objptr = &ptr->cdr;
            goto loop;
          }
 
@@ -4167,11 +4833,14 @@ mark_object (argptr)
        if (EQ (ptr->cdr, Qnil))
          {
            objptr = &ptr->car;
+           cdr_count = 0;
            goto loop;
          }
        mark_object (&ptr->car);
-       /* See comment above under Lisp_Vector for why not use ptr here.  */
-       objptr = &XCDR (obj);
+       objptr = &ptr->cdr;
+       cdr_count++;
+       if (cdr_count == mark_object_loop_halt)
+         abort ();
        goto loop;
       }
 
@@ -4224,8 +4893,8 @@ mark_buffer (buf)
              && ! XMARKBIT (XCAR (ptr->car))
              && GC_MARKERP (XCAR (ptr->car)))
            {
-             XMARK (XCAR (ptr->car));
-             mark_object (&XCDR (ptr->car));
+             XMARK (XCAR_AS_LVALUE (ptr->car));
+             mark_object (&XCDR_AS_LVALUE (ptr->car));
            }
          else
            mark_object (&ptr->car);
@@ -4236,7 +4905,7 @@ mark_buffer (buf)
            break;
        }
 
-      mark_object (&XCDR (tail));
+      mark_object (&XCDR_AS_LVALUE (tail));
     }
   else
     mark_object (&buffer->undo_list);
@@ -4278,6 +4947,7 @@ mark_kboards ()
       mark_object (&kb->Vsystem_key_alist);
       mark_object (&kb->system_key_syms);
       mark_object (&kb->Vdefault_minibuffer_frame);
+      mark_object (&kb->echo_string);
     }
 }
 
@@ -4373,6 +5043,10 @@ gc_sweep ()
   sweep_weak_hash_tables ();
 
   sweep_strings ();
+#ifdef GC_CHECK_STRING_BYTES
+  if (!noninteractive)
+    check_string_bytes (1);
+#endif
 
   /* Put all unmarked conses on free list */
   {
@@ -4531,29 +5205,39 @@ gc_sweep ()
     register int lim = symbol_block_index;
     register int num_free = 0, num_used = 0;
 
-    symbol_free_list = 0;
+    symbol_free_list = NULL;
   
     for (sblk = symbol_block; sblk; sblk = *sprev)
       {
-       register int i;
        int this_free = 0;
-       for (i = 0; i < lim; i++)
-         if (!XMARKBIT (sblk->symbols[i].plist))
-           {
-             *(struct Lisp_Symbol **)&sblk->symbols[i].value = symbol_free_list;
-             symbol_free_list = &sblk->symbols[i];
+       struct Lisp_Symbol *sym = sblk->symbols;
+       struct Lisp_Symbol *end = sym + lim;
+
+       for (; sym < end; ++sym)
+         {
+           /* Check if the symbol was created during loadup.  In such a case
+              it might be pointed to by pure bytecode which we don't trace,
+              so we conservatively assume that it is live.  */
+           int pure_p = PURE_POINTER_P (XSTRING (sym->xname));
+           
+           if (!XMARKBIT (sym->plist) && !pure_p)
+             {
+               *(struct Lisp_Symbol **) &sym->value = symbol_free_list;
+               symbol_free_list = sym;
 #if GC_MARK_STACK
-             symbol_free_list->function = Vdead;
+               symbol_free_list->function = Vdead;
 #endif
-             this_free++;
-           }
-         else
-           {
-             num_used++;
-             if (!PURE_POINTER_P (sblk->symbols[i].name))
-               UNMARK_STRING (sblk->symbols[i].name);
-             XUNMARK (sblk->symbols[i].plist);
-           }
+               ++this_free;
+             }
+           else
+             {
+               ++num_used;
+               if (!pure_p)
+                 UNMARK_STRING (XSTRING (sym->xname));
+               XUNMARK (sym->plist);
+             }
+         }
+       
        lim = SYMBOL_BLOCK_SIZE;
        /* If this block contains only free symbols and we have already
           seen more than two blocks worth of free symbols then deallocate
@@ -4715,6 +5399,11 @@ gc_sweep ()
          prev = vector, vector = vector->next;
        }
   }
+  
+#ifdef GC_CHECK_STRING_BYTES
+  if (!noninteractive)
+    check_string_bytes (1);
+#endif
 }
 
 
@@ -4723,10 +5412,10 @@ gc_sweep ()
 /* Debugging aids.  */
 
 DEFUN ("memory-limit", Fmemory_limit, Smemory_limit, 0, 0, 0,
-  "Return the address of the last byte Emacs has allocated, divided by 1024.\n\
-This may be helpful in debugging Emacs's memory usage.\n\
-We divide the value by 1024 to make sure it fits in a Lisp integer.")
-  ()
+       doc: /* Return the address of the last byte Emacs has allocated, divided by 1024.
+This may be helpful in debugging Emacs's memory usage.
+We divide the value by 1024 to make sure it fits in a Lisp integer.  */)
+     ()
 {
   Lisp_Object end;
 
@@ -4736,38 +5425,30 @@ We divide the value by 1024 to make sure it fits in a Lisp integer.")
 }
 
 DEFUN ("memory-use-counts", Fmemory_use_counts, Smemory_use_counts, 0, 0, 0,
-  "Return a list of counters that measure how much consing there has been.\n\
-Each of these counters increments for a certain kind of object.\n\
-The counters wrap around from the largest positive integer to zero.\n\
-Garbage collection does not decrease them.\n\
-The elements of the value are as follows:\n\
-  (CONSES FLOATS VECTOR-CELLS SYMBOLS STRING-CHARS MISCS INTERVALS STRINGS)\n\
-All are in units of 1 = one object consed\n\
-except for VECTOR-CELLS and STRING-CHARS, which count the total length of\n\
-objects consed.\n\
-MISCS include overlays, markers, and some internal types.\n\
-Frames, windows, buffers, and subprocesses count as vectors\n\
-  (but the contents of a buffer's text do not count here).")
-  ()
+       doc: /* Return a list of counters that measure how much consing there has been.
+Each of these counters increments for a certain kind of object.
+The counters wrap around from the largest positive integer to zero.
+Garbage collection does not decrease them.
+The elements of the value are as follows:
+  (CONSES FLOATS VECTOR-CELLS SYMBOLS STRING-CHARS MISCS INTERVALS STRINGS)
+All are in units of 1 = one object consed
+except for VECTOR-CELLS and STRING-CHARS, which count the total length of
+objects consed.
+MISCS include overlays, markers, and some internal types.
+Frames, windows, buffers, and subprocesses count as vectors
+  (but the contents of a buffer's text do not count here).  */)
+     ()
 {
   Lisp_Object consed[8];
 
-  XSETINT (consed[0],
-          cons_cells_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[1],
-          floats_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[2],
-          vector_cells_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[3],
-          symbols_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[4],
-          string_chars_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[5],
-          misc_objects_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[6],
-          intervals_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
-  XSETINT (consed[7],
-          strings_consed & ~(((EMACS_INT) 1) << (VALBITS - 1)));
+  consed[0] = make_number (min (MOST_POSITIVE_FIXNUM, cons_cells_consed));
+  consed[1] = make_number (min (MOST_POSITIVE_FIXNUM, floats_consed));
+  consed[2] = make_number (min (MOST_POSITIVE_FIXNUM, vector_cells_consed));
+  consed[3] = make_number (min (MOST_POSITIVE_FIXNUM, symbols_consed));
+  consed[4] = make_number (min (MOST_POSITIVE_FIXNUM, string_chars_consed));
+  consed[5] = make_number (min (MOST_POSITIVE_FIXNUM, misc_objects_consed));
+  consed[6] = make_number (min (MOST_POSITIVE_FIXNUM, intervals_consed));
+  consed[7] = make_number (min (MOST_POSITIVE_FIXNUM, strings_consed));
 
   return Flist (8, consed);
 }
@@ -4790,14 +5471,16 @@ void
 init_alloc_once ()
 {
   /* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet!  */
-  pureptr = 0;
-#if GC_MARK_STACK
+  purebeg = PUREBEG;
+  pure_size = PURESIZE;
+  pure_bytes_used = 0;
+  pure_bytes_used_before_overflow = 0;
+
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
   mem_init ();
   Vdead = make_pure_string ("DEAD", 4, 4, 0);
 #endif
-#ifdef HAVE_SHM
-  pure_size = PURESIZE;
-#endif
+
   all_vectors = 0;
   ignore_warnings = 1;
 #ifdef DOUG_LEA_MALLOC
@@ -4848,68 +5531,82 @@ void
 syms_of_alloc ()
 {
   DEFVAR_INT ("gc-cons-threshold", &gc_cons_threshold,
-    "*Number of bytes of consing between garbage collections.\n\
-Garbage collection can happen automatically once this many bytes have been\n\
-allocated since the last garbage collection.  All data types count.\n\n\
-Garbage collection happens automatically only when `eval' is called.\n\n\
-By binding this temporarily to a large number, you can effectively\n\
-prevent garbage collection during a part of the program.");
+             doc: /* *Number of bytes of consing between garbage collections.
+Garbage collection can happen automatically once this many bytes have been
+allocated since the last garbage collection.  All data types count.
 
-  DEFVAR_INT ("pure-bytes-used", &pureptr,
-    "Number of bytes of sharable Lisp data allocated so far.");
+Garbage collection happens automatically only when `eval' is called.
+
+By binding this temporarily to a large number, you can effectively
+prevent garbage collection during a part of the program.  */);
+
+  DEFVAR_INT ("pure-bytes-used", &pure_bytes_used,
+             doc: /* Number of bytes of sharable Lisp data allocated so far.  */);
 
   DEFVAR_INT ("cons-cells-consed", &cons_cells_consed,
-    "Number of cons cells that have been consed so far.");
+             doc: /* Number of cons cells that have been consed so far.  */);
 
   DEFVAR_INT ("floats-consed", &floats_consed,
-    "Number of floats that have been consed so far.");
+             doc: /* Number of floats that have been consed so far.  */);
 
   DEFVAR_INT ("vector-cells-consed", &vector_cells_consed,
-    "Number of vector cells that have been consed so far.");
+             doc: /* Number of vector cells that have been consed so far.  */);
 
   DEFVAR_INT ("symbols-consed", &symbols_consed,
-    "Number of symbols that have been consed so far.");
+             doc: /* Number of symbols that have been consed so far.  */);
 
   DEFVAR_INT ("string-chars-consed", &string_chars_consed,
-    "Number of string characters that have been consed so far.");
+             doc: /* Number of string characters that have been consed so far.  */);
 
   DEFVAR_INT ("misc-objects-consed", &misc_objects_consed,
-    "Number of miscellaneous objects that have been consed so far.");
+             doc: /* Number of miscellaneous objects that have been consed so far.  */);
 
   DEFVAR_INT ("intervals-consed", &intervals_consed,
-    "Number of intervals that have been consed so far.");
+             doc: /* Number of intervals that have been consed so far.  */);
 
   DEFVAR_INT ("strings-consed", &strings_consed,
-    "Number of strings that have been consed so far.");
+             doc: /* Number of strings that have been consed so far.  */);
 
   DEFVAR_LISP ("purify-flag", &Vpurify_flag,
-    "Non-nil means loading Lisp code in order to dump an executable.\n\
-This means that certain objects should be allocated in shared (pure) space.");
+              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.  */);
 
   DEFVAR_INT ("undo-limit", &undo_limit,
-    "Keep no more undo information once it exceeds this size.\n\
-This limit is applied when garbage collection happens.\n\
-The size is counted as the number of bytes occupied,\n\
-which includes both saved text and other data.");
+             doc: /* Keep no more undo information once it exceeds this size.
+This limit is applied when garbage collection happens.
+The size is counted as the number of bytes occupied,
+which includes both saved text and other data.  */);
   undo_limit = 20000;
 
   DEFVAR_INT ("undo-strong-limit", &undo_strong_limit,
-    "Don't keep more than this much size of undo information.\n\
-A command which pushes past this size is itself forgotten.\n\
-This limit is applied when garbage collection happens.\n\
-The size is counted as the number of bytes occupied,\n\
-which includes both saved text and other data.");
+             doc: /* Don't keep more than this much size of undo information.
+A command which pushes past this size is itself forgotten.
+This limit is applied when garbage collection happens.
+The size is counted as the number of bytes occupied,
+which includes both saved text and other data.  */);
   undo_strong_limit = 30000;
 
   DEFVAR_BOOL ("garbage-collection-messages", &garbage_collection_messages,
-    "Non-nil means display messages at start and end of garbage collection.");
+              doc: /* Non-nil means display messages at start and end of garbage collection.  */);
   garbage_collection_messages = 0;
 
+  DEFVAR_LISP ("post-gc-hook", &Vpost_gc_hook,
+              doc: /* Hook run after garbage collection has finished.  */);
+  Vpost_gc_hook = Qnil;
+  Qpost_gc_hook = intern ("post-gc-hook");
+  staticpro (&Qpost_gc_hook);
+
+  DEFVAR_LISP ("memory-signal-data", &Vmemory_signal_data,
+              doc: /* Precomputed `signal' argument for memory-full error.  */);
   /* 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.  */
-  memory_signal_data
-    = Fcons (Qerror, Fcons (build_string ("Memory exhausted--use M-x save-some-buffers RET"), Qnil));
-  staticpro (&memory_signal_data);
+  Vmemory_signal_data
+    = list2 (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 we are handling a memory-full error.  */);
+  Vmemory_full = Qnil;
 
   staticpro (&Qgc_cons_threshold);
   Qgc_cons_threshold = intern ("gc-cons-threshold");