[libc-commits] [libc] [libc][NFC] Restructure freelist heap free store (PR #200710)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Tue Jun 2 15:49:08 PDT 2026
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/200710
>From 671ce68ca5262dddca4434075502326efdb775b0 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yfzhu at google.com>
Date: Mon, 1 Jun 2026 00:07:22 -0400
Subject: [PATCH 1/3] [libc] Restructure freelist heap free store
Assisted-by: AI tools, checked manually
---
libc/src/__support/CMakeLists.txt | 10 +-
libc/src/__support/freelist_heap.h | 13 +-
libc/src/__support/freestore.h | 113 ------------------
libc/src/__support/freetrie.h | 103 +++++++++++++++-
libc/test/src/__support/CMakeLists.txt | 5 +-
...estore_test.cpp => triefreestore_test.cpp} | 40 ++++---
6 files changed, 138 insertions(+), 146 deletions(-)
delete mode 100644 libc/src/__support/freestore.h
rename libc/test/src/__support/{freestore_test.cpp => triefreestore_test.cpp} (73%)
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index ada489046ef9e..89c4379381956 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -49,14 +49,7 @@ add_object_library(
DEPENDS
.block
.freelist
-)
-
-add_header_library(
- freestore
- HDRS
- freestore.h
- DEPENDS
- .freetrie
+ libc.src.__support.CPP.array
)
libc_set_definition(libc_freelist_malloc_size "LIBC_FREELIST_MALLOC_SIZE=${LIBC_CONF_FREELIST_MALLOC_BUFFER_SIZE}")
@@ -71,7 +64,6 @@ add_object_library(
DEPENDS
.block
.freelist
- .freestore
.freetrie
libc.src.__support.CPP.cstddef
libc.src.__support.CPP.array
diff --git a/libc/src/__support/freelist_heap.h b/libc/src/__support/freelist_heap.h
index 66f3739efe214..bc992dd71da6d 100644
--- a/libc/src/__support/freelist_heap.h
+++ b/libc/src/__support/freelist_heap.h
@@ -1,10 +1,15 @@
-//===-- Interface for freelist_heap ---------------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for freelist_heap.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_FREELIST_HEAP_H
#define LLVM_LIBC_SRC___SUPPORT_FREELIST_HEAP_H
@@ -12,7 +17,7 @@
#include <stddef.h>
#include "block.h"
-#include "freestore.h"
+#include "freetrie.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/span.h"
#include "src/__support/libc_assert.h"
@@ -62,7 +67,7 @@ class FreeListHeap {
cpp::byte *begin;
cpp::byte *end;
bool is_initialized = false;
- FreeStore free_store;
+ TrieFreeStore free_store;
};
template <size_t BUFF_SIZE> class FreeListHeapBuffer : public FreeListHeap {
@@ -93,7 +98,7 @@ LIBC_INLINE void *FreeListHeap::allocate_impl(size_t alignment, size_t size) {
if (!request_size)
return nullptr;
- Block *block = free_store.remove_best_fit(request_size);
+ Block *block = free_store.find_and_remove_fit(request_size);
if (!block)
return nullptr;
diff --git a/libc/src/__support/freestore.h b/libc/src/__support/freestore.h
deleted file mode 100644
index 2dcb4b10b93d5..0000000000000
--- a/libc/src/__support/freestore.h
+++ /dev/null
@@ -1,113 +0,0 @@
-//===-- Interface for freestore ------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
-#define LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
-
-#include "freetrie.h"
-
-namespace LIBC_NAMESPACE_DECL {
-
-/// A best-fit store of variously-sized free blocks. Blocks can be inserted and
-/// removed in logarithmic time.
-class FreeStore {
-public:
- FreeStore() = default;
- FreeStore(const FreeStore &other) = delete;
- FreeStore &operator=(const FreeStore &other) = delete;
-
- /// Sets the range of possible block sizes. This can only be called when the
- /// trie is empty.
- LIBC_INLINE void set_range(FreeTrie::SizeRange range) {
- large_trie.set_range(range);
- }
-
- /// Insert a free block. If the block is too small to be tracked, nothing
- /// happens.
- void insert(Block *block);
-
- /// Remove a free block. If the block is too small to be tracked, nothing
- /// happens.
- void remove(Block *block);
-
- /// Remove a best-fit free block that can contain the given size when
- /// allocated. Returns nullptr if there is no such block.
- Block *remove_best_fit(size_t size);
-
-private:
- static constexpr size_t MIN_OUTER_SIZE =
- align_up(sizeof(Block) + sizeof(FreeList::Node), Block::MIN_ALIGN);
- static constexpr size_t MIN_LARGE_OUTER_SIZE =
- align_up(sizeof(Block) + sizeof(FreeTrie::Node), Block::MIN_ALIGN);
- static constexpr size_t NUM_SMALL_SIZES =
- (MIN_LARGE_OUTER_SIZE - MIN_OUTER_SIZE) / Block::MIN_ALIGN;
-
- LIBC_INLINE static bool too_small(Block *block) {
- return block->outer_size() < MIN_OUTER_SIZE;
- }
- LIBC_INLINE static bool is_small(Block *block) {
- return block->outer_size() < MIN_LARGE_OUTER_SIZE;
- }
-
- FreeList &small_list(Block *block);
- FreeList *find_best_small_fit(size_t size);
-
- cpp::array<FreeList, NUM_SMALL_SIZES> small_lists;
- FreeTrie large_trie;
-};
-
-LIBC_INLINE void FreeStore::insert(Block *block) {
- if (too_small(block))
- return;
- if (is_small(block))
- small_list(block).push(block);
- else
- large_trie.push(block);
-}
-
-LIBC_INLINE void FreeStore::remove(Block *block) {
- if (too_small(block))
- return;
- if (is_small(block)) {
- small_list(block).remove(
- reinterpret_cast<FreeList::Node *>(block->usable_space()));
- } else {
- large_trie.remove(
- reinterpret_cast<FreeTrie::Node *>(block->usable_space()));
- }
-}
-
-LIBC_INLINE Block *FreeStore::remove_best_fit(size_t size) {
- if (FreeList *list = find_best_small_fit(size)) {
- Block *block = list->front();
- list->pop();
- return block;
- }
- if (FreeTrie::Node *best_fit = large_trie.find_best_fit(size)) {
- Block *block = best_fit->block();
- large_trie.remove(best_fit);
- return block;
- }
- return nullptr;
-}
-
-LIBC_INLINE FreeList &FreeStore::small_list(Block *block) {
- LIBC_ASSERT(is_small(block) && "only legal for small blocks");
- return small_lists[(block->outer_size() - MIN_OUTER_SIZE) / Block::MIN_ALIGN];
-}
-
-LIBC_INLINE FreeList *FreeStore::find_best_small_fit(size_t size) {
- for (FreeList &list : small_lists)
- if (!list.empty() && list.size() >= size)
- return &list;
- return nullptr;
-}
-
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
diff --git a/libc/src/__support/freetrie.h b/libc/src/__support/freetrie.h
index c1a8306c6f8d2..ce8b80d280ae3 100644
--- a/libc/src/__support/freetrie.h
+++ b/libc/src/__support/freetrie.h
@@ -1,15 +1,21 @@
-//===-- Interface for freetrie --------------------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the definition of FreeTrie and TrieFreeStore.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
#define LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
#include "freelist.h"
+#include "src/__support/CPP/array.h"
namespace LIBC_NAMESPACE_DECL {
@@ -117,6 +123,54 @@ class FreeTrie {
SizeRange range;
};
+/// A best-fit store of variously-sized free blocks. Blocks can be inserted and
+/// removed in logarithmic time.
+class TrieFreeStore {
+public:
+ TrieFreeStore() = default;
+ TrieFreeStore(const TrieFreeStore &other) = delete;
+ TrieFreeStore &operator=(const TrieFreeStore &other) = delete;
+
+ /// Sets the range of possible block sizes. This can only be called when the
+ /// trie is empty.
+ LIBC_INLINE void set_range(FreeTrie::SizeRange range) {
+ large_trie.set_range(range);
+ }
+
+ /// Insert a free block. If the block is too small to be tracked, nothing
+ /// happens.
+ void insert(Block *block);
+
+ /// Remove a free block. If the block is too small to be tracked, nothing
+ /// happens.
+ void remove(Block *block);
+
+ /// Remove a best-fit free block that can contain the given size when
+ /// allocated. Returns nullptr if there is no such block.
+ Block *find_and_remove_fit(size_t size);
+
+private:
+ static constexpr size_t MIN_OUTER_SIZE =
+ align_up(sizeof(Block) + sizeof(FreeList::Node), Block::MIN_ALIGN);
+ static constexpr size_t MIN_LARGE_OUTER_SIZE =
+ align_up(sizeof(Block) + sizeof(FreeTrie::Node), Block::MIN_ALIGN);
+ static constexpr size_t NUM_SMALL_SIZES =
+ (MIN_LARGE_OUTER_SIZE - MIN_OUTER_SIZE) / Block::MIN_ALIGN;
+
+ LIBC_INLINE static bool too_small(Block *block) {
+ return block->outer_size() < MIN_OUTER_SIZE;
+ }
+ LIBC_INLINE static bool is_small(Block *block) {
+ return block->outer_size() < MIN_LARGE_OUTER_SIZE;
+ }
+
+ FreeList &small_list(Block *block);
+ FreeList *find_best_small_fit(size_t size);
+
+ cpp::array<FreeList, NUM_SMALL_SIZES> small_lists;
+ FreeTrie large_trie;
+};
+
LIBC_INLINE void FreeTrie::push(Block *block) {
LIBC_ASSERT(block->inner_size_free() >= sizeof(Node) &&
"block too small to accomodate free trie node");
@@ -232,6 +286,53 @@ LIBC_INLINE FreeTrie::Node *FreeTrie::find_best_fit(size_t size) {
}
}
+LIBC_INLINE void TrieFreeStore::insert(Block *block) {
+ if (too_small(block))
+ return;
+ if (is_small(block))
+ small_list(block).push(block);
+ else
+ large_trie.push(block);
+}
+
+LIBC_INLINE void TrieFreeStore::remove(Block *block) {
+ if (too_small(block))
+ return;
+ if (is_small(block)) {
+ small_list(block).remove(
+ reinterpret_cast<FreeList::Node *>(block->usable_space()));
+ } else {
+ large_trie.remove(
+ reinterpret_cast<FreeTrie::Node *>(block->usable_space()));
+ }
+}
+
+LIBC_INLINE Block *TrieFreeStore::find_and_remove_fit(size_t size) {
+ if (FreeList *list = find_best_small_fit(size)) {
+ Block *block = list->front();
+ list->pop();
+ return block;
+ }
+ if (FreeTrie::Node *best_fit = large_trie.find_best_fit(size)) {
+ Block *block = best_fit->block();
+ large_trie.remove(best_fit);
+ return block;
+ }
+ return nullptr;
+}
+
+LIBC_INLINE FreeList &TrieFreeStore::small_list(Block *block) {
+ LIBC_ASSERT(is_small(block) && "only legal for small blocks");
+ return small_lists[(block->outer_size() - MIN_OUTER_SIZE) / Block::MIN_ALIGN];
+}
+
+LIBC_INLINE FreeList *TrieFreeStore::find_best_small_fit(size_t size) {
+ for (FreeList &list : small_lists)
+ if (!list.empty() && list.size() >= size)
+ return &list;
+ return nullptr;
+}
+
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt
index 6b9c1b4ac8cc7..042fdf3eba40c 100644
--- a/libc/test/src/__support/CMakeLists.txt
+++ b/libc/test/src/__support/CMakeLists.txt
@@ -41,16 +41,15 @@ if(NOT LIBC_TARGET_OS_IS_GPU)
)
add_libc_test(
- freestore_test
+ triefreestore_test
SUITE
libc-support-tests
SRCS
- freestore_test.cpp
+ triefreestore_test.cpp
DEPENDS
libc.src.__support.CPP.optional
libc.src.__support.block
libc.src.__support.freelist
- libc.src.__support.freestore
libc.src.__support.freetrie
)
endif()
diff --git a/libc/test/src/__support/freestore_test.cpp b/libc/test/src/__support/triefreestore_test.cpp
similarity index 73%
rename from libc/test/src/__support/freestore_test.cpp
rename to libc/test/src/__support/triefreestore_test.cpp
index 7017d6b9ebe93..dfecbf6153085 100644
--- a/libc/test/src/__support/freestore_test.cpp
+++ b/libc/test/src/__support/triefreestore_test.cpp
@@ -1,25 +1,30 @@
-//===-- Unittests for a freestore -------------------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for TrieFreeStore.
+///
+//===----------------------------------------------------------------------===//
#include <stddef.h>
-#include "src/__support/freestore.h"
+#include "src/__support/freetrie.h"
#include "test/UnitTest/Test.h"
using LIBC_NAMESPACE::Block;
using LIBC_NAMESPACE::FreeList;
-using LIBC_NAMESPACE::FreeStore;
using LIBC_NAMESPACE::FreeTrie;
+using LIBC_NAMESPACE::TrieFreeStore;
using LIBC_NAMESPACE::cpp::byte;
using LIBC_NAMESPACE::cpp::optional;
// Inserting or removing blocks too small to be tracked does nothing.
-TEST(LlvmLibcFreeStore, TooSmall) {
+TEST(LlvmLibcTrieFreeStore, TooSmall) {
byte mem[1024];
optional<Block *> maybeBlock = Block::init(mem);
ASSERT_TRUE(maybeBlock.has_value());
@@ -32,16 +37,16 @@ TEST(LlvmLibcFreeStore, TooSmall) {
return;
Block *remainder = *maybeBlock;
- FreeStore store;
+ TrieFreeStore store;
store.set_range({0, 4096});
store.insert(too_small);
store.insert(remainder);
- EXPECT_EQ(store.remove_best_fit(too_small->inner_size()), remainder);
+ EXPECT_EQ(store.find_and_remove_fit(too_small->inner_size()), remainder);
store.remove(too_small);
}
-TEST(LlvmLibcFreeStore, RemoveBestFit) {
+TEST(LlvmLibcTrieFreeStore, FindAndRemoveFit) {
byte mem[1024];
optional<Block *> maybeBlock = Block::init(mem);
ASSERT_TRUE(maybeBlock.has_value());
@@ -60,7 +65,7 @@ TEST(LlvmLibcFreeStore, RemoveBestFit) {
Block *remainder = *maybeBlock;
- FreeStore store;
+ TrieFreeStore store;
store.set_range({0, 4096});
store.insert(smallest);
if (largest_small != smallest)
@@ -68,23 +73,26 @@ TEST(LlvmLibcFreeStore, RemoveBestFit) {
store.insert(remainder);
// Find exact match for smallest.
- ASSERT_EQ(store.remove_best_fit(smallest->inner_size()), smallest);
+ ASSERT_EQ(store.find_and_remove_fit(smallest->inner_size()), smallest);
store.insert(smallest);
// Find exact match for largest.
- ASSERT_EQ(store.remove_best_fit(largest_small->inner_size()), largest_small);
+ ASSERT_EQ(store.find_and_remove_fit(largest_small->inner_size()),
+ largest_small);
store.insert(largest_small);
// Search small list for best fit.
Block *next_smallest = largest_small == smallest ? remainder : largest_small;
- ASSERT_EQ(store.remove_best_fit(smallest->inner_size() + 1), next_smallest);
+ ASSERT_EQ(store.find_and_remove_fit(smallest->inner_size() + 1),
+ next_smallest);
store.insert(next_smallest);
// Continue search for best fit to large blocks.
- EXPECT_EQ(store.remove_best_fit(largest_small->inner_size() + 1), remainder);
+ EXPECT_EQ(store.find_and_remove_fit(largest_small->inner_size() + 1),
+ remainder);
}
-TEST(LlvmLibcFreeStore, Remove) {
+TEST(LlvmLibcTrieFreeStore, Remove) {
byte mem[1024];
optional<Block *> maybeBlock = Block::init(mem);
ASSERT_TRUE(maybeBlock.has_value());
@@ -95,15 +103,15 @@ TEST(LlvmLibcFreeStore, Remove) {
Block *remainder = *maybeBlock;
- FreeStore store;
+ TrieFreeStore store;
store.set_range({0, 4096});
store.insert(small);
store.insert(remainder);
store.remove(remainder);
- ASSERT_EQ(store.remove_best_fit(remainder->inner_size()),
+ ASSERT_EQ(store.find_and_remove_fit(remainder->inner_size()),
static_cast<Block *>(nullptr));
store.remove(small);
- ASSERT_EQ(store.remove_best_fit(small->inner_size()),
+ ASSERT_EQ(store.find_and_remove_fit(small->inner_size()),
static_cast<Block *>(nullptr));
}
>From 417c80a6a6b42e29d907a3eb107d6dbecf983d44 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yfzhu at google.com>
Date: Tue, 2 Jun 2026 14:07:03 -0700
Subject: [PATCH 2/3] cleanup
---
libc/src/__support/CMakeLists.txt | 13 ++++++
libc/src/__support/freelist_heap.h | 71 +++++++++++++++++++++++-------
libc/src/__support/freestore.h | 49 +++++++++++++++++++++
libc/src/__support/freetrie.cpp | 2 +-
libc/src/__support/freetrie.h | 24 +++++-----
5 files changed, 129 insertions(+), 30 deletions(-)
create mode 100644 libc/src/__support/freestore.h
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 89c4379381956..9a617f95e2d53 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -40,6 +40,17 @@ add_object_library(
libc.src.__support.CPP.span
)
+add_header_library(
+ freestore
+ HDRS
+ freestore.h
+ DEPENDS
+ .block
+ .freelist
+ libc.hdr.types.size_t
+ libc.src.__support.macros.config
+)
+
add_object_library(
freetrie
HDRS
@@ -49,6 +60,7 @@ add_object_library(
DEPENDS
.block
.freelist
+ .freestore
libc.src.__support.CPP.array
)
@@ -65,6 +77,7 @@ add_object_library(
.block
.freelist
.freetrie
+ .freestore
libc.src.__support.CPP.cstddef
libc.src.__support.CPP.array
libc.src.__support.CPP.optional
diff --git a/libc/src/__support/freelist_heap.h b/libc/src/__support/freelist_heap.h
index bc992dd71da6d..218dfa1db4308 100644
--- a/libc/src/__support/freelist_heap.h
+++ b/libc/src/__support/freelist_heap.h
@@ -16,10 +16,11 @@
#include <stddef.h>
-#include "block.h"
-#include "freetrie.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/span.h"
+#include "src/__support/block.h"
+#include "src/__support/freestore.h"
+#include "src/__support/freetrie.h"
#include "src/__support/libc_assert.h"
#include "src/__support/macros/config.h"
#include "src/__support/math_extras.h"
@@ -36,11 +37,19 @@ using cpp::span;
LIBC_INLINE constexpr bool IsPow2(size_t x) { return x && (x & (x - 1)) == 0; }
-class FreeListHeap {
+template <typename T> LIBC_INLINE void init_free_store(T &, size_t) {}
+
+template <>
+LIBC_INLINE void init_free_store<TrieFreeStore>(TrieFreeStore &store,
+ size_t size) {
+ store.set_range({0, cpp::bit_ceil(size)});
+}
+
+template <typename FreeStoreType = TrieFreeStore> class FreeListHeapImpl {
public:
- constexpr FreeListHeap() : begin(&_end), end(&__llvm_libc_heap_limit) {}
+ constexpr FreeListHeapImpl() : begin(&_end), end(&__llvm_libc_heap_limit) {}
- constexpr FreeListHeap(span<cpp::byte> region)
+ constexpr FreeListHeapImpl(span<cpp::byte> region)
: begin(region.begin()), end(region.end()) {}
void *allocate(size_t size);
@@ -67,18 +76,38 @@ class FreeListHeap {
cpp::byte *begin;
cpp::byte *end;
bool is_initialized = false;
- TrieFreeStore free_store;
+ FreeStoreType free_store;
+};
+
+// Deduction guide for FreeListHeapImpl to allow bracket-less instantiation
+FreeListHeapImpl(span<cpp::byte>) -> FreeListHeapImpl<TrieFreeStore>;
+
+using FreeListHeap = FreeListHeapImpl<TrieFreeStore>;
+
+template <size_t BUFF_SIZE, typename FreeStoreType = TrieFreeStore>
+class FreeListHeapBuffer : public FreeListHeapImpl<FreeStoreType> {
+public:
+ constexpr FreeListHeapBuffer()
+ : FreeListHeapImpl<FreeStoreType>{buffer}, buffer{} {}
+
+private:
+ cpp::byte buffer[BUFF_SIZE];
};
-template <size_t BUFF_SIZE> class FreeListHeapBuffer : public FreeListHeap {
+// Specialization for the default FreeStore to allow conversion to FreeListHeap*
+template <size_t BUFF_SIZE>
+class FreeListHeapBuffer<BUFF_SIZE, TrieFreeStore>
+ : public FreeListHeapImpl<TrieFreeStore> {
public:
- constexpr FreeListHeapBuffer() : FreeListHeap{buffer}, buffer{} {}
+ constexpr FreeListHeapBuffer()
+ : FreeListHeapImpl<TrieFreeStore>{buffer}, buffer{} {}
private:
cpp::byte buffer[BUFF_SIZE];
};
-LIBC_INLINE void FreeListHeap::init() {
+template <typename FreeStoreType>
+LIBC_INLINE void FreeListHeapImpl<FreeStoreType>::init() {
LIBC_ASSERT(!is_initialized && "duplicate initialization");
auto result = Block::init(region());
Block *block = *result;
@@ -87,7 +116,9 @@ LIBC_INLINE void FreeListHeap::init() {
is_initialized = true;
}
-LIBC_INLINE void *FreeListHeap::allocate_impl(size_t alignment, size_t size) {
+template <typename FreeStoreType>
+LIBC_INLINE void *
+FreeListHeapImpl<FreeStoreType>::allocate_impl(size_t alignment, size_t size) {
if (size == 0)
return nullptr;
@@ -112,12 +143,15 @@ LIBC_INLINE void *FreeListHeap::allocate_impl(size_t alignment, size_t size) {
return block_info.block->usable_space();
}
-LIBC_INLINE void *FreeListHeap::allocate(size_t size) {
+template <typename FreeStoreType>
+LIBC_INLINE void *FreeListHeapImpl<FreeStoreType>::allocate(size_t size) {
return allocate_impl(Block::MIN_ALIGN, size);
}
-LIBC_INLINE void *FreeListHeap::aligned_allocate(size_t alignment,
- size_t size) {
+template <typename FreeStoreType>
+LIBC_INLINE void *
+FreeListHeapImpl<FreeStoreType>::aligned_allocate(size_t alignment,
+ size_t size) {
// The alignment must be an integral power of two.
if (!IsPow2(alignment))
return nullptr;
@@ -132,7 +166,8 @@ LIBC_INLINE void *FreeListHeap::aligned_allocate(size_t alignment,
return allocate_impl(alignment, size);
}
-LIBC_INLINE void FreeListHeap::free(void *ptr) {
+template <typename FreeStoreType>
+LIBC_INLINE void FreeListHeapImpl<FreeStoreType>::free(void *ptr) {
if (ptr == nullptr)
return;
@@ -165,7 +200,9 @@ LIBC_INLINE void FreeListHeap::free(void *ptr) {
// Follows constract of the C standard realloc() function
// If ptr is free'd, will return nullptr.
-LIBC_INLINE void *FreeListHeap::realloc(void *ptr, size_t size) {
+template <typename FreeStoreType>
+LIBC_INLINE void *FreeListHeapImpl<FreeStoreType>::realloc(void *ptr,
+ size_t size) {
if (size == 0) {
free(ptr);
return nullptr;
@@ -200,7 +237,9 @@ LIBC_INLINE void *FreeListHeap::realloc(void *ptr, size_t size) {
return new_ptr;
}
-LIBC_INLINE void *FreeListHeap::calloc(size_t num, size_t size) {
+template <typename FreeStoreType>
+LIBC_INLINE void *FreeListHeapImpl<FreeStoreType>::calloc(size_t num,
+ size_t size) {
size_t bytes;
if (__builtin_mul_overflow(num, size, &bytes))
return nullptr;
diff --git a/libc/src/__support/freestore.h b/libc/src/__support/freestore.h
new file mode 100644
index 0000000000000..97a7f7f3270e4
--- /dev/null
+++ b/libc/src/__support/freestore.h
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the definition of the FreeStore template class.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
+#define LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
+
+#include "hdr/types/size_t.h"
+#include "src/__support/block.h"
+#include "src/__support/freelist.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+template <typename T> class FreeStore {
+protected:
+ static constexpr size_t MIN_OUTER_SIZE =
+ align_up(sizeof(Block) + sizeof(FreeList::Node), Block::MIN_ALIGN);
+
+ LIBC_INLINE static bool too_small(Block *block) {
+ return block->outer_size() < MIN_OUTER_SIZE;
+ }
+
+public:
+ LIBC_INLINE void insert(Block *block) {
+ static_cast<T *>(this)->insert_impl(block);
+ }
+
+ LIBC_INLINE void remove(Block *block) {
+ static_cast<T *>(this)->remove_impl(block);
+ }
+
+ LIBC_INLINE Block *find_and_remove_fit(size_t size) {
+ return static_cast<T *>(this)->find_and_remove_fit_impl(size);
+ }
+};
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FREESTORE_H
diff --git a/libc/src/__support/freetrie.cpp b/libc/src/__support/freetrie.cpp
index e76efe717f215..bb7a53a7635d9 100644
--- a/libc/src/__support/freetrie.cpp
+++ b/libc/src/__support/freetrie.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "freetrie.h"
+#include "src/__support/freetrie.h"
namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/__support/freetrie.h b/libc/src/__support/freetrie.h
index ce8b80d280ae3..cff995d48f376 100644
--- a/libc/src/__support/freetrie.h
+++ b/libc/src/__support/freetrie.h
@@ -14,8 +14,11 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
#define LLVM_LIBC_SRC___SUPPORT_FREETRIE_H
-#include "freelist.h"
+#include "hdr/types/size_t.h"
#include "src/__support/CPP/array.h"
+#include "src/__support/freelist.h"
+#include "src/__support/freestore.h"
+#include "src/__support/macros/attributes.h"
namespace LIBC_NAMESPACE_DECL {
@@ -125,7 +128,7 @@ class FreeTrie {
/// A best-fit store of variously-sized free blocks. Blocks can be inserted and
/// removed in logarithmic time.
-class TrieFreeStore {
+class TrieFreeStore : public FreeStore<TrieFreeStore> {
public:
TrieFreeStore() = default;
TrieFreeStore(const TrieFreeStore &other) = delete;
@@ -139,27 +142,22 @@ class TrieFreeStore {
/// Insert a free block. If the block is too small to be tracked, nothing
/// happens.
- void insert(Block *block);
+ void insert_impl(Block *block);
/// Remove a free block. If the block is too small to be tracked, nothing
/// happens.
- void remove(Block *block);
+ void remove_impl(Block *block);
/// Remove a best-fit free block that can contain the given size when
/// allocated. Returns nullptr if there is no such block.
- Block *find_and_remove_fit(size_t size);
+ Block *find_and_remove_fit_impl(size_t size);
private:
- static constexpr size_t MIN_OUTER_SIZE =
- align_up(sizeof(Block) + sizeof(FreeList::Node), Block::MIN_ALIGN);
static constexpr size_t MIN_LARGE_OUTER_SIZE =
align_up(sizeof(Block) + sizeof(FreeTrie::Node), Block::MIN_ALIGN);
static constexpr size_t NUM_SMALL_SIZES =
(MIN_LARGE_OUTER_SIZE - MIN_OUTER_SIZE) / Block::MIN_ALIGN;
- LIBC_INLINE static bool too_small(Block *block) {
- return block->outer_size() < MIN_OUTER_SIZE;
- }
LIBC_INLINE static bool is_small(Block *block) {
return block->outer_size() < MIN_LARGE_OUTER_SIZE;
}
@@ -286,7 +284,7 @@ LIBC_INLINE FreeTrie::Node *FreeTrie::find_best_fit(size_t size) {
}
}
-LIBC_INLINE void TrieFreeStore::insert(Block *block) {
+LIBC_INLINE void TrieFreeStore::insert_impl(Block *block) {
if (too_small(block))
return;
if (is_small(block))
@@ -295,7 +293,7 @@ LIBC_INLINE void TrieFreeStore::insert(Block *block) {
large_trie.push(block);
}
-LIBC_INLINE void TrieFreeStore::remove(Block *block) {
+LIBC_INLINE void TrieFreeStore::remove_impl(Block *block) {
if (too_small(block))
return;
if (is_small(block)) {
@@ -307,7 +305,7 @@ LIBC_INLINE void TrieFreeStore::remove(Block *block) {
}
}
-LIBC_INLINE Block *TrieFreeStore::find_and_remove_fit(size_t size) {
+LIBC_INLINE Block *TrieFreeStore::find_and_remove_fit_impl(size_t size) {
if (FreeList *list = find_best_small_fit(size)) {
Block *block = list->front();
list->pop();
>From dc773380aa37752bf4ab712878496944eac745f1 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yfzhu at google.com>
Date: Tue, 2 Jun 2026 15:48:53 -0700
Subject: [PATCH 3/3] remove
---
libc/src/__support/freelist_heap.h | 8 --------
1 file changed, 8 deletions(-)
diff --git a/libc/src/__support/freelist_heap.h b/libc/src/__support/freelist_heap.h
index 218dfa1db4308..74e3777712941 100644
--- a/libc/src/__support/freelist_heap.h
+++ b/libc/src/__support/freelist_heap.h
@@ -37,14 +37,6 @@ using cpp::span;
LIBC_INLINE constexpr bool IsPow2(size_t x) { return x && (x & (x - 1)) == 0; }
-template <typename T> LIBC_INLINE void init_free_store(T &, size_t) {}
-
-template <>
-LIBC_INLINE void init_free_store<TrieFreeStore>(TrieFreeStore &store,
- size_t size) {
- store.set_range({0, cpp::bit_ceil(size)});
-}
-
template <typename FreeStoreType = TrieFreeStore> class FreeListHeapImpl {
public:
constexpr FreeListHeapImpl() : begin(&_end), end(&__llvm_libc_heap_limit) {}
More information about the libc-commits
mailing list