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
8pub struct ScheduleCollection;
9
10impl<VM: VMBinding> GCWork<VM> for ScheduleCollection {
11 fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
12 mmtk.gc_trigger.policy.on_gc_start(mmtk);
14
15 let is_emergency = mmtk.state.set_collection_kind(
17 mmtk.get_plan().last_collection_was_exhaustive(),
18 mmtk.gc_trigger.policy.can_heap_size_grow(),
19 );
20 if is_emergency {
21 mmtk.get_plan().notify_emergency_collection();
22 }
23 mmtk.state.stacks_prepared.store(false, Ordering::SeqCst);
24 mmtk.stats.start_gc();
28
29 mmtk.get_plan().schedule_collection(worker.scheduler());
31 }
32}
33
34pub struct Prepare<C: GCWorkContext> {
42 pub plan: *const C::PlanType,
43}
44
45unsafe impl<C: GCWorkContext> Send for Prepare<C> {}
46
47impl<C: GCWorkContext> Prepare<C> {
48 pub fn new(plan: *const C::PlanType) -> Self {
49 Self { plan }
50 }
51}
52
53impl<C: GCWorkContext> GCWork<C::VM> for Prepare<C> {
54 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
55 trace!("Prepare Global");
56 let plan_mut: &mut C::PlanType = unsafe { &mut *(self.plan as *const _ as *mut _) };
58 plan_mut.prepare(worker.tls);
59
60 if plan_mut.constraints().needs_prepare_mutator {
61 let prepare_mutator_packets = <C::VM as VMBinding>::VMActivePlan::mutators()
62 .map(|mutator| Box::new(PrepareMutator::<C::VM>::new(mutator)) as _)
63 .collect::<Vec<_>>();
64 debug_assert_eq!(
66 prepare_mutator_packets.len(),
67 <C::VM as VMBinding>::VMActivePlan::number_of_mutators()
68 );
69 mmtk.scheduler.work_buckets[WorkBucketStage::Prepare].bulk_add(prepare_mutator_packets);
70 }
71
72 for w in &mmtk.scheduler.worker_group.workers_shared {
73 let result = w.designated_work.push(Box::new(PrepareCollector));
74 debug_assert!(result.is_ok());
75 }
76 }
77}
78
79pub struct PrepareMutator<VM: VMBinding> {
81 pub mutator: &'static mut Mutator<VM>,
84}
85
86impl<VM: VMBinding> PrepareMutator<VM> {
87 pub fn new(mutator: &'static mut Mutator<VM>) -> Self {
88 Self { mutator }
89 }
90}
91
92impl<VM: VMBinding> GCWork<VM> for PrepareMutator<VM> {
93 fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
94 trace!("Prepare Mutator");
95 self.mutator.prepare(worker.tls);
96 }
97}
98
99#[derive(Default)]
101pub struct PrepareCollector;
102
103impl<VM: VMBinding> GCWork<VM> for PrepareCollector {
104 fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
105 trace!("Prepare Collector");
106 worker.get_copy_context_mut().prepare();
107 mmtk.get_plan().prepare_worker(worker);
108 }
109}
110
111pub struct Release<C: GCWorkContext> {
119 pub plan: *const C::PlanType,
120}
121
122impl<C: GCWorkContext> Release<C> {
123 pub fn new(plan: *const C::PlanType) -> Self {
124 Self { plan }
125 }
126}
127
128unsafe impl<C: GCWorkContext> Send for Release<C> {}
129
130impl<C: GCWorkContext + 'static> GCWork<C::VM> for Release<C> {
131 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
132 trace!("Release Global");
133
134 mmtk.gc_trigger.policy.on_gc_release(mmtk);
135 let plan_mut: &mut C::PlanType = unsafe { &mut *(self.plan as *const _ as *mut _) };
138 plan_mut.release(worker.tls);
139
140 let release_mutator_packets = <C::VM as VMBinding>::VMActivePlan::mutators()
141 .map(|mutator| Box::new(ReleaseMutator::<C::VM>::new(mutator)) as _)
142 .collect::<Vec<_>>();
143 debug_assert_eq!(
145 release_mutator_packets.len(),
146 <C::VM as VMBinding>::VMActivePlan::number_of_mutators()
147 );
148 mmtk.scheduler.work_buckets[WorkBucketStage::Release].bulk_add(release_mutator_packets);
149
150 for w in &mmtk.scheduler.worker_group.workers_shared {
151 let result = w.designated_work.push(Box::new(ReleaseCollector));
152 debug_assert!(result.is_ok());
153 }
154 }
155}
156
157pub struct ReleaseMutator<VM: VMBinding> {
159 pub mutator: &'static mut Mutator<VM>,
162}
163
164impl<VM: VMBinding> ReleaseMutator<VM> {
165 pub fn new(mutator: &'static mut Mutator<VM>) -> Self {
166 Self { mutator }
167 }
168}
169
170impl<VM: VMBinding> GCWork<VM> for ReleaseMutator<VM> {
171 fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
172 trace!("Release Mutator");
173 self.mutator.release(worker.tls);
174 }
175}
176
177#[derive(Default)]
179pub struct ReleaseCollector;
180
181impl<VM: VMBinding> GCWork<VM> for ReleaseCollector {
182 fn do_work(&mut self, worker: &mut GCWorker<VM>, _mmtk: &'static MMTK<VM>) {
183 trace!("Release Collector");
184 worker.get_copy_context_mut().release();
185 }
186}
187
188#[derive(Default)]
192pub struct StopMutators<C: GCWorkContext> {
193 skip_roots: bool,
196 flush_mutator: bool,
198 phantom: PhantomData<C>,
199}
200
201impl<C: GCWorkContext> StopMutators<C> {
202 pub fn new() -> Self {
203 Self {
204 skip_roots: false,
205 flush_mutator: false,
206 phantom: PhantomData,
207 }
208 }
209
210 pub fn new_no_scan_roots() -> Self {
212 Self {
213 skip_roots: true,
214 flush_mutator: true,
215 phantom: PhantomData,
216 }
217 }
218}
219
220impl<C: GCWorkContext> GCWork<C::VM> for StopMutators<C> {
221 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
222 trace!("stop_all_mutators start");
223 mmtk.state.prepare_for_stack_scanning();
224 <C::VM as VMBinding>::VMCollection::stop_all_mutators(worker.tls, |mutator| {
225 if self.flush_mutator {
229 mutator.flush();
230 }
231 if !self.skip_roots {
232 mmtk.scheduler.work_buckets[WorkBucketStage::Prepare]
233 .add(ScanMutatorRoots::<C>(mutator));
234 }
235 });
236 trace!("stop_all_mutators end");
237 mmtk.get_plan().notify_mutators_paused(&mmtk.scheduler);
238 mmtk.scheduler.notify_mutators_paused(mmtk);
239 if !self.skip_roots {
240 mmtk.scheduler.work_buckets[WorkBucketStage::Prepare]
241 .add(ScanVMSpecificRoots::<C>::new());
242 }
243 }
244}
245
246pub struct ScanMutatorRoots<C: GCWorkContext>(pub &'static mut Mutator<C::VM>);
247
248impl<C: GCWorkContext> GCWork<C::VM> for ScanMutatorRoots<C> {
249 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
250 trace!("ScanMutatorRoots for mutator {:?}", self.0.get_tls());
251 let mutators = <C::VM as VMBinding>::VMActivePlan::number_of_mutators();
252 let factory = C::make_roots_work_factory(mmtk);
253 <C::VM as VMBinding>::VMScanning::scan_roots_in_mutator_thread(
254 worker.tls,
255 unsafe { &mut *(self.0 as *mut _) },
256 factory,
257 );
258 self.0.flush();
259
260 if mmtk.state.inform_stack_scanned(mutators) {
261 <C::VM as VMBinding>::VMScanning::notify_initial_thread_scan_complete(
262 false, worker.tls,
263 );
264 }
265 }
266}
267
268#[derive(Default)]
269pub struct ScanVMSpecificRoots<C: GCWorkContext>(PhantomData<C>);
270
271impl<C: GCWorkContext> ScanVMSpecificRoots<C> {
272 pub fn new() -> Self {
273 Self(PhantomData)
274 }
275}
276
277impl<C: GCWorkContext> GCWork<C::VM> for ScanVMSpecificRoots<C> {
278 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
279 trace!("ScanStaticRoots");
280 let factory = C::make_roots_work_factory(mmtk);
281 <C::VM as VMBinding>::VMScanning::scan_vm_specific_roots(worker.tls, factory);
282 }
283}