-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(())
}