]> git.lizzy.rs Git - rust.git/blobdiff - src/tools/miri/src/tag_gc.rs
Merge commit '266e96785ab71834b917bf474f130a6d8fdecd4b' into sync_cg_clif-2022-10-23
[rust.git] / src / tools / miri / src / tag_gc.rs
index e20a86711478ae076cb1a261337320fc67b7c3e8..5aa653632f395818dc69ca5b13e34436fec63dbf 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(());
+use crate::*;
+
+pub trait VisitTags {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag));
+}
+
+impl<T: VisitTags> VisitTags for Option<T> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        if let Some(x) = self {
+            x.visit_tags(visit);
         }
+    }
+}
 
-        let mut tags = FxHashSet::default();
+impl<T: VisitTags> VisitTags for std::cell::RefCell<T> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        self.borrow().visit_tags(visit)
+    }
+}
+
+impl VisitTags for SbTag {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        visit(*self)
+    }
+}
 
-        for thread in this.machine.threads.iter() {
-            if let Some(Scalar::Ptr(
-                Pointer { provenance: Provenance::Concrete { sb, .. }, .. },
-                _,
-            )) = thread.panic_payload
-            {
-                tags.insert(sb);
+impl VisitTags for Provenance {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        if let Provenance::Concrete { sb, .. } = self {
+            visit(*sb);
+        }
+    }
+}
+
+impl VisitTags for Pointer<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        let (prov, _offset) = self.into_parts();
+        prov.visit_tags(visit);
+    }
+}
+
+impl VisitTags for Pointer<Option<Provenance>> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        let (prov, _offset) = self.into_parts();
+        prov.visit_tags(visit);
+    }
+}
+
+impl VisitTags for Scalar<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        match self {
+            Scalar::Ptr(ptr, _) => ptr.visit_tags(visit),
+            Scalar::Int(_) => (),
+        }
+    }
+}
+
+impl VisitTags for Immediate<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        match self {
+            Immediate::Scalar(s) => {
+                s.visit_tags(visit);
+            }
+            Immediate::ScalarPair(s1, s2) => {
+                s1.visit_tags(visit);
+                s2.visit_tags(visit);
             }
+            Immediate::Uninit => {}
         }
+    }
+}
+
+impl VisitTags for MemPlaceMeta<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        match self {
+            MemPlaceMeta::Meta(m) => m.visit_tags(visit),
+            MemPlaceMeta::None => {}
+        }
+    }
+}
 
-        self.find_tags_in_tls(&mut tags);
-        self.find_tags_in_memory(&mut tags);
-        self.find_tags_in_locals(&mut tags)?;
+impl VisitTags for MemPlace<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        let MemPlace { ptr, meta } = self;
+        ptr.visit_tags(visit);
+        meta.visit_tags(visit);
+    }
+}
 
-        self.remove_unreachable_tags(tags);
+impl VisitTags for MPlaceTy<'_, Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        (**self).visit_tags(visit)
+    }
+}
 
-        Ok(())
+impl VisitTags for Place<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        match self {
+            Place::Ptr(p) => p.visit_tags(visit),
+            Place::Local { .. } => {
+                // Will be visited as part of the stack frame.
+            }
+        }
+    }
+}
+
+impl VisitTags for PlaceTy<'_, Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        (**self).visit_tags(visit)
     }
+}
 
-    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 VisitTags for Operand<Provenance> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        match self {
+            Operand::Immediate(imm) => {
+                imm.visit_tags(visit);
             }
-        });
+            Operand::Indirect(p) => {
+                p.visit_tags(visit);
+            }
+        }
     }
+}
 
-    fn find_tags_in_memory(&mut self, tags: &mut FxHashSet<SbTag>) {
-        let this = self.eval_context_mut();
-        this.memory.alloc_map().iter(|it| {
+impl VisitTags for Allocation<Provenance, AllocExtra> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        for (_size, prov) in self.provenance().iter() {
+            prov.visit_tags(visit);
+        }
+
+        self.extra.visit_tags(visit);
+    }
+}
+
+impl VisitTags for crate::MiriInterpCx<'_, '_> {
+    fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+        // Memory.
+        self.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);
-                    }
-                }
+                alloc.visit_tags(visit);
             }
         });
+
+        // And all the other machine values.
+        self.machine.visit_tags(visit);
     }
+}
 
-    fn find_tags_in_locals(&mut self, tags: &mut FxHashSet<SbTag>) -> InterpResult<'tcx> {
+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();
-        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 {
-                    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);
-                        },
-                    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);
-                            }
-                        }
-                    }
-                    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(_))) => {}
-                }
-            }
+        // 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();
+        this.visit_tags(&mut |tag| {
+            tags.insert(tag);
+        });
+        self.remove_unreachable_tags(tags);
+
         Ok(())
     }