1
1
import stackwalk:: Word ;
2
2
import libc:: size_t;
3
+ import send_map:: linear:: LinearMap ;
3
4
4
5
extern mod rustrt {
5
6
fn rust_annihilate_box ( ptr : * Word ) ;
@@ -37,7 +38,7 @@ unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
37
38
return None ;
38
39
}
39
40
40
- type Visitor = fn ( root : * * Word , tydesc : * Word ) ;
41
+ type Visitor = fn ( root : * * Word , tydesc : * Word ) -> bool ;
41
42
42
43
unsafe fn walk_safe_point ( fp : * Word , sp : SafePoint , visitor : Visitor ) {
43
44
let fp_bytes: * u8 = unsafe :: reinterpret_cast ( & fp) ;
@@ -69,7 +70,7 @@ unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
69
70
} else {
70
71
ptr:: null ( )
71
72
} ;
72
- visitor ( root, tydesc) ;
73
+ if ! visitor ( root, tydesc) { return ; }
73
74
}
74
75
sri += 1 ;
75
76
}
@@ -94,25 +95,25 @@ const need_cleanup: Memory = exchange_heap | stack;
94
95
95
96
unsafe fn walk_gc_roots ( mem : Memory , visitor : Visitor ) {
96
97
let mut last_ret: * Word = ptr:: null ( ) ;
97
- do stackwalk:: walk_stack |frame| {
98
+ for stackwalk:: walk_stack |frame| {
98
99
unsafe {
99
100
if ptr:: is_not_null ( last_ret) {
100
101
let sp = is_safe_point ( last_ret) ;
101
102
match sp {
102
103
Some ( sp_info) => {
103
- do walk_safe_point ( frame. fp , sp_info) |root, tydesc| {
104
+ for walk_safe_point( frame. fp, sp_info) |root, tydesc| {
104
105
if ptr:: is_null ( tydesc) {
105
106
// Root is a generic box.
106
107
let refcount = * * root;
107
108
if mem | task_local_heap != 0 && refcount != -1 {
108
- visitor ( root, tydesc) ;
109
+ if ! visitor ( root, tydesc) { return ; }
109
110
} else if mem | exchange_heap != 0 {
110
- visitor ( root, tydesc) ;
111
+ if ! visitor ( root, tydesc) { return ; }
111
112
}
112
113
} else {
113
114
// Root is a non-immediate.
114
115
if mem | stack != 0 {
115
- visitor ( root, tydesc) ;
116
+ if ! visitor ( root, tydesc) { return ; }
116
117
}
117
118
}
118
119
}
@@ -122,34 +123,42 @@ unsafe fn walk_gc_roots(mem: Memory, visitor: Visitor) {
122
123
}
123
124
last_ret = * ptr:: offset ( frame. fp , 1 ) as * Word ;
124
125
}
125
- true
126
126
}
127
127
}
128
128
129
129
fn gc ( ) {
130
130
unsafe {
131
- let mut i = 0 ;
132
- do walk_gc_roots ( task_local_heap) |_root, _tydesc| {
131
+ for walk_gc_roots( task_local_heap) |_root, _tydesc| {
133
132
// FIXME(#2997): Walk roots and mark them.
134
133
io:: stdout( ) . write( [ 46 ] ) ; // .
135
- i += 1 ;
136
134
}
137
135
}
138
136
}
139
137
138
+ type RootSet = LinearMap < * Word , ( ) > ;
139
+
140
+ fn RootSet ( ) -> RootSet {
141
+ LinearMap( )
142
+ }
143
+
140
144
// This should only be called from fail, as it will drop the roots
141
145
// which are *live* on the stack, rather than dropping those that are
142
146
// dead.
143
147
fn cleanup_stack_for_failure( ) {
144
148
unsafe {
145
- let mut i = 0 ;
146
- do walk_gc_roots ( need_cleanup) |root, tydesc| {
149
+ let mut roots = ~RootSet( ) ;
150
+ for walk_gc_roots( need_cleanup) |root, tydesc| {
151
+ // Track roots to avoid double frees.
152
+ if option:: is_some( roots. find( & * root) ) {
153
+ again;
154
+ }
155
+ roots. insert( * root, ( ) ) ;
156
+
147
157
if ptr:: is_null ( tydesc) {
148
158
rustrt:: rust_annihilate_box ( * root) ;
149
159
} else {
150
160
rustrt:: rust_call_tydesc_glue ( * root, tydesc, 3 as size_t ) ;
151
161
}
152
- i += 1 ;
153
162
}
154
163
}
155
164
}
0 commit comments