@@ -12,6 +12,7 @@ use std::fmt::{Debug, Formatter};
12
12
use std:: { fmt, mem} ;
13
13
use std:: collections:: HashSet ;
14
14
use parking_lot:: { Mutex , RwLockReadGuard , RwLockUpgradableReadGuard , RwLockWriteGuard } ;
15
+ use std:: ptr:: NonNull ;
15
16
16
17
#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
17
18
enum ContextState {
@@ -93,7 +94,7 @@ impl RawContext {
93
94
"original_thread" => original_thread. clone( )
94
95
) ) ,
95
96
shadow_stack : UnsafeCell :: new ( ShadowStack {
96
- elements : Vec :: with_capacity ( 4 )
97
+ last : std :: ptr :: null_mut ( ) ,
97
98
} ) ,
98
99
state : Cell :: new ( ContextState :: Active )
99
100
} ) ) ;
@@ -181,7 +182,7 @@ impl RawContext {
181
182
self . logger, "Awaiting collection" ;
182
183
"ptr" => ?ptr,
183
184
"current_thread" => FnValue ( |_| ThreadId :: current( ) ) ,
184
- "shadow_stack" => ? shadow_stack. elements ,
185
+ "shadow_stack" => FnValue ( |_| format! ( "{:?}" , shadow_stack. as_vec ( ) ) ) ,
185
186
"total_contexts" => pending. total_contexts,
186
187
"waiting_contexts" => pending. waiting_contexts,
187
188
"state" => ?pending. state,
@@ -260,7 +261,7 @@ impl RawContext {
260
261
* inside of RawContext that is not thread-safe.
261
262
*/
262
263
pub struct SimpleCollectorContext {
263
- raw : ManuallyDrop < Box < RawContext > > ,
264
+ raw : * mut RawContext ,
264
265
/// Whether we are the root context
265
266
///
266
267
/// Only the root actually owns the `Arc`
@@ -270,13 +271,44 @@ pub struct SimpleCollectorContext {
270
271
impl SimpleCollectorContext {
271
272
pub ( crate ) unsafe fn register_root ( collector : & SimpleCollector ) -> Self {
272
273
SimpleCollectorContext {
273
- raw : RawContext :: register_new ( & collector. 0 ) ,
274
+ raw : Box :: into_raw ( ManuallyDrop :: into_inner (
275
+ RawContext :: register_new ( & collector. 0 )
276
+ ) ) ,
274
277
root : true , // We are responsible for unregistering
275
278
}
276
279
}
277
280
#[ inline]
278
281
pub ( crate ) fn collector ( & self ) -> & RawSimpleCollector {
279
- & * self . raw . collector
282
+ unsafe { & ( * self . raw ) . collector }
283
+ }
284
+ #[ inline( always) ]
285
+ unsafe fn with_shadow_stack < R , T : Trace > (
286
+ & self , value : * mut & mut T , func : impl FnOnce ( ) -> R
287
+ ) -> R {
288
+ let old_link = ( * ( * self . raw ) . shadow_stack . get ( ) ) . last ;
289
+ let new_link = ShadowStackLink {
290
+ element : NonNull :: new_unchecked (
291
+ std:: mem:: transmute :: <
292
+ * mut dyn DynTrace ,
293
+ * mut ( dyn DynTrace + ' static )
294
+ > ( value as * mut dyn DynTrace )
295
+ ) ,
296
+ prev : old_link
297
+ } ;
298
+ ( * ( * self . raw ) . shadow_stack . get ( ) ) . last = & new_link;
299
+ let result = func ( ) ;
300
+ debug_assert_eq ! (
301
+ ( * ( * self . raw) . shadow_stack. get( ) ) . last,
302
+ & new_link
303
+ ) ;
304
+ ( * ( * self . raw ) . shadow_stack . get ( ) ) . last = new_link. prev ;
305
+ result
306
+ }
307
+ #[ cold]
308
+ unsafe fn trigger_basic_safepoint < T : Trace > ( & self , element : & mut & mut T ) {
309
+ self . with_shadow_stack ( element, || {
310
+ ( * self . raw ) . trigger_safepoint ( ) ;
311
+ } )
280
312
}
281
313
}
282
314
impl Drop for SimpleCollectorContext {
@@ -287,13 +319,13 @@ impl Drop for SimpleCollectorContext {
287
319
unsafe {
288
320
trace ! (
289
321
collector. logger, "Freeing context" ;
290
- "ptr" => format_args!( "{:p}" , & * * self . raw) ,
322
+ "ptr" => format_args!( "{:p}" , self . raw) ,
291
323
"current_thread" => FnValue ( |_| ThreadId :: current( ) ) ,
292
- "state" => ?self . raw. state. get( )
324
+ "state" => ?( * self . raw) . state. get( )
293
325
) ;
294
- collector. free_context (
295
- std :: ptr :: read ( & self . raw )
296
- )
326
+ collector. free_context ( ManuallyDrop :: new (
327
+ Box :: from_raw ( self . raw )
328
+ ) ) ;
297
329
}
298
330
}
299
331
}
@@ -303,28 +335,23 @@ unsafe impl GcContext for SimpleCollectorContext {
303
335
304
336
#[ inline]
305
337
unsafe fn basic_safepoint < T : Trace > ( & mut self , value : & mut & mut T ) {
306
- debug_assert_eq ! ( self . raw. state. get( ) , ContextState :: Active ) ;
307
- let dyn_ptr = ( * self . raw . shadow_stack . get ( ) )
308
- . push ( value) ;
309
- if self . raw . collector . should_collect_relaxed ( ) {
310
- self . raw . trigger_safepoint ( ) ;
338
+ debug_assert_eq ! ( ( * self . raw) . state. get( ) , ContextState :: Active ) ;
339
+ if ( * self . raw ) . collector . should_collect_relaxed ( ) {
340
+ self . trigger_basic_safepoint ( value) ;
311
341
}
312
- debug_assert_eq ! ( self . raw. state. get( ) , ContextState :: Active ) ;
313
- let popped = ( * self . raw . shadow_stack . get ( ) )
314
- . pop_unchecked ( ) ;
315
- debug_assert_eq ! ( popped, dyn_ptr) ;
342
+ debug_assert_eq ! ( ( * self . raw) . state. get( ) , ContextState :: Active ) ;
316
343
}
317
344
318
345
unsafe fn freeze ( & mut self ) {
319
- assert_eq ! ( self . raw. state. get( ) , ContextState :: Active ) ;
346
+ assert_eq ! ( ( * self . raw) . state. get( ) , ContextState :: Active ) ;
320
347
// TODO: Isn't this state read concurrently?
321
- self . raw . state . set ( ContextState :: Frozen ) ;
348
+ ( * self . raw ) . state . set ( ContextState :: Frozen ) ;
322
349
/*
323
350
* We may need to notify others that we are frozen
324
351
* This means we are now "valid" for the purposes of
325
352
* collection ^_^
326
353
*/
327
- self . raw . collector . valid_contexts_wait . notify_all ( ) ;
354
+ ( * self . raw ) . collector . valid_contexts_wait . notify_all ( ) ;
328
355
}
329
356
330
357
unsafe fn unfreeze ( & mut self ) {
@@ -334,35 +361,32 @@ unsafe impl GcContext for SimpleCollectorContext {
334
361
* could trigger undefined behavior!!!!!
335
362
*/
336
363
self . collector ( ) . prevent_collection ( |_| {
337
- assert_eq ! ( self . raw. state. get( ) , ContextState :: Frozen ) ;
338
- self . raw . state . set ( ContextState :: Active ) ;
364
+ assert_eq ! ( ( * self . raw) . state. get( ) , ContextState :: Frozen ) ;
365
+ ( * self . raw ) . state . set ( ContextState :: Active ) ;
339
366
} )
340
367
}
341
368
342
369
#[ inline]
343
370
unsafe fn recurse_context < T , F , R > ( & self , value : & mut & mut T , func : F ) -> R
344
371
where T : Trace , F : for < ' gc > FnOnce ( & ' gc mut Self , & ' gc mut T ) -> R {
345
- debug_assert_eq ! ( self . raw. state. get( ) , ContextState :: Active ) ;
346
- let dyn_ptr = ( * self . raw . shadow_stack . get ( ) )
347
- . push ( value) ;
348
- let mut sub_context = SimpleCollectorContext {
349
- /*
350
- * safe to copy because we wont drop it
351
- * Lifetime is guarenteed to be restricted to
352
- * the closure.
353
- */
354
- raw : std:: ptr:: read ( & self . raw ) ,
355
- root : false /* don't drop our pointer!!! */
356
- } ;
357
- let result = func ( & mut sub_context, value) ;
358
- debug_assert ! ( !sub_context. root) ;
359
- // Since we're not the root, no need to run drop code!
360
- std:: mem:: forget ( sub_context) ;
361
- debug_assert_eq ! ( self . raw. state. get( ) , ContextState :: Active ) ;
362
- let actual_ptr = ( * self . raw . shadow_stack . get ( ) )
363
- . pop_unchecked ( ) ;
364
- debug_assert_eq ! ( actual_ptr, dyn_ptr) ;
365
- result
372
+ debug_assert_eq ! ( ( * self . raw) . state. get( ) , ContextState :: Active ) ;
373
+ self . with_shadow_stack ( value, || {
374
+ let mut sub_context = ManuallyDrop :: new ( SimpleCollectorContext {
375
+ /*
376
+ * safe to copy because we wont drop it
377
+ * Lifetime is guarenteed to be restricted to
378
+ * the closure.
379
+ */
380
+ raw : self . raw ,
381
+ root : false /* don't drop our pointer!!! */
382
+ } ) ;
383
+ let result = func ( & mut * sub_context, value) ;
384
+ debug_assert ! ( !sub_context. root) ;
385
+ // No need to run drop code on context.....
386
+ std:: mem:: forget ( sub_context) ;
387
+ debug_assert_eq ! ( ( * self . raw) . state. get( ) , ContextState :: Active ) ;
388
+ result
389
+ } )
366
390
}
367
391
}
368
392
@@ -379,40 +403,33 @@ impl !Send for SimpleCollectorContext {}
379
403
// Root tracking
380
404
//
381
405
406
+ #[ repr( C ) ]
407
+ #[ derive( Debug ) ]
408
+ pub ( crate ) struct ShadowStackLink {
409
+ pub element : NonNull < dyn DynTrace > ,
410
+ /// The previous link in the chain,
411
+ /// or NULL if there isn't any
412
+ pub prev : * const ShadowStackLink
413
+ }
414
+
382
415
#[ derive( Clone , Debug ) ]
383
416
pub struct ShadowStack {
384
- pub ( crate ) elements : Vec < * mut dyn DynTrace >
417
+ /// The last element in the shadow stack,
418
+ /// or NULL if it's empty
419
+ pub ( crate ) last : * const ShadowStackLink
385
420
}
386
421
impl ShadowStack {
387
- #[ inline]
388
- pub ( crate ) unsafe fn push < ' a , T : Trace + ' a > ( & mut self , value : & ' a mut T ) -> * mut dyn DynTrace {
389
- let short_ptr = value as & mut ( dyn DynTrace + ' a )
390
- as * mut ( dyn DynTrace + ' a ) ;
391
- let long_ptr = std:: mem:: transmute :: <
392
- * mut ( dyn DynTrace + ' a ) ,
393
- * mut ( dyn DynTrace + ' static )
394
- > ( short_ptr) ;
395
- self . elements . push ( long_ptr) ;
396
- long_ptr
422
+ unsafe fn as_vec ( & self ) -> Vec < * mut dyn DynTrace > {
423
+ let mut result: Vec < _ > = self . reverse_iter ( ) . collect ( ) ;
424
+ result. reverse ( ) ;
425
+ result
397
426
}
398
427
#[ inline]
399
- pub ( crate ) unsafe fn pop_unchecked ( & mut self ) -> * mut dyn DynTrace {
400
- match self . elements . pop ( ) {
401
- Some ( value) => value,
402
- None => {
403
- #[ cfg( debug_assertions) ] {
404
- /*
405
- * In debug mode we'd rather panic than
406
- * trigger undefined behavior.
407
- */
408
- unreachable ! ( )
409
- }
410
- #[ cfg( not( debug_assertions) ) ] {
411
- // Hint to optimizer we consider this impossible
412
- std:: hint:: unreachable_unchecked ( )
413
- }
414
- }
415
- }
428
+ pub ( crate ) unsafe fn reverse_iter ( & self ) -> impl Iterator < Item =* mut dyn DynTrace > + ' _ {
429
+ std:: iter:: successors (
430
+ self . last . as_ref ( ) ,
431
+ |link| link. prev . as_ref ( )
432
+ ) . map ( |link| link. element . as_ptr ( ) )
416
433
}
417
434
}
418
435
0 commit comments