*** empty log message ***
[bpt/emacs.git] / src / alloc.c
index 47e75f5..4affa42 100644 (file)
@@ -1,5 +1,5 @@
 /* Storage allocation and gc for GNU Emacs Lisp interpreter.
 /* 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.
       Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -26,11 +26,12 @@ Boston, MA 02111-1307, USA.  */
 
 #include <signal.h>
 
 
 #include <signal.h>
 
-/* Define this temporarily to hunt a bug.  If defined, the size of
-   strings is always recorded in sdata structures so that it can be
-   compared to the sizes recorded in Lisp strings.  */
+/* GC_MALLOC_CHECK defined means perform validity checks of malloc'd
+   memory.  Can do this only if using gmalloc.c.  */
 
 
-#define GC_CHECK_STRING_BYTES 1
+#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
 
 /* This file is part of the core Lisp implementation, and thus must
    deal with the real data structures.  If the Lisp implementation is
@@ -215,7 +216,7 @@ EMACS_INT pure_size;
 
 /* Index in pure at which next pure object will be allocated.. */
 
 
 /* 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.  */
 
 /* If nonzero, this is a warning delivered by malloc and not yet
    displayed.  */
@@ -278,7 +279,7 @@ enum mem_type
   MEM_TYPE_VECTOR
 };
 
   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.  */
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
 #include <stdio.h>             /* For fprintf.  */
@@ -289,7 +290,64 @@ enum mem_type
 
 Lisp_Object Vdead;
 
 
 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));
 static POINTER_TYPE *lisp_malloc P_ ((size_t, enum mem_type));
 static void lisp_free P_ ((POINTER_TYPE *));
 static void mark_stack P_ ((void));
@@ -316,7 +374,29 @@ static INLINE struct mem_node *mem_find P_ ((void *));
 static void check_gcpros P_ ((void));
 #endif
 
 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
 /************************************************************************
 
 \f
 /************************************************************************
@@ -493,13 +573,18 @@ lisp_malloc (nbytes, type)
   register void *val;
 
   BLOCK_INPUT;
   register void *val;
 
   BLOCK_INPUT;
+
+#ifdef GC_MALLOC_CHECK
+  allocated_mem_type = type;
+#endif
+  
   val = (void *) malloc (nbytes);
 
   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
   if (val && type != MEM_TYPE_NON_LISP)
     mem_insert (val, (char *) val + nbytes, type);
 #endif
-  
+   
   UNBLOCK_INPUT;
   if (!val && nbytes)
     memory_full ();
   UNBLOCK_INPUT;
   if (!val && nbytes)
     memory_full ();
@@ -527,7 +612,7 @@ lisp_free (block)
 {
   BLOCK_INPUT;
   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;
   mem_delete (mem_find (block));
 #endif
   UNBLOCK_INPUT;
@@ -562,8 +647,30 @@ emacs_blocked_free (ptr)
      void *ptr;
 {
   BLOCK_INPUT;
      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);
   __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.  */
   /* 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.  */
@@ -610,10 +717,34 @@ emacs_blocked_malloc (size)
 #else
     __malloc_extra_blocks = malloc_hysteresis;
 #endif
 #else
     __malloc_extra_blocks = malloc_hysteresis;
 #endif
+
   value = (void *) malloc (size);
   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;
 
   __malloc_hook = emacs_blocked_malloc;
   UNBLOCK_INPUT;
 
+  /* fprintf (stderr, "%p malloc\n", value); */
   return value;
 }
 
   return value;
 }
 
@@ -629,7 +760,48 @@ emacs_blocked_realloc (ptr, size)
 
   BLOCK_INPUT;
   __realloc_hook = old_realloc_hook;
 
   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);
   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;
 
   __realloc_hook = emacs_blocked_realloc;
   UNBLOCK_INPUT;
 
@@ -1023,50 +1195,84 @@ init_strings ()
 
 #ifdef GC_CHECK_STRING_BYTES
 
 
 #ifdef GC_CHECK_STRING_BYTES
 
-/* Check validity of all live Lisp strings' string_bytes member.
-   Used for hunting a bug.  */
-
 static int check_string_bytes_count;
 
 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
 void
