]> code.delx.au - gnu-emacs/blobdiff - src/alloc.c
Ibuffer change marks
[gnu-emacs] / src / alloc.c
index b5be0f6e69c543a12b1732c65d10c6a406071825..e25d91ff8aa072a177681dbe3ee2ff27de9527df 100644 (file)
@@ -20,12 +20,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#include <errno.h>
 #include <stdio.h>
 #include <limits.h>            /* For CHAR_BIT.  */
-
-#ifdef ENABLE_CHECKING
-#include <signal.h>            /* For SIGABRT.  */
-#endif
+#include <signal.h>            /* For SIGABRT, SIGDANGER.  */
 
 #ifdef HAVE_PTHREAD
 #include <pthread.h>
@@ -35,6 +33,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "dispextern.h"
 #include "intervals.h"
 #include "puresize.h"
+#include "sheap.h"
 #include "systime.h"
 #include "character.h"
 #include "buffer.h"
@@ -58,6 +57,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "dosfns.h"            /* For dos_memory_info.  */
 #endif
 
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
 #if (defined ENABLE_CHECKING                   \
      && defined HAVE_VALGRIND_VALGRIND_H       \
      && !defined USE_VALGRIND)
@@ -106,8 +109,6 @@ my_heap_start (void)
 
 #ifdef DOUG_LEA_MALLOC
 
-#include <malloc.h>
-
 /* Specify maximum number of areas to mmap.  It would be nice to use a
    value that explicitly means "no limit".  */
 
@@ -117,18 +118,6 @@ my_heap_start (void)
    inside glibc's malloc.  */
 static void *malloc_state_ptr;
 
-/* Get and free this pointer; useful around unexec.  */
-void
-alloc_unexec_pre (void)
-{
-  malloc_state_ptr = malloc_get_state ();
-}
-void
-alloc_unexec_post (void)
-{
-  free (malloc_state_ptr);
-}
-
 /* Restore the dumped malloc state.  Because malloc can be invoked
    even before main (e.g. by the dynamic linker), the dumped malloc
    state must be restored as early as possible using this special hook.  */
@@ -162,21 +151,50 @@ malloc_initialize_hook (void)
                }
        }
 
-      malloc_set_state (malloc_state_ptr);
+      if (malloc_set_state (malloc_state_ptr) != 0)
+       emacs_abort ();
 # ifndef XMALLOC_OVERRUN_CHECK
       alloc_unexec_post ();
 # endif
     }
 }
 
+/* Declare the malloc initialization hook, which runs before 'main' starts.
+   EXTERNALLY_VISIBLE works around Bug#22522.  */
 # ifndef __MALLOC_HOOK_VOLATILE
 #  define __MALLOC_HOOK_VOLATILE
 # endif
-voidfuncptr __MALLOC_HOOK_VOLATILE __malloc_initialize_hook
+voidfuncptr __MALLOC_HOOK_VOLATILE __malloc_initialize_hook EXTERNALLY_VISIBLE
   = malloc_initialize_hook;
 
 #endif
 
+/* Allocator-related actions to do just before and after unexec.  */
+
+void
+alloc_unexec_pre (void)
+{
+#ifdef DOUG_LEA_MALLOC
+  malloc_state_ptr = malloc_get_state ();
+  if (!malloc_state_ptr)
+    fatal ("malloc_get_state: %s", strerror (errno));
+#endif
+#ifdef HYBRID_MALLOC
+  bss_sbrk_did_unexec = true;
+#endif
+}
+
+void
+alloc_unexec_post (void)
+{
+#ifdef DOUG_LEA_MALLOC
+  free (malloc_state_ptr);
+#endif
+#ifdef HYBRID_MALLOC
+  bss_sbrk_did_unexec = false;
+#endif
+}
+
 /* Mark, unmark, query mark bit of a Lisp string.  S must be a pointer
    to a struct Lisp_String.  */
 
