Work on GC
This commit is contained in:
+78
-16
@@ -1,6 +1,8 @@
|
||||
#include "stack.h"
|
||||
|
||||
#include "function.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -82,26 +84,86 @@ void add_local_reference_no_recurse(LispVal *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
static LispVal *next_local_reference(size_t *restrict i) {
|
||||
if (*i >= LISP_STACK_TOP()->local_refs.num_refs) {
|
||||
return NULL;
|
||||
}
|
||||
size_t block_idx = *i / LOCAL_REFERENCES_BLOCK_LENGTH;
|
||||
size_t small_idx = *i % LOCAL_REFERENCES_BLOCK_LENGTH;
|
||||
LispVal *obj =
|
||||
LISP_STACK_TOP()->local_refs.blocks[block_idx]->refs[small_idx];
|
||||
++*i;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static inline void add_local_ref_if_not_seen_no_recurse(LispVal *seen_objs,
|
||||
LispVal *obj) {
|
||||
if (NILP(Fgethash(seen_objs, obj, Qnil))) {
|
||||
add_local_reference_no_recurse(obj);
|
||||
Fputhash(seen_objs, obj, Qt);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void add_local_refs_for_object_sub_vals(LispVal *seen_objs,
|
||||
LispVal *val) {
|
||||
switch (((LispObject *) val)->type) {
|
||||
case TYPE_CONS:
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs,
|
||||
((LispCons *) val)->car);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs,
|
||||
((LispCons *) val)->cdr);
|
||||
break;
|
||||
case TYPE_SYMBOL: {
|
||||
LispSymbol *sym = val;
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, sym->name);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, sym->value);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, sym->function);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, sym->plist);
|
||||
break;
|
||||
}
|
||||
case TYPE_VECTOR: {
|
||||
LispVector *vec = val;
|
||||
for (size_t i = 0; i < vec->length; ++i) {
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, vec->data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_HASH_TABLE: {
|
||||
HT_FOREACH_INDEX(val, i) {
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, HASH_KEY(val, i));
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, HASH_VALUE(val, i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_FUNCTION: {
|
||||
LispFunction *fobj = val;
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, fobj->name);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, fobj->docstr);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, fobj->args.req);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, fobj->args.opt);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, fobj->args.kw);
|
||||
add_local_ref_if_not_seen_no_recurse(seen_objs, fobj->args.rest);
|
||||
break;
|
||||
}
|
||||
case TYPE_STRING:
|
||||
// ho held refs
|
||||
break;
|
||||
case TYPE_FIXNUM:
|
||||
case TYPE_FLOAT:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void add_local_reference(LispVal *obj) {
|
||||
add_local_reference_no_recurse(obj);
|
||||
LispVal *seen_objs = make_hash_table_no_gc(Qnil, Qnil);
|
||||
ObjectProcessStack stack;
|
||||
init_object_process_stack(&stack);
|
||||
object_process_stack_push_held_objects(&stack, obj);
|
||||
while (!OBJECT_PROCESS_STACK_EMPTY_P(&stack)) {
|
||||
LispVal *top = object_process_stack_pop(&stack);
|
||||
assert(OBJECTP(top));
|
||||
if (!OBJECT_HAS_LOCAL_REFERENCE_P(obj)) {
|
||||
store_local_reference_in_frame(LISP_STACK_TOP(), top);
|
||||
SET_OBJECT_HAS_LOCAL_REFERENCE(obj, true);
|
||||
}
|
||||
if (NILP(Fgethash(seen_objs, obj, Qnil))) {
|
||||
object_process_stack_push_held_objects(&stack, top);
|
||||
Fputhash(seen_objs, obj, Qt);
|
||||
}
|
||||
Fputhash(seen_objs, obj, Qt);
|
||||
size_t i = LISP_STACK_TOP()->local_refs.num_refs - 1;
|
||||
LispVal *cur;
|
||||
while ((cur = next_local_reference(&i))) {
|
||||
add_local_refs_for_object_sub_vals(seen_objs, cur);
|
||||
}
|
||||
free_object_process_stack(&stack);
|
||||
release_hash_table_no_gc(seen_objs);
|
||||
}
|
||||
|
||||
void compact_stack_frame(struct StackFrame *restrict frame) {
|
||||
|
||||
Reference in New Issue
Block a user