gc: Tighter coupling to full context
We'll soon need the whole apfl_ctx in the garbage collector.
This commit is contained in:
parent
0361000e7c
commit
396c5ad866
8 changed files with 60 additions and 53 deletions
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
56
src/gc.c
56
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
26
src/gc.h
26
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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue