aboutsummaryrefslogtreecommitdiff
path: root/src/base/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/mem')
-rw-r--r--src/base/mem/arena.c119
-rw-r--r--src/base/mem/buffer.c45
-rw-r--r--src/base/mem/interface.c36
-rw-r--r--src/base/mem/internal.h4
-rw-r--r--src/base/mem/rules.mk5
-rw-r--r--src/base/mem/set64.c13
6 files changed, 222 insertions, 0 deletions
diff --git a/src/base/mem/arena.c b/src/base/mem/arena.c
new file mode 100644
index 0000000..b2ce044
--- /dev/null
+++ b/src/base/mem/arena.c
@@ -0,0 +1,119 @@
+#include "internal.h"
+
+#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;
+};
+
+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,
+};
+
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
diff --git a/src/base/mem/buffer.c b/src/base/mem/buffer.c
new file mode 100644
index 0000000..b684d35
--- /dev/null
+++ b/src/base/mem/buffer.c
@@ -0,0 +1,45 @@
+#include "internal.h"
+
+/* 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--;
+}
diff --git a/src/base/mem/interface.c b/src/base/mem/interface.c
new file mode 100644
index 0000000..4d7d1ce
--- /dev/null
+++ b/src/base/mem/interface.c
@@ -0,0 +1,36 @@
+#include "internal.h"
+
+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
+};
+
+mem·Reallocator sys·FullMemory = {
+ .alloc = ·calloc,
+ .realloc = ·realloc,
+ .free = ·free
+};
diff --git a/src/base/mem/internal.h b/src/base/mem/internal.h
new file mode 100644
index 0000000..302c035
--- /dev/null
+++ b/src/base/mem/internal.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <u.h>
+#include <base.h>
diff --git a/src/base/mem/rules.mk b/src/base/mem/rules.mk
new file mode 100644
index 0000000..b912d0c
--- /dev/null
+++ b/src/base/mem/rules.mk
@@ -0,0 +1,5 @@
+SRCS_$(d)+=\
+ $(d)/mem/arena.c\
+ $(d)/mem/buffer.c\
+ $(d)/mem/interface.c\
+ $(d)/mem/set64.c\
diff --git a/src/base/mem/set64.c b/src/base/mem/set64.c
new file mode 100644
index 0000000..464b3ad
--- /dev/null
+++ b/src/base/mem/set64.c
@@ -0,0 +1,13 @@
+#include "internal.h"
+
+void
+mem·set64(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];
+}