@@ -1021,6 +1021,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
1021
1021
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
1022
1022
fn retag ( & mut self , kind : RetagKind , place : & PlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1023
1023
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
+
1024
1028
// Determine mutability and whether to add a protector.
1025
1029
// Cannot use `builtin_deref` because that reports *immutable* for `Box`,
1026
1030
// making it useless.
@@ -1037,90 +1041,67 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1037
1041
// Raw pointers need to be enabled.
1038
1042
ty:: RawPtr ( tym) if kind == RetagKind :: Raw =>
1039
1043
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.
1041
1046
_ => None ,
1042
1047
}
1043
1048
}
1044
1049
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
-
1086
1050
// The actual visitor.
1087
1051
struct RetagVisitor < ' ecx , ' mir , ' tcx > {
1088
1052
ecx : & ' ecx mut MiriEvalContext < ' mir , ' tcx > ,
1089
1053
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
+ }
1090
1069
}
1091
1070
impl < ' ecx , ' mir , ' tcx > MutValueVisitor < ' mir , ' tcx , Evaluator < ' mir , ' tcx > >
1092
1071
for RetagVisitor < ' ecx , ' mir , ' tcx >
1093
1072
{
1094
- type V = MPlaceTy < ' tcx , Tag > ;
1073
+ type V = PlaceTy < ' tcx , Tag > ;
1095
1074
1096
1075
#[ inline( always) ]
1097
1076
fn ecx ( & mut self ) -> & mut MiriEvalContext < ' mir , ' tcx > {
1098
1077
self . ecx
1099
1078
}
1100
1079
1101
- fn visit_box ( & mut self , place : & MPlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1080
+ fn visit_box ( & mut self , place : & PlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1102
1081
// Boxes do not get a protector: protectors reflect that references outlive the call
1103
1082
// 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
+ )
1110
1088
}
1111
1089
1112
- fn visit_value ( & mut self , place : & MPlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1090
+ fn visit_value ( & mut self , place : & PlaceTy < ' tcx , Tag > ) -> InterpResult < ' tcx > {
1113
1091
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) ?;
1117
1093
} else if matches ! ( place. layout. ty. kind( ) , ty:: RawPtr ( ..) ) {
1118
1094
// Wide raw pointers *do* have fields and their types are strange.
1119
1095
// vtables have a type like `&[*const (); 3]` or so!
1120
1096
// 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*)
1124
1105
self . walk_value ( place) ?;
1125
1106
}
1126
1107
Ok ( ( ) )
0 commit comments