/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //~ Base arena implementation internal Arena * arena_alloc_() { U64 reserve_size = g_arena_default_reserve_size; U64 commit_size = g_arena_default_commit_size; // TODO align to page sizes // Reserve/commit initial block void *base = 0; if(base == 0) // TODO(anton): can have optional backing buffer { base = os_reserve(reserve_size); os_commit(base, commit_size); } // Extract arena header and fill it Arena *arena = (Arena *)base; arena->current = arena; arena->commit_size = commit_size; arena->reserve_size = reserve_size; arena->base_pos = 0; arena->pos = ARENA_HEADER_SIZE; arena->commit = commit_size; arena->reserve = reserve_size; return arena; } internal void arena_release(Arena *arena) { // Go back in chain and release for(Arena *n = arena->current, *prev = 0; n != 0; n = prev) { prev = n->prev; os_release(n, n->reserve); } } internal void * arena_push(Arena *arena, U64 size, U64 align) { Arena *current = arena->current; U64 pos_pre = AlignPow2(current->pos, align); U64 pos_post = pos_pre + size; // TODO(anton): Add chaining etc. Now we always just put up a new block. // Commit new pages if needed, that is if the new position of the arena pointer // is larger than the current commit adress. if(current->commit < pos_post) { U64 commit_post_aligned = pos_post + current->commit_size - 1; commit_post_aligned -= commit_post_aligned % current->commit_size; // Now commit_post_aligned is aligned U64 commit_post_clamped = ClampTop(commit_post_aligned, current->reserve); U64 commit_size = commit_post_clamped - current->commit; U8 *commit_ptr = (U8 *)current + current->commit; os_commit(commit_ptr, commit_size); current->commit = commit_post_clamped; } // Push to current block void *result = 0; if(current->commit >= pos_post) { result = (U8 *)current+pos_pre; current->pos = pos_post; } if(result == 0) { LOG("FATAL ERROR IN ARENA ALLOC"); ExitProcess(0); } return result; } internal U64 arena_pos(Arena *arena) { Arena *current = arena->current; U64 pos = current->base_pos + current->pos; return pos; } internal void arena_pop_to(Arena *arena, U64 pos) { U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos); Arena *current = arena->current; for(Arena *prev = 0; current->base_pos >= big_pos; current = prev) { prev = current->prev; os_release(current, current->reserve); } arena->current = current; U64 new_pos = big_pos - current->base_pos; AssertAlways(new_pos <= current->pos); current->pos = new_pos; } internal void arena_clear(Arena *arena) { arena_pop_to(arena, 0); } internal void arena_pop(Arena *arena, U64 amt) { U64 pos_old = arena_pos(arena); U64 pos_new = pos_old; if(amt < pos_old) { pos_new = pos_old - amt; } arena_pop_to(arena, pos_new); } //- rjf: temporary arena scopes internal Temp temp_begin(Arena *arena) { U64 pos = arena_pos(arena); Temp temp = {arena, pos}; return temp; } internal void temp_end(Temp temp) { arena_pop_to(temp.arena, temp.pos); }