use crate::*;
-pub trait VisitMachineValues {
- fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>));
+pub trait VisitTags {
+ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag));
}
-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();
+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);
+ }
+ }
+}
+
+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)
+ }
+}
+
+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 => {}
+ }
+ }
+}
+
+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);
+ }
+}
+
+impl VisitTags for MPlaceTy<'_, Provenance> {
+ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+ (**self).visit_tags(visit)
+ }
+}
+
+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)
+ }
+}
+
+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);
+ }
+ }
+ }
+}
+
+impl VisitTags for Allocation<Provenance, AllocExtra> {
+ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+ for prov in self.provenance().provenances() {
+ prov.visit_tags(visit);
+ }
+
+ self.extra.visit_tags(visit);
+ }
+}
+
+impl VisitTags for crate::MiriInterpCx<'_, '_> {
+ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
// Memory.
- this.memory.alloc_map().iter(|it| {
+ self.memory.alloc_map().iter(|it| {
for (_id, (_kind, alloc)) in it {
- visit_alloc(acc, alloc);
+ alloc.visit_tags(visit);
}
});
// And all the other machine values.
- this.machine.visit_machine_values(&mut |op| visit_operand(acc, op));
+ self.machine.visit_tags(visit);
}
+}
+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.
}
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);
- }
- }
- };
-
- 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)) => {
- 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);
- }
- }
- }
- },
- |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 GC if Stacked Borrows is disabled");
- tags.extend(&stacks.borrow().exposed_tags);
-
- if let Some(store_buffers) = alloc.extra.weak_memory.as_ref() {
- store_buffers.iter(|val| {
- if let Scalar::Ptr(ptr, _) = val {
- if let Provenance::Concrete { sb, .. } = ptr.provenance {
- tags.insert(sb);
- }
- }
- });
- }
- },
- );
-
+ this.visit_tags(&mut |tag| {
+ tags.insert(tag);
+ });
self.remove_unreachable_tags(tags);
Ok(())