mmtk/util/sanity/
sanity_checker.rs

1use crate::plan::Plan;
2use crate::scheduler::gc_work::*;
3use crate::util::ObjectReference;
4use crate::vm::slot::Slot;
5use crate::vm::*;
6use crate::MMTK;
7use crate::{scheduler::*, ObjectQueue};
8use std::collections::HashSet;
9use std::ops::{Deref, DerefMut};
10
11#[allow(dead_code)]
12pub struct SanityChecker<SL: Slot> {
13    /// Visited objects
14    refs: HashSet<ObjectReference>,
15    /// Cached root slots for sanity root scanning
16    root_slots: Vec<Vec<SL>>,
17    /// Cached root nodes for sanity root scanning
18    root_nodes: Vec<Vec<ObjectReference>>,
19}
20
21impl<SL: Slot> Default for SanityChecker<SL> {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl<SL: Slot> SanityChecker<SL> {
28    pub fn new() -> Self {
29        Self {
30            refs: HashSet::new(),
31            root_slots: vec![],
32            root_nodes: vec![],
33        }
34    }
35
36    /// Cache a list of root slots to the sanity checker.
37    pub fn add_root_slots(&mut self, roots: Vec<SL>) {
38        debug!("Added {} root slots", roots.len());
39        self.root_slots.push(roots)
40    }
41
42    pub fn add_root_nodes(&mut self, roots: Vec<ObjectReference>) {
43        debug!("Added {} root nodes", roots.len());
44        self.root_nodes.push(roots)
45    }
46
47    /// Reset roots cache at the end of the sanity gc.
48    fn clear_roots_cache(&mut self) {
49        debug!("Cleared roots cache");
50        self.root_slots.clear();
51        self.root_nodes.clear();
52    }
53}
54
55pub struct ScheduleSanityGC<P: Plan> {
56    _plan: &'static P,
57}
58
59impl<P: Plan> ScheduleSanityGC<P> {
60    pub fn new(plan: &'static P) -> Self {
61        ScheduleSanityGC { _plan: plan }
62    }
63}
64
65impl<P: Plan> GCWork<P::VM> for ScheduleSanityGC<P> {
66    fn do_work(&mut self, worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
67        let scheduler = worker.scheduler();
68        let plan = mmtk.get_plan();
69
70        scheduler.reset_state();
71
72        // We are going to do sanity GC which will traverse the object graph again. Reset slot logger to clear recorded slots.
73        #[cfg(feature = "extreme_assertions")]
74        mmtk.slot_logger.reset();
75
76        mmtk.sanity_begin(); // Stop & scan mutators (mutator scanning can happen before STW)
77
78        // We use the cached roots for sanity gc, based on the assumption that
79        // the stack scanning triggered by the selected plan is correct and precise.
80        // FIXME(Wenyu,Tianle): When working on eager stack scanning on OpenJDK,
81        // the stack scanning may be broken. Uncomment the following lines to
82        // collect the roots again.
83        // Also, remember to call `DerivedPointerTable::update_pointers(); DerivedPointerTable::clear();`
84        // in openjdk binding before the second round of roots scanning.
85        // for mutator in <P::VM as VMBinding>::VMActivePlan::mutators() {
86        //     scheduler.work_buckets[WorkBucketStage::Prepare]
87        //         .add(ScanMutatorRoots::<SanityGCProcessEdges<P::VM>>(mutator));
88        // }
89        {
90            let sanity_checker = mmtk.sanity_checker.lock().unwrap();
91            for roots in &sanity_checker.root_slots {
92                scheduler.work_buckets[WorkBucketStage::Closure].add(
93                    SanityGCProcessEdges::<P::VM>::new(
94                        roots.clone(),
95                        true,
96                        mmtk,
97                        WorkBucketStage::Closure,
98                    ),
99                );
100            }
101            for roots in &sanity_checker.root_nodes {
102                scheduler.work_buckets[WorkBucketStage::Closure].add(ProcessRootNodes::<
103                    P::VM,
104                    SanityGCProcessEdges<P::VM>,
105                    SanityGCProcessEdges<P::VM>,
106                >::new(
107                    roots.clone(),
108                    WorkBucketStage::Closure,
109                ));
110            }
111        }
112        // Prepare global/collectors/mutators
113        worker.scheduler().work_buckets[WorkBucketStage::Prepare]
114            .add(SanityPrepare::<P>::new(plan.downcast_ref::<P>().unwrap()));
115        // Release global/collectors/mutators
116        worker.scheduler().work_buckets[WorkBucketStage::Release]
117            .add(SanityRelease::<P>::new(plan.downcast_ref::<P>().unwrap()));
118    }
119}
120
121pub struct SanityPrepare<P: Plan> {
122    pub plan: &'static P,
123}
124
125impl<P: Plan> SanityPrepare<P> {
126    pub fn new(plan: &'static P) -> Self {
127        Self { plan }
128    }
129}
130
131impl<P: Plan> GCWork<P::VM> for SanityPrepare<P> {
132    fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
133        info!("Sanity GC prepare");
134        {
135            let mut sanity_checker = mmtk.sanity_checker.lock().unwrap();
136            sanity_checker.refs.clear();
137        }
138    }
139}
140
141pub struct SanityRelease<P: Plan> {
142    pub plan: &'static P,
143}
144
145impl<P: Plan> SanityRelease<P> {
146    pub fn new(plan: &'static P) -> Self {
147        Self { plan }
148    }
149}
150
151impl<P: Plan> GCWork<P::VM> for SanityRelease<P> {
152    fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
153        info!("Sanity GC release");
154        mmtk.sanity_checker.lock().unwrap().clear_roots_cache();
155        mmtk.sanity_end();
156    }
157}
158
159// #[derive(Default)]
160pub struct SanityGCProcessEdges<VM: VMBinding> {
161    base: ProcessEdgesBase<VM>,
162}
163
164impl<VM: VMBinding> Deref for SanityGCProcessEdges<VM> {
165    type Target = ProcessEdgesBase<VM>;
166    fn deref(&self) -> &Self::Target {
167        &self.base
168    }
169}
170
171impl<VM: VMBinding> DerefMut for SanityGCProcessEdges<VM> {
172    fn deref_mut(&mut self) -> &mut Self::Target {
173        &mut self.base
174    }
175}
176
177impl<VM: VMBinding> ProcessEdgesWork for SanityGCProcessEdges<VM> {
178    type VM = VM;
179    type ScanObjectsWorkType = ScanObjects<Self>;
180
181    const OVERWRITE_REFERENCE: bool = false;
182    fn new(
183        slots: Vec<SlotOf<Self>>,
184        roots: bool,
185        mmtk: &'static MMTK<VM>,
186        bucket: WorkBucketStage,
187    ) -> Self {
188        Self {
189            base: ProcessEdgesBase::new(slots, roots, mmtk, bucket),
190            // ..Default::default()
191        }
192    }
193
194    fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
195        let mut sanity_checker = self.mmtk().sanity_checker.lock().unwrap();
196        if !sanity_checker.refs.contains(&object) {
197            // FIXME steveb consider VM-specific integrity check on reference.
198            assert!(object.is_sane(), "Invalid reference {:?}", object);
199
200            // Let plan check object
201            assert!(
202                self.mmtk().get_plan().sanity_check_object(object),
203                "Invalid reference {:?}",
204                object
205            );
206
207            // Let VM check object
208            assert!(
209                VM::VMObjectModel::is_object_sane(object),
210                "Invalid reference {:?}",
211                object
212            );
213
214            // Object is not "marked"
215            sanity_checker.refs.insert(object); // "Mark" it
216            trace!("Sanity mark object {}", object);
217            self.nodes.enqueue(object);
218        }
219
220        // If the valid object (VO) bit metadata is enabled, all live objects should have the VO
221        // bit set when sanity GC starts.
222        #[cfg(feature = "vo_bit")]
223        if !crate::util::metadata::vo_bit::is_vo_bit_set(object) {
224            panic!("VO bit is not set: {}", object);
225        }
226
227        object
228    }
229
230    fn create_scan_work(&self, nodes: Vec<ObjectReference>) -> Option<Self::ScanObjectsWorkType> {
231        Some(ScanObjects::<Self>::new(
232            nodes,
233            false,
234            WorkBucketStage::Closure,
235        ))
236    }
237}