Fix failure to compile on Windows due to 2012-07-27T06:04:35Z!dmantipov@yandex.ru.
[bpt/emacs.git] / src / alloc.c
index 67ff345..27426cd 100644 (file)
@@ -161,6 +161,10 @@ static pthread_mutex_t alloc_mutex;
 
 #define GC_STRING_BYTES(S)     (STRING_BYTES (S))
 
+/* Default value of gc_cons_threshold (see below).  */
+
+#define GC_DEFAULT_THRESHOLD (100000 * sizeof (Lisp_Object))
+
 /* Global variables.  */
 struct emacs_globals globals;
 
@@ -189,9 +193,9 @@ int abort_on_gc;
 
 /* Number of live and free conses etc.  */
 
-static EMACS_INT total_conses, total_markers, total_symbols, total_vector_size;
+static EMACS_INT total_conses, total_markers, total_symbols, total_buffers;
 static EMACS_INT total_free_conses, total_free_markers, total_free_symbols;
-static EMACS_INT total_free_floats, total_floats, total_free_vector_bytes;
+static EMACS_INT total_free_floats, total_floats;
 
 /* Points to memory space allocated as "spare", to be freed if we run
    out of memory.  We keep one large block, four cons-blocks, and
@@ -258,6 +262,7 @@ static char *stack_copy;
 static ptrdiff_t stack_copy_size;
 #endif
 
+static Lisp_Object Qstring_bytes, Qvector_slots, Qheap;
 static Lisp_Object Qgc_cons_threshold;
 Lisp_Object Qchar_table_extra_slots;
 
@@ -281,6 +286,14 @@ static void sweep_strings (void);
 static void free_misc (Lisp_Object);
 extern Lisp_Object which_symbols (Lisp_Object, EMACS_INT) EXTERNALLY_VISIBLE;
 
+/* Handy constants for vectorlike objects.  */
+enum
+  {
+    header_size = offsetof (struct Lisp_Vector, contents),
+    bool_header_size = offsetof (struct Lisp_Bool_Vector, data),
+    word_size = sizeof (Lisp_Object)
+  };
+
 /* When scanning the C stack for live Lisp objects, Emacs keeps track
    of what memory allocated via lisp_malloc is intended for what
    purpose.  This enumeration specifies the type of memory.  */
@@ -1708,7 +1721,7 @@ static EMACS_INT total_strings, total_free_strings;
 
 /* Number of bytes used by live strings.  */
 
-static EMACS_INT total_string_size;
+static EMACS_INT total_string_bytes;
 
 /* Given a pointer to a Lisp_String S which is on the free-list
    string_free_list, return a pointer to its successor in the
@@ -1971,9 +1984,9 @@ void
 allocate_string_data (struct Lisp_String *s,
                      EMACS_INT nchars, EMACS_INT nbytes)
 {
-  struct sdata *data;
+  struct sdata *data, *old_data;
   struct sblock *b;
-  ptrdiff_t needed;
+  ptrdiff_t needed, old_nbytes;
 
   if (STRING_BYTES_MAX < nbytes)
     string_overflow ();
@@ -1981,6 +1994,13 @@ allocate_string_data (struct Lisp_String *s,
   /* Determine the number of bytes needed to store NBYTES bytes
      of string data.  */
   needed = SDATA_SIZE (nbytes);
+  if (s->data)
+    {
+      old_data = SDATA_OF_STRING (s);
+      old_nbytes = GC_STRING_BYTES (s);
+    }
+  else
+    old_data = NULL;
 
   MALLOC_BLOCK_INPUT;
 
@@ -2050,6 +2070,16 @@ allocate_string_data (struct Lisp_String *s,
   memcpy ((char *) data + needed, string_overrun_cookie,
          GC_STRING_OVERRUN_COOKIE_SIZE);
 #endif
+
+  /* Note that Faset may call to this function when S has already data
+     assigned.  In this case, mark data as free by setting it's string
+     back-pointer to null, and record the size of the data in it.  */
+  if (old_data)
+    {
+      SDATA_NBYTES (old_data) = old_nbytes;
+      old_data->string = NULL;
+    }
+
   consing_since_gc += needed;
 }
 
@@ -2064,7 +2094,7 @@ sweep_strings (void)
 
   string_free_list = NULL;
   total_strings = total_free_strings = 0;
