@@ -47,6 +47,7 @@ use std::{
4747} ;
4848
4949use rustc_ast:: Mutability ;
50+ use rustc_data_structures:: fx:: FxHashMap ;
5051use rustc_data_structures:: fx:: FxHashSet ;
5152use rustc_index:: { Idx , IndexVec } ;
5253use rustc_middle:: { mir, ty:: Ty } ;
@@ -1121,6 +1122,103 @@ impl VClockAlloc {
11211122 }
11221123}
11231124
1125+ /// Vector clock state for a stack frame (tracking the local variables
1126+ /// that do not have an allocation yet).
1127+ #[ derive( Debug , Default ) ]
1128+ pub struct FrameState {
1129+ local_clocks : RefCell < FxHashMap < mir:: Local , LocalClocks > > ,
1130+ }
1131+
1132+ /// Stripped-down version of [`MemoryCellClocks`] for the clocks we need to keep track
1133+ /// of in a local that does not yet have addressable memory -- and hence can only
1134+ /// be accessed from the thread its stack frame belongs to, and cannot be access atomically.
1135+ #[ derive( Debug ) ]
1136+ struct LocalClocks {
1137+ write : VTimestamp ,
1138+ write_type : NaWriteType ,
1139+ read : VTimestamp ,
1140+ }
1141+
1142+ impl Default for LocalClocks {
1143+ fn default ( ) -> Self {
1144+ Self { write : VTimestamp :: ZERO , write_type : NaWriteType :: Allocate , read : VTimestamp :: ZERO }
1145+ }
1146+ }
1147+
1148+ impl FrameState {
1149+ pub fn local_write ( & self , local : mir:: Local , storage_live : bool , machine : & MiriMachine < ' _ > ) {
1150+ let current_span = machine. current_span ( ) ;
1151+ let global = machine. data_race . as_ref ( ) . unwrap ( ) ;
1152+ if global. race_detecting ( ) {
1153+ let ( index, mut thread_clocks) = global. active_thread_state_mut ( & machine. threads ) ;
1154+ // This should do the same things as `MemoryCellClocks::write_race_detect`.
1155+ if !current_span. is_dummy ( ) {
1156+ thread_clocks. clock . index_mut ( index) . span = current_span;
1157+ }
1158+ let mut clocks = self . local_clocks . borrow_mut ( ) ;
1159+ if storage_live {
1160+ let new_clocks = LocalClocks {
1161+ write : thread_clocks. clock [ index] ,
1162+ write_type : NaWriteType :: Allocate ,
1163+ read : VTimestamp :: ZERO ,
1164+ } ;
1165+ // There might already be an entry in the map for this, if the local was previously
1166+ // live already.
1167+ clocks. insert ( local, new_clocks) ;
1168+ } else {
1169+ // This can fail to exist if `race_detecting` was false when the allocation
1170+ // occurred, in which case we can backdate this to the beginning of time.
1171+ let clocks = clocks. entry ( local) . or_insert_with ( Default :: default) ;
1172+ clocks. write = thread_clocks. clock [ index] ;
1173+ clocks. write_type = NaWriteType :: Write ;
1174+ }
1175+ }
1176+ }
1177+
1178+ pub fn local_read ( & self , local : mir:: Local , machine : & MiriMachine < ' _ > ) {
1179+ let current_span = machine. current_span ( ) ;
1180+ let global = machine. data_race . as_ref ( ) . unwrap ( ) ;
1181+ if global. race_detecting ( ) {
1182+ let ( index, mut thread_clocks) = global. active_thread_state_mut ( & machine. threads ) ;
1183+ // This should do the same things as `MemoryCellClocks::read_race_detect`.
1184+ if !current_span. is_dummy ( ) {
1185+ thread_clocks. clock . index_mut ( index) . span = current_span;
1186+ }
1187+ thread_clocks. clock . index_mut ( index) . set_read_type ( NaReadType :: Read ) ;
1188+ // This can fail to exist if `race_detecting` was false when the allocation
1189+ // occurred, in which case we can backdate this to the beginning of time.
1190+ let mut clocks = self . local_clocks . borrow_mut ( ) ;
1191+ let clocks = clocks. entry ( local) . or_insert_with ( Default :: default) ;
1192+ clocks. read = thread_clocks. clock [ index] ;
1193+ }
1194+ }
1195+
1196+ pub fn local_moved_to_memory (
1197+ & self ,
1198+ local : mir:: Local ,
1199+ alloc : & mut VClockAlloc ,
1200+ machine : & MiriMachine < ' _ > ,
1201+ ) {
1202+ let global = machine. data_race . as_ref ( ) . unwrap ( ) ;
1203+ if global. race_detecting ( ) {
1204+ let ( index, _thread_clocks) = global. active_thread_state_mut ( & machine. threads ) ;
1205+ // Get the time the last write actually happened. This can fail to exist if
1206+ // `race_detecting` was false when the write occurred, in that case we can backdate this
1207+ // to the beginning of time.
1208+ let local_clocks = self . local_clocks . borrow_mut ( ) . remove ( & local) . unwrap_or_default ( ) ;
1209+ for ( _mem_clocks_range, mem_clocks) in alloc. alloc_ranges . get_mut ( ) . iter_mut_all ( ) {
1210+ // The initialization write for this already happened, just at the wrong timestamp.
1211+ // Check that the thread index matches what we expect.
1212+ assert_eq ! ( mem_clocks. write. 0 , index) ;
1213+ // Convert the local's clocks into memory clocks.
1214+ mem_clocks. write = ( index, local_clocks. write ) ;
1215+ mem_clocks. write_type = local_clocks. write_type ;
1216+ mem_clocks. read = VClock :: new_with_index ( index, local_clocks. read ) ;
1217+ }
1218+ }
1219+ }
1220+ }
1221+
11241222impl < ' tcx > EvalContextPrivExt < ' tcx > for MiriInterpCx < ' tcx > { }
11251223trait EvalContextPrivExt < ' tcx > : MiriInterpCxExt < ' tcx > {
11261224 /// Temporarily allow data-races to occur. This should only be used in
0 commit comments