1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
#include <lcq/pit/runtime/gc.h>
static i64 gc_copy(pit_runtime *rt, pit_value_heavy *h) {
if (h->hsort == PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER) {
return h->in.forwarding_pointer;
} else {
i64 ret = rt->backbuffer->next;
pit_value_heavy *g = pit_arena_alloc(rt->backbuffer);
*g = *h;
h->hsort = PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER;
h->in.forwarding_pointer = ret;
return ret;
}
}
static pit_value gc_copy_value(pit_runtime *rt, pit_value v) {
if (pit_value_sort(v) == PIT_VALUE_SORT_REF) {
pit_ref r = pit_value_as_ref(rt, v);
pit_value_heavy *h = pit_value_ref_deref(rt, r);
i64 new = gc_copy(rt, h);
pit_annotated_ref *ann = pit_annotation_get(rt, r);
if (ann != NULL) {
pit_annotated_ref newann = *ann;
newann.ref = new;
if (pit_vec_push(pit_annotated_ref)(rt->backtrace, newann) < 0)
pit_error(rt, "annotation overflow");
}
return pit_value_ref_new(rt, new);
} else {
return v;
}
}
void pit_gc(pit_runtime *rt) {
rt->frozen_values = 0;
rt->frozen_symtab = 0;
pit_arena *fromspace = rt->heap;
pit_arena *tospace = rt->backbuffer;
pit_vec(pit_annotated_ref) *fromspace_ann = rt->annotations;
pit_vec(pit_annotated_ref) *tospace_ann = rt->backtrace;
pit_arena_reset(tospace);
pit_vec_reset(pit_annotated_ref)(tospace_ann);
/* populate tospace with immediately reachable values */
for (i64 i = 0; i < rt->symtab->next; ++i) {
pit_symtab_entry *ent = pit_vec_get(pit_symtab_entry)(rt->symtab, i);
if (ent == NULL) continue; /* TODO warn on failure here? */
ent->name = gc_copy_value(rt, ent->name);
ent->value = gc_copy_value(rt, ent->value);
ent->function = gc_copy_value(rt, ent->function);
}
for (i64 i = 0; i < rt->saved_bindings->next; ++i) {
pit_value *v = pit_vec_get(pit_value)(rt->saved_bindings, i);
if (v != NULL) *v = gc_copy_value(rt, *v); /* TODO warn on failure here? */
}
for (i64 scan = 0; scan < tospace->next; ++scan) {
pit_value_heavy *h = pit_arena_get(tospace, scan);
switch (h->hsort) {
case PIT_VALUE_HEAVY_SORT_CELL:
h->in.cell = gc_copy_value(rt, h->in.cell);
break;
case PIT_VALUE_HEAVY_SORT_CONS:
h->in.cons.car = gc_copy_value(rt, h->in.cons.car);
h->in.cons.cdr = gc_copy_value(rt, h->in.cons.cdr);
break;
case PIT_VALUE_HEAVY_SORT_ARRAY: {
i64 byte_len = 0; pit_mul(&byte_len, sizeof(pit_value), h->in.array.len);
pit_value *data = pit_arena_alloc_back(tospace, byte_len);
for (i64 i = 0; i < h->in.array.len; ++i) {
data[i] = gc_copy_value(rt, h->in.array.data[i]);
}
h->in.array.data = data;
break;
}
case PIT_VALUE_HEAVY_SORT_BYTES: {
u8 *data = pit_arena_alloc_back(tospace, h->in.bytes.len);
for (i64 i = 0; i < h->in.bytes.len; ++i) {
data[i] = h->in.bytes.data[i];
}
h->in.bytes.data = data;
break;
}
case PIT_VALUE_HEAVY_SORT_FUNC:
h->in.func.env = gc_copy_value(rt, h->in.func.env);
h->in.func.args = gc_copy_value(rt, h->in.func.args);
h->in.func.arg_rest_nm = gc_copy_value(rt, h->in.func.arg_rest_nm);
h->in.func.body = gc_copy_value(rt, h->in.func.body);
break;
case PIT_VALUE_HEAVY_SORT_NATIVEFUNC: break;
case PIT_VALUE_HEAVY_SORT_NATIVEDATA:
h->in.nativedata.tag = gc_copy_value(rt, h->in.nativedata.tag);
break;
case PIT_VALUE_HEAVY_SORT_FORWARDING_POINTER:
pit_error(rt, "garbage collection broken! encountered forwarding pointer in to-space");
break;
}
}
rt->heap = tospace;
rt->backbuffer = fromspace;
rt->annotations = tospace_ann;
rt->backtrace = fromspace_ann;
pit_vec_reset(pit_annotated_ref)(rt->backtrace);
}
|