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