diff --git a/libsuicmez/suicmez_gc.c b/libsuicmez/suicmez_gc.c index 84ea666..f51aa70 100644 --- a/libsuicmez/suicmez_gc.c +++ b/libsuicmez/suicmez_gc.c @@ -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);