@@ -118,6 +118,13 @@ pub struct Thread<'mir, 'tcx> {
118
118
/// The virtual call stack.
119
119
stack : Vec < Frame < ' mir , ' tcx , Provenance , FrameData < ' tcx > > > ,
120
120
121
+ /// The index of the topmost user-relevant frame in `stack`. This field must contain
122
+ /// the value produced by `get_top_user_relevant_frame`.
123
+ /// The `None` state here represents
124
+ /// This field is a cache to reduce how often we call that method. The cache is manually
125
+ /// maintained inside `MiriMachine::after_stack_push` and `MiriMachine::after_stack_pop`.
126
+ top_user_relevant_frame : Option < usize > ,
127
+
121
128
/// The join status.
122
129
join_status : ThreadJoinStatus ,
123
130
@@ -147,6 +154,40 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
147
154
fn thread_name ( & self ) -> & [ u8 ] {
148
155
if let Some ( ref thread_name) = self . thread_name { thread_name } else { b"<unnamed>" }
149
156
}
157
+
158
+ /// Return the top user-relevant frame, if there is one.
159
+ /// Note that the choice to return `None` here when there is no user-relevant frame is part of
160
+ /// justifying the optimization that only pushes of user-relevant frames require updating the
161
+ /// `top_user_relevant_frame` field.
162
+ fn compute_top_user_relevant_frame ( & self ) -> Option < usize > {
163
+ self . stack
164
+ . iter ( )
165
+ . enumerate ( )
166
+ . rev ( )
167
+ . find_map ( |( idx, frame) | if frame. extra . is_user_relevant { Some ( idx) } else { None } )
168
+ }
169
+
170
+ /// Re-compute the top user-relevant frame from scratch.
171
+ pub fn recompute_top_user_relevant_frame ( & mut self ) {
172
+ self . top_user_relevant_frame = self . compute_top_user_relevant_frame ( ) ;
173
+ }
174
+
175
+ /// Set the top user-relevant frame to the given value. Must be equal to what
176
+ /// `get_top_user_relevant_frame` would return!
177
+ pub fn set_top_user_relevant_frame ( & mut self , frame_idx : usize ) {
178
+ debug_assert_eq ! ( Some ( frame_idx) , self . compute_top_user_relevant_frame( ) ) ;
179
+ self . top_user_relevant_frame = Some ( frame_idx) ;
180
+ }
181
+
182
+ /// Returns the topmost frame that is considered user-relevant, or the
183
+ /// top of the stack if there is no such frame, or `None` if the stack is empty.
184
+ pub fn top_user_relevant_frame ( & self ) -> Option < usize > {
185
+ debug_assert_eq ! ( self . top_user_relevant_frame, self . compute_top_user_relevant_frame( ) ) ;
186
+ // This can be called upon creation of an allocation. We create allocations while setting up
187
+ // parts of the Rust runtime when we do not have any stack frames yet, so we need to handle
188
+ // empty stacks.
189
+ self . top_user_relevant_frame . or_else ( || self . stack . len ( ) . checked_sub ( 1 ) )
190
+ }
150
191
}
151
192
152
193
impl < ' mir , ' tcx > std:: fmt:: Debug for Thread < ' mir , ' tcx > {
@@ -167,6 +208,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
167
208
state : ThreadState :: Enabled ,
168
209
thread_name : None ,
169
210
stack : Vec :: new ( ) ,
211
+ top_user_relevant_frame : None ,
170
212
join_status : ThreadJoinStatus :: Joinable ,
171
213
panic_payload : None ,
172
214
last_error : None ,
@@ -184,8 +226,15 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
184
226
185
227
impl VisitTags for Thread < ' _ , ' _ > {
186
228
fn visit_tags ( & self , visit : & mut dyn FnMut ( SbTag ) ) {
187
- let Thread { panic_payload, last_error, stack, state : _, thread_name : _, join_status : _ } =
188
- self ;
229
+ let Thread {
230
+ panic_payload,
231
+ last_error,
232
+ stack,
233
+ top_user_relevant_frame : _,
234
+ state : _,
235
+ thread_name : _,
236
+ join_status : _,
237
+ } = self ;
189
238
190
239
panic_payload. visit_tags ( visit) ;
191
240
last_error. visit_tags ( visit) ;
@@ -414,7 +463,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
414
463
}
415
464
416
465
/// Get a shared borrow of the currently active thread.
417
- fn active_thread_ref ( & self ) -> & Thread < ' mir , ' tcx > {
466
+ pub fn active_thread_ref ( & self ) -> & Thread < ' mir , ' tcx > {
418
467
& self . threads [ self . active_thread ]
419
468
}
420
469
0 commit comments