use std::marker::PhantomData;
use crate::{
plan::{
tracing::{
gc_work::closure::{ProcessNodes, ProcessSlots},
Trace,
},
VectorObjectQueue,
},
scheduler::{GCWork, GCWorker, WorkBucketStage},
util::ObjectReference,
vm::{RootsKind, RootsWorkFactory, VMBinding},
MMTK,
};
pub(crate) struct DefaultRootsWorkFactory<VM: VMBinding, DT: Trace<VM = VM>, PT: Trace<VM = VM>> {
pub(crate) mmtk: &'static MMTK<VM>,
phantom: PhantomData<(DT, PT)>,
}
impl<VM: VMBinding, DT: Trace<VM = VM>, PT: Trace<VM = VM>> Clone
for DefaultRootsWorkFactory<VM, DT, PT>
{
fn clone(&self) -> Self {
Self {
mmtk: self.mmtk,
phantom: PhantomData,
}
}
}
impl<VM: VMBinding, DT: Trace<VM = VM>, PT: Trace<VM = VM>> RootsWorkFactory<VM::VMSlot>
for DefaultRootsWorkFactory<VM, DT, PT>
{
fn create_process_roots_work(&mut self, slots: Vec<VM::VMSlot>) {
probe!(mmtk, roots, RootsKind::NORMAL, slots.len());
#[cfg(feature = "sanity")]
self.mmtk
.sanity_checker
.lock()
.unwrap()
.add_root_slots(slots.clone());
crate::memory_manager::add_work_packet(
self.mmtk,
WorkBucketStage::Closure,
ProcessSlots::<DT>::new(slots, WorkBucketStage::Closure),
);
}
fn create_process_pinning_roots_work(&mut self, nodes: Vec<ObjectReference>) {
probe!(mmtk, roots, RootsKind::PINNING, nodes.len());
#[cfg(feature = "sanity")]
self.mmtk
.sanity_checker
.lock()
.unwrap()
.add_root_nodes(nodes.clone());
crate::memory_manager::add_work_packet(
self.mmtk,
WorkBucketStage::PinningRootsTrace,
ProcessPinningRoots::<VM, PT, DT>::new(nodes, WorkBucketStage::Closure),
);
}
fn create_process_tpinning_roots_work(&mut self, nodes: Vec<ObjectReference>) {
probe!(mmtk, roots, RootsKind::TPINNING, nodes.len());
#[cfg(feature = "sanity")]
self.mmtk
.sanity_checker
.lock()
.unwrap()
.add_root_nodes(nodes.clone());
crate::memory_manager::add_work_packet(
self.mmtk,
WorkBucketStage::TPinningClosure,
ProcessPinningRoots::<VM, PT, PT>::new(nodes, WorkBucketStage::TPinningClosure),
);
}
}
impl<VM: VMBinding, DT: Trace<VM = VM>, PT: Trace<VM = VM>> DefaultRootsWorkFactory<VM, DT, PT> {
pub(crate) fn new(mmtk: &'static MMTK<VM>) -> Self {
Self {
mmtk,
phantom: PhantomData,
}
}
}
pub(crate) struct ProcessPinningRoots<VM: VMBinding, R2OT: Trace<VM = VM>, O2OT: Trace<VM = VM>> {
phantom: PhantomData<(VM, R2OT, O2OT)>,
roots: Vec<ObjectReference>,
bucket: WorkBucketStage,
}
impl<VM: VMBinding, R2OT: Trace<VM = VM>, O2OT: Trace<VM = VM>>
ProcessPinningRoots<VM, R2OT, O2OT>
{
pub fn new(nodes: Vec<ObjectReference>, bucket: WorkBucketStage) -> Self {
Self {
phantom: PhantomData,
roots: nodes,
bucket,
}
}
}
impl<VM: VMBinding, R2OT: Trace<VM = VM>, O2OT: Trace<VM = VM>> GCWork<VM>
for ProcessPinningRoots<VM, R2OT, O2OT>
{
fn do_work(&mut self, worker: &mut GCWorker<VM>, mmtk: &'static MMTK<VM>) {
trace!("ProcessPinningRoots");
let num_roots = self.roots.len();
let root_objects_to_scan = {
let mut queue = VectorObjectQueue::new();
let r2o_trace = R2OT::from_mmtk(mmtk);
for object in self.roots.iter().copied() {
let new_object = r2o_trace.trace_object(worker, object, &mut queue);
debug_assert_eq!(
object, new_object,
"Object moved while tracing root unmovable root object: {} -> {}",
object, new_object
);
}
queue.take()
};
let num_enqueued_nodes = root_objects_to_scan.len();
probe!(mmtk, process_pinning_roots, num_roots, num_enqueued_nodes);
if !root_objects_to_scan.is_empty() {
let work = ProcessNodes::<O2OT>::new(root_objects_to_scan, self.bucket);
worker.add_work(self.bucket, work);
}
trace!("ProcessPinningRoots End");
}
}