Skip to content

Commit cd78f83

Browse files
committed
Track local frames incrementally during execution
1 parent c20217f commit cd78f83

File tree

4 files changed

+79
-63
lines changed

4 files changed

+79
-63
lines changed

src/concurrency/thread.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ pub struct Thread<'mir, 'tcx> {
118118
/// The virtual call stack.
119119
stack: Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>>,
120120

121+
/// The index of the topmost local frame in `stack`
122+
pub(crate) top_local_frame: usize,
123+
121124
/// The join status.
122125
join_status: ThreadJoinStatus,
123126

@@ -167,6 +170,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
167170
state: ThreadState::Enabled,
168171
thread_name: None,
169172
stack: Vec::new(),
173+
top_local_frame: 0,
170174
join_status: ThreadJoinStatus::Joinable,
171175
panic_payload: None,
172176
last_error: None,
@@ -184,8 +188,15 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> {
184188

185189
impl VisitTags for Thread<'_, '_> {
186190
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
187-
let Thread { panic_payload, last_error, stack, state: _, thread_name: _, join_status: _ } =
188-
self;
191+
let Thread {
192+
panic_payload,
193+
last_error,
194+
stack,
195+
top_local_frame: _,
196+
state: _,
197+
thread_name: _,
198+
join_status: _,
199+
} = self;
189200

190201
panic_payload.visit_tags(visit);
191202
last_error.visit_tags(visit);
@@ -414,10 +425,22 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
414425
}
415426

416427
/// Get a shared borrow of the currently active thread.
417-
fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
428+
pub fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> {
418429
&self.threads[self.active_thread]
419430
}
420431

432+
/// Reset the current-span caching logic. Mostly called when a new frame is added or removed.
433+
pub fn reset_top_local(&mut self) {
434+
let idx = self
435+
.active_thread_stack()
436+
.iter()
437+
.enumerate()
438+
.rev()
439+
.find_map(|(idx, frame)| if frame.extra.is_local { Some(idx) } else { None })
440+
.unwrap_or_else(|| self.active_thread_stack().len().saturating_sub(1));
441+
self.active_thread_mut().top_local_frame = idx;
442+
}
443+
421444
/// Mark the thread as detached, which means that no other thread will try
422445
/// to join it and the thread is responsible for cleaning up.
423446
///

src/helpers.rs

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
945945

946946
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
947947
pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> {
948-
CurrentSpan { current_frame_idx: None, machine: self }
948+
CurrentSpan { machine: self }
949949
}
950950
}
951951

@@ -955,7 +955,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
955955
/// The result of that search is cached so that later calls are approximately free.
956956
#[derive(Clone)]
957957
pub struct CurrentSpan<'a, 'mir, 'tcx> {
958-
current_frame_idx: Option<usize>,
959958
machine: &'a MiriMachine<'mir, 'tcx>,
960959
}
961960

@@ -967,8 +966,10 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
967966
/// Get the current span, skipping non-local frames.
968967
/// This function is backed by a cache, and can be assumed to be very fast.
969968
pub fn get(&mut self) -> Span {
970-
let idx = self.current_frame_idx();
971-
self.stack().get(idx).map(Frame::current_span).unwrap_or(rustc_span::DUMMY_SP)
969+
self.stack()
970+
.get(self.top_local_frame())
971+
.map(Frame::current_span)
972+
.unwrap_or(rustc_span::DUMMY_SP)
972973
}
973974

974975
/// Returns the span of the *caller* of the current operation, again
@@ -979,7 +980,7 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
979980
pub fn get_caller(&mut self) -> Span {
980981
// We need to go down at least to the caller (len - 2), or however
981982
// far we have to go to find a frame in a local crate.
982-
let local_frame_idx = self.current_frame_idx();
983+
let local_frame_idx = self.top_local_frame();
983984
let stack = self.stack();
984985
let idx = cmp::min(local_frame_idx, stack.len().saturating_sub(2));
985986
stack.get(idx).map(Frame::current_span).unwrap_or(rustc_span::DUMMY_SP)
@@ -989,33 +990,8 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> {
989990
self.machine.threads.active_thread_stack()
990991
}
991992

992-
fn current_frame_idx(&mut self) -> usize {
993-
*self
994-
.current_frame_idx
995-
.get_or_insert_with(|| Self::compute_current_frame_index(self.machine))
996-
}
997-
998-
// Find the position of the inner-most frame which is part of the crate being
999-
// compiled/executed, part of the Cargo workspace, and is also not #[track_caller].
1000-
#[inline(never)]
1001-
fn compute_current_frame_index(machine: &MiriMachine<'_, '_>) -> usize {
1002-
machine
1003-
.threads
1004-
.active_thread_stack()
1005-
.iter()
1006-
.enumerate()
1007-
.rev()
1008-
.find_map(|(idx, frame)| {
1009-
let def_id = frame.instance.def_id();
1010-
if (def_id.is_local() || machine.local_crates.contains(&def_id.krate))
1011-
&& !frame.instance.def.requires_caller_location(machine.tcx)
1012-
{
1013-
Some(idx)
1014-
} else {
1015-
None
1016-
}
1017-
})
1018-
.unwrap_or(0)
993+
fn top_local_frame(&self) -> usize {
994+
self.machine.threads.active_thread_ref().top_local_frame
1019995
}
1020996
}
1021997

src/machine.rs

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ pub struct FrameData<'tcx> {
5050
/// for the start of this frame. When we finish executing this frame,
5151
/// we use this to register a completed event with `measureme`.
5252
pub timing: Option<measureme::DetachedTiming>,
53+
54+
pub is_local: bool,
5355
}
5456

