[Concept,31/37] malloc: Add NO_REALLOC_IN_PLACE option to reduce code size

Message ID 20251201170529.3237986-32-sjg@u-boot.org
State New
Headers
Series malloc: Import dlmalloc 2.8.6 |

Commit Message

Simon Glass Dec. 1, 2025, 5:05 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a new NO_REALLOC_IN_PLACE option that disables in-place realloc
optimization. When enabled via CONFIG_SYS_MALLOC_SMALL, realloc() always
allocates new memory, copies data, and frees the old block instead of
trying to extend the existing allocation.

This saves about 500 bytes by eliminating try_realloc_chunk() and
mmap_resize() functions.

When unit tests are enabled, the extra realloc logic is included.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 common/dlmalloc.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)
  

Patch

diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index 869473b2bd1..4439d278188 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -595,6 +595,10 @@  static inline void MALLOC_COPY(void *dest, const void *src, size_t sz) { memcpy(
 #define INSECURE 1
 #endif
 
+#if CONFIG_IS_ENABLED(SYS_MALLOC_SMALL)
+#define NO_REALLOC_IN_PLACE 1
+#endif
+
 /* Use simplified sys_alloc for non-sandbox builds */
 #if !IS_ENABLED(CONFIG_SANDBOX)
 #define SIMPLE_SYSALLOC 1
@@ -807,6 +811,9 @@  ulong mem_malloc_brk;
 #ifndef NO_SEGMENT_TRAVERSAL
 #define NO_SEGMENT_TRAVERSAL 0
 #endif /* NO_SEGMENT_TRAVERSAL */
+#ifndef NO_REALLOC_IN_PLACE
+#define NO_REALLOC_IN_PLACE 0
+#endif /* NO_REALLOC_IN_PLACE */
 
 /*
   mallopt tuning options.  SVID/XPG defines four standard parameter
@@ -3984,7 +3991,7 @@  static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
   }
   return 0;
 }
-#endif /* !NO_REALLOC_IN_PLACE */
+#endif /* !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE */
 
 
 /* -------------------------- mspace management -------------------------- */
@@ -5002,6 +5009,7 @@  void* dlcalloc_impl(size_t n_elements, size_t elem_size) {
 
 /* ------------ Internal support for realloc, memalign, etc -------------- */
 
+#if !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE
 /* Try to realloc; only in-place unless can_move true */
 static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
                                    int can_move) {
@@ -5081,6 +5089,7 @@  static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
   }
   return newp;
 }
+#endif /* !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE */
 
 static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
   void* mem = 0;
@@ -5444,8 +5453,9 @@  void* dlrealloc_impl(void* oldmem, size_t bytes) {
   }
 #endif /* REALLOC_ZERO_BYTES_FREES */
   else {
-    size_t nb = request2size(bytes);
     mchunkptr oldp = mem2chunk(oldmem);
+#if !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE
+    size_t nb = request2size(bytes);
 #if ! FOOTERS
     mstate m = gm;
 #else /* FOOTERS */
@@ -5484,10 +5494,23 @@  void* dlrealloc_impl(void* oldmem, size_t bytes) {
         }
       }
     }
+#else /* defined(__UBOOT__) && NO_REALLOC_IN_PLACE */
+    mem = dlmalloc_impl(bytes);
+    if (mem != 0) {
+      size_t oc = chunksize(oldp) - overhead_for(oldp);
+      memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
+#ifdef __UBOOT__
+      VALGRIND_MALLOCLIKE_BLOCK(mem, bytes, SIZE_SZ, false);
+      VALGRIND_FREELIKE_BLOCK(oldmem, SIZE_SZ);
+#endif
+      dlfree_impl(oldmem);
+    }
+#endif /* !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE */
   }
   return mem;
 }
 
+#if !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE
 void* dlrealloc_in_place(void* oldmem, size_t bytes) {
   void* mem = 0;
   if (oldmem != 0) {
@@ -5522,6 +5545,7 @@  void* dlrealloc_in_place(void* oldmem, size_t bytes) {
   }
   return mem;
 }
+#endif /* !defined(__UBOOT__) || !NO_REALLOC_IN_PLACE */
 
 STATIC_IF_MCHECK
 void* dlmemalign_impl(size_t alignment, size_t bytes) {