]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/tag_gc.rs
Auto merge of #2559 - RalfJung:gc-refactor, r=saethlin
[rust.git] / src / tools / miri / src / tag_gc.rs
1 use rustc_data_structures::fx::FxHashSet;
2
3 use crate::*;
4
5 pub trait VisitMachineValues {
6     fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>));
7 }
8
9 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
10 pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
11     /// Generic GC helper to visit everything that can store a value. The `acc` offers some chance to
12     /// accumulate everything.
13     fn visit_all_machine_values<T>(
14         &self,
15         acc: &mut T,
16         mut visit_operand: impl FnMut(&mut T, &Operand<Provenance>),
17         mut visit_alloc: impl FnMut(&mut T, &Allocation<Provenance, AllocExtra>),
18     ) {
19         let this = self.eval_context_ref();
20
21         // Memory.
22         this.memory.alloc_map().iter(|it| {
23             for (_id, (_kind, alloc)) in it {
24                 visit_alloc(acc, alloc);
25             }
26         });
27
28         // And all the other machine values.
29         this.machine.visit_machine_values(&mut |op| visit_operand(acc, op));
30     }
31
32     fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
33         let this = self.eval_context_mut();
34         // No reason to do anything at all if stacked borrows is off.
35         if this.machine.stacked_borrows.is_none() {
36             return Ok(());
37         }
38
39         let mut tags = FxHashSet::default();
40
41         let visit_scalar = |tags: &mut FxHashSet<SbTag>, s: &Scalar<Provenance>| {
42             if let Scalar::Ptr(ptr, _) = s {
43                 if let Provenance::Concrete { sb, .. } = ptr.provenance {
44                     tags.insert(sb);
45                 }
46             }
47         };
48
49         this.visit_all_machine_values(
50             &mut tags,
51             |tags, op| {
52                 match op {
53                     Operand::Immediate(Immediate::Scalar(s)) => {
54                         visit_scalar(tags, s);
55                     }
56                     Operand::Immediate(Immediate::ScalarPair(s1, s2)) => {
57                         visit_scalar(tags, s1);
58                         visit_scalar(tags, s2);
59                     }
60                     Operand::Immediate(Immediate::Uninit) => {}
61                     Operand::Indirect(MemPlace { ptr, .. }) => {
62                         if let Some(Provenance::Concrete { sb, .. }) = ptr.provenance {
63                             tags.insert(sb);
64                         }
65                     }
66                 }
67             },
68             |tags, alloc| {
69                 for (_size, prov) in alloc.provenance().iter() {
70                     if let Provenance::Concrete { sb, .. } = prov {
71                         tags.insert(*sb);
72                     }
73                 }
74             },
75         );
76
77         self.remove_unreachable_tags(tags);
78
79         Ok(())
80     }
81
82     fn remove_unreachable_tags(&mut self, tags: FxHashSet<SbTag>) {
83         let this = self.eval_context_mut();
84         this.memory.alloc_map().iter(|it| {
85             for (_id, (_kind, alloc)) in it {
86                 alloc
87                     .extra
88                     .stacked_borrows
89                     .as_ref()
90                     .unwrap()
91                     .borrow_mut()
92                     .remove_unreachable_tags(&tags);
93             }
94         });
95     }
96 }