#include #include static void ·free(void *_, void *ptr) { return free(ptr); } static void * ·alloc(void *_, uint n, ulong size) { return malloc(n*size); } static void * ·calloc(void *_, uint n, ulong size) { return calloc(n, size); } static void * ·realloc(void *_, void *ptr, uint n, ulong size) { return realloc(ptr, n*size); } mem·Allocator sys·Memory = { .alloc = ·calloc, .free = ·free }; // ------------------------------------------------------------------------- // Dynamic buffer. /* Grow to particular size */ void* ·bufgrow(void* buf, vlong newLen, vlong eltsize) { assert(bufcap(buf) <= (SIZE_MAX - 1) / 2); vlong newCap = MAX(16, MAX(1 + 2 * bufcap(buf), newLen)); assert(newLen <= newCap); assert(newCap <= (SIZE_MAX - offsetof(BufHdr, buf)) / eltsize); vlong newSize = offsetof(BufHdr, buf) + newCap * eltsize; BufHdr* newHdr; if (buf) { newHdr = bufhdr(buf); newHdr = (BufHdr*)realloc((void*)newHdr, newSize); } else { newHdr = (BufHdr*)malloc(newSize); newHdr->len = 0; } newHdr->cap = newCap; return (void*)newHdr->buf; } /* Pop out a value */ void ·bufdel(void *buf, int i, vlong eltsize) { int n; byte *b; byte stk[1024]; assert(eltsize < sizeof(stk)); b = (byte*)buf; if(n = buflen(buf), i < n) { memcpy(stk, b+eltsize*i, eltsize); memcpy(b+eltsize*i, b+eltsize*(i+1), eltsize*(n-i-1)); memcpy(b+eltsize*(n-1), stk, 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 { void *heap; mem·Allocator mem; byte *off; byte *end; struct Block *curr; struct Block first; }; mem·Arena* mem·makearena(mem·Allocator from, void *impl) { mem·Arena *a = from.alloc(impl, 1, sizeof(*a) + ARENA_BLOCK_SIZE); a->mem = from; a->heap = impl; a->off = a->first.buf; a->end = a->first.buf + ARENA_BLOCK_SIZE; a->curr = &a->first; a->first.next = nil; return a; } static void grow(mem·Arena *a, vlong min) { uintptr size; struct Block *blk; size = ALIGN_UP(MAX(min, ARENA_BLOCK_SIZE), ARENA_ALIGN); blk = a->mem.alloc(a->heap, 1, 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, uint n, ulong size) { if(!n) { return nil; } void *ptr; // TODO(nnoll): check for overflow size = n * size; 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.next; while (it != nil) { next = it->next; a->mem.free(a->heap, it); it = next; } a->mem.free(a->heap, a); } static void* ·arenaalloc(void *heap, uint n, ulong size) { return mem·arenaalloc(heap, n, size); } static void ·arenafree(void *heap, void *ptr) { /* no-op */ } mem·Allocator mem·ArenaAllocator = { .alloc = ·arenaalloc, .free = ·arenafree, }; // ------------------------------------------------------------------------- // Generalized memory helpers void memset64(void *dst, uint64 val, uintptr size) { intptr i; for (i = 0; i < (size & (~7)); i += 8) { memcpy((byte*)dst + i, &val, 8); } for (; i < size; i++) { ((byte*)dst)[i] = ((byte*)&val)[i&7]; } }