use crate::plan::is_nursery_gc;
use crate::scheduler::gc_work::ProcessEdgesWork;
use crate::scheduler::{GCWork, GCWorker, WorkBucketStage};
use crate::util::reference_processor::RescanReferences;
use crate::util::ObjectReference;
use crate::util::VMWorkerThread;
use crate::vm::Finalizable;
use crate::vm::{Collection, VMBinding};
use crate::MMTK;
use std::marker::PhantomData;
#[derive(Default)]
pub struct FinalizableProcessor<F: Finalizable> {
candidates: Vec<F>,
nursery_index: usize,
ready_for_finalize: Vec<F>,
}
impl<F: Finalizable> FinalizableProcessor<F> {
pub fn new() -> Self {
Self {
candidates: vec![],
nursery_index: 0,
ready_for_finalize: vec![],
}
}
pub fn add(&mut self, object: F) {
self.candidates.push(object);
}
fn forward_finalizable_reference<E: ProcessEdgesWork>(e: &mut E, finalizable: &mut F) {
finalizable.keep_alive::<E>(e);
}
pub fn scan<E: ProcessEdgesWork>(&mut self, tls: VMWorkerThread, e: &mut E, nursery: bool) {
let start = if nursery { self.nursery_index } else { 0 };
self.candidates.append(&mut self.ready_for_finalize);
debug_assert!(self.ready_for_finalize.is_empty());
for mut f in self.candidates.drain(start..).collect::<Vec<F>>() {
let reff = f.get_reference();
trace!("Pop {:?} for finalization", reff);
if reff.is_live() {
FinalizableProcessor::<F>::forward_finalizable_reference(e, &mut f);
trace!("{:?} is live, push {:?} back to candidates", reff, f);
self.candidates.push(f);
continue;
}
self.ready_for_finalize.push(f);
}
self.forward_finalizable(e, nursery);
self.nursery_index = self.candidates.len();
<<E as ProcessEdgesWork>::VM as VMBinding>::VMCollection::schedule_finalization(tls);
}
pub fn forward_candidate<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
self.candidates
.iter_mut()
.for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(e, f));
e.flush();
}
pub fn forward_finalizable<E: ProcessEdgesWork>(&mut self, e: &mut E, _nursery: bool) {
self.ready_for_finalize
.iter_mut()
.for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(e, f));
e.flush();
}
pub fn get_ready_object(&mut self) -> Option<F> {
self.ready_for_finalize.pop()
}
pub fn get_all_finalizers(&mut self) -> Vec<F> {
let mut ret = std::mem::take(&mut self.candidates);
let ready_objects = std::mem::take(&mut self.ready_for_finalize);
ret.extend(ready_objects);
self.nursery_index = 0;
ret
}
pub fn get_finalizers_for(&mut self, object: ObjectReference) -> Vec<F> {
let drain_filter = |vec: &mut Vec<F>| -> Vec<F> {
let mut i = 0;
let mut ret = vec![];
while i < vec.len() {
if vec[i].get_reference() == object {
let val = vec.remove(i);
ret.push(val);
} else {
i += 1;
}
}
ret
};
let mut ret: Vec<F> = drain_filter(&mut self.candidates);
ret.extend(drain_filter(&mut self.ready_for_finalize));
self.nursery_index = 0;
ret
}
}
#[derive(Default)]
pub struct Finalization<E: ProcessEdgesWork>(PhantomData<E>);
impl<E: ProcessEdgesWork> GCWork<E::VM> for Finalization<E> {
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
if !*mmtk.options.no_reference_types {
let rescan = Box::new(RescanReferences {
soft: true,
weak: true,
phantom_data: PhantomData,
});
worker.scheduler().work_buckets[WorkBucketStage::FinalRefClosure].set_sentinel(rescan);
}
let mut finalizable_processor = mmtk.finalizable_processor.lock().unwrap();
debug!(
"Finalization, {} objects in candidates, {} objects ready to finalize",
finalizable_processor.candidates.len(),
finalizable_processor.ready_for_finalize.len()
);
let mut w = E::new(vec![], false, mmtk, WorkBucketStage::FinalRefClosure);
w.set_worker(worker);
finalizable_processor.scan(worker.tls, &mut w, is_nursery_gc(mmtk.get_plan()));
debug!(
"Finished finalization, {} objects in candidates, {} objects ready to finalize",
finalizable_processor.candidates.len(),
finalizable_processor.ready_for_finalize.len()
);
}
}
impl<E: ProcessEdgesWork> Finalization<E> {
pub fn new() -> Self {
Self(PhantomData)
}
}
#[derive(Default)]
pub struct ForwardFinalization<E: ProcessEdgesWork>(PhantomData<E>);
impl<E: ProcessEdgesWork> GCWork<E::VM> for ForwardFinalization<E> {
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
trace!("Forward finalization");
let mut finalizable_processor = mmtk.finalizable_processor.lock().unwrap();
let mut w = E::new(vec![], false, mmtk, WorkBucketStage::FinalizableForwarding);
w.set_worker(worker);
finalizable_processor.forward_candidate(&mut w, is_nursery_gc(mmtk.get_plan()));
finalizable_processor.forward_finalizable(&mut w, is_nursery_gc(mmtk.get_plan()));
trace!("Finished forwarding finlizable");
}
}
impl<E: ProcessEdgesWork> ForwardFinalization<E> {
pub fn new() -> Self {
Self(PhantomData)
}
}