@@ -2,6 +2,10 @@ import stackwalk::Word;
2
2
import libc:: size_t;
3
3
import send_map:: linear:: LinearMap ;
4
4
5
+ export Word ;
6
+ export gc;
7
+ export cleanup_stack_for_failure;
8
+
5
9
extern mod rustrt {
6
10
fn rust_annihilate_box ( ptr : * Word ) ;
7
11
@@ -93,15 +97,29 @@ const stack: Memory = 4;
93
97
94
98
const need_cleanup: Memory = exchange_heap | stack;
95
99
96
- unsafe fn walk_gc_roots ( mem : Memory , visitor : Visitor ) {
100
+ unsafe fn walk_gc_roots ( mem : Memory , sentinel : * * Word , visitor : Visitor ) {
97
101
let mut last_ret: * Word = ptr:: null ( ) ;
102
+ // To avoid collecting memory used by the GC itself, skip stack
103
+ // frames until past the root GC stack frame. The root GC stack
104
+ // frame is marked by a sentinel, which is a box pointer stored on
105
+ // the stack.
106
+ let mut reached_sentinel = ptr:: is_null ( sentinel) ;
98
107
for stackwalk:: walk_stack |frame| {
99
108
unsafe {
109
+ let mut delay_reached_sentinel = reached_sentinel;
100
110
if ptr:: is_not_null ( last_ret) {
101
111
let sp = is_safe_point ( last_ret) ;
102
112
match sp {
103
113
Some ( sp_info) => {
104
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;
121
+ }
122
+
105
123
// Skip null pointers, which can occur when a
106
124
// unique pointer has already been freed.
107
125
if ptr:: is_null ( * root) {
@@ -128,14 +146,15 @@ unsafe fn walk_gc_roots(mem: Memory, visitor: Visitor) {
128
146
None => ( )
129
147
}
130
148
}
149
+ reached_sentinel = delay_reached_sentinel;
131
150
last_ret = * ptr:: offset ( frame. fp , 1 ) as * Word ;
132
151
}
133
152
}
134
153
}
135
154
136
155
fn gc ( ) {
137
156
unsafe {
138
- for walk_gc_roots( task_local_heap) |_root, _tydesc| {
157
+ for walk_gc_roots( task_local_heap, ptr :: null ( ) ) |_root, _tydesc| {
139
158
// FIXME(#2997): Walk roots and mark them.
140
159
io:: stdout( ) . write( [ 46 ] ) ; // .
141
160
}
@@ -153,8 +172,16 @@ fn RootSet() -> RootSet {
153
172
// dead.
154
173
fn cleanup_stack_for_failure ( ) {
155
174
unsafe {
175
+ // Leave a sentinel on the stack to mark the current
176
+ // frame. The stack walker will ignore any frames above the
177
+ // sentinel, thus avoiding collecting any memory being used by
178
+ // the stack walker itself.
179
+ let sentinel_box = ~0 ;
180
+ let sentinel : * * Word =
181
+ unsafe :: reinterpret_cast( & ptr:: addr_of( sentinel_box) ) ;
182
+
156
183
let mut roots = ~RootSet ( ) ;
157
- for walk_gc_roots( need_cleanup) |root, tydesc| {
184
+ for walk_gc_roots( need_cleanup, sentinel ) |root, tydesc| {
158
185
// Track roots to avoid double frees.
159
186
if option : : is_some( roots. find( & * root) ) {
160
187
again;
0 commit comments