1
1
import stackwalk:: Word ;
2
2
import libc:: size_t;
3
+ import libc:: uintptr_t;
3
4
import send_map:: linear:: LinearMap ;
4
5
5
6
export Word ;
6
7
export gc;
7
8
export cleanup_stack_for_failure;
8
9
10
+ // Mirrors rust_stack.h stk_seg
11
+ struct StackSegment {
12
+ let prev: * StackSegment ;
13
+ let next: * StackSegment ;
14
+ let end: uintptr_t ;
15
+ // And other fields which we don't care about...
16
+ }
17
+
9
18
extern mod rustrt {
10
19
fn rust_annihilate_box ( ptr : * Word ) ;
11
20
12
21
#[ rust_stack]
13
- fn rust_gc_metadata ( ) -> * Word ;
22
+ fn rust_call_tydesc_glue ( root : * Word , tydesc : * Word , field : size_t ) ;
14
23
15
24
#[ rust_stack]
16
- fn rust_call_tydesc_glue ( root : * Word , tydesc : * Word , field : size_t ) ;
25
+ fn rust_gc_metadata ( ) -> * Word ;
26
+
27
+ fn rust_get_stack_segment ( ) -> * StackSegment ;
28
+ }
29
+
30
+ unsafe fn is_frame_in_segment ( fp : * Word , segment : * StackSegment ) -> bool {
31
+ let begin: Word = unsafe :: reinterpret_cast ( & segment) ;
32
+ let end: Word = unsafe :: reinterpret_cast ( & ( * segment) . end ) ;
33
+ let frame: Word = unsafe :: reinterpret_cast ( & fp) ;
34
+
35
+ return begin <= frame && frame <= end;
17
36
}
18
37
19
38
type SafePoint = { sp_meta : * Word , fn_meta : * Word } ;
@@ -44,6 +63,17 @@ unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
44
63
45
64
type Visitor = fn ( root : * * Word , tydesc : * Word ) -> bool ;
46
65
66
+ unsafe fn bump < T , U > ( ptr : * T , count : uint ) -> * U {
67
+ return unsafe :: reinterpret_cast ( & ptr:: offset ( ptr, count) ) ;
68
+ }
69
+
70
+ unsafe fn align_to_pointer < T > ( ptr : * T ) -> * T {
71
+ let align = sys:: min_align_of :: < * T > ( ) ;
72
+ let ptr: uint = unsafe :: reinterpret_cast ( & ptr) ;
73
+ let ptr = ( ptr + ( align - 1 ) ) & -align;
74
+ return unsafe :: reinterpret_cast ( & ptr) ;
75
+ }
76
+
47
77
unsafe fn walk_safe_point ( fp : * Word , sp : SafePoint , visitor : Visitor ) {
48
78
let fp_bytes: * u8 = unsafe :: reinterpret_cast ( & fp) ;
49
79
let sp_meta_u32s: * u32 = unsafe :: reinterpret_cast ( & sp. sp_meta ) ;
@@ -97,7 +127,35 @@ const stack: Memory = 4;
97
127
98
128
const need_cleanup: Memory = exchange_heap | stack;
99
129
130
+ unsafe fn find_segment_for_frame ( fp : * Word , segment : * StackSegment )
131
+ -> { segment : * StackSegment , boundary : bool } {
132
+ // Check if frame is in either current frame or previous frame.
133
+ let in_segment = is_frame_in_segment ( fp, segment) ;
134
+ let in_prev_segment = ptr:: is_not_null ( ( * segment) . prev ) &&
135
+ is_frame_in_segment ( fp, ( * segment) . prev ) ;
136
+
137
+ // If frame is not in either segment, walk down segment list until
138
+ // we find the segment containing this frame.
139
+ if !in_segment && !in_prev_segment {
140
+ let mut segment = segment;
141
+ while ptr:: is_not_null ( ( * segment) . next ) &&
142
+ is_frame_in_segment ( fp, ( * segment) . next ) {
143
+ segment = ( * segment) . next ;
144
+ }
145
+ return { segment: segment, boundary: false } ;
146
+ }
147
+
148
+ // If frame is in previous frame, then we're at a boundary.
149
+ if !in_segment && in_prev_segment {
150
+ return { segment : ( * segment) . prev , boundary: true} ;
151
+ }
152
+
153
+ // Otherwise, we're somewhere on the inside of the frame.
154
+ return { segment: segment, boundary: false } ;
155
+ }
156
+
100
157
unsafe fn walk_gc_roots ( mem : Memory , sentinel : * * Word , visitor : Visitor ) {
158
+ let mut segment = rustrt:: rust_get_stack_segment ( ) ;
101
159
let mut last_ret: * Word = ptr:: null ( ) ;
102
160
// To avoid collecting memory used by the GC itself, skip stack
103
161
// frames until past the root GC stack frame. The root GC stack
@@ -106,48 +164,55 @@ unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
106
164
let mut reached_sentinel = ptr:: is_null ( sentinel) ;
107
165
for stackwalk:: walk_stack |frame| {
108
166
unsafe {
167
+ let pc = last_ret;
168
+ let { segment: next_segment , boundary: boundary} =
169
+ find_segment_for_frame ( frame. fp , segment) ;
170
+ segment = next_segment;
171
+ let ret_offset = if boundary { 4 } else { 1 } ;
172
+ last_ret = * ptr:: offset ( frame. fp , ret_offset) as * Word ;
173
+
174
+ if ptr:: is_null ( pc) {
175
+ again;
176
+ }
177
+
109
178
let mut delay_reached_sentinel = reached_sentinel;
110
- if ptr:: is_not_null ( last_ret) {
111
- let sp = is_safe_point ( last_ret) ;
112
- match sp {
113
- Some ( sp_info) => {
114
- for walk_safe_point( frame. fp, sp_info) |root, tydesc| {
115
- // Skip roots until we see the sentinel.
116
- if !reached_sentinel {
117
- if root == sentinel {
118
- delay_reached_sentinel = true ;
119
- }
120
- again;
179
+ let sp = is_safe_point ( pc) ;
180
+ match sp {
181
+ Some ( sp_info) => {
182
+ for walk_safe_point( frame. fp, sp_info) |root, tydesc| {
183
+ // Skip roots until we see the sentinel.
184
+ if !reached_sentinel {
185
+ if root == sentinel {
186
+ delay_reached_sentinel = true ;
121
187
}
188
+ again;
189
+ }
122
190
123
- // Skip null pointers, which can occur when a
124
- // unique pointer has already been freed.
125
- if ptr:: is_null ( * root) {
126
- again;
127
- }
191
+ // Skip null pointers, which can occur when a
192
+ // unique pointer has already been freed.
193
+ if ptr:: is_null ( * root) {
194
+ again;
195
+ }
128
196
129
- if ptr:: is_null ( tydesc) {
130
- // Root is a generic box.
131
- let refcount = * * root;
132
- if mem | task_local_heap != 0 && refcount != -1 {
133
- if !visitor ( root, tydesc) { return ; }
134
- } else if mem | exchange_heap != 0
135
- && refcount == -1 {
136
- if !visitor ( root, tydesc) { return ; }
137
- }
138
- } else {
139
- // Root is a non-immediate.
140
- if mem | stack != 0 {
141
- if !visitor ( root, tydesc) { return ; }
142
- }
197
+ if ptr:: is_null ( tydesc) {
198
+ // Root is a generic box.
199
+ let refcount = * * root;
200
+ if mem | task_local_heap != 0 && refcount != -1 {
201
+ if !visitor ( root, tydesc) { return ; }
202
+ } else if mem | exchange_heap != 0 && refcount == -1 {
203
+ if !visitor ( root, tydesc) { return ; }
204
+ }
205
+ } else {
206
+ // Root is a non-immediate.
207
+ if mem | stack != 0 {
208
+ if !visitor ( root, tydesc) { return ; }
143
209
}
144
210
}
145
- }
146
- None => ( )
147
211
}
212
+ }
213
+ None => ( )
148
214
}
149
215
reached_sentinel = delay_reached_sentinel;
150
- last_ret = * ptr:: offset ( frame. fp , 1 ) as * Word ;
151
216
}
152
217
}
153
218
}
0 commit comments