mmtk/util/sanity/
sanity_checker.rs1use 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 refs: HashSet<ObjectReference>,
15 root_slots: Vec<Vec<SL>>,
17 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 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 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 #[cfg(feature = "extreme_assertions")]
74 mmtk.slot_logger.reset();
75
76 mmtk.sanity_begin(); {
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 worker.scheduler().work_buckets[WorkBucketStage::Prepare]
114 .add(SanityPrepare::<P>::new(plan.downcast_ref::<P>().unwrap()));
115 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
159pub 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 }
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 assert!(object.is_sane(), "Invalid reference {:?}", object);
199
200 assert!(
202 self.mmtk().get_plan().sanity_check_object(object),
203 "Invalid reference {:?}",
204 object
205 );
206
207 assert!(
209 VM::VMObjectModel::is_object_sane(object),
210 "Invalid reference {:?}",
211 object
212 );
213
214 sanity_checker.refs.insert(object); trace!("Sanity mark object {}", object);
217 self.nodes.enqueue(object);
218 }
219
220 #[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}