aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert2025-01-15 23:32:43 -0800
committerPaul Eggert2025-01-17 15:56:30 -0800
commitd3a2ec5210746a942263d5e18ee3b8190b9698e1 (patch)
treee5f9974259a48a557c12387ea1fd4e297e644354 /src/alloc.c
parent29794c71452c58c596c58fd6148741d213d3ee7b (diff)
downloademacs-d3a2ec5210746a942263d5e18ee3b8190b9698e1.tar.gz
emacs-d3a2ec5210746a942263d5e18ee3b8190b9698e1.zip
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.
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c128
1 files changed, 26 insertions, 102 deletions
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)
704 ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) 704 ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b))
705 705
706/* Alignment needed for memory blocks that are allocated via malloc 706/* Alignment needed for memory blocks that are allocated via malloc
707 and that contain Lisp objects. On typical hosts malloc already 707 and that contain Lisp objects. */
708 aligns sufficiently, but extra work is needed on oddball hosts
709 where Emacs would crash if malloc returned a non-GCALIGNED pointer. */
710enum { LISP_ALIGNMENT = alignof (union { union emacs_align_type x; 708enum { LISP_ALIGNMENT = alignof (union { union emacs_align_type x;
711 GCALIGNED_UNION_MEMBER }) }; 709 GCALIGNED_UNION_MEMBER }) };
712static_assert (LISP_ALIGNMENT % GCALIGNMENT == 0); 710static_assert (LISP_ALIGNMENT % GCALIGNMENT == 0);
713 711
714/* True if malloc (N) is known to return storage suitably aligned for 712/* Verify Emacs's assumption that malloc (N) returns storage suitably
715 Lisp objects whenever N is a multiple of LISP_ALIGNMENT. In 713 aligned for Lisp objects whenever N is a multiple of LISP_ALIGNMENT.
716 practice this is true whenever alignof (max_align_t) is also a 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
717 multiple of LISP_ALIGNMENT. This works even for buggy platforms 719 multiple of LISP_ALIGNMENT. This works even for buggy platforms
718 like MinGW circa 2020, where alignof (max_align_t) is 16 even though 720 like MinGW circa 2020, where alignof (max_align_t) is 16 even though
719 the malloc alignment is only 8, and where Emacs still works because 721 the malloc alignment is only 8, and where Emacs still works because
720 it never does anything that requires an alignment of 16. */ 722 it never does anything that requires an alignment of 16. */
721enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 }; 723enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 };
724static_assert (MALLOC_IS_LISP_ALIGNED);
722 725
723/* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol 726/* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol
724 BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger. 727 BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger.
@@ -759,9 +762,6 @@ malloc_unblock_input (void)
759 malloc_probe (size); \ 762 malloc_probe (size); \
760 } while (0) 763 } while (0)
761 764
762static void *lmalloc (size_t, bool) ATTRIBUTE_MALLOC_SIZE ((1));
763static void *lrealloc (void *, size_t);
764
765/* Like malloc but check for no memory and block interrupt input. */ 765/* Like malloc but check for no memory and block interrupt input. */
766 766
767void * 767void *
@@ -770,7 +770,7 @@ xmalloc (size_t size)
770 void *val; 770 void *val;
771 771
772 MALLOC_BLOCK_INPUT; 772 MALLOC_BLOCK_INPUT;
773 val = lmalloc (size, false); 773 val = malloc (size);
774 MALLOC_UNBLOCK_INPUT; 774 MALLOC_UNBLOCK_INPUT;
775 775
776 if (!val) 776 if (!val)
@@ -787,7 +787,7 @@ xzalloc (size_t size)
787 void *val; 787 void *val;
788 788
789 MALLOC_BLOCK_INPUT; 789 MALLOC_BLOCK_INPUT;
790 val = lmalloc (size, true); 790 val = calloc (1, size);
791 MALLOC_UNBLOCK_INPUT; 791 MALLOC_UNBLOCK_INPUT;
792 792
793 if (!val) 793 if (!val)
@@ -804,12 +804,7 @@ xrealloc (void *block, size_t size)
804 void *val; 804 void *val;
805 805
806 MALLOC_BLOCK_INPUT; 806 MALLOC_BLOCK_INPUT;
807 /* Call lmalloc when BLOCK is null, for the benefit of long-obsolete 807 val = realloc (block, size);
808 platforms lacking support for realloc (NULL, size). */
809 if (! block)
810 val = lmalloc (size, false);
811 else
812 val = lrealloc (block, size);
813 MALLOC_UNBLOCK_INPUT; 808 MALLOC_UNBLOCK_INPUT;
814 809
815 if (!val) 810 if (!val)
@@ -994,15 +989,23 @@ record_xmalloc (size_t size)
994} 989}
995 990
996 991
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
1001#if ! USE_LSB_TAG 992#if ! USE_LSB_TAG
1002extern void *lisp_malloc_loser; 993extern void *lisp_malloc_loser;
1003void *lisp_malloc_loser EXTERNALLY_VISIBLE; 994void *lisp_malloc_loser EXTERNALLY_VISIBLE;
1004#endif 995#endif
1005 996
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
1006static void * 1009static void *
1007lisp_malloc (size_t nbytes, bool clearit, enum mem_type type) 1010lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
1008{ 1011{
@@ -1014,7 +1017,7 @@ lisp_malloc (size_t nbytes, bool clearit, enum mem_type type)
1014 allocated_mem_type = type; 1017 allocated_mem_type = type;
1015#endif 1018#endif
1016 1019
1017 val = lmalloc (nbytes, clearit); 1020 val = clearit ? calloc (1, nbytes) : malloc (nbytes);
1018 1021
1019#if ! USE_LSB_TAG 1022#if ! USE_LSB_TAG
1020 /* If the memory just allocated cannot be addressed thru a Lisp 1023 /* If the memory just allocated cannot be addressed thru a Lisp
@@ -1098,11 +1101,7 @@ aligned_alloc (size_t alignment, size_t size)
1098 Verify this for all arguments this function is given. */ 1101 Verify this for all arguments this function is given. */
1099 static_assert (BLOCK_ALIGN % sizeof (void *) == 0 1102 static_assert (BLOCK_ALIGN % sizeof (void *) == 0
1100 && POWER_OF_2 (BLOCK_ALIGN / sizeof (void *))); 1103 && POWER_OF_2 (BLOCK_ALIGN / sizeof (void *)));
1101 static_assert (MALLOC_IS_LISP_ALIGNED 1104 eassert (alignment == BLOCK_ALIGN);
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));
1106 1105
1107 void *p; 1106 void *p;
1108 return posix_memalign (&p, alignment, size) == 0 ? p : 0; 1107 return posix_memalign (&p, alignment, size) == 0 ? p : 0;
@@ -1350,81 +1349,6 @@ lisp_align_free (void *block)
1350 MALLOC_UNBLOCK_INPUT; 1349 MALLOC_UNBLOCK_INPUT;
1351} 1350}
1352 1351
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
1357static bool
1358laligned (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
1384static void *
1385lmalloc (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
1414static void *
1415lrealloc (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
1428 1352
1429/*********************************************************************** 1353/***********************************************************************
1430 Interval Allocation 1354 Interval Allocation