Skip to content

Commit d3a2ec5

Browse files
committed
Simplify alloc by assuming MALLOC_IS_LISP_ALIGNED
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.
1 parent 29794c7 commit d3a2ec5

File tree

1 file changed

+26
-102
lines changed

1 file changed

+26
-102
lines changed

src/alloc.c

Lines changed: 26 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -704,21 +704,24 @@ buffer_memory_full (ptrdiff_t nbytes)
704704
((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b))
705705

706706
/* Alignment needed for memory blocks that are allocated via malloc
707-
and that contain Lisp objects. On typical hosts malloc already
708-
aligns sufficiently, but extra work is needed on oddball hosts
709-
where Emacs would crash if malloc returned a non-GCALIGNED pointer. */
707+
and that contain Lisp objects. */
710708
enum { LISP_ALIGNMENT = alignof (union { union emacs_align_type x;
711709
GCALIGNED_UNION_MEMBER }) };
712710
static_assert (LISP_ALIGNMENT % GCALIGNMENT == 0);
713711

714-
/* True if malloc (N) is known to return storage suitably aligned for
715-
Lisp objects whenever N is a multiple of LISP_ALIGNMENT. In
716-
practice this is true whenever alignof (max_align_t) is also a
712+
/* Verify Emacs's assumption that malloc (N) returns storage suitably
713+
aligned for Lisp objects whenever N is a multiple of LISP_ALIGNMENT.
714+
This assumption holds for current Emacs porting targets;
715+
if the assumption fails on a new platform, this check should
716+
cause compilation to fail and some porting work will need to be done.
717+
718+
In practice the assumption holds when alignof (max_align_t) is also a
717719
multiple of LISP_ALIGNMENT. This works even for buggy platforms
718720
like MinGW circa 2020, where alignof (max_align_t) is 16 even though
719721
the malloc alignment is only 8, and where Emacs still works because
720722
it never does anything that requires an alignment of 16. */
721723
enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 };
724+
static_assert (MALLOC_IS_LISP_ALIGNED);
722725

723726
/* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol
724727
BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger.
@@ -759,9 +762,6 @@ malloc_unblock_input (void)
759762
malloc_probe (size); \
760763
} while (0)
761764

762-
static void *lmalloc (size_t, bool) ATTRIBUTE_MALLOC_SIZE ((1));
763-
static void *lrealloc (void *, size_t);
764-
765765
/* Like malloc but check for no memory and block interrupt input. */
766766

767767
void *
@@ -770,7 +770,7 @@ xmalloc (size_t size)
770770
void *val;
771771

772772
MALLOC_BLOCK_INPUT;
773-
val = lmalloc (size, false);
773+
val = malloc (size);
774774
MALLOC_UNBLOCK_INPUT;
775775

776776
if (!val)
@@ -787,7 +787,7 @@ xzalloc (size_t size)
787787
void *val;
788788

789789
MALLOC_BLOCK_INPUT;
790-
val = lmalloc (size, true);
790+
val = calloc (1, size);
791791
MALLOC_UNBLOCK_INPUT;
792792

793793
if (!val)
@@ -804,12 +804,7 @@ xrealloc (void *block, size_t size)
804804
void *val;
805805

806806
MALLOC_BLOCK_INPUT;
807-
/* Call lmalloc when BLOCK is null, for the benefit of long-obsolete
808-
platforms lacking support for realloc (NULL, size). */
809-
if (! block)
810-
val = lmalloc (size, false);
811-
else
812-
val = lrealloc (block, size);
807+
val = realloc (block, size);
813808
MALLOC_UNBLOCK_INPUT;
814809

815810
if (!val)
@@ -994,15 +989,23 @@ record_xmalloc (size_t size)
994989
}
995990

996991

997-
/* Like malloc but used for allocating Lisp data. NBYTES is the
998-
number of bytes to allocate, TYPE describes the intended use of the
999-
allocated memory block (for strings, for conses, ...). */
1000-
1001992
#if ! USE_LSB_TAG
1002993
extern void *lisp_malloc_loser;
1003994
void *lisp_malloc_loser EXTERNALLY_VISIBLE;
1004995
#endif
1005996

