From 7d254c81400128923d1952909bf22b1784e540fc Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Tue, 21 Apr 2020 13:29:38 -0700 Subject: feat: added simple memory arena allocator to libn --- sys/libn/memory.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'sys/libn/memory.c') diff --git a/sys/libn/memory.c b/sys/libn/memory.c index d3deef7..6b715d9 100644 --- a/sys/libn/memory.c +++ b/sys/libn/memory.c @@ -48,3 +48,92 @@ _bufpop(void *buf, int i, vlong eltsize) _bufHdr(buf)->len--; } +// ------------------------------------------------------------------------- +// Arena allocator + +#define ARENA_ALIGN 8 +#define ARENA_BLOCK_SIZE 1024 * 1024 + +#define ALIGN_DOWN(n, a) ((n) & ~((a)-1)) +#define ALIGN_UP(n, a) ALIGN_DOWN((n) + (a)-1, (a)) +#define ALIGN_DOWN_PTR(p, a) ((void*)ALIGN_DOWN((uintptr)(p), (a))) +#define ALIGN_UP_PTR(p, a) ((void*)ALIGN_UP((uintptr)(p), (a))) + +struct Block +{ + struct Block *next; + byte buf[]; +}; + +struct mem·Arena +{ + mem·Allocator heap; + byte *off; + byte *end; + struct Block *curr; + struct Block first; +}; + +mem·Arena* +mem·newarena(mem·Allocator from) +{ + mem·Arena *a = from.alloc(sizeof(*a) + ARENA_BLOCK_SIZE); + a->heap = from; + a->off = a->first.buf; + a->end = a->first.buf + ARENA_BLOCK_SIZE; + a->curr = &a->first; + a->first.next = nil; + + return a; +} + +void +grow(mem·Arena *a, vlong min) +{ + uintptr size; + struct Block *blk; + + size = ALIGN_UP(MAX(min, ARENA_BLOCK_SIZE), ARENA_ALIGN); + blk = a->heap.alloc(sizeof(*blk) + size); + a->off = blk->buf; + a->end = a->off + size; + + Assert(a->curr->next == nil); + Assert(a->off == ALIGN_DOWN_PTR(a->off, ARENA_ALIGN)); + + a->curr->next = blk; + a->curr = blk; +} + +void* +mem·arenaalloc(mem·Arena *a, ulong size) +{ + void *ptr; + if (size > (ulong)(a->end - a->off)) { + grow(a, size); + Assert(size <= (uintptr)(a->end - a->off)); + } + + ptr = a->off; + a->off = ALIGN_UP_PTR(a->off + size, ARENA_ALIGN); + + Assert(a->off <= a->end); + Assert(ptr == ALIGN_DOWN_PTR(ptr, ARENA_ALIGN)); + + return ptr; +} + +void +mem·freearena(mem·Arena *a) +{ + struct Block *it, *next; + + it = &a->first; + while (it != nil) { + next = it->next; + a->heap.free(it); + it = next; + } + + a->heap.free(a); +} -- cgit v1.2.1