Skip to content

Commit 1594170

Browse files
committed
Add an "epsilon" collector that never collects memory
This replaces the "dummy_impl" Name inspired by JEP 318: https://openjdk.java.net/jeps/318
1 parent eba235c commit 1594170

File tree

17 files changed

+655
-220
lines changed

17 files changed

+655
-220
lines changed

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ parking_lot = { version = "0.11", optional = true }
1919
serde = { version = "1", optional = true, features = ["derive"] }
2020
# Used for macros
2121
zerogc-derive = { path = "libs/derive", version = "0.2.0-alpha.5" }
22+
# Used for the "epsilon" no-op collector
23+
bumpalo = { version = "3", optional = true }
2224

2325
[workspace]
2426
members = ["libs/simple", "libs/derive", "libs/context"]
2527

2628
[features]
27-
default = ["std"]
29+
default = ["std", "epsilon"]
2830
# Depend on the standard library (optional)
2931
#
3032
# This implements tracing for most standard library types.
@@ -35,4 +37,6 @@ std = ["alloc"]
3537
# This implements `Trace` for `Box` and collections like `Vec`
3638
alloc = []
3739
# Serde support
38-
serde1 = ["serde", "zerogc-derive/__serde-internal"]
40+
serde1 = ["serde", "zerogc-derive/__serde-internal", "indexmap/serde-1"]
41+
# Support the "epsilon" no-op collector
42+
epsilon = ["bumpalo"]

libs/context/src/collector.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{CollectorContext};
1515
use crate::state::{CollectionManager, RawContext};
1616
use zerogc::vec::GcVec;
1717
use zerogc::vec::repr::GcVecRepr;
18+
use std::hash::{Hasher, Hash};
1819

1920
/// A specific implementation of a collector
2021
pub unsafe trait RawCollectorImpl: 'static + Sized {
@@ -112,6 +113,12 @@ impl<C: RawCollectorImpl> PartialEq for CollectorId<C> {
112113
self.ptr == other.ptr
113114
}
114115
}
116+
impl<C: RawCollectorImpl> Hash for CollectorId<C> {
117+
#[inline]
118+
fn hash<H: Hasher>(&self, hasher: &mut H) {
119+
hasher.write_usize(self.ptr.as_ptr() as usize);
120+
}
121+
}
115122
impl<C: RawCollectorImpl> Eq for CollectorId<C> {}
116123
impl<C: RawCollectorImpl> Clone for CollectorId<C> {
117124
#[inline]

libs/context/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ unsafe impl<C: RawCollectorImpl> GcContext for CollectorContext<C> {
211211
})
212212
}
213213

214+
#[inline]
215+
fn system(&self) -> &'_ Self::System {
216+
unsafe { (&*self.raw).collector_ref() }
217+
}
218+
214219
#[inline]
215220
fn id(&self) -> Self::Id {
216221
unsafe { (&*self.raw).collector() }.id()

libs/context/src/state/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,21 @@ pub unsafe trait RawContext<C>: Debug + self::sealed::Sealed
8585
}
8686
/// Get a pointer to the shadow stack
8787
fn shadow_stack_ptr(&self) -> *mut ShadowStack<C>;
88+
/// Get a reference to the collector as a [CollectorRef]
89+
///
90+
/// ## Safety
91+
/// Assumes the underlying collector is still valid.
92+
unsafe fn collector_ref(&self) -> &'_ CollectorRef<C>;
8893
/// Get a reference to the collector,
8994
/// assuming that it's valid
9095
///
9196
/// ## Safety
9297
/// Assumes that the underlying collector
9398
/// is still valid.
94-
unsafe fn collector(&self) -> &C;
99+
#[inline]
100+
unsafe fn collector(&self) -> &C {
101+
self.collector_ref().as_raw()
102+
}
95103
fn state(&self) -> ContextState;
96104
}
97105

libs/context/src/state/nosync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ unsafe impl<C> super::RawContext<C> for RawContext<C>
188188
}
189189

190190
#[inline]
191-
unsafe fn collector(&self) -> &C {
192-
self.collector.as_raw()
191+
unsafe fn collector_ref(&self) -> &CollectorRef<C> {
192+
&self.collector
193193
}
194194

195195
#[inline]

libs/context/src/state/sync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ unsafe impl<C> super::RawContext<C> for RawContext<C>
296296
}
297297

298298
#[inline]
299-
unsafe fn collector(&self) -> &C {
300-
self.collector.as_raw()
299+
unsafe fn collector_ref(&self) -> &CollectorRef<C> {
300+
&self.collector
301301
}
302302

303303
#[inline]

libs/derive/tests/basic.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![feature(
22
arbitrary_self_types, // Used for `zerogc(mutable)`
33
)]
4-
use zerogc::{Gc, CollectorId, Trace, GcSafe, NullTrace, dummy_impl::{self, DummyCollectorId}};
4+
use zerogc::{Gc, CollectorId, Trace, GcSafe, NullTrace, epsilon::{self, EpsilonCollectorId}};
55

66
use zerogc_derive::{Trace, NullTrace};
77
use zerogc::cell::GcCell;
@@ -10,10 +10,10 @@ use std::marker::PhantomData;
1010
#[derive(Trace)]
1111
#[zerogc(collector_ids(DummyCollectorId))]
1212
pub struct SpecificCollector<'gc> {
13-
gc: Gc<'gc, i32, DummyCollectorId>,
14-
rec: Gc<'gc, SpecificCollector<'gc>, DummyCollectorId>,
13+
gc: Gc<'gc, i32, EpsilonCollectorId>,
14+
rec: Gc<'gc, SpecificCollector<'gc>, EpsilonCollectorId>,
1515
#[zerogc(mutable)]
16-
cell: GcCell<Gc<'gc, SpecificCollector<'gc>, DummyCollectorId>>
16+
cell: GcCell<Gc<'gc, SpecificCollector<'gc>, EpsilonCollectorId>>
1717
}
1818

