Skip to content

Commit 1bad3c5

Browse files
committed
Add a default feature-flag for "multiple-collectors"
If this is off, than `SimpleCollector` is a global singleton. Gc pointers don't need to store a reference to their owning collector, so they should be just a single thin pointer. Make `Gc` pointer repr(C), since DuckLogic will rely on the assumption it's represented just like a simple pointer. Outside of safepoints, that's all it really is ;)
1 parent 21a5e21 commit 1bad3c5

File tree

6 files changed

+279
-133
lines changed

6 files changed

+279
-133
lines changed

libs/simple/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ serde = { version = "1", optional = true }
2424
default = [
2525
"small-object-arenas", # Without this, allocating small objects is slow
2626
"sync", # Thread-safety by default
27+
"multiple-collectors", # By default, allow multiple collectors
2728
]
2829
# Use very fast dedicated arenas for small objects.
2930
# This makes allocation much faster
@@ -44,6 +45,12 @@ implicit-grey-stack = []
4445
#
4546
# This can increase overhead by requiring communication between threads.
4647
sync = []
48+
# Allow multiple collectors to exist at once
49+
# Otherwise, there's a single global collector (useful in VMs)
50+
#
51+
# Even if multiple collectors are enabled, pointers from
52+
# one collector can't be safely mixed with other collectors.
53+
multiple-collectors = []
4754

4855
[dev-dependencies]
4956
# Used for examples :)

