-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathgc-stack.c
89 lines (78 loc) · 2.85 KB
/
gc-stack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// 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 struct gc_stack_addr capture_current_thread_hot_stack_addr(void) {
return gc_stack_addr(current_thread_hot_stack_addr());
}
static struct gc_stack_addr capture_current_thread_cold_stack_addr(void) {
return gc_stack_addr(gc_platform_current_thread_stack_base());
}
void gc_stack_init(struct gc_stack *stack, struct gc_stack_addr base) {
if (gc_stack_addr_is_empty (base))
base = capture_current_thread_cold_stack_addr();
stack->cold = stack->hot = base;
}
void gc_stack_capture_hot(struct gc_stack *stack) {
stack->hot = capture_current_thread_hot_stack_addr();
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();
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);
}
}