997+
/* Allocate memory for Lisp data.
998+
NBYTES is the number of bytes to allocate; it must be Lisp-aligned.
999+
If CLEARIT, arrange for the allocated memory to be cleared
1000+
by using calloc, which can be faster than malloc+memset.
1001+
TYPE describes the intended use of the allocated memory block
1002+
(for strings, for conses, ...).
1003+
Return a null pointer if and only if allocation failed.
1004+
1005+
Code allocating heap memory for Lisp should use this function to get
1006+
a pointer P; that way, if T is an enum Lisp_Type value and
1007+
L == make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T. */
1008+
10061009
static void *
10071010
lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
10081011
{
@@ -1014,7 +1017,7 @@ lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
10141017
allocated_mem_type = type;
10151018
#endif
10161019

1017-
val = lmalloc (nbytes, clearit);
1020+
val = clearit ? calloc (1, nbytes) : malloc (nbytes);
10181021

10191022
#if ! USE_LSB_TAG
10201023
/* If the memory just allocated cannot be addressed thru a Lisp
@@ -1098,11 +1101,7 @@ aligned_alloc (size_t alignment, size_t size)
10981101
Verify this for all arguments this function is given. */
10991102
static_assert (BLOCK_ALIGN % sizeof (void *) == 0
11001103
&& POWER_OF_2 (BLOCK_ALIGN / sizeof (void *)));
1101-
static_assert (MALLOC_IS_LISP_ALIGNED
1102-
|| (LISP_ALIGNMENT % sizeof (void *) == 0
1103-
&& POWER_OF_2 (LISP_ALIGNMENT / sizeof (void *))));
1104-
eassert (alignment == BLOCK_ALIGN
1105-
|| (!MALLOC_IS_LISP_ALIGNED && alignment == LISP_ALIGNMENT));
1104+
eassert (alignment == BLOCK_ALIGN);
11061105

11071106
void *p;
11081107
return posix_memalign (&p, alignment, size) == 0 ? p : 0;
@@ -1350,81 +1349,6 @@ lisp_align_free (void *block)
13501349
MALLOC_UNBLOCK_INPUT;
13511350
}
13521351

1353-
/* True if a malloc-returned pointer P is suitably aligned for SIZE,
1354-
where Lisp object alignment may be needed if SIZE is a multiple of
1355-
LISP_ALIGNMENT. */
1356-
1357-
static bool
1358-
laligned (void *p, size_t size)
1359-
{
1360-
return (MALLOC_IS_LISP_ALIGNED || (intptr_t) p % LISP_ALIGNMENT == 0
1361-
|| size % LISP_ALIGNMENT != 0);
1362-
}
1363-
1364-
/* Like malloc and realloc except return null only on failure,
1365-
the result is Lisp-aligned if SIZE is, and lrealloc's pointer
1366-
argument must be nonnull. Code allocating C heap memory
1367-
for a Lisp object should use one of these functions to obtain a
1368-
pointer P; that way, if T is an enum Lisp_Type value and L ==
1369-
make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
1370-
1371-
If CLEARIT, arrange for the allocated memory to be cleared.
1372-
This might use calloc, as calloc can be faster than malloc+memset.
1373-
1374-
On typical modern platforms these functions' loops do not iterate.
1375-
On now-rare (and perhaps nonexistent) platforms, the code can loop,
1376-
reallocating (typically with larger and larger sizes) until the
1377-
allocator returns a Lisp-aligned pointer. This loop in
1378-
theory could repeat forever. If an infinite loop is possible on a
1379-
platform, a build would surely loop and the builder can then send
1380-
us a bug report. Adding a counter to try to detect any such loop
1381-
would complicate the code (and possibly introduce bugs, in code
1382-
that's never really exercised) for little benefit. */
1383-
1384-
static void *
1385-
lmalloc (size_t size, bool clearit)
1386-
{
1387-
#ifdef USE_ALIGNED_ALLOC
1388-
if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
1389-
{
1390-
void *p = aligned_alloc (LISP_ALIGNMENT, size);
1391-
if (p)
1392-
{
1393-
if (clearit)
1394-
memclear (p, size);
1395-
}
1396-
else if (! (MALLOC_0_IS_NONNULL || size))
1397-
return aligned_alloc (LISP_ALIGNMENT, LISP_ALIGNMENT);
1398-
return p;
1399-
}
1400-
#endif
1401-
1402-
while (true)
1403-
{
1404-
void *p = clearit ? calloc (1, size) : malloc (size);
1405-
if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p))
1406-
return p;
1407-
free (p);
1408-
size_t bigger;
1409-
if (!ckd_add (&bigger, size, LISP_ALIGNMENT))
1410-
size = bigger;
1411-
}
1412-
}
1413-
1414-
static void *
1415-
lrealloc (void *p, size_t size)
1416-
{
1417-
while (true)
1418-
{
1419-
p = realloc (p, size);
1420-
if (laligned (p, size) && (size || p))
1421-
return p;
1422-
size_t bigger;
1423-
if (!ckd_add (&bigger, size, LISP_ALIGNMENT))
1424-
size = bigger;
1425-
}
1426-
}
1427-
14281352

14291353
/***********************************************************************
14301354
Interval Allocation

0 commit comments

Comments
 (0)