Skip to content

Use generic associated types for GcHandleSystem #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions libs/context/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,10 @@ impl<C: RawCollectorImpl> WeakCollectorRef<C> {
pub unsafe trait RawSimpleAlloc: RawCollectorImpl {
fn alloc<'gc, T: GcSafe + 'gc>(context: &'gc CollectorContext<Self>, value: T) -> Gc<'gc, T, CollectorId<Self>>;
}
unsafe impl<'gc, T, C> GcSimpleAlloc<'gc, T> for CollectorContext<C>
where T: GcSafe + 'gc, C: RawSimpleAlloc {
unsafe impl<C> GcSimpleAlloc for CollectorContext<C>
where C: RawSimpleAlloc {
#[inline]
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id> {
fn alloc<'gc, T>(&'gc self, value: T) -> Gc<'gc, T, Self::Id> where T: GcSafe + 'gc, {
C::alloc(self, value)
}
}
Expand Down
67 changes: 36 additions & 31 deletions libs/context/src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
use alloc::boxed::Box;
use alloc::vec::Vec;

use zerogc::{Trace, GcSafe, GcErase, GcRebrand, GcVisitor, NullTrace, TraceImmutable, GcHandleSystem, GcBindHandle};
use zerogc::{Trace, GcSafe, GcErase, GcRebrand, GcVisitor, NullTrace, TraceImmutable, GcHandleSystem};
use crate::{Gc, WeakCollectorRef, CollectorId, CollectorContext, CollectorRef, CollectionManager};
use crate::collector::RawCollectorImpl;

Expand Down Expand Up @@ -417,30 +417,10 @@ unsafe impl<T: GcSafe, C: RawHandleImpl> ::zerogc::GcHandle<T> for GcHandle<T, C
type System = CollectorRef<C>;
type Id = CollectorId<C>;

fn use_critical<R>(&self, func: impl FnOnce(&T) -> R) -> R {
self.collector.ensure_valid(|collector| unsafe {
/*
* This should be sufficient to ensure
* the value won't be collected or relocated.
*
* Note that this is implemented using a read lock,
* so recursive calls will deadlock.
* This is preferable to using `recursive_read`,
* since that could starve writers (collectors).
*/
C::Manager::prevent_collection(collector.as_ref(), || {
let value = self.inner.as_ref().value
.load(Ordering::Acquire) as *mut T;
func(&*value)
})
})
}
}
unsafe impl<'new_gc, T, C> GcBindHandle<'new_gc, T> for GcHandle<T, C>
where T: GcSafe, T: GcRebrand<'new_gc, CollectorId<C>>,
T::Branded: GcSafe, C: RawHandleImpl {
#[inline]
fn bind_to(&self, context: &'new_gc CollectorContext<C>) -> Gc<'new_gc, T::Branded, CollectorId<C>> {
fn bind_to<'new_gc>(&self, context: &'new_gc CollectorContext<C>) -> Gc<'new_gc, T::Branded, CollectorId<C>>
where T: GcRebrand<'new_gc, Self::Id>,
<T as GcRebrand<'new_gc, Self::Id>>::Branded: GcSafe {
/*
* We can safely assume the object will
* be as valid as long as the context.
Expand Down Expand Up @@ -472,6 +452,24 @@ unsafe impl<'new_gc, T, C> GcBindHandle<'new_gc, T> for GcHandle<T, C>
}
}

fn use_critical<R>(&self, func: impl FnOnce(&T) -> R) -> R {
self.collector.ensure_valid(|collector| unsafe {
/*
* This should be sufficient to ensure
* the value won't be collected or relocated.
*
* Note that this is implemented using a read lock,
* so recursive calls will deadlock.
* This is preferable to using `recursive_read`,
* since that could starve writers (collectors).
*/
C::Manager::prevent_collection(collector.as_ref(), || {
let value = self.inner.as_ref().value
.load(Ordering::Acquire) as *mut T;
func(&*value)
})
})
}
}
unsafe impl<T: GcSafe, C: RawHandleImpl> Trace for GcHandle<T, C> {
/// See docs on reachability
Expand Down Expand Up @@ -595,16 +593,23 @@ unsafe impl<T: GcSafe + Sync, C: RawHandleImpl + Sync> Send for GcHandle<T, C> {
/// Requires that the collector is thread-safe.
unsafe impl<T: GcSafe + Sync, C: RawHandleImpl + Sync> Sync for GcHandle<T, C> {}

#[doc(hidden)]
pub trait GcSafeErase<'a, Id: ::zerogc::CollectorId>: GcErase<'a, Id> + GcSafe
where <Self as GcErase<'a, Id>>::Erased: GcSafe {
}
/// We support handles
unsafe impl<'gc, 'a, T, C> GcHandleSystem<'gc, 'a, T> for CollectorRef<C>
where C: RawHandleImpl,
T: GcSafe + 'gc,
T: GcErase<'a, CollectorId<C>>,
T::Erased: GcSafe {
type Handle = GcHandle<T::Erased, C>;
unsafe impl<C> GcHandleSystem for CollectorRef<C>
where C: RawHandleImpl, {
type Handle<'a, T>
where T: GcSafe + ?Sized + GcErase<'a, CollectorId<C>>,
<T as GcErase<'a, CollectorId<C>>>::Erased: GcSafe
= GcHandle<<T as GcErase<'a, Self::Id>>::Erased, C>;

#[inline]
fn create_handle(gc: Gc<'gc, T, CollectorId<C>>) -> Self::Handle {
fn create_handle<'gc, 'a, T>(gc: Gc<'gc, T, CollectorId<C>>) -> Self::Handle<'a, T>
where T: ?Sized + GcSafe + 'gc,
T: GcErase<'a, CollectorId<C>>,
T::Erased: GcSafe {
unsafe {
let collector = gc.collector_id();
let value = gc.as_raw_ptr();
Expand Down
1 change: 1 addition & 0 deletions libs/context/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
negative_impls, // !Send is much cleaner than `PhantomData<Rc>`
untagged_unions, // I want to avoid ManuallyDrop in unions
const_fn_trait_bound, // So generics + const fn are unstable, huh?
generic_associated_types, // GcHandle
)]
#![cfg_attr(not(feature = "std"), no_std)]
//! The implementation of (GcContext)[`::zerogc::GcContext`] that is
Expand Down
63 changes: 28 additions & 35 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![feature(
const_panic, // RFC 2345 - Const asserts
generic_associated_types, // Needed for GcHandleSystem
)]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
Expand Down Expand Up @@ -208,12 +209,11 @@ pub unsafe trait GcSystem {
///
/// This type-system hackery is needed because
/// we need to place bounds on `T as GcBrand`
// TODO: Remove when we get more powerful types
pub unsafe trait GcHandleSystem<'gc, 'a, T: GcSafe + ?Sized + 'gc>: GcSystem
where T: GcErase<'a, Self::Id>,
<T as GcErase<'a, Self::Id>>::Erased: GcSafe {
pub unsafe trait GcHandleSystem: GcSystem {
/// The type of handles to this object.
type Handle: GcHandle<<T as GcErase<'a, Self::Id>>::Erased, System=Self>;
type Handle<'a, T>: GcHandle<<T as GcErase<'a, Self::Id>>::Erased, System=Self>
where T: ?Sized + GcSafe + GcErase<'a, Self::Id>,
<T as GcErase<'a, Self::Id>>::Erased: GcSafe;

/// Create a handle to the specified GC pointer,
/// which can be used without a context
Expand All @@ -222,7 +222,9 @@ pub unsafe trait GcHandleSystem<'gc, 'a, T: GcSafe + ?Sized + 'gc>: GcSystem
///
/// The system is implicit in the [Gc]
#[doc(hidden)]
fn create_handle(gc: Gc<'gc, T, Self::Id>) -> Self::Handle;
fn create_handle<'gc, 'a, T>(gc: Gc<'gc, T, Self::Id>) -> Self::Handle<'a, T>
where T: ?Sized + GcSafe + GcErase<'a, Self::Id>,
<T as GcErase<'a, Self::Id>>::Erased: GcSafe;
}

/// The context of garbage collection,
Expand Down Expand Up @@ -321,7 +323,7 @@ pub unsafe trait GcContext: Sized {
///
/// Some garbage collectors implement more complex interfaces,
/// so implementing this is optional
pub unsafe trait GcSimpleAlloc<'gc, T: GcSafe + 'gc>: GcContext + 'gc {
pub unsafe trait GcSimpleAlloc: GcContext {
/// Allocate the specified object in this garbage collector,
/// binding it to the lifetime of this collector.
///
Expand All @@ -334,7 +336,7 @@ pub unsafe trait GcSimpleAlloc<'gc, T: GcSafe + 'gc>: GcContext + 'gc {
///
/// This gives a immutable reference to the resulting object.
/// Once allocated, the object can only be correctly modified with a `GcCell`
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id>;
fn alloc<'gc, T: GcSafe + 'gc>(&'gc self, value: T) -> Gc<'gc, T, Self::Id>;
}
/// The internal representation of a frozen context
///
Expand Down Expand Up @@ -468,11 +470,11 @@ impl<'gc, T: GcSafe + ?Sized + 'gc, Id: CollectorId> Gc<'gc, T, Id> {

/// Create a handle to this object, which can be used without a context
#[inline]
pub fn create_handle<'a>(&self) -> <Id::System as GcHandleSystem<'gc, 'a, T>>::Handle
where Id::System: GcHandleSystem<'gc, 'a, T>,
pub fn create_handle<'a>(&self) -> <Id::System as GcHandleSystem>::Handle<'a, T>
where Id::System: GcHandleSystem,
T: GcErase<'a, Id> + 'a,
<T as GcErase<'a, Id>>::Erased: GcSafe + 'a {
<Id::System as GcHandleSystem<'gc, 'a, T>>::create_handle(*self)
<Id::System as GcHandleSystem>::create_handle(*self)
}

/// Get a reference to the system
Expand Down Expand Up @@ -628,6 +630,21 @@ pub unsafe trait GcHandle<T: GcSafe + ?Sized>: Clone + NullTrace {
/// The type of [CollectorId] used with this sytem
type Id: CollectorId;

/// Associate this handle with the specified context,
/// allowing its underlying object to be accessed
/// as long as the context is valid.
///
/// The underlying object can be accessed just like any
/// other object that would be allocated from the context.
/// It'll be properly collected and can even be used as a root
/// at the next safepoint.
fn bind_to<'new_gc>(&self, context: &'new_gc <Self::System as GcSystem>::Context) -> Gc<
'new_gc,
<T as GcRebrand<'new_gc, Self::Id>>::Branded,
Self::Id
> where T: GcRebrand<'new_gc, Self::Id>,
<T as GcRebrand<'new_gc, Self::Id>>::Branded: GcSafe;

/// Access this handle inside the closure,
/// possibly associating it with the specified
///
Expand All @@ -646,30 +663,6 @@ pub unsafe trait GcHandle<T: GcSafe + ?Sized>: Clone + NullTrace {
*/
fn use_critical<R>(&self, func: impl FnOnce(&T) -> R) -> R;
}
/// Trait for binding [GcHandle]s to contexts
/// using [GcBindHandle::bind_to]
///
/// This is separate from the [GcHandle] trait
/// because Rust doesn't have Generic Associated Types
///
/// TODO: Remove when we get more powerful types
pub unsafe trait GcBindHandle<'new_gc, T: GcSafe + ?Sized>: GcHandle<T>
where T: GcRebrand<'new_gc, Self::Id>,
<T as GcRebrand<'new_gc, Self::Id>>::Branded: GcSafe {
/// Associate this handle with the specified context,
/// allowing its underlying object to be accessed
/// as long as the context is valid.
///
/// The underlying object can be accessed just like any
/// other object that would be allocated from the context.
/// It'll be properly collected and can even be used as a root
/// at the next safepoint.
fn bind_to(&self, context: &'new_gc <Self::System as GcSystem>::Context) -> Gc<
'new_gc,
<T as GcRebrand<'new_gc, Self::Id>>::Branded,
Self::Id
>;
}

/// Safely trigger a write barrier before
/// writing to a garbage collected value.
Expand Down
2 changes: 0 additions & 2 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ pub use crate::{
pub use crate::{
GcSafe, GcErase, GcRebrand, Trace, TraceImmutable, NullTrace
};
// Hack traits
pub use crate::{GcBindHandle};
// TODO: Should this trait be auto-imported???
pub use crate::CollectorId;
// Utils
Expand Down