#include #include #include #include #include "paper.h" #include "y.tab.h" #include "impl.h" static Gc* gcl; /* prevent gc */ void pppin(Node *n) { n->gc.flag |= GCPIN; } /* allow gc */ void ppunpin(Node *n) { n->gc.flag &= ~GCPIN; } /* allocators */ Node* an(int op, Node *l, Node *r) { Node *n; n = gmalloc(sizeof(Node)); memset(n, 0, sizeof(Node)); n->gc.type = GNODE; n->gc.flag = 0; n->gc.link = gcl; gcl = &n->gc; n->op = op; n->left = l; n->right = r; return n; } Node* ppdup(Node *n) { Node *nn; assert(n != nil); nn = an(n->op, n->left, n->right); nn->sym = n->sym; nn->builtin = n->builtin; nn->store = n->store; return nn; } Node* ppsetnil(Node *n) { n->op = OLIST; n->left = nil; n->right = nil; n->store.type = TLIST; n->store.l = nil; return n; } List* pplist(int t) { List *l; l = gmalloc(sizeof(List)); memset(l, 0, sizeof(List)); l->gc.link = gcl; l->gc.flag = 0; l->gc.type = GLIST; gcl = &l->gc; l->store.type = t; return l; } Node* ppsetstringlen(Node *n, char *s, int len) { assert(n != nil); assert(s != nil); assert(len >= 0); n->op = OCONST; n->store.string = strnodlen(s, len); n->store.type = TSTRING; return n; } Node* ppsetstring(Node *n, char *s) { assert(n != nil); assert(s != nil); n->op = OCONST; n->store.string = strnode(s); n->store.type = TSTRING; return n; } Node* ppstring(char *s) { Node *n; n = an(OCONST, ZN, ZN); return ppsetstring(n, s); } Node* ppsetconst(Node *n, vlong v) { n->op = OCONST; n->store.ival = v; n->store.type = TINT; return n; } Node* ppconst(vlong v) { Node *n; n = an(OCONST, ZN, ZN); n->store.ival = v; n->store.type = TINT; return n; } Node* ppsetpointer(Node *n, void *v, Metatable *meta) { n->op = OCONST; n->store.type = TPOINTER; n->store.pval = pppointernode(v, meta); return n; } Pointer* pppointernode(void *v, Metatable *meta) { Pointer *p; assert(meta != nil); p = gmalloc(sizeof(*p)); memset(p, 0, sizeof(*p)); p->v = v; p->meta = meta; p->gc.link = gcl; p->gc.flag = GCMETA; p->gc.type = GPOINTER; gcl = &p->gc; return p; } Node* pppointer(void *v, Metatable *meta) { Node *n; n = an(OCONST, ZN, ZN); n->store.pval = pppointernode(v, meta); n->store.type = TPOINTER; return n; } String* strnodlen(char *name, int len) { String *s; s = gmalloc(sizeof(String)+len+1); s->string = (char*)s+sizeof(String); s->len = len; if(name != 0) memmove(s->string, name, len); s->string[len] = '\0'; s->gc.flag = 0; s->gc.type = GSTRING; s->gc.link = gcl; gcl = &s->gc; return s; } String* strnode(char *name) { return strnodlen(name, strlen(name)); } String* runenode(Rune *name) { int len; Rune *p; String *s; p = name; for(len = 0; *p; p++) len++; len++; len *= sizeof(Rune); s = gmalloc(sizeof(String)+len); s->string = (char*)s+sizeof(String); s->len = len; memmove(s->string, name, len); s->gc.link = gcl; s->gc.flag = 0; s->gc.type = GSTRING; gcl = &s->gc; return s; } String* stradd(String *l, String *r) { int len; String *s; len = l->len+r->len; s = gmalloc(sizeof(String)+len+1); s->gc.link = gcl; s->gc.flag = 0; s->gc.type = GSTRING; gcl = &s->gc; s->len = len; s->string = (char*)s+sizeof(String); memmove(s->string, l->string, l->len); memmove(s->string+l->len, r->string, r->len); s->string[s->len] = 0; return s; } String* straddrune(String *l, Rune r) { int len; String *s; len = l->len+runelen(r); s = gmalloc(sizeof(String)+len+1); s->gc.link = gcl; s->gc.flag = 0; s->gc.type = GSTRING; gcl = &s->gc; s->len = len; s->string = (char*)s+sizeof(String); memmove(s->string, l->string, l->len); runetochar(s->string+l->len, &r); s->string[s->len] = 0; return s; } int scmp(String *sr, String *sl) { if(sr->len != sl->len) return 0; if(memcmp(sr->string, sl->string, sl->len)) return 0; return 1; } /* gc implementation below */ static void marklist(List*); static void marktree(Node *n) { if(n == nil) return; marktree(n->left); marktree(n->right); n->gc.mark = GCMARK; if(n->op != OCONST) return; switch(n->store.type) { case TSTRING: n->store.string->gc.mark = GCMARK; break; case TLIST: marklist(n->store.l); break; case TCODE: marktree(n->store.cc); break; case TPOINTER: n->store.string->gc.mark = GCMARK; } } static void marklist(List *l) { while(l) { l->gc.mark = GCMARK; switch(l->store.type) { case TSTRING: l->store.string->gc.mark = GCMARK; break; case TLIST: marklist(l->store.l); break; case TCODE: marktree(l->store.cc); break; case TPOINTER: l->store.pval->gc.mark = GCMARK; break; } l = l->next; } } static int dogc; void gc(int force) { int i; Lsym *f; Value *v; Gc *m, **p, *next; if(!force && (dogc < Mempergc)) return; dogc = 0; /* init */ for(m = gcl; m; m = m->link) m->mark = 0; /* mark pinned roots */ for(m = gcl; m; m = m->link){ if(m->mark == 0 && (m->flag & GCPIN)){ switch(m->type){ default: abort(); break; case GSTRING: ((String*)m)->gc.mark = GCMARK; break; case GNODE: marktree((Node*)m); break; case GLIST: marklist((List*)m); break; } } } /* mark variable roots */ for(i = 0; i < Hashsize; i++){ for(f = hash[i]; f; f = f->hash){ marktree(f->proc); if(f->lexval != Tid) continue; for(v = f->v; v; v = v->pop){ switch(v->store.type){ case TSTRING: v->store.string->gc.mark = GCMARK; break; case TLIST: marklist(v->store.l); break; case TCODE: marktree(v->store.cc); break; case TPOINTER: v->store.pval->gc.mark = GCMARK; } } } } /* sweep */ p = &gcl; for(m = gcl; m; m = next) { next = m->link; /* if not marked, collect */ if((m->mark & GCMARK) == 0){ *p = next; if(m->flag & GCMETA){ Pointer *p = (Pointer*)m; if(p->meta->gc != nil) p->meta->gc(p); } free(m); /* Sleazy reliance on my malloc */ } else p = &m->link; } } void* gmalloc(long l) { void *p; dogc += l; p = mallocz(l, 0); if(p == 0) sysfatal("out of memory"); return p; }