194 lines
5.5 KiB
C
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);
|
|
}
|