mmtk/scheduler/
gc_work.rs1use super::work_bucket::WorkBucketStage;
2use super::*;
3use crate::vm::*;
4use crate::*;
5use std::marker::PhantomData;
6use std::sync::atomic::Ordering;
7
8#[repr(u8)]
11#[derive(Debug, Eq, PartialEq, Clone, Copy)]
12pub enum RootKind {
13 Strong,
16 YoungCodeCacheRoots,
20 Weak,
23}
24
25impl RootKind {
26 pub fn should_record_remset(&self) -> bool {
29 matches!(self, RootKind::YoungCodeCacheRoots)
30 }
31
32 pub fn should_skip_mark_and_decs(&self) -> bool {
34 matches!(self, RootKind::YoungCodeCacheRoots) || matches!(self, RootKind::Weak)
35 }
36
37 pub fn should_skip_decs(&self) -> bool {
39 matches!(self, RootKind::YoungCodeCacheRoots) || matches!(self, RootKind::Weak)
40 }
41}
42
43pub struct ScheduleCollection;
44
45impl<VM: VMBinding> GCWork<VM> for ScheduleCollection {
46 fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
47 let is_emergency = mmtk.state.set_collection_kind(
49 mmtk.get_plan().last_collection_was_exhaustive(),
50 mmtk.gc_trigger.policy.can_heap_size_grow(),
51 );
52 if is_emergency {
53 mmtk.get_plan().notify_emergency_collection();
54 }
55 mmtk.state.stacks_prepared.store(false, Ordering::SeqCst);
56 mmtk.stats.start_gc();
60
61 mmtk.get_plan().schedule_collection(worker.scheduler());
63 }
64}
65
66pub struct Prepare<C: GCWorkContext> {
74 pub plan: *const C::PlanType,
75}
76
77unsafe impl<C: GCWorkContext> Send for Prepare<C> {}
78
79impl<C: GCWorkContext> Prepare<C> {
80 pub fn new(plan: *const C::PlanType) -> Self {
81 Self { plan }
82 }
83}
84
85impl<C: GCWorkContext> GCWork<C::VM> for Prepare<C> {
86 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
87 trace!("Prepare Global");
88 let plan_mut: &mut C::PlanType = unsafe { &mut *(self.plan as *const _ as *mut _) };
90 plan_mut.prepare(worker.tls);
91
92 if plan_mut.constraints().needs_prepare_mutator {
93 let prepare_mutator_packets = <C::VM as VMBinding>::VMActivePlan::mutators()
94 .map(|mutator| Box::new(PrepareMutator::<C::VM>::new(mutator)) as _)
95 .collect::<Vec<_>>();
96 debug_assert_eq!(
98 prepare_mutator_packets.len(),
99 <C::VM as VMBinding>::VMActivePlan::number_of_mutators()
100 );
101 mmtk.scheduler.work_buckets[WorkBucketStage::Prepare].bulk_add(prepare_mutator_packets);
102 }
103
104 for w in &mmtk.scheduler.worker_group.workers_shared {
105 let result = w.designated_work.push(Box::new(PrepareCollector));
106 debug_assert!(result.is_ok());
107 }
108 }
109}
110
111pub struct PrepareMutator<VM: VMBinding> {
113 pub mutator: &'static mut Mutator<VM>,
116}
117
118impl<VM: VMBinding> PrepareMutator<VM> {
119 pub fn new(mutator: &'static mut Mutator<VM>) -> Self {
120 Self { mutator }
121 }
122}
123
124impl<VM: VMBinding> GCWork<VM> for PrepareMutator<VM> {
125 fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
126 trace!("Prepare Mutator");
127 self.mutator.prepare(worker.tls);
128 }
129}
130
131#[derive(Default)]
133pub struct PrepareCollector;
134
135impl<VM: VMBinding> GCWork<VM> for PrepareCollector {
136 fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
137 trace!("Prepare Collector");
138 worker.get_copy_context_mut().prepare();
139 mmtk.get_plan().prepare_worker(worker);
140 }
141}
142
143pub struct Release<C: GCWorkContext> {
151 pub plan: *const C::PlanType,
152}
153
154impl<C: GCWorkContext> Release<C> {
155 pub fn new(plan: *const C::PlanType) -> Self {
156 Self { plan }
157 }
158}
159
160unsafe impl<C: GCWorkContext> Send for Release<C> {}
161
162impl<C: GCWorkContext + 'static> GCWork<C::VM> for Release<C> {
163 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
164 trace!("Release Global");
165
166 mmtk.gc_trigger.policy.on_gc_release(mmtk);
167 let plan_mut: &mut C::PlanType = unsafe { &mut *(self.plan as *const _ as *mut _) };
170 plan_mut.release(worker.tls);
171
172 let release_mutator_packets = <C::VM as VMBinding>::VMActivePlan::mutators()
173 .map(|mutator| Box::new(ReleaseMutator::<C::VM>::new(mutator)) as _)
174 .collect::<Vec<_>>();
175 debug_assert_eq!(
177 release_mutator_packets.len(),
178 <C::VM as VMBinding>::VMActivePlan::number_of_mutators()
179 );
180 mmtk.scheduler.work_buckets[WorkBucketStage::Release].bulk_add(release_mutator_packets);
181
182 for w in &mmtk.scheduler.worker_group.workers_shared {
183 let result = w.designated_work.push(Box::new(ReleaseCollector));
184 debug_assert!(result.is_ok());
185 }
186 }
187}
188
189pub struct ReleaseMutator<VM: VMBinding> {
191 pub mutator: &'static mut Mutator<VM>,
194}
195
196impl<VM: VMBinding> ReleaseMutator<VM> {
197 pub fn new(mutator: &'static mut Mutator<VM>) -> Self {
198 Self { mutator }
199 }
200}
201
202impl<VM: VMBinding> GCWork<VM> for ReleaseMutator<VM> {
203 fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
204 trace!("Release Mutator");
205 self.mutator.release(worker.tls);
206 }
207}
208
209#[derive(Default)]
211pub struct ReleaseCollector;
212
213impl<VM: VMBinding> GCWork<VM> for ReleaseCollector {
214 fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
215 trace!("Release Collector");
216 worker.get_copy_context_mut().release();
217 }
218}
219
220#[derive(Default)]
224pub struct StopMutators<C: GCWorkContext> {
225 skip_mutator_roots: bool,
228 skip_vm_roots: bool,
231 flush_mutator: bool,
233 phantom: PhantomData<C>,
234}
235
236impl<C: GCWorkContext> StopMutators<C> {
237 pub fn new() -> Self {
238 Self {
239 skip_mutator_roots: false,
240 skip_vm_roots: false,
241 flush_mutator: false,
242 phantom: PhantomData,
243 }
244 }
245
246 pub fn new_with_flush() -> Self {
247 let mut me = Self::new();
248 me.flush_mutator = true;
249 me
250 }
251
252 pub fn new_no_scan_roots() -> Self {
254 Self {
255 skip_mutator_roots: true,
256 skip_vm_roots: true,
257 flush_mutator: true,
258 phantom: PhantomData,
259 }
260 }
261}
262
263impl<C: GCWorkContext> GCWork<C::VM> for StopMutators<C> {
264 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
265 trace!("stop_all_mutators start");
266 mmtk.state.prepare_for_stack_scanning();
267 <C::VM as VMBinding>::VMCollection::stop_all_mutators(worker.tls, |mutator| {
268 if self.flush_mutator {
272 mutator.flush();
273 }
274 if !self.skip_mutator_roots {
275 mmtk.scheduler.work_buckets[mmtk.get_plan().root_scanning_stage()]
276 .add(ScanMutatorRoots::<C>(mutator));
277 }
278 });
279 trace!("stop_all_mutators end");
280 mmtk.stats
282 .record_time_to_yield(mmtk.state.take_time_to_yield());
283 mmtk.state.record_pause_start_time();
284 mmtk.get_plan().on_pause_start(mmtk);
286 mmtk.scheduler.notify_mutators_paused(mmtk);
287 mmtk.gc_trigger.policy.on_pause_start(mmtk);
289 if !self.skip_vm_roots {
290 let factory = C::make_roots_work_factory(mmtk);
291 <C::VM as VMBinding>::VMScanning::scan_vm_specific_roots(worker.tls, factory);
292 }
293 }
294}
295
296pub struct ScanMutatorRoots<C: GCWorkContext>(pub &'static mut Mutator<C::VM>);
297
298impl<C: GCWorkContext> GCWork<C::VM> for ScanMutatorRoots<C> {
299 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
300 trace!("ScanMutatorRoots for mutator {:?}", self.0.get_tls());
301 let mutators = <C::VM as VMBinding>::VMActivePlan::number_of_mutators();
302 let factory = C::make_roots_work_factory(mmtk);
303 <C::VM as VMBinding>::VMScanning::scan_roots_in_mutator_thread(
304 worker.tls,
305 unsafe { &mut *(self.0 as *mut _) },
306 factory,
307 );
308 self.0.flush();
309
310 if mmtk.state.inform_stack_scanned(mutators) {
311 <C::VM as VMBinding>::VMScanning::notify_initial_thread_scan_complete(
312 false, worker.tls,
313 );
314 }
315 }
316}
317
318#[derive(Default)]
319pub struct ScanVMSpecificRoots<C: GCWorkContext>(PhantomData<C>);
320
321impl<C: GCWorkContext> ScanVMSpecificRoots<C> {
322 pub fn new() -> Self {
323 Self(PhantomData)
324 }
325}
326
327impl<C: GCWorkContext> GCWork<C::VM> for ScanVMSpecificRoots<C> {
328 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
329 trace!("ScanStaticRoots");
330 let factory = C::make_roots_work_factory(mmtk);
331 <C::VM as VMBinding>::VMScanning::scan_vm_specific_roots(worker.tls, factory);
332 }
333}