Skip to content

Commit 36a7a65

Browse files
committed
Auto merge of rust-lang#2378 - RalfJung:sb, r=RalfJung
use PlaceTy visitor and dedup sime retagging code I benchmarked this and as far as I can see the difference to the old code is totally within noise. And this makes the code a lot simpler and removes duplication so yay. :)
2 parents 416cddb + 39866f8 commit 36a7a65

File tree

1 file changed

+38
-57
lines changed

1 file changed

+38
-57
lines changed

src/stacked_borrows/mod.rs

Lines changed: 38 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
10211021
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
10221022
fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
10231023
let this = self.eval_context_mut();
1024+
let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields;
1025+
let mut visitor = RetagVisitor { ecx: this, kind, retag_fields };
1026+
return visitor.visit_value(place);
1027+
10241028
// Determine mutability and whether to add a protector.
10251029
// Cannot use `builtin_deref` because that reports *immutable* for `Box`,
10261030
// making it useless.
@@ -1037,90 +1041,67 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
10371041
// Raw pointers need to be enabled.
10381042
ty::RawPtr(tym) if kind == RetagKind::Raw =>
10391043
Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)),
1040-
// Boxes are handled separately due to that allocator situation.
1044+
// Boxes are handled separately due to that allocator situation,
1045+
// see the visitor below.
10411046
_ => None,
10421047
}
10431048
}
10441049

1045-
// We need a visitor to visit all references. However, that requires
1046-
// a `MPlaceTy` (or `OpTy`), so we have a fast path for reference types that
1047-
// avoids allocating.
1048-
1049-
if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) {
1050-
// Fast path.
1051-
let val = this.read_immediate(&this.place_to_op(place)?)?;
1052-
let val = this.retag_reference(&val, ref_kind, protector)?;
1053-
this.write_immediate(*val, place)?;
1054-
return Ok(());
1055-
}
1056-
1057-
// If we don't want to recurse, we are already done.
1058-
// EXCEPT if this is a `Box`, then we have to recurse because allocators.
1059-
// (Yes this means we technically also recursively retag the allocator itself even if field
1060-
// retagging is not enabled. *shrug*)
1061-
if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields
1062-
&& !place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box())
1063-
{
1064-
return Ok(());
1065-
}
1066-
1067-
// Skip some types that have no further structure we might care about.
1068-
if matches!(
1069-
place.layout.ty.kind(),
1070-
ty::RawPtr(..)
1071-
| ty::Ref(..)
1072-
| ty::Int(..)
1073-
| ty::Uint(..)
1074-
| ty::Float(..)
1075-
| ty::Bool
1076-
| ty::Char
1077-
) {
1078-
return Ok(());
1079-
}
1080-
// Now go visit this thing.
1081-
let place = this.force_allocation(place)?;
1082-
1083-
let mut visitor = RetagVisitor { ecx: this, kind };
1084-
return visitor.visit_value(&place);
1085-
10861050
// The actual visitor.
10871051
struct RetagVisitor<'ecx, 'mir, 'tcx> {
10881052
ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>,
10891053
kind: RetagKind,
1054+
retag_fields: bool,
1055+
}
1056+
impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> {
1057+
#[inline(always)] // yes this helps in our benchmarks
1058+
fn retag_place(
1059+
&mut self,
1060+
place: &PlaceTy<'tcx, Tag>,
1061+
ref_kind: RefKind,
1062+
protector: bool,
1063+
) -> InterpResult<'tcx> {
1064+
let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?;
1065+
let val = self.ecx.retag_reference(&val, ref_kind, protector)?;
1066+
self.ecx.write_immediate(*val, place)?;
1067+
Ok(())
1068+
}
10901069
}
10911070
impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>>
10921071
for RetagVisitor<'ecx, 'mir, 'tcx>
10931072
{
1094-
type V = MPlaceTy<'tcx, Tag>;
1073+
type V = PlaceTy<'tcx, Tag>;
10951074

10961075
#[inline(always)]
10971076
fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> {
10981077
self.ecx
10991078
}
11001079

1101-
fn visit_box(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
1080+
fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
11021081
// Boxes do not get a protector: protectors reflect that references outlive the call
11031082
// they were passed in to; that's just not the case for boxes.
1104-
let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false);
1105-
1106-
let val = self.ecx.read_immediate(&place.into())?;
1107-
let val = self.ecx.retag_reference(&val, ref_kind, protector)?;
1108-
self.ecx.write_immediate(*val, &place.into())?;
1109-
Ok(())
1083+
self.retag_place(
1084+
place,
1085+
RefKind::Unique { two_phase: false },
1086+
/*protector*/ false,
1087+
)
11101088
}
11111089

1112-
fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
1090+
fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
11131091
if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) {
1114-
let val = self.ecx.read_immediate(&place.into())?;
1115-
let val = self.ecx.retag_reference(&val, ref_kind, protector)?;
1116-
self.ecx.write_immediate(*val, &place.into())?;
1092+
self.retag_place(place, ref_kind, protector)?;
11171093
} else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) {
11181094
// Wide raw pointers *do* have fields and their types are strange.
11191095
// vtables have a type like `&[*const (); 3]` or so!
11201096
// Do *not* recurse into them.
1121-
// (No need to worry about wide references or boxes, those always "qualify".)
1122-
} else {
1123-
// Maybe we need to go deeper.
1097+
// (No need to worry about wide references, those always "qualify". And Boxes
1098+
// are handles specially by the visitor anyway.)
1099+
} else if self.retag_fields
1100+
|| place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box())
1101+
{
1102+
// Recurse deeper. Need to always recurse for `Box` to even hit `visit_box`.
1103+
// (Yes this means we technically also recursively retag the allocator itself
1104+
// even if field retagging is not enabled. *shrug*)
11241105
self.walk_value(place)?;
11251106
}
11261107
Ok(())

0 commit comments

Comments
 (0)