Add seemingly functional but hacky gc
This commit is contained in:
@@ -35,6 +35,7 @@ struct ucl_object *ucl_evaluate_builtin_form(struct ucl_state *state, struct ucl
|
||||
i++;
|
||||
}
|
||||
result = ucl_progn(fun_state, fun_forms);
|
||||
ucl_state_delete(fun_state);
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,15 @@
|
||||
item_name != NULL && iter_name != NULL && (cond); \
|
||||
iter_name = iter_name->cell.cdr, item_name = (iter_name == NULL) ? NULL : iter_name->cell.car)
|
||||
|
||||
// TODO: Refactor this struct's location
|
||||
struct ucl_state {
|
||||
// TODO: For garbage collection, we need references from the parent->child state
|
||||
struct ucl_object *list;
|
||||
struct ucl_state *parent;
|
||||
};
|
||||
|
||||
extern struct ucl_arena *state_arena;
|
||||
|
||||
struct ucl_object *ucl_cell_create(struct ucl_object *car, struct ucl_object *cdr);
|
||||
struct ucl_object *ucl_int_create(int integer);
|
||||
struct ucl_object *ucl_symbol_create(const char* symbol);
|
||||
|
||||
@@ -85,6 +85,7 @@ int main(int argc, const char **argv) {
|
||||
printf("\n");
|
||||
|
||||
free(line);
|
||||
ucl_gc();
|
||||
}
|
||||
} else {
|
||||
struct ucl_object *sexp = ucl_parse(argv[1]);
|
||||
|
||||
72
src/memory.c
72
src/memory.c
@@ -1,12 +1,26 @@
|
||||
#include "uclisp.h"
|
||||
#include "internal.h"
|
||||
#include "arena.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef UCL_STATE_ARENA_SIZE
|
||||
#define UCL_STATE_ARENA_SIZE 16
|
||||
#endif
|
||||
|
||||
#ifndef UCL_OBJECT_ARENA_SIZE
|
||||
#define UCL_OBJECT_ARENA_SIZE (1 << 14)
|
||||
#endif
|
||||
|
||||
static struct ucl_object *ucl_object_alloc();
|
||||
|
||||
static struct ucl_arena *object_arena = NULL;
|
||||
|
||||
struct ucl_object *ucl_cell_create(struct ucl_object *car, struct ucl_object *cdr)
|
||||
{
|
||||
struct ucl_object* obj = ucl_object_alloc();
|
||||
@@ -67,7 +81,12 @@ struct ucl_object *ucl_special_create(ucl_lisp special)
|
||||
|
||||
|
||||
static struct ucl_object* ucl_object_alloc() {
|
||||
return malloc(sizeof(struct ucl_object));
|
||||
if (object_arena == NULL) {
|
||||
object_arena = ucl_arena_create(sizeof(struct ucl_object), UCL_OBJECT_ARENA_SIZE);
|
||||
}
|
||||
struct ucl_object *obj = ucl_arena_get(object_arena);
|
||||
assert(obj != NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ucl_object_delete(struct ucl_object *obj) {
|
||||
@@ -77,9 +96,9 @@ void ucl_object_delete(struct ucl_object *obj) {
|
||||
|
||||
switch (obj->type) {
|
||||
case UCL_TYPE_CELL:
|
||||
ucl_object_delete(obj->cell.car);
|
||||
//ucl_object_delete(obj->cell.car);
|
||||
obj->cell.car = NULL;
|
||||
ucl_object_delete(obj->cell.cdr);
|
||||
//ucl_object_delete(obj->cell.cdr);
|
||||
obj->cell.cdr = NULL;
|
||||
break;
|
||||
case UCL_TYPE_SYMBOL:
|
||||
@@ -99,5 +118,50 @@ void ucl_object_delete(struct ucl_object *obj) {
|
||||
case UCL_TYPE_COUNT:
|
||||
break;
|
||||
}
|
||||
free(obj);
|
||||
|
||||
ucl_arena_put(object_arena, obj);
|
||||
}
|
||||
|
||||
void ucl_object_mark(struct ucl_object *obj) {
|
||||
if (obj == NULL || obj->reachable) {
|
||||
return;
|
||||
}
|
||||
|
||||
obj->reachable = 1;
|
||||
if (obj->type == UCL_TYPE_CELL) {
|
||||
ucl_object_mark(obj->cell.car);
|
||||
ucl_object_mark(obj->cell.cdr);
|
||||
}
|
||||
}
|
||||
|
||||
void ucl_state_mark(struct ucl_arena * arena, void *obj) {
|
||||
(void) arena;
|
||||
struct ucl_state *state = (struct ucl_state *) obj;
|
||||
|
||||
ucl_object_mark(state->list);
|
||||
}
|
||||
|
||||
void ucl_gc_unmark(struct ucl_arena * arena, void *obj) {
|
||||
(void) arena;
|
||||
struct ucl_object *object = (struct ucl_object *) obj;
|
||||
object->reachable = 0;
|
||||
}
|
||||
|
||||
void ucl_gc_sweep(struct ucl_arena * arena, void *obj) {
|
||||
(void) arena;
|
||||
struct ucl_object *object = (struct ucl_object *) obj;
|
||||
if (object->reachable == 0) {
|
||||
// TODO: Mapping across this is broken, since this is a recursive delete
|
||||
ucl_object_delete(object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ucl_gc() {
|
||||
ucl_arena_map(object_arena, ucl_gc_unmark);
|
||||
|
||||
ucl_arena_map(state_arena, ucl_state_mark);
|
||||
|
||||
ucl_arena_map(object_arena, ucl_gc_sweep);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ struct ucl_object *ucl_special_let(struct ucl_state *state, struct ucl_object *a
|
||||
|
||||
if (value->type == UCL_TYPE_ERROR) {
|
||||
// TODO cleanup
|
||||
ucl_state_delete(let_state);
|
||||
return value;
|
||||
}
|
||||
ucl_state_put(let_state, sym->symbol, value);
|
||||
|
||||
22
src/state.c
22
src/state.c
@@ -2,22 +2,24 @@
|
||||
#include "internal.h"
|
||||
#include "state.h"
|
||||
#include "utility.h"
|
||||
#include "arena.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Implements state as a giant alist
|
||||
// TODO: Consider generalizing the alist concept
|
||||
|
||||
struct ucl_state {
|
||||
struct ucl_object *list;
|
||||
struct ucl_state *parent;
|
||||
};
|
||||
// TODO: Consider generalizing the alist concept
|
||||
// TODO: Rename 'state' to 'scope'
|
||||
|
||||
#define NAME_POSITION 0
|
||||
#define DATA_POSITION 1
|
||||
|
||||
#define STATE_ARENA_CAPACITY 32
|
||||
|
||||
struct ucl_arena *state_arena;
|
||||
|
||||
static struct ucl_object *ucl_state_get_cell(struct ucl_state *state, const char *name) {
|
||||
FOREACH_LIST(state->list, iter, item) {
|
||||
assert(item->type == UCL_TYPE_CELL);
|
||||
@@ -57,7 +59,10 @@ void ucl_state_put(struct ucl_state *state, const char *name, struct ucl_object
|
||||
}
|
||||
|
||||
struct ucl_state *ucl_state_create() {
|
||||
struct ucl_state *state = malloc(sizeof(struct ucl_state));
|
||||
if (state_arena == NULL) {
|
||||
state_arena = ucl_arena_create(sizeof(struct ucl_state), STATE_ARENA_CAPACITY);
|
||||
}
|
||||
struct ucl_state *state = ucl_arena_get(state_arena);
|
||||
state->list = ucl_nil_create();
|
||||
state->parent = NULL;
|
||||
return state;
|
||||
@@ -77,6 +82,7 @@ struct ucl_state *ucl_state_get_root(struct ucl_state *state) {
|
||||
}
|
||||
|
||||
void ucl_state_delete(struct ucl_state *state) {
|
||||
// TODO: Cleanup
|
||||
// ucl_object_delete(state->list);
|
||||
assert(state_arena != NULL);
|
||||
ucl_arena_put(state_arena, state);
|
||||
// Garbage collection will handle the objects, they are shared
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ struct ucl_state;
|
||||
typedef struct ucl_object *(*ucl_lisp)(struct ucl_state* state, struct ucl_object *args);
|
||||
|
||||
struct ucl_object {
|
||||
enum ucl_type type;
|
||||
union {
|
||||
struct ucl_cell cell;
|
||||
const char *symbol;
|
||||
@@ -31,6 +30,8 @@ struct ucl_object {
|
||||
ucl_lisp builtin;
|
||||
ucl_lisp special;
|
||||
};
|
||||
enum ucl_type type;
|
||||
char reachable;
|
||||
};
|
||||
|
||||
|
||||
@@ -46,4 +47,7 @@ struct ucl_object *ucl_tokenize(const char *source);
|
||||
struct ucl_object *ucl_parse(const char *sexp);
|
||||
struct ucl_object *ucl_evaluate(struct ucl_state *state, struct ucl_object *sexp);
|
||||
|
||||
// TODO: State encapsulation is all wonky here)
|
||||
void ucl_gc();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -77,6 +77,7 @@ struct ucl_object *ucl_list_nth(struct ucl_object *list, int n) {
|
||||
|
||||
int length = ucl_list_length(list)->integer;
|
||||
UCL_COND_OR_RET_ERROR(length > n, "Position n >= list length in ucl_list_nth");
|
||||
UCL_COND_OR_RET_ERROR(n >= 0, "Index to ucl_list_nth was less that zero");
|
||||
|
||||
struct ucl_object *node = list;
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
||||
Reference in New Issue
Block a user