-  total_string_size = 0;
+  total_string_bytes = 0;
 
   /* Scan strings_blocks, free Lisp_Strings that aren't marked.  */
   for (b = string_blocks; b; b = next)
@@ -2090,7 +2120,7 @@ sweep_strings (void)
                    UNMARK_BALANCE_INTERVALS (s->intervals);
 
                  ++total_strings;
-                 total_string_size += STRING_BYTES (s);
+                 total_string_bytes += STRING_BYTES (s);
                }
              else
                {
@@ -2339,6 +2369,8 @@ LENGTH must be a number.  INIT matters only in whether it is t or nil.  */)
   ptrdiff_t length_in_chars;
   EMACS_INT length_in_elts;
   int bits_per_value;
+  int extra_bool_elts = ((bool_header_size - header_size + word_size - 1)
+                        / word_size);
 
   CHECK_NATNUM (length);
 
@@ -2346,9 +2378,7 @@ LENGTH must be a number.  INIT matters only in whether it is t or nil.  */)
 
   length_in_elts = (XFASTINT (length) + bits_per_value - 1) / bits_per_value;
 
-  /* We must allocate one more elements than LENGTH_IN_ELTS for the
-     slot `size' of the struct Lisp_Bool_Vector.  */
-  val = Fmake_vector (make_number (length_in_elts + 1), Qnil);
+  val = Fmake_vector (make_number (length_in_elts + extra_bool_elts), Qnil);
 
   /* No Lisp_Object to trace in there.  */
   XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0);
@@ -2364,7 +2394,7 @@ LENGTH must be a number.  INIT matters only in whether it is t or nil.  */)
 
       /* Clear any extraneous bits in the last byte.  */
       p->data[length_in_chars - 1]
-       &= (1 << (XINT (length) % BOOL_VECTOR_BITS_PER_CHAR)) - 1;
+       &= (1 << ((XFASTINT (length) - 1) % BOOL_VECTOR_BITS_PER_CHAR + 1)) - 1;
     }
 
   return val;
@@ -2685,6 +2715,7 @@ free_cons (struct Lisp_Cons *ptr)
   ptr->car = Vdead;
 #endif
   cons_free_list = ptr;
+  consing_since_gc -= sizeof *ptr;
   total_free_conses++;
 }
 
@@ -2780,6 +2811,38 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4, L
                                                       Fcons (arg5, Qnil)))));
 }
 
+/* Make a list of COUNT Lisp_Objects, where ARG is the
+   first one.  Allocate conses from pure space if TYPE
+   is CONSTYPE_PURE, or allocate as usual if type is CONSTYPE_HEAP.  */
+
+Lisp_Object
+listn (enum constype type, ptrdiff_t count, Lisp_Object arg, ...)
+{
+  va_list ap;
+  ptrdiff_t i;
+  Lisp_Object val, *objp;
+
+  /* Change to SAFE_ALLOCA if you hit this eassert.  */
+  eassert (count <= MAX_ALLOCA / sizeof (Lisp_Object));
+
+  objp = alloca (count * sizeof (Lisp_Object));
+  objp[0] = arg;
+  va_start (ap, arg);
+  for (i = 1; i < count; i++)
+    objp[i] = va_arg (ap, Lisp_Object);
+  va_end (ap);
+
+  for (i = 0, val = Qnil; i < count; i++)
+    {
+      if (type == CONSTYPE_PURE)
+       val = pure_cons (objp[i], val);
+      else if (type == CONSTYPE_HEAP)
+       val = Fcons (objp[i], val);
+      else
+       abort ();
+    }
+  return val;
+}
 
 DEFUN ("list", Flist, Slist, 0, MANY, 0,
        doc: /* Return a newly created list with specified arguments as elements.
@@ -2857,12 +2920,10 @@ DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
 
 #define VECTOR_BLOCK_SIZE 4096
 
-/* Handy constants for vectorlike objects.  */
+/* Align allocation request sizes to be a multiple of ROUNDUP_SIZE.  */
 enum
   {
-    header_size = offsetof (struct Lisp_Vector, contents),
-    word_size = sizeof (Lisp_Object),
-    roundup_size = COMMON_MULTIPLE (sizeof (Lisp_Object),
+    roundup_size = COMMON_MULTIPLE (word_size,
                                    USE_LSB_TAG ? 1 << GCTYPEBITS : 1)
   };
 
@@ -2888,7 +2949,7 @@ verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS));
 /* Size of the largest vector allocated from block.  */
 
 #define VBLOCK_BYTES_MAX                                       \
