Skip to content
4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ edition = "2018"
readme = "README.md"

[dependencies]
scopeguard = "1.1"
# Manually included tracing support for third party libraries
# Providing support for these important libraries,
# gives zerogc 'batteries included' support.
Expand All @@ -19,9 +20,6 @@ zerogc-derive = { path = "libs/derive", version = "0.2.0-alpha.3" }
[workspace]
members = ["libs/simple", "libs/derive", "libs/context"]

[profile.dev]
opt-level = 1

[features]
default = ["std"]
# Depend on the standard library (optional)
Expand Down
70 changes: 52 additions & 18 deletions libs/context/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use zerogc::{Gc, GcSafe, GcSystem, Trace, GcSimpleAlloc, NullTrace, TraceImmutab

use crate::{CollectorContext};
use crate::state::{CollectionManager, RawContext};
use zerogc::vec::GcVec;
use zerogc::vec::repr::GcVecRepr;

/// A specific implementation of a collector
pub unsafe trait RawCollectorImpl: 'static + Sized {
Expand All @@ -20,6 +22,8 @@ pub unsafe trait RawCollectorImpl: 'static + Sized {
/// The simple collector implements this as
/// a trait object pointer.
type DynTracePtr: Copy + Debug + 'static;
/// The configuration
type Config: Sized + Default;

/// A pointer to this collector
///
Expand All @@ -31,6 +35,8 @@ pub unsafe trait RawCollectorImpl: 'static + Sized {

/// The context
type RawContext: RawContext<Self>;
/// The raw representation of a vec
type RawVecRepr: GcVecRepr;

/// True if this collector is a singleton
///
Expand All @@ -50,18 +56,18 @@ pub unsafe trait RawCollectorImpl: 'static + Sized {
/// Initialize an instance of the collector
///
/// Must panic if the collector is not a singleton
fn init(logger: Logger) -> NonNull<Self>;
fn init(config: Self::Config, logger: Logger) -> NonNull<Self>;

/// The id of this collector
#[inline]
fn id(&self) -> CollectorId<Self> {
CollectorId { ptr: unsafe { Self::Ptr::from_raw(self as *const _ as *mut _) } }
}
unsafe fn gc_write_barrier<'gc, T, V>(
owner: &Gc<'gc, T, CollectorId<Self>>,
unsafe fn gc_write_barrier<'gc, O, V>(
owner: &Gc<'gc, O, CollectorId<Self>>,
value: &Gc<'gc, V, CollectorId<Self>>,
field_offset: usize
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc;
) where O: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc;
/// The logger associated with this collector
fn logger(&self) -> &Logger;

Expand Down Expand Up @@ -90,7 +96,7 @@ pub unsafe trait SingletonCollector: RawCollectorImpl<Ptr=PhantomData<&'static S
/// Initialize the global singleton
///
/// Panics if already initialized
fn init_global(logger: Logger);
fn init_global(config: Self::Config, logger: Logger);
}

impl<C: RawCollectorImpl> PartialEq for CollectorId<C> {
Expand Down Expand Up @@ -278,6 +284,7 @@ impl<C: RawCollectorImpl> CollectorId<C> {
}
unsafe impl<C: RawCollectorImpl> ::zerogc::CollectorId for CollectorId<C> {
type System = CollectorRef<C>;
type RawVecRepr = C::RawVecRepr;

#[inline]
fn from_gc_ptr<'a, 'gc, T>(gc: &'a Gc<'gc, T, Self>) -> &'a Self where T: GcSafe + ?Sized + 'gc, 'gc: 'a {
Expand All @@ -286,11 +293,11 @@ unsafe impl<C: RawCollectorImpl> ::zerogc::CollectorId for CollectorId<C> {


#[inline(always)]
unsafe fn gc_write_barrier<'gc, T, V>(
owner: &Gc<'gc, T, Self>,
unsafe fn gc_write_barrier<'gc, O, V>(
owner: &Gc<'gc, O, Self>,
value: &Gc<'gc, V, Self>,
field_offset: usize
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
) where O: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
C::gc_write_barrier(owner, value, field_offset)
}

Expand Down Expand Up @@ -341,13 +348,36 @@ 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 fn alloc_uninit_slice<'gc, T>(context: &'gc CollectorContext<Self>, len: usize) -> (CollectorId<Self>, *mut T)
where T: GcSafe + 'gc;
fn alloc_vec<'gc, T>(context: &'gc CollectorContext<Self>) -> GcVec<'gc, T, CollectorContext<Self>>
where T: GcSafe + 'gc;
fn alloc_vec_with_capacity<'gc, T>(context: &'gc CollectorContext<Self>, capacity: usize) -> GcVec<'gc, T, CollectorContext<Self>>
where T: GcSafe + 'gc;
}
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)
}

