use crate::plan::is_nursery_gc;
use crate::plan::tracing::gc_work::DefaultObjectTracerContext;
use crate::plan::tracing::Trace;
use crate::scheduler::{GCWork, GCWorker, WorkBucketStage};
use crate::util::reference_processor::RescanReferences;
use crate::util::ObjectReference;
use crate::util::VMWorkerThread;
use crate::vm::{Collection, ObjectTracer, VMBinding};
use crate::vm::{Finalizable, ObjectTracerContext};
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<OT: ObjectTracer>(tracer: &mut OT, finalizable: &mut F) {
finalizable.keep_alive::<OT>(tracer);
}
pub fn scan<VM: VMBinding, OT: ObjectTracer>(
&mut self,
tls: VMWorkerThread,
tracer: &mut OT,
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(tracer, &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(tracer, nursery);
self.nursery_index = self.candidates.len();
VM::VMCollection::schedule_finalization(tls);
}
pub fn forward_candidate<OT: ObjectTracer>(&mut self, tracer: &mut OT, _nursery: bool) {
self.candidates
.iter_mut()
.for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(tracer, f));
}
pub fn forward_finalizable<OT: ObjectTracer>(&mut self, tracer: &mut OT, _nursery: bool) {
self.ready_for_finalize
.iter_mut()
.for_each(|f| FinalizableProcessor::<F>::forward_finalizable_reference(tracer, f));
}
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<T: Trace>(PhantomData<T>);
impl<T: Trace> GCWork<T::VM> for Finalization<T> {
fn do_work(&mut self, worker: &mut GCWorker<T::VM>, mmtk: &'static MMTK<T::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();
let num_candidates_begin = finalizable_processor.candidates.len();
let num_ready_for_finalize_begin = finalizable_processor.ready_for_finalize.len();
debug!(
"Finalization, {} objects in candidates, {} objects ready to finalize",
num_candidates_begin, num_ready_for_finalize_begin
);
let tracer_context = DefaultObjectTracerContext::<T>::new(WorkBucketStage::FinalRefClosure);
let tls = worker.tls;
tracer_context.with_tracer(worker, |tracer| {
finalizable_processor.scan::<T::VM, _>(tls, tracer, is_nursery_gc(mmtk.get_plan()));
});
let num_candidates_end = finalizable_processor.candidates.len();
let num_ready_for_finalize_end = finalizable_processor.ready_for_finalize.len();
debug!(
"Finished finalization, {} objects in candidates, {} objects ready to finalize",
num_candidates_end, num_ready_for_finalize_end
);
probe!(
mmtk,
finalization,
num_candidates_begin,
num_candidates_end,
num_ready_for_finalize_begin,
num_ready_for_finalize_end
);
}
}
impl<T: Trace> Finalization<T> {
pub fn new() -> Self {
Self(PhantomData)
}
}
#[derive(Default)]
pub struct ForwardFinalization<T: Trace>(PhantomData<T>);
impl<T: Trace> GCWork<T::VM> for ForwardFinalization<T> {
fn do_work(&mut self, worker: &mut GCWorker<T::VM>, mmtk: &'static MMTK<T::VM>) {
trace!("Forward finalization");
let mut finalizable_processor = mmtk.finalizable_processor.lock().unwrap();
let tracer_context =
DefaultObjectTracerContext::<T>::new(WorkBucketStage::FinalizableForwarding);
tracer_context.with_tracer(worker, |tracer| {
finalizable_processor.forward_candidate(tracer, is_nursery_gc(mmtk.get_plan()));
finalizable_processor.forward_finalizable(tracer, is_nursery_gc(mmtk.get_plan()));
});
trace!("Finished forwarding finlizable");
}
}
impl<T: Trace> ForwardFinalization<T> {
pub fn new() -> Self {
Self(PhantomData)
}
}