185 lines
4.7 KiB
C
185 lines
4.7 KiB
C
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#ifndef SYMS_DEFAULT_ARENA_C
|
|
#define SYMS_DEFAULT_ARENA_C
|
|
|
|
SYMS_OVERRIDE_FUNC SYMS_DefArena*
|
|
syms_arena_def_alloc__sized(SYMS_U64 res, SYMS_U64 cmt){
|
|
SYMS_ASSERT(SYMS_ARENA_HEADER_SIZE < cmt && cmt <= res);
|
|
SYMS_Arena *result = 0;
|
|
void *memory = syms_mem_reserve(res);
|
|
if (memory != 0){
|
|
if (syms_mem_commit(memory, cmt)){
|
|
result = (SYMS_Arena*)memory;
|
|
result->prev = 0;
|
|
result->current = result;
|
|
result->base_pos = 0;
|
|
result->pos = SYMS_ARENA_HEADER_SIZE;
|
|
result->cmt = cmt;
|
|
result->cap = res;
|
|
result->align = 8;
|
|
result->dev = 0;
|
|
}
|
|
else{
|
|
syms_mem_release(memory, res);
|
|
}
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
SYMS_OVERRIDE_FUNC SYMS_DefArena*
|
|
syms_arena_def_alloc(void){
|
|
SYMS_DefArena *result = syms_arena_def_alloc__sized(SYMS_ARENA_RESERVE_SIZE, SYMS_ARENA_COMMIT_SIZE);
|
|
return(result);
|
|
}
|
|
|
|
SYMS_OVERRIDE_FUNC void
|
|
syms_arena_def_release(SYMS_DefArena *arena){
|
|
for (SYMS_DefArena *node = arena->current, *prev = 0;
|
|
node != 0;
|
|
node = prev){
|
|
prev = node->prev;
|
|
syms_mem_release(node, node->cap);
|
|
}
|
|
}
|
|
|
|
#define SYMS_ARENA_VERY_LARGE ((SYMS_ARENA_RESERVE_SIZE - SYMS_ARENA_HEADER_SIZE)/2) + 1
|
|
|
|
SYMS_OVERRIDE_FUNC void*
|
|
syms_arena_def_push(SYMS_DefArena *arena, SYMS_U64 size){
|
|
void *result = 0;
|
|
|
|
// get new pos
|
|
SYMS_Arena *current = arena->current;
|
|
SYMS_U64 pos_aligned = SYMS_AlignPow2(current->pos, arena->align);
|
|
SYMS_U64 pos_new = pos_aligned + size;
|
|
|
|
// check cap
|
|
if (current->cap < pos_new){
|
|
|
|
// normal growth path
|
|
SYMS_Arena *new_block = 0;
|
|
if (size < SYMS_ARENA_VERY_LARGE){
|
|
new_block = syms_arena_def_alloc();
|
|
}
|
|
// "very large" growth path
|
|
else{
|
|
SYMS_U64 size_aligned = SYMS_AlignPow2(size + SYMS_ARENA_HEADER_SIZE, (4 << 10));
|
|
new_block = syms_arena_def_alloc__sized(size_aligned, size_aligned);
|
|
}
|
|
|
|
// connect block to chain
|
|
if (new_block != 0){
|
|
new_block->base_pos = current->base_pos + current->cap;
|
|
SYMS_StackPush_N(arena->current, new_block, prev);
|
|
|
|
// recompute the new pos
|
|
current = new_block;
|
|
pos_aligned = SYMS_AlignPow2(current->pos, arena->align);
|
|
pos_new = pos_aligned + size;
|
|
}
|
|
}
|
|
|
|
// cap big enough?
|
|
if (current->cap >= pos_new){
|
|
|
|
// cmt too small?
|
|
if (current->cmt < pos_new){
|
|
|
|
// get new cmt
|
|
SYMS_U64 cmt_new_unclamped = SYMS_AlignPow2(pos_new, SYMS_ARENA_COMMIT_SIZE);
|
|
SYMS_U64 cmt_new = SYMS_ClampTop(cmt_new_unclamped, current->cap);
|
|
SYMS_U64 cmt_size = cmt_new - current->cmt;
|
|
|
|
// try commit
|
|
if (syms_mem_commit((SYMS_U8*)current + current->cmt, cmt_size)){
|
|
current->cmt = cmt_new;
|
|
}
|
|
}
|
|
|
|
// cmt big enough?
|
|
if (current->cmt >= pos_new){
|
|
|
|
// get result & advance pos
|
|
result = (SYMS_U8*)current + pos_aligned;
|
|
current->pos = pos_new;
|
|
}
|
|
}
|
|
|
|
SYMS_ASSERT(arena->current != 0);
|
|
|
|
// dev
|
|
#if SYMS_ENABLE_DEV_ARENA
|
|
syms_arena_dev_push__impl(arena, size, result);
|
|
#endif
|
|
|
|
return(result);
|
|
}
|
|
|
|
SYMS_OVERRIDE_FUNC SYMS_U64
|
|
syms_arena_def_pos(SYMS_Arena *arena){
|
|
SYMS_Arena *current = arena->current;
|
|
SYMS_U64 result = current->base_pos + current->pos;
|
|
return(result);
|
|
}
|
|
|
|
SYMS_OVERRIDE_FUNC void
|
|
syms_arena_def_pop_to(SYMS_DefArena *arena, SYMS_U64 pos_unclamped){
|
|
SYMS_U64 big_pos = SYMS_ClampBot(SYMS_ARENA_HEADER_SIZE, pos_unclamped);
|
|
|
|
// unroll the chain
|
|
SYMS_Arena *current = arena->current;
|
|
for (SYMS_Arena *prev = 0;
|
|
current->base_pos >= big_pos;
|
|
current = prev){
|
|
prev = current->prev;
|
|
syms_mem_release(current, current->cap);
|
|
}
|
|
arena->current = current;
|
|
|
|
// fix the pos
|
|
{
|
|
SYMS_U64 pos_unclamped = big_pos - current->base_pos;
|
|
SYMS_U64 pos = SYMS_ClampBot(SYMS_ARENA_HEADER_SIZE, pos_unclamped);
|
|
if (pos < current->pos){
|
|
current->pos = pos;
|
|
}
|
|
}
|
|
|
|
SYMS_ASSERT(arena->current != 0);
|
|
|
|
// dev
|
|
#if SYMS_ENABLE_DEV_ARENA
|
|
syms_arena_dev_pop_to__impl(arena, pos_unclamped);
|
|
#endif
|
|
}
|
|
|
|
SYMS_OVERRIDE_FUNC void
|
|
syms_arena_def_set_auto_align(SYMS_DefArena *arena, SYMS_U64 pow2_align){
|
|
arena->align = pow2_align;
|
|
}
|
|
|
|
SYMS_OVERRIDE_FUNC void
|
|
syms_arena_def_absorb(SYMS_DefArena *arena, SYMS_DefArena *sub){
|
|
// base adjustment
|
|
SYMS_DefArena *current = arena->current;
|
|
SYMS_U64 base_adjust = current->base_pos + current->cap;
|
|
for (SYMS_DefArena *node = sub->current;
|
|
node != 0;
|
|
node = node->prev){
|
|
node->base_pos += base_adjust;
|
|
}
|
|
|
|
// attach sub to arena
|
|
sub->prev = arena->current;
|
|
arena->current = sub->current;
|
|
sub->current = sub;
|
|
|
|
// dev
|
|
#if SYMS_ENABLE_DEV_ARENA
|
|
syms_arena_dev_absorb__impl(arena, sub);
|
|
#endif
|
|
}
|
|
|
|
#endif //SYMS_DEFAULT_ARENA_C
|