diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2011-10-15 13:48:41 -0400 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2011-10-15 13:48:41 -0400 |
commit | e6fc643b480c519262bb7097c8f2cb50df1a30f8 (patch) | |
tree | 58bc32acffd141030154597e912e83529a477114 /gc.c | |
parent | 94f45d08c3c9db275aae5cb47e948b8c6824c384 (diff) | |
download | txr-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.c | 28 |
1 files changed, 21 insertions, 7 deletions
@@ -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; |