Skip to content

Commit 8b5f68d

Browse files
committed
First attempt a garbage collected arrays/vectors
This crashes even the most basic tests :( Everything is broken. I feel like I need to cleanup.
1 parent de6f5d7 commit 8b5f68d

File tree

14 files changed

+1051
-193
lines changed

14 files changed

+1051
-193
lines changed

Cargo.toml

Lines changed: 1 addition & 0 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.

libs/context/src/collector.rs

Lines changed: 49 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,33 @@ 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_with_capacity<'gc, T>(context: &'gc CollectorContext<Self>, capacity: usize) -> GcVec<'gc, T, CollectorContext<Self>> where T: GcSafe + 'gc;
344354
}
345-
unsafe impl<'gc, T, C> GcSimpleAlloc<'gc, T> for CollectorContext<C>
346-
where T: GcSafe + 'gc, C: RawSimpleAlloc {
355+
unsafe impl<C> GcSimpleAlloc for CollectorContext<C>
356+
where C: RawSimpleAlloc {
347357
#[inline]
348-
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id> {
358+
fn alloc<'gc, T>(&'gc self, value: T) -> Gc<'gc, T, Self::Id>
359+
where T: GcSafe + 'gc {
349360
C::alloc(self, value)
350361
}
362+
363+
#[inline]
364+
unsafe fn alloc_uninit_slice<'gc, T>(&'gc self, len: usize) -> (Self::Id, *mut T)
365+
where T: GcSafe + 'gc {
366+
C::alloc_uninit_slice(self, len)
367+
}
368+
369+
#[inline]
370+
fn alloc_vec<'gc, T>(&'gc self) -> GcVec<'gc, T, Self> where T: GcSafe + 'gc {
371+
self.alloc_vec_with_capacity(0)
372+
}
373+
374+
#[inline]
375+
fn alloc_vec_with_capacity<'gc, T>(&'gc self, capacity: usize) -> GcVec<'gc, T, Self> where T: GcSafe + 'gc {
376+
C::alloc_vec_with_capacity(self, capacity)
377+
}
351378
}
352379

