2024-07-10 18:11:42 +00:00
|
|
|
// Mostly taken from the raddebugger -- thanks, Ryan.
|
|
|
|
|
2024-07-10 15:48:23 +00:00
|
|
|
#define align_pow2(x, b) (((x) + (b) - 1) & ( ~((b) - 1)))
|
|
|
|
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
|
|
|
|
2024-07-11 12:00:43 +00:00
|
|
|
#ifdef ENABLE_ASAN
|
2024-07-10 15:48:23 +00:00
|
|
|
#define asan_poison_memory_region(mem, cmt) __asan_poison_memory_region(mem, cmt)
|
|
|
|
#define asan_unpoison_memory_region(mem, cmt) __asan_unpoison_memory_region(mem, cmt)
|
|
|
|
#else
|
|
|
|
#define asan_poison_memory_region(mem, cmt)
|
|
|
|
#define asan_unpoison_memory_region(mem, cmt)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// init_res: initial reserved size
|
|
|
|
// init_cmt: initial committed size
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 15:48:23 +00:00
|
|
|
Arena *arena_alloc_sized(u64 init_res, u64 init_cmt)
|
|
|
|
{
|
|
|
|
assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
|
|
|
|
|
|
|
|
u64 page_size = getpagesize();
|
|
|
|
u64 res = align_pow2(init_res, page_size);
|
|
|
|
u64 cmt = align_pow2(init_cmt, page_size);
|
|
|
|
|
|
|
|
// reserve memory
|
|
|
|
void *mem = os_reserve(res);
|
|
|
|
if (!os_commit(mem, cmt)) {
|
|
|
|
munmap(mem, init_res);
|
|
|
|
}
|
|
|
|
|
|
|
|
Arena *arena = (Arena *)mem;
|
|
|
|
if (arena) {
|
|
|
|
asan_poison_memory_region(mem, cmt);
|
|
|
|
asan_unpoison_memory_region(mem, ARENA_HEADER_SIZE);
|
|
|
|
|
|
|
|
arena->cur = arena;
|
|
|
|
arena->pos = ARENA_HEADER_SIZE;
|
|
|
|
arena->cmt = cmt;
|
|
|
|
arena->res = res;
|
|
|
|
arena->align = 8;
|
2024-07-10 18:11:42 +00:00
|
|
|
arena->grow = true;
|
2024-07-10 15:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return arena;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 15:48:23 +00:00
|
|
|
Arena *arena_alloc()
|
|
|
|
{
|
|
|
|
return arena_alloc_sized(ARENA_RESERVE_SIZE, ARENA_COMMIT_SIZE);
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 15:48:23 +00:00
|
|
|
void arena_release(Arena *arena)
|
|
|
|
{
|
|
|
|
for (Arena *node = arena->cur, *prev = 0; node; node = prev) {
|
|
|
|
prev = node->prev;
|
|
|
|
os_release(node, node->res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 13:27:38 +00:00
|
|
|
internal u64
|
|
|
|
arena_mem_used(Arena *arena)
|
|
|
|
{
|
|
|
|
u64 tot = 0;
|
|
|
|
for (Arena *node = arena->cur, *prev = 0; node; node = prev) {
|
|
|
|
tot += node->pos - node->base_pos;
|
|
|
|
}
|
|
|
|
return tot;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 15:48:23 +00:00
|
|
|
u64 arena_huge_push_threshold()
|
|
|
|
{
|
|
|
|
u64 res = ARENA_RESERVE_SIZE;
|
|
|
|
u64 threshold = (res - ARENA_HEADER_SIZE) / 2 + 1;
|
|
|
|
return threshold;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 15:48:23 +00:00
|
|
|
void *arena_push_impl(Arena *arena, u64 size)
|
|
|
|
{
|
|
|
|
Arena *cur = arena->cur;
|
|
|
|
u64 pos_mem = align_pow2(cur->pos, arena->align);
|
|
|
|
u64 pos_new = pos_mem + size;
|
|
|
|
|
2024-07-10 18:11:42 +00:00
|
|
|
if (cur->res < pos_new && arena->grow) {
|
2024-07-10 15:48:23 +00:00
|
|
|
Arena *new_block;
|
|
|
|
if (size < arena_huge_push_threshold()) {
|
|
|
|
new_block = arena_alloc();
|
|
|
|
} else {
|
|
|
|
u64 new_block_size = size + ARENA_HEADER_SIZE;
|
|
|
|
new_block = arena_alloc_sized(new_block_size, new_block_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_block) {
|
|
|
|
new_block->base_pos = cur->base_pos + cur->res;
|
2024-07-11 13:27:38 +00:00
|
|
|
new_block->prev = arena->cur;
|
|
|
|
arena->cur = new_block;
|
2024-07-10 15:48:23 +00:00
|
|
|
|
|
|
|
cur = new_block;
|
|
|
|
pos_mem = align_pow2(cur->pos, cur->align);
|
|
|
|
pos_new = pos_mem + size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur->cmt < pos_new) {
|
|
|
|
u64 cmt_new_aligned = align_pow2(pos_new, ARENA_COMMIT_SIZE);
|
2024-07-10 18:11:42 +00:00
|
|
|
u64 cmt_new_clamped = min(cmt_new_aligned, cur->res);
|
2024-07-10 15:48:23 +00:00
|
|
|
u64 cmt_new_size = cmt_new_clamped - cur->cmt;
|
|
|
|
b32x is_cmt_ok = os_commit((u8*)cur + cur->cmt, cmt_new_size);
|
|
|
|
|
|
|
|
if (is_cmt_ok)
|
|
|
|
cur->cmt = cmt_new_clamped;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *mem = 0;
|
|
|
|
if (cur->cmt >= pos_new) {
|
|
|
|
mem = (u8*)cur + pos_mem;
|
|
|
|
cur->pos = pos_new;
|
|
|
|
asan_unpoison_memory_region(mem, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
}
|
2024-07-10 18:11:42 +00:00
|
|
|
|
|
|
|
template <typename T>
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
T *arena_push(Arena *arena)
|
|
|
|
{
|
|
|
|
void *mem = arena_push_impl(arena, sizeof(T));
|
|
|
|
return (T *)mem;
|
|
|
|
}
|
|
|
|
|
2024-07-11 12:00:43 +00:00
|
|
|
template <typename T>
|
|
|
|
internal
|
|
|
|
T *arena_push_zeroed(Arena *arena)
|
|
|
|
{
|
|
|
|
T *mem = arena_push<T>(arena);
|
|
|
|
memset(mem, 0, sizeof(T));
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
2024-07-10 18:11:42 +00:00
|
|
|
template <typename T>
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
T *arena_push_array_no_zero(Arena *arena, u64 count)
|
|
|
|
{
|
|
|
|
void *mem = arena_push_impl(arena, sizeof(T) * count);
|
|
|
|
return (T *)mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
T *arena_push_array(Arena *arena, u64 count)
|
|
|
|
{
|
|
|
|
T *ary = arena_push_array_no_zero<T>(arena, count);
|
|
|
|
memset(ary, 0, sizeof(T) * count);
|
|
|
|
return ary;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
u8 *arena_push_contiguous(Arena *arena, u64 size)
|
|
|
|
{
|
|
|
|
b32 restore = arena->grow;
|
|
|
|
arena->grow = 0;
|
|
|
|
void *mem = arena_push_impl(arena, size);
|
|
|
|
arena->grow = restore;
|
|
|
|
return (u8 *)mem;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
u64 arena_pos(Arena *arena)
|
|
|
|
{
|
|
|
|
Arena *cur = arena->cur;
|
|
|
|
u64 pos = cur->base_pos + cur->pos;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
void arena_pop_to(Arena *arena, u64 big_pos_unclamped)
|
|
|
|
{
|
2024-07-11 12:00:43 +00:00
|
|
|
u64 big_pos = max(ARENA_HEADER_SIZE, big_pos_unclamped);
|
2024-07-10 18:11:42 +00:00
|
|
|
|
|
|
|
// unroll the chain
|
|
|
|
Arena *current = arena->cur;
|
|
|
|
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
|
|
|
|
prev = current->prev;
|
|
|
|
os_release(current, current->res);
|
|
|
|
}
|
|
|
|
assert(current);
|
|
|
|
arena->cur = current;
|
|
|
|
|
|
|
|
// compute arena-relative position
|
|
|
|
u64 new_pos = big_pos - current->base_pos;
|
|
|
|
assert(new_pos <= current->pos);
|
|
|
|
|
|
|
|
// poison popped memory block
|
|
|
|
asan_poison_memory_region((u8*)current + new_pos, (current->pos - new_pos));
|
|
|
|
|
|
|
|
// update position
|
|
|
|
current->pos = new_pos;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
Temp temp_begin(Arena *arena)
|
|
|
|
{
|
|
|
|
u64 pos = arena_pos(arena);
|
|
|
|
Temp temp = {arena, pos};
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2024-07-10 19:47:37 +00:00
|
|
|
internal
|
2024-07-10 18:11:42 +00:00
|
|
|
void temp_end(Temp temp)
|
|
|
|
{
|
|
|
|
arena_pop_to(temp.arena, temp.pos);
|
|
|
|
}
|