5557
impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
5658
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5759
// Omitting `timing`, it does not support `Debug`.
58-
let FrameData { stacked_borrows, catch_unwind, timing: _ } = self;
60+
let FrameData { stacked_borrows, catch_unwind, timing: _, is_local: _ } = self;
5961
f.debug_struct("FrameData")
6062
.field("stacked_borrows", stacked_borrows)
6163
.field("catch_unwind", catch_unwind)
@@ -65,7 +67,7 @@ impl<'tcx> std::fmt::Debug for FrameData<'tcx> {
6567

6668
impl VisitTags for FrameData<'_> {
6769
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
68-
let FrameData { catch_unwind, stacked_borrows, timing: _ } = self;
70+
let FrameData { catch_unwind, stacked_borrows, timing: _, is_local: _ } = self;
6971

7072
catch_unwind.visit_tags(visit);
7173
stacked_borrows.visit_tags(visit);
@@ -1004,6 +1006,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10041006
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
10051007
range: AllocRange,
10061008
) -> InterpResult<'tcx> {
1009+
let mut current_span = machine.current_span();
10071010
if let Some(data_race) = &alloc_extra.data_race {
10081011
data_race.read(
10091012
alloc_id,
@@ -1018,7 +1021,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10181021
prov_extra,
10191022
range,
10201023
machine.stacked_borrows.as_ref().unwrap(),
1021-
machine.current_span(),
1024+
&mut current_span,
10221025
&machine.threads,
10231026
)?;
10241027
}
@@ -1036,21 +1039,23 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10361039
(alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra),
10371040
range: AllocRange,
10381041
) -> InterpResult<'tcx> {
1039-
if let Some(data_race) = &mut alloc_extra.data_race {
1040-
data_race.write(
1042+
let mut current_span = machine.current_span();
1043+
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
1044+
stacked_borrows.get_mut().before_memory_write(
10411045
alloc_id,
1046+
prov_extra,
10421047
range,
1043-
machine.data_race.as_mut().unwrap(),
1048+
machine.stacked_borrows.as_ref().unwrap(),
1049+
&mut current_span,
10441050
&machine.threads,
10451051
)?;
10461052
}
1047-
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
1048-
stacked_borrows.get_mut().before_memory_write(
1053+
if let Some(data_race) = &mut alloc_extra.data_race {
1054+
let _span = current_span.get();
1055+
data_race.write(
10491056
alloc_id,
1050-
prov_extra,
10511057
range,
1052-
machine.stacked_borrows.as_ref().unwrap(),
1053-
machine.current_span(),
1058+
machine.data_race.as_mut().unwrap(),
10541059
&machine.threads,
10551060
)?;
10561061
}
@@ -1071,26 +1076,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
10711076
if machine.tracked_alloc_ids.contains(&alloc_id) {
10721077
machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
10731078
}
1074-
if let Some(data_race) = &mut alloc_extra.data_race {
1075-
data_race.deallocate(
1079+
let mut current_span = machine.current_span();
1080+
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
1081+
stacked_borrows.get_mut().before_memory_deallocation(
10761082
alloc_id,
1083+
prove_extra,
10771084
range,
1078-
machine.data_race.as_mut().unwrap(),
1085+
machine.stacked_borrows.as_ref().unwrap(),
1086+
&mut current_span,
10791087
&machine.threads,
10801088
)?;
10811089
}
1082-
if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows {
1083-
stacked_borrows.get_mut().before_memory_deallocation(
1090+
if let Some(data_race) = &mut alloc_extra.data_race {
1091+
data_race.deallocate(
10841092
alloc_id,
1085-
prove_extra,
10861093
range,
1087-
machine.stacked_borrows.as_ref().unwrap(),
1088-
machine.current_span(),
1094+
machine.data_race.as_mut().unwrap(),
10891095
&machine.threads,
1090-
)
1091-
} else {
1092-
Ok(())
1096+
)?;
10931097
}
1098+
Ok(())
10941099
}
10951100

10961101
#[inline(always)]
@@ -1122,13 +1127,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
11221127
None
11231128
};
11241129

1130+
let def_id = frame.instance.def_id();
1131+
let is_local = (def_id.is_local() || ecx.machine.local_crates.contains(&def_id.krate))
1132+
&& !frame.instance.def.requires_caller_location(ecx.machine.tcx);
1133+
1134+
if is_local {
1135+
let stack_len = ecx.active_thread_stack().len();
1136+
ecx.active_thread_mut().top_local_frame = stack_len;
1137+
}
1138+
11251139
let stacked_borrows = ecx.machine.stacked_borrows.as_ref();
11261140

11271141
let extra = FrameData {
11281142
stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame(&ecx.machine)),
11291143
catch_unwind: None,
11301144
timing,
1145+
is_local,
11311146
};
1147+
11321148
Ok(frame.with_extra(extra))
11331149
}
11341150