-  vroundup ((VECTOR_BLOCK_BYTES / 2) - sizeof (Lisp_Object))
+  vroundup ((VECTOR_BLOCK_BYTES / 2) - word_size)
 
 /* We maintain one free list for each possible block-allocated
    vector size, and this is the number of free lists we have.  */
@@ -2914,7 +2975,7 @@ verify (VECTOR_BLOCK_SIZE <= (1 << PSEUDOVECTOR_SIZE_BITS));
     eassert ((index) < VECTOR_MAX_FREE_LIST_INDEX);            \
     (v)->header.next.vector = vector_free_lists[index];                \
     vector_free_lists[index] = (v);                            \
-    total_free_vector_bytes += (nbytes);                       \
+    total_free_vector_slots += (nbytes) / word_size;           \
   } while (0)
 
 struct vector_block
@@ -2940,6 +3001,14 @@ static struct Lisp_Vector *large_vectors;
 
 Lisp_Object zero_vector;
 
+/* Number of live vectors.  */
+
+static EMACS_INT total_vectors;
+
+/* Total size of live and free vectors, in Lisp_Object units.  */
+
+static EMACS_INT total_vector_slots, total_free_vector_slots;
+
 /* Get a new vector block.  */
 
 static struct vector_block *
@@ -2985,7 +3054,7 @@ allocate_vector_from_block (size_t nbytes)
       vector = vector_free_lists[index];
       vector_free_lists[index] = vector->header.next.vector;
       vector->header.next.nbytes = nbytes;
-      total_free_vector_bytes -= nbytes;
+      total_free_vector_slots -= nbytes / word_size;
       return vector;
     }
 
@@ -3000,7 +3069,7 @@ allocate_vector_from_block (size_t nbytes)
        vector = vector_free_lists[index];
        vector_free_lists[index] = vector->header.next.vector;
        vector->header.next.nbytes = nbytes;
-       total_free_vector_bytes -= nbytes;
+       total_free_vector_slots -= nbytes / word_size;
 
        /* Excess bytes are used for the smaller vector,
           which should be set on an appropriate free list.  */
@@ -3030,12 +3099,6 @@ allocate_vector_from_block (size_t nbytes)
   return vector;
  }
 
-/* Return how many Lisp_Objects can be stored in V.  */
-
-#define VECTOR_SIZE(v) ((v)->header.size & PSEUDOVECTOR_FLAG ?         \
-                       (PSEUDOVECTOR_SIZE_MASK & (v)->header.size) :   \
-                       (v)->header.size)
-
 /* Nonzero if VECTOR pointer is valid pointer inside BLOCK.  */
 
 #define VECTOR_IN_BLOCK(vector, block)         \
@@ -3060,7 +3123,7 @@ sweep_vectors (void)
   struct vector_block *block = vector_blocks, **bprev = &vector_blocks;
   struct Lisp_Vector *vector, *next, **vprev = &large_vectors;
 
-  total_free_vector_bytes = total_vector_size = 0;
+  total_vectors = total_vector_slots = total_free_vector_slots = 0;
   memset (vector_free_lists, 0, sizeof (vector_free_lists));
 
   /* Looking through vector blocks.  */
@@ -3075,7 +3138,8 @@ sweep_vectors (void)
          if (VECTOR_MARKED_P (vector))
            {
              VECTOR_UNMARK (vector);
-             total_vector_size += VECTOR_SIZE (vector);
+             total_vectors++;
+             total_vector_slots += vector->header.next.nbytes / word_size;
              next = ADVANCE (vector, vector->header.next.nbytes);
            }
          else
@@ -3131,7 +3195,24 @@ sweep_vectors (void)
       if (VECTOR_MARKED_P (vector))
        {
          VECTOR_UNMARK (vector);
-         total_vector_size += VECTOR_SIZE (vector);
+         total_vectors++;
+         if (vector->header.size & PSEUDOVECTOR_FLAG)
+           {
+             struct Lisp_Bool_Vector *b = (struct Lisp_Bool_Vector *) vector;
+
+             /* All non-bool pseudovectors are small enough to be allocated
+                from vector blocks.  This code should be redesigned if some
+                pseudovector type grows beyond VBLOCK_BYTES_MAX.  */
+             eassert (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_BOOL_VECTOR));
+
+             total_vector_slots
+               += (bool_header_size
+                   + ((b->size + BOOL_VECTOR_BITS_PER_CHAR - 1)
+                      / BOOL_VECTOR_BITS_PER_CHAR)) / word_size;
+           }
+         else
+           total_vector_slots
+             += header_size / word_size + vector->header.size;
          vprev = &vector->header.next.vector;
        }
       else
