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 self.root_slots.push(roots)
39 }
40
41 pub fn add_root_nodes(&mut self, roots: Vec<ObjectReference>) {
42 self.root_nodes.push(roots)
43 }
44
45 fn clear_roots_cache(&mut self) {
47 self.root_slots.clear();
48 self.root_nodes.clear();
49 }
50}
51
52pub struct ScheduleSanityGC<P: Plan> {
53 _plan: &'static P,
54}
55
56impl<P: Plan> ScheduleSanityGC<P> {
57 pub fn new(plan: &'static P) -> Self {
58 ScheduleSanityGC { _plan: plan }
59 }
60}
61
62impl<P: Plan> GCWork<P::VM> for ScheduleSanityGC<P> {
63 fn do_work(&mut self, worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
64 let scheduler = worker.scheduler();
65 let plan = mmtk.get_plan();
66
67 scheduler.reset_state();
68
69 #[cfg(feature = "extreme_assertions")]
71 mmtk.slot_logger.reset();
72
73 mmtk.sanity_begin(); {
87 let sanity_checker = mmtk.sanity_checker.lock().unwrap();
88 for roots in &sanity_checker.root_slots {
89 scheduler.work_buckets[WorkBucketStage::Closure].add(
90 SanityGCProcessEdges::<P::VM>::new(
91 roots.clone(),
92 true,
93 mmtk,
94 WorkBucketStage::Closure,
95 ),
96 );
97 }
98 for roots in &sanity_checker.root_nodes {
99 scheduler.work_buckets[WorkBucketStage::Closure].add(ProcessRootNodes::<
100 P::VM,
101 SanityGCProcessEdges<P::VM>,
102 SanityGCProcessEdges<P::VM>,
103 >::new(
104 roots.clone(),
105 WorkBucketStage::Closure,
106 ));
107 }
108 }
109 worker.scheduler().work_buckets[WorkBucketStage::Prepare]
111 .add(SanityPrepare::<P>::new(plan.downcast_ref::<P>().unwrap()));
112 worker.scheduler().work_buckets[WorkBucketStage::Release]
114 .add(SanityRelease::<P>::new(plan.downcast_ref::<P>().unwrap()));
115 }
116}
117
118pub struct SanityPrepare<P: Plan> {
119 pub plan: &'static P,
120}
121
122impl<P: Plan> SanityPrepare<P> {
123 pub fn new(plan: &'static P) -> Self {
124 Self { plan }
125 }
126}
127
128impl<P: Plan> GCWork<P::VM> for SanityPrepare<P> {
129 fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
130 info!("Sanity GC prepare");
131 {
132 let mut sanity_checker = mmtk.sanity_checker.lock().unwrap();
133 sanity_checker.refs.clear();
134 }
135 }
136}
137
138pub struct SanityRelease<P: Plan> {
139 pub plan: &'static P,
140}
141
142impl<P: Plan> SanityRelease<P> {
143 pub fn new(plan: &'static P) -> Self {
144 Self { plan }
145 }
146}
147
148impl<P: Plan> GCWork<P::VM> for SanityRelease<P> {
149 fn do_work(&mut self, _worker: &mut GCWorker<P::VM>, mmtk: &'static MMTK<P::VM>) {
150 info!("Sanity GC release");
151 mmtk.sanity_checker.lock().unwrap().clear_roots_cache();
152 mmtk.sanity_end();
153 }
154}
155
156pub struct SanityGCProcessEdges<VM: VMBinding> {
158 base: ProcessEdgesBase<VM>,
159}
160
161impl<VM: VMBinding> Deref for SanityGCProcessEdges<VM> {
162 type Target = ProcessEdgesBase<VM>;
163 fn deref(&self) -> &Self::Target {
164 &self.base
165 }
166}
167
168impl<VM: VMBinding> DerefMut for SanityGCProcessEdges<VM> {
169 fn deref_mut(&mut self) -> &mut Self::Target {
170 &mut self.base
171 }
172}
173
174impl<VM: VMBinding> ProcessEdgesWork for SanityGCProcessEdges<VM> {
175 type VM = VM;
176 type ScanObjectsWorkType = ScanObjects<Self>;
177
178 const OVERWRITE_REFERENCE: bool = false;
179 fn new(
180 slots: Vec<SlotOf<Self>>,
181 roots: bool,
182 mmtk: &'static MMTK<VM>,
183 bucket: WorkBucketStage,
184 ) -> Self {
185 Self {
186 base: ProcessEdgesBase::new(slots, roots, mmtk, bucket),
187 }
189 }
190
191 fn trace_object(&mut self, object: ObjectReference) -> ObjectReference {
192 let mut sanity_checker = self.mmtk().sanity_checker.lock().unwrap();
193 if !sanity_checker.refs.contains(&object) {
194 assert!(object.is_sane(), "Invalid reference {:?}", object);
196
197 assert!(
199 self.mmtk().get_plan().sanity_check_object(object),
200 "Invalid reference {:?}",
201 object
202 );
203
204 assert!(
206 VM::VMObjectModel::is_object_sane(object),
207 "Invalid reference {:?}",
208 object
209 );
210
211 sanity_checker.refs.insert(object); trace!("Sanity mark object {}", object);
214 self.nodes.enqueue(object);
215 }
216
217 #[cfg(feature = "vo_bit")]
220 if !crate::util::metadata::vo_bit::is_vo_bit_set(object) {
221 panic!("VO bit is not set: {}", object);
222 }
223
224 object
225 }
226
227 fn create_scan_work(&self, nodes: Vec<ObjectReference>) -> Self::ScanObjectsWorkType {
228 ScanObjects::<Self>::new(nodes, false, WorkBucketStage::Closure)
229 }
230}