Permalink
Browse files

Implement registering roots to a full heap.

This was stubbed during the refactor, and I'm not honestly convinced it
worked before. We add a test as well to ensure it does.
  • Loading branch information...
1 parent 63e7674 commit 488bb983302bd99d5b89cef3d17eabe2b4fe6040 @nelhage committed Dec 29, 2008
Showing with 52 additions and 6 deletions.
  1. +29 −4 gc.c
  2. +23 −2 tests.c
View
@@ -21,6 +21,9 @@ static int in_gc = 0;
static gc_handle gc_root_stack = NIL;
static gc_handle gc_root_hooks = NIL;
+static uint32_t gc_n_temp_roots = 0;
+static gc_handle *gc_temp_roots[MAX_EXTERNAL_ROOTS_FRAME];
+
void *_gc_try_alloc(uint32_t n) {
if(free_ptr - working_mem + n <= mem_size) {
void *h = free_ptr;
@@ -133,12 +136,28 @@ void gc_register_roots(gc_handle* root0, ...) {
/*
* Because the roots may already be live, we can't perform GC
* until we've safely registered them. Use _try_alloc to try to
- * put them in the heap. If that fails, we stash them in a
- * statically allocated buffer, do the GC, and then stick them in
- * the heap.
+ * put them in the heap without risking a GC.
*/
frame = (gc_external_roots*)_gc_try_alloc(3 + nroots);
- assert(frame); /* XXX FIXME */
+
+ if(!frame) {
+ /*
+ * If there's no room on the heap, we stash them in a
+ * statically allocated buffer, do the GC, and then move them
+ * into the heap.
+ */
+ i = 0;
+ va_start(ap, root0);
+ gc_temp_roots[i++] = root0;
+ while(i < nroots)
+ gc_temp_roots[i++] = va_arg(ap, gc_handle*);
+ va_end(ap);
+ gc_n_temp_roots = nroots;
+ frame = (gc_external_roots*)_gc_alloc(3 + nroots);
+ gc_n_temp_roots = 0;
+ }
+
+ assert(frame);
frame->header.ops = &gc_external_root_ops;
frame->nroots = nroots;
@@ -216,8 +235,14 @@ void gc_relocate(gc_handle *v) {
}
void gc_relocate_root() {
+ int i;
gc_relocate(&gc_root_stack);
gc_relocate(&gc_root_hooks);
+ if(gc_n_temp_roots) {
+ for(i = 0; i < gc_n_temp_roots; i++) {
+ gc_relocate(gc_temp_roots[i]);
+ }
+ }
}
void gc_protect_roots() {
View
@@ -162,12 +162,13 @@ START_TEST(gc_roots)
{
gc_handle reg;
- reg = reg1 = sc_alloc_cons();
-
gc_register_roots(&reg, NULL);
+ reg = reg1 = sc_alloc_cons();
+
gc_gc();
+ fail_unless(sc_consp(reg1));
fail_unless(reg == reg1);
gc_pop_roots();
@@ -178,6 +179,25 @@ START_TEST(gc_roots)
}
END_TEST
+START_TEST(gc_live_roots)
+{
+ gc_handle reg;
+ reg = reg1 = sc_alloc_cons();
+
+ /* Use up all available memory */
+ gc_alloc(NULL, gc_free_mem());
+
+ gc_register_roots(&reg, NULL);
+
+ gc_gc();
+
+ fail_unless(sc_consp(reg1));
+ fail_unless(reg == reg1);
+
+ gc_pop_roots();
+}
+END_TEST
+
static void obarray_setup() {
obarray_init();
}
@@ -230,6 +250,7 @@ Suite *gc_suite()
tcase_add_test(tc_core, gc_large_allocs);
tcase_add_test(tc_core, gc_root_hook);
tcase_add_test(tc_core, gc_roots);
+ tcase_add_test(tc_core, gc_live_roots);
suite_add_tcase(s, tc_core);
TCase *tc_obarray = tcase_create("obarray");

0 comments on commit 488bb98

Please sign in to comment.