@@ -471,7 +489,7 @@ static void *pure_alloc (size_t, int);
 /* Return PTR rounded up to the next multiple of ALIGNMENT.  */
 
 static void *
-ALIGN (void *ptr, int alignment)
+pointer_align (void *ptr, int alignment)
 {
   return (void *) ROUNDUP ((uintptr_t) ptr, alignment);
 }
@@ -550,6 +568,8 @@ static struct Lisp_Finalizer doomed_finalizers;
                                Malloc
  ************************************************************************/
 
+#if defined SIGDANGER || (!defined SYSTEM_MALLOC && !defined HYBRID_MALLOC)
+
 /* Function malloc calls this if it finds we are near exhausting storage.  */
 
 void
@@ -558,6 +578,7 @@ malloc_warning (const char *str)
   pending_malloc_warning = str;
 }
 
+#endif
 
 /* Display an already-pending malloc warning.  */
 
@@ -1111,23 +1132,14 @@ lisp_free (void *block)
    unexmacosx.c, so don't use it on Darwin.  */
 
 #if ! ADDRESS_SANITIZER && !defined DARWIN_OS
-# if !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC && !defined HYBRID_MALLOC
-#  define USE_ALIGNED_ALLOC 1
-#  ifndef HAVE_ALIGNED_ALLOC
-/* Defined in gmalloc.c.  */
-void *aligned_alloc (size_t, size_t);
-#  endif
-# elif defined HYBRID_MALLOC
-#  if defined HAVE_ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN
-#   define USE_ALIGNED_ALLOC 1
-#   define aligned_alloc hybrid_aligned_alloc
-/* Defined in gmalloc.c.  */
-void *aligned_alloc (size_t, size_t);
-#  endif
-# elif defined HAVE_ALIGNED_ALLOC
+# if (defined HAVE_ALIGNED_ALLOC                                       \
+      || (defined HYBRID_MALLOC                                                \
+         ? defined HAVE_POSIX_MEMALIGN                                 \
+         : !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC))
 #  define USE_ALIGNED_ALLOC 1
-# elif defined HAVE_POSIX_MEMALIGN
+# elif !defined HYBRID_MALLOC && defined HAVE_POSIX_MEMALIGN
 #  define USE_ALIGNED_ALLOC 1
+#  define aligned_alloc my_aligned_alloc /* Avoid collision with lisp.h.  */
 static void *
 aligned_alloc (size_t alignment, size_t size)
 {
@@ -1166,16 +1178,18 @@ struct ablock
     char payload[BLOCK_BYTES];
     struct ablock *next_free;
   } x;
-  /* `abase' is the aligned base of the ablocks.  */
-  /* It is overloaded to hold the virtual `busy' field that counts
-     the number of used ablock in the parent ablocks.
-     The first ablock has the `busy' field, the others have the `abase'
-     field.  To tell the difference, we assume that pointers will have
-     integer values larger than 2 * ABLOCKS_SIZE.  The lowest bit of `busy'
-     is used to tell whether the real base of the parent ablocks is `abase'
-     (if not, the word before the first ablock holds a pointer to the
-     real base).  */
+
+  /* ABASE is the aligned base of the ablocks.  It is overloaded to
+     hold a virtual "busy" field that counts twice the number of used
+     ablock values in the parent ablocks, plus one if the real base of
+     the parent ablocks is ABASE (if the "busy" field is even, the
+     word before the first ablock holds a pointer to the real base).
+     The first ablock has a "busy" ABASE, and the others have an
+     ordinary pointer ABASE.  To tell the difference, the code assumes
+     that pointers, when cast to uintptr_t, are at least 2 *
+     ABLOCKS_SIZE + 1.  */
   struct ablocks *abase;
+
   /* The padding of all but the last ablock is unused.  The padding of
      the last ablock in an ablocks is not allocated.  */
 #if BLOCK_PADDING
