summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--gc.c28
2 files changed, 46 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 5eca7379..8e1fa686 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,30 @@
2011-10-15 Kaz Kylheku <kaz@kylheku.com>
+ 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.
+
+2011-10-15 Kaz Kylheku <kaz@kylheku.com>
+
* configure: POSIX Portability. Use = instead of ==
in test expressions. This was revealed by ubuntu's dash.
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;