diff --git a/src/context.c b/src/context.c index 483f045..b6f451e 100644 --- a/src/context.c +++ b/src/context.c @@ -356,6 +356,20 @@ apfl_stack_clear(apfl_ctx ctx) ctx->stack->len = 0; } +static void +get_roots(void *own_opaque, gc_visitor visitor, void *visitor_opaque) +{ + apfl_ctx ctx = own_opaque; + + if (ctx->scope != NULL) { + visitor(visitor_opaque, GC_OBJECT_FROM(ctx->scope, GC_TYPE_SCOPE)); + } + + if (ctx->stack != NULL) { + visitor(visitor_opaque, GC_OBJECT_FROM(ctx->stack, GC_TYPE_STACK)); + } +} + apfl_ctx apfl_ctx_new(struct apfl_allocator base_allocator) { @@ -364,27 +378,16 @@ apfl_ctx_new(struct apfl_allocator base_allocator) return NULL; } - if (!apfl_gc_init(&ctx->gc, base_allocator)) { - FREE_OBJ(base_allocator, ctx); - return NULL; - } + apfl_gc_init(&ctx->gc, base_allocator, get_roots, ctx); if ((ctx->scope = apfl_scope_new(&ctx->gc)) == NULL) { goto error; } - if (!apfl_gc_root_add(&ctx->gc, GC_OBJECT_FROM(ctx->scope, GC_TYPE_SCOPE))) { - goto error; - } - if ((ctx->stack = stack_new(&ctx->gc)) == NULL) { goto error; } - if (!apfl_gc_root_add(&ctx->gc, GC_OBJECT_FROM(ctx->stack, GC_TYPE_STACK))) { - goto error; - } - ctx->error_handler = NULL; ctx->panic_callback = NULL; ctx->panic_callback_data = NULL; diff --git a/src/gc.c b/src/gc.c index a25f1de..e17222f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -5,7 +5,6 @@ #include "bytecode.h" #include "context.h" #include "gc.h" -#include "hashmap.h" #include "resizable.h" #include "scope.h" #include "value.h" @@ -68,8 +67,8 @@ apfl_gc_object_from_ptr(void *ptr, enum gc_type type) return object; } -bool -apfl_gc_init(struct gc *gc, struct apfl_allocator allocator) +void +apfl_gc_init(struct gc *gc, struct apfl_allocator allocator, gc_roots_getter roots_getter, void *roots_getter_opaque) { gc->base_allocator = allocator; gc->allocator = (struct apfl_allocator) { @@ -78,22 +77,14 @@ apfl_gc_init(struct gc *gc, struct apfl_allocator allocator) }; gc->block = NULL; + gc->roots_getter = roots_getter; + gc->roots_getter_opaque = roots_getter_opaque; gc->tmproots = (struct gc_tmproots) { .roots = NULL, .len = 0, .cap = 0, }; gc->tmproot_for_adding = NULL; - - // TODO: It's a bit wasteful that we use a hashmap here. We are only - // ever interested in the keys. - return apfl_hashmap_init( - &gc->roots, - allocator, - (struct apfl_hashmap_callbacks) {.opaque = NULL}, - sizeof(struct gc_object *), - sizeof(char) - ); } static struct gc_block * @@ -168,29 +159,6 @@ IMPL_NEW(struct instruction_list, apfl_gc_new_instructions, GC_T IMPL_NEW(struct scope, apfl_gc_new_scope, GC_TYPE_SCOPE, scope ) IMPL_NEW(struct stack, apfl_gc_new_stack, GC_TYPE_STACK, stack ) -bool -apfl_gc_root_add(struct gc *gc, struct gc_object *object) -{ - // Since setting the new root can trigger a garbage collection, we need to - // set the root as the tmproot_for_adding, so we'll treat it as a root and - // not free it. - assert(gc->tmproot_for_adding == NULL); - gc->tmproot_for_adding = object; - - char v = 0; - bool ok = apfl_hashmap_set(&gc->roots, &object, &v); - - gc->tmproot_for_adding = NULL; - - return ok; -} - -void -apfl_gc_root_remove(struct gc *gc, struct gc_object *object) -{ - apfl_hashmap_delete(&gc->roots, &object); -} - size_t apfl_gc_tmproots_begin(struct gc *gc) { @@ -237,12 +205,7 @@ color_object_grey(struct gc_object *object) static void visit_roots(struct gc *gc, gc_visitor visitor, void *opaque) { - HASHMAP_EACH(&gc->roots, cur) { - struct gc_object *obj; - assert(apfl_hashmap_cursor_get_key(cur, &obj)); - - visitor(opaque, obj); - } + gc->roots_getter(gc->roots_getter_opaque, visitor, opaque); for (size_t i = 0; i < gc->tmproots.len; i++) { visitor(opaque, gc->tmproots.roots[i]); @@ -542,5 +505,4 @@ apfl_gc_deinit(struct gc *gc) gc->block = NULL; FREE_LIST(gc->allocator, gc->tmproots.roots, gc->tmproots.cap); - apfl_hashmap_deinit(&gc->roots); } diff --git a/src/gc.h b/src/gc.h index fd59802..d34923c 100644 --- a/src/gc.h +++ b/src/gc.h @@ -36,18 +36,21 @@ struct gc_tmproots { size_t cap; }; +typedef void (*gc_visitor)(void *, struct gc_object *); +typedef void (*gc_roots_getter)(void *own_opaque, gc_visitor, void *visitor_opaque); + struct gc { struct apfl_allocator base_allocator; struct apfl_allocator allocator; struct gc_block *block; - struct apfl_hashmap roots; + gc_roots_getter roots_getter; + void *roots_getter_opaque; struct gc_tmproots tmproots; struct gc_object *tmproot_for_adding; }; -typedef void (*gc_visitor)(void *, struct gc_object *); #ifdef NDEBUG # define GC_OBJECT_FROM(ptr, type) ((struct gc_object *)(ptr)) @@ -57,14 +60,11 @@ typedef void (*gc_visitor)(void *, struct gc_object *); struct gc_object *apfl_gc_object_from_ptr(void *, enum gc_type); -bool apfl_gc_init(struct gc *, struct apfl_allocator); +void apfl_gc_init(struct gc *, struct apfl_allocator, gc_roots_getter, void *roots_getter_opaque); void apfl_gc_deinit(struct gc *); void apfl_gc_debug_dump_graph(struct gc *, FILE *); -bool apfl_gc_root_add(struct gc *gc, struct gc_object *object); -void apfl_gc_root_remove(struct gc *gc, struct gc_object *object); - size_t apfl_gc_tmproots_begin(struct gc *gc); void apfl_gc_tmproots_restore(struct gc *gc, size_t); bool apfl_gc_tmproot_add(struct gc *gc, struct gc_object *object);