@@ -1194,18 +1208,18 @@ struct ablocks
 
 #define ABLOCK_ABASE(block) \
   (((uintptr_t) (block)->abase) <= (1 + 2 * ABLOCKS_SIZE)      \
-   ? (struct ablocks *)(block)                                 \
+   ? (struct ablocks *) (block)                                        \
    : (block)->abase)
 
 /* Virtual `busy' field.  */
-#define ABLOCKS_BUSY(abase) ((abase)->blocks[0].abase)
+#define ABLOCKS_BUSY(a_base) ((a_base)->blocks[0].abase)
 
 /* Pointer to the (not necessarily aligned) malloc block.  */
 #ifdef USE_ALIGNED_ALLOC
 #define ABLOCKS_BASE(abase) (abase)
 #else
 #define ABLOCKS_BASE(abase) \
-  (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void **)abase)[-1])
+  (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void **) (abase))[-1])
 #endif
 
 /* The list of free ablock.   */
@@ -1231,7 +1245,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
   if (!free_ablock)
     {
       int i;
-      intptr_t aligned; /* int gets warning casting to 64-bit pointer.  */
+      bool aligned;
 
 #ifdef DOUG_LEA_MALLOC
       if (!mmap_lisp_allowed_p ())
@@ -1242,7 +1256,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
       abase = base = aligned_alloc (BLOCK_ALIGN, ABLOCKS_BYTES);
 #else
       base = malloc (ABLOCKS_BYTES);
-      abase = ALIGN (base, BLOCK_ALIGN);
+      abase = pointer_align (base, BLOCK_ALIGN);
 #endif
 
       if (base == 0)
@@ -1287,13 +1301,14 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
          abase->blocks[i].x.next_free = free_ablock;
          free_ablock = &abase->blocks[i];
        }
-      ABLOCKS_BUSY (abase) = (struct ablocks *) aligned;
+      intptr_t ialigned = aligned;
+      ABLOCKS_BUSY (abase) = (struct ablocks *) ialigned;
 
-      eassert (0 == ((uintptr_t) abase) % BLOCK_ALIGN);
+      eassert ((uintptr_t) abase % BLOCK_ALIGN == 0);
       eassert (ABLOCK_ABASE (&abase->blocks[3]) == abase); /* 3 is arbitrary */
       eassert (ABLOCK_ABASE (&abase->blocks[0]) == abase);
       eassert (ABLOCKS_BASE (abase) == base);
-      eassert (aligned == (intptr_t) ABLOCKS_BUSY (abase));
+      eassert ((intptr_t) ABLOCKS_BUSY (abase) == aligned);
     }
 
   abase = ABLOCK_ABASE (free_ablock);
@@ -1329,12 +1344,14 @@ lisp_align_free (void *block)
   ablock->x.next_free = free_ablock;
   free_ablock = ablock;
   /* Update busy count.  */
-  ABLOCKS_BUSY (abase)
-    = (struct ablocks *) (-2 + (intptr_t) ABLOCKS_BUSY (abase));
+  intptr_t busy = (intptr_t) ABLOCKS_BUSY (abase) - 2;
+  eassume (0 <= busy && busy <= 2 * ABLOCKS_SIZE - 1);
+  ABLOCKS_BUSY (abase) = (struct ablocks *) busy;
 
