Skip to content

Commit c6aea93

Browse files
Enable loop detector in step loop
The detector runs every `DETECTOR_SNAPSHOT_PERIOD` steps. Since the number of steps can increase by more than 1 (I'd like to remove this), the detector may fail if the step counter is incremented past the scheduled detection point during the loop.
1 parent f7e9d2a commit c6aea93

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

src/librustc_mir/interpret/eval_context.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
4545

4646
/// The number of terminators to be evaluated before enabling the infinite
4747
/// loop detector.
48-
pub(crate) steps_until_detector_enabled: usize,
48+
pub(crate) steps_until_detector_enabled: isize,
4949

5050
pub(crate) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
5151
}
@@ -175,12 +175,17 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
175175
where M: Clone + Eq + Hash + Machine<'mir, 'tcx>,
176176
'tcx: 'a + 'mir,
177177
{
178-
pub fn observe(
178+
/// Returns `true` if the loop detector has not yet observed a snapshot.
179+
pub fn is_empty(&self) -> bool {
180+
self.bloom.is_empty()
181+
}
182+
183+
pub fn observe_and_analyze(
179184
&mut self,
180185
machine: &M,
181186
stack: &Vec<Frame<'mir, 'tcx>>,
182187
memory: &Memory<'a, 'mir, 'tcx, M>,
183-
) -> EvalResult<'_, ()> {
188+
) -> EvalResult<'tcx, ()> {
184189
let snapshot = (machine, stack, memory);
185190

186191
let mut fx = FxHasher::default();
@@ -286,7 +291,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf
286291
}
287292
}
288293

289-
const MAX_TERMINATORS: usize = 1_000_000;
294+
const MAX_TERMINATORS: isize = 1_000_000;
290295

291296
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
292297
pub fn new(
@@ -656,7 +661,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
656661
}
657662

658663
Aggregate(ref kind, ref operands) => {
659-
self.inc_step_counter_and_detect_loops(operands.len());
664+
self.inc_step_counter_and_detect_loops(operands.len())?;
660665

661666
let (dest, active_field_index) = match **kind {
662667
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {

src/librustc_mir/interpret/step.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,34 @@ use super::{EvalContext, Machine};
1212
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
1313
where M: Clone + Eq + Hash,
1414
{
15-
pub fn inc_step_counter_and_detect_loops(&mut self, n: usize) {
16-
self.steps_until_detector_enabled
17-
= self.steps_until_detector_enabled.saturating_sub(n);
15+
/// Returns `true` if the loop detector should take a snapshot during the current step.
16+
pub fn is_loop_detector_scheduled(&self) -> bool {
17+
/// The number of steps between loop detector snapshots.
18+
/// Should be a power of two for performance reasons.
19+
const LOOP_SNAPSHOT_PERIOD: isize = 1 << 8;
20+
21+
let steps = self.steps_until_detector_enabled;
22+
steps <= 0 && steps % LOOP_SNAPSHOT_PERIOD == 0
23+
}
24+
25+
pub fn inc_step_counter_and_detect_loops(&mut self, n: usize) -> EvalResult<'tcx, ()> {
26+
// TODO: Remove `as` cast
27+
self.steps_until_detector_enabled =
28+
self.steps_until_detector_enabled.saturating_sub(n as isize);
1829

19-
if self.steps_until_detector_enabled == 0 {
20-
let _ = self.loop_detector.observe(&self.machine, &self.stack, &self.memory); // TODO: Handle error
30+
if !self.is_loop_detector_scheduled() {
31+
return Ok(());
32+
}
33+
34+
if self.loop_detector.is_empty() {
35+
// First run of the loop detector
2136

2237
// FIXME(#49980): make this warning a lint
23-
self.tcx.sess.span_warn(self.frame().span, "Constant evaluating a complex constant, this might take some time");
24-
self.steps_until_detector_enabled = 1_000_000;
38+
self.tcx.sess.span_warn(self.frame().span,
39+
"Constant evaluating a complex constant, this might take some time");
2540
}
41+
42+
self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
2643
}
2744

2845
/// Returns true as long as there are more things to do.
@@ -44,7 +61,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
4461
return Ok(true);
4562
}
4663

47-
self.inc_step_counter_and_detect_loops(1);
64+
self.inc_step_counter_and_detect_loops(1)?;
4865

4966
let terminator = basic_block.terminator();
5067
assert_eq!(old_frames, self.cur_frame());

0 commit comments

Comments
 (0)