Skip to content

Commit 3ec6bd8

Browse files
authored
Add support for garbage collected arrays/vectors
Merges #29 Closes #16 Right now, access to arrays doesn't trigger write barriers. I need to implement that before I can work on generational or incremental collection...... The vector API is a little rough around the edges because `GcVec` doesn't implement `Copy` as all the other `Gc` types do. See #30 for more details
2 parents de6f5d7 + 7c0a62c commit 3ec6bd8

File tree

15 files changed

+1628
-382
lines changed

15 files changed

+1628
-382
lines changed

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2018"
99
readme = "README.md"
1010

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

22-
[profile.dev]
23-
opt-level = 1
24-
2523
[features]
2624
default = ["std"]
2725
# Depend on the standard library (optional)

libs/context/src/collector.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use zerogc::{Gc, GcSafe, GcSystem, Trace, GcSimpleAlloc, NullTrace, TraceImmutab
1212

1313
use crate::{CollectorContext};
1414
use crate::state::{CollectionManager, RawContext};
15+
use zerogc::vec::GcVec;
16+
use zerogc::vec::repr::GcVecRepr;
1517

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

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

3236
/// The context
3337
type RawContext: RawContext<Self>;
38+
/// The raw representation of a vec
39+
type RawVecRepr: GcVecRepr;
3440

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

5561
/// The id of this collector
5662
#[inline]
5763
fn id(&self) -> CollectorId<Self> {
5864
CollectorId { ptr: unsafe { Self::Ptr::from_raw(self as *const _ as *mut _) } }
5965
}
60-
unsafe fn gc_write_barrier<'gc, T, V>(
61-
owner: &Gc<'gc, T, CollectorId<Self>>,
66+
unsafe fn gc_write_barrier<'gc, O, V>(
67+
owner: &Gc<'gc, O, CollectorId<Self>>,
6268
value: &Gc<'gc, V, CollectorId<Self>>,
6369
field_offset: usize
64-
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc;
70+
) where O: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc;
6571
/// The logger associated with this collector
6672
fn logger(&self) -> &Logger;
6773

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

96102
impl<C: RawCollectorImpl> PartialEq for CollectorId<C> {
@@ -278,6 +284,7 @@ impl<C: RawCollectorImpl> CollectorId<C> {
278284
}
279285
unsafe impl<C: RawCollectorImpl> ::zerogc::CollectorId for CollectorId<C> {
280286
type System = CollectorRef<C>;
287+
type RawVecRepr = C::RawVecRepr;
281288

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

287294

288295
#[inline(always)]
289-
unsafe fn gc_write_barrier<'gc, T, V>(
290-
owner: &Gc<'gc, T, Self>,
296+
unsafe fn gc_write_barrier<'gc, O, V>(
297+
owner: &Gc<'gc, O, Self>,
291298
value: &Gc<'gc, V, Self>,
292299
field_offset: usize
293-
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
300+
) where O: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
294301
C::gc_write_barrier(owner, value, field_offset)
295302
}
296303

@@ -341,13 +348,36 @@ impl<C: RawCollectorImpl> WeakCollectorRef<C> {
341348

342349
pub unsafe trait RawSimpleAlloc: RawCollectorImpl {
343350
fn alloc<'gc, T: GcSafe + 'gc>(context: &'gc CollectorContext<Self>, value: T) -> Gc<'gc, T, CollectorId<Self>>;
351+
unsafe fn alloc_uninit_slice<'gc, T>(context: &'gc CollectorContext<Self>, len: usize) -> (CollectorId<Self>, *mut T)
352+
where T: GcSafe + 'gc;
353+
fn alloc_vec<'gc, T>(context: &'gc CollectorContext<Self>) -> GcVec<'gc, T, CollectorContext<Self>>
354+
where T: GcSafe + 'gc;
355+
fn alloc_vec_with_capacity<'gc, T>(context: &'gc CollectorContext<Self>, capacity: usize) -> GcVec<'gc, T, CollectorContext<Self>>
356+
where T: GcSafe + 'gc;
344357
}
345-
unsafe impl<'gc, T, C> GcSimpleAlloc<'gc, T> for CollectorContext<C>
346-
where T: GcSafe + 'gc, C: RawSimpleAlloc {
358+
unsafe impl<C> GcSimpleAlloc for CollectorContext<C>
359+
where C: RawSimpleAlloc {
347360
#[inline]
348-
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id> {
361+
fn alloc<'gc, T>(&'gc self, value: T) -> Gc<'gc, T, Self::Id>
362+
where T: GcSafe + 'gc {
349363
C::alloc(self, value)
350364
}
365+
366+
#[inline]
367+
unsafe fn alloc_uninit_slice<'gc, T>(&'gc self, len: usize) -> (Self::Id, *mut T)
368+
where T: GcSafe + 'gc {
369+
C::alloc_uninit_slice(self, len)
370+
}
371+
372+
#[inline]
373+
fn alloc_vec<'gc, T>(&'gc self) -> GcVec<'gc, T, Self> where T: GcSafe + 'gc {
374+
C::alloc_vec(self)
375+
}
376+
377+
#[inline]
378+
fn alloc_vec_with_capacity<'gc, T>(&'gc self, capacity: usize) -> GcVec<'gc, T, Self> where T: GcSafe + 'gc {
379+
C::alloc_vec_with_capacity(self, capacity)
380+
}
351381
}
352382

