summaryrefslogtreecommitdiff
path: root/libguile/whippet/src/gc-stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'libguile/whippet/src/gc-stack.c')
-rw-r--r--libguile/whippet/src/gc-stack.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/libguile/whippet/src/gc-stack.c b/libguile/whippet/src/gc-stack.c
new file mode 100644
index 000000000..318f5757f
--- /dev/null
+++ b/libguile/whippet/src/gc-stack.c
@@ -0,0 +1,92 @@
+// For pthread_getattr_np.
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define GC_IMPL 1
+
+#include "debug.h"
+#include "gc-align.h"
+#include "gc-assert.h"
+#include "gc-inline.h"
+#include "gc-platform.h"
+#include "gc-stack.h"
+
+static uintptr_t current_thread_hot_stack_addr(void) {
+#ifdef __GNUC__
+ return (uintptr_t)__builtin_frame_address(0);
+#else
+ uintptr_t local;
+ return (uintptr_t)&local;
+#endif
+}
+
+// FIXME: check platform stack growth direction.
+#define HOTTER_THAN <=
+
+static void capture_current_thread_hot_stack_addr(struct gc_stack_addr *addr) {
+ addr->addr = current_thread_hot_stack_addr();
+}
+
+static void capture_current_thread_cold_stack_addr(struct gc_stack_addr *addr) {
+ addr->addr = gc_platform_current_thread_stack_base();
+}
+
+void gc_stack_init(struct gc_stack *stack, struct gc_stack_addr *base) {
+ if (base)
+ stack->cold = *base;
+ else
+ capture_current_thread_cold_stack_addr(&stack->cold);
+ stack->hot = stack->cold;
+}
+
+void gc_stack_capture_hot(struct gc_stack *stack) {
+ capture_current_thread_hot_stack_addr(&stack->hot);
+ setjmp(stack->registers);
+ GC_ASSERT(stack->hot.addr HOTTER_THAN stack->cold.addr);
+}
+
+static void* call_with_stack(void* (*)(struct gc_stack_addr*, void*),
+ struct gc_stack_addr*, void*) GC_NEVER_INLINE;
+static void* call_with_stack(void* (*f)(struct gc_stack_addr *, void *),
+ struct gc_stack_addr *addr, void *arg) {
+ return f(addr, arg);
+}
+void* gc_call_with_stack_addr(void* (*f)(struct gc_stack_addr *base,
+ void *arg),
+ void *arg) {
+ struct gc_stack_addr base;
+ capture_current_thread_hot_stack_addr(&base);
+ return call_with_stack(f, &base, arg);
+}
+
+void gc_stack_visit(struct gc_stack *stack,
+ void (*visit)(uintptr_t low, uintptr_t high,
+ struct gc_heap *heap, void *data),
+ struct gc_heap *heap,
+ void *data) {
+ {
+ uintptr_t low = (uintptr_t)stack->registers;
+ GC_ASSERT(low == align_down(low, sizeof(uintptr_t)));
+ uintptr_t high = low + sizeof(jmp_buf);
+ DEBUG("found mutator register roots for %p: [%p,%p)\n", stack,
+ (void*)low, (void*)high);
+ visit(low, high, heap, data);
+ }
+
+ if (0 HOTTER_THAN 1) {
+ DEBUG("found mutator stack roots for %p: [%p,%p)\n", stack,
+ (void*)stack->hot.addr, (void*)stack->cold.addr);
+ visit(align_up(stack->hot.addr, sizeof(uintptr_t)),
+ align_down(stack->cold.addr, sizeof(uintptr_t)),
+ heap, data);
+ } else {
+ DEBUG("found mutator stack roots for %p: [%p,%p)\n", stack,
+ (void*)stack->cold.addr, (void*)stack->hot.addr);
+ visit(align_up(stack->cold.addr, sizeof(uintptr_t)),
+ align_down(stack->hot.addr, sizeof(uintptr_t)),
+ heap, data);
+ }
+}