Start refactor, restructure basic

This commit is contained in:
Krzosa Karol
2025-11-27 09:00:10 +01:00
parent 38b9b7df10
commit 781c2dc53c
30 changed files with 5716 additions and 3490 deletions

248
src/basic/basic_alloc.cpp Normal file
View File

@@ -0,0 +1,248 @@
#if defined(USE_ADDRESS_SANITIZER)
#include <sanitizer/asan_interface.h>
#endif
#if !defined(ASAN_POISON_MEMORY_REGION)
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#else
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
#endif
#if OS_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
void *VReserve(size_t size) {
void *result = (uint8_t *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return result;
}
bool VCommit(void *p, size_t size) {
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
return result ? true : false;
}
bool VRelease(void *p, size_t size) {
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
return result ? true : false;
}
bool VDecommit(void *p, size_t size) {
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
return result ? true : false;
}
#elif OS_LINUX || OS_MAC
void *VReserve(size_t size) {
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t)0);
return result == (void *)-1 ? 0 : result;
}
bool VCommit(void *p, size_t size) {
int result = mprotect(p, size, PROT_READ | PROT_WRITE);
return result == 0;
}
bool VRelease(void *p, size_t size) {
int result = munmap(p, size);
return result == 0;
}
bool VDecommit(void *p, size_t size) {
mprotect(p, size, PROT_NONE);
madvise(p, size, MADV_DONTNEED);
return true;
}
#else
void *VReserve(size_t size) {
InvalidCodepath();
return NULL;
}
bool VCommit(void *p, size_t size) {
InvalidCodepath();
return false;
}
bool VRelease(void *p, size_t size) {
InvalidCodepath();
return false;
}
bool VDecommit(void *p, size_t size) {
InvalidCodepath();
return false;
}
#endif
void InitArena(Arena *arena, size_t reserve) {
reserve = AlignUp(reserve, PAGE_SIZE);
arena->align = DEFAULT_ALIGNMENT;
arena->data = (uint8_t *)VReserve(reserve);
if (arena->data) {
arena->reserve = reserve;
}
}
Arena *AllocArena(Allocator allocator, size_t size) {
Arena *result = AllocType(allocator, Arena);
result->data = (uint8_t *)AllocSize(allocator, size);
result->reserve = size;
result->commit = size;
result->align = DEFAULT_ALIGNMENT;
return result;
}
Arena *AllocArena(size_t reserve) {
Arena *result = NULL;
void *data = VReserve(reserve);
if (!data) return result;
bool success = VCommit(data, PAGE_SIZE);
if (!success) {
VRelease(data, reserve);
return result;
}
result = (Arena *)data;
result->data = (uint8_t *)data;
result->reserve = reserve;
result->commit = PAGE_SIZE;
result->len = result->base_len = sizeof(Arena);
result->align = DEFAULT_ALIGNMENT;
return result;
}
void *PushSize(Arena *arena, size_t size) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
Assert(arena->len >= arena->base_len);
size_t align_offset = 0;
if (arena->align) {
align_offset = GetAlignOffset((uintptr_t)arena->data + arena->len, arena->align);
}
size_t size_with_alignment = size + align_offset;
size_t new_len = arena->len + size_with_alignment;
if (new_len > arena->commit) {
size_t new_len_aligned_to_page_size = AlignUp(new_len, PAGE_SIZE);
size_t to_commit = new_len_aligned_to_page_size - arena->commit;
size_t to_commit_clamped = ClampTop(to_commit, arena->reserve);
if (to_commit_clamped > 0) {
bool success = VCommit(arena->data + arena->commit, to_commit_clamped);
if (success) {
MA_ASAN_UNPOISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
arena->commit += to_commit_clamped;
}
}
if (new_len > arena->commit) {
return NULL;
}
}
uint8_t *result = arena->data + arena->len + align_offset;
arena->len = new_len;
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
return (void *)result;
}
void Release(Arena *arena) {
if (arena == NULL || arena->data == NULL) return;
bool zero_memory = (uint8_t *)arena != arena->data;
VRelease(arena->data, arena->reserve);
if (zero_memory) MemoryZero(arena, sizeof(Arena));
}
void PopToPos(Arena *arena, size_t pos) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
Assert(arena->len >= arena->base_len);
pos = Clamp(pos, arena->base_len, arena->len);
size_t size = arena->len - pos;
arena->len = pos;
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
}
void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
if (kind == AllocatorKind_Allocate) {
return PushSize((Arena *)object, size);
} else if (AllocatorKind_Deallocate) {
} else {
Assert(!"invalid codepath");
}
return NULL;
}
thread_local Arena *ScratchArenaPool[4];
#if OS_WASM
void InitScratch() {
Allocator sys_allocator = GetSystemAllocator();
ScratchArenaPool[0] = AllocArena(sys_allocator, MiB(16));
ScratchArenaPool[1] = AllocArena(sys_allocator, MiB(8));
ScratchArenaPool[3] = AllocArena(sys_allocator, MiB(2));
ScratchArenaPool[3] = AllocArena(sys_allocator, MiB(1));
}
#else
void InitScratch() {
for (int i = 0; i < Lengthof(ScratchArenaPool); i += 1) {
ScratchArenaPool[i] = AllocArena();
}
}
#endif
TempArena GetScratchEx(Arena **conflicts, int conflict_count) {
Arena *unoccupied = 0;
for (int i = 0; i < Lengthof(ScratchArenaPool); i += 1) {
Arena *from_pool = ScratchArenaPool[i];
unoccupied = from_pool;
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
Arena *from_conflict = conflicts[conflict_i];
if (from_pool == from_conflict) {
unoccupied = 0;
break;
}
}
if (unoccupied) {
break;
}
}
// Failed to get free scratch memory, this is a fatal error, this shouldnt happen
Assert(unoccupied);
TempArena result = BeginTemp(unoccupied);
return result;
}
#include <stdlib.h>
void *SystemAllocator_Alloc(void *object, int kind, void *p, size_t size) {
void *result = NULL;
if (kind == AllocatorKind_Allocate) {
result = malloc(size);
Assert(result);
} else if (kind == AllocatorKind_Deallocate) {
free(p);
}
return result;
}
Allocator GetSystemAllocator() {
Allocator result = {SystemAllocator_Alloc};
return result;
}