libs/simple/src/context/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl SimpleCollectorContext {
9696
pub(crate) unsafe fn from_collector(collector: &SimpleCollector) -> Self {
9797
SimpleCollectorContext {
9898
raw: Box::into_raw(ManuallyDrop::into_inner(
99-
RawContext::from_collector(collector.0.clone())
99+
RawContext::from_collector(collector.internal_clone())
100100
)),
101101
root: true // We are the exclusive owner
102102
}
@@ -105,14 +105,14 @@ impl SimpleCollectorContext {
105105
pub(crate) unsafe fn register_root(collector: &SimpleCollector) -> Self {
106106
SimpleCollectorContext {
107107
raw: Box::into_raw(ManuallyDrop::into_inner(
108-
RawContext::register_new(&collector.0)
108+
RawContext::register_new(&collector)
109109
)),
110110
root: true, // We are responsible for unregistering
111111
}
112112
}
113113
#[inline]
114114
pub(crate) fn collector(&self) -> &RawSimpleCollector {
115-
unsafe { &(*self.raw).collector }
115+
unsafe { &(*self.raw).collector.as_raw() }
116116
}
117117
#[inline(always)]
118118
unsafe fn with_shadow_stack<R, T: Trace>(
@@ -160,18 +160,18 @@ unsafe impl GcContext for SimpleCollectorContext {
160160
#[inline]
161161
unsafe fn basic_safepoint<T: Trace>(&mut self, value: &mut &mut T) {
162162
debug_assert_eq!((*self.raw).state.get(), ContextState::Active);
163-
if (*self.raw).collector.should_collect() {
163+
if (*self.raw).collector.as_raw().should_collect() {
164164
self.trigger_basic_safepoint(value);
165165
}
166166
debug_assert_eq!((*self.raw).state.get(), ContextState::Active);
167167
}
168168

169169
unsafe fn freeze(&mut self) {
170-
(*self.raw).collector.manager.freeze_context(&*self.raw);
170+
(*self.raw).collector.as_raw().manager.freeze_context(&*self.raw);
171171
}
172172

173173
unsafe fn unfreeze(&mut self) {
174-
(*self.raw).collector.manager.unfreeze_context(&*self.raw);
174+
(*self.raw).collector.as_raw().manager.unfreeze_context(&*self.raw);
175175
}
176176

177177
#[inline]

libs/simple/src/context/simple.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::cell::{Cell, UnsafeCell, RefCell};
88

99
use slog::{Logger, FnValue, trace, o};
1010

11-
use crate::{RawSimpleCollector};
11+
use crate::{RawSimpleCollector, SimpleCollector};
1212
use std::mem::ManuallyDrop;
1313
use std::fmt::{self, Debug, Formatter};
1414
use crate::context::{ShadowStack, ContextState};
@@ -67,7 +67,7 @@ pub struct RawContext {
6767
///
6868
/// This is still an Arc for easier use alongside the
6969
/// thread-safe implementation
70-
pub(crate) collector: Arc<RawSimpleCollector>,
70+
pub(crate) collector: SimpleCollector,
7171
// NOTE: We are Send, not Sync
7272
pub(super) shadow_stack: UnsafeCell<ShadowStack>,
7373
// TODO: Does the collector access this async?
@@ -91,7 +91,7 @@ impl Debug for RawContext {
9191
}
9292
}
9393
impl RawContext {
94-
pub(crate) unsafe fn from_collector(collector: Arc<RawSimpleCollector>) -> ManuallyDrop<Box<Self>> {
94+
pub(crate) unsafe fn from_collector(collector: SimpleCollector) -> ManuallyDrop<Box<Self>> {
9595
assert!(
9696
!collector.manager.has_existing_context
9797
.replace(true),

libs/simple/src/context/sync.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use std::sync::{Arc};
21
use std::cell::{Cell, UnsafeCell};
32
use std::sync::atomic::{Ordering, AtomicBool};
43

54
use slog::{Logger, FnValue, trace, Drain, o};
65

7-
use crate::{RawSimpleCollector};
6+
use crate::{RawSimpleCollector, SimpleCollector};
87
use crate::utils::ThreadId;
98
use std::mem::ManuallyDrop;
109
use std::fmt::{Debug, Formatter};
@@ -96,15 +95,15 @@ impl CollectionManager {
9695
* context's shadow stack, so unfreezing it while in progress
9796
* could trigger undefined behavior!!!!!
9897
*/
99-
context.collector.prevent_collection(|_| {
98+
context.collector.as_raw().prevent_collection(|_| {
10099
assert_eq!(context.state.get(), ContextState::Frozen);
101100
context.state.set(ContextState::Active);
102101
})
103102
}
104103
}
105104

106105
pub struct RawContext {
107-
pub(crate) collector: Arc<RawSimpleCollector>,
106+
pub(crate) collector: SimpleCollector,
108107
original_thread: ThreadId,
109108
// NOTE: We are Send, not Sync
110109
pub(super) shadow_stack: UnsafeCell<ShadowStack>,
@@ -129,26 +128,26 @@ impl Debug for RawContext {
129128
}
130129
}
131130
impl RawContext {
132-
pub(crate) unsafe fn register_new(collector: &Arc<RawSimpleCollector>) -> ManuallyDrop<Box<Self>> {
133-
let original_thread = if collector.logger.is_trace_enabled() {
131+
pub(crate) unsafe fn register_new(collector: &SimpleCollector) -> ManuallyDrop<Box<Self>> {
132+
let original_thread = if collector.as_raw().logger.is_trace_enabled() {
134133
ThreadId::current()
135134
} else {
136135
ThreadId::Nop
137136
};
138137
let mut context = ManuallyDrop::new(Box::new(RawContext {
139-
collector: collector.clone(),
138+
collector: collector.clone_internal(),
140139
original_thread: original_thread.clone(),
141-
logger: collector.logger.new(o!(
140+
logger: collector.as_raw().logger.new(o!(
142141
"original_thread" => original_thread.clone()
143142
)),
144143
shadow_stack: UnsafeCell::new(ShadowStack {
145144
last: std::ptr::null_mut(),
146145
}),
147146
state: Cell::new(ContextState::Active)
148147
}));
149-
let old_num_total = collector.add_context(&mut **context);
148+
let old_num_total = collector.as_raw().add_context(&mut **context);
150149
trace!(
151-
collector.logger, "Creating new context";
150+
collector.as_raw().logger, "Creating new context";
152151
"ptr" => format_args!("{:p}", &**context),
153152
"old_num_total" => old_num_total,
154153
"current_thread" => &original_thread
@@ -171,11 +170,12 @@ impl RawContext {
171170
* This assumes that parking_lot priorities pending writes
172171
* over pending reads. The standard library doesn't guarantee this.
173172
*/
174-
let mut guard = self.collector.state.write();
173+
let collector = self.collector.as_raw();
174+
let mut guard = collector.state.write();
175175
let state = &mut *guard;
176176
// If there is not a active `PendingCollection` - create one
177177
if state.pending.is_none() {
178-
assert!(!self.collector.manager.collecting.compare_and_swap(
178+
assert!(!collector.manager.collecting.compare_and_swap(
179179
false, true, Ordering::SeqCst
180180
));
181181
let id = state.next_pending_id();
@@ -236,7 +236,7 @@ impl RawContext {
236236
"state" => ?pending.state,
237237
"collector_id" => expected_id
238238
);
239-
self.collector.await_collection(
239+
collector.await_collection(
240240
expected_id, ptr, guard,
241241
|state, contexts| {
242242
let pending = state.pending.as_mut().unwrap();
@@ -247,20 +247,20 @@ impl RawContext {
247247
trace!(
248248
self.logger, "Beginning simple collection";
249249
"current_thread" => FnValue(|_| ThreadId::current()),
250-
"original_size" => self.collector.heap.allocator.allocated_size(),
250+
"original_size" => collector.heap.allocator.allocated_size(),
251251
"contexts" => ?contexts,
252252
"total_contexts" => pending.total_contexts,
253253
"state" => ?pending.state,
254254
"collector_id" => pending.id,
255255
);
256-
self.collector.perform_raw_collection(&contexts);
256+
collector.perform_raw_collection(&contexts);
257257
assert_eq!(
258258
pending.state,
259259
PendingState::InProgress
260260
);
261261
pending.state = PendingState::Finished;
262262
// Now acknowledge that we're finished
263-
self.collector.acknowledge_finished_collection(
263+
collector.acknowledge_finished_collection(
264264
&mut state.pending, ptr
265265
);
266266
}

0 commit comments

Comments
 (0)