Skip to content

Commit afcc179

Browse files
committed
Implement a DynTrace trait for object-safe tracing
This doesn't work well because it leaks the underlying visitor :(
1 parent 264224f commit afcc179

File tree

3 files changed

+44
-26
lines changed

3 files changed

+44
-26
lines changed

libs/derive/tests/basic.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ struct NopTrace {
3838
wow: Box<NopTrace>
3939
}
4040

41-
4241
#[test]
4342
fn basic() {
4443
let _b = Basic::<dummy::DummyCollectorId> {

libs/simple/src/lib.rs

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,12 @@ unsafe impl RawSimpleAlloc for RawSimpleCollector {
9494
}
9595
}
9696

97-
#[doc(hidden)] // NOTE: Needs be public for RawCollectorImpl
98-
pub unsafe trait DynTrace {
99-
fn trace(&mut self, visitor: &mut MarkVisitor);
100-
}
101-
unsafe impl<T: Trace + ?Sized> DynTrace for T {
102-
fn trace(&mut self, visitor: &mut MarkVisitor) {
103-
let Ok(()) = self.visit(visitor);
104-
}
105-
}
97+
/// A type alias for [::zerogc::DynTrace], which is an
98+
/// object-safe version of [::zerogc::Trace]
99+
///
100+
/// The `'static` lifetime is a lie and simply represents the
101+
/// fact the lifetime is unchecked.
102+
type DynTrace = dyn ::zerogc::DynTrace<MarkVisitor<'static>>;
106103

107104
unsafe impl RawHandleImpl for RawSimpleCollector {
108105
type TypeInfo = GcType;
@@ -118,13 +115,13 @@ unsafe impl RawHandleImpl for RawSimpleCollector {
118115
}
119116
}
120117

121-
/// A wrapper for [GcHandleList] that implements [DynTrace]
118+
/// A wrapper for [GcHandleList] that implements [::zerogc::DynTrace]
122119
#[repr(transparent)]
123120
struct GcHandleListWrapper(GcHandleList<RawSimpleCollector>);
124-
unsafe impl DynTrace for GcHandleListWrapper {
125-
fn trace(&mut self, visitor: &mut MarkVisitor) {
121+
unsafe impl<'a> ::zerogc::DynTrace<MarkVisitor<'a>> for GcHandleListWrapper {
122+
fn visit(&mut self, visitor: &mut MarkVisitor) -> Result<(), !> {
126123
unsafe {
127-
let Ok(()) = self.0.trace::<_, !>(|raw_ptr, type_info| {
124+
self.0.trace::<_, !>(|raw_ptr, type_info| {
128125
let header = &mut *GcHeader::from_value_ptr(raw_ptr, type_info);
129126
// Mark grey
130127
header.update_raw_state(MarkState::Grey.
@@ -135,7 +132,7 @@ unsafe impl DynTrace for GcHandleListWrapper {
135132
header.update_raw_state(MarkState::Black.
136133
to_raw(visitor.inverted_mark));
137134
Ok(())
138-
});
135+
})
139136
}
140137
}
141138
}
@@ -419,7 +416,7 @@ pub struct RawSimpleCollector {
419416
}
420417

421418
unsafe impl ::zerogc_context::collector::RawCollectorImpl for RawSimpleCollector {
422-
type GcDynPointer = NonNull<dyn DynTrace>;
419+
type GcDynPointer = NonNull<DynTrace>;
423420

424421
#[cfg(feature = "multiple-collectors")]
425422
type Ptr = NonNull<Self>;
@@ -440,9 +437,8 @@ unsafe impl ::zerogc_context::collector::RawCollectorImpl for RawSimpleCollector
440437
debug_assert!(!value.is_null());
441438
NonNull::new_unchecked(
442439
std::mem::transmute::<
443-
*mut dyn DynTrace,
444-
*mut (dyn DynTrace + 'static)
445-
>(value as *mut dyn DynTrace)
440+
_, *mut DynTrace
441+
>(value as *mut dyn ::zerogc::DynTrace<MarkVisitor>)
446442
)
447443
}
448444

@@ -553,7 +549,7 @@ impl RawSimpleCollector {
553549
&self, contexts: &[*mut RawContext<RawSimpleCollector>]
554550
) {
555551
debug_assert!(self.manager.is_collecting());
556-
let roots: Vec<*mut dyn DynTrace> = contexts.iter()
552+
let roots: Vec<*mut DynTrace> = contexts.iter()
557553
.flat_map(|ctx| {
558554
(**ctx).assume_valid_shadow_stack()
559555
.reverse_iter().map(NonNull::as_ptr)
@@ -562,8 +558,8 @@ impl RawSimpleCollector {
562558
// Cast to wrapper type
563559
as *const GcHandleList<Self> as *const GcHandleListWrapper
564560
// Make into virtual pointer
565-
as *const dyn DynTrace
566-
as *mut dyn DynTrace
561+
as *const DynTrace
562+
as *mut DynTrace
567563
))
568564
.collect();
569565
let num_roots = roots.len();
@@ -590,7 +586,7 @@ impl RawSimpleCollector {
590586
}
591587
struct CollectionTask<'a> {
592588
expected_collector: CollectorId,
593-
roots: Vec<*mut dyn DynTrace>,
589+
roots: Vec<*mut DynTrace>,
594590
heap: &'a GcHeap,
595591
#[cfg_attr(feature = "implicit-grey-stack", allow(dead_code))]
596592
grey_stack: Vec<*mut GcHeader>
@@ -604,8 +600,16 @@ impl<'a> CollectionTask<'a> {
604600
grey_stack: &mut self.grey_stack,
605601
inverted_mark: self.heap.allocator.mark_inverted()
606602
};
607-
// Dynamically dispatched
608-
unsafe { (*root).trace(&mut visitor); }
603+
unsafe {
604+
// Dynamically dispatched
605+
let Ok(()) = (*root).visit(
606+
// Ignore lifetime
607+
std::mem::transmute::<
608+
&mut MarkVisitor,
609+
&mut MarkVisitor<'static>
610+
>(&mut visitor)
611+
);
612+
}
609613
}
610614
#[cfg(not(feature = "implicit-grey-stack"))] unsafe {
611615
let was_inverted_mark = self.heap.allocator.mark_inverted();
@@ -788,7 +792,8 @@ impl<T: GcSafe> StaticGcType for T {
788792
value_size: std::mem::size_of::<T>(),
789793
value_offset: Self::VALUE_OFFSET,
790794
trace_func: unsafe { transmute::<_, unsafe fn(*mut c_void, &mut MarkVisitor)>(
791-
<T as DynTrace>::trace as fn(&mut T, &mut MarkVisitor),
795+
<T as ::zerogc::DynTrace<MarkVisitor<'static>>>::visit
796+
as fn(&mut T, &mut MarkVisitor<'static>) -> Result<(), !>,
792797
) },
793798
drop_func: if <T as GcSafe>::NEEDS_DROP {
794799
unsafe { Some(transmute::<_, unsafe fn(*mut c_void)>(

src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,20 @@ pub unsafe trait GcBrand<'new_gc, Id: CollectorId>: Trace {
783783
type Branded: Trace + 'new_gc;
784784
}
785785

786+
/// An object-safe version of the [Trace] trait
787+
pub unsafe trait DynTrace<V: GcVisitor> {
788+
/// Visit this object
789+
///
790+
/// See [Trace::visit] for more details
791+
fn visit(&mut self, visitor: &mut V) -> Result<(), V::Err>;
792+
}
793+
unsafe impl<T: Trace, V: GcVisitor> DynTrace<V> for T {
794+
#[inline]
795+
fn visit(&mut self, visitor: &mut V) -> Result<(), <V as GcVisitor>::Err> {
796+
<T as Trace>::visit(self, visitor)
797+
}
798+
}
799+
786800
/// Indicates that a type can be traced by a garbage collector.
787801
///
788802
/// This doesn't necessarily mean that the type is safe to allocate in a garbage collector ([GcSafe]).

0 commit comments

Comments
 (0)