summaryrefslogtreecommitdiffstats
path: root/gc.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-10-15 13:48:41 -0400
committerKaz Kylheku <kaz@kylheku.com>2011-10-15 13:48:41 -0400
commite6fc643b480c519262bb7097c8f2cb50df1a30f8 (patch)
tree58bc32acffd141030154597e912e83529a477114 /gc.c
parent94f45d08c3c9db275aae5cb47e948b8c6824c384 (diff)
downloadtxr-e6fc643b480c519262bb7097c8f2cb50df1a30f8.tar.gz
txr-e6fc643b480c519262bb7097c8f2cb50df1a30f8.tar.bz2
txr-e6fc643b480c519262bb7097c8f2cb50df1a30f8.zip
Fixed broken GC on x86_64 (Ubuntu 11, gcc 4.5.2).
The issues is that due to the aggressive function inlining in the gc module, the mark_mem_region function is not real subroutine. The address of its local variable &gc_stack_top ended up excluding the machine context saved by setjmp in the parent function. I.e. the buffer was not between the computed stack top and bottom. Thus registers were not being scanned for references to values. I added a little abstraction to the machine context in the process of fixing this. * gc.c (struct mach_context, mach_context_t): New type. (save_context): New macro. (mark): Takes two new arguments, pointer to the stack top and machine context. It scans the machine context explicitly rather than relying it to be on the stack, between the top and bottom. This context is in fact only object within the garbage collector part of the activation chain that we need to scan. (gc): Use new abstraction to save machine context. Local variable is used to derive the stack top here. The stack top is the top of the stack above the activation frames in the garbage collector itself. The gc has nothing on its stack that should be scanned, except for the machine context, which is now handled explicitly.
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/gc.c b/gc.c
index ae234291..8f1ee6dc 100644
--- a/gc.c
+++ b/gc.c
@@ -49,6 +49,12 @@ typedef struct heap {
obj_t block[HEAP_SIZE];
} heap_t;
+typedef struct mach_context {
+ jmp_buf buf;
+} mach_context_t;
+
+#define save_context(X) setjmp((X).buf)
+
int opt_gc_debug;
#ifdef HAVE_VALGRIND
int opt_vg_debug;
@@ -341,19 +347,25 @@ static void mark_mem_region(val *low, val *high)
}
}
-static void mark(void)
+static void mark(mach_context_t *pmc, val *gc_stack_top)
{
- val gc_stack_top;
val **rootloc;
/*
* First, scan the officially registered locations.
*/
-
for (rootloc = prot_stack; rootloc != top; rootloc++)
mark_obj(**rootloc);
- mark_mem_region(&gc_stack_top, gc_stack_bottom);
+ /*
+ * Then the machine context
+ */
+ mark_mem_region((val *) pmc, (val *) (pmc + 1));
+
+ /*
+ * Finally, the stack.
+ */
+ mark_mem_region(gc_stack_top, gc_stack_bottom);
}
static void sweep(void)
@@ -433,11 +445,13 @@ static void sweep(void)
void gc(void)
{
+ val gc_stack_top = nil;
+
if (gc_enabled) {
- jmp_buf jmp;
- setjmp(jmp);
+ mach_context_t mc;
+ save_context(mc);
gc_enabled = 0;
- mark();
+ mark(&mc, &gc_stack_top);
hash_process_weak();
sweep();
gc_enabled = 1;