]> git.eshelyaron.com Git - emacs.git/commitdiff
Simplify alloc by assuming MALLOC_IS_LISP_ALIGNED
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 16 Jan 2025 07:32:43 +0000 (23:32 -0800)
committerEshel Yaron <me@eshelyaron.com>
Sat, 18 Jan 2025 22:00:57 +0000 (23:00 +0100)
Problem reported by Hong Xu <https://bugs.gnu.org/75551#14>.
* src/alloc.c (MALLOC_IS_LISP_ALIGNED): static_assert it,
since it is true on all current Emacs platforms.
All uses simplified to assume it is true.
(xmalloc, xzalloc, xrealloc, lisp_malloc): Just use
malloc/calloc/realloc.  Since we are using the malloc-gnu
and realloc-posix modules, we need not worry about whether
these functions return a null pointer for zero-size requests.
(xrealloc): Stop worrying about no-longer-existing platforms
where realloc (nullptr, ...) did not work.
(laligned, lmalloc, lrealloc): Remove.  All uses removed.

(cherry picked from commit d3a2ec5210746a942263d5e18ee3b8190b9698e1)

src/alloc.c

index 8307c74c106babdf8dc557cb447aee14fe7ab626..e7290c55f88d698cfcaf9d2899a0d1168ac7dfce 100644 (file)
@@ -704,21 +704,24 @@ buffer_memory_full (ptrdiff_t nbytes)
   ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b))
 
 /* Alignment needed for memory blocks that are allocated via malloc
-   and that contain Lisp objects.  On typical hosts malloc already
-   aligns sufficiently, but extra work is needed on oddball hosts
-   where Emacs would crash if malloc returned a non-GCALIGNED pointer.  */
+   and that contain Lisp objects.  */
 enum { LISP_ALIGNMENT = alignof (union { union emacs_align_type x;
                                         GCALIGNED_UNION_MEMBER }) };
 static_assert (LISP_ALIGNMENT % GCALIGNMENT == 0);
 
-/* True if malloc (N) is known to return storage suitably aligned for
-   Lisp objects whenever N is a multiple of LISP_ALIGNMENT.  In
-   practice this is true whenever alignof (max_align_t) is also a
+/* Verify Emacs's assumption that malloc (N) returns storage suitably
+   aligned for Lisp objects whenever N is a multiple of LISP_ALIGNMENT.
+   This assumption holds for current Emacs porting targets;
+   if the assumption fails on a new platform, this check should
+   cause compilation to fail and some porting work will need to be done.
+
+   In practice the assumption holds when alignof (max_align_t) is also a
    multiple of LISP_ALIGNMENT.  This works even for buggy platforms
    like MinGW circa 2020, where alignof (max_align_t) is 16 even though
    the malloc alignment is only 8, and where Emacs still works because
    it never does anything that requires an alignment of 16.  */
 enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 };
+static_assert (MALLOC_IS_LISP_ALIGNED);
 
 /* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol
    BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger.
@@ -759,9 +762,6 @@ malloc_unblock_input (void)
       malloc_probe (size);                     \
   } while (0)
 
-static void *lmalloc (size_t, bool) ATTRIBUTE_MALLOC_SIZE ((1));
-static void *lrealloc (void *, size_t);
-
 /* Like malloc but check for no memory and block interrupt input.  */
 
 void *
@@ -770,7 +770,7 @@ xmalloc (size_t size)
   void *val;
 
   MALLOC_BLOCK_INPUT;
-  val = lmalloc (size, false);
+  val = malloc (size);
   MALLOC_UNBLOCK_INPUT;
 
   if (!val)
@@ -787,7 +787,7 @@ xzalloc (size_t size)
   void *val;
 
   MALLOC_BLOCK_INPUT;
-  val = lmalloc (size, true);
+  val = calloc (1, size);
   MALLOC_UNBLOCK_INPUT;
 
   if (!val)
@@ -804,12 +804,7 @@ xrealloc (void *block, size_t size)
   void *val;
 
   MALLOC_BLOCK_INPUT;
-  /* Call lmalloc when BLOCK is null, for the benefit of long-obsolete
-     platforms lacking support for realloc (NULL, size).  */
-  if (! block)
-    val = lmalloc (size, false);
-  else
-    val = lrealloc (block, size);
+  val = realloc (block, size);
   MALLOC_UNBLOCK_INPUT;
 
   if (!val)
@@ -994,15 +989,23 @@ record_xmalloc (size_t size)
 }
 
 
-/* Like malloc but used for allocating Lisp data.  NBYTES is the
-   number of bytes to allocate, TYPE describes the intended use of the
-   allocated memory block (for strings, for conses, ...).  */
-
 #if ! USE_LSB_TAG
 extern void *lisp_malloc_loser;
 void *lisp_malloc_loser EXTERNALLY_VISIBLE;
 #endif
 
