Skip to content

Commit d2ab662

Browse files
committed
Make GcRef a trait once again
1 parent f4d4b7e commit d2ab662

File tree

12 files changed

+308
-237
lines changed

12 files changed

+308
-237
lines changed

libs/context/src/collector.rs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use alloc::sync::Arc;
88

99
use slog::{Logger, o};
1010

11-
use zerogc::{Gc, GcSafe, GcSystem, Trace, GcSimpleAlloc, NullTrace, TraceImmutable, GcVisitor};
11+
use zerogc::{GcRef, GcSafe, GcSystem, Trace, GcSimpleAlloc, NullTrace, TraceImmutable, GcVisitor};
1212

1313
use crate::{CollectorContext};
1414
use crate::state::{CollectionManager, RawContext};
@@ -54,11 +54,7 @@ pub unsafe trait RawCollectorImpl: 'static + Sized {
5454
fn id(&self) -> CollectorId<Self> {
5555
CollectorId { ptr: unsafe { Self::Ptr::from_raw(self as *const _ as *mut _) } }
5656
}
57-
unsafe fn gc_write_barrier<'gc, T, V>(
58-
owner: &Gc<'gc, T, CollectorId<Self>>,
59-
value: &Gc<'gc, V, CollectorId<Self>>,
60-
field_offset: usize
61-
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc;
57+
6258
/// The logger associated with this collector
6359
fn logger(&self) -> &Logger;
6460