@@ -1189,6 +1205,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
11891205
if let Some(stacked_borrows) = &ecx.machine.stacked_borrows {
11901206
stacked_borrows.borrow_mut().end_call(&frame.extra);
11911207
}
1208+
ecx.machine.threads.reset_top_local();
11921209
let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
11931210
if let Some(profiler) = ecx.machine.profiler.as_ref() {
11941211
profiler.finish_recording_interval_event(timing.unwrap());

src/stacked_borrows/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ impl Stacks {
621621
tag: ProvenanceExtra,
622622
range: AllocRange,
623623
state: &GlobalState,
624-
mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
624+
current_span: &mut CurrentSpan<'ecx, 'mir, 'tcx>,
625625
threads: &'ecx ThreadManager<'mir, 'tcx>,
626626
) -> InterpResult<'tcx>
627627
where
@@ -633,7 +633,7 @@ impl Stacks {
633633
Pointer::new(alloc_id, range.start),
634634
range.size.bytes()
635635
);
636-
let dcx = DiagnosticCxBuilder::read(&mut current_span, threads, tag, range);
636+
let dcx = DiagnosticCxBuilder::read(current_span, threads, tag, range);
637637
let mut state = state.borrow_mut();
638638
self.for_each(range, dcx, |stack, dcx, exposed_tags| {
639639
stack.access(AccessKind::Read, tag, &mut state, dcx, exposed_tags)
@@ -647,7 +647,7 @@ impl Stacks {
647647
tag: ProvenanceExtra,
648648
range: AllocRange,
649649
state: &GlobalState,
650-
mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
650+
current_span: &mut CurrentSpan<'ecx, 'mir, 'tcx>,
651651
threads: &'ecx ThreadManager<'mir, 'tcx>,
652652
) -> InterpResult<'tcx> {
653653
trace!(
@@ -656,7 +656,7 @@ impl Stacks {
656656
Pointer::new(alloc_id, range.start),
657657
range.size.bytes()
658658
);
659-
let dcx = DiagnosticCxBuilder::write(&mut current_span, threads, tag, range);
659+
let dcx = DiagnosticCxBuilder::write(current_span, threads, tag, range);
660660
let mut state = state.borrow_mut();
661661
self.for_each(range, dcx, |stack, dcx, exposed_tags| {
662662
stack.access(AccessKind::Write, tag, &mut state, dcx, exposed_tags)
@@ -670,11 +670,11 @@ impl Stacks {
670670
tag: ProvenanceExtra,
671671
range: AllocRange,
672672
state: &GlobalState,
673-
mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>,
673+
current_span: &mut CurrentSpan<'ecx, 'mir, 'tcx>,
674674
threads: &'ecx ThreadManager<'mir, 'tcx>,
675675
) -> InterpResult<'tcx> {
676676
trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes());
677-
let dcx = DiagnosticCxBuilder::dealloc(&mut current_span, threads, tag);
677+
let dcx = DiagnosticCxBuilder::dealloc(current_span, threads, tag);
678678
let state = state.borrow();
679679
self.for_each(range, dcx, |stack, dcx, exposed_tags| {
680680
stack.dealloc(tag, &state, dcx, exposed_tags)

0 commit comments

Comments
 (0)