]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/tag_gc.rs
for now, do not do fake reads on non-Unpin mutable references
[rust.git] / src / tools / miri / src / tag_gc.rs
1 use rustc_data_structures::fx::FxHashSet;
2
3 use crate::*;
4
5 pub trait VisitTags {
6     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag));
7 }
8
9 impl<T: VisitTags> VisitTags for Option<T> {
10     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
11         if let Some(x) = self {
12             x.visit_tags(visit);
13         }
14     }
15 }
16
17 impl<T: VisitTags> VisitTags for std::cell::RefCell<T> {
18     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
19         self.borrow().visit_tags(visit)
20     }
21 }
22
23 impl VisitTags for BorTag {
24     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
25         visit(*self)
26     }
27 }
28
29 impl VisitTags for Provenance {
30     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
31         if let Provenance::Concrete { tag, .. } = self {
32             visit(*tag);
33         }
34     }
35 }
36
37 impl VisitTags for Pointer<Provenance> {
38     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
39         let (prov, _offset) = self.into_parts();
40         prov.visit_tags(visit);
41     }
42 }
43
44 impl VisitTags for Pointer<Option<Provenance>> {
45     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
46         let (prov, _offset) = self.into_parts();
47         prov.visit_tags(visit);
48     }
49 }
50
51 impl VisitTags for Scalar<Provenance> {
52     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
53         match self {
54             Scalar::Ptr(ptr, _) => ptr.visit_tags(visit),
55             Scalar::Int(_) => (),
56         }
57     }
58 }
59
60 impl VisitTags for Immediate<Provenance> {
61     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
62         match self {
63             Immediate::Scalar(s) => {
64                 s.visit_tags(visit);
65             }
66             Immediate::ScalarPair(s1, s2) => {
67                 s1.visit_tags(visit);
68                 s2.visit_tags(visit);
69             }
70             Immediate::Uninit => {}
71         }
72     }
73 }
74
75 impl VisitTags for MemPlaceMeta<Provenance> {
76     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
77         match self {
78             MemPlaceMeta::Meta(m) => m.visit_tags(visit),
79             MemPlaceMeta::None => {}
80         }
81     }
82 }
83
84 impl VisitTags for MemPlace<Provenance> {
85     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
86         let MemPlace { ptr, meta } = self;
87         ptr.visit_tags(visit);
88         meta.visit_tags(visit);
89     }
90 }
91
92 impl VisitTags for MPlaceTy<'_, Provenance> {
93     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
94         (**self).visit_tags(visit)
95     }
96 }
97
98 impl VisitTags for Place<Provenance> {
99     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
100         match self {
101             Place::Ptr(p) => p.visit_tags(visit),
102             Place::Local { .. } => {
103                 // Will be visited as part of the stack frame.
104             }
105         }
106     }
107 }
108
109 impl VisitTags for PlaceTy<'_, Provenance> {
110     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
111         (**self).visit_tags(visit)
112     }
113 }
114
115 impl VisitTags for Operand<Provenance> {
116     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
117         match self {
118             Operand::Immediate(imm) => {
119                 imm.visit_tags(visit);
120             }
121             Operand::Indirect(p) => {
122                 p.visit_tags(visit);
123             }
124         }
125     }
126 }
127
128 impl VisitTags for Allocation<Provenance, AllocExtra> {
129     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
130         for prov in self.provenance().provenances() {
131             prov.visit_tags(visit);
132         }
133
134         self.extra.visit_tags(visit);
135     }
136 }
137
138 impl VisitTags for crate::MiriInterpCx<'_, '_> {
139     fn visit_tags(&self, visit: &mut dyn FnMut(BorTag)) {
140         // Memory.
141         self.memory.alloc_map().iter(|it| {
142             for (_id, (_kind, alloc)) in it {
143                 alloc.visit_tags(visit);
144             }
145         });
146
147         // And all the other machine values.
148         self.machine.visit_tags(visit);
149     }
150 }
151
152 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
153 pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
154     fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
155         let this = self.eval_context_mut();
156         // No reason to do anything at all if stacked borrows is off.
157         if this.machine.borrow_tracker.is_none() {
158             return Ok(());
159         }
160
161         let mut tags = FxHashSet::default();
162         this.visit_tags(&mut |tag| {
163             tags.insert(tag);
164         });
165         self.remove_unreachable_tags(tags);
166
167         Ok(())
168     }
169
170     fn remove_unreachable_tags(&mut self, tags: FxHashSet<BorTag>) {
171         let this = self.eval_context_mut();
172         this.memory.alloc_map().iter(|it| {
173             for (_id, (_kind, alloc)) in it {
174                 if let Some(bt) = &alloc.extra.borrow_tracker {
175                     bt.remove_unreachable_tags(&tags);
176                 }
177             }
178         });
179     }
180 }