Compare commits

...

2 commits

View file

@ -60,7 +60,9 @@ void gc_remove_root(void **slot) {
void gc_write_barrier(void *owner, void *value) {
if (is_old(owner) && is_young(value)) {
size_t idx = card_index(owner);
gc.card_table[idx] = 1;
if (idx < gc.card_count){
gc.card_table[idx] = 1;
}
}
}
@ -93,6 +95,7 @@ static Obj *forward(Obj *obj) {
if (obj->header.age >= PROMOTION_AGE) {
Obj *p = promote(obj);
obj->header.forwarding = p;
scan_object_fields(p);
return p;
}
@ -166,9 +169,13 @@ static void gc_minor_collect(void) {
void *gc_alloc(const TypeInfo *type, size_t payload_size) {
size_t size = sizeof(ObjHeader) + payload_size;
size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
if (gc.from_ptr + size > gc.from_space + gc.young_size) {
gc_minor_collect();
if ((gc.old_ptr - gc.old) > (gc.old_size * 7 / 10)) {
gc_collect_old();
}
}
Obj *obj = (Obj*)gc.from_ptr;
@ -210,6 +217,107 @@ void gc_init(void) {
gc.root_count = 0;
}
static void mark_object_fields(Obj *obj) {
const TypeInfo *t = obj->header.type;
for (uint16_t i = 0; i < t->field_count; i++) {
if (t->pointer_bitmap[i]) {
Obj *child = (Obj*)obj->fields[i];
if (child && is_old(child)) {
mark_obj(child);
}
}
}
}
static void mark_obj(Obj *obj) {
if (!obj) return;
if (!(obj->header.flags & MARKED)) {
obj->header.flags |= MARKED;
mark_object_fields(obj);
}
}
static void mark_roots(void) {
for (size_t i = 0; i < gc.root_count; i++) {
Obj *obj = (Obj*)*gc.roots[i];
if (obj && is_old(obj)) {
mark_obj(obj);
}
}
}
static void compute_forwarding(void) {
uint8_t *dest = gc.old;
uint8_t *scan = gc.old;
while (scan < gc.old_ptr) {
Obj *obj = (Obj*)scan;
if (obj->header.flags & MARKED) {
obj->header.forwarding = (Obj*)dest;
dest += obj->header.size;
}
scan += obj->header.size;
}
}
static void update_old_pointers(void) {
uint8_t *scan = gc.old;
while (scan < gc.old_ptr) {
Obj *obj = (Obj*)scan;
if (obj->header.flags & MARKED) {
const TypeInfo *t = obj->header.type;
for (uint16_t i = 0; i < t->field_count; i++) {
if (t->pointer_bitmap[i]) {
Obj *child = (Obj*)obj->fields[i];
if (child && is_old(child)) {
obj->fields[i] = child->header.forwarding;
}
}
}
}
scan += obj->header.size;
}
}
static void update_root_pointers(void) {
for (size_t i = 0; i < gc.root_count; i++) {
Obj *obj = (Obj*)*gc.roots[i];
if (obj && is_old(obj)) {
*gc.roots[i] = obj->header.forwarding;
}
}
}
static void compact_old(void) {
uint8_t *scan = gc.old;
uint8_t *dest = gc.old;
while (scan < gc.old_ptr) {
Obj *obj = (Obj*)scan;
if (obj->header.flags & MARKED) {
Obj *new_loc = obj->header.forwarding;
memmove(new_loc, obj, obj->header.size);
Obj *moved = new_loc;
moved->header.flags &= ~MARKED;
moved->header.forwarding = NULL;
dest += moved->header.size;
}
scan += obj->header.size;
}
gc.old_ptr = dest;
}
void gc_collect_old(void) {
mark_roots();
compute_forwarding();
update_root_pointers();
update_old_pointers();
compact_old();
}
void gc_shutdown(void) {
free(gc.from_space);