klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit 13815696f641e7d0742b3de7c21ff2ed8adaaa6c
parent 0777435d9df74745aecdf2f076054db5c13fb540
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Tue, 19 Apr 2011 23:23:30 -0300

Added GC support for string/symbol table.

Diffstat:
Msrc/Makefile | 3++-
Msrc/kgc.c | 100++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/kgc.h | 6+++---
Msrc/kstate.c | 7+++++++
Msrc/kstate.h | 1+
5 files changed, 66 insertions(+), 51 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -145,4 +145,5 @@ kgstrings.o: kgstrings.c kgstrings.h kghelpers.h kstate.h klisp.h \ kobject.h kerror.h kapplicative.h koperative.h kcontinuation.h \ kstring.h ksymbol.h kgnumbers.h imath.o: kobject.h kstate.h kmem.h kerror.h -kgc.o: kgc.c kgc.h kobject.h kmem.h kstate.h kport.h imath.h ktable.h +kgc.o: kgc.c kgc.h kobject.h kmem.h kstate.h kport.h imath.h ktable.h \ + kstring.h diff --git a/src/kgc.c b/src/kgc.c @@ -18,10 +18,7 @@ #include "kport.h" #include "imath.h" #include "ktable.h" - -/* XXX */ -#include "kwrite.h" -/* XXX */ +#include "kstring.h" #define GCSTEPSIZE 1024u #define GCSWEEPMAX 40 @@ -385,10 +382,9 @@ static void cleartable (GCObject *l) { } static void freeobj (klisp_State *K, GCObject *o) { - /* TODO use specific functions like in bigint & lua */ + /* TODO use specific functions like in bigint & table */ uint8_t type = o->gch.tt; switch (type) { - /* case LUA_TTABLE: luaH_free(L, gco2h(o)); break; */ case K_TBIGINT: { mp_int_free(K, (Bigint *)o); break; @@ -397,10 +393,15 @@ static void freeobj (klisp_State *K, GCObject *o) { klispM_free(K, (Pair *)o); break; case K_TSYMBOL: + /* symbols are in the string/symbol table */ /* The string will be freed before/after */ + K->strt.nuse--; klispM_free(K, (Symbol *)o); break; case K_TSTRING: + /* immutable strings are in the string/symbol table */ + if (kstring_immutablep(gc2str(o))) + K->strt.nuse--; klispM_freemem(K, o, sizeof(String)+o->str.size+1); break; case K_TENVIRONMENT: @@ -468,20 +469,19 @@ static GCObject **sweeplist (klisp_State *K, GCObject **p, uint32_t count) return p; } -#if 0 /* klisp: keep this around */ -static void checkSizes (lua_State *L) { - global_State *g = G(L); - /* check size of string hash */ - if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && - g->strt.size > MINSTRTABSIZE*2) - luaS_resize(L, g->strt.size/2); /* table is too big */ +static void checkSizes (klisp_State *K) { + /* check size of string/symbol hash */ + if (K->strt.nuse < cast(uint32_t , K->strt.size/4) && + K->strt.size > MINSTRTABSIZE*2) + klispS_resize(K, K->strt.size/2); /* table is too big */ +#if 0 /* not used in klisp */ /* check size of buffer */ if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ size_t newsize = luaZ_sizebuffer(&g->buff) / 2; luaZ_resizebuffer(L, &g->buff, newsize); } -} #endif +} #if 0 /* klisp: keep this around */ static void GCTM (lua_State *L) { @@ -529,6 +529,9 @@ void klispC_freeall (klisp_State *K) { K->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* in klisp this may not be necessary */ sweepwholelist(K, &K->rootgc); + /* free all symbol/string lists */ + for (int32_t i = 0; i < K->strt.size; i++) + sweepwholelist(K, &K->strt.hash[i]); } @@ -603,6 +606,7 @@ static void atomic (klisp_State *K) { /* flip current white */ K->currentwhite = cast(uint16_t, otherwhite(K)); + K->sweepstrgc = 0; K->sweepgc = &K->rootgc; K->gcstate = GCSsweepstring; K->estimate = K->totalbytes - udsize; /* first estimate */ @@ -624,16 +628,19 @@ static int32_t singlestep (klisp_State *K) { } } case GCSsweepstring: { - /* No need to do anything in klisp, we just kept it - to avoid eliminating a state in the GC */ - K->gcstate = GCSsweep; /* end sweep-string phase */ - return 0; + uint32_t old = K->totalbytes; + sweepwholelist(K, &K->strt.hash[K->sweepstrgc++]); + if (K->sweepstrgc >= K->strt.size) /* nothing more to sweep? */ + K->gcstate = GCSsweep; /* end sweep-string phase */ + klisp_assert(old >= K->totalbytes); + K->estimate -= old - K->totalbytes; + return GCSWEEPCOST; } case GCSsweep: { uint32_t old = K->totalbytes; K->sweepgc = sweeplist(K, K->sweepgc, GCSWEEPMAX); if (*K->sweepgc == NULL) { /* nothing more to sweep? */ - /* checkSizes(K); */ /* klisp: keep this around */ + checkSizes(K); K->gcstate = GCSfinalize; /* end sweep phase */ } klisp_assert(old >= K->totalbytes); @@ -678,8 +685,8 @@ void klispC_step (klisp_State *K) { if (K->gcstate != GCSpause) { if (K->gcdept < GCSTEPSIZE) { - /* - lim/g->gcstepmul;*/ K->GCthreshold = K->totalbytes + GCSTEPSIZE; + /* - lim/g->gcstepmul;*/ } else { K->gcdept -= GCSTEPSIZE; K->GCthreshold = K->totalbytes; @@ -692,25 +699,26 @@ void klispC_step (klisp_State *K) { void klispC_fullgc (klisp_State *K) { if (K->gcstate <= GCSpropagate) { - /* reset sweep marks to sweep all elements (returning them to white) */ - K->sweepgc = &K->rootgc; - /* reset other collector lists */ - K->gray = NULL; - K->grayagain = NULL; - K->weak = NULL; - K->gcstate = GCSsweepstring; - } - klisp_assert(K->gcstate != GCSpause && K->gcstate != GCSpropagate); - /* finish any pending sweep phase */ - while (K->gcstate != GCSfinalize) { - klisp_assert(K->gcstate == GCSsweepstring || K->gcstate == GCSsweep); - singlestep(K); - } - markroot(K); - while (K->gcstate != GCSpause) { - singlestep(K); - } - setthreshold(K); + /* reset sweep marks to sweep all elements (returning them to white) */ + K->sweepstrgc = 0; + K->sweepgc = &K->rootgc; + /* reset other collector lists */ + K->gray = NULL; + K->grayagain = NULL; + K->weak = NULL; + K->gcstate = GCSsweepstring; + } + klisp_assert(K->gcstate != GCSpause && K->gcstate != GCSpropagate); + /* finish any pending sweep phase */ + while (K->gcstate != GCSfinalize) { + klisp_assert(K->gcstate == GCSsweepstring || K->gcstate == GCSsweep); + singlestep(K); + } + markroot(K); + while (K->gcstate != GCSpause) { + singlestep(K); + } + setthreshold(K); } /* TODO: make all code using mutation to call these, @@ -722,7 +730,7 @@ guarded stack! */ void klispC_barrierf (klisp_State *K, GCObject *o, GCObject *v) { klisp_assert(isblack(o) && iswhite(v) && !isdead(K, v) && !isdead(K, o)); klisp_assert(K->gcstate != GCSfinalize && K->gcstate != GCSpause); -/* klisp_assert(ttype(&o->gch) != LUA_TTABLE); */ + klisp_assert(o->gch.tt != K_TTABLE); /* must keep invariant? */ if (K->gcstate == GCSpropagate) reallymarkobject(K, v); /* restore invariant */ @@ -730,16 +738,14 @@ void klispC_barrierf (klisp_State *K, GCObject *o, GCObject *v) { makewhite(K, o); /* mark as white just to avoid other barriers */ } -#if 0 /* keep around */ -void klispC_barrierback (lua_State *L, Table *t) { +void klispC_barrierback (klisp_State *K, Table *t) { GCObject *o = obj2gco(t); - klisp_assert(isblack(o) && !isdead(g, o)); - klisp_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + klisp_assert(isblack(o) && !isdead(K, o)); + klisp_assert(K->gcstate != GCSfinalize && K->gcstate != GCSpause); black2gray(o); /* make table gray (again) */ - t->gclist = g->grayagain; - g->grayagain = o; + t->gclist = K->grayagain; + K->grayagain = o; } -#endif /* NOTE: kflags is added for klisp */ void klispC_link (klisp_State *K, GCObject *o, uint8_t tt, uint8_t kflags) { diff --git a/src/kgc.h b/src/kgc.h @@ -42,8 +42,8 @@ #define reset2bits(x,b1,b2) resetbits(x, (bit2mask(b1, b2))) #define test2bits(x,b1,b2) testbits(x, (bit2mask(b1, b2))) -/* NOTE: in klisp there is still no tables, userdata, threads, weak keys, - or finalization. Also the field is called gct instead of marked */ +/* NOTE: in klisp there is still no userdata, threads or finalization. + Also the field is called gct instead of marked */ /* ** Layout for bit use in `gct' field: @@ -110,6 +110,6 @@ void klispC_step (klisp_State *K); void klispC_fullgc (klisp_State *K); void klispC_link (klisp_State *K, GCObject *o, uint8_t tt, uint8_t flags); void klispC_barrierf (klisp_State *K, GCObject *o, GCObject *v); -/* void klispC_barrierback (klisp_State *K, Table *t); */ +void klispC_barrierback (klisp_State *K, Table *t); #endif diff --git a/src/kstate.c b/src/kstate.c @@ -92,6 +92,7 @@ klisp_State *klisp_newstate (klisp_Alloc f, void *ud) { /* GC */ K->currentwhite = bit2mask(WHITE0BIT, FIXEDBIT); K->gcstate = GCSpause; + K->sweepstrgc = 0; K->rootgc = NULL; K->sweepgc = &(K->rootgc); K->gray = NULL; @@ -501,6 +502,12 @@ void klisp_close (klisp_State *K) klispM_freemem(K, ks_sbuf(K), ks_ssize(K) * sizeof(TValue)); klispM_freemem(K, ks_tbuf(K), ks_tbsize(K)); + /* there should be no pending strings */ + klisp_assert(K->strt.nuse == 0); + + /* free string/symbol table */ + klispM_freearray(K, K->strt.hash, K->strt.size, GCObject *); + /* only remaining mem should be of the state struct */ klisp_assert(K->totalbytes == state_size()); diff --git a/src/kstate.h b/src/kstate.h @@ -78,6 +78,7 @@ struct klisp_State { uint16_t currentwhite; /* the one of the two whites that is in use in this collection cycle */ uint8_t gcstate; /* state of garbage collector */ + int32_t sweepstrgc; /* position of sweep in `strt' */ GCObject *rootgc; /* list of all collectable objects */ GCObject **sweepgc; /* position of sweep in `rootgc' */ GCObject *gray; /* list of gray objects */