#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 mem·sys = { .alloc = ·alloc, .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 _bufpop(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 { mem·Allocator heap; void *impl; 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->impl = impl; 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(a->impl, 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->heap.free(a->impl, it); it = next; } a->heap.free(a->impl, a); } // ------------------------------------------------------------------------- // 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]; } } // ------------------------------------------------------------------------- // First argument char *argv0;