diff --git a/09/runtime.c b/09/runtime.c index c5f855f..52a74c8 100644 --- a/09/runtime.c +++ b/09/runtime.c @@ -6,6 +6,8 @@ struct node_base* alloc_node() { struct node_base* new_node = malloc(sizeof(struct node_app)); + new_node->gc_next = NULL; + new_node->gc_reachable = 0; assert(new_node != NULL); return new_node; } @@ -46,6 +48,27 @@ void free_node_direct(struct node_base* n) { } } +void gc_visit_node(struct node_base* n) { + if(n->gc_reachable) return; + n->gc_reachable = 1; + + if(n->tag == NODE_APP) { + struct node_app* app = (struct node_app*) n; + gc_visit_node(app->left); + gc_visit_node(app->right); + } if(n->tag == NODE_IND) { + struct node_ind* ind = (struct node_ind*) n; + gc_visit_node(ind->next); + } if(n->tag == NODE_DATA) { + struct node_data* data = (struct node_data*) n; + struct node_base** to_visit = data->array; + while(*to_visit) { + gc_visit_node(*to_visit); + to_visit++; + } + } +} + void stack_init(struct stack* s) { s->size = 4; s->count = 0; @@ -82,12 +105,14 @@ void stack_popn(struct stack* s, size_t n) { void gmachine_init(struct gmachine* g) { stack_init(&g->stack); - g->nodes = NULL; + g->gc_nodes = NULL; + g->gc_node_count = 0; + g->gc_node_threshold = 128; } void gmachine_free(struct gmachine* g) { stack_free(&g->stack); - struct node_base* to_free = g->nodes; + struct node_base* to_free = g->gc_nodes; struct node_base* next; while(to_free) { @@ -122,9 +147,10 @@ void gmachine_alloc(struct gmachine* g, size_t o) { void gmachine_pack(struct gmachine* g, size_t n, int8_t t) { assert(g->stack.count >= n); - struct node_base** data = malloc(sizeof(*data) * n); + struct node_base** data = malloc(sizeof(*data) * (n + 1)); assert(data != NULL); memcpy(data, &g->stack.data[g->stack.count - n], n * sizeof(*data)); + data[n] = NULL; struct node_data* new_node = (struct node_data*) alloc_node(); new_node->array = data; @@ -143,13 +169,36 @@ void gmachine_split(struct gmachine* g, size_t n) { } struct node_base* gmachine_track(struct gmachine* g, struct node_base* b) { - b->gc_next = g->nodes; - g->nodes = b; + g->gc_node_count++; + if(g->gc_node_count >= g->gc_node_threshold) { + gc_visit_node(b); + gmachine_gc(g); + g->gc_node_threshold *= 2; + } + + b->gc_next = g->gc_nodes; + g->gc_nodes = b; return b; } void gmachine_gc(struct gmachine* g) { + for(size_t i = 0; i < g->stack.count; i++) { + gc_visit_node(g->stack.data[i]); + } + struct node_base** head_ptr = &g->gc_nodes; + while(*head_ptr) { + if((*head_ptr)->gc_reachable) { + (*head_ptr)->gc_reachable = 0; + head_ptr = &(*head_ptr)->gc_next; + } else { + struct node_base* to_free = *head_ptr; + *head_ptr = to_free->gc_next; + free_node_direct(to_free); + free(to_free); + g->gc_node_count--; + } + } } void unwind(struct gmachine* g) { diff --git a/09/runtime.h b/09/runtime.h index c1f9dee..030a27c 100644 --- a/09/runtime.h +++ b/09/runtime.h @@ -13,7 +13,7 @@ enum node_tag { struct node_base { enum node_tag tag; - int8_t gc_color; + int8_t gc_reachable; struct node_base* gc_next; }; @@ -51,6 +51,7 @@ struct node_num* alloc_num(int32_t n); struct node_global* alloc_global(void (*f)(struct gmachine*), int32_t a); struct node_ind* alloc_ind(struct node_base* n); void free_node_direct(struct node_base*); +void gc_visit_node(struct node_base*); struct stack { size_t size; @@ -67,7 +68,9 @@ void stack_popn(struct stack* s, size_t n); struct gmachine { struct stack stack; - struct node_base* nodes; + struct node_base* gc_nodes; + int64_t gc_node_count; + int64_t gc_node_threshold; }; void gmachine_init(struct gmachine* g);