1
1
//! Implementation of [::zerogc::GcHandle]
2
2
//!
3
3
//! Inspired by [Mono's Lock free Gc Handles](https://www.mono-project.com/news/2016/08/16/lock-free-gc-handles/)
4
- use core:: ptr:: { self , NonNull } ;
4
+ use core:: ptr:: { self , NonNull , Pointee } ;
5
+ use core:: mem;
5
6
use core:: marker:: PhantomData ;
6
7
use core:: sync:: atomic:: { self , AtomicPtr , AtomicUsize , Ordering } ;
7
8
8
9
use alloc:: boxed:: Box ;
9
10
use alloc:: vec:: Vec ;
10
11
11
- use zerogc:: { Trace , GcSafe , GcRebrand , GcVisitor , NullTrace , TraceImmutable , GcHandleSystem , GcBindHandle } ;
12
- use crate :: { Gc , WeakCollectorRef , CollectorId , CollectorContext , CollectorRef , CollectionManager } ;
12
+ use zerogc:: { GcRebrand , GcSafe , GcVisitor , HandleCollectorId , NullTrace , Trace , TraceImmutable , TrustedDrop } ;
13
+ use crate :: { Gc , WeakCollectorRef , CollectorId , CollectorRef , CollectionManager } ;
13
14
use crate :: collector:: RawCollectorImpl ;
14
15
15
16
const INITIAL_HANDLE_CAPACITY : usize = 64 ;
@@ -21,6 +22,10 @@ pub unsafe trait RawHandleImpl: RawCollectorImpl {
21
22
22
23
fn type_info_of < ' gc , T : GcSafe < ' gc , CollectorId < Self > > > ( ) -> & ' static Self :: TypeInfo ;
23
24
25
+ fn resolve_type_info < ' gc , T : ?Sized + GcSafe < ' gc , CollectorId < Self > > > (
26
+ gc : Gc < ' gc , T , CollectorId < Self > >
27
+ ) -> & ' static Self :: TypeInfo ;
28
+
24
29
fn handle_list ( & self ) -> & GcHandleList < Self > ;
25
30
}
26
31
@@ -397,24 +402,41 @@ impl<C: RawHandleImpl> GcRawHandle<C> {
397
402
trace ( value, type_info)
398
403
}
399
404
}
400
- pub struct GcHandle < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > {
405
+ pub struct GcHandle < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > {
401
406
inner : NonNull < GcRawHandle < C > > ,
402
407
collector : WeakCollectorRef < C > ,
408
+ /// The pointer metadata for the type.
409
+ ///
410
+ /// Assumed to be immutable
411
+ /// and not change
412
+ /// SAFETY:
413
+ /// 1. slices - Length never changes
414
+ /// 2. dyn pointers - Never needs
415
+ metadata : <T as Pointee >:: Metadata ,
403
416
marker : PhantomData < * mut T >
404
417
}
405
- impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > GcHandle < T , C > {
418
+ impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > GcHandle < T , C > {
406
419
#[ inline]
407
420
pub ( crate ) unsafe fn new (
408
421
inner : NonNull < GcRawHandle < C > > ,
409
- collector : WeakCollectorRef < C >
422
+ collector : WeakCollectorRef < C > ,
423
+ metadata : <T as Pointee >:: Metadata
410
424
) -> Self {
411
425
GcHandle {
412
- inner, collector,
426
+ inner, collector, metadata ,
413
427
marker : PhantomData
414
428
}
415
429
}
430
+ #[ inline]
431
+ unsafe fn assume_valid ( & self ) -> * mut T {
432
+ ptr:: from_raw_parts_mut (
433
+ self . inner . as_ref ( ) . value
434
+ . load ( Ordering :: Acquire ) as * mut ( ) ,
435
+ self . metadata
436
+ )
437
+ }
416
438
}
417
- unsafe impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > :: zerogc:: GcHandle < T > for GcHandle < T , C > {
439
+ unsafe impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > :: zerogc:: GcHandle < T > for GcHandle < T , C > {
418
440
type System = CollectorRef < C > ;
419
441
type Id = CollectorId < C > ;
420
442
@@ -430,19 +452,17 @@ unsafe impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> ::zerogc::GcHa
430
452
* since that could starve writers (collectors).
431
453
*/
432
454
C :: Manager :: prevent_collection ( collector. as_ref ( ) , || {
433
- let value = self . inner . as_ref ( ) . value
434
- . load ( Ordering :: Acquire ) as * mut T ;
455
+ let value = self . assume_valid ( ) ;
435
456
func ( & * value)
436
457
} )
437
458
} )
438
459
}
439
- }
440
- unsafe impl < ' new_gc , T , C > GcBindHandle < ' new_gc , T > for GcHandle < T , C >
441
- where T : GcSafe < ' static , CollectorId < C > > , T : GcRebrand < ' new_gc , CollectorId < C > > , T :: Branded : Sized ,
442
- T :: Branded : GcSafe < ' new_gc , CollectorId < C > > ,
443
- C : RawHandleImpl {
444
460
#[ inline]
445
- fn bind_to ( & self , context : & ' new_gc CollectorContext < C > ) -> Gc < ' new_gc , T :: Branded , CollectorId < C > > {
461
+ fn bind_to < ' new_gc > (
462
+ & self ,
463
+ context : & ' new_gc <Self :: System as zerogc:: GcSystem >:: Context
464
+ ) -> Gc < ' new_gc , <T as GcRebrand < ' new_gc , Self :: Id > >:: Branded , Self :: Id >
465
+ where T : GcRebrand < ' new_gc , Self :: Id > {
446
466
/*
447
467
* We can safely assume the object will
448
468
* be as valid as long as the context.
@@ -464,15 +484,20 @@ unsafe impl<'new_gc, T, C> GcBindHandle<'new_gc, T> for GcHandle<T, C>
464
484
"Collectors mismatch"
465
485
) ;
466
486
let inner = self . inner . as_ref ( ) ;
467
- let value = inner. value . load ( Ordering :: Acquire )
468
- as * mut T as * mut T :: Branded ;
487
+ /*
488
+ * NOTE: Can't use regular pointer-cast
489
+ * because of potentially mismatched vtables.
490
+ */
491
+ let value = crate :: utils:: transmute_mismatched :: <
492
+ * mut T ,
493
+ * mut T :: Branded
494
+ > ( self . assume_valid ( ) ) ;
469
495
debug_assert ! ( !value. is_null( ) ) ;
470
496
Gc :: from_raw ( NonNull :: new_unchecked ( value) )
471
497
}
472
498
}
473
-
474
499
}
475
- unsafe impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > Trace for GcHandle < T , C > {
500
+ unsafe impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > Trace for GcHandle < T , C > {
476
501
/// See docs on reachability
477
502
const NEEDS_TRACE : bool = false ;
478
503
const NEEDS_DROP : bool = true ;
@@ -489,15 +514,18 @@ unsafe impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> Trace for GcHa
489
514
visitor. trace_gc ( gc)
490
515
}
491
516
}
492
- unsafe impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > TraceImmutable for GcHandle < T , C > {
517
+ unsafe impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > TraceImmutable for GcHandle < T , C > {
493
518
#[ inline( always) ]
494
519
fn trace_immutable < V > ( & self , _visitor : & mut V ) -> Result < ( ) , V :: Err >
495
520
where V : GcVisitor {
496
521
Ok ( ( ) )
497
522
}
498
523
}
499
- unsafe impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > NullTrace for GcHandle < T , C > { }
500
- impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > Clone for GcHandle < T , C > {
524
+ unsafe impl < T : ?Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > NullTrace for GcHandle < T , C > { }
525
+ unsafe impl < ' gc , T : ?Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl >
526
+ GcSafe < ' gc , CollectorId < C > > for GcHandle < T , C > { }
527
+ unsafe impl < T : ?Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > TrustedDrop for GcHandle < T , C > { }
528
+ impl < T : ?Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > Clone for GcHandle < T , C > {
501
529
fn clone ( & self ) -> Self {
502
530
// NOTE: Dead collector -> invalid handle
503
531
let collector = self . collector
@@ -536,11 +564,12 @@ impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> Clone for GcHandle<T,
536
564
}
537
565
GcHandle {
538
566
inner : self . inner ,
567
+ metadata : self . metadata ,
539
568
collector, marker : PhantomData
540
569
}
541
570
}
542
571
}
543
- impl < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > Drop for GcHandle < T , C > {
572
+ impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > Drop for GcHandle < T , C > {
544
573
fn drop ( & mut self ) {
545
574
self . collector . try_ensure_valid ( |id| {
546
575
let collector = match id {
@@ -594,24 +623,23 @@ impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> Drop for GcHandle<T,
594
623
/// This is the same reason that `Arc<T>: Send` requires `T: Sync`
595
624
///
596
625
/// Requires that the collector is thread-safe.
597
- unsafe impl < T : GcSafe < ' static , CollectorId < C > > + Sync , C : RawHandleImpl + Sync > Send for GcHandle < T , C > { }
626
+ unsafe impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > + Sync , C : RawHandleImpl + Sync > Send for GcHandle < T , C > { }
598
627
599
628
/// If the underlying type is Sync,
600
629
/// it's safe to share garbage collected references between threads.
601
630
///
602
631
/// Requires that the collector is thread-safe.
603
- unsafe impl < T : GcSafe < ' static , CollectorId < C > > + Sync , C : RawHandleImpl + Sync > Sync for GcHandle < T , C > { }
632
+ unsafe impl < T : ? Sized + GcSafe < ' static , CollectorId < C > > + Sync , C : RawHandleImpl + Sync > Sync for GcHandle < T , C > { }
604
633
605
634
/// We support handles
606
- unsafe impl < ' gc , T , C > GcHandleSystem < ' gc , T > for CollectorRef < C >
607
- where C : RawHandleImpl ,
608
- T : GcSafe < ' gc , CollectorId < C > > ,
609
- T : GcRebrand < ' static , CollectorId < C > > ,
610
- T :: Branded : GcSafe < ' static , CollectorId < C > > + Sized {
611
- type Handle = GcHandle < T :: Branded , C > ;
635
+ unsafe impl < C > HandleCollectorId for CollectorId < C >
636
+ where C : RawHandleImpl {
637
+ type Handle < T : GcSafe < ' static , Self > + ?Sized > = GcHandle < T , C > ;
638
+
612
639
613
640
#[ inline]
614
- fn create_handle ( gc : Gc < ' gc , T , CollectorId < C > > ) -> Self :: Handle {
641
+ fn create_handle < ' gc , T > ( gc : Gc < ' gc , T , CollectorId < C > > ) -> Self :: Handle < T :: Branded >
642
+ where T : ?Sized + GcSafe < ' gc , Self > + GcRebrand < ' static , Self > , T :: Branded : GcSafe < ' static , Self > {
615
643
unsafe {
616
644
let collector = gc. collector_id ( ) ;
617
645
let value = gc. as_raw_ptr ( ) ;
@@ -623,14 +651,18 @@ unsafe impl<'gc, T, C> GcHandleSystem<'gc, T> for CollectorRef<C>
623
651
* the handle!!!
624
652
*/
625
653
raw. type_info . store (
626
- C :: type_info_of :: < T > ( )
654
+ C :: resolve_type_info ( gc )
627
655
as * const C :: TypeInfo
628
656
as * mut C :: TypeInfo ,
629
657
Ordering :: Release
630
658
) ;
631
659
raw. refcnt . store ( 1 , Ordering :: Release ) ;
632
660
let weak_collector = collector. weak_ref ( ) ;
633
- GcHandle :: new ( NonNull :: from ( raw) , weak_collector)
661
+ let metadata = crate :: utils:: transmute_mismatched :: <
662
+ <T as Pointee >:: Metadata ,
663
+ <T :: Branded as Pointee >:: Metadata
664
+ > ( ptr:: metadata ( value) ) ;
665
+ GcHandle :: new ( NonNull :: from ( raw) , weak_collector, metadata)
634
666
}
635
667
}
636
668
}
0 commit comments