]> git.lizzy.rs Git - rust.git/blobdiff - src/tools/miri/src/tag_gc.rs
Use VisitProvenance to factor allocation visiting better
[rust.git] / src / tools / miri / src / tag_gc.rs
index e20a86711478ae076cb1a261337320fc67b7c3e8..0a8d5d00cfb63e747287de2fbfd7223249d7480e 100644 (file)
-use crate::*;
 use rustc_data_structures::fx::FxHashSet;
 
-impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
-pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
-    fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
-        let this = self.eval_context_mut();
-        // No reason to do anything at all if stacked borrows is off.
-        if this.machine.stacked_borrows.is_none() {
-            return Ok(());
-        }
-
-        let mut tags = FxHashSet::default();
-
-        for thread in this.machine.threads.iter() {
-            if let Some(Scalar::Ptr(
-                Pointer { provenance: Provenance::Concrete { sb, .. }, .. },
-                _,
-            )) = thread.panic_payload
-            {
-                tags.insert(sb);
-            }
-        }
-
-        self.find_tags_in_tls(&mut tags);
-        self.find_tags_in_memory(&mut tags);
-        self.find_tags_in_locals(&mut tags)?;
+use crate::*;
 
-        self.remove_unreachable_tags(tags);
+pub trait VisitMachineValues {
+    fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>));
+}
 
-        Ok(())
-    }
+pub trait VisitProvenance {
+    fn visit_provenance(&self, visit: &mut impl FnMut(SbTag));
+}
 
-    fn find_tags_in_tls(&mut self, tags: &mut FxHashSet<SbTag>) {
-        let this = self.eval_context_mut();
-        this.machine.tls.iter(|scalar| {
-            if let Scalar::Ptr(Pointer { provenance: Provenance::Concrete { sb, .. }, .. }, _) =
-                scalar
-            {
-                tags.insert(*sb);
-            }
-        });
-    }
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
+    /// Generic GC helper to visit everything that can store a value. The `acc` offers some chance to
+    /// accumulate everything.
+    fn visit_all_machine_values<T>(
+        &self,
+        acc: &mut T,
+        mut visit_operand: impl FnMut(&mut T, &Operand<Provenance>),
+        mut visit_alloc: impl FnMut(&mut T, &Allocation<Provenance, AllocExtra>),
+    ) {
+        let this = self.eval_context_ref();
 
-    fn find_tags_in_memory(&mut self, tags: &mut FxHashSet<SbTag>) {
-        let this = self.eval_context_mut();
+        // Memory.
         this.memory.alloc_map().iter(|it| {
             for (_id, (_kind, alloc)) in it {
-                for (_size, prov) in alloc.provenance().iter() {
-                    if let Provenance::Concrete { sb, .. } = prov {
-                        tags.insert(*sb);
-                    }
-                }
+                visit_alloc(acc, alloc);
             }
         });
+
+        // And all the other machine values.
+        this.machine.visit_machine_values(&mut |op| visit_operand(acc, op));
     }
 
-    fn find_tags_in_locals(&mut self, tags: &mut FxHashSet<SbTag>) -> InterpResult<'tcx> {
+    fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        for frame in this.machine.threads.all_stacks().flatten() {
-            // Handle the return place of each frame
-            if let Ok(return_place) = frame.return_place.try_as_mplace() {
-                if let Some(Provenance::Concrete { sb, .. }) = return_place.ptr.provenance {
+        // No reason to do anything at all if stacked borrows is off.
+        if this.machine.stacked_borrows.is_none() {
+            return Ok(());
+        }
+
+        let mut tags = FxHashSet::default();
+
+        let visit_scalar = |tags: &mut FxHashSet<SbTag>, s: &Scalar<Provenance>| {
+            if let Scalar::Ptr(ptr, _) = s {
+                if let Provenance::Concrete { sb, .. } = ptr.provenance {
                     tags.insert(sb);
                 }
             }
+        };
 
-            for local in frame.locals.iter() {
-                let LocalValue::Live(value) = local.value else {
-                continue;
-            };
-                match value {
-                    Operand::Immediate(Immediate::Scalar(Scalar::Ptr(ptr, _))) =>
-                        if let Provenance::Concrete { sb, .. } = ptr.provenance {
-                            tags.insert(sb);
-                        },
+        let visit_provenance = |tags: &mut FxHashSet<SbTag>, tag: SbTag| {
+            tags.insert(tag);
+        };
+
+        this.visit_all_machine_values(
+            &mut tags,
+            |tags, op| {
+                match op {
+                    Operand::Immediate(Immediate::Scalar(s)) => {
+                        visit_scalar(tags, s);
+                    }
                     Operand::Immediate(Immediate::ScalarPair(s1, s2)) => {
-                        if let Scalar::Ptr(ptr, _) = s1 {
-                            if let Provenance::Concrete { sb, .. } = ptr.provenance {
-                                tags.insert(sb);
-                            }
-                        }
-                        if let Scalar::Ptr(ptr, _) = s2 {
-                            if let Provenance::Concrete { sb, .. } = ptr.provenance {
-                                tags.insert(sb);
-                            }
-                        }
+                        visit_scalar(tags, s1);
+                        visit_scalar(tags, s2);
                     }
+                    Operand::Immediate(Immediate::Uninit) => {}
                     Operand::Indirect(MemPlace { ptr, .. }) => {
                         if let Some(Provenance::Concrete { sb, .. }) = ptr.provenance {
                             tags.insert(sb);
                         }
                     }
-                    Operand::Immediate(Immediate::Uninit)
-                    | Operand::Immediate(Immediate::Scalar(Scalar::Int(_))) => {}
                 }
-            }
-        }
+            },
+            |tags, alloc| {
+                for (_size, prov) in alloc.provenance().iter() {
+                    if let Provenance::Concrete { sb, .. } = prov {
+                        tags.insert(*sb);
+                    }
+                }
+
+                let stacks =
+                    alloc.extra.stacked_borrows.as_ref().expect(
+                        "we should not even enter the tag GC if Stacked Borrows is disabled",
+                    );
+                stacks.borrow().visit_provenance(&mut |tag| visit_provenance(tags, tag));
+
+                if let Some(store_buffers) = alloc.extra.weak_memory.as_ref() {
+                    store_buffers.visit_provenance(&mut |tag| visit_provenance(tags, tag));
+                }
+            },
+        );
+
+        self.remove_unreachable_tags(tags);
 
         Ok(())
     }