gc: Use a callback to get the (non-tmp) roots
This let's us get rid of that awkward hashmap in the GC that was used as a set, makes determining the roots more flexible and now gc_init can't even fail any more, as there are no allocations happening here any more :)
This commit is contained in:
parent
8d947244c9
commit
c974b675e1
3 changed files with 26 additions and 61 deletions
|
|
@ -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;
|
||||
|
|
|
|||
48
src/gc.c
48
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);
|
||||
}
|
||||
|
|
|
|||
12
src/gc.h
12
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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue