WIP Two-Level Segregated Fit (TLSF) implementation
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, macos-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled

This commit is contained in:
2026-08-15 19:44:47 -07:00
parent ae7269e6fd
commit 69b8fa4c72
3 changed files with 70 additions and 0 deletions

View File

@@ -55,6 +55,9 @@ public:
// Allocate `size` bytes, aligned to 64 bytes and padded to next 64-byte offset.
std::byte* allocA64(size_t size);
// Free the allocation at `address`
void free(std::byte* address);
private:
Region m_region;
};

View File

@@ -34,6 +34,7 @@
#include <cassert>
#include <cstring>
#include <bit>
#define KRENGINE_MIN_MMAP 32768

View File

@@ -40,6 +40,35 @@ namespace mimir {
// Two-Level Segregated Fit (TLSF): http://www.gii.upv.es/tlsf/files/papers/ecrts04_tlsf.pdf
const size_t kMinblockSize = 32;
struct TLSFBlock
{
size_t size; // LSB: T, F: T = Last physical block, F = Free block
TLSFBlock* prevPhys;
TLSFBlock* prevFree;
TLSFBlock* nextFree;
};
struct TLSFIndex
{
uint64_t firstLevelFreeBitMap;
uint8_t secondLevelFreeBitMap[60];
TLSFBlock* secondLevelFreeBlocks[60 * 16];
};
uint64_t blockSizeToIndex(uint64_t size)
{
// MSB 60 bits are the first level index
// LSB 4 bits is the second level index
size_t firstLevelIndex = std::bit_width(size) - 5;
size_t secondLevelIndex = (size >> firstLevelIndex) & 0b1111;
return (firstLevelIndex << 4) | secondLevelIndex;
}
static_assert(sizeof(TLSFBlock) == kMinblockSize);
Heap::Heap()
{
}
@@ -53,12 +82,44 @@ bool Heap::init(size_t maxSize)
if (!m_region.init(maxSize)) {
return false;
}
if (!m_region.resize(sizeof(TLSFIndex) + 16)) {
return false;
}
TLSFIndex* index = (TLSFIndex*)m_region.getAddress();
memset(index, 0, sizeof(TLSFIndex));
// Start with one free block, filling the entire Region
TLSFBlock* block = (TLSFBlock*)(m_region.getAddress() + sizeof(TLSFIndex));
block->nextFree = nullptr;
block->prevFree = nullptr;
block->size = m_region.getMaxSize() - sizeof(TLSFIndex);
block->size |= 0b11; // T=1: Last Block, F=1: Free Block
// Add the block to the index
size_t usableSize = (block->size & ~0b11) - 16;
size_t secondLevelIndex = blockSizeToIndex(usableSize);
index->firstLevelFreeBitMap |= std::bit_floor(usableSize);
index->secondLevelFreeBitMap[secondLevelIndex >> 4] |= secondLevelIndex & 0b1111;
index->secondLevelFreeBlocks[secondLevelIndex] = block;
return true;
}
// Allocate `size` bytes
std::byte* Heap::alloc(size_t size)
{
/*
HeapEmptyBlock* block = (HeapEmptyBlock*)address;
if (block->prevBlock) {
block->prevBlock->nextBlock = block->nextBlock;
}
if (block->nextBlock) {
block->nextBlock->prevBlock = block->prevBlock;
}
*/
return nullptr; // not implemented
}
@@ -74,4 +135,9 @@ std::byte* Heap::allocA64(size_t size)
return nullptr; // not implemented
}
// Free the allocation at `address`
void Heap::free(std::byte* address)
{
}
} // namespace mimir