@@ -276,15 +272,6 @@ impl<C: RawCollectorImpl> CollectorId<C> {
276272
unsafe impl<C: RawCollectorImpl> ::zerogc::CollectorId for CollectorId<C> {
277273
type System = CollectorRef<C>;
278274

279-
#[inline(always)]
280-
unsafe fn gc_write_barrier<'gc, T, V>(
281-
owner: &Gc<'gc, T, Self>,
282-
value: &Gc<'gc, V, Self>,
283-
field_offset: usize
284-
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
285-
C::gc_write_barrier(owner, value, field_offset)
286-
}
287-
288275
#[inline]
289276
unsafe fn assume_valid_system(&self) -> &Self::System {
290277
// TODO: Make the API nicer? (avoid borrowing and indirection)
@@ -330,13 +317,21 @@ impl<C: RawCollectorImpl> WeakCollectorRef<C> {
330317
}
331318
}
332319

333-
pub unsafe trait RawSimpleAlloc: RawCollectorImpl {
334-
fn alloc<'gc, T: GcSafe + 'gc>(context: &'gc CollectorContext<Self>, value: T) -> Gc<'gc, T, CollectorId<Self>>;
320+
pub unsafe trait RawSimpleAlloc<'gc, T>: RawCollectorImpl
321+
where T: GcSafe + 'gc {
322+
/// The type of GC references that are returned
323+
type Gc: GcRef<'gc, T, Id=CollectorId<Self>>;
324+
/// Allocate a new garbage collected reference
325+
fn alloc(
326+
context: &'gc CollectorContext<Self>,
327+
value: T
328+
) -> Self::Gc;
335329
}
336330
unsafe impl<'gc, T, C> GcSimpleAlloc<'gc, T> for CollectorContext<C>
337-
where T: GcSafe + 'gc, C: RawSimpleAlloc {
331+
where T: GcSafe + 'gc, C: RawSimpleAlloc<'gc, T> {
332+
type Gc = C::Gc;
338333
#[inline]
339-
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id> {
334+
fn alloc(&'gc self, value: T) -> C::Gc {
340335
C::alloc(self, value)
341336
}
342337
}

libs/context/src/handle.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use alloc::boxed::Box;
99
use alloc::vec::Vec;
1010

1111
use zerogc::{Trace, GcSafe, GcErase, GcRebrand, GcVisitor, NullTrace, TraceImmutable, GcHandleSystem, GcBindHandle};
12-
use crate::{Gc, WeakCollectorRef, CollectorId, CollectorContext, CollectorRef, CollectionManager};
12+
use crate::{GcRef, WeakCollectorRef, CollectorId, CollectorContext, CollectorRef, CollectionManager};
1313
use crate::collector::RawCollectorImpl;
1414

1515
const INITIAL_HANDLE_CAPACITY: usize = 64;
@@ -23,6 +23,13 @@ pub unsafe trait RawHandleImpl: RawCollectorImpl {
2323

2424
fn handle_list(&self) -> &GcHandleList<Self>;
2525
}
26+
/// A type hack on [RawHandleImpl] to get the associated type
27+
/// of [::zerogc::GcRef]
28+
///
29+
/// This is needed because we don't have generic associated types (yet)
30+
pub trait RawHandleImplHack<'gc, T: GcSafe + 'gc>: RawHandleImpl {
31+
type Gc: GcRef<'gc, T, Id=CollectorId<Self>>;
32+
}
2633

2734
/// Concurrent list of [GcHandle]s
2835
///
@@ -438,9 +445,10 @@ unsafe impl<T: GcSafe, C: RawHandleImpl> ::zerogc::GcHandle<T> for GcHandle<T, C
438445
}
439446
unsafe impl<'new_gc, T, C> GcBindHandle<'new_gc, T> for GcHandle<T, C>
440447
where T: GcSafe, T: GcRebrand<'new_gc, CollectorId<C>>,
441-
T::Branded: GcSafe, C: RawHandleImpl {
448+
T::Branded: GcSafe, C: RawHandleImplHack<'new_gc, T::Branded> {
449+
type Gc = C::Gc;
442450
#[inline]
443-
fn bind_to(&self, context: &'new_gc CollectorContext<C>) -> Gc<'new_gc, T::Branded, CollectorId<C>> {
451+
fn bind_to(&self, context: &'new_gc CollectorContext<C>) -> Self::Gc {
444452
/*
445453
* We can safely assume the object will
446454
* be as valid as long as the context.
@@ -465,7 +473,7 @@ unsafe impl<'new_gc, T, C> GcBindHandle<'new_gc, T> for GcHandle<T, C>
465473
let value = inner.value.load(Ordering::Acquire)
466474
as *mut T as *mut T::Branded;
467475
debug_assert!(!value.is_null());
468-
Gc::from_raw(
476+
Self::Gc::from_raw(
469477
collector,
470478
NonNull::new_unchecked(value)
471479
)
@@ -597,14 +605,15 @@ unsafe impl<T: GcSafe + Sync, C: RawHandleImpl + Sync> Sync for GcHandle<T, C> {
597605

598606
/// We support handles
599607
unsafe impl<'gc, 'a, T, C> GcHandleSystem<'gc, 'a, T> for CollectorRef<C>
600-
where C: RawHandleImpl,
608+
where C: RawHandleImplHack<'gc, T>,
601609
T: GcSafe + 'gc,
602610
T: GcErase<'a, CollectorId<C>>,
603611
T::Erased: GcSafe {
612+
type Gc = C::Gc;
604613
type Handle = GcHandle<T::Erased, C>;
605614

606615
#[inline]
607-
fn create_handle(gc: Gc<'gc, T, CollectorId<C>>) -> Self::Handle {
616+
fn create_handle(gc: Self::Gc) -> Self::Handle {
608617
unsafe {
609618
let collector = gc.collector_id();
610619
let value = gc.as_raw_ptr();

libs/context/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use alloc::vec::Vec;
2828
use zerogc::prelude::*;
2929

3030
pub mod state;
31-
3231
pub mod utils;
3332
pub mod collector;
3433
pub mod handle;

libs/derive/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -601,9 +601,9 @@ fn impl_extras(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, E
601601
let barrier = quote_spanned!(field.span() => #zerogc_crate::GcDirectBarrier::write_barrier(&value, &self, offset));
602602
extra_items.push(quote! {
603603
#[inline] // TODO: Implement `GcDirectBarrier` ourselves
604-
#mutator_vis fn #mutator_name<Id>(self: #zerogc_crate::Gc<#gc_lifetime, Self, Id>, value: #value_ref_type)
605-
where Id: #zerogc_crate::CollectorId,
606-
#value_ref_type: #zerogc_crate::GcDirectBarrier<#gc_lifetime, #zerogc_crate::Gc<#gc_lifetime, Self, Id>> {
604+
#mutator_vis fn #mutator_name<G>(self: G, value: #value_ref_type)
605+
where G: #zerogc_crate::GcRef<#gc_lifetime, Self>,
606+
#value_ref_type: #zerogc_crate::GcDirectBarrier<#gc_lifetime, G> {
607607
unsafe {
608608
let target_ptr = #field_as_ptr;
609609
let offset = target_ptr as usize - self.as_raw_ptr() as usize;

libs/simple/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ zerogc = { path = "../..", version = "0.2.0-alpha.2" }
1313
once_cell = { version = "1.5", optional = true }
1414
# Shared impl
1515
zerogc-context = { path = "../context", version = "0.2.0-alpha.2", default-features = false }
16+
zerogc-derive = { path = "../derive", version = "0.2.0-alpha.2" }
1617
# Concurrency
1718
parking_lot = { version = "0.11", optional = true }
1819
# Logging

libs/simple/examples/binary_trees.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ fn main() {
6969

7070
let long_lived_tree = bottom_up_tree(&gc, max_depth);
7171

72-
let (long_lived_tree, ()) = safepoint_recurse!(gc, long_lived_tree, |gc, long_lived_tree| {
72+
let (long_lived_tree, ()) = safepoint_recurse!(gc, long_lived_tree, |gc, _long_lived_tree| {
7373
(min_depth / 2..max_depth / 2 + 1).into_iter().for_each(|half_depth| {
7474
let depth = half_depth * 2;
7575
let iterations = 1 << ((max_depth - depth + min_depth) as u32);

libs/simple/src/gc.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//! Our specific implementation of [::zerogc::GcRef]
2+
3+
use std::marker::PhantomData;
4+
use std::ptr::NonNull;
5+
use std::hash::{Hash, Hasher};
6+
7+
use zerogc::prelude::*;
8+
use zerogc_derive::unsafe_gc_impl;
9+
10+
use super::CollectorId as SimpleCollectorId;
11+
12+
/// A garbage collected smart pointer
13+
///
14+
/// This is safely copyable. It can be freely
15+
/// dereferenced and is guarenteed to live
16+
/// until the next [safepoint](::zerogc::safepoint!)
17+
#[repr(C)]
18+
pub struct Gc<'gc, T: GcSafe + 'gc> {
19+
ptr: NonNull<T>,
20+
id: SimpleCollectorId,
21+
marker: PhantomData<&'gc T>
22+
}
23+
impl<'gc, T: GcSafe + 'gc> Gc<'gc, T> {
24+
/// The value of the pointer
25+
///
26+
/// This is the same as [GcRef::value](::zerogc::GcRef::value)
27+
/// but is available as an inherent method for convenience.
28+
#[inline(always)]
29+
pub fn value(&self) -> &'gc T {
30+
unsafe { &*(&self.ptr as *const NonNull<T> as *const &T) }
31+
}
32+
}
33+
unsafe impl<'gc, T: GcSafe + 'gc> GcRef<'gc, T> for Gc<'gc, T> {
34+
type Id = SimpleCollectorId;
35+
#[inline(always)]
36+
fn collector_id(&self) -> Self::Id {
37+
self.id
38+
}
39+
#[inline(always)]
40+
unsafe fn from_raw(id: SimpleCollectorId, ptr: NonNull<T>) -> Self {
41+
Gc { ptr, id, marker: PhantomData }
42+
}
43+
#[inline(always)]
44+
fn value(&self) -> &'gc T {
45+
unsafe { &*(&self.ptr as *const NonNull<T> as *const &T) }
46+
}
47+
#[inline]
48+
unsafe fn as_raw_ptr(&self) -> *mut T {
49+
self.ptr.as_ptr()
50+
}
51+
#[inline(always)]
52+
fn system(&self) -> &'_ <Self::Id as CollectorId>::System {
53+
// This assumption is safe - see the docs
54+
unsafe { self.id.assume_valid_system() }
55+
}
56+
}
57+
unsafe impl<'gc, O, V> ::zerogc::GcDirectBarrier<'gc, Gc<'gc, O>> for Gc<'gc, V>
58+
where O: GcSafe + 'gc, V: GcSafe + 'gc {
59+
#[inline(always)]
60+
unsafe fn write_barrier(&self, _owner: &Gc<'gc, O>, _field_offset: usize) {
61+
// This is a NOP
62+
}
63+
}
64+
impl<'gc, T: GcSafe + 'gc> Copy for Gc<'gc, T> {}
65+
impl<'gc, T: GcSafe + 'gc> Clone for Gc<'gc, T> {
66+
#[inline(always)]
67+
fn clone(&self) -> Self {
68+
*self
69+
}
70+
}
71+
unsafe_gc_impl!(
72+
target => Gc<'gc, T>,
73+
params => ['gc, T: GcSafe + 'gc],
74+
null_trace => never,
75+
bounds => {
76+
TraceImmutable => never,
77+
GcRebrand => { where T: GcRebrand<'new_gc, Id>, T::Branded: GcSafe },
78+
GcErase => { where T: GcErase<'min, Id>, T::Erased: GcSafe }
79+
},
80+
branded_type => Gc<'new_gc, T::Branded>,
81+
erased_type => Gc<'min, T::Erased>,
82+
NEEDS_TRACE => true, // We're the whole point
83+
NEEDS_DROP => false, // Copy
84+
trace_mut => |self, visitor| {
85+
unsafe { visitor.visit_gc(self) }
86+
}
87+
);
88+
impl<'gc, T: GcSafe +'gc> std::ops::Deref for Gc<'gc, T> {
89+
type Target = &'gc T;
90+
#[inline(always)]
91+
fn deref(&self) -> &&'gc T {
92+
unsafe { &*(&self.ptr as *const NonNull<T> as *const &T) }
93+
}
94+
}
95+
96+
impl<'gc, T> PartialEq for Gc<'gc, T>
97+
where T: GcSafe + PartialEq + 'gc {
98+
#[inline]
99+
fn eq(&self, other: &Self) -> bool {
100+
*self.value() == *other.value()
101+
}
102+
}
103+
impl<'gc, T> PartialEq<T> for Gc<'gc, T>
104+
where T: GcSafe + PartialEq<T> + 'gc {
105+
#[inline]
106+
fn eq(&self, other: &T) -> bool {
107+
*self.value() == *other
108+
}
109+
}
110+
impl<'gc, T: GcSafe + Eq + 'gc> Eq for Gc<'gc, T> {}
111+
112+
impl<'gc, T> Hash for Gc<'gc, T> where T: GcSafe + Hash + 'gc {
113+
#[inline]
114+
fn hash<H: Hasher>(&self, hasher: &mut H) {
115+
T::hash(self.value(), hasher)
116+
}
117+
}
118+
119+
120+
/// In order to send *references* between threads,
121+
/// the underlying type must be sync.
122+
///
123+
/// This is the same reason that `Arc<T>: Send` requires `T: Sync`
124+
#[cfg(feature = "sync")]
125+
unsafe impl<'gc, T> Send for Gc<'gc, T>
126+
where T: GcSafe + Sync {}
127+
128+
/// If the underlying type is `Sync`, it's safe
129+
/// to share garbage collected references between threads.
130+
///
131+
/// The safety of the collector itself depends on the flag `cfg!(feature = "sync")`
132+
/// If it is, the whole garbage collection implenentation should be as well.
133+
#[cfg(feature = "sync")]
134+
unsafe impl<'gc, T> Sync for Gc<'gc, T>
135+
where T: GcSafe + Sync {}

libs/simple/src/lib.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ use std::any::TypeId;
3131

3232
use slog::{Logger, FnValue, debug};
3333

34-
use zerogc::{GcSafe, Trace, GcVisitor};
34+
use zerogc::{GcSafe, Trace, GcVisitor, GcRef};
3535

3636
use zerogc_context::utils::{ThreadId, AtomicCell, MemorySize};
3737

3838
use crate::alloc::{SmallArenaList, small_object_size};
3939

4040
use zerogc_context::collector::{RawSimpleAlloc};
41-
use zerogc_context::handle::{GcHandleList, RawHandleImpl};
41+
use zerogc_context::handle::{GcHandleList, RawHandleImpl, RawHandleImplHack};
4242
use zerogc_context::{
4343
CollectionManager as AbstractCollectionManager,
4444
RawContext as AbstractRawContext
@@ -67,6 +67,9 @@ mod alloc {
6767
pub fn find<T>(&self) -> Option<FakeArena> { None }
6868
}
6969
}
70+
mod gc;
71+
72+
pub use self::gc::Gc;
7073

7174
#[cfg(feature = "sync")]
7275
type RawContext<C> = zerogc_context::state::sync::RawContext<C>;
@@ -81,14 +84,14 @@ type CollectionManager<C> = zerogc_context::state::nosync::CollectionManager<C>;
8184
pub type SimpleCollector = ::zerogc_context::CollectorRef<RawSimpleCollector>;
8285
pub type SimpleCollectorContext = ::zerogc_context::CollectorContext<RawSimpleCollector>;
8386
pub type CollectorId = ::zerogc_context::CollectorId<RawSimpleCollector>;
84-
pub type Gc<'gc, T> = ::zerogc::Gc<'gc, T, CollectorId>;
8587

8688
#[cfg(not(feature = "multiple-collectors"))]
8789
static GLOBAL_COLLECTOR: AtomicPtr<RawSimpleCollector> = AtomicPtr::new(std::ptr::null_mut());
8890

89-
unsafe impl RawSimpleAlloc for RawSimpleCollector {
91+
unsafe impl<'gc, T: GcSafe + 'gc> RawSimpleAlloc<'gc, T> for RawSimpleCollector {
92+
type Gc = Gc<'gc, T>;
9093
#[inline]
91-
fn alloc<'gc, T>(context: &'gc SimpleCollectorContext, value: T) -> Gc<'gc, T> where T: GcSafe + 'gc {
94+
fn alloc(context: &'gc SimpleCollectorContext, value: T) -> Gc<'gc, T> where T: GcSafe + 'gc {
9295
context.collector().heap.allocator.alloc(value)
9396
}
9497
}
@@ -116,6 +119,9 @@ unsafe impl RawHandleImpl for RawSimpleCollector {
116119
&self.handle_list
117120
}
118121
}
122+
impl<'gc, T: GcSafe + 'gc> RawHandleImplHack<'gc, T> for RawSimpleCollector {
123+
type Gc = Gc<'gc, T>;
124+
}
119125

120126
/// A wrapper for [GcHandleList] that implements [DynTrace]
121127
#[repr(transparent)]
@@ -464,14 +470,6 @@ unsafe impl ::zerogc_context::collector::RawCollectorImpl for RawSimpleCollector
464470
raw_ptr
465471
}
466472

467-
#[inline(always)]
468-
unsafe fn gc_write_barrier<'gc, T, V>(
469-
_owner: &Gc<'gc, T>,
470-
_value: &Gc<'gc, V>,
471-
_field_offset: usize
472-
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
473-
// Simple GC doesn't need write barriers
474-
}
475473
#[inline]
476474
fn logger(&self) -> &Logger {
477475
&self.logger
@@ -673,20 +671,20 @@ unsafe impl GcVisitor for MarkVisitor<'_> {
673671
type Err = !;
674672

675673
#[inline]
676-
unsafe fn visit_gc<'gc, T, Id>(
677-
&mut self, gc: &mut ::zerogc::Gc<'gc, T, Id>
674+
unsafe fn visit_gc<'gc, T, G>(
675+
&mut self, gc: &mut G
678676
) -> Result<(), Self::Err>
679-
where T: GcSafe + 'gc, Id: ::zerogc::CollectorId {
680-
if TypeId::of::<Id>() == TypeId::of::<crate::CollectorId>() {
677+
where T: GcSafe + 'gc, G: GcRef<'gc, T> {
678+
if TypeId::of::<G::Id>() == TypeId::of::<crate::CollectorId>() {
681679
/*
682680
* Since the `TypeId`s match, we know the generic `Id`
683681
* matches our own `crate::CollectorId`.
684682
* Therefore its safe to specific the generic `Id` into the
685683
* `Gc` into its more specific type.
686684
*/
687685
let gc = std::mem::transmute::<
688-
&mut ::zerogc::Gc<'gc, T, Id>,
689-
&mut ::zerogc::Gc<'gc, T, crate::CollectorId>
686+
&mut G,
687+
&mut crate::gc::Gc<'gc, T>
690688
>(gc);
691689
/*
692690
* Check the collectors match. Otherwise we're mutating

0 commit comments

Comments
 (0)