-  if (2 > (intptr_t) ABLOCKS_BUSY (abase))
+  if (busy < 2)
     { /* All the blocks are free.  */
-      int i = 0, aligned = (intptr_t) ABLOCKS_BUSY (abase);
+      int i = 0;
+      bool aligned = busy;
       struct ablock **tem = &free_ablock;
       struct ablock *atop = &abase->blocks[aligned ? ABLOCKS_SIZE : ABLOCKS_SIZE - 1];
 
@@ -2166,89 +2183,96 @@ free_large_strings (void)
 static void
 compact_small_strings (void)
 {
-  struct sblock *b, *tb, *next;
-  sdata *from, *to, *end, *tb_end;
-  sdata *to_end, *from_end;
-
   /* TB is the sblock we copy to, TO is the sdata within TB we copy
      to, and TB_END is the end of TB.  */
-  tb = oldest_sblock;
-  tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
-  to = tb->data;
-
-  /* Step through the blocks from the oldest to the youngest.  We
-     expect that old blocks will stabilize over time, so that less
-     copying will happen this way.  */
-  for (b = oldest_sblock; b; b = b->next)
+  struct sblock *tb = oldest_sblock;
+  if (tb)
     {
-      end = b->next_free;
-      eassert ((char *) end <= (char *) b + SBLOCK_SIZE);
+      sdata *tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
+      sdata *to = tb->data;
 
-      for (from = b->data; from < end; from = from_end)
+      /* Step through the blocks from the oldest to the youngest.  We
+        expect that old blocks will stabilize over time, so that less
+        copying will happen this way.  */
+      struct sblock *b = tb;
+      do
        {
-         /* Compute the next FROM here because copying below may
-            overwrite data we need to compute it.  */
-         ptrdiff_t nbytes;
-         struct Lisp_String *s = from->string;
+         sdata *end = b->next_free;
+         eassert ((char *) end <= (char *) b + SBLOCK_SIZE);
+
+         for (sdata *from = b->data; from < end; )
+           {
+             /* Compute the next FROM here because copying below may
+                overwrite data we need to compute it.  */
+             ptrdiff_t nbytes;
+             struct Lisp_String *s = from->string;
 
 #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 (s && string_bytes (s) != SDATA_NBYTES (from))
-           emacs_abort ();
+             /* Check that the string size recorded in the string is the
+                same as the one recorded in the sdata structure.  */
+             if (s && string_bytes (s) != SDATA_NBYTES (from))
+               emacs_abort ();
 #endif /* GC_CHECK_STRING_BYTES */
 
-         nbytes = s ? STRING_BYTES (s) : SDATA_NBYTES (from);
-         eassert (nbytes <= LARGE_STRING_BYTES);
+             nbytes = s ? STRING_BYTES (s) : SDATA_NBYTES (from);
+             eassert (nbytes <= LARGE_STRING_BYTES);
 
-         nbytes = SDATA_SIZE (nbytes);
-         from_end = (sdata *) ((char *) from + nbytes + GC_STRING_EXTRA);
+             nbytes = SDATA_SIZE (nbytes);
+             sdata *from_end = (sdata *) ((char *) from
+                                          + nbytes + GC_STRING_EXTRA);
 
 #ifdef GC_CHECK_STRING_OVERRUN
-         if (memcmp (string_overrun_cookie,
-                     (char *) from_end - GC_STRING_OVERRUN_COOKIE_SIZE,
-                     GC_STRING_OVERRUN_COOKIE_SIZE))
-           emacs_abort ();
+             if (memcmp (string_overrun_cookie,
+                         (char *) from_end - GC_STRING_OVERRUN_COOKIE_SIZE,
+                         GC_STRING_OVERRUN_COOKIE_SIZE))
+               emacs_abort ();
 #endif
 
-         /* Non-NULL S means it's alive.  Copy its data.  */
-         if (s)
-           {
-             /* If TB is full, proceed with the next sblock.  */
-             to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
-             if (to_end > tb_end)
+             /* Non-NULL S means it's alive.  Copy its data.  */
+             if (s)
                {
-                 tb->next_free = to;
-                 tb = tb->next;
-                 tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
-                 to = tb->data;
-                 to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
-               }
+                 /* If TB is full, proceed with the next sblock.  */
+                 sdata *to_end = (sdata *) ((char *) to
+                                            + nbytes + GC_STRING_EXTRA);
+                 if (to_end > tb_end)
+                   {
+                     tb->next_free = to;
+                     tb = tb->next;
+                     tb_end = (sdata *) ((char *) tb + SBLOCK_SIZE);
+                     to = tb->data;
+                     to_end = (sdata *) ((char *) to + nbytes + GC_STRING_EXTRA);
+                   }
 
-             /* Copy, and update the string's `data' pointer.  */
-             if (from != to)
-               {
-                 eassert (tb != b || to < from);
-                 memmove (to, from, nbytes + GC_STRING_EXTRA);
-                 to->string->data = SDATA_DATA (to);
-               }
+                 /* Copy, and update the string's `data' pointer.  */
+                 if (from != to)
+                   {
+                     eassert (tb != b || to < from);
+                     memmove (to, from, nbytes + GC_STRING_EXTRA);
+                     to->string->data = SDATA_DATA (to);
+                   }
 
-             /* Advance past the sdata we copied to.  */
-             to = to_end;
+                 /* Advance past the sdata we copied to.  */
+                 to = to_end;
+               }
+             from = from_end;
            }
+         b = b->next;
        }
-    }
+      while (b);
 
-  /* The rest of the sblocks following TB don't contain live data, so
-     we can free them.  */
-  for (b = tb->next; b; b = next)
-    {
-      next = b->next;
-      lisp_free (b);
+      /* The rest of the sblocks following TB don't contain live data, so
+        we can free them.  */
+      for (b = tb->next; b; )
+       {
+         struct sblock *next = b->next;
+         lisp_free (b);
+         b = next;
+       }
+
+      tb->next_free = to;
+      tb->next = NULL;
     }
 
-  tb->next_free = to;
-  tb->next = NULL;
   current_sblock = tb;
 }
 
@@ -3391,22 +3415,13 @@ allocate_buffer (void)
 DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0,
        doc: /* Return a newly created vector of length LENGTH, with each element being INIT.
 See also the function `vector'.  */)
