11//! Implementation of [::zerogc::GcHandle]
22//!
33//! 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;
56use core:: marker:: PhantomData ;
67use core:: sync:: atomic:: { self , AtomicPtr , AtomicUsize , Ordering } ;
78
89use alloc:: boxed:: Box ;
910use alloc:: vec:: Vec ;
1011
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 } ;
1314use crate :: collector:: RawCollectorImpl ;
1415
1516const INITIAL_HANDLE_CAPACITY : usize = 64 ;
@@ -21,6 +22,10 @@ pub unsafe trait RawHandleImpl: RawCollectorImpl {
2122
2223 fn type_info_of < ' gc , T : GcSafe < ' gc , CollectorId < Self > > > ( ) -> & ' static Self :: TypeInfo ;
2324
25+ fn resolve_type_info < ' gc , T : ?Sized + GcSafe < ' gc , CollectorId < Self > > > (
26+ gc : Gc < ' gc , T , CollectorId < Self > >
27+ ) -> & ' static Self :: TypeInfo ;
28+
2429 fn handle_list ( & self ) -> & GcHandleList < Self > ;
2530}
2631
@@ -397,24 +402,41 @@ impl<C: RawHandleImpl> GcRawHandle<C> {
397402 trace ( value, type_info)
398403 }
399404}
400- pub struct GcHandle < T : GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > {
405+ pub struct GcHandle < T : ? Sized + GcSafe < ' static , CollectorId < C > > , C : RawHandleImpl > {
401406 inner : NonNull < GcRawHandle < C > > ,
402407 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 ,
403416 marker : PhantomData < * mut T >
404417}
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 > {
406419 #[ inline]
407420 pub ( crate ) unsafe fn new (
408421 inner : NonNull < GcRawHandle < C > > ,
409- collector : WeakCollectorRef < C >
422+ collector : WeakCollectorRef < C > ,
423+ metadata : <T as Pointee >:: Metadata
410424 ) -> Self {
411425 GcHandle {
412- inner, collector,
426+ inner, collector, metadata ,
413427 marker : PhantomData
414428 }
415429 }
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+ }
416438}
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 > {
418440 type System = CollectorRef < C > ;
419441 type Id = CollectorId < C > ;
420442
@@ -430,19 +452,17 @@ unsafe impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> ::zerogc::GcHa
430452 * since that could starve writers (collectors).
431453 */
432454 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 ( ) ;
435456 func ( & * value)
436457 } )
437458 } )
438459 }
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 {
444460 #[ 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 > {
446466 /*
447467 * We can safely assume the object will
448468 * 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>
464484 "Collectors mismatch"
465485 ) ;
466486 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 ( ) ) ;
469495 debug_assert ! ( !value. is_null( ) ) ;
470496 Gc :: from_raw ( NonNull :: new_unchecked ( value) )
471497 }
472498 }
473-
474499}
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 > {
476501 /// See docs on reachability
477502 const NEEDS_TRACE : bool = false ;
478503 const NEEDS_DROP : bool = true ;
@@ -489,15 +514,18 @@ unsafe impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> Trace for GcHa
489514 visitor. trace_gc ( gc)
490515 }
491516}
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 > {
493518 #[ inline( always) ]
494519 fn trace_immutable < V > ( & self , _visitor : & mut V ) -> Result < ( ) , V :: Err >
495520 where V : GcVisitor {
496521 Ok ( ( ) )
497522 }
498523}
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 > {
501529 fn clone ( & self ) -> Self {
502530 // NOTE: Dead collector -> invalid handle
503531 let collector = self . collector
@@ -536,11 +564,12 @@ impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> Clone for GcHandle<T,
536564 }
537565 GcHandle {
538566 inner : self . inner ,
567+ metadata : self . metadata ,
539568 collector, marker : PhantomData
540569 }
541570 }
542571}
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 > {
544573 fn drop ( & mut self ) {
545574 self . collector . try_ensure_valid ( |id| {
546575 let collector = match id {
@@ -594,24 +623,23 @@ impl<T: GcSafe<'static, CollectorId<C>>, C: RawHandleImpl> Drop for GcHandle<T,
594623/// This is the same reason that `Arc<T>: Send` requires `T: Sync`
595624///
596625/// 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 > { }
598627
599628/// If the underlying type is Sync,
600629/// it's safe to share garbage collected references between threads.
601630///
602631/// 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 > { }
604633
605634/// 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+
612639
613640 #[ 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 > {
615643 unsafe {
616644 let collector = gc. collector_id ( ) ;
617645 let value = gc. as_raw_ptr ( ) ;
@@ -623,14 +651,18 @@ unsafe impl<'gc, T, C> GcHandleSystem<'gc, T> for CollectorRef<C>
623651 * the handle!!!
624652 */
625653 raw. type_info . store (
626- C :: type_info_of :: < T > ( )
654+ C :: resolve_type_info ( gc )
627655 as * const C :: TypeInfo
628656 as * mut C :: TypeInfo ,
629657 Ordering :: Release
630658 ) ;
631659 raw. refcnt . store ( 1 , Ordering :: Release ) ;
632660 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)
634666 }
635667 }
636668}
0 commit comments