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