#[inline]
unsafe fn alloc_uninit_slice<'gc, T>(&'gc self, len: usize) -> (Self::Id, *mut T)
where T: GcSafe + 'gc {
C::alloc_uninit_slice(self, len)
}

#[inline]
fn alloc_vec<'gc, T>(&'gc self) -> GcVec<'gc, T, Self> where T: GcSafe + 'gc {
C::alloc_vec(self)
}

#[inline]
fn alloc_vec_with_capacity<'gc, T>(&'gc self, capacity: usize) -> GcVec<'gc, T, Self> where T: GcSafe + 'gc {
C::alloc_vec_with_capacity(self, capacity)
}
}

/// A reference to the collector.
Expand All @@ -371,26 +401,26 @@ unsafe impl<C: SyncCollector> Sync for CollectorRef<C> {}
#[doc(hidden)]
pub trait CollectorInit<C: RawCollectorImpl<Ptr=Self>>: CollectorPtr<C> {
fn create() -> CollectorRef<C> {
Self::with_logger(Logger::root(
Self::with_logger(C::Config::default(), Logger::root(
slog::Discard,
o!()
))
}
fn with_logger(logger: Logger) -> CollectorRef<C>;
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C>;
}

impl<C: RawCollectorImpl<Ptr=NonNull<C>>> CollectorInit<C> for NonNull<C> {
fn with_logger(logger: Logger) -> CollectorRef<C> {
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C> {
assert!(!C::SINGLETON);
let raw_ptr = C::init(logger);
let raw_ptr = C::init(config, logger);
CollectorRef { ptr: raw_ptr }
}
}
impl<C> CollectorInit<C> for PhantomData<&'static C>
where C: SingletonCollector {
fn with_logger(logger: Logger) -> CollectorRef<C> {
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C> {
assert!(C::SINGLETON);
C::init_global(logger); // TODO: Is this safe?
C::init_global(config, logger); // TODO: Is this safe?
// NOTE: The raw pointer is implicit (now that we're leaked)
CollectorRef { ptr: PhantomData }
}
Expand All @@ -405,7 +435,11 @@ impl<C: RawCollectorImpl> CollectorRef<C> {

#[inline]
pub fn with_logger(logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
<C::Ptr as CollectorInit<C>>::with_logger(logger)
Self::with_config(C::Config::default(), logger)
}

pub fn with_config(config: C::Config, logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
<C::Ptr as CollectorInit<C>>::with_logger(config, logger)
}

#[inline]
Expand Down
4 changes: 2 additions & 2 deletions libs/context/src/state/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,13 +429,13 @@ pub(crate) trait SyncCollectorImpl: RawCollectorImpl<Manager=CollectionManager<S
unreachable!("cant free while collection is in progress")
},
}
// Now drop the Box
drop(Box::from_raw(raw));
/*
* Notify all threads waiting for contexts to be valid.
* TODO: I think this is really only useful if we're waiting....
*/
self.manager().valid_contexts_wait.notify_all();
// Now drop the Box
drop(Box::from_raw(raw));
}
/// Wait until the specified collection is finished
///
Expand Down
11 changes: 8 additions & 3 deletions libs/context/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ use core::cell::Cell;
/// Get the offset of the specified field within a structure
#[macro_export]
macro_rules! field_offset {
($target:ty, $($field:ident).+) => {
unsafe { (core::ptr::addr_of!((*(std::ptr::null_mut::<$target>()))$(.$field)*) as usize) }
};
($target:ty, $($field:ident).+) => {{
const OFFSET: usize = {
let uninit = core::mem::MaybeUninit::<$target>::uninit();
unsafe { ((core::ptr::addr_of!((*uninit.as_ptr())$(.$field)*)) as *const u8)
.offset_from(uninit.as_ptr() as *const u8) as usize }
};
OFFSET
}};
}

#[cfg(feature = "sync")]
Expand Down
56 changes: 44 additions & 12 deletions libs/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,12 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
};
for param in &mut generics.params {
let rewritten_param: GenericArgument;
fn unsupported_lifetime_param(lt: &Lifetime) -> Error {
Error::new(
lt.span(),
"Unless Self: NullTrace, derive(GcErase) is currently unable to handle lifetimes"
)
}
match param {
GenericParam::Type(ref mut type_param) => {
let param_name = &type_param.ident;
Expand All @@ -740,7 +746,20 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
rewritten_params.push(parse_quote!(#param_name));
continue
}
let original_bounds = type_param.bounds.iter().cloned().collect::<Vec<_>>();
fn rewrite_bound(bound: &TypeParamBound, info: &GcTypeInfo) -> Result<TypeParamBound, Error> {
match bound {
TypeParamBound::Trait(ref t) => Ok(TypeParamBound::Trait(t.clone())),
TypeParamBound::Lifetime(ref lt) if *lt == info.config.gc_lifetime() => {
Ok(parse_quote!('new_gc))
},
TypeParamBound::Lifetime(ref lt) => {
return Err(unsupported_lifetime_param(lt))
}
}
}
let original_bounds = type_param.bounds.iter()
.map(|bound| rewrite_bound(bound, info))
.collect::<Result<Vec<_>, _>>()?;
type_param.bounds.push(parse_quote!(#zerogc_crate::GcErase<'min, #collector_id>));
type_param.bounds.push(parse_quote!('min));
let rewritten_type: Type = parse_quote!(<#param_name as #zerogc_crate::GcErase<'min, #collector_id>>::Erased);
Expand All @@ -754,13 +773,10 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
},
GenericParam::Lifetime(ref l) => {
if l.lifetime == info.config.gc_lifetime() {
rewritten_param = parse_quote!('static);
rewritten_param = parse_quote!('min);
assert!(!info.config.ignored_lifetimes.contains(&l.lifetime));
} else {
return Err(Error::new(
l.span(),
"Unless Self: NullTrace, derive(GcErase) is currently unable to handle lifetimes"
))
return Err(unsupported_lifetime_param(&l.lifetime))
}
},
GenericParam::Const(ref param) => {
Expand Down Expand Up @@ -881,14 +897,33 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
};
for param in &mut generics.params {
let rewritten_param: GenericArgument;
fn unsupported_lifetime_param(lt: &Lifetime) -> Error {
Error::new(
lt.span(),
"Unless Self: NullTrace, derive(GcRebrand) is currently unable to handle lifetimes"
)
}
match param {
GenericParam::Type(ref mut type_param) => {
let param_name = &type_param.ident;
if info.is_ignored_param(&*type_param) {
rewritten_params.push(parse_quote!(#param_name));
continue
}
let original_bounds = type_param.bounds.iter().cloned().collect::<Vec<_>>();
let original_bounds = type_param.bounds.iter()
.map(|bound| rewrite_bound(bound, info))
.collect::<Result<Vec<_>, Error>>()?;
fn rewrite_bound(bound: &TypeParamBound, info: &GcTypeInfo) -> Result<TypeParamBound, Error> {
match bound {
TypeParamBound::Trait(ref t) => Ok(TypeParamBound::Trait(t.clone())),
TypeParamBound::Lifetime(ref lt) if *lt == info.config.gc_lifetime() => {
Ok(parse_quote!('new_gc))
},
TypeParamBound::Lifetime(ref lt) => {
return Err(unsupported_lifetime_param(lt))
}
}
}
type_param.bounds.push(parse_quote!(#zerogc_crate::GcRebrand<'new_gc, #collector_id>));
let rewritten_type: Type = parse_quote!(<#param_name as #zerogc_crate::GcRebrand<'new_gc, #collector_id>>::Branded);
rewritten_restrictions.push(WherePredicate::Type(PredicateType {
Expand All @@ -904,10 +939,7 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
rewritten_param = parse_quote!('new_gc);
assert!(!info.config.ignored_lifetimes.contains(&l.lifetime));
} else {
return Err(Error::new(
l.span(),
"Unless Self: NullTrace, derive(GcRebrand) is currently unable to handle lifetimes"
))
return Err(unsupported_lifetime_param(&l.lifetime));
}
},
GenericParam::Const(ref param) => {
Expand Down Expand Up @@ -962,7 +994,7 @@ fn impl_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
let zerogc_crate = zerogc_crate();
let name = &target.ident;
let generics = add_trait_bounds_except(
&target.generics, parse_quote!(zerogc::Trace),
&target.generics, parse_quote!(#zerogc_crate::Trace),
&info.config.ignore_params, None
)?;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
Expand Down
Loading