Fix gc with exceptions

This commit is contained in:
2026-09-03 21:04:46 -07:00
parent 2533b0db7d
commit 3b2ecf2b16
10 changed files with 139 additions and 275 deletions
+31 -55
View File
@@ -23,17 +23,16 @@ static size_t free_objects_list_count;
static struct GCObjectList *free_objects_list;
static struct GCObjectList *black_objects;
static struct GCObjectList *grey_objects;
static struct GCObjectList *GRAY_objects;
static struct GCObjectList *white_objects;
static struct GCObjectList *static_objects;
ObjectGCSet GC_BLACK = 0;
ObjectGCSet GC_GREY = 1;
ObjectGCSet GC_GRAY = 1;
ObjectGCSet GC_WHITE = 2;
enum IncrementalGCSetp {
GC_STEP_STATICS,
GC_STEP_UNWIND,
GC_STEP_STACK,
GC_STEP_HEAP,
GC_STEP_FREE,
@@ -52,8 +51,8 @@ static struct IncrementalGCState incremental_state = {
static ALWAYS_INLINE struct GCObjectList **HEAD_FOR_SET(ObjectGCSet set) {
if (set == GC_BLACK) {
return &black_objects;
} else if (set == GC_GREY) {
return &grey_objects;
} else if (set == GC_GRAY) {
return &GRAY_objects;
} else if (set == GC_WHITE) {
return &white_objects;
} else {
@@ -188,9 +187,9 @@ static void free_object(LispVal *val) {
lisp_release_object(val);
}
static inline void make_grey_if_white(LispVal *val) {
static inline void make_GRAY_if_white(LispVal *val) {
if (OBJECTP(val) && OBJECT_GC_SET_P(val, GC_WHITE)) {
gc_move_to_set(val, GC_GREY);
gc_move_to_set(val, GC_GRAY);
}
}
@@ -201,39 +200,39 @@ static void mark_object(LispVal *val) {
}
switch (((LispObject *) val)->type) {
case TYPE_CONS:
make_grey_if_white(((LispCons *) val)->car);
make_grey_if_white(((LispCons *) val)->cdr);
make_GRAY_if_white(((LispCons *) val)->car);
make_GRAY_if_white(((LispCons *) val)->cdr);
break;
case TYPE_SYMBOL: {
LispSymbol *sym = val;
make_grey_if_white(sym->name);
make_grey_if_white(SYMBOL_VALUE(sym));
make_grey_if_white(sym->function);
make_grey_if_white(sym->plist);
make_GRAY_if_white(sym->name);
make_GRAY_if_white(SYMBOL_VALUE(sym));
make_GRAY_if_white(sym->function);
make_GRAY_if_white(sym->plist);
break;
}
case TYPE_VECTOR: {
LispVector *vec = val;
for (size_t i = 0; i < vec->length; ++i) {
make_grey_if_white(vec->data[i]);
make_GRAY_if_white(vec->data[i]);
}
break;
}
case TYPE_HASH_TABLE: {
HT_FOREACH_INDEX(val, i) {
make_grey_if_white(HASH_KEY(val, i));
make_grey_if_white(HASH_VALUE(val, i));
make_GRAY_if_white(HASH_KEY(val, i));
make_GRAY_if_white(HASH_VALUE(val, i));
}
break;
}
case TYPE_FUNCTION: {
LispFunction *fobj = val;
make_grey_if_white(fobj->name);
make_grey_if_white(fobj->docstr);
make_grey_if_white(fobj->args.req);
make_grey_if_white(fobj->args.opt);
make_grey_if_white(fobj->args.kw);
make_grey_if_white(fobj->args.rest);
make_GRAY_if_white(fobj->name);
make_GRAY_if_white(fobj->docstr);
make_GRAY_if_white(fobj->args.req);
make_GRAY_if_white(fobj->args.opt);
make_GRAY_if_white(fobj->args.kw);
make_GRAY_if_white(fobj->args.rest);
break;
}
case TYPE_STRING:
@@ -265,7 +264,7 @@ static void mark_statics(size_t *restrict limit) {
// we processed the whole list, move to the next step
if (!node) {
incremental_state.next_static = static_objects;
incremental_state.step = GC_STEP_UNWIND;
incremental_state.step = GC_STEP_STACK;
}
}
@@ -312,26 +311,6 @@ static void mark_stack_frame(StackFrame *frame, size_t *restrict limit) {
}
}
static void mark_unwind_info(size_t *restrict limit) {
if (the_stack.unwind_info.set) {
switch (the_stack.unwind_info.cause) {
case UNWIND_NORMAL:
mark_object(the_stack.unwind_info.target);
saturating_dec(limit, 1);
break;
case UNWIND_EXCEPTION:
mark_object(the_stack.unwind_info.exception.name);
mark_object(the_stack.unwind_info.exception.data);
saturating_dec(limit, 2);
break;
default:
abort();
break;
}
}
incremental_state.step = GC_STEP_STACK;
}
static void mark_the_stack(size_t *restrict limit) {
size_t i;
for (i = 0; i < the_stack.depth && *limit; ++i) {
@@ -351,11 +330,11 @@ static void unmark_the_stack(void) {
}
}
static void mark_grey_objects(size_t *restrict limit) {
while (grey_objects && saturating_dec(limit, 1)) {
mark_object(grey_objects->obj);
static void mark_GRAY_objects(size_t *restrict limit) {
while (GRAY_objects && saturating_dec(limit, 1)) {
mark_object(GRAY_objects->obj);
}
if (!grey_objects) {
if (!GRAY_objects) {
incremental_state.step = GC_STEP_FREE;
}
}
@@ -398,22 +377,19 @@ void lisp_gc_yield(struct timespec *restrict time_took, bool full) {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
size_t limit = full ? SIZE_MAX : LISP_GC_INCREMENTAL_COUNT;
while (limit) {
// there are more grey objects, mark them before we sweep
if (incremental_state.step == GC_STEP_FREE && grey_objects) {
// there are more GRAY objects, mark them before we sweep
if (incremental_state.step == GC_STEP_FREE && GRAY_objects) {
incremental_state.step = GC_STEP_HEAP;
}
switch (incremental_state.step) {
case GC_STEP_STATICS:
mark_statics(&limit);
break;
case GC_STEP_UNWIND:
mark_unwind_info(&limit);
break;
case GC_STEP_STACK:
mark_the_stack(&limit);
break;
case GC_STEP_HEAP:
mark_grey_objects(&limit);
mark_GRAY_objects(&limit);
break;
case GC_STEP_FREE:
gc_sweep_objects(&limit);
@@ -438,8 +414,8 @@ void lisp_gc_teardown(void) {
while (white_objects) {
free_object(white_objects->obj);
}
while (grey_objects) {
free_object(grey_objects->obj);
while (GRAY_objects) {
free_object(GRAY_objects->obj);
}
while (black_objects) {
free_object(black_objects->obj);