From 396c5ad866e08ff440487b510e570043e5cc1d23 Mon Sep 17 00:00:00 2001 From: Laria Carolin Chabowski Date: Thu, 23 Nov 2023 21:29:05 +0100 Subject: [PATCH] gc: Tighter coupling to full context We'll soon need the whole apfl_ctx in the garbage collector. --- src/bytecode.h | 3 --- src/context.c | 12 +++++------ src/context.h | 1 - src/gc.c | 56 ++++++++++++++++++++++++++++++-------------------- src/gc.h | 26 +++++++++++++++-------- src/globals.c | 6 +++--- src/scope.h | 3 --- src/value.h | 6 ------ 8 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/bytecode.h b/src/bytecode.h index 8d290f3..b451b49 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -98,9 +98,6 @@ const char *apfl_matcher_instruction_to_string(enum matcher_instruction); struct instruction_list *apfl_instructions_new(struct gc *, size_t line, struct apfl_string *filename); void apfl_instructions_deinit(struct apfl_allocator, struct instruction_list *); -void apfl_gc_instructions_traverse(struct instruction_list *, gc_visitor, void *); -void apfl_gc_matcher_instructions_traverse(struct matcher_instruction_list *, gc_visitor, void *); - struct matcher_instruction_list *apfl_matcher_instructions_new(struct gc *); void apfl_matcher_instructions_deinit(struct apfl_allocator, struct matcher_instruction_list *); diff --git a/src/context.c b/src/context.c index 07641cd..61d54f2 100644 --- a/src/context.c +++ b/src/context.c @@ -741,11 +741,9 @@ gc_traverse_call_stack_entry(struct call_stack_entry cse, gc_visitor visitor, vo } } -static void -get_roots(void *own_opaque, gc_visitor visitor, void *visitor_opaque) +void +apfl_gc_roots_traverse(apfl_ctx ctx, gc_visitor visitor, void *visitor_opaque) { - apfl_ctx ctx = own_opaque; - if (ctx->globals != NULL) { visitor(visitor_opaque, GC_OBJECT_FROM(ctx->globals, GC_TYPE_SCOPE)); } @@ -948,7 +946,7 @@ apfl_ctx_new(struct apfl_config config) ctx->iterative_runners = iterative_runners_list_new(); ctx->registry = NULL; - apfl_gc_init(&ctx->gc, config.allocator, get_roots, ctx); + apfl_gc_init(ctx, config.allocator); if ((ctx->globals = apfl_scope_new(&ctx->gc)) == NULL) { goto error; @@ -1003,8 +1001,8 @@ apfl_ctx_destroy(apfl_ctx ctx) struct apfl_allocator base_allocator = ctx->gc.base_allocator; - apfl_gc_full(&ctx->gc); - apfl_gc_deinit(&ctx->gc); + apfl_gc_full(ctx); + apfl_gc_deinit(ctx); FREE_OBJ(base_allocator, ctx); } diff --git a/src/context.h b/src/context.h index 290fe59..0f6816a 100644 --- a/src/context.h +++ b/src/context.h @@ -226,7 +226,6 @@ void apfl_ctx_unregister_iterative_runner(apfl_ctx, apfl_iterative_runner); struct matcher *apfl_matcher_new(struct gc *, struct matcher_instruction_list *); void apfl_matcher_deinit(struct apfl_allocator, struct matcher *); -void apfl_gc_matcher_traverse(struct matcher *, gc_visitor, void *); void apfl_iterative_runner_visit_gc_objects(apfl_iterative_runner, gc_visitor, void *); diff --git a/src/gc.c b/src/gc.c index 46f88f5..621784d 100644 --- a/src/gc.c +++ b/src/gc.c @@ -51,7 +51,8 @@ struct gc_block { static void * gc_allocator(void *opaque, void *oldptr, size_t oldsize, size_t newsize) { - struct gc *gc = opaque; + apfl_ctx ctx = opaque; + struct gc *gc = &ctx->gc; #ifdef GC_DEBUG_COLLECT_EVERY_ALLOCATION if (newsize != 0 && !gc->is_collecting) { @@ -63,7 +64,7 @@ gc_allocator(void *opaque, void *oldptr, size_t oldsize, size_t newsize) if (newsize != 0 && out == NULL && !gc->is_collecting) { // We're out of memory! Try to get out of this situation by doing a full // GC run. - apfl_gc_full(gc); + apfl_gc_full(ctx); // Hopefully we now have memory again. Try the allocation again. out = ALLOCATOR_CALL(gc->base_allocator, oldptr, oldsize, newsize); @@ -87,17 +88,17 @@ apfl_gc_object_from_ptr(void *ptr, enum gc_type type) } void -apfl_gc_init(struct gc *gc, struct apfl_allocator allocator, gc_roots_getter roots_getter, void *roots_getter_opaque) +apfl_gc_init(apfl_ctx ctx, struct apfl_allocator allocator) { + struct gc *gc = &ctx->gc; + gc->base_allocator = allocator; gc->allocator = (struct apfl_allocator) { - .opaque = gc, + .opaque = ctx, .alloc = gc_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, @@ -239,9 +240,10 @@ color_object_grey(struct gc_object *object) } static void -visit_roots(struct gc *gc, gc_visitor visitor, void *opaque) +visit_roots(apfl_ctx ctx, gc_visitor visitor, void *opaque) { - gc->roots_getter(gc->roots_getter_opaque, visitor, opaque); + struct gc *gc = &ctx->gc; + apfl_gc_roots_traverse(ctx, visitor, opaque); for (size_t i = 0; i < gc->tmproots.len; i++) { visitor(opaque, gc->tmproots.roots[i]); @@ -260,9 +262,9 @@ mark_roots_visitor(void *opaque, struct gc_object *root) } static void -mark_roots(struct gc *gc) +mark_roots(apfl_ctx ctx) { - visit_roots(gc, mark_roots_visitor, NULL); + visit_roots(ctx, mark_roots_visitor, NULL); } static void @@ -348,8 +350,10 @@ trace_while_having_grey(struct gc *gc) } static void -deinit_object(struct gc *gc, struct gc_object *object) +deinit_object(apfl_ctx ctx, struct gc_object *object) { + struct gc *gc = &ctx->gc; + switch (object->type) { case GC_TYPE_LIST: apfl_list_deinit(gc->allocator, &object->list); @@ -391,8 +395,10 @@ deinit_object(struct gc *gc, struct gc_object *object) } static void -sweep(struct gc *gc) +sweep(apfl_ctx ctx) { + struct gc *gc = &ctx->gc; + #ifdef GC_DEBUG_STATS int reclaimed_objects = 0; int reclaimed_blocks = 0; @@ -411,7 +417,7 @@ sweep(struct gc *gc) break; case GC_STATUS_WHITE: LOG_NEW_AND_RECLAIM("reclaiming %p of type %s\n", (void *)object, type_to_string(object->type)); - deinit_object(gc, object); + deinit_object(ctx, object); #ifdef GC_DEBUG_WIPE_RECLAIMED_OBJECTS memset(object, 0, sizeof(struct gc_object)); @@ -453,22 +459,24 @@ sweep(struct gc *gc) } #ifdef GC_DEBUG_DUMP_GRAPH_ON_COLLECT -# define DUMP_ON_COLLECT() apfl_gc_debug_dump_graph(gc, apfl_io_file_writer(stderr)) +# define DUMP_ON_COLLECT() apfl_gc_debug_dump_graph(ctx, apfl_io_file_writer(stderr)) #else # define DUMP_ON_COLLECT() #endif void -apfl_gc_full(struct gc *gc) +apfl_gc_full(apfl_ctx ctx) { + struct gc *gc = &ctx->gc; + assert(!gc->is_collecting); gc->is_collecting = true; - mark_roots(gc); + mark_roots(ctx); DUMP_ON_COLLECT(); trace_while_having_grey(gc); DUMP_ON_COLLECT(); - sweep(gc); + sweep(ctx); DUMP_ON_COLLECT(); gc->is_collecting = false; @@ -576,15 +584,16 @@ dump_graph_visitor(void *opaque, struct gc_object *obj) } bool -apfl_gc_debug_dump_graph(struct gc *gc, struct apfl_io_writer w) +apfl_gc_debug_dump_graph(apfl_ctx ctx, struct apfl_io_writer w) { + struct gc *gc = &ctx->gc; FMT_TRY(apfl_io_write_string(w, "digraph G {\n")); struct dump_graph_roots_visitor_data roots_visitor_data = { .w = w, .success = true, }; - visit_roots(gc, dump_graph_roots_visitor, &roots_visitor_data); + visit_roots(ctx, dump_graph_roots_visitor, &roots_visitor_data); FMT_TRY(roots_visitor_data.success); for (struct gc_block *block = gc->block; block != NULL; block = block->next) { @@ -670,8 +679,10 @@ blockstat_line(struct apfl_io_writer w, size_t i, statuscounts counts) } bool -apfl_gc_debug_blockstats(struct gc *gc, struct apfl_io_writer w) +apfl_gc_debug_blockstats(apfl_ctx ctx, struct apfl_io_writer w) { + struct gc *gc = &ctx->gc; + statuscounts total = {0, 0, 0, 0}; size_t i = 0; @@ -701,13 +712,14 @@ apfl_gc_debug_blockstats(struct gc *gc, struct apfl_io_writer w) } void -apfl_gc_deinit(struct gc *gc) +apfl_gc_deinit(apfl_ctx ctx) { + struct gc *gc = &ctx->gc; for (struct gc_block *block = gc->block; block != NULL; ) { for (size_t i = 0; i < GC_OBJECTS_PER_BLOCK; i++) { struct gc_object *object = &block->objects[i]; if (object->status != GC_STATUS_FREE) { - deinit_object(gc, object); + deinit_object(ctx, object); } } diff --git a/src/gc.h b/src/gc.h index ec8b350..b139d65 100644 --- a/src/gc.h +++ b/src/gc.h @@ -44,7 +44,6 @@ struct gc_tmproots { }; 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; @@ -52,8 +51,6 @@ struct gc { struct gc_block *block; - gc_roots_getter roots_getter; - void *roots_getter_opaque; struct gc_tmproots tmproots; struct gc_object *tmproot_for_adding; @@ -69,17 +66,17 @@ struct gc { struct gc_object *apfl_gc_object_from_ptr(void *, enum gc_type); -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_init(apfl_ctx, struct apfl_allocator); +void apfl_gc_deinit(apfl_ctx); -bool apfl_gc_debug_dump_graph(struct gc *, struct apfl_io_writer); -bool apfl_gc_debug_blockstats(struct gc *, struct apfl_io_writer); +bool apfl_gc_debug_dump_graph(apfl_ctx ctx, struct apfl_io_writer); +bool apfl_gc_debug_blockstats(apfl_ctx ctx, struct apfl_io_writer); 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); -void apfl_gc_full(struct gc *gc); +void apfl_gc_full(apfl_ctx); struct list_header* apfl_gc_new_list(struct gc *); struct dict_header* apfl_gc_new_dict(struct gc *); @@ -95,6 +92,19 @@ struct native_object* apfl_gc_new_native_object(struct gc *); struct value_pair* apfl_gc_new_pair(struct gc *); struct apfl_string** apfl_gc_new_symbol(struct gc *); +void apfl_gc_roots_traverse(apfl_ctx, gc_visitor, void *); +void apfl_gc_list_traverse(struct list_header *, gc_visitor, void *); +void apfl_gc_dict_traverse(struct dict_header *, gc_visitor, void *); +void apfl_gc_var_traverse(struct apfl_value *, gc_visitor, void *); +void apfl_gc_instructions_traverse(struct instruction_list *, gc_visitor, void *); +void apfl_gc_scope_traverse(struct scope *, gc_visitor, void *); +void apfl_gc_func_traverse(struct function*, gc_visitor, void *); +void apfl_gc_cfunc_traverse(struct cfunction*, gc_visitor, void *); +void apfl_gc_matcher_instructions_traverse(struct matcher_instruction_list *, gc_visitor, void *); +void apfl_gc_matcher_traverse(struct matcher *, gc_visitor, void *); +void apfl_gc_pair_traverse(struct value_pair *, gc_visitor, void *); +void apfl_gc_symbol_traverse(struct apfl_string **, gc_visitor, void *); + #ifdef __cplusplus } #endif diff --git a/src/globals.c b/src/globals.c index d0c5843..86d27ee 100644 --- a/src/globals.c +++ b/src/globals.c @@ -402,12 +402,12 @@ impl_gc(apfl_ctx ctx) if (apfl_string_eq(sv, "dump")) { struct apfl_io_writer w = apfl_get_output_writer(ctx); - TRY_FORMAT(ctx, apfl_gc_debug_dump_graph(&ctx->gc, w)); + TRY_FORMAT(ctx, apfl_gc_debug_dump_graph(ctx, w)); } else if (apfl_string_eq(sv, "collect")) { - apfl_gc_full(&ctx->gc); + apfl_gc_full(ctx); } else if (apfl_string_eq(sv, "blockstats")) { struct apfl_io_writer w = apfl_get_output_writer(ctx); - TRY_FORMAT(ctx, apfl_gc_debug_blockstats(&ctx->gc, w)); + TRY_FORMAT(ctx, apfl_gc_debug_blockstats(ctx, w)); } else { apfl_raise_const_error(ctx, "Unknown gc command"); } diff --git a/src/scope.h b/src/scope.h index 9b8eea8..e26d3d6 100644 --- a/src/scope.h +++ b/src/scope.h @@ -24,9 +24,6 @@ bool apfl_scope_update_existing(struct scope *, struct apfl_string *, struct apf bool apfl_scope_merge_into(struct scope *self, struct scope *other); -void apfl_gc_var_traverse(struct apfl_value *, gc_visitor, void *); -void apfl_gc_scope_traverse(struct scope *, gc_visitor, void *); - #ifdef __cplusplus } #endif diff --git a/src/value.h b/src/value.h index 03b27cb..f349005 100644 --- a/src/value.h +++ b/src/value.h @@ -186,12 +186,6 @@ void apfl_native_object_deinit(struct apfl_allocator, struct native_object *); struct gc_object *apfl_value_get_gc_object(struct apfl_value); void apfl_value_visit_gc_object(struct apfl_value value, gc_visitor cb, void *opaque); bool apfl_value_add_as_tmproot(struct gc *, struct apfl_value); -void apfl_gc_list_traverse(struct list_header *, gc_visitor, void *); -void apfl_gc_dict_traverse(struct dict_header *, gc_visitor, void *); -void apfl_gc_pair_traverse(struct value_pair *, gc_visitor, void *); -void apfl_gc_func_traverse(struct function*, gc_visitor, void *); -void apfl_gc_cfunc_traverse(struct cfunction*, gc_visitor, void *); -void apfl_gc_symbol_traverse(struct apfl_string **, gc_visitor, void *); #ifdef __cplusplus }