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.
This commit is contained in:
parent
f7e9d2ac3e
commit
c6aea935cf
2 changed files with 35 additions and 13 deletions
|
|
@ -45,7 +45,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
|||
|
||||
/// The number of terminators to be evaluated before enabling the infinite
|
||||
/// loop detector.
|
||||
pub(crate) steps_until_detector_enabled: usize,
|
||||
pub(crate) steps_until_detector_enabled: isize,
|
||||
|
||||
pub(crate) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
|
||||
}
|
||||
|
|
@ -175,12 +175,17 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
|
|||
where M: Clone + Eq + Hash + Machine<'mir, 'tcx>,
|
||||
'tcx: 'a + 'mir,
|
||||
{
|
||||
pub fn observe(
|
||||
/// Returns `true` if the loop detector has not yet observed a snapshot.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.bloom.is_empty()
|
||||
}
|
||||
|
||||
pub fn observe_and_analyze(
|
||||
&mut self,
|
||||
machine: &M,
|
||||
stack: &Vec<Frame<'mir, 'tcx>>,
|
||||
memory: &Memory<'a, 'mir, 'tcx, M>,
|
||||
) -> EvalResult<'_, ()> {
|
||||
) -> EvalResult<'tcx, ()> {
|
||||
let snapshot = (machine, stack, memory);
|
||||
|
||||
let mut fx = FxHasher::default();
|
||||
|
|
@ -286,7 +291,7 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf
|
|||
}
|
||||
}
|
||||
|
||||
const MAX_TERMINATORS: usize = 1_000_000;
|
||||
const MAX_TERMINATORS: isize = 1_000_000;
|
||||
|
||||
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
pub fn new(
|
||||
|
|
@ -656,7 +661,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
}
|
||||
|
||||
Aggregate(ref kind, ref operands) => {
|
||||
self.inc_step_counter_and_detect_loops(operands.len());
|
||||
self.inc_step_counter_and_detect_loops(operands.len())?;
|
||||
|
||||
let (dest, active_field_index) = match **kind {
|
||||
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
|
||||
|
|
|
|||
|
|
@ -12,17 +12,34 @@ use super::{EvalContext, Machine};
|
|||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
|
||||
where M: Clone + Eq + Hash,
|
||||
{
|
||||
pub fn inc_step_counter_and_detect_loops(&mut self, n: usize) {
|
||||
self.steps_until_detector_enabled
|
||||
= self.steps_until_detector_enabled.saturating_sub(n);
|
||||
/// Returns `true` if the loop detector should take a snapshot during the current step.
|
||||
pub fn is_loop_detector_scheduled(&self) -> bool {
|
||||
/// The number of steps between loop detector snapshots.
|
||||
/// Should be a power of two for performance reasons.
|
||||
const LOOP_SNAPSHOT_PERIOD: isize = 1 << 8;
|
||||
|
||||
if self.steps_until_detector_enabled == 0 {
|
||||
let _ = self.loop_detector.observe(&self.machine, &self.stack, &self.memory); // TODO: Handle error
|
||||
let steps = self.steps_until_detector_enabled;
|
||||
steps <= 0 && steps % LOOP_SNAPSHOT_PERIOD == 0
|
||||
}
|
||||
|
||||
pub fn inc_step_counter_and_detect_loops(&mut self, n: usize) -> EvalResult<'tcx, ()> {
|
||||
// TODO: Remove `as` cast
|
||||
self.steps_until_detector_enabled =
|
||||
self.steps_until_detector_enabled.saturating_sub(n as isize);
|
||||
|
||||
if !self.is_loop_detector_scheduled() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.loop_detector.is_empty() {
|
||||
// First run of the loop detector
|
||||
|
||||
// FIXME(#49980): make this warning a lint
|
||||
self.tcx.sess.span_warn(self.frame().span, "Constant evaluating a complex constant, this might take some time");
|
||||
self.steps_until_detector_enabled = 1_000_000;
|
||||
self.tcx.sess.span_warn(self.frame().span,
|
||||
"Constant evaluating a complex constant, this might take some time");
|
||||
}
|
||||
|
||||
self.loop_detector.observe_and_analyze(&self.machine, &self.stack, &self.memory)
|
||||
}
|
||||
|
||||
/// 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>
|
|||
return Ok(true);
|
||||
}
|
||||
|
||||
self.inc_step_counter_and_detect_loops(1);
|
||||
self.inc_step_counter_and_detect_loops(1)?;
|
||||
|
||||
let terminator = basic_block.terminator();
|
||||
assert_eq!(old_frames, self.cur_frame());
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue