Files
Juliet/Juliet/core/core_arena.c
T
2026-10-24 18:17:43 -04:00

194 lines
5.5 KiB
C

// =============================================================================
// Arena Functions
#include "core/core.h"
internal Arena* arena_alloc_internal(ArenaParams* params)
{
uint64 committed = params->commit_size;
uint64 reserved = params->reserve_size;
// Initial block
void* base = NULL;
if (params->flags & ArenaFlag_LargePages)
{
uint64 page_size = get_system_info()->large_page_size;
reserved = AlignPow2(reserved, page_size);
committed = AlignPow2(committed, page_size);
base = reserve_memory_large(reserved);
commit_memory_large(base, committed);
}
else
{
uint64 page_size = get_system_info()->page_size;
reserved = AlignPow2(reserved, page_size);
committed = AlignPow2(committed, page_size);
base = reserve_memory(reserved);
commit_memory(base, committed);
}
if (Unlikely(base == 0))
{
abort_self(1);
}
Arena* arena = base;
arena->current = arena;
arena->commit_size = params->commit_size;
arena->reserve_size = params->reserve_size;
arena->base_position = 0;
arena->position = ARENA_HEADER_SIZE;
arena->committed = committed;
arena->reserved = reserved;
#if BUILD_DEBUG
arena->alloc_file = params->alloc_file;
arena->alloc_line = params->alloc_line;
arena->name = params->name;
#endif
return arena;
}
internal void arena_release(Arena* arena)
{
for (Arena *p = arena->current, *prev = 0; p != 0; p = prev)
{
prev = p->previous;
release_memory(p, p->reserved);
}
}
// =============================================================================
// Arena Push/Pop core Functions
internal void* arena_push(Arena* arena, uint64 size, uint64 align, bool32 zero)
{
Arena* current = arena->current;
uint64 pos_pre = AlignPow2(current->position, align);
uint64 pos_post = pos_pre + size;
uint64 size_to_zero = 0;
if (zero)
{
size_to_zero = Min(current->committed, pos_post) - pos_pre;
}
if (current->reserved < pos_post && !(arena->flags & ArenaFlag_NoChain))
{
Arena* new_block = 0;
if (new_block == 0)
{
uint64 reserved_size = arena->reserve_size;
uint64 committed_size = arena->commit_size;
if (size + ARENA_HEADER_SIZE > reserved_size)
{
reserved_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
committed_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
}
new_block = arena_alloc(.reserve_size = reserved_size, .commit_size = committed_size, .flags = arena->flags,
#if BUILD_DEBUG
.alloc_file = arena->alloc_file, .alloc_line = arena->alloc_line
#endif
);
size_to_zero = 0;
}
else
{
size_to_zero = size;
}
new_block->base_position = current->base_position + current->reserved;
SLL_stack_push_next(arena->current, new_block, previous);
current = new_block;
pos_pre = AlignPow2(current->position, align);
pos_post = pos_pre + size;
}
// commit new pages if needed
if (current->committed < pos_post)
{
uint64 committed_past_aligned = pos_post + current->commit_size - 1;
committed_past_aligned -= committed_past_aligned % current->commit_size;
uint64 committed_past_clamped = ClampTop(committed_past_aligned, current->reserved);
uint64 committed_size = committed_past_clamped - current->committed;
uint8* committed_ptr = (uint8*)current + current->committed;
if (current->flags & ArenaFlag_LargePages)
{
commit_memory_large(committed_ptr, committed_size);
}
else
{
commit_memory(committed_ptr, committed_size);
}
current->committed = committed_past_clamped;
}
void* result = 0;
if (current->committed >= pos_post)
{
result = (uint8*)current + pos_pre;
current->position = pos_post;
MemoryZero(result, size_to_zero);
}
if (Unlikely(result == 0))
{
abort_self(1);
}
return result;
}
internal uint64 arena_pos(Arena* arena)
{
Arena* current = arena->current;
uint64 position = current->base_position + current->position;
return position;
}
internal void arena_pop_to(Arena* arena, uint64 position)
{
uint64 clamped_pos = ClampBottom(ARENA_HEADER_SIZE, position);
Arena* current = arena->current;
for (Arena* previous = 0; current->base_position >= clamped_pos; current = previous)
{
previous = current->previous;
release_memory(current, current->reserved);
}
arena->current = current;
uint64 new_position = clamped_pos - current->base_position;
AssertAlways(new_position <= current->position);
current->position = new_position;
}
internal void arena_clear(Arena* arena)
{
arena_pop_to(arena, 0);
}
internal void arena_pop(Arena* arena, uint64 amount)
{
uint64 pos_old = arena_pos(arena);
Assert(pos_old > amount);
uint64 pos_new = pos_old - amount;
arena_pop_to(arena, pos_new);
}
// Temp arena
internal TempArena temp_begin(Arena* arena)
{
uint64 position = arena_pos(arena);
TempArena temp = { arena, position };
return temp;
}
internal void temp_end(TempArena temp)
{
arena_pop_to(temp.arena, temp.position);
}