1
Fork 0

Use static dispatch in the visitor

This commit is contained in:
Ben Kimock 2022-09-26 19:50:50 -04:00 committed by Ralf Jung
parent 61e71cebd3
commit a8f8106cec
10 changed files with 148 additions and 105 deletions

View file

@ -182,15 +182,15 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
}
impl VisitMachineValues for Thread<'_, '_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let Thread { panic_payload, last_error, stack, state: _, thread_name: _, join_status: _ } =
self;
if let Some(payload) = panic_payload {
visit(&Operand::Immediate(Immediate::Scalar(*payload)))
visit.visit(*payload);
}
if let Some(error) = last_error {
visit(&Operand::Indirect(**error))
visit.visit(**error);
}
for frame in stack {
frame.visit_machine_values(visit)
@ -199,7 +199,7 @@ impl VisitMachineValues for Thread<'_, '_> {
}
impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let Frame {
return_place,
locals,
@ -213,12 +213,12 @@ impl VisitMachineValues for Frame<'_, '_, Provenance, FrameData<'_>> {
// Return place.
if let Place::Ptr(mplace) = **return_place {
visit(&Operand::Indirect(mplace));
visit.visit(mplace);
}
// Locals.
for local in locals.iter() {
if let LocalValue::Live(value) = &local.value {
visit(value);
visit.visit(value);
}
}
@ -299,7 +299,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
}
impl VisitMachineValues for ThreadManager<'_, '_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let ThreadManager {
threads,
thread_local_alloc_ids,
@ -313,8 +313,7 @@ impl VisitMachineValues for ThreadManager<'_, '_> {
thread.visit_machine_values(visit);
}
for ptr in thread_local_alloc_ids.borrow().values().copied() {
let ptr: Pointer<Option<Provenance>> = ptr.into();
visit(&Operand::Indirect(MemPlace::from_ptr(ptr)));
visit.visit(ptr);
}
// FIXME: Do we need to do something for TimeoutCallback? That's a Box<dyn>, not sure what
// to do.

View file

@ -108,19 +108,15 @@ pub struct StoreBufferAlloc {
store_buffers: RefCell<RangeObjectMap<StoreBuffer>>,
}
impl VisitProvenance for StoreBufferAlloc {
fn visit_provenance(&self, visitor: &mut impl FnMut(SbTag)) {
impl VisitMachineValues for StoreBufferAlloc {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
for val in self
.store_buffers
.borrow()
.iter()
.flat_map(|buf| buf.buffer.iter().map(|element| &element.val))
{
if let Scalar::Ptr(ptr, _) = val {
if let Provenance::Concrete { sb, .. } = ptr.provenance {
visitor(sb);
}
}
visit.visit(val);
}
}
}

View file

@ -112,7 +112,7 @@ pub use crate::range_map::RangeMap;
pub use crate::stacked_borrows::{
CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks,
};
pub use crate::tag_gc::{EvalContextExt as _, VisitMachineValues, VisitProvenance};
pub use crate::tag_gc::{EvalContextExt as _, ProvenanceVisitor, VisitMachineValues};
/// Insert rustc arguments at the beginning of the argument list that Miri wants to be
/// set per default, for maximal validation power.

View file

@ -64,7 +64,7 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
}
impl VisitMachineValues for FrameData<'_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let FrameData { catch_unwind, stacked_borrows: _, timing: _ } = self;
if let Some(catch_unwind) = catch_unwind {
@ -261,6 +261,20 @@ pub struct AllocExtra {
pub weak_memory: Option<weak_memory::AllocExtra>,
}
impl VisitMachineValues for AllocExtra {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let AllocExtra { stacked_borrows, data_race: _, weak_memory } = self;
if let Some(stacked_borrows) = stacked_borrows {
stacked_borrows.borrow().visit_machine_values(visit);
}
if let Some(weak_memory) = weak_memory {
weak_memory.visit_machine_values(visit);
}
}
}
/// Precomputed layouts of primitive types
pub struct PrimitiveLayouts<'tcx> {
pub unit: TyAndLayout<'tcx>,
@ -602,7 +616,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
}
impl VisitMachineValues for MiriMachine<'_, '_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let MiriMachine {
threads,
tls,
@ -621,17 +635,16 @@ impl VisitMachineValues for MiriMachine<'_, '_> {
dir_handler.visit_machine_values(visit);
if let Some(argc) = argc {
visit(&Operand::Indirect(*argc));
visit.visit(argc);
}
if let Some(argv) = argv {
visit(&Operand::Indirect(*argv));
visit.visit(argv);
}
if let Some(cmd_line) = cmd_line {
visit(&Operand::Indirect(*cmd_line));
visit.visit(cmd_line);
}
for ptr in extern_statics.values().copied() {
let ptr: Pointer<Option<Provenance>> = ptr.into();
visit(&Operand::Indirect(MemPlace::from_ptr(ptr)));
visit.visit(ptr);
}
}
}

View file

@ -37,15 +37,14 @@ pub struct EnvVars<'tcx> {
}
impl VisitMachineValues for EnvVars<'_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let EnvVars { map, environ } = self;
for ptr in map.values() {
visit(&Operand::Indirect(MemPlace::from_ptr(*ptr)));
visit.visit(*ptr);
}
if let Some(env) = environ {
visit(&Operand::Indirect(**env));
visit.visit(**env);
}
}
}