353380
/// A reference to the collector.
@@ -371,26 +398,26 @@ unsafe impl<C: SyncCollector> Sync for CollectorRef<C> {}
371398
#[doc(hidden)]
372399
pub trait CollectorInit<C: RawCollectorImpl<Ptr=Self>>: CollectorPtr<C> {
373400
fn create() -> CollectorRef<C> {
374-
Self::with_logger(Logger::root(
401+
Self::with_logger(C::Config::default(), Logger::root(
375402
slog::Discard,
376403
o!()
377404
))
378405
}
379-
fn with_logger(logger: Logger) -> CollectorRef<C>;
406+
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C>;
380407
}
381408

382409
impl<C: RawCollectorImpl<Ptr=NonNull<C>>> CollectorInit<C> for NonNull<C> {
383-
fn with_logger(logger: Logger) -> CollectorRef<C> {
410+
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C> {
384411
assert!(!C::SINGLETON);
385-
let raw_ptr = C::init(logger);
412+
let raw_ptr = C::init(config, logger);
386413
CollectorRef { ptr: raw_ptr }
387414
}
388415
}
389416
impl<C> CollectorInit<C> for PhantomData<&'static C>
390417
where C: SingletonCollector {
391-
fn with_logger(logger: Logger) -> CollectorRef<C> {
418+
fn with_logger(config: C::Config, logger: Logger) -> CollectorRef<C> {
392419
assert!(C::SINGLETON);
393-
C::init_global(logger); // TODO: Is this safe?
420+
C::init_global(config, logger); // TODO: Is this safe?
394421
// NOTE: The raw pointer is implicit (now that we're leaked)
395422
CollectorRef { ptr: PhantomData }
396423
}
@@ -405,7 +432,11 @@ impl<C: RawCollectorImpl> CollectorRef<C> {
405432

406433
#[inline]
407434
pub fn with_logger(logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
408-
<C::Ptr as CollectorInit<C>>::with_logger(logger)
435+
Self::with_config(C::Config::default(), logger)
436+
}
437+
438+
pub fn with_config(config: C::Config, logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
439+
<C::Ptr as CollectorInit<C>>::with_logger(config, logger)
409440
}
410441

411442
#[inline]

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();

libs/derive/src/macros.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,13 @@ impl MacroInput {
172172
}
173173
let target_type = &self.target_type;
174174
let mut generics = self.basic_generics();
175+
let id_type: Type = match self.options.collector_id {
176+
Some(ref tp) => tp.clone(),
177+
None => {
178+
generics.params.push(parse_quote!(Id: #zerogc_crate::CollectorId));
179+
parse_quote!(Id)
180+
}
181+
};
175182
let default_bounds: Vec<TypeParamBound> = match requirements {
176183
Some(TraitRequirements::Where(ref explicit_requirements)) => {
177184
generics.make_where_clause().predicates
@@ -185,9 +192,9 @@ impl MacroInput {
185192
Some(TraitRequirements::Never) => unreachable!(),
186193
None => {
187194
if rebrand {
188-
vec![parse_quote!(#zerogc_crate::GcRebrand<'new_gc, Id>)]
195+
vec![parse_quote!(#zerogc_crate::GcRebrand<'new_gc, #id_type>)]
189196
} else {
190-
vec![parse_quote!(#zerogc_crate::GcErase<'min, Id>)]
197+
vec![parse_quote!(#zerogc_crate::GcErase<'min, #id_type>)]
191198
}
192199
}
193200
};
@@ -236,17 +243,16 @@ impl MacroInput {
236243
*/
237244
generics.make_where_clause().predicates
238245
.extend(self.bounds.trace_where_clause(&self.params).predicates);
239-
generics.params.push(parse_quote!(Id: #zerogc_crate::CollectorId));
240246
if rebrand {
241247
generics.params.push(parse_quote!('new_gc));
242248
} else {
243249
generics.params.push(parse_quote!('min));
244250
}
245251
let (impl_generics, _, where_clause) = generics.split_for_impl();
246252
let target_trait = if rebrand {
247-
quote!(#zerogc_crate::GcRebrand<'new_gc, Id>)
253+
quote!(#zerogc_crate::GcRebrand<'new_gc, #id_type>)
248254
} else {
249-
quote!(#zerogc_crate::GcErase<'min, Id>)
255+
quote!(#zerogc_crate::GcErase<'min, #id_type>)
250256
};
251257
fn rewrite_brand_trait(
252258
target: &Type, trait_name: &str, target_params: &HashSet<Ident>,
@@ -278,7 +284,7 @@ impl MacroInput {
278284
rewrite_brand_trait(
279285
&self.target_type, "GcRebrand",
280286
&target_params,
281-
parse_quote!(#zerogc_crate::GcRebrand<'new_gc, Id>),
287+
parse_quote!(#zerogc_crate::GcRebrand<'new_gc, #id_type>),
282288
parse_quote!(Branded)
283289
)
284290
}, Ok)?;
@@ -288,7 +294,7 @@ impl MacroInput {
288294
rewrite_brand_trait(
289295
&self.target_type, "GcErase",
290296
&target_params,
291-
parse_quote!(#zerogc_crate::GcErase<'min, Id>),
297+
parse_quote!(#zerogc_crate::GcErase<'min, #id_type>),
292298
parse_quote!(Erased)
293299
)
294300
})?;
@@ -378,6 +384,7 @@ impl Parse for MacroInput {
378384
"visit" [VisitClosure] opt => visit_closure;
379385
"trace_mut" [VisitClosure] opt => trace_mut_closure;
380386
"trace_immutable" [VisitClosure] opt => trace_immutable_closure;
387+
"collector_id" [Type] opt => collector_id;
381388
});
382389
let bounds = res.bounds.unwrap_or_default();
383390
if let Some(TraitRequirements::Never) = bounds.trace {
@@ -439,7 +446,8 @@ impl Parse for MacroInput {
439446
branded_type: res.branded_type,
440447
erased_type: res.erased_type,
441448
needs_trace: res.needs_trace,
442-
needs_drop: res.needs_drop
449+
needs_drop: res.needs_drop,
450+
collector_id: res.collector_id
443451
},
444452
visit: visit_impl
445453
})
@@ -598,6 +606,8 @@ pub struct StandardOptions {
598606
needs_trace: Expr,
599607
/// A (constant) expression determining whether the type should be dropped
600608
needs_drop: Expr,
609+
/// The fixed id of the collector, or `None` if the type can work with any collector
610+
collector_id: Option<Type>
601611
}
602612

603613
/// The visit implementation.

0 commit comments

Comments
 (0)