@@ -3515,10 +3596,10 @@ static int marker_block_index = MARKER_BLOCK_SIZE;
 
 static union Lisp_Misc *marker_free_list;
 
-/* Return a newly allocated Lisp_Misc object, with no substructure.  */
+/* Return a newly allocated Lisp_Misc object of specified TYPE.  */
 
-Lisp_Object
-allocate_misc (void)
+static Lisp_Object
+allocate_misc (enum Lisp_Misc_Type type)
 {
   Lisp_Object val;
 
@@ -3550,6 +3631,7 @@ allocate_misc (void)
   --total_free_markers;
   consing_since_gc += sizeof (union Lisp_Misc);
   misc_objects_consed++;
+  XMISCTYPE (val) = type;
   XMISCANY (val)->gcmarkbit = 0;
   return val;
 }
@@ -3562,7 +3644,7 @@ free_misc (Lisp_Object misc)
   XMISCTYPE (misc) = Lisp_Misc_Free;
   XMISC (misc)->u_free.chain = marker_free_list;
   marker_free_list = XMISC (misc);
-
+  consing_since_gc -= sizeof (union Lisp_Misc);
   total_free_markers++;
 }
 
@@ -3576,8 +3658,7 @@ make_save_value (void *pointer, ptrdiff_t integer)
   register Lisp_Object val;
   register struct Lisp_Save_Value *p;
 
-  val = allocate_misc ();
-  XMISCTYPE (val) = Lisp_Misc_Save_Value;
+  val = allocate_misc (Lisp_Misc_Save_Value);
   p = XSAVE_VALUE (val);
   p->pointer = pointer;
   p->integer = integer;
@@ -3585,6 +3666,21 @@ make_save_value (void *pointer, ptrdiff_t integer)
   return val;
 }
 
+/* Return a Lisp_Misc_Overlay object with specified START, END and PLIST.  */
+
+Lisp_Object
+build_overlay (Lisp_Object start, Lisp_Object end, Lisp_Object plist)
+{
+  register Lisp_Object overlay;
+
+  overlay = allocate_misc (Lisp_Misc_Overlay);
+  OVERLAY_START (overlay) = start;
+  OVERLAY_END (overlay) = end;
+  OVERLAY_PLIST (overlay) = plist;
+  XOVERLAY (overlay)->next = NULL;
+  return overlay;
+}
+
 DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
        doc: /* Return a newly allocated marker which does not point at any place.  */)
   (void)
@@ -3592,8 +3688,7 @@ DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
   register Lisp_Object val;
   register struct Lisp_Marker *p;
 
-  val = allocate_misc ();
-  XMISCTYPE (val) = Lisp_Misc_Marker;
+  val = allocate_misc (Lisp_Misc_Marker);
   p = XMARKER (val);
   p->buffer = 0;
   p->bytepos = 0;
@@ -3618,8 +3713,7 @@ build_marker (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos)
   /* Every character is at least one byte.  */
   eassert (charpos <= bytepos);
 
-  obj = allocate_misc ();
-  XMISCTYPE (obj) = Lisp_Misc_Marker;
+  obj = allocate_misc (Lisp_Misc_Marker);
   m = XMARKER (obj);
   m->buffer = buf;
   m->charpos = charpos;
@@ -5220,8 +5314,7 @@ make_pure_vector (ptrdiff_t len)
 {
   Lisp_Object new;
   struct Lisp_Vector *p;
-  size_t size = (offsetof (struct Lisp_Vector, contents)
-                + len * sizeof (Lisp_Object));
+  size_t size = header_size + len * word_size;
 
   p = (struct Lisp_Vector *) pure_alloc (size, Lisp_Vectorlike);
   XSETVECTOR (new, p);
@@ -5322,26 +5415,38 @@ inhibit_garbage_collection (void)
   return count;
 }
 