+/* Allocate memory for Lisp data.
+   NBYTES is the number of bytes to allocate; it must be Lisp-aligned.
+   If CLEARIT, arrange for the allocated memory to be cleared
+   by using calloc, which can be faster than malloc+memset.
+   TYPE describes the intended use of the allocated memory block
+   (for strings, for conses, ...).
+   Return a null pointer if and only if allocation failed.
+
+   Code allocating heap memory for Lisp should use this function to get
+   a pointer P; that way, if T is an enum Lisp_Type value and
+   L == make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.  */
+
 static void *
 lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
 {
@@ -1014,7 +1017,7 @@ lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
   allocated_mem_type = type;
 #endif
 
-  val = lmalloc (nbytes, clearit);
+  val = clearit ? calloc (1, nbytes) : malloc (nbytes);
 
 #if ! USE_LSB_TAG
   /* If the memory just allocated cannot be addressed thru a Lisp
@@ -1098,11 +1101,7 @@ aligned_alloc (size_t alignment, size_t size)
      Verify this for all arguments this function is given.  */
   static_assert (BLOCK_ALIGN % sizeof (void *) == 0
                 && POWER_OF_2 (BLOCK_ALIGN / sizeof (void *)));
-  static_assert (MALLOC_IS_LISP_ALIGNED
-                || (LISP_ALIGNMENT % sizeof (void *) == 0
-                    && POWER_OF_2 (LISP_ALIGNMENT / sizeof (void *))));
-  eassert (alignment == BLOCK_ALIGN
-          || (!MALLOC_IS_LISP_ALIGNED && alignment == LISP_ALIGNMENT));
+  eassert (alignment == BLOCK_ALIGN);
 
   void *p;
   return posix_memalign (&p, alignment, size) == 0 ? p : 0;
@@ -1350,81 +1349,6 @@ lisp_align_free (void *block)
   MALLOC_UNBLOCK_INPUT;
 }
 
-/* True if a malloc-returned pointer P is suitably aligned for SIZE,
-   where Lisp object alignment may be needed if SIZE is a multiple of
-   LISP_ALIGNMENT.  */
-
-static bool
-laligned (void *p, size_t size)
-{
-  return (MALLOC_IS_LISP_ALIGNED || (intptr_t) p % LISP_ALIGNMENT == 0
-         || size % LISP_ALIGNMENT != 0);
-}
-
-/* Like malloc and realloc except return null only on failure,
-   the result is Lisp-aligned if SIZE is, and lrealloc's pointer
-   argument must be nonnull.  Code allocating C heap memory
-   for a Lisp object should use one of these functions to obtain a
-   pointer P; that way, if T is an enum Lisp_Type value and L ==
-   make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
-
-   If CLEARIT, arrange for the allocated memory to be cleared.
-   This might use calloc, as calloc can be faster than malloc+memset.
-
-   On typical modern platforms these functions' loops do not iterate.
-   On now-rare (and perhaps nonexistent) platforms, the code can loop,
-   reallocating (typically with larger and larger sizes) until the
-   allocator returns a Lisp-aligned pointer.  This loop in
-   theory could repeat forever.  If an infinite loop is possible on a
-   platform, a build would surely loop and the builder can then send
-   us a bug report.  Adding a counter to try to detect any such loop
-   would complicate the code (and possibly introduce bugs, in code
-   that's never really exercised) for little benefit.  */
-
-static void *
-lmalloc (size_t size, bool clearit)
-{
-#ifdef USE_ALIGNED_ALLOC
-  if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
-    {
-      void *p = aligned_alloc (LISP_ALIGNMENT, size);
-      if (p)
-       {
-         if (clearit)
-           memclear (p, size);
-       }
-      else if (! (MALLOC_0_IS_NONNULL || size))
-       return aligned_alloc (LISP_ALIGNMENT, LISP_ALIGNMENT);
-      return p;
-    }
-#endif
-
-  while (true)
-    {
-      void *p = clearit ? calloc (1, size) : malloc (size);
-      if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p))
-       return p;
-      free (p);
-      size_t bigger;
-      if (!ckd_add (&bigger, size, LISP_ALIGNMENT))
-       size = bigger;
-    }
-}
-
-static void *
-lrealloc (void *p, size_t size)
-{
-  while (true)
-    {
-      p = realloc (p, size);
-      if (laligned (p, size) && (size || p))
-       return p;
-      size_t bigger;
-      if (!ckd_add (&bigger, size, LISP_ALIGNMENT))
-       size = bigger;
-    }
-}
-
 \f
 /***********************************************************************
                         Interval Allocation