Implement pin-based gc

This will allow for cleanup to occur mid-calculation when used throughout
This commit is contained in:
2022-11-29 21:21:16 -05:00
parent 13704fae2c
commit afaa53bb7f
3 changed files with 18 additions and 25 deletions

View File

@@ -38,8 +38,8 @@ void ucl_add_special(struct ucl *state, const char *name, ucl_lisp fun);
if (len != 2) { \ if (len != 2) { \
return NULL; \ return NULL; \
} \ } \
struct ucl_object *arg0 = ucl_list_nth(args, 0); \ struct ucl_object *arg0 = ucl_list_nth(args, 0); \
struct ucl_object *arg1 = ucl_list_nth(args, 1); \ struct ucl_object *arg1 = ucl_list_nth(args, 1); \
return func_name##_impl(ucl, scope, arg0, arg1); \ return func_name##_impl(ucl, scope, arg0, arg1); \
} \ } \
static struct ucl_object *func_name##_impl(UNUSED struct ucl *ucl_name, UNUSED struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name) static struct ucl_object *func_name##_impl(UNUSED struct ucl *ucl_name, UNUSED struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)

View File

@@ -83,7 +83,7 @@ void ucl_object_pin(struct ucl_object *obj) {
obj->flags |= UCL_OBJ_FLAG_PINNED; obj->flags |= UCL_OBJ_FLAG_PINNED;
} }
void ucl_object_unpinned(struct ucl_object *obj) { void ucl_object_unpin(struct ucl_object *obj) {
obj->flags &= ~UCL_OBJ_FLAG_PINNED; obj->flags &= ~UCL_OBJ_FLAG_PINNED;
} }
@@ -131,52 +131,43 @@ void ucl_object_delete(struct ucl* state, struct ucl_object *obj) {
ucl_object_delete_internal(state->obj_arena, obj); ucl_object_delete_internal(state->obj_arena, obj);
} }
static void ucl_object_mark(struct ucl_object *obj) { static void ucl_object_mark_recursive(struct ucl_object *obj) {
if (obj == NULL || obj->flags & UCL_OBJ_FLAG_REACHABLE) { if (obj == NULL || obj->flags & UCL_OBJ_FLAG_REACHABLE) {
return; return;
} }
obj->flags |= 1; obj->flags |= UCL_OBJ_FLAG_REACHABLE;
if (obj->type == UCL_TYPE_CELL) { if (obj->type == UCL_TYPE_CELL) {
ucl_object_mark(obj->cell.car); ucl_object_mark_recursive(obj->cell.car);
ucl_object_mark(obj->cell.cdr); ucl_object_mark_recursive(obj->cell.cdr);
} }
} }
static void ucl_scope_mark(struct ucl_arena * arena, void *obj) { static void ucl_gc_mark_pinned(struct ucl_arena * arena, void *obj) {
(void) arena; (void) arena;
struct ucl_scope *scope = (struct ucl_scope *) obj; struct ucl_object *object = (struct ucl_object *) obj;
ucl_object_mark(scope->list); if (object->flags & UCL_OBJ_FLAG_PINNED) {
ucl_object_mark_recursive(object);
}
} }
static void ucl_gc_unmark(struct ucl_arena * arena, void *obj) { static void ucl_gc_unmark_all(struct ucl_arena * arena, void *obj) {
(void) arena; (void) arena;
struct ucl_object *object = (struct ucl_object *) obj; struct ucl_object *object = (struct ucl_object *) obj;
object->flags &= ~UCL_OBJ_FLAG_REACHABLE; object->flags &= ~UCL_OBJ_FLAG_REACHABLE;
} }
static void ucl_gc_sweep(struct ucl_arena * arena, void *obj) { static void ucl_gc_sweep(struct ucl_arena * arena, void *obj) {
(void) arena;
struct ucl_object *object = (struct ucl_object *) obj; struct ucl_object *object = (struct ucl_object *) obj;
if (!(object->flags &UCL_OBJ_FLAG_REACHABLE)) { if (!(object->flags &UCL_OBJ_FLAG_REACHABLE)) {
ucl_object_delete_internal(arena, object); ucl_object_delete_internal(arena, object);
} }
} }
// TODO: Implement full cleanup
/* static void ucl_gc_deleteall(struct ucl_arena * arena, void *obj) { */
/* (void) arena; */
/* struct ucl_object *object = (struct ucl_object *) obj; */
/* ucl_object_delete_internal(arena, object); */
/* } */
void ucl_gc(struct ucl* ucl) { void ucl_gc(struct ucl* ucl) {
// TODO: Implement scope cleanup ucl_arena_map(ucl->obj_arena, ucl_gc_unmark_all);
ucl_arena_map(ucl->obj_arena, ucl_gc_mark_pinned);
ucl_arena_map(ucl->obj_arena, ucl_gc_unmark);
ucl_arena_map(ucl->scope_arena, ucl_scope_mark);
ucl_arena_map(ucl->obj_arena, ucl_gc_sweep); ucl_arena_map(ucl->obj_arena, ucl_gc_sweep);
} }

View File

@@ -60,12 +60,14 @@ struct ucl_scope *ucl_scope_create(struct ucl *state) {
struct ucl_scope *scope = ucl_arena_get(state->scope_arena); struct ucl_scope *scope = ucl_arena_get(state->scope_arena);
scope->list = ucl_nil_create(state); scope->list = ucl_nil_create(state);
scope->parent = NULL; scope->parent = NULL;
ucl_object_pin(scope->list);
return scope; return scope;
} }
struct ucl_scope *ucl_scope_create_child(struct ucl *state, struct ucl_scope *parent) { struct ucl_scope *ucl_scope_create_child(struct ucl *state, struct ucl_scope *parent) {
struct ucl_scope *scope = ucl_scope_create(state); struct ucl_scope *scope = ucl_scope_create(state);
scope->parent = parent; scope->parent = parent;
ucl_object_pin(scope->list);
return scope; return scope;
} }
@@ -78,6 +80,6 @@ struct ucl_scope *ucl_scope_get_root(struct ucl_scope *scope) {
void ucl_scope_delete(struct ucl *ucl, struct ucl_scope *scope) { void ucl_scope_delete(struct ucl *ucl, struct ucl_scope *scope) {
assert(ucl->scope_arena != NULL); assert(ucl->scope_arena != NULL);
ucl_object_unpin(scope->list);
ucl_arena_put(ucl->scope_arena, scope); ucl_arena_put(ucl->scope_arena, scope);
// Garbage collection will handle the objects, they are shared
} }