View file

@ -36,10 +36,10 @@ pub struct CatchUnwindData<'tcx> {
}
impl VisitMachineValues for CatchUnwindData<'_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let CatchUnwindData { catch_fn, data, dest: _, ret: _ } = self;
visit(&Operand::Indirect(MemPlace::from_ptr(*catch_fn)));
visit(&Operand::Immediate(Immediate::Scalar(*data)));
visit.visit(catch_fn);
visit.visit(data);
}
}

View file

@ -236,14 +236,14 @@ impl<'tcx> TlsData<'tcx> {
}
impl VisitMachineValues for TlsData<'_> {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let TlsData { keys, macos_thread_dtors, next_key: _, dtors_running: _ } = self;
for scalar in keys.values().flat_map(|v| v.data.values()) {
visit(&Operand::Immediate(Immediate::Scalar(*scalar)));
visit.visit(scalar);
}
for (_, scalar) in macos_thread_dtors.values() {
visit(&Operand::Immediate(Immediate::Scalar(*scalar)));
visit.visit(scalar);
}
}
}

View file

@ -463,11 +463,11 @@ impl Default for DirHandler {
}
impl VisitMachineValues for DirHandler {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>)) {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
let DirHandler { streams, next_id: _ } = self;
for dir in streams.values() {
visit(&Operand::Indirect(MemPlace::from_ptr(dir.entry)));
visit.visit(dir.entry);
}
}
}

View file

@ -513,10 +513,10 @@ impl Stacks {
}
}
impl VisitProvenance for Stacks {
fn visit_provenance(&self, visit: &mut impl FnMut(SbTag)) {
impl VisitMachineValues for Stacks {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
for tag in self.exposed_tags.iter().copied() {
visit(tag);
visit.visit(tag);
}
}
}

View file

@ -3,34 +3,120 @@ use rustc_data_structures::fx::FxHashSet;
use crate::*;
pub trait VisitMachineValues {
fn visit_machine_values(&self, visit: &mut impl FnMut(&Operand<Provenance>));
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor);
}
pub trait VisitProvenance {
fn visit_provenance(&self, visit: &mut impl FnMut(SbTag));
pub trait MachineValue {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>);
}
pub struct ProvenanceVisitor {
tags: FxHashSet<SbTag>,
}
impl ProvenanceVisitor {
pub fn visit<V>(&mut self, v: V)
where
V: MachineValue,
{
v.visit_provenance(&mut self.tags);
}
}
impl<T: MachineValue> MachineValue for &T {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
(**self).visit_provenance(tags);
}
}
impl MachineValue for Operand<Provenance> {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
match self {
Operand::Immediate(Immediate::Scalar(s)) => {
s.visit_provenance(tags);
}
Operand::Immediate(Immediate::ScalarPair(s1, s2)) => {
s1.visit_provenance(tags);
s2.visit_provenance(tags);
}
Operand::Immediate(Immediate::Uninit) => {}
Operand::Indirect(p) => {
p.visit_provenance(tags);
}
}
}
}
impl MachineValue for Scalar<Provenance> {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
if let Scalar::Ptr(ptr, _) = self {
if let Provenance::Concrete { sb, .. } = ptr.provenance {
tags.insert(sb);
}
}
}
}
impl MachineValue for MemPlace<Provenance> {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
if let Some(Provenance::Concrete { sb, .. }) = self.ptr.provenance {
tags.insert(sb);
}
}
}
impl MachineValue for SbTag {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
tags.insert(*self);
}
}
impl MachineValue for Pointer<Provenance> {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
let (prov, _offset) = self.into_parts();
if let Provenance::Concrete { sb, .. } = prov {
tags.insert(sb);
}
}
}
impl MachineValue for Pointer<Option<Provenance>> {
fn visit_provenance(&self, tags: &mut FxHashSet<SbTag>) {
let (prov, _offset) = self.into_parts();
if let Some(Provenance::Concrete { sb, .. }) = prov {
tags.insert(sb);
}
}
}
impl VisitMachineValues for Allocation<Provenance, AllocExtra> {
fn visit_machine_values(&self, visit: &mut ProvenanceVisitor) {
for (_size, prov) in self.provenance().iter() {
if let Provenance::Concrete { sb, .. } = prov {
visit.visit(*sb);
}
}
self.extra.visit_machine_values(visit);
}
}
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>),
) {
/// GC helper to visit everything that can store provenance. The `ProvenanceVisitor` knows how
/// to extract provenance from the interpreter data types.
fn visit_all_machine_values(&self, acc: &mut ProvenanceVisitor) {
let this = self.eval_context_ref();
// Memory.
this.memory.alloc_map().iter(|it| {
for (_id, (_kind, alloc)) in it {
visit_alloc(acc, alloc);
alloc.visit_machine_values(acc);
}
});
// And all the other machine values.
this.machine.visit_machine_values(&mut |op| visit_operand(acc, op));
this.machine.visit_machine_values(acc);
}
fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> {
@ -40,59 +126,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
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);
}
}
};
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)) => {
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 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);
let mut visitor = ProvenanceVisitor { tags: FxHashSet::default() };
this.visit_all_machine_values(&mut visitor);
self.remove_unreachable_tags(visitor.tags);
Ok(())
}