From: Paul Eggert Date: Thu, 16 Jan 2025 07:32:43 +0000 (-0800) Subject: Simplify alloc by assuming MALLOC_IS_LISP_ALIGNED X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=9fb04ce7e9e7b0d89fd19523160c5acf917bb882;p=emacs.git Simplify alloc by assuming MALLOC_IS_LISP_ALIGNED Problem reported by Hong Xu . * 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) --- diff --git a/src/alloc.c b/src/alloc.c index 8307c74c106..e7290c55f88 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -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; - } -} - /*********************************************************************** Interval Allocation