mmtk/util/sanity/
sanity_checker.rs1use crate::plan::Plan;
2use crate::scheduler::GCWork;
3use crate::scheduler::GCWorker;
4use crate::scheduler::WorkBucketStage;
5use crate::util::scanning_helper;
6use crate::util::ObjectReference;
7use crate::vm::slot::Slot;
8use crate::vm::{ObjectModel, VMBinding};
9use crate::MMTK;
10use std::collections::HashSet;
11
12#[allow(dead_code)]
13pub struct SanityChecker<SL: Slot> {
14 refs: HashSet<ObjectReference>,
16 root_slots: Vec<Vec<SL>>,
18 root_nodes: Vec<Vec<ObjectReference>>,
20}
21
22impl<SL: Slot> Default for SanityChecker<SL> {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl<SL: Slot> SanityChecker<SL> {
29 pub fn new() -> Self {
30 Self {
31 refs: HashSet::new(),
32 root_slots: vec![],
33 root_nodes: vec![],
34 }
35 }
36
37 pub fn add_root_slots(&mut self, roots: Vec<SL>) {
39 debug!("Added {} root slots", roots.len());
40 self.root_slots.push(roots)
41 }
42
43 pub fn add_root_nodes(&mut self, roots: Vec<ObjectReference>) {
44 debug!("Added {} root nodes", roots.len());
45 self.root_nodes.push(roots)
46 }
47
48 fn clear_roots_cache(&mut self) {
50 debug!("Cleared roots cache");
51 self.root_slots.clear();
52 self.root_nodes.clear();
53 }
54}
55
56pub struct ScheduleSanityGC<P: Plan> {
57 plan: &'static P,
58}
59
60impl<P: Plan> ScheduleSanityGC<P> {
61 pub fn new(plan: &'static P) -> Self {
62 ScheduleSanityGC { plan }
63 }
64}
65
66impl<P: Plan> GCWork<P::VM> for ScheduleSanityGC<P> {
67 fn do_work(&mut self, worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
68 let scheduler = worker.scheduler();
69
70 scheduler.reset_state();
71
72 #[cfg(feature = "extreme_assertions")]
74 mmtk.slot_logger.reset();
75
76 mmtk.sanity_begin(); worker.scheduler().work_buckets[WorkBucketStage::Prepare]
80 .add(SanityPrepare::<P>::new(self.plan));
81 worker.scheduler().work_buckets[WorkBucketStage::Closure]
83 .add(SanityClosure::<P>::new(self.plan));
84 worker.scheduler().work_buckets[WorkBucketStage::Release]
86 .add(SanityRelease::<P>::new(self.plan));
87 }
88}
89
90pub struct SanityPrepare<P: Plan> {
91 pub plan: &'static P,
92}
93
94impl<P: Plan> SanityPrepare<P> {
95 pub fn new(plan: &'static P) -> Self {
96 Self { plan }
97 }
98}
99
100impl<P: Plan> GCWork<P::VM> for SanityPrepare<P> {
101 fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
102 info!("Sanity GC prepare");
103 {
104 let mut sanity_checker = mmtk.sanity_checker.lock().unwrap();
105 sanity_checker.refs.clear();
106 }
107 }
108}
109
110pub struct SanityRelease<P: Plan> {
111 pub plan: &'static P,
112}
113
114impl<P: Plan> SanityRelease<P> {
115 pub fn new(plan: &'static P) -> Self {
116 Self { plan }
117 }
118}
119
120impl<P: Plan> GCWork<P::VM> for SanityRelease<P> {
121 fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
122 info!("Sanity GC release");
123 mmtk.sanity_checker.lock().unwrap().clear_roots_cache();
124 mmtk.sanity_end();
125 }
126}
127
128pub struct SanityClosure<P: Plan> {
129 pub plan: &'static P,
130}
131
132impl<P: Plan> SanityClosure<P> {
133 pub fn new(plan: &'static P) -> Self {
134 Self { plan }
135 }
136}
137
138impl<P: Plan> GCWork<P::VM> for SanityClosure<P> {
139 fn do_work(&mut self, worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
140 info!("Sanity GC closure");
141 let mut sanity_checker = mmtk.sanity_checker.lock().unwrap();
142
143 let mut queue = Vec::new();
144
145 for roots in &sanity_checker.root_slots {
157 queue.extend(roots.iter().flat_map(|slot| slot.load()));
158 }
159 for roots in &sanity_checker.root_nodes {
160 queue.extend(roots);
161 }
162
163 let tls = worker.tls;
164
165 while let Some(object) = queue.pop() {
166 if !sanity_checker.refs.insert(object) {
167 continue;
168 }
169
170 trace!("Doing sanity check on object {object}");
171
172 assert!(
174 object.is_sane(),
175 "`object.is_sane()` returned false. object: {object}",
176 );
177
178 assert!(
180 self.plan.sanity_check_object(object),
181 "plan.sanity_check_object(object) returned false. object: {object}",
182 );
183
184 assert!(
186 <P::VM as VMBinding>::VMObjectModel::is_object_sane(object),
187 "VMObjectModel::is_object_sane(object) returned false. object: {object}",
188 );
189
190 scanning_helper::visit_children_non_moving::<P::VM>(tls, object, &mut |child| {
193 queue.push(child);
194 child
195 });
196 }
197 }
198}