1 #include "system/stacktrace.h"
10 #include "system/lt.h"
12 #define GC_INITIAL_CAPACITY 256
23 static intptr_t value_of_expr(struct Expr expr)
25 if (expr.type == EXPR_CONS) {
26 return (intptr_t) expr.cons;
27 } else if (expr.type == EXPR_ATOM) {
28 return (intptr_t) expr.atom;
34 static int compare_exprs(const void *a, const void *b)
39 const intptr_t ptr_a = value_of_expr(*(const struct Expr *)a);
40 const intptr_t ptr_b = value_of_expr(*(const struct Expr *)b);
41 const intptr_t d = ptr_b - ptr_a;
56 Gc *gc = PUSH_LT(lt, calloc(1, sizeof(Gc)), free);
62 gc->exprs = PUSH_LT(lt, calloc(GC_INITIAL_CAPACITY, sizeof(struct Expr)), free);
63 if (gc->exprs == NULL) {
67 gc->visited = PUSH_LT(lt, calloc(GC_INITIAL_CAPACITY, sizeof(int)), free);
68 if (gc->visited == NULL) {
73 gc->capacity = GC_INITIAL_CAPACITY;
78 void destroy_gc(Gc *gc)
82 for (size_t i = 0; i < gc->size; ++i) {
83 destroy_expr(gc->exprs[i]);
89 int gc_add_expr(Gc *gc, struct Expr expr)
93 if (gc->size >= gc->capacity) {
94 const size_t new_capacity = gc->capacity * 2;
95 struct Expr *const new_exprs = realloc(
97 sizeof(struct Expr) * new_capacity);
99 if (new_exprs == NULL) {
103 int *const new_visited = realloc(
105 sizeof(int) * new_capacity);
107 if (new_visited == NULL) {
111 gc->capacity = new_capacity;
112 gc->exprs = REPLACE_LT(gc->lt, gc->exprs, new_exprs);
113 gc->visited = REPLACE_LT(gc->lt, gc->visited, new_visited);
116 gc->exprs[gc->size++] = expr;
121 static long int gc_find_expr(Gc *gc, struct Expr expr)
126 struct Expr *result =
127 (struct Expr *) bsearch(&expr, gc->exprs, gc->size,
128 sizeof(struct Expr), compare_exprs);
130 if (result == NULL) {
134 return (long int) (result - gc->exprs);
137 static void gc_traverse_expr(Gc *gc, struct Expr root)
140 trace_assert(root.type != EXPR_VOID);
141 const long int root_index = gc_find_expr(gc, root);
142 if (root_index < 0) {
143 fprintf(stderr, "GC tried to collect something that was not registered\n");
144 print_expr_as_sexpr(stderr, root);
145 fprintf(stderr, "\n");
146 trace_assert(root_index >= 0);
149 if (gc->visited[root_index]) {
153 gc->visited[root_index] = 1;
156 gc_traverse_expr(gc, root.cons->car);
157 gc_traverse_expr(gc, root.cons->cdr);
158 } else if (root.type == EXPR_ATOM
159 && root.atom->type == ATOM_LAMBDA) {
160 gc_traverse_expr(gc, root.atom->lambda.args_list);
161 gc_traverse_expr(gc, root.atom->lambda.body);
162 gc_traverse_expr(gc, root.atom->lambda.envir);
166 void gc_collect(Gc *gc, struct Expr root)
171 /* Sort gc->exprs O(nlogn) */
172 qsort(gc->exprs, gc->size, sizeof(struct Expr), compare_exprs);
174 /* Defragment O(n) */
175 while(gc->size > 0 && gc->exprs[gc->size - 1].type == EXPR_VOID) {
179 /* Initialize visited array O(n) */
180 memset(gc->visited, 0, sizeof(int) * gc->size);
182 /* Traverse root O(nlogn) */
183 gc_traverse_expr(gc, root);
185 /* Dealloc unvisted O(n) */
186 for (size_t i = 0; i < gc->size; ++i) {
187 if (!gc->visited[i]) {
188 destroy_expr(gc->exprs[i]);
189 gc->exprs[i] = void_expr();
194 void gc_inspect(const Gc *gc)
196 for (size_t i = 0; i < gc->size; ++i) {
197 if (gc->exprs[i].type == EXPR_VOID) {