From f211d2245522d328bc034f868f1285303a930a8f Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Wed, 6 May 2026 22:03:11 +0200 Subject: [PATCH 1/3] introduce metadata --- Engine/src/delta/core/FreeListAllocator.cpp | 10 ++++++++-- Engine/src/delta/core/FreeListAllocator.h | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Engine/src/delta/core/FreeListAllocator.cpp b/Engine/src/delta/core/FreeListAllocator.cpp index 3a07bc0..7a6eea1 100644 --- a/Engine/src/delta/core/FreeListAllocator.cpp +++ b/Engine/src/delta/core/FreeListAllocator.cpp @@ -23,13 +23,18 @@ using namespace delta::core; using MemoryState = MemoryManager::MemoryState; using Node = FreeListAllocator::Node; +using BucketMetadata = FreeListAllocator::BucketMetadata; DLT_FORCE_INLINE void* AllocatePageForBucket(FreeListAllocator* allocator, uint32_t bucketIx, uint64_t size) { void* rawPage = MemoryManager::AllocatePageLockFree(allocator->memState); - uint64_t numChunks = allocator->pageSize / size; - uint8_t* walker = static_cast(rawPage); + BucketMetadata* meta = reinterpret_cast(rawPage); + meta->bucketIx = bucketIx; + meta->bitmask = 0; + + uint64_t numChunks = allocator->remaining / size; + uint8_t* walker = static_cast(rawPage) + sizeof(BucketMetadata); Node* head = reinterpret_cast(walker); Node* current = head; @@ -50,6 +55,7 @@ void delta::core::FreeList_Init(FreeListAllocator* allocator, MemoryState* memSt { allocator->memState = memState; allocator->pageSize = memState->pageSize; + allocator->remaining = memState->pageSize - sizeof(BucketMetadata); } void* delta::core::FreeList_Allocate(FreeListAllocator* allocator, uint64_t size, uint64_t alignment) diff --git a/Engine/src/delta/core/FreeListAllocator.h b/Engine/src/delta/core/FreeListAllocator.h index 8c115b3..93950a4 100644 --- a/Engine/src/delta/core/FreeListAllocator.h +++ b/Engine/src/delta/core/FreeListAllocator.h @@ -28,12 +28,18 @@ namespace delta::core static constexpr uint32_t BUCKET_COUNT = 7ull; // log2(2048) - log2(16) = 7, calculated manually for simplicity struct Node { Node* next; }; + struct alignas(16) BucketMetadata + { + uint32_t bucketIx; + uint32_t bitmask; + }; MemoryManager::MemoryState* memState; Node* buckets[BUCKET_COUNT]; uint64_t pageSize; + uint64_t remaining; // pageSize - metadata size }; void FreeList_Init(FreeListAllocator* allocator, MemoryManager::MemoryState* memState); From ef244c9575b2fb0a5e8a23a01ded8f1e2f10587a Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Wed, 6 May 2026 22:30:45 +0200 Subject: [PATCH 2/3] O(1) free mechanism, bug fixes --- Engine/src/delta/core/FreeListAllocator.cpp | 16 ++++++++++++++++ Engine/src/delta/core/FreeListAllocator.h | 1 + 2 files changed, 17 insertions(+) diff --git a/Engine/src/delta/core/FreeListAllocator.cpp b/Engine/src/delta/core/FreeListAllocator.cpp index 7a6eea1..41ffaba 100644 --- a/Engine/src/delta/core/FreeListAllocator.cpp +++ b/Engine/src/delta/core/FreeListAllocator.cpp @@ -48,6 +48,7 @@ DLT_FORCE_INLINE void* AllocatePageForBucket(FreeListAllocator* allocator, uint3 } current->next = nullptr; + allocator->buckets[bucketIx] = head; return head; } @@ -82,3 +83,18 @@ void* delta::core::FreeList_Allocate(FreeListAllocator* allocator, uint64_t size return MemoryManager::AllocatePageLockFree(allocator->memState); } + +void delta::core::FreeList_Free(FreeListAllocator* allocator, void* ptr) +{ + if (!ptr) + return; + + uintptr_t address = reinterpret_cast(ptr); + uintptr_t basePage = address & ~0xfffull; + + const BucketMetadata* metadata = reinterpret_cast(basePage); + uint32_t bucketIx = metadata->bucketIx; + Node* freeNode = reinterpret_cast(ptr); + freeNode->next = allocator->buckets[bucketIx]; + allocator->buckets[bucketIx] = freeNode; +} diff --git a/Engine/src/delta/core/FreeListAllocator.h b/Engine/src/delta/core/FreeListAllocator.h index 93950a4..eec3ad7 100644 --- a/Engine/src/delta/core/FreeListAllocator.h +++ b/Engine/src/delta/core/FreeListAllocator.h @@ -44,4 +44,5 @@ namespace delta::core void FreeList_Init(FreeListAllocator* allocator, MemoryManager::MemoryState* memState); void* FreeList_Allocate(FreeListAllocator* allocator, uint64_t size, uint64_t alignment); + void FreeList_Free(FreeListAllocator* allocator, void* ptr); } From c52a037fb5306d27e91b298402be30e312d80141 Mon Sep 17 00:00:00 2001 From: YasInvolved Date: Wed, 6 May 2026 22:49:53 +0200 Subject: [PATCH 3/3] introduce magic value to check for region corruption or invalid pointer passed in --- Engine/src/delta/core/FreeListAllocator.cpp | 4 +++- Engine/src/delta/core/FreeListAllocator.h | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Engine/src/delta/core/FreeListAllocator.cpp b/Engine/src/delta/core/FreeListAllocator.cpp index 41ffaba..604344f 100644 --- a/Engine/src/delta/core/FreeListAllocator.cpp +++ b/Engine/src/delta/core/FreeListAllocator.cpp @@ -30,8 +30,8 @@ DLT_FORCE_INLINE void* AllocatePageForBucket(FreeListAllocator* allocator, uint3 void* rawPage = MemoryManager::AllocatePageLockFree(allocator->memState); BucketMetadata* meta = reinterpret_cast(rawPage); + meta->magic = BucketMetadata::MAGIC_VALUE; meta->bucketIx = bucketIx; - meta->bitmask = 0; uint64_t numChunks = allocator->remaining / size; uint8_t* walker = static_cast(rawPage) + sizeof(BucketMetadata); @@ -93,6 +93,8 @@ void delta::core::FreeList_Free(FreeListAllocator* allocator, void* ptr) uintptr_t basePage = address & ~0xfffull; const BucketMetadata* metadata = reinterpret_cast(basePage); + assert(metadata->magic == BucketMetadata::MAGIC_VALUE); + uint32_t bucketIx = metadata->bucketIx; Node* freeNode = reinterpret_cast(ptr); freeNode->next = allocator->buckets[bucketIx]; diff --git a/Engine/src/delta/core/FreeListAllocator.h b/Engine/src/delta/core/FreeListAllocator.h index eec3ad7..47dec73 100644 --- a/Engine/src/delta/core/FreeListAllocator.h +++ b/Engine/src/delta/core/FreeListAllocator.h @@ -30,8 +30,11 @@ namespace delta::core struct Node { Node* next; }; struct alignas(16) BucketMetadata { + static constexpr char MAGIC_VALUE_STR[sizeof(uint64_t)] = "DLT_SFA"; + static constexpr uint64_t MAGIC_VALUE = std::bit_cast(MAGIC_VALUE_STR); + + uint64_t magic; uint32_t bucketIx; - uint32_t bitmask; }; MemoryManager::MemoryState* memState;