diff options
Diffstat (limited to 'libguile/whippet/src/gc-stack.c')
-rw-r--r-- | libguile/whippet/src/gc-stack.c | 92 |
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); + } +} |