scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit ee643349eedf014d5275bd38a4c7ffcf5719e148
parent 9a4612256c7e1642b4fcf860c81704aea4b5b00c
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Wed, 13 Sep 2017 16:19:29 +0100

[lib] Add generic arena allocator

At this moment we are using a specific arena allocator in cc2 for nodes,
but there are other places in the code where an arena allocator can be
used, so it is a good idea to have a generic implementation.

Diffstat:
cc2/target/qbe/code.c | 6+++---
inc/scc.h | 18++++++++++++++++++
lib/scc/alloc.c | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/scc/libdep.mk | 1+
4 files changed, 126 insertions(+), 3 deletions(-)

diff --git a/cc2/target/qbe/code.c b/cc2/target/qbe/code.c @@ -13,7 +13,7 @@ static char sccsid[] = "@(#) ./cc2/arch/qbe/code.c"; static void binary(void), unary(void), store(void), jmp(void), ret(void), branch(void), call(void), ecall(void), param(void), - alloc(void), form2local(void), ldir(void), vastart(void), + asalloc(void), form2local(void), ldir(void), vastart(void), vaarg(void); static struct opdata { @@ -146,7 +146,7 @@ static struct opdata { [ASCALLEX] = {.fun = ecall, .txt = ", ...)"}, [ASPAR] = {.fun = param, .txt = "%s %s, "}, [ASPARE] = {.fun = param, .txt = "%s %s"}, - [ASALLOC] = {.fun = alloc}, + [ASALLOC] = {.fun = asalloc}, [ASFORM] = {.fun = form2local}, [ASVSTAR] = {.fun = vastart}, @@ -516,7 +516,7 @@ vaarg(void) } static void -alloc(void) +asalloc(void) { Symbol *sym = pc->to.u.sym; Type *tp = &sym->type; diff --git a/inc/scc.h b/inc/scc.h @@ -19,6 +19,20 @@ struct items { unsigned n; }; +typedef struct alloc Alloc; + +struct arena; +union hdr; + +struct alloc { + size_t size; + size_t nmemb; + size_t padding; + struct arena *arena; + union hdr *freep; +}; + + extern void die(const char *fmt, ...); extern void dbg(const char *fmt, ...); extern void newitem(struct items *items, char *item); @@ -26,3 +40,7 @@ extern void *xmalloc(size_t size); extern void *xcalloc(size_t nmemb, size_t size); extern char *xstrdup(const char *s); extern void *xrealloc(void *buff, register size_t size); +extern Alloc *alloc(size_t size, size_t nmemb); +extern void dealloc(Alloc *allocp); +extern void *new(Alloc *allocp); +extern void delete(Alloc *allocp, void *p); diff --git a/lib/scc/alloc.c b/lib/scc/alloc.c @@ -0,0 +1,104 @@ +static char sccsid[] = "@(#) ./lib/alloc.c"; +#include <stdlib.h> +#include "../../inc/scc.h" + +/* + * This is the most pedantic piece of code that I have written + * in my life. The next union is used to enforce the aligmnet + * of the address returned by new(). A union has the aligment + * of the field with the biggest aligment. This union has all + * the types that we use in scc, and we round all the address + * to the aligment of this struct, so we can be sure that any + * pointer using that address will be safe. The field ap is + * in the union to be sure that struct pointers are included + * in the list, although they will have the same aligment or + * smaller than void *, but I wanted to be pedantic. + */ +union hdr { + union hdr *next; + struct arena *ap; + char c; + unsigned char uc; + int i; + short s; + long l; + long long ll; + float f; + double d; + long double ld; + void *vp; +}; + +struct arena { + struct arena *next; + union hdr *array; +}; + +static void +newarena(Alloc *allocp) +{ + struct arena *ap; + union hdr *bp, *lim; + size_t unit, n = allocp->nmemb; + + unit = (allocp->size-1) / sizeof(union hdr) + 1; + ap = xmalloc(sizeof(struct arena)); + ap->array = xmalloc(unit * sizeof(union hdr) * n); + + bp = ap->array; + for (lim = &bp[unit * (n-1)]; bp < lim; bp += unit) + bp->next = bp + unit; + bp->next = NULL; + + ap->next = allocp->arena; + allocp->arena = ap; + allocp->freep = ap->array; +} + +Alloc * +alloc(size_t size, size_t nmemb) +{ + Alloc *allocp = xmalloc(sizeof(*allocp)); + + allocp->size = size; + allocp->nmemb = nmemb; + allocp->arena = NULL; + allocp->freep = NULL; + + return allocp; +} + +void +dealloc(Alloc *allocp) +{ + struct arena *ap, *next; + + for (ap = allocp->arena; ap; ap = next) { + next = ap->next; + free(ap->array); + free(ap); + } + free(allocp); +} + +void * +new(Alloc *allocp) +{ + union hdr *bp; + + if (!allocp->freep) + newarena(allocp); + bp = allocp->freep; + allocp->freep = bp->next; + + return bp; +} + +void +delete(Alloc *allocp, void *p) +{ + union hdr *bp = p; + + bp->next = allocp->freep; + allocp->freep = bp; +} diff --git a/lib/scc/libdep.mk b/lib/scc/libdep.mk @@ -5,3 +5,4 @@ LIB-OBJ = $(LIBDIR)/debug.o \ $(LIBDIR)/xmalloc.o \ $(LIBDIR)/xrealloc.o \ $(LIBDIR)/xstrdup.o \ + $(LIBDIR)/alloc.o \