mmtk/util/
finalizable_processor.rs1use crate::plan::is_nursery_gc;
2use crate::scheduler::gc_work::ProcessEdgesWork;
3use crate::scheduler::{GCWork, GCWorker, WorkBucketStage};
4use crate::util::reference_processor::RescanReferences;
5use crate::util::ObjectReference;
6use crate::util::VMWorkerThread;
7use crate::vm::Finalizable;
8use crate::vm::{Collection, VMBinding};
9use crate::MMTK;
10use std::marker::PhantomData;
11
12#[derive(Default)]
16pub struct FinalizableProcessor<F: Finalizable> {
17 candidates: Vec<F>,
19 nursery_index: usize,
22 ready_for_finalize: Vec<F>,
25}
26
27impl<F: Finalizable> FinalizableProcessor<F> {
28 pub fn new() -> Self {
29 Self {
30 candidates: vec![],
31 nursery_index: 0,
32 ready_for_finalize: vec![],
33 }
34 }
35
36 pub fn add(&mut self, object: F) {
37 self.candidates.push(object);
38 }
39
40 fn forward_finalizable_reference<E: ProcessEdgesWork>(e: &mut E, finalizable: &mut F) {
41 finalizable.keep_alive::<E>(e);
42 }
43
44 pub fn scan<E: ProcessEdgesWork>(&mut self, tls: VMWorkerThread, e: &mut E, nursery: bool) {
45 let start = if nursery { self.nursery_index } else { 0 };
46
47 self.candidates.append(&mut self.ready_for_finalize);
52 debug_assert!(self.ready_for_finalize.is_empty());
53
54 for mut f in self.candidates.drain(start..).collect::<Vec<F>>() {
55 let reff = f.get_reference();
56 trace!("Pop {:?} for finalization", reff);
57 if reff.is_live() {
58 FinalizableProcessor::<F>::forward_finalizable_reference(e, &mut f);
59 trace!("{:?} is live, push {:?} back to candidates", reff, f);
60 self.candidates.push(f);
61 continue;
62 }
63
64 self.ready_for_finalize.push(f);
71 }
72
73 self.forward_finalizable(e, nursery);
75
76 self.nursery_index = self.candidates.len();
78
79 <<E as ProcessEdgesWork>::VM as VMBinding>::VMCollection::schedule_finalization(tls);
80 }
81
82 pub fn forward_candidate<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
83 self.candidates
84 .iter_mut()
85 .for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(e, f));
86 e.flush();
87 }
88
89 pub fn forward_finalizable<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
90 self.ready_for_finalize
91 .iter_mut()
92 .for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(e, f));
93 e.flush();
94 }
95
96 pub fn get_ready_object(&mut self) -> Option<F> {
97 self.ready_for_finalize.pop()
98 }
99
100 pub fn get_all_finalizers(&mut self) -> Vec<F> {
101 let mut ret = std::mem::take(&mut self.candidates);
102 let ready_objects = std::mem::take(&mut self.ready_for_finalize);
103 ret.extend(ready_objects);
104
105 self.nursery_index = 0;
107
108 ret
109 }
110
111 pub fn get_finalizers_for(&mut self, object: ObjectReference) -> Vec<F> {
112 let drain_filter = |vec: &mut Vec<F>| -> Vec<F> {
117 let mut i = 0;
118 let mut ret = vec![];
119 while i < vec.len() {
120 if vec[i].get_reference() == object {
121 let val = vec.remove(i);
122 ret.push(val);
123 } else {
124 i += 1;
125 }
126 }
127 ret
128 };
129 let mut ret: Vec<F> = drain_filter(&mut self.candidates);
130 ret.extend(drain_filter(&mut self.ready_for_finalize));
131
132 self.nursery_index = 0;
134
135 ret
136 }
137}
138
139#[derive(Default)]
140pub struct Finalization<E: ProcessEdgesWork>(PhantomData<E>);
141
142impl<E: ProcessEdgesWork> GCWork<E::VM> for Finalization<E> {
143 fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
144 if !*mmtk.options.no_reference_types {
145 let rescan = Box::new(RescanReferences {
148 soft: true,
149 weak: true,
150 phantom_data: PhantomData,
151 });
152 worker.scheduler().work_buckets[WorkBucketStage::FinalRefClosure].set_sentinel(rescan);
153 }
154
155 let mut finalizable_processor = mmtk.finalizable_processor.lock().unwrap();
156 let num_candidates_begin = finalizable_processor.candidates.len();
157 let num_ready_for_finalize_begin = finalizable_processor.ready_for_finalize.len();
158 debug!(
159 "Finalization, {} objects in candidates, {} objects ready to finalize",
160 num_candidates_begin, num_ready_for_finalize_begin
161 );
162
163 let mut w = E::new(vec![], false, mmtk, WorkBucketStage::FinalRefClosure);
164 w.set_worker(worker);
165 finalizable_processor.scan(worker.tls, &mut w, is_nursery_gc(mmtk.get_plan()));
166
167 let num_candidates_end = finalizable_processor.candidates.len();
168 let num_ready_for_finalize_end = finalizable_processor.ready_for_finalize.len();
169
170 debug!(
171 "Finished finalization, {} objects in candidates, {} objects ready to finalize",
172 num_candidates_end, num_ready_for_finalize_end
173 );
174 probe!(
175 mmtk,
176 finalization,
177 num_candidates_begin,
178 num_candidates_end,
179 num_ready_for_finalize_begin,
180 num_ready_for_finalize_end
181 );
182 }
183}
184impl<E: ProcessEdgesWork> Finalization<E> {
185 pub fn new() -> Self {
186 Self(PhantomData)
187 }
188}
189
190#[derive(Default)]
191pub struct ForwardFinalization<E: ProcessEdgesWork>(PhantomData<E>);
192
193impl<E: ProcessEdgesWork> GCWork<E::VM> for ForwardFinalization<E> {
194 fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
195 trace!("Forward finalization");
196 let mut finalizable_processor = mmtk.finalizable_processor.lock().unwrap();
197 let mut w = E::new(vec![], false, mmtk, WorkBucketStage::FinalizableForwarding);
198 w.set_worker(worker);
199 finalizable_processor.forward_candidate(&mut w, is_nursery_gc(mmtk.get_plan()));
200
201 finalizable_processor.forward_finalizable(&mut w, is_nursery_gc(mmtk.get_plan()));
202 trace!("Finished forwarding finlizable");
203 }
204}
205impl<E: ProcessEdgesWork> ForwardFinalization<E> {
206 pub fn new() -> Self {
207 Self(PhantomData)
208 }
209}