353383
/// A reference to the collector.
@@ -371,26 +401,26 @@ unsafe impl<C: SyncCollector> Sync for CollectorRef<C> {}
371401
#[doc(hidden)]
372402
pub trait CollectorInit<C: RawCollectorImpl<Ptr=Self>>: CollectorPtr<C> {
373403
fn create() -> CollectorRef<C> {
374-
Self::with_logger(Logger::root(
404+
Self::with_logger(C::Config::default(), Logger::root(
375405
slog::Discard,
376406
o!()
377407
))
378408
}
379-
fn with_logger(logger: Logger) -> CollectorRef<C>;
409+
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C>;
380410
}
381411

382412
impl<C: RawCollectorImpl<Ptr=NonNull<C>>> CollectorInit<C> for NonNull<C> {
383-
fn with_logger(logger: Logger) -> CollectorRef<C> {
413+
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C> {
384414
assert!(!C::SINGLETON);
385-
let raw_ptr = C::init(logger);
415+
let raw_ptr = C::init(config, logger);
386416
CollectorRef { ptr: raw_ptr }
387417
}
388418
}
389419
impl<C> CollectorInit<C> for PhantomData<&'static C>
390420
where C: SingletonCollector {
391-
fn with_logger(logger: Logger) -> CollectorRef<C> {
421+
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C> {
392422
assert!(C::SINGLETON);
393-
C::init_global(logger); // TODO: Is this safe?
423+
C::init_global(config, logger); // TODO: Is this safe?
394424
// NOTE: The raw pointer is implicit (now that we're leaked)
395425
CollectorRef { ptr: PhantomData }
396426
}
@@ -405,7 +435,11 @@ impl<C: RawCollectorImpl> CollectorRef<C> {
405435

406436
#[inline]
407437
pub fn with_logger(logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
408-
<C::Ptr as CollectorInit<C>>::with_logger(logger)
438+
Self::with_config(C::Config::default(), logger)
439+
}
440+
441+
pub fn with_config(config: C::Config, logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
442+
<C::Ptr as CollectorInit<C>>::with_logger(config, logger)
409443
}
410444

411445
#[inline]

libs/context/src/state/sync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,13 +429,13 @@ pub(crate) trait SyncCollectorImpl: RawCollectorImpl<Manager=CollectionManager<S
429429
unreachable!("cant free while collection is in progress")
430430
},
431431
}
432-
// Now drop the Box
433-
drop(Box::from_raw(raw));
434432
/*
435433
* Notify all threads waiting for contexts to be valid.
436434
* TODO: I think this is really only useful if we're waiting....
437435
*/
438436
self.manager().valid_contexts_wait.notify_all();
437+
// Now drop the Box
438+
drop(Box::from_raw(raw));
439439
}
440440
/// Wait until the specified collection is finished
441441
///

libs/context/src/utils.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ use core::cell::Cell;
88
/// Get the offset of the specified field within a structure
99
#[macro_export]
1010
macro_rules! field_offset {
11-
($target:ty, $($field:ident).+) => {
12-
unsafe { (core::ptr::addr_of!((*(std::ptr::null_mut::<$target>()))$(.$field)*) as usize) }
13-
};
11+
($target:ty, $($field:ident).+) => {{
12+
const OFFSET: usize = {
13+
let uninit = core::mem::MaybeUninit::<$target>::uninit();
14+
unsafe { ((core::ptr::addr_of!((*uninit.as_ptr())$(.$field)*)) as *const u8)
15+
.offset_from(uninit.as_ptr() as *const u8) as usize }
16+
};
17+
OFFSET
18+
}};
1419
}
1520

1621
#[cfg(feature = "sync")]

libs/derive/src/lib.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,12 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
732732
};
733733
for param in &mut generics.params {
734734
let rewritten_param: GenericArgument;
735+
fn unsupported_lifetime_param(lt: &Lifetime) -> Error {
736+
Error::new(
737+
lt.span(),
738+
"Unless Self: NullTrace, derive(GcErase) is currently unable to handle lifetimes"
739+
)
740+
}
735741
match param {
736742
GenericParam::Type(ref mut type_param) => {
737743
let param_name = &type_param.ident;
@@ -740,7 +746,20 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
740746
rewritten_params.push(parse_quote!(#param_name));
741747
continue
742748
}
743-
let original_bounds = type_param.bounds.iter().cloned().collect::<Vec<_>>();
749+
fn rewrite_bound(bound: &TypeParamBound, info: &GcTypeInfo) -> Result<TypeParamBound, Error> {
750+
match bound {
751+
TypeParamBound::Trait(ref t) => Ok(TypeParamBound::Trait(t.clone())),
752+
TypeParamBound::Lifetime(ref lt) if *lt == info.config.gc_lifetime() => {
753+
Ok(parse_quote!('new_gc))
754+
},
755+
TypeParamBound::Lifetime(ref lt) => {
756+
return Err(unsupported_lifetime_param(lt))
757+
}
758+
}
759+
}
760+
let original_bounds = type_param.bounds.iter()
761+
.map(|bound| rewrite_bound(bound, info))
762+
.collect::<Result<Vec<_>, _>>()?;
744763
type_param.bounds.push(parse_quote!(#zerogc_crate::GcErase<'min, #collector_id>));
745764
type_param.bounds.push(parse_quote!('min));
746765
let rewritten_type: Type = parse_quote!(<#param_name as #zerogc_crate::GcErase<'min, #collector_id>>::Erased);
@@ -754,13 +773,10 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
754773
},
755774
GenericParam::Lifetime(ref l) => {
756775
if l.lifetime == info.config.gc_lifetime() {
757-
rewritten_param = parse_quote!('static);
776+
rewritten_param = parse_quote!('min);
758777
assert!(!info.config.ignored_lifetimes.contains(&l.lifetime));
759778
} else {
760-
return Err(Error::new(
761-
l.span(),
762-
"Unless Self: NullTrace, derive(GcErase) is currently unable to handle lifetimes"
763-
))
779+
return Err(unsupported_lifetime_param(&l.lifetime))
764780
}
765781
},
766782
GenericParam::Const(ref param) => {
@@ -881,14 +897,33 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
881897
};
882898
for param in &mut generics.params {
883899
let rewritten_param: GenericArgument;
900+
fn unsupported_lifetime_param(lt: &Lifetime) -> Error {
901+
Error::new(
902+
lt.span(),
903+
"Unless Self: NullTrace, derive(GcRebrand) is currently unable to handle lifetimes"
904+
)
905+
}
884906
match param {
885907
GenericParam::Type(ref mut type_param) => {
886908
let param_name = &type_param.ident;
887909
if info.is_ignored_param(&*type_param) {
888910
rewritten_params.push(parse_quote!(#param_name));
889911
continue
890912
}
891-
let original_bounds = type_param.bounds.iter().cloned().collect::<Vec<_>>();
913+
let original_bounds = type_param.bounds.iter()
914+
.map(|bound| rewrite_bound(bound, info))
915+
.collect::<Result<Vec<_>, Error>>()?;
916+
fn rewrite_bound(bound: &TypeParamBound, info: &GcTypeInfo) -> Result<TypeParamBound, Error> {
917+
match bound {
918+
TypeParamBound::Trait(ref t) => Ok(TypeParamBound::Trait(t.clone())),
919+
TypeParamBound::Lifetime(ref lt) if *lt == info.config.gc_lifetime() => {
920+
Ok(parse_quote!('new_gc))
921+
},
922+
TypeParamBound::Lifetime(ref lt) => {
923+
return Err(unsupported_lifetime_param(lt))
924+
}
925+
}
926+
}
892927
type_param.bounds.push(parse_quote!(#zerogc_crate::GcRebrand<'new_gc, #collector_id>));
893928
let rewritten_type: Type = parse_quote!(<#param_name as #zerogc_crate::GcRebrand<'new_gc, #collector_id>>::Branded);
894929
rewritten_restrictions.push(WherePredicate::Type(PredicateType {
@@ -904,10 +939,7 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
904939
rewritten_param = parse_quote!('new_gc);
905940
assert!(!info.config.ignored_lifetimes.contains(&l.lifetime));
906941
} else {
907-
return Err(Error::new(
908-
l.span(),
909-
"Unless Self: NullTrace, derive(GcRebrand) is currently unable to handle lifetimes"
910-
))
942+
return Err(unsupported_lifetime_param(&l.lifetime));
911943
}
912944
},
913945
GenericParam::Const(ref param) => {
@@ -962,7 +994,7 @@ fn impl_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
962994
let zerogc_crate = zerogc_crate();
963995
let name = &target.ident;
964996
let generics = add_trait_bounds_except(
965-
&target.generics, parse_quote!(zerogc::Trace),
997+
&target.generics, parse_quote!(#zerogc_crate::Trace),
966998
&info.config.ignore_params, None
967999
)?;
9681000
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

0 commit comments

Comments
 (0)