Implement garbage collection in runtime
This commit is contained in:
parent
30579afc6d
commit
d86ff453bb
59
09/runtime.c
59
09/runtime.c
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
struct node_base* alloc_node() {
|
struct node_base* alloc_node() {
|
||||||
struct node_base* new_node = malloc(sizeof(struct node_app));
|
struct node_base* new_node = malloc(sizeof(struct node_app));
|
||||||
|
new_node->gc_next = NULL;
|
||||||
|
new_node->gc_reachable = 0;
|
||||||
assert(new_node != NULL);
|
assert(new_node != NULL);
|
||||||
return new_node;
|
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) {
|
void stack_init(struct stack* s) {
|
||||||
s->size = 4;
|
s->size = 4;
|
||||||
s->count = 0;
|
s->count = 0;
|
||||||
|
@ -82,12 +105,14 @@ void stack_popn(struct stack* s, size_t n) {
|
||||||
|
|
||||||
void gmachine_init(struct gmachine* g) {
|
void gmachine_init(struct gmachine* g) {
|
||||||
stack_init(&g->stack);
|
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) {
|
void gmachine_free(struct gmachine* g) {
|
||||||
stack_free(&g->stack);
|
stack_free(&g->stack);
|
||||||
struct node_base* to_free = g->nodes;
|
struct node_base* to_free = g->gc_nodes;
|
||||||
struct node_base* next;
|
struct node_base* next;
|
||||||
|
|
||||||
while(to_free) {
|
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) {
|
void gmachine_pack(struct gmachine* g, size_t n, int8_t t) {
|
||||||
assert(g->stack.count >= n);
|
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);
|
assert(data != NULL);
|
||||||
memcpy(data, &g->stack.data[g->stack.count - n], n * sizeof(*data));
|
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();
|
struct node_data* new_node = (struct node_data*) alloc_node();
|
||||||
new_node->array = data;
|
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) {
|
struct node_base* gmachine_track(struct gmachine* g, struct node_base* b) {
|
||||||
b->gc_next = g->nodes;
|
g->gc_node_count++;
|
||||||
g->nodes = b;
|
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;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gmachine_gc(struct gmachine* g) {
|
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) {
|
void unwind(struct gmachine* g) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ enum node_tag {
|
||||||
|
|
||||||
struct node_base {
|
struct node_base {
|
||||||
enum node_tag tag;
|
enum node_tag tag;
|
||||||
int8_t gc_color;
|
int8_t gc_reachable;
|
||||||
struct node_base* gc_next;
|
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_global* alloc_global(void (*f)(struct gmachine*), int32_t a);
|
||||||
struct node_ind* alloc_ind(struct node_base* n);
|
struct node_ind* alloc_ind(struct node_base* n);
|
||||||
void free_node_direct(struct node_base*);
|
void free_node_direct(struct node_base*);
|
||||||
|
void gc_visit_node(struct node_base*);
|
||||||
|
|
||||||
struct stack {
|
struct stack {
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -67,7 +68,9 @@ void stack_popn(struct stack* s, size_t n);
|
||||||
|
|
||||||
struct gmachine {
|
struct gmachine {
|
||||||
struct stack stack;
|
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);
|
void gmachine_init(struct gmachine* g);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user