use crate::plan::Plan;
use crate::scheduler::gc_work::*;
use crate::util::ObjectReference;
use crate::vm::slot::Slot;
use crate::vm::*;
use crate::MMTK;
use crate::{scheduler::*, ObjectQueue};
use std::collections::HashSet;
use std::ops::{Deref, DerefMut};
#[allow(dead_code)]
pub struct SanityChecker<SL: Slot> {
refs: HashSet<ObjectReference>,
root_slots: Vec<Vec<SL>>,
root_nodes: Vec<Vec<ObjectReference>>,
}
impl<SL: Slot> Default for SanityChecker<SL> {
fn default() -> Self {
Self::new()
}
}
impl<SL: Slot> SanityChecker<SL> {
pub fn new() -> Self {
Self {
refs: HashSet::new(),
root_slots: vec![],
root_nodes: vec![],
}
}
pub fn add_root_slots(&mut self, roots: Vec<SL>) {
self.root_slots.push(roots)
}
pub fn add_root_nodes(&mut self, roots: Vec<ObjectReference>) {
self.root_nodes.push(roots)
}
fn clear_roots_cache(&mut self) {
self.root_slots.clear();
self.root_nodes.clear();
}
}
pub struct ScheduleSanityGC<P: Plan> {
_plan: &'static P,
}
impl<P: Plan> ScheduleSanityGC<P> {
pub fn new(plan: &'static P) -> Self {
ScheduleSanityGC { _plan: plan }
}
}
impl<P: Plan> GCWork<P::VM> for ScheduleSanityGC<P> {
fn do_work(&mut self, worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
let scheduler = worker.scheduler();
let plan = mmtk.get_plan();
scheduler.reset_state();
#[cfg(feature = "extreme_assertions")]
mmtk.slot_logger.reset();
mmtk.sanity_begin(); {
let sanity_checker = mmtk.sanity_checker.lock().unwrap();
for roots in &sanity_checker.root_slots {
scheduler.work_buckets[WorkBucketStage::Closure].add(
SanityGCProcessEdges::<P::VM>::new(
roots.clone(),
true,
mmtk,
WorkBucketStage::Closure,
),
);
}
for roots in &sanity_checker.root_nodes {
scheduler.work_buckets[WorkBucketStage::Closure].add(ProcessRootNode::<
P::VM,
SanityGCProcessEdges<P::VM>,
SanityGCProcessEdges<P::VM>,
>::new(
roots.clone(),
WorkBucketStage::Closure,
));
}
}
worker.scheduler().work_buckets[WorkBucketStage::Prepare]
.add(SanityPrepare::<P>::new(plan.downcast_ref::<P>().unwrap()));
worker.scheduler().work_buckets[WorkBucketStage::Release]
.add(SanityRelease::<P>::new(plan.downcast_ref::<P>().unwrap()));
}
}
pub struct SanityPrepare<P: Plan> {
pub plan: &'static P,
}
impl<P: Plan> SanityPrepare<P> {
pub fn new(plan: &'static P) -> Self {
Self { plan }
}
}
impl<P: Plan> GCWork<P::VM> for SanityPrepare<P> {
fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
info!("Sanity GC prepare");
{
let mut sanity_checker = mmtk.sanity_checker.lock().unwrap();
sanity_checker.refs.clear();
}
}
}
pub struct SanityRelease<P: Plan> {
pub plan: &'static P,
}
impl<P: Plan> SanityRelease<P> {
pub fn new(plan: &'static P) -> Self {
Self { plan }
}
}
impl<P: Plan> GCWork<P::VM> for SanityRelease<P> {
fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
info!("Sanity GC release");
mmtk.sanity_checker.lock().unwrap().clear_roots_cache();
mmtk.sanity_end();
}
}
pub struct SanityGCProcessEdges<VM: VMBinding> {
base: ProcessEdgesBase<VM>,
}
impl<VM: VMBinding> Deref for SanityGCProcessEdges<VM> {
type Target = ProcessEdgesBase<VM>;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl<VM: VMBinding> DerefMut for SanityGCProcessEdges<VM> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl<VM: VMBinding> ProcessEdgesWork for SanityGCProcessEdges<VM> {
type VM = VM;
type ScanObjectsWorkType = ScanObjects<Self>;
const OVERWRITE_REFERENCE: bool = false;
fn new(
slots: Vec<SlotOf<Self>>,
roots: bool,
mmtk: &'static MMTK<VM>,
bucket: WorkBucketStage,
) -> Self {
Self {
base: ProcessEdgesBase::new(slots, roots, mmtk, bucket),
}
}
fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
let mut sanity_checker = self.mmtk().sanity_checker.lock().unwrap();
if !sanity_checker.refs.contains(&object) {
assert!(object.is_sane(), "Invalid reference {:?}", object);
assert!(
self.mmtk().get_plan().sanity_check_object(object),
"Invalid reference {:?}",
object
);
assert!(
VM::VMObjectModel::is_object_sane(object),
"Invalid reference {:?}",
object
);
sanity_checker.refs.insert(object); trace!("Sanity mark object {}", object);
self.nodes.enqueue(object);
}
#[cfg(feature = "vo_bit")]
if !crate::util::metadata::vo_bit::is_vo_bit_set(object) {
panic!("VO bit is not set: {}", object);
}
object
}
fn create_scan_work(&self, nodes: Vec<ObjectReference>) -> Self::ScanObjectsWorkType {
ScanObjects::<Self>::new(nodes, false, WorkBucketStage::Closure)
}
}