-check_string_bytes ()
+check_sblock (b)
+     struct sblock *b;
 {
 {
-  struct sblock *b;
-  
-  for (b = large_sblocks; b; b = b->next)
-    {
-      struct Lisp_String *s = b->first_data.string;
-      if (s && GC_STRING_BYTES (s) != SDATA_NBYTES (SDATA_OF_STRING (s)))
-       abort ();
-    }
+  struct sdata *from, *end, *from_end;
       
       
-  for (b = oldest_sblock; b; b = b->next)
+  end = b->next_free;
+      
+  for (from = &b->first_data; from < end; from = from_end)
     {
     {
-      struct sdata *from, *end, *from_end;
+      /* Compute the next FROM here because copying below may
+        overwrite data we need to compute it.  */
+      int nbytes;
       
       
-      end = b->next_free;
+      /* 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);
       
       
-      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;
+      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 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 ();
-         
-         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 */
 }
 
 #endif /* GC_CHECK_STRING_BYTES */
@@ -1116,12 +1322,21 @@ allocate_string ()
   consing_since_gc += sizeof *s;
 
 #ifdef GC_CHECK_STRING_BYTES
   consing_since_gc += sizeof *s;
 
 #ifdef GC_CHECK_STRING_BYTES
-  if (++check_string_bytes_count == 10)
+  if (!noninteractive
+#ifdef macintosh
+      && current_sblock
+#endif
+     )
     {
     {
-      check_string_bytes_count = 0;
-      check_string_bytes ();
+      if (++check_string_bytes_count == 200)
+       {
+         check_string_bytes_count = 0;
+         check_string_bytes (1);
+       }
+      else
+       check_string_bytes (0);
     }
     }
-#endif
+#endif /* GC_CHECK_STRING_BYTES */
 
   return s;
 }
 
   return s;
 }
@@ -1450,7 +1665,7 @@ Both LENGTH and INIT must be numbers.")
     }
   else
     {
     }
   else
     {
-      unsigned char str[4];
+      unsigned char str[MAX_MULTIBYTE_LENGTH];
       int len = CHAR_STRING (c, str);
 
       nbytes = len * XINT (length);
       int len = CHAR_STRING (c, str);
 
       nbytes = len * XINT (length);
@@ -1523,12 +1738,12 @@ make_string (contents, nbytes)
   int nchars, multibyte_nbytes;
 
   parse_str_as_multibyte (contents, nbytes, &nchars, &multibyte_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.  */
   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;
 }
 
   return val;
 }
 
@@ -1927,8 +2142,38 @@ DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
   size = XFASTINT (length);
 
   val = Qnil;
   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;
 }
 
   return val;
 }
 
@@ -2353,60 +2598,7 @@ make_event_array (nargs, args)
                           C Stack Marking
  ************************************************************************/
 
                           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.  */
 
 
 /* Initialize this part of alloc.c.  */
 
@@ -2479,7 +2671,13 @@ mem_insert (start, end, type)
 #endif /* GC_MARK_STACK == GC_MARK_STACK_CHECK_GCPROS */
 
   /* Create a new node.  */
 #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);
   x = (struct mem_node *) xmalloc (sizeof *x);
+#endif
   x->start = start;
   x->end = end;
   x->type = type;
   x->start = start;
   x->end = end;
   x->type = type;
@@ -2500,6 +2698,7 @@ mem_insert (start, end, type)
 
   /* Re-establish red-black tree properties.  */
   mem_insert_fixup (x);
 
   /* Re-establish red-black tree properties.  */
   mem_insert_fixup (x);
+
   return x;
 }
 
   return x;
 }
 
@@ -2699,7 +2898,12 @@ mem_delete (z)
   
   if (y->color == MEM_BLACK)
     mem_delete_fixup (x);
   
   if (y->color == MEM_BLACK)
     mem_delete_fixup (x);
+
+#ifdef GC_MALLOC_CHECK
+  _free_internal (y);
+#else
   xfree (y);
   xfree (y);
+#endif
 }
 
 
 }
 
 
@@ -2939,6 +3143,9 @@ live_buffer_p (m, p)
          && !NILP (((struct buffer *) p)->name));
 }
 
          && !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
 
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
 
@@ -3320,6 +3527,44 @@ mark_stack ()
                       Pure Storage Management
  ***********************************************************************/
 
                       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.
 /* 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.
@@ -3336,29 +3581,14 @@ make_pure_string (data, nchars, nbytes, multibyte)
 {
   Lisp_Object string;
   struct Lisp_String *s;
 {
   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;
   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;
 }
   XSETSTRING (string, s);
   return string;
 }
@@ -3372,11 +3602,10 @@ pure_cons (car, cdr)
      Lisp_Object car, cdr;
 {
   register Lisp_Object new;
      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;
   XCAR (new) = Fpurecopy (car);
   XCDR (new) = Fpurecopy (cdr);
   return new;
@@ -3390,34 +3619,11 @@ make_pure_float (num)
      double num;
 {
   register Lisp_Object new;
      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;
   XFLOAT_DATA (new) = num;
-  XSETFASTINT (XFLOAT (new)->type, 0); /* bug chasing -wsr */
   return new;
 }
 
   return new;
 }
 
