@@ -6,7 +6,7 @@ use std::ptr::{self, NonNull};
6
6
struct GcState {
7
7
stats : GcStats ,
8
8
config : GcConfig ,
9
- boxes_start : Option < NonNull < GcBox < dyn Trace > > > ,
9
+ boxes_start : Cell < Option < NonNull < GcBox < dyn Trace > > > > ,
10
10
}
11
11
12
12
impl Drop for GcState {
@@ -42,7 +42,7 @@ pub fn finalizer_safe() -> bool {
42
42
thread_local ! ( static GC_STATE : RefCell <GcState > = RefCell :: new( GcState {
43
43
stats: Default :: default ( ) ,
44
44
config: Default :: default ( ) ,
45
- boxes_start: None ,
45
+ boxes_start: Cell :: new ( None ) ,
46
46
} ) ) ;
47
47
48
48
const MARK_MASK : usize = 1 << ( usize:: BITS - 1 ) ;
@@ -51,15 +51,15 @@ const ROOTS_MAX: usize = ROOTS_MASK; // max allowed value of roots
51
51
52
52
pub ( crate ) struct GcBoxHeader {
53
53
roots : Cell < usize > , // high bit is used as mark flag
54
- next : Option < NonNull < GcBox < dyn Trace > > > ,
54
+ next : Cell < Option < NonNull < GcBox < dyn Trace > > > > ,
55
55
}
56
56
57
57
impl GcBoxHeader {
58
58
#[ inline]
59
59
pub fn new ( next : Option < NonNull < GcBox < dyn Trace > > > ) -> Self {
60
60
GcBoxHeader {
61
61
roots : Cell :: new ( 1 ) , // unmarked and roots count = 1
62
- next,
62
+ next : Cell :: new ( next ) ,
63
63
}
64
64
}
65
65
@@ -137,7 +137,8 @@ impl<T: Trace> GcBox<T> {
137
137
data : value,
138
138
} ) ) ;
139
139
140
- st. boxes_start = Some ( unsafe { NonNull :: new_unchecked ( gcbox) } ) ;
140
+ st. boxes_start
141
+ . set ( Some ( unsafe { NonNull :: new_unchecked ( gcbox) } ) ) ;
141
142
142
143
// We allocated some bytes! Let's record it
143
144
st. stats . bytes_allocated += mem:: size_of :: < GcBox < T > > ( ) ;
@@ -176,6 +177,11 @@ impl<T: Trace + ?Sized> GcBox<T> {
176
177
self . header . dec_roots ( ) ;
177
178
}
178
179
180
+ /// Returns a pointer to the `GcBox`'s value, without dereferencing it.
181
+ pub ( crate ) fn value_ptr ( this : * const GcBox < T > ) -> * const T {
182
+ unsafe { ptr:: addr_of!( ( * this) . data) }
183
+ }
184
+
179
185
/// Returns a reference to the `GcBox`'s value.
180
186
pub ( crate ) fn value ( & self ) -> & T {
181
187
& self . data
@@ -186,26 +192,26 @@ impl<T: Trace + ?Sized> GcBox<T> {
186
192
fn collect_garbage ( st : & mut GcState ) {
187
193
st. stats . collections_performed += 1 ;
188
194
189
- struct Unmarked {
190
- incoming : * mut Option < NonNull < GcBox < dyn Trace > > > ,
195
+ struct Unmarked < ' a > {
196
+ incoming : & ' a Cell < Option < NonNull < GcBox < dyn Trace > > > > ,
191
197
this : NonNull < GcBox < dyn Trace > > ,
192
198
}
193
- unsafe fn mark ( head : & mut Option < NonNull < GcBox < dyn Trace > > > ) -> Vec < Unmarked > {
199
+ unsafe fn mark ( head : & Cell < Option < NonNull < GcBox < dyn Trace > > > > ) -> Vec < Unmarked < ' _ > > {
194
200
// Walk the tree, tracing and marking the nodes
195
- let mut mark_head = * head;
201
+ let mut mark_head = head. get ( ) ;
196
202
while let Some ( node) = mark_head {
197
203
if ( * node. as_ptr ( ) ) . header . roots ( ) > 0 {
198
204
( * node. as_ptr ( ) ) . trace_inner ( ) ;
199
205
}
200
206
201
- mark_head = ( * node. as_ptr ( ) ) . header . next ;
207
+ mark_head = ( * node. as_ptr ( ) ) . header . next . get ( ) ;
202
208
}
203
209
204
210
// Collect a vector of all of the nodes which were not marked,
205
211
// and unmark the ones which were.
206
212
let mut unmarked = Vec :: new ( ) ;
207
213
let mut unmark_head = head;
208
- while let Some ( node) = * unmark_head {
214
+ while let Some ( node) = unmark_head. get ( ) {
209
215
if ( * node. as_ptr ( ) ) . header . is_marked ( ) {
210
216
( * node. as_ptr ( ) ) . header . unmark ( ) ;
211
217
} else {
@@ -214,33 +220,33 @@ fn collect_garbage(st: &mut GcState) {
214
220
this : node,
215
221
} ) ;
216
222
}
217
- unmark_head = & mut ( * node. as_ptr ( ) ) . header . next ;
223
+ unmark_head = & ( * node. as_ptr ( ) ) . header . next ;
218
224
}
219
225
unmarked
220
226
}
221
227
222
- unsafe fn sweep ( finalized : Vec < Unmarked > , bytes_allocated : & mut usize ) {
228
+ unsafe fn sweep ( finalized : Vec < Unmarked < ' _ > > , bytes_allocated : & mut usize ) {
223
229
let _guard = DropGuard :: new ( ) ;
224
230
for node in finalized. into_iter ( ) . rev ( ) {
225
231
if ( * node. this . as_ptr ( ) ) . header . is_marked ( ) {
226
232
continue ;
227
233
}
228
234
let incoming = node. incoming ;
229
- let mut node = Box :: from_raw ( node. this . as_ptr ( ) ) ;
235
+ let node = Box :: from_raw ( node. this . as_ptr ( ) ) ;
230
236
* bytes_allocated -= mem:: size_of_val :: < GcBox < _ > > ( & * node) ;
231
- * incoming = node. header . next . take ( ) ;
237
+ incoming. set ( node. header . next . take ( ) ) ;
232
238
}
233
239
}
234
240
235
241
unsafe {
236
- let unmarked = mark ( & mut st. boxes_start ) ;
242
+ let unmarked = mark ( & st. boxes_start ) ;
237
243
if unmarked. is_empty ( ) {
238
244
return ;
239
245
}
240
246
for node in & unmarked {
241
247
Trace :: finalize_glue ( & ( * node. this . as_ptr ( ) ) . data ) ;
242
248
}
243
- mark ( & mut st. boxes_start ) ;
249
+ mark ( & st. boxes_start ) ;
244
250
sweep ( unmarked, & mut st. stats . bytes_allocated ) ;
245
251
}
246
252
}
0 commit comments