*** empty log message ***
[bpt/emacs.git] / src / alloc.c
index 5f08cd0..4affa42 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
       Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -26,6 +26,13 @@ Boston, MA 02111-1307, USA.  */
 
 #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.  */
@@ -52,7 +59,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,14 +73,9 @@ 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 */
 
@@ -211,7 +216,7 @@ EMACS_INT pure_size;
 
 /* Index in pure at which next pure object will be allocated.. */
 
-int pureptr;
+int pure_bytes_used;
 
 /* If nonzero, this is a warning delivered by malloc and not yet
    displayed.  */
@@ -274,7 +279,7 @@ enum mem_type
   MEM_TYPE_VECTOR
 };
 
-#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,7 +290,64 @@ 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
+{
+  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;
+};
+
+/* 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;
+
+/* 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 void lisp_free P_ ((POINTER_TYPE *));
 static void mark_stack P_ ((void));
@@ -312,7 +374,29 @@ 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 1024
+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
 /************************************************************************
@@ -489,13 +573,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 ();
@@ -523,7 +612,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 +647,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 +717,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 +760,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;
 
@@ -870,6 +1046,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 +1064,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 +1144,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 +1193,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 +1321,23 @@ allocate_string ()
   ++strings_consed;
   consing_since_gc += sizeof *s;
 
+#ifdef GC_CHECK_STRING_BYTES
+  if (!noninteractive
+#ifdef macintosh
+      && 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 +1409,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 +1423,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 +1477,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 +1582,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 +1617,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.  */
@@ -1332,7 +1665,7 @@ Both LENGTH and INIT must be numbers.")
     }
   else
     {
-      unsigned char str[4];
+      unsigned char str[MAX_MULTIBYTE_LENGTH];
       int len = CHAR_STRING (c, str);
 
       nbytes = len * XINT (length);
@@ -1405,12 +1738,12 @@ make_string (contents, nbytes)
   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;
 }
 
@@ -1809,8 +2142,38 @@ DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
   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;
 }
 
@@ -2235,60 +2598,7 @@ 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
 
 /* Initialize this part of alloc.c.  */
 
@@ -2361,7 +2671,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 +2698,7 @@ mem_insert (start, end, type)
 
   /* Re-establish red-black tree properties.  */
   mem_insert_fixup (x);
+
   return x;
 }
 
@@ -2581,7 +2898,12 @@ mem_delete (z)
   
   if (y->color == MEM_BLACK)
     mem_delete_fixup (x);
+
+#ifdef GC_MALLOC_CHECK
+  _free_internal (y);
+#else
   xfree (y);
+#endif
 }
 
 
@@ -2821,6 +3143,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
 
@@ -2936,6 +3261,7 @@ mark_maybe_object (obj)
          break;
 
        case Lisp_Int:
+       case Lisp_Type_Limit:
          break;
        }
 
@@ -3201,6 +3527,44 @@ 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;
+{
+  size_t nbytes;
+  POINTER_TYPE *result;
+  char *beg = PUREBEG;
+
+  /* Give Lisp_Floats an extra alignment.  */
+  if (type == Lisp_Float)
+    {
+      size_t alignment;
+#if defined __GNUC__ && __GNUC__ >= 2
+      alignment = __alignof (struct Lisp_Float);
+#else
+      alignment = sizeof (struct Lisp_Float);
+#endif
+      pure_bytes_used = ALIGN (pure_bytes_used, alignment);
+    }
+    
+  nbytes = ALIGN (size, sizeof (EMACS_INT));
+  if (pure_bytes_used + nbytes > PURESIZE)
+    error ("Pure Lisp storage exhausted");
+
+  result = (POINTER_TYPE *) (beg + pure_bytes_used);
+  pure_bytes_used += nbytes;
+  return result;
+}
+
+
 /* 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.
@@ -3217,29 +3581,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;
 }
@@ -3253,11 +3602,10 @@ 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);
+  p = (struct Lisp_Cons *) pure_alloc (sizeof *p, Lisp_Cons);
+  XSETCONS (new, p);
   XCAR (new) = Fpurecopy (car);
   XCDR (new) = Fpurecopy (cdr);
   return new;
@@ -3271,34 +3619,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;
 }
 
@@ -3310,15 +3635,12 @@ 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;
 }
@@ -3334,8 +3656,7 @@ Does not copy symbols.  Copies strings without text properties.")
   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))
@@ -3375,20 +3696,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.  */
 
@@ -3447,7 +3754,7 @@ DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
 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-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.")
@@ -3461,7 +3768,8 @@ 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 = BINDING_STACK_SIZE ();
 
   /* In case user calls debug_print during GC,
      don't let that cause a recursive GC.  */
@@ -3469,6 +3777,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 (push_message_unwind, Qnil);
 
   /* Save a copy of the contents of the stack, for debugging.  */
 #if MAX_SAVE_STACK > 0
@@ -3540,7 +3849,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
@@ -3671,7 +3982,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));
@@ -3679,13 +3990,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
@@ -3704,7 +4015,7 @@ Garbage collection happens automatically if you cons more than\n\
     }
 #endif
 
-  return Flist (7, total);
+  return Flist (sizeof total / sizeof *total, total);
 }
 
 
@@ -3769,7 +4080,7 @@ mark_image (img)
 {
   mark_object (&img->spec);
   
-  if (!GC_NILP (img->data.lisp_val))
+  if (!NILP (img->data.lisp_val))
     mark_object (&img->data.lisp_val);
 }
 
@@ -3812,7 +4123,7 @@ mark_object (argptr)
  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;
@@ -3866,6 +4177,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;
 
@@ -3904,8 +4220,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)
@@ -3917,17 +4231,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 */
@@ -3953,8 +4266,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 */
@@ -3973,13 +4285,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.  */
@@ -3993,9 +4298,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
@@ -4044,13 +4349,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 */
@@ -4060,14 +4358,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;
@@ -4125,8 +4422,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;
          }
 
@@ -4173,8 +4469,7 @@ mark_object (argptr)
            goto loop;
          }
        mark_object (&ptr->car);
-       /* See comment above under Lisp_Vector for why not use ptr here.  */
-       objptr = &XCDR (obj);
+       objptr = &ptr->cdr;
        goto loop;
       }
 
@@ -4376,6 +4671,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 */
   {
@@ -4534,29 +4833,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 (sym->name);
+           
+           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 (sym->name);
+               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
@@ -4718,6 +5027,11 @@ gc_sweep ()
          prev = vector, vector = vector->next;
        }
   }
+  
+#ifdef GC_CHECK_STRING_BYTES
+  if (!noninteractive)
+    check_string_bytes (1);
+#endif
 }
 
 
@@ -4793,8 +5107,8 @@ void
 init_alloc_once ()
 {
   /* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet!  */
-  pureptr = 0;
-#if GC_MARK_STACK
+  pure_bytes_used = 0;
+#if GC_MARK_STACK || defined GC_MALLOC_CHECK
   mem_init ();
   Vdead = make_pure_string ("DEAD", 4, 4, 0);
 #endif
@@ -4858,7 +5172,7 @@ 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.");
 
-  DEFVAR_INT ("pure-bytes-used", &pureptr,
+  DEFVAR_INT ("pure-bytes-used", &pure_bytes_used,
     "Number of bytes of sharable Lisp data allocated so far.");
 
   DEFVAR_INT ("cons-cells-consed", &cons_cells_consed,