1919
#[derive(Trace)]
@@ -98,13 +98,13 @@ struct UnsafeSkipped<'gc> {
9898
s: &'static str,
9999
i: i32,
100100
#[zerogc(unsafe_skip_trace)]
101-
wow: Gc<'gc, i32, DummyCollectorId>
101+
wow: Gc<'gc, i32, EpsilonCollectorId>
102102
}
103103

104104
#[derive(Trace)]
105105
#[zerogc(ignore_lifetimes("'a"), immutable, collector_ids(DummyCollectorId))]
106106
#[allow(unused)]
107-
struct LifetimeTrace<'a: 'gc, 'gc, T: GcSafe<'gc, DummyCollectorId> + 'a> {
107+
struct LifetimeTrace<'a: 'gc, 'gc, T: GcSafe<'gc, EpsilonCollectorId> + 'a> {
108108
s: String,
109109
i: i32,
110110
wow: Box<NopTrace>,
@@ -115,21 +115,21 @@ struct LifetimeTrace<'a: 'gc, 'gc, T: GcSafe<'gc, DummyCollectorId> + 'a> {
115115

116116
#[test]
117117
fn basic<'gc>() {
118-
let _b = Basic::<dummy_impl::DummyCollectorId> {
118+
let _b = Basic::<epsilon::EpsilonCollectorId> {
119119
value: String::new(),
120120
parent: None,
121121
children: vec![],
122122
cell: GcCell::new(None)
123123
};
124-
assert!(<Basic::<dummy_impl::DummyCollectorId> as Trace>::NEEDS_TRACE);
125-
assert!(<BasicCopy::<dummy_impl::DummyCollectorId> as Trace>::NEEDS_TRACE);
126-
assert!(<Basic::<dummy_impl::DummyCollectorId> as Trace>::NEEDS_DROP);
127-
assert!(!<BasicCopy::<dummy_impl::DummyCollectorId> as Trace>::NEEDS_DROP);
128-
assert_copy::<BasicCopy::<dummy_impl::DummyCollectorId>>();
124+
assert!(<Basic::<epsilon::EpsilonCollectorId> as Trace>::NEEDS_TRACE);
125+
assert!(<BasicCopy::<epsilon::EpsilonCollectorId> as Trace>::NEEDS_TRACE);
126+
assert!(<Basic::<epsilon::EpsilonCollectorId> as Trace>::NEEDS_DROP);
127+
assert!(!<BasicCopy::<epsilon::EpsilonCollectorId> as Trace>::NEEDS_DROP);
128+
assert_copy::<BasicCopy::<epsilon::EpsilonCollectorId>>();
129129
assert_null_trace::<NopTrace>();
130130
assert!(!<NopTrace as Trace>::NEEDS_TRACE);
131131

132-
check_id::<dummy_impl::DummyCollectorId>();
132+
check_id::<epsilon::EpsilonCollectorId>();
133133

134134
// We explicitly skipped the only trace field
135135
assert!(!<UnsafeSkipped<'gc> as Trace>::NEEDS_TRACE);

libs/derive/tests/deserialize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ use zerogc_derive::{GcDeserialize, Trace};
22

33
use zerogc::SimpleAllocCollectorId;
44
use zerogc::prelude::*;
5-
use zerogc::dummy_impl::{DummyCollectorId};
5+
use zerogc::epsilon::{EpsilonCollectorId};
66

77
#[derive(Trace, GcDeserialize)]
88
#[zerogc(collector_ids(DummyCollectorId))]
99
struct BasicDeserialize<'gc> {
10-
test: Gc<'gc, String, DummyCollectorId>
10+
test: Gc<'gc, String, EpsilonCollectorId>
1111
}
1212

1313
#[derive(Trace, GcDeserialize)]

libs/simple/src/layout.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,11 @@ impl<'gc, T: GcSafe<'gc, crate::CollectorId>> SimpleVecRepr<'gc, T> {
266266
#[inline]
267267
fn header(&self) -> *mut GcVecHeader {
268268
unsafe {
269+
/*
270+
* TODO: what if we have a non-standard alignment?\
271+
* Our `T` is erased at runtime....
272+
* this is a bug in the epsilon collector too
273+
*/
269274
(self as *const Self as *mut Self as *mut u8)
270275
.sub(GcVecHeader::LAYOUT.value_offset(std::mem::align_of::<T>()))
271276
.cast()
@@ -279,7 +284,14 @@ unsafe impl<'gc, T: GcSafe<'gc, crate::CollectorId>> GcVecRepr<'gc> for SimpleVe
279284

280285
#[inline]
281286
fn element_layout(&self) -> Layout {
282-
Layout::new::<T>()
287+
unsafe {
288+
match (*self.header()).common_header.type_info.layout {
289+
GcTypeLayout::Vec {
290+
element_layout, ..
291+
} => element_layout,
292+
_ => std::hint::unreachable_unchecked()
293+
}
294+
}
283295
}
284296

285297
#[inline]

src/dummy_impl.rs

Lines changed: 0 additions & 181 deletions
This file was deleted.

0 commit comments

Comments
 (0)