From 8c3a666975df04b30c88c20bd7384a17d0331ec2 Mon Sep 17 00:00:00 2001 From: yoyo Date: Wed, 4 Sep 2024 12:20:58 +0900 Subject: [PATCH] rewrite GC --- bltin.c | 46 ++++---- dat.h | 48 ++------ eval.c | 2 +- fn.h | 10 +- gc.c | 340 ++++++++++++++++++++++--------------------------------- main.c | 5 +- obj.c | 35 +++--- parser.c | 2 +- str.c | 52 +++++---- 9 files changed, 228 insertions(+), 312 deletions(-) diff --git a/bltin.c b/bltin.c index 483995b..b7f45f1 100644 --- a/bltin.c +++ b/bltin.c @@ -1,28 +1,28 @@ #include "dat.h" #include "fn.h" -Object Nil = (Object){.type=OSYMBOL, .sym="nil"}; -Object Minus= (Object){.type=OBLTIN, .sym="-"}; -Object Plus = (Object){.type=OBLTIN, .sym="+"}; -Object Mul = (Object){.type=OBLTIN, .sym="*"}; -Object Div = (Object){.type=OBLTIN, .sym="/"}; -Object Mod = (Object){.type=OBLTIN, .sym="%"}; +Object Nil = (Object){.type=OSYMBOL, .beg="nil"}; +Object Minus= (Object){.type=OBLTIN, .beg="-"}; +Object Plus = (Object){.type=OBLTIN, .beg="+"}; +Object Mul = (Object){.type=OBLTIN, .beg="*"}; +Object Div = (Object){.type=OBLTIN, .beg="/"}; +Object Mod = (Object){.type=OBLTIN, .beg="%"}; -Object Ge = (Object){.type=OBLTIN, .sym= ">="}; -Object Le = (Object){.type=OBLTIN, .sym= "<="}; -Object Lt = (Object){.type=OBLTIN, .sym= "<"}; -Object Gt = (Object){.type=OBLTIN, .sym= ">"}; -Object Ne = (Object){.type=OBLTIN, .sym= "!="}; -Object Eq = (Object){.type=OBLTIN, .sym= "=="}; +Object Ge = (Object){.type=OBLTIN, .beg= ">="}; +Object Le = (Object){.type=OBLTIN, .beg= "<="}; +Object Lt = (Object){.type=OBLTIN, .beg= "<"}; +Object Gt = (Object){.type=OBLTIN, .beg= ">"}; +Object Ne = (Object){.type=OBLTIN, .beg= "!="}; +Object Eq = (Object){.type=OBLTIN, .beg= "=="}; -Object Lambda= (Object){.type=OBLTIN, .sym="lambda"}; -Object Car = (Object){.type=OBLTIN, .sym="car"}; -Object Cdr = (Object){.type=OBLTIN, .sym="cdr"}; -Object Quote= (Object){.type=OBLTIN, .sym="'"}; -Object Cons = (Object){.type=OBLTIN, .sym="cons"}; -Object Define= (Object){.type=OBLTIN, .sym="define"}; -Object Setq = (Object){.type=OBLTIN, .sym="setq"}; -Object If = (Object){.type=OBLTIN, .sym="if"}; +Object Lambda= (Object){.type=OBLTIN, .beg="lambda"}; +Object Car = (Object){.type=OBLTIN, .beg="car"}; +Object Cdr = (Object){.type=OBLTIN, .beg="cdr"}; +Object Quote= (Object){.type=OBLTIN, .beg="'"}; +Object Cons = (Object){.type=OBLTIN, .beg="cons"}; +Object Define= (Object){.type=OBLTIN, .beg="define"}; +Object Setq = (Object){.type=OBLTIN, .beg="setq"}; +Object If = (Object){.type=OBLTIN, .beg="if"}; extern Object* fnplus(Object *, Object *); extern Object* fnmul(Object *, Object *); @@ -50,7 +50,7 @@ bltinlookup(Object *obj) { static struct { - Object *sym; + Object *beg; Bltinfn fn; }bltins[] = { {&Lambda , fnlambda}, @@ -75,8 +75,8 @@ bltinlookup(Object *obj) {0}, }; - for(int i = 0; bltins[i].sym; ++i){ - if(obj == bltins[i].sym) + for(int i = 0; bltins[i].beg; ++i){ + if(obj == bltins[i].beg) return bltins[i].fn; } return 0; diff --git a/dat.h b/dat.h index f0dfe62..c261c77 100644 --- a/dat.h +++ b/dat.h @@ -1,19 +1,17 @@ -#include - -typedef uintptr_t u64; +typedef struct GC GC; typedef struct Object Object; typedef Object* (*Bltinfn)(Object *env, Object *args); enum OType { - OERROR, - OCELL, - OSYMBOL, - OIDENT, - OINT, - OSTRING, - OLAMBDA, + ONONE, OBLTIN, + OSYMBOL, + OCELL, + OIDENT, + OSTRING, + OINT, + OLAMBDA, OFUNC, OENV, }; @@ -22,7 +20,6 @@ struct Object { enum OType type; /* type */ int flag; /* flag */ - Object *next; /* for gc */ Object *forward; union{ /* int */ @@ -32,8 +29,7 @@ struct Object Object *car; Object *cdr; }; - /* string & ident */ - char *sym; + /* string & ident & symbol */ struct{ char *beg; char *ptr; @@ -54,32 +50,6 @@ struct Object }; }; -/* - *0 ~ 64 : for object - *64 ~ 100 : for string - */ -typedef struct -{ - int running; - void *memory; - u64 cap; - u64 using; - u64 top; - /* objects */ - struct{ - Object *objs; - Object *freed; - u64 ob; - u64 oe; - u64 op; - }; - /* string */ - struct{ - u64 sb; - u64 se; - }; -}GC; - extern GC *gc; extern Object Nil; extern Object Minus; diff --git a/eval.c b/eval.c index f5a7cd4..f8be81d 100644 --- a/eval.c +++ b/eval.c @@ -144,7 +144,7 @@ plusstr(Object *env, Object *p) for(;p!=&Nil; p=p->cdr){ if(p->car->type != OSTRING) error("+ take only number"); - strputs(str, p->car->beg); + str = strputs(str, p->car); } return str; } diff --git a/fn.h b/fn.h index 76746cf..650868b 100644 --- a/fn.h +++ b/fn.h @@ -16,16 +16,16 @@ Object* newstr(GC *,int); Object* newfn(GC *,Object *env, Object *params, Object *body); /* gc.c */ -Object* newobj(GC *,enum OType); -void* gcalloc(GC *,int); -void* gcralloc(GC *, void*, int); GC* newgc(void *top, int cap); void gcrun(GC *); +void* gcalloc(GC *gc, int sz); +void printgc(char *, GC *); /* str.c */ -void strputc(Object*, int); -void strputs(Object*, char*); +Object* strputc(Object*, int); +Object* strputs(Object*, Object*); int strequal(Object*, Object*); +void strinit(Object *s, Object *str); /* error.c */ void panic(char *fmt, ...); diff --git a/gc.c b/gc.c index a8798ae..ef7b81e 100644 --- a/gc.c +++ b/gc.c @@ -4,50 +4,75 @@ #include #include #include +#include +#include + +struct GC +{ + int running; + int cap; + int using; + uintptr_t *top; + uintptr_t *beg; + uintptr_t *end; +}; enum { USING = 1 << 1, FORWARD = 1 << 2, - OFFSET = sizeof(int), + PTR = sizeof(void*), }; +static Object* +findobj(GC *gc, uintptr_t *stk) +{ + if(gc->beg <= stk && stk < gc->end) + for(uintptr_t *p = gc->beg; p < stk;){ + if(*p){ + if(p <= stk && stk < p + *p) return (Object*)&p[1]; + else p += *p; + }else{ + p++; + } + } + return 0; +} + Object* cloneobj(GC *dst, GC *src, Object *obj) { - if(obj == 0) - return 0; - if(obj->type==OBLTIN||obj->type==OSYMBOL) - return obj; - if(obj->flag&FORWARD) - return obj->forward; - Object *p = newobj(dst, obj->type); + if(obj->type==OBLTIN||obj->type==OSYMBOL) return obj; + if(obj->flag&FORWARD) return obj->forward; + + Object *p; obj->flag |= FORWARD; - obj->forward = p; switch(obj->type){ default: panic("unreachable"); case OINT: - p->num = obj->num; + obj->forward = p = newint(dst, obj->num); break; case OSTRING: - case OIDENT:{ - int len = obj->ptr - obj->beg; - p->beg = gcalloc(dst, len + 1); - p->end = p->ptr = p->beg + len; - memcpy(p->beg, obj->beg, len + 1); - break; - } + obj->forward = p = newstr(dst, obj->end - obj->beg); + strinit(p, obj); + break; + case OIDENT: + obj->forward = p = newsymbol(dst, obj->beg, obj->ptr - obj->beg); + break; case OCELL: + obj->forward = p = newcons(dst, &Nil, &Nil); p->car = cloneobj(dst, src, obj->car); p->cdr = cloneobj(dst, src, obj->cdr); break; case OENV: + obj->forward = p = newenv(dst, &Nil, &Nil, &Nil); p->name = cloneobj(dst, src, obj->name); p->vars = cloneobj(dst, src, obj->vars); p->up = cloneobj(dst, src, obj->up); break; case OFUNC: + obj->forward = p = newfn(dst, &Nil, &Nil, &Nil); p->params = cloneobj(dst, src, obj->params); p->body = cloneobj(dst, src, obj->body); p->env = cloneobj(dst, src, obj->env); @@ -56,138 +81,45 @@ cloneobj(GC *dst, GC *src, Object *obj) return p; } -Object* -moveobj(Object *p) -{ - if(p == 0 || p->type == 0) - return 0; - switch(p->type){ - default: - return p->forward; - case OBLTIN: - case OSYMBOL: - return p; - } -} - void -forwardstack(u64 bot, GC *dst, GC *src) +gcraise(GC *src) { - u64 pos, diff, *stk; - Object *moved, *org; - for(; bot < src->top; bot += sizeof(bot)){ - stk = (u64*)(void**)bot; - if(src->ob <= *stk && *stk < src->oe){ - diff = (*stk - src->ob) % sizeof(Object); - org = (Object*)(*stk - diff); - if((moved = moveobj(org)) == 0) - continue; - diff = (u64)org - *stk; - pos = (u64)moved + diff; - memcpy(stk, &pos, sizeof(pos)); + jmp_buf reg; + uintptr_t _ = 0; + if(src->running) return; + if(setjmp(reg) == 1) return; + + GC *dst = newgc(src->top, src->cap * 2); + src->running = dst->running = 1; + for(uintptr_t *p = src->beg; p < src->end;) + if(*p){ + cloneobj(dst, src, (Object*)&p[1]); + p += *p; + }else{ + p++; } - else if(src->sb <= *stk && *stk < src->se) - for(org = src->objs; org; org = org->next){ - if(org->type == OSTRING || org->type == OIDENT){ - u64 beg = (u64)org->beg - OFFSET; - u64 end = beg + *(int*)beg; - if(beg <= *stk && *stk < end){ - moved = moveobj(org); - diff = (*stk - beg); - pos = (u64)moved->beg - OFFSET + diff; - memcpy(stk, &pos, sizeof(pos)); - break; - } - } + for(uintptr_t *bot = &_; bot < src->top; bot++){ + Object *p = findobj(src, (uintptr_t*)*bot); + if(p){ + uintptr_t diff = (uintptr_t)p - *bot; + uintptr_t pos = (uintptr_t)p->forward + diff; + memcpy(bot, &pos, PTR); } } -} -void -gccompact(int cap, GC *src) -{ - void *_ = 0; - u64 bot = (u64)&_; - GC *dst = newgc((void*)src->top, cap); - dst->running = 1; - for(Object *p=src->objs; p; p=p->next) - cloneobj(dst, src, p); - forwardstack(bot, dst, src); - free(src->memory); + free((void*)src->beg); + dst->running = 0; *src = *dst; free(dst); -} - -void -gcfree(GC *gc, void *src) -{ - int *p = (int*)src - 1; - int sz = *p; - memset(p, 0, sz); - gc->using -= sz; -} - -void -freeobj(GC *gc, Object *p) -{ - gc->using -= sizeof(Object); - p->next = 0; - switch(p->type){ - default: - break; - case OSTRING: - case OIDENT: - gcfree(gc, p->beg); - break; - } - memset(p, 0, sizeof(Object)); - if(gc->freed == 0) - gc->freed = p; - else{ - p->next = gc->freed; - gc->freed = p; - } -} - -void* -gcalloc(GC *gc, int sz) -{ - sz += OFFSET; - if(sz % OFFSET) sz = sz + OFFSET - (sz % OFFSET); - for(u64 i = gc->sb; i < gc->se;){ - u64 j = i; - for(;j - i < sz; j += OFFSET){ - if(*(int*)(j) != 0) - break; - } - if(j - i == sz){ - gc->using += sz; - *(int*)i = sz; - i += OFFSET; - return (void*)i; - } - i = j + *(int*)(j); - } - panic("gccalloc : Not impl yet raise"); - return 0; -} - -void* -gcralloc(GC *gc, void *src, int sz) -{ - void *dst = gcalloc(gc, sz); - int osz = ((int*)src)[-1]; - memcpy(dst, src, osz); - gcfree(gc, src); - return dst; + longjmp(reg, 1); } void mark(GC *gc, Object *obj) { - if(obj == 0 || obj->flag&USING || - obj->type == 0|| obj->type==OBLTIN ||obj->type==OSYMBOL) + if(obj->flag&USING||obj->type==ONONE||obj->type==OSYMBOL||obj->type==OBLTIN) return; + obj->flag = USING; switch(obj->type){ default:break; @@ -211,91 +143,93 @@ mark(GC *gc, Object *obj) void gcsweep(GC *gc) { - Object *last = 0; - for(Object *p = gc->objs; p;){ - if(p->type == 0|| p->type==OBLTIN ||p->type==OSYMBOL) - return; - if(p->flag&USING){ - p->flag &= ~(USING); - last = p; - p = p->next; - }else{ - Object *tmp = p; - if(last == 0){ - gc->objs = p->next; + for(uintptr_t *p = gc->beg; p < gc->end;) + if(*p){ + Object *obj = (Object*)&p[1]; + if(obj->flag & USING){ + obj->flag = 0; + p += p[0]; }else{ - last->next = p->next; + uintptr_t sz = *p; + memset(p, 0, sz*PTR); + gc->using -= sz*PTR; + p += sz; } - p = p->next; - freeobj(gc, tmp); + }else{ + p++; } - } } void gcmark(GC *gc) { - u64 _ = 0, stk, diff; - u64 bot = (u64)&_; - Object *obj; - for(; bot < gc->top; bot += sizeof(bot)){ - stk = (u64)*(void**)bot; - if(gc->ob <= stk && stk <= gc->oe){ - diff = (stk - gc->ob) % sizeof(Object); - obj = (Object*)(stk - diff); + uintptr_t _ = 0; + for(uintptr_t *bot = &_; bot < gc->top; bot++){ + Object *obj = findobj(gc, (uintptr_t*)*bot); + if(obj) mark(gc, obj); - } - else if(gc->sb <= stk && stk <= gc->se) - for(Object *obj = gc->objs; obj; obj = obj->next) - if(obj->type == OSTRING || obj->type == OIDENT){ - u64 beg = (u64)obj->beg - OFFSET; - u64 end = beg + *(int*)beg; - if(beg <= stk && stk < end){ - mark(gc, obj); - break; - } - } } } void -gcrun(GC *src) +gcrun(GC *gc) { - if(src->running) + if(gc->running) return; - printf("BEFORE=> cap:%10ld using:%10ld remain:%10ld\n", src->cap, src->using, src->cap - src->using); - src->running = 1; + printgc("gc-beg", gc); + gc->running = 1; jmp_buf reg; if(setjmp(reg)==1){ - printf("AFTER => cap:%10ld using:%10ld remain:%10ld\n", src->cap, src->using, src->cap - src->using); - src->running = 0; + gc->running = 0; + printgc("gc-end", gc); return; } - gcmark(src); - gcsweep(src); - if(src->using >= src->cap * 0.5){ - gccompact(src->cap * 2, src); - } + gcmark(gc); + gcsweep(gc); longjmp(reg, 1); } -Object* -newobj(GC *gc, enum OType type) +static void* +alloc(GC *gc, int sz) { - gcrun(gc); - gc->using += sizeof(Object); - Object *r = 0; - if(gc->freed){ - r = gc->freed; - gc->freed = gc->freed->next; - }else{ - r = (Object*)gc->op; - gc->op += sizeof(Object); + sz /= PTR; + for(uintptr_t *p = gc->beg; p < gc->end - sz;){ + int i = 0; + for(; p[i] == 0 && i < sz; ++i) + ; + if(i == sz){ + *p = sz; + gc->using += sz*PTR; + return p+1; + } + if(p[i]) p = &p[i] + p[i]; + else p = &p[i] + 1; } - r->type = type; - if(gc->objs) - r->next = gc->objs; - return gc->objs = r; + return 0; +} + +void* +gcalloc(GC *gc, int sz) +{ + sz += PTR; + if(sz%PTR) sz = sz + PTR - sz % PTR; + if(gc->using + sz > gc->cap * 0.64) gcrun(gc); + + void *p = alloc(gc, sz); + if(p) + return p; + gcraise(gc); + p = alloc(gc, sz); + if(p) + return p; + panic("newobj:can't alloc %d byte", sz); + return 0; +} + +void +printgc(char *prefix, GC *gc) +{ + printf("%*s=> cap:%10d using:%10d remain:%10d\n", 10, prefix, gc->cap, gc->using, gc->cap - gc->using); } GC* @@ -304,16 +238,10 @@ newgc(void *top, int cap) GC *gc = calloc(1, sizeof(GC)); if(gc == 0) panic("can't alloc %d byte\n", sizeof(GC)); - gc->top = (u64)top; - if((gc->memory = calloc(1, cap)) == 0) - panic("can't alloc %d byte\n", cap); gc->cap = cap; - gc->using = 0; - - gc->op = gc->ob = (u64)gc->memory; - gc->oe = gc->op + (float)cap * 0.75; - - gc->sb = (u64)gc->memory + (float)cap * 0.75; - gc->se = (u64)gc->memory + cap; + gc->top = top; + if((gc->beg = calloc(1, cap)) == 0) + panic("can't alloc %d byte\n", cap); + gc->end = gc->beg + cap/PTR; return gc; } diff --git a/main.c b/main.c index 377cfa5..e1b85fc 100644 --- a/main.c +++ b/main.c @@ -32,7 +32,7 @@ SExprint(Object *obj) break; case OBLTIN: case OSYMBOL: - printf("%s", obj->sym); + printf("%s", obj->beg); break; case OENV: printf(""); @@ -71,6 +71,7 @@ loop(void) while(1){ Object *res = nextexpr(); res = eval(env, res); + printgc("status", gc); printf("=============res===========\n"); printexpr(res); printf("=============env===========\n"); @@ -82,6 +83,6 @@ loop(void) int main(int argc, char *argv[]) { - gc = newgc(&argc, 4000); + gc = newgc(&argc, 500); loop(); } diff --git a/obj.c b/obj.c index ded5054..9ed888d 100644 --- a/obj.c +++ b/obj.c @@ -3,10 +3,18 @@ #include #include +static Object* +newobj(GC *gc, enum OType type, int sz) +{ + Object *obj = gcalloc(gc, sizeof(Object) + sz); + obj->type = type; + return obj; +} + Object* newint(GC *gc, long val) { - Object *obj = newobj(gc, OINT); + Object *obj = newobj(gc, OINT, 0); obj->num = val; return obj; } @@ -14,7 +22,7 @@ newint(GC *gc, long val) Object* newcons(GC *gc, Object *car, Object *cdr) { - Object *obj = newobj(gc, OCELL); + Object *obj = newobj(gc, OCELL, 0); obj->car = car; obj->cdr = cdr; return obj; @@ -23,7 +31,7 @@ newcons(GC *gc, Object *car, Object *cdr) Object* newenv(GC *gc, Object* name, Object *vars, Object *up) { - Object *obj = newobj(gc, OENV); + Object *obj = newobj(gc, OENV, 0); obj->name = name; obj->up = up; obj->vars = vars; @@ -40,7 +48,7 @@ newacons(GC *gc, Object *x, Object *y, Object *z) Object* newfn(GC *gc, Object *env, Object *params, Object *body) { - Object *fn = newobj(gc, OFUNC); + Object *fn = newobj(gc, OFUNC, 0); fn->params = params; fn->body = body; fn->env = env; @@ -57,21 +65,22 @@ newsymbol(GC *gc, char *str, int len) }; for(int i = 0; i < sizeof(syms)/sizeof(syms[0]); ++i){ Object *c = syms[i]; - if(strlen(c->sym)==len && memcmp(c->sym, str, len) == 0) + if(strlen(c->beg)==len && memcmp(c->beg, str, len) == 0) return c; } - Object *obj = newobj(gc, OIDENT); - obj->beg = gcalloc(gc, len + 1); - obj->end = obj->ptr = obj->beg + len; - memcpy(obj->beg, str, len+1); + Object *obj = newobj(gc, OIDENT, len + 1); + obj->ptr = obj->beg = (char*)&obj[1]; + obj->end = obj->beg + len; + memcpy(obj->beg, str, len + 1); + obj->ptr += len; return obj; } Object* newstr(GC *gc, int len) { - Object *obj = newobj(gc, OSTRING); - obj->ptr = obj->beg = gcalloc(gc, len + 1); + Object *obj = newobj(gc, OSTRING, len + 1); + obj->ptr = obj->beg = (char*)&obj[1]; obj->end = obj->beg + len; - return obj; -} + return obj; +} \ No newline at end of file diff --git a/parser.c b/parser.c index c4c824a..19aec4b 100644 --- a/parser.c +++ b/parser.c @@ -88,7 +88,7 @@ string(void) { Object *str = newstr(gc, 16); while(lookup() != '\"'){ - strputc(str, get()); + str = strputc(str, get()); } expect('\"'); return str; diff --git a/str.c b/str.c index 4dea718..7ffe339 100644 --- a/str.c +++ b/str.c @@ -3,33 +3,41 @@ #include void -strraise(Object *s, int ns) +strinit(Object *s, Object *p) { - int pos = s->ptr - s->beg; - char *ptr = gcralloc(gc, s->beg, ns + 1); - s->beg = ptr; - s->ptr = s->beg + pos; - s->end = s->beg + ns; -} - -void -strputc(Object *s, int c) -{ - if(s->ptr >= s->end) - strraise(s, (s->end - s->beg) * 2); - *s->ptr++ = c; + for(char *c = p->beg ; c < p->ptr;) + *s->ptr++ = *c++; *s->ptr = 0; } -void -strputs(Object *s, char *ptr) +Object* +strraise(Object *s, int ns) { - int l = strlen(ptr); - if(s->ptr + l >= s->end) - strraise(s, s->end - s->beg + l); - memcpy(s->ptr, ptr, l); + Object *dst = newstr(gc, ns + 1); + strinit(dst, s); + return dst; +} + +Object* +strputc(Object *s, int c) +{ + if(s->ptr + 1 >= s->end) + s = strraise(s, (s->end - s->beg) * 2); + *s->ptr++ = c; + *s->ptr = 0; + return s; +} + +Object* +strputs(Object *s, Object *ptr) +{ + int l = ptr->ptr - ptr->beg; + if(s->ptr + l>= s->end) + s = strraise(s, s->end - s->beg + l); + memcpy(s->ptr, ptr->beg, l); s->ptr += l; - s->ptr[0] = 0; + *s->ptr = 0; + return s; } int @@ -38,4 +46,4 @@ strequal(Object *a, Object *b) int la = a->ptr - a->beg; int lb = b->ptr - b->beg; return la == lb && memcmp(a->beg, b->beg, la) == 0; -} +} \ No newline at end of file