From afaa53bb7f669fc25d4fe4ff009e482dfb83666d Mon Sep 17 00:00:00 2001 From: Max Regan Date: Tue, 29 Nov 2022 21:21:16 -0500 Subject: [PATCH] Implement pin-based gc This will allow for cleanup to occur mid-calculation when used throughout --- src/lisp.h | 4 ++-- src/memory.c | 35 +++++++++++++---------------------- src/scope.c | 4 +++- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/lisp.h b/src/lisp.h index e12aa86..29ebc93 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -38,8 +38,8 @@ void ucl_add_special(struct ucl *state, const char *name, ucl_lisp fun); if (len != 2) { \ return NULL; \ } \ - struct ucl_object *arg0 = ucl_list_nth(args, 0); \ - struct ucl_object *arg1 = ucl_list_nth(args, 1); \ + struct ucl_object *arg0 = ucl_list_nth(args, 0); \ + struct ucl_object *arg1 = ucl_list_nth(args, 1); \ 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) diff --git a/src/memory.c b/src/memory.c index de21228..3722dab 100644 --- a/src/memory.c +++ b/src/memory.c @@ -83,7 +83,7 @@ void ucl_object_pin(struct ucl_object *obj) { 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; } @@ -131,52 +131,43 @@ void ucl_object_delete(struct ucl* state, struct ucl_object *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) { return; } - obj->flags |= 1; + obj->flags |= UCL_OBJ_FLAG_REACHABLE; if (obj->type == UCL_TYPE_CELL) { - ucl_object_mark(obj->cell.car); - ucl_object_mark(obj->cell.cdr); + ucl_object_mark_recursive(obj->cell.car); + 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; - 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; struct ucl_object *object = (struct ucl_object *) obj; object->flags &= ~UCL_OBJ_FLAG_REACHABLE; } static void ucl_gc_sweep(struct ucl_arena * arena, void *obj) { - (void) arena; struct ucl_object *object = (struct ucl_object *) obj; if (!(object->flags &UCL_OBJ_FLAG_REACHABLE)) { 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) { - // TODO: Implement scope cleanup - - 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_unmark_all); + ucl_arena_map(ucl->obj_arena, ucl_gc_mark_pinned); ucl_arena_map(ucl->obj_arena, ucl_gc_sweep); } diff --git a/src/scope.c b/src/scope.c index 931d547..6c0a0eb 100644 --- a/src/scope.c +++ b/src/scope.c @@ -60,12 +60,14 @@ struct ucl_scope *ucl_scope_create(struct ucl *state) { struct ucl_scope *scope = ucl_arena_get(state->scope_arena); scope->list = ucl_nil_create(state); scope->parent = NULL; + ucl_object_pin(scope->list); return scope; } struct ucl_scope *ucl_scope_create_child(struct ucl *state, struct ucl_scope *parent) { struct ucl_scope *scope = ucl_scope_create(state); scope->parent = parent; + ucl_object_pin(scope->list); 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) { assert(ucl->scope_arena != NULL); + ucl_object_unpin(scope->list); ucl_arena_put(ucl->scope_arena, scope); - // Garbage collection will handle the objects, they are shared }