-  (register Lisp_Object length, Lisp_Object init)
+  (Lisp_Object length, Lisp_Object init)
 {
-  Lisp_Object vector;
-  register ptrdiff_t sizei;
-  register ptrdiff_t i;
-  register struct Lisp_Vector *p;
-
   CHECK_NATNUM (length);
-
-  p = allocate_vector (XFASTINT (length));
-  sizei = XFASTINT (length);
-  for (i = 0; i < sizei; i++)
+  struct Lisp_Vector *p = allocate_vector (XFASTINT (length));
+  for (ptrdiff_t i = 0; i < XFASTINT (length); i++)
     p->contents[i] = init;
-
-  XSETVECTOR (vector, p);
-  return vector;
+  return make_lisp_ptr (p, Lisp_Vectorlike);
 }
 
 DEFUN ("vector", Fvector, Svector, 0, MANY, 0,
@@ -3415,12 +3430,9 @@ Any number of arguments, even zero arguments, are allowed.
 usage: (vector &rest OBJECTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  ptrdiff_t i;
-  register Lisp_Object val = make_uninit_vector (nargs);
-  register struct Lisp_Vector *p = XVECTOR (val);
-
-  for (i = 0; i < nargs; i++)
-    p->contents[i] = args[i];
+  Lisp_Object val = make_uninit_vector (nargs);
+  struct Lisp_Vector *p = XVECTOR (val);
+  memcpy (p->contents, args, nargs * sizeof *args);
   return val;
 }
 
@@ -3459,9 +3471,8 @@ stack before executing the byte-code.
 usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INTERACTIVE-SPEC &rest ELEMENTS)  */)
   (ptrdiff_t nargs, Lisp_Object *args)
 {
-  ptrdiff_t i;
-  register Lisp_Object val = make_uninit_vector (nargs);
-  register struct Lisp_Vector *p = XVECTOR (val);
+  Lisp_Object val = make_uninit_vector (nargs);
+  struct Lisp_Vector *p = XVECTOR (val);
 
   /* We used to purecopy everything here, if purify-flag was set.  This worked
      OK for Emacs-23, but with Emacs-24's lexical binding code, it can be
@@ -3471,8 +3482,7 @@ usage: (make-byte-code ARGLIST BYTE-CODE CONSTANTS DEPTH &optional DOCSTRING INT
      just wasteful and other times plainly wrong (e.g. those free vars may want
      to be setcar'd).  */
 
-  for (i = 0; i < nargs; i++)
-    p->contents[i] = args[i];
+  memcpy (p->contents, args, nargs * sizeof *args);
   make_byte_code (p);
   XSETCOMPILED (val, p);
   return val;
@@ -3730,7 +3740,6 @@ make_save_ptr_int (void *a, ptrdiff_t b)
   return val;
 }
 