+/* Used to avoid possible overflows when
+   converting from C to Lisp integers.  */
+
+static inline Lisp_Object
+bounded_number (EMACS_INT number)
+{
+  return make_number (min (MOST_POSITIVE_FIXNUM, number));
+}
 
 DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
        doc: /* Reclaim storage for Lisp objects no longer needed.
 Garbage collection happens automatically if you cons more than
 `gc-cons-threshold' bytes of Lisp data since previous garbage collection.
-`garbage-collect' normally returns a list with info on amount of space in use:
- ((USED-CONSES . FREE-CONSES) (USED-SYMS . FREE-SYMS)
-  (USED-MISCS . FREE-MISCS) USED-STRING-CHARS USED-VECTOR-SLOTS
-  (USED-FLOATS . FREE-FLOATS) (USED-INTERVALS . FREE-INTERVALS)
-  (USED-STRINGS . FREE-STRINGS))
+`garbage-collect' normally returns a list with info on amount of space in use,
+where each entry has the form (NAME SIZE USED FREE), where:
+- NAME is a symbol describing the kind of objects this entry represents,
+- SIZE is the number of bytes used by each one,
+- USED is the number of those objects that were found live in the heap,
+- FREE is the number of those objects that are not live but that Emacs
+  keeps around for future allocations (maybe because it does not know how
+  to return them to the OS).
 However, if there was overflow in pure space, `garbage-collect'
 returns nil, because real GC can't be done.
 See Info node `(elisp)Garbage Collection'.  */)
   (void)
 {
   register struct specbinding *bind;
+  register struct buffer *nextb;
   char stack_top_variable;
   ptrdiff_t i;
   int message_p;
-  Lisp_Object total[8];
+  Lisp_Object total[11];
   ptrdiff_t count = SPECPDL_INDEX ();
   EMACS_TIME t1;
 
@@ -5357,40 +5462,8 @@ See Info node `(elisp)Garbage Collection'.  */)
 
   /* Don't keep undo information around forever.
      Do this early on, so it is no problem if the user quits.  */
-  {
-    register struct buffer *nextb = all_buffers;
-
-    while (nextb)
-      {
-       /* If a buffer's undo list is Qt, that means that undo is
-          turned off in that buffer.  Calling truncate_undo_list on
-          Qt tends to return NULL, which effectively turns undo back on.
-          So don't call truncate_undo_list if undo_list is Qt.  */
-       if (! NILP (nextb->BUFFER_INTERNAL_FIELD (name))
-           && ! EQ (nextb->BUFFER_INTERNAL_FIELD (undo_list), Qt))
-         truncate_undo_list (nextb);
-
-       /* Shrink buffer gaps, but skip indirect and dead buffers.  */
-       if (nextb->base_buffer == 0 && !NILP (nextb->BUFFER_INTERNAL_FIELD (name))
-           && ! nextb->text->inhibit_shrinking)
-         {
-           /* 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->header.next.buffer;
-      }
-  }
+  FOR_EACH_BUFFER (nextb)
+    compact_buffer (nextb);
 
   t1 = current_emacs_time ();
 
@@ -5439,8 +5512,6 @@ See Info node `(elisp)Garbage Collection'.  */)
 
   gc_in_progress = 1;
 
-  /* clear_marks (); */
-
   /* Mark all the special slots that serve as the roots of accessibility.  */
 
   for (i = 0; i < staticidx; i++)
@@ -5504,48 +5575,42 @@ See Info node `(elisp)Garbage Collection'.  */)
      Look thru every buffer's undo list
      for elements that update markers that were not marked,
      and delete them.  */
-  {
-    register struct buffer *nextb = all_buffers;
-
-    while (nextb)
-      {
-       /* If a buffer's undo list is Qt, that means that undo is
-          turned off in that buffer.  Calling truncate_undo_list on
-          Qt tends to return NULL, which effectively turns undo back on.
-          So don't call truncate_undo_list if undo_list is Qt.  */
-       if (! EQ (nextb->BUFFER_INTERNAL_FIELD (undo_list), Qt))
-         {
-           Lisp_Object tail, prev;
-           tail = nextb->BUFFER_INTERNAL_FIELD (undo_list);
-           prev = Qnil;
-           while (CONSP (tail))
-             {
-               if (CONSP (XCAR (tail))
-                   && MARKERP (XCAR (XCAR (tail)))
-                   && !XMARKER (XCAR (XCAR (tail)))->gcmarkbit)
-                 {
-                   if (NILP (prev))
-                     nextb->BUFFER_INTERNAL_FIELD (undo_list) = tail = XCDR (tail);
-                   else
-                     {
-                       tail = XCDR (tail);
-                       XSETCDR (prev, tail);
-                     }
-                 }
-               else
-                 {
-                   prev = tail;
-                   tail = XCDR (tail);
-                 }
-             }
-         }
-       /* Now that we have stripped the elements that need not be in the
-          undo_list any more, we can finally mark the list.  */
-       mark_object (nextb->BUFFER_INTERNAL_FIELD (undo_list));
-
-       nextb = nextb->header.next.buffer;
-      }
-  }
+  FOR_EACH_BUFFER (nextb)
+    {
+      /* If a buffer's undo list is Qt, that means that undo is
+        turned off in that buffer.  Calling truncate_undo_list on
+        Qt tends to return NULL, which effectively turns undo back on.
+        So don't call truncate_undo_list if undo_list is Qt.  */
+      if (! EQ (nextb->BUFFER_INTERNAL_FIELD (undo_list), Qt))
+       {
+         Lisp_Object tail, prev;
+         tail = nextb->BUFFER_INTERNAL_FIELD (undo_list);
+         prev = Qnil;
+         while (CONSP (tail))
+           {
+             if (CONSP (XCAR (tail))
+                 && MARKERP (XCAR (XCAR (tail)))
+                 && !XMARKER (XCAR (XCAR (tail)))->gcmarkbit)
+               {
+                 if (NILP (prev))
+                   nextb->BUFFER_INTERNAL_FIELD (undo_list) = tail = XCDR (tail);
+                 else
+                   {
+                     tail = XCDR (tail);
+                     XSETCDR (prev, tail);
+                   }
+               }
+             else
+               {
+                 prev = tail;
+                 tail = XCDR (tail);
+               }
+           }
+       }
+      /* Now that we have stripped the elements that need not be in the
+        undo_list any more, we can finally mark the list.  */
+      mark_object (nextb->BUFFER_INTERNAL_FIELD (undo_list));
+    }
 
   gc_sweep ();
 
@@ -5563,12 +5628,11 @@ See Info node `(elisp)Garbage Collection'.  */)
 
   CHECK_CONS_LIST ();
 
-  /* clear_marks (); */
   gc_in_progress = 0;
 
   consing_since_gc = 0;
-  if (gc_cons_threshold < 10000)
-    gc_cons_threshold = 10000;
+  if (gc_cons_threshold < GC_DEFAULT_THRESHOLD / 10)
+    gc_cons_threshold = GC_DEFAULT_THRESHOLD / 10;
 
   gc_relative_threshold = 0;
   if (FLOATP (Vgc_cons_percentage))
@@ -5578,8 +5642,8 @@ See Info node `(elisp)Garbage Collection'.  */)
       tot += total_conses  * sizeof (struct Lisp_Cons);
       tot += total_symbols * sizeof (struct Lisp_Symbol);
       tot += total_markers * sizeof (union Lisp_Misc);
-      tot += total_string_size;
-      tot += total_vector_size * sizeof (Lisp_Object);
+      tot += total_string_bytes;
+      tot += total_vector_slots * word_size;
       tot += total_floats  * sizeof (struct Lisp_Float);
       tot += total_intervals * sizeof (struct interval);
       tot += total_strings * sizeof (struct Lisp_String);
@@ -5604,20 +5668,51 @@ See Info node `(elisp)Garbage Collection'.  */)
 
   unbind_to (count, Qnil);
 
-  total[0] = Fcons (make_number (total_conses),
-                   make_number (total_free_conses));
-  total[1] = Fcons (make_number (total_symbols),
-                   make_number (total_free_symbols));
-  total[2] = Fcons (make_number (total_markers),
-                   make_number (total_free_markers));
-  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[6] = Fcons (make_number (total_intervals),
-                   make_number (total_free_intervals));
-  total[7] = Fcons (make_number (total_strings),
-                   make_number (total_free_strings));
+  total[0] = list4 (Qcons, make_number (sizeof (struct Lisp_Cons)),
+                   bounded_number (total_conses),
+                    bounded_number (total_free_conses));
+
+  total[1] = list4 (Qsymbol, make_number (sizeof (struct Lisp_Symbol)),
+                   bounded_number (total_symbols),
+                    bounded_number (total_free_symbols));
+
+  total[2] = list4 (Qmisc, make_number (sizeof (union Lisp_Misc)),
+                   bounded_number (total_markers),
+                   bounded_number (total_free_markers));
+
+  total[3] = list4 (Qstring, make_number (sizeof (struct Lisp_String)),
+                   bounded_number (total_strings),
+                   bounded_number (total_free_strings));
+
+  total[4] = list3 (Qstring_bytes, make_number (1),
+                   bounded_number (total_string_bytes));
+
+  total[5] = list3 (Qvector, make_number (sizeof (struct Lisp_Vector)),
+                   bounded_number (total_vectors));
+
+  total[6] = list4 (Qvector_slots, make_number (word_size),
+                   bounded_number (total_vector_slots),
+                   bounded_number (total_free_vector_slots));
+
+  total[7] = list4 (Qfloat, make_number (sizeof (struct Lisp_Float)),
+                   bounded_number (total_floats),
+                    bounded_number (total_free_floats));
+
+  total[8] = list4 (Qinterval, make_number (sizeof (struct interval)),
+                   bounded_number (total_intervals),
+                    bounded_number (total_free_intervals));
+
+  total[9] = list3 (Qbuffer, make_number (sizeof (struct buffer)),
+                   bounded_number (total_buffers));
+
+  total[10] = list4 (Qheap, make_number (1024),
+#ifdef DOUG_LEA_MALLOC
+                    bounded_number ((mallinfo ().uordblks + 1023) >> 10),
+                    bounded_number ((mallinfo ().fordblks + 1023) >> 10)
+#else
+                    Qnil, Qnil
+#endif
+                    );
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
   {
@@ -5915,9 +6010,10 @@ mark_object (Lisp_Object arg)
 #ifdef GC_CHECK_MARKED_OBJECTS
            if (po != &buffer_defaults && po != &buffer_local_symbols)
              {
-               struct buffer *b = all_buffers;
-               for (; b && b != po; b = b->header.next.buffer)
-                 ;
+               struct buffer *b;
+               FOR_EACH_BUFFER (b)
+                 if (b == po)
+                   break;
                if (b == NULL)
                  abort ();
              }
@@ -6518,6 +6614,7 @@ gc_sweep (void)
   {
     register struct buffer *buffer = all_buffers, *prev = 0, *next;
 
+    total_buffers = 0;
     while (buffer)
       if (!VECTOR_MARKED_P (buffer))
        {
@@ -6533,6 +6630,7 @@ gc_sweep (void)
        {
          VECTOR_UNMARK (buffer);
          UNMARK_BALANCE_INTERVALS (BUF_INTERVALS (buffer));
+         total_buffers++;
          prev = buffer, buffer = buffer->header.next.buffer;
        }
   }
@@ -6563,36 +6661,6 @@ We divide the value by 1024 to make sure it fits in a Lisp integer.  */)
   return end;
 }
 
-DEFUN ("memory-free", Fmemory_free, Smemory_free, 0, 0, 0,
-       doc: /* Return a list of two counters that measure how much free memory
-is hold by the Emacs process.  Both counters are in KBytes.  First
-counter shows how much memory holds in a free lists maintained by
-the Emacs itself.  Second counter shows how much free memory is in
-the heap (freed by Emacs but not released back to the operating
-system).  If the second counter is zero, heap statistics is not
-available.  */)
-     (void)
-{
-  Lisp_Object data[2];
-  
-  data[0] = make_number
-    (min (MOST_POSITIVE_FIXNUM,
-         (total_free_conses * sizeof (struct Lisp_Cons)
-          + total_free_markers * sizeof (union Lisp_Misc)
-          + total_free_symbols * sizeof (struct Lisp_Symbol)
-          + total_free_floats * sizeof (struct Lisp_Float)
-          + total_free_intervals * sizeof (struct interval)
-          + total_free_strings * sizeof (struct Lisp_String)
-          + total_free_vector_bytes) / 1024));
-#ifdef DOUG_LEA_MALLOC
-  data[1] = make_number
-    (min (MOST_POSITIVE_FIXNUM, mallinfo ().fordblks / 1024));
-#else
-  data[1] = make_number (0);
-#endif
-  return Flist (2, data);
-}
-
 DEFUN ("memory-use-counts", Fmemory_use_counts, Smemory_use_counts, 0, 0, 0,
        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.
@@ -6608,18 +6676,15 @@ Frames, windows, buffers, and subprocesses count as vectors
   (but the contents of a buffer's text do not count here).  */)
   (void)
 {
-  Lisp_Object consed[8];
-
-  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);
+  return listn (CONSTYPE_HEAP, 8,
+               bounded_number (cons_cells_consed),
+               bounded_number (floats_consed),
+               bounded_number (vector_cells_consed),
+               bounded_number (symbols_consed),
+               bounded_number (string_chars_consed),
+               bounded_number (misc_objects_consed),
+               bounded_number (intervals_consed),
+               bounded_number (strings_consed));
 }
 
 /* Find at most FIND_MAX symbols which have OBJ as their value or
@@ -6713,7 +6778,7 @@ init_alloc_once (void)
 #endif
 
   refill_memory_reserve ();
-  gc_cons_threshold = 100000 * sizeof (Lisp_Object);
+  gc_cons_threshold = GC_DEFAULT_THRESHOLD;
 }
 
 void
@@ -6800,13 +6865,17 @@ do hash-consing of the objects allocated to pure space.  */);
   /* We build this in advance because if we wait until we need it, we might
      not be able to allocate the memory to hold it.  */
   Vmemory_signal_data
-    = pure_cons (Qerror,
-                pure_cons (build_pure_c_string ("Memory exhausted--use M-x save-some-buffers then exit and restart Emacs"), Qnil));
+    = listn (CONSTYPE_PURE, 2, Qerror,
+            build_pure_c_string ("Memory exhausted--use M-x save-some-buffers then exit and restart Emacs"));
 
   DEFVAR_LISP ("memory-full", Vmemory_full,
               doc: /* Non-nil means Emacs cannot get much more Lisp memory.  */);
   Vmemory_full = Qnil;
 
+  DEFSYM (Qstring_bytes, "string-bytes");
+  DEFSYM (Qvector_slots, "vector-slots");
+  DEFSYM (Qheap, "heap");
+
   DEFSYM (Qgc_cons_threshold, "gc-cons-threshold");
   DEFSYM (Qchar_table_extra_slots, "char-table-extra-slots");
 
@@ -6829,10 +6898,48 @@ The time is in seconds as a floating point value.  */);
   defsubr (&Spurecopy);
   defsubr (&Sgarbage_collect);
   defsubr (&Smemory_limit);
