/// 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>,
}
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();
}
}
-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(
}
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) => {
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;
+
+ 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.steps_until_detector_enabled == 0 {
- let _ = self.loop_detector.observe(&self.machine, &self.stack, &self.memory); // TODO: Handle error
+ 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.
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());