diff --git a/include/heap.h b/include/heap.h new file mode 100644 index 0000000..d04b8ee --- /dev/null +++ b/include/heap.h @@ -0,0 +1,17 @@ +#ifndef FROSTBYTE_HEAP_H +#define FROSTBYTE_HEAP_H + +#include "types.h" + +void heapInit(uint64 start, uint64 size); +void* kmalloc(usize size); +void kfree(void* pointer); +void* krealloc(void* pointer, usize size); + +uint64 heapUsed(void); +uint64 heapTotal(void); +uint64 heapFreeBytes(void); +uint64 heapLargestFree(void); +uint64 heapBlockCount(void); + +#endif diff --git a/src/heap.c b/src/heap.c new file mode 100644 index 0000000..77d3514 --- /dev/null +++ b/src/heap.c @@ -0,0 +1,145 @@ +#include "heap.h" +#include "string.h" + +typedef struct Block { + usize size; + struct Block* prev; + struct Block* next; + uint64 free; +} Block; + +static uint64 heapBase; +static uint64 heapLimit; +static Block* head; + +static uint64 alignUp(uint64 value, uint64 alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +void heapInit(uint64 start, uint64 size) +{ + heapBase = alignUp(start, 16); + heapLimit = start + size; + + head = (Block*)heapBase; + head->size = (heapLimit - heapBase) - sizeof(Block); + head->prev = nullptr; + head->next = nullptr; + head->free = 1; +} + +static void split(Block* block, usize wanted) +{ + if (block->size < wanted + sizeof(Block) + 16) + return; + + Block* rest = (Block*)((uint8*)block + sizeof(Block) + wanted); + rest->size = block->size - wanted - sizeof(Block); + rest->free = 1; + rest->prev = block; + rest->next = block->next; + if (block->next) + block->next->prev = rest; + block->next = rest; + block->size = wanted; +} + +void* kmalloc(usize size) +{ + if (size == 0) + size = 16; + usize wanted = alignUp(size, 16); + + for (Block* block = head; block; block = block->next) { + if (block->free && block->size >= wanted) { + split(block, wanted); + block->free = 0; + return (uint8*)block + sizeof(Block); + } + } + return nullptr; +} + +void kfree(void* pointer) +{ + if (!pointer) + return; + + Block* block = (Block*)((uint8*)pointer - sizeof(Block)); + block->free = 1; + + if (block->next && block->next->free) { + Block* victim = block->next; + block->size += sizeof(Block) + victim->size; + block->next = victim->next; + if (victim->next) + victim->next->prev = block; + } + + if (block->prev && block->prev->free) { + Block* keep = block->prev; + keep->size += sizeof(Block) + block->size; + keep->next = block->next; + if (block->next) + block->next->prev = keep; + } +} + +void* krealloc(void* pointer, usize size) +{ + if (!pointer) + return kmalloc(size); + if (size == 0) { + kfree(pointer); + return nullptr; + } + + Block* block = (Block*)((uint8*)pointer - sizeof(Block)); + usize wanted = alignUp(size, 16); + if (block->size >= wanted) + return pointer; + + void* fresh = kmalloc(size); + if (!fresh) + return nullptr; + memcpy(fresh, pointer, block->size); + kfree(pointer); + return fresh; +} + +uint64 heapFreeBytes(void) +{ + uint64 total = 0; + for (Block* block = head; block; block = block->next) + if (block->free) + total += block->size; + return total; +} + +uint64 heapLargestFree(void) +{ + uint64 largest = 0; + for (Block* block = head; block; block = block->next) + if (block->free && block->size > largest) + largest = block->size; + return largest; +} + +uint64 heapBlockCount(void) +{ + uint64 count = 0; + for (Block* block = head; block; block = block->next) + count++; + return count; +} + +uint64 heapTotal(void) +{ + return heapLimit - heapBase; +} + +uint64 heapUsed(void) +{ + return heapTotal() - heapFreeBytes(); +}