-  defsubr (&Smemory_free);
   defsubr (&Smemory_use_counts);
 
 #if GC_MARK_STACK == GC_USE_GCPROS_CHECK_ZOMBIES
   defsubr (&Sgc_status);
 #endif
 }
+
+/* Make some symbols visible to GDB.  This section is last, so that
+   the #undef lines don't mess up later code.  */
+
+/* When compiled with GCC, GDB might say "No enum type named
+   pvec_type" if we don't have at least one symbol with that type, and
+   then xbacktrace could fail.  Similarly for the other enums and
+   their values.  */
+union
+{
+  enum CHECK_LISP_OBJECT_TYPE CHECK_LISP_OBJECT_TYPE;
+  enum enum_USE_LSB_TAG enum_USE_LSB_TAG;
+  enum Lisp_Bits Lisp_Bits;
+  enum More_Lisp_Bits More_Lisp_Bits;
+  enum pvec_type pvec_type;
+} const EXTERNALLY_VISIBLE gdb_make_enums_visible = {0};
+
+/* These symbols cannot be done as enums, since values might not be
+   in 'int' range.  Each symbol X has a corresponding X_VAL symbol,
+   verified to have the correct value.  */
+
+#define ARRAY_MARK_FLAG_VAL PTRDIFF_MIN
+#define PSEUDOVECTOR_FLAG_VAL (PTRDIFF_MAX - PTRDIFF_MAX / 2)
+#define VALMASK_VAL (USE_LSB_TAG ? -1 << GCTYPEBITS : VAL_MAX)
+
+verify (ARRAY_MARK_FLAG_VAL == ARRAY_MARK_FLAG);
+verify (PSEUDOVECTOR_FLAG_VAL == PSEUDOVECTOR_FLAG);
+verify (VALMASK_VAL == VALMASK);
+
+#undef ARRAY_MARK_FLAG
+#undef PSEUDOVECTOR_FLAG
+#undef VALMASK
+
+ptrdiff_t const EXTERNALLY_VISIBLE
+  ARRAY_MARK_FLAG = ARRAY_MARK_FLAG_VAL,
+  PSEUDOVECTOR_FLAG = PSEUDOVECTOR_FLAG_VAL;
+
+EMACS_INT const EXTERNALLY_VISIBLE
+  VALMASK = VALMASK_VAL;