From 61a999a531d03c73626716e2b48d259e13f3b6af Mon Sep 17 00:00:00 2001 From: Bruno Dutra Date: Sat, 1 Sep 2018 21:16:22 +0200 Subject: [PATCH] Move InfiniteLoopDetector to snapshot.rs --- src/librustc_mir/interpret/eval_context.rs | 71 +------------------- src/librustc_mir/interpret/snapshot.rs | 77 ++++++++++++++++++++-- 2 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index bc03ef8c025c1..f7277f8d27610 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -14,7 +14,7 @@ use std::mem; use rustc::hir::def_id::DefId; use rustc::hir::def::Def; use rustc::hir::map::definitions::DefPathData; -use rustc::ich::{StableHashingContext, StableHashingContextProvider}; +use rustc::ich::StableHashingContext; use rustc::mir; use rustc::ty::layout::{ self, Size, Align, HasDataLayout, LayoutOf, TyLayout @@ -22,7 +22,6 @@ use rustc::ty::layout::{ use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::query::TyCtxtAt; -use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use rustc::mir::interpret::{ @@ -39,7 +38,7 @@ use super::{ Memory, Machine }; -use super::snapshot::EvalSnapshot; +use super::snapshot::InfiniteLoopDetector; pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. @@ -189,72 +188,6 @@ impl_stable_hash_for!(enum self::LocalValue { Live(x), }); -pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { - /// The set of all `EvalSnapshot` *hashes* observed by this detector. - /// - /// When a collision occurs in this table, we store the full snapshot in - /// `snapshots`. - hashes: FxHashSet, - - /// The set of all `EvalSnapshot`s observed by this detector. - /// - /// An `EvalSnapshot` will only be fully cloned once it has caused a - /// collision in `hashes`. As a result, the detector must observe at least - /// *two* full cycles of an infinite loop before it triggers. - snapshots: FxHashSet>, -} - -impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M> - where M: Machine<'mir, 'tcx>, - 'tcx: 'a + 'mir, -{ - fn default() -> Self { - InfiniteLoopDetector { - hashes: FxHashSet::default(), - snapshots: FxHashSet::default(), - } - } -} - -impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M> - where M: Machine<'mir, 'tcx>, - 'tcx: 'a + 'mir, -{ - /// Returns `true` if the loop detector has not yet observed a snapshot. - pub fn is_empty(&self) -> bool { - self.hashes.is_empty() - } - - pub fn observe_and_analyze( - &mut self, - tcx: &TyCtxt<'b, 'tcx, 'tcx>, - machine: &M, - memory: &Memory<'a, 'mir, 'tcx, M>, - stack: &[Frame<'mir, 'tcx>], - ) -> EvalResult<'tcx, ()> { - - let mut hcx = tcx.get_stable_hashing_context(); - let mut hasher = StableHasher::::new(); - (machine, stack).hash_stable(&mut hcx, &mut hasher); - let hash = hasher.finish(); - - if self.hashes.insert(hash) { - // No collision - return Ok(()) - } - - info!("snapshotting the state of the interpreter"); - - if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) { - // Spurious collision or first cycle - return Ok(()) - } - - // Second cycle - Err(EvalErrorKind::InfiniteLoop.into()) - } -} - impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'a, 'mir, 'tcx, M> { #[inline] fn data_layout(&self) -> &layout::TargetDataLayout { diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 72cc6220470da..316c80d18c11c 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -3,11 +3,14 @@ use std::hash::{Hash, Hasher}; use rustc::ich::{StableHashingContext, StableHashingContextProvider}; use rustc::mir; use rustc::mir::interpret::{ - AllocId, Pointer, Scalar, ScalarMaybeUndef, Relocations, Allocation, UndefMask + AllocId, Pointer, Scalar, ScalarMaybeUndef, + Relocations, Allocation, UndefMask, + EvalResult, EvalErrorKind, }; -use rustc::ty; +use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::Align; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use syntax::ast::Mutability; @@ -16,6 +19,72 @@ use syntax::source_map::Span; use super::eval_context::{LocalValue, StackPopCleanup}; use super::{Frame, Memory, Machine, Operand, MemPlace, Place, Value}; +pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { + /// The set of all `EvalSnapshot` *hashes* observed by this detector. + /// + /// When a collision occurs in this table, we store the full snapshot in + /// `snapshots`. + hashes: FxHashSet, + + /// The set of all `EvalSnapshot`s observed by this detector. + /// + /// An `EvalSnapshot` will only be fully cloned once it has caused a + /// collision in `hashes`. As a result, the detector must observe at least + /// *two* full cycles of an infinite loop before it triggers. + snapshots: FxHashSet>, +} + +impl<'a, 'mir, 'tcx, M> Default for InfiniteLoopDetector<'a, 'mir, 'tcx, M> + where M: Machine<'mir, 'tcx>, + 'tcx: 'a + 'mir, +{ + fn default() -> Self { + InfiniteLoopDetector { + hashes: FxHashSet::default(), + snapshots: FxHashSet::default(), + } + } +} + +impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M> + where M: Machine<'mir, 'tcx>, + 'tcx: 'a + 'mir, +{ + /// Returns `true` if the loop detector has not yet observed a snapshot. + pub fn is_empty(&self) -> bool { + self.hashes.is_empty() + } + + pub fn observe_and_analyze( + &mut self, + tcx: &TyCtxt<'b, 'tcx, 'tcx>, + machine: &M, + memory: &Memory<'a, 'mir, 'tcx, M>, + stack: &[Frame<'mir, 'tcx>], + ) -> EvalResult<'tcx, ()> { + + let mut hcx = tcx.get_stable_hashing_context(); + let mut hasher = StableHasher::::new(); + (machine, stack).hash_stable(&mut hcx, &mut hasher); + let hash = hasher.finish(); + + if self.hashes.insert(hash) { + // No collision + return Ok(()) + } + + info!("snapshotting the state of the interpreter"); + + if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) { + // Spurious collision or first cycle + return Ok(()) + } + + // Second cycle + Err(EvalErrorKind::InfiniteLoop.into()) + } +} + trait SnapshotContext<'a> { fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>; } @@ -269,7 +338,7 @@ impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M> } /// The virtual machine state during const-evaluation at a given point in time. -pub struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { +struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { machine: M, memory: Memory<'a, 'mir, 'tcx, M>, stack: Vec>, @@ -278,7 +347,7 @@ pub struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { impl<'a, 'mir, 'tcx, M> EvalSnapshot<'a, 'mir, 'tcx, M> where M: Machine<'mir, 'tcx>, { - pub fn new( + fn new( machine: &M, memory: &Memory<'a, 'mir, 'tcx, M>, stack: &[Frame<'mir, 'tcx>]) -> Self {