[libc-commits] [libc] [WIP][libc] Add freelist malloc (PR #94270)
Petr Hosek via libc-commits
libc-commits at lists.llvm.org
Mon Jun 3 22:09:38 PDT 2024
================
@@ -0,0 +1,125 @@
+#include "freelist.h"
+#include "src/__support/CPP/span.h"
+#include <stddef.h>
+
+using LIBC_NAMESPACE::cpp::span;
+
+namespace pw::allocator {
+
+template <size_t kNumBuckets>
+Status FreeList<kNumBuckets>::AddChunk(span<LIBC_NAMESPACE::cpp::byte> chunk) {
+ // Check that the size is enough to actually store what we need
+ if (chunk.size() < sizeof(FreeListNode)) {
+ return Status::OutOfRange();
+ }
+
+ union {
+ FreeListNode *node;
+ LIBC_NAMESPACE::cpp::byte *bytes;
+ } aliased;
+
+ aliased.bytes = chunk.data();
+
+ unsigned short chunk_ptr = FindChunkPtrForSize(chunk.size(), false);
+
+ // Add it to the correct list.
+ aliased.node->size = chunk.size();
+ aliased.node->next = chunks_[chunk_ptr];
+ chunks_[chunk_ptr] = aliased.node;
+
+ return OkStatus();
+}
+
+template <size_t kNumBuckets>
+span<LIBC_NAMESPACE::cpp::byte>
+FreeList<kNumBuckets>::FindChunk(size_t size) const {
+ if (size == 0) {
+ return span<LIBC_NAMESPACE::cpp::byte>();
+ }
+
+ unsigned short chunk_ptr = FindChunkPtrForSize(size, true);
+
+ // Check that there's data. This catches the case where we run off the
+ // end of the array
+ if (chunks_[chunk_ptr] == nullptr) {
+ return span<LIBC_NAMESPACE::cpp::byte>();
+ }
+
+ // Now iterate up the buckets, walking each list to find a good candidate
+ for (size_t i = chunk_ptr; i < chunks_.size(); i++) {
+ union {
+ FreeListNode *node;
+ LIBC_NAMESPACE::cpp::byte *data;
+ } aliased;
+ aliased.node = chunks_[static_cast<unsigned short>(i)];
+
+ while (aliased.node != nullptr) {
+ if (aliased.node->size >= size) {
+ return span<LIBC_NAMESPACE::cpp::byte>(aliased.data,
+ aliased.node->size);
+ }
+
+ aliased.node = aliased.node->next;
+ }
+ }
+
+ // If we get here, we've checked every block in every bucket. There's
+ // nothing that can support this allocation.
+ return span<LIBC_NAMESPACE::cpp::byte>();
+}
+
+template <size_t kNumBuckets>
+Status
+FreeList<kNumBuckets>::RemoveChunk(span<LIBC_NAMESPACE::cpp::byte> chunk) {
+ unsigned short chunk_ptr = FindChunkPtrForSize(chunk.size(), true);
+
+ // Walk that list, finding the chunk.
+ union {
+ FreeListNode *node;
+ LIBC_NAMESPACE::cpp::byte *data;
+ } aliased, aliased_next;
+
+ // Check head first.
+ if (chunks_[chunk_ptr] == nullptr) {
+ return Status::NotFound();
+ }
+
+ aliased.node = chunks_[chunk_ptr];
+ if (aliased.data == chunk.data()) {
+ chunks_[chunk_ptr] = aliased.node->next;
+
+ return OkStatus();
+ }
+
+ // No? Walk the nodes.
+ aliased.node = chunks_[chunk_ptr];
+
+ while (aliased.node->next != nullptr) {
+ aliased_next.node = aliased.node->next;
+ if (aliased_next.data == chunk.data()) {
+ // Found it, remove this node out of the chain
+ aliased.node->next = aliased_next.node->next;
+ return OkStatus();
+ }
+
+ aliased.node = aliased.node->next;
+ }
+
+ return Status::NotFound();
+}
+
+template <size_t kNumBuckets>
+unsigned short FreeList<kNumBuckets>::FindChunkPtrForSize(size_t size,
+ bool non_null) const {
+ unsigned short chunk_ptr = 0;
+ for (chunk_ptr = 0u; chunk_ptr < sizes_.size(); chunk_ptr++) {
+ if (sizes_[chunk_ptr] >= size &&
+ (!non_null || chunks_[chunk_ptr] != nullptr)) {
+ break;
+ }
+ }
+
+ return chunk_ptr;
+}
+
+} // namespace pw::allocator
----------------
petrhosek wrote:
```suggestion
} // namespace LIBC_NAMESPACE
```
https://github.com/llvm/llvm-project/pull/94270
More information about the libc-commits
mailing list