@@ -3429,15 +3635,12 @@ Lisp_Object
 make_pure_vector (len)
      EMACS_INT len;
 {
 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;
 }
   XVECTOR (new)->size = len;
   return new;
 }
@@ -3453,8 +3656,7 @@ Does not copy symbols.  Copies strings without text properties.")
   if (NILP (Vpurify_flag))
     return 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))
     return obj;
 
   if (CONSP (obj))
@@ -3494,20 +3696,6 @@ Does not copy symbols.  Copies strings without text properties.")
                          Protection from GC
  ***********************************************************************/
 
                          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.  */
 
 /* Put an entry in staticvec, pointing at the variable with address
    VARADDRESS.  */
 
@@ -3566,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\
 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.")
   (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.")
@@ -3580,7 +3768,8 @@ Garbage collection happens automatically if you cons more than\n\
   char stack_top_variable;
   register int i;
   int message_p;
   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.  */
 
   /* In case user calls debug_print during GC,
      don't let that cause a recursive GC.  */
@@ -3588,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 ();
 
   /* 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
 
   /* Save a copy of the contents of the stack, for debugging.  */
 #if MAX_SAVE_STACK > 0
@@ -3792,7 +3982,7 @@ Garbage collection happens automatically if you cons more than\n\
        message1_nolog ("Garbage collecting...done");
     }
 
        message1_nolog ("Garbage collecting...done");
     }
 
-  pop_message ();
+  unbind_to (count, Qnil);
 
   total[0] = Fcons (make_number (total_conses),
                    make_number (total_free_conses));
 
   total[0] = Fcons (make_number (total_conses),
                    make_number (total_free_conses));
@@ -3800,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));
                    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));
                    make_number (total_free_floats));
-  total[5] = Fcons (make_number (total_intervals),
+  total[6] = Fcons (make_number (total_intervals),
                    make_number (total_free_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
                    make_number (total_free_strings));
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
@@ -3825,7 +4015,7 @@ Garbage collection happens automatically if you cons more than\n\
     }
 #endif
 
     }
 #endif
 
-  return Flist (7, total);
+  return Flist (sizeof total / sizeof *total, total);
 }
 
 
 }
 
 
@@ -3933,7 +4123,7 @@ mark_object (argptr)
  loop2:
   XUNMARK (obj);
 
  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;
     return;
 
   last_marked[last_marked_index++] = objptr;
@@ -3988,13 +4178,9 @@ mark_object (argptr)
        MARK_INTERVAL_TREE (ptr->intervals);
        MARK_STRING (ptr);
 #ifdef GC_CHECK_STRING_BYTES
        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. */
-         struct sdata *p = SDATA_OF_STRING (ptr);
-         if (GC_STRING_BYTES (ptr) != SDATA_NBYTES (p))
-           abort ();
-        }
+       /* 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;
 #endif /* GC_CHECK_STRING_BYTES */
       }
       break;
@@ -4080,8 +4266,7 @@ mark_object (argptr)
          mark_face_cache (ptr->face_cache);
 #ifdef HAVE_WINDOW_SYSTEM
          mark_image_cache (ptr);
          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 */
          mark_object (&ptr->desired_tool_bar_string);
          mark_object (&ptr->current_tool_bar_string);
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -4486,6 +4671,10 @@ gc_sweep ()
   sweep_weak_hash_tables ();
 
   sweep_strings ();
   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 */
   {
 
   /* Put all unmarked conses on free list */
   {
@@ -4644,29 +4833,39 @@ gc_sweep ()
     register int lim = symbol_block_index;
     register int num_free = 0, num_used = 0;
 
     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)
       {
   
     for (sblk = symbol_block; sblk; sblk = *sprev)
       {
-       register int i;
        int this_free = 0;
        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
 #if GC_MARK_STACK
-             symbol_free_list->function = Vdead;
+               symbol_free_list->function = Vdead;
 #endif
 #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
        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
@@ -4828,6 +5027,11 @@ gc_sweep ()
          prev = vector, vector = vector->next;
        }
   }
          prev = vector, vector = vector->next;
        }
   }
+  
+#ifdef GC_CHECK_STRING_BYTES
+  if (!noninteractive)
+    check_string_bytes (1);
+#endif
 }
 
 
 }
 
 
@@ -4903,8 +5107,8 @@ void
 init_alloc_once ()
 {
   /* Used to do Vpurify_flag = Qt here, but Qt isn't set up yet!  */
 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
   mem_init ();
   Vdead = make_pure_string ("DEAD", 4, 4, 0);
 #endif
@@ -4968,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.");
 
 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,
     "Number of bytes of sharable Lisp data allocated so far.");
 
   DEFVAR_INT ("cons-cells-consed", &cons_cells_consed,