-#if ! (defined USE_X_TOOLKIT || defined USE_GTK)
 Lisp_Object
 make_save_ptr_ptr (void *a, void *b)
 {
@@ -3741,7 +3750,6 @@ make_save_ptr_ptr (void *a, void *b)
   p->data[1].pointer = b;
   return val;
 }
-#endif
 
 Lisp_Object
 make_save_funcptr_ptr_obj (void (*a) (void), void *b, Lisp_Object c)
@@ -5170,7 +5178,7 @@ pure_alloc (size_t size, int type)
     {
       /* Allocate space for a Lisp object from the beginning of the free
         space with taking account of alignment.  */
-      result = ALIGN (purebeg + pure_bytes_used_lisp, GCALIGNMENT);
+      result = pointer_align (purebeg + pure_bytes_used_lisp, GCALIGNMENT);
       pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size;
     }
   else
@@ -5433,7 +5441,7 @@ purecopy (Lisp_Object obj)
     }
   else
     {
-      Lisp_Object fmt = build_pure_c_string ("Don't know how to purify: %S");
+      AUTO_STRING (fmt, "Don't know how to purify: %S");
       Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj)));
     }
 
@@ -5664,7 +5672,7 @@ garbage_collect_1 (void *end)
     return Qnil;
 
   /* Record this function, so it appears on the profiler's backtraces.  */
-  record_in_backtrace (Qautomatic_gc, 0, 0);
+  record_in_backtrace (QAutomatic_GC, 0, 0);
 
   check_cons_list ();
 
@@ -6127,7 +6135,7 @@ mark_face_cache (struct face_cache *c)
       int i, j;
       for (i = 0; i < c->used; ++i)
        {
-         struct face *face = FACE_FROM_ID (c->f, i);
+         struct face *face = FACE_FROM_ID_OR_NULL (c->f, i);
 
          if (face)
            {
@@ -7224,21 +7232,6 @@ die (const char *msg, const char *file, int line)
 
 #if defined (ENABLE_CHECKING) && USE_STACK_LISP_OBJECTS
 
-/* Debugging check whether STR is ASCII-only.  */
-
-const char *
-verify_ascii (const char *str)
-{
-  const unsigned char *ptr = (unsigned char *) str, *end = ptr + strlen (str);
-  while (ptr < end)
-    {
-      int c = STRING_CHAR_ADVANCE (ptr);
-      if (!ASCII_CHAR_P (c))
-       emacs_abort ();
-    }
-  return str;
-}
-
 /* Stress alloca with inconveniently sized requests and check
    whether all allocated areas may be used for Lisp_Object.  */
 
@@ -7394,7 +7387,7 @@ do hash-consing of the objects allocated to pure space.  */);
   DEFSYM (Qstring_bytes, "string-bytes");
   DEFSYM (Qvector_slots, "vector-slots");
   DEFSYM (Qheap, "heap");
-  DEFSYM (Qautomatic_gc, "Automatic GC");
+  DEFSYM (QAutomatic_GC, "Automatic GC");
 
   DEFSYM (Qgc_cons_threshold, "gc-cons-threshold");
   DEFSYM (Qchar_table_extra_slots, "char-table-extra-slots");