mmtk/scheduler/
gc_work.rs1use super::work_bucket::WorkBucketStage;
2use super::*;
3use crate::global_state::GcStatus;
4use crate::vm::*;
5use crate::*;
6use std::marker::PhantomData;
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.set_gc_status(GcStatus::GcPrepare);
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.scheduler);
235 mmtk.scheduler.notify_mutators_paused(mmtk);
236 if !self.skip_roots {
237 mmtk.scheduler.work_buckets[WorkBucketStage::Prepare]
238 .add(ScanVMSpecificRoots::<C>::new());
239 }
240 }
241}
242
243pub struct ScanMutatorRoots<C: GCWorkContext>(pub &'static mut Mutator<C::VM>);
244
245impl<C: GCWorkContext> GCWork<C::VM> for ScanMutatorRoots<C> {
246 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
247 trace!("ScanMutatorRoots for mutator {:?}", self.0.get_tls());
248 let mutators = <C::VM as VMBinding>::VMActivePlan::number_of_mutators();
249 let factory = C::make_roots_work_factory(mmtk);
250 <C::VM as VMBinding>::VMScanning::scan_roots_in_mutator_thread(
251 worker.tls,
252 unsafe { &mut *(self.0 as *mut _) },
253 factory,
254 );
255 self.0.flush();
256
257 if mmtk.state.inform_stack_scanned(mutators) {
258 <C::VM as VMBinding>::VMScanning::notify_initial_thread_scan_complete(
259 false, worker.tls,
260 );
261 mmtk.set_gc_status(GcStatus::GcProper);
262 }
263 }
264}
265
266#[derive(Default)]
267pub struct ScanVMSpecificRoots<C: GCWorkContext>(PhantomData<C>);
268
269impl<C: GCWorkContext> ScanVMSpecificRoots<C> {
270 pub fn new() -> Self {
271 Self(PhantomData)
272 }
273}
274
275impl<C: GCWorkContext> GCWork<C::VM> for ScanVMSpecificRoots<C> {
276 fn do_work(&mut self, worker: &mut GCWorker<C::VM>, mmtk: &'static MMTK<C::VM>) {
277 trace!("ScanStaticRoots");
278 let factory = C::make_roots_work_factory(mmtk);
279 <C::VM as VMBinding>::VMScanning::scan_vm_specific_roots(worker.tls, factory);
280 }
281}