提交 a083aa02 编写于 作者: B Bruno Dutra

Implement Hash in terms of HashStable for EvalSnapshot

上级 03007740
......@@ -412,7 +412,7 @@ fn hash_stable<W: StableHasherResult>(
ty::tls::with_opt(|tcx| {
trace!("hashing {:?}", *self);
let tcx = tcx.expect("can't hash AllocIds during hir lowering");
let alloc_kind = tcx.alloc_map.lock().get(*self).expect("no value for AllocId");
let alloc_kind = tcx.alloc_map.lock().get(*self);
alloc_kind.hash_stable(hcx, hasher);
});
}
......
......@@ -281,6 +281,23 @@ fn hash_stable<W: StableHasherResult>(&self,
}
}
impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
where T1: HashStable<CTX>,
T2: HashStable<CTX>,
T3: HashStable<CTX>,
T4: HashStable<CTX>,
{
fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
hasher: &mut StableHasher<W>) {
let (ref _0, ref _1, ref _2, ref _3) = *self;
_0.hash_stable(ctx, hasher);
_1.hash_stable(ctx, hasher);
_2.hash_stable(ctx, hasher);
_3.hash_stable(ctx, hasher);
}
}
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
default fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
......
......@@ -196,6 +196,8 @@ fn into(self) -> EvalError<'tcx> {
}
}
impl_stable_hash_for!(struct CompileTimeEvaluator {});
#[derive(Clone, Debug)]
enum ConstEvalError {
NeedsRfc(String),
......
......@@ -15,6 +15,7 @@
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
use rustc::hir::map::definitions::DefPathData;
use rustc::ich::{StableHashingContext, StableHashingContextProvider};
use rustc::mir;
use rustc::ty::layout::{
self, Size, Align, HasDataLayout, LayoutOf, TyLayout
......@@ -22,8 +23,9 @@
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::query::TyCtxtAt;
use rustc_data_structures::fx::{FxHashSet, FxHasher};
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::{
GlobalId, Scalar, FrameInfo,
EvalResult, EvalErrorKind,
......@@ -134,12 +136,12 @@ fn eq(&self, other: &Self) -> bool {
}
}
impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> {
fn hash<H: Hasher>(&self, state: &mut H) {
impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) {
let Frame {
mir: _,
mir,
instance,
span: _,
span,
return_to_block,
return_place,
locals,
......@@ -147,12 +149,8 @@ fn hash<H: Hasher>(&self, state: &mut H) {
stmt,
} = self;
instance.hash(state);
return_to_block.hash(state);
return_place.hash(state);
locals.hash(state);
block.hash(state);
stmt.hash(state);
(mir, instance, span, return_to_block).hash_stable(hcx, hasher);
(return_place, locals, block, stmt).hash_stable(hcx, hasher);
}
}
......@@ -168,6 +166,15 @@ pub enum StackPopCleanup {
None { cleanup: bool },
}
impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'b>, hasher: &mut StableHasher<W>) {
match self {
StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
}
}
}
// State of a local variable
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum LocalValue {
......@@ -195,9 +202,14 @@ pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> {
}
}
impl_stable_hash_for!(enum self::LocalValue {
Dead,
Live(x),
});
/// The virtual machine state during const-evaluation at a given point in time.
#[derive(Eq, PartialEq, Hash)]
pub(crate) struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
#[derive(Eq, PartialEq)]
struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
machine: M,
memory: Memory<'a, 'mir, 'tcx, M>,
stack: Vec<Frame<'mir, 'tcx>>,
......@@ -215,6 +227,27 @@ fn new<'b>(machine: &M, memory: &Memory<'a, 'mir, 'tcx, M>, stack: &[Frame<'mir,
}
}
impl<'a, 'mir, 'tcx, M> Hash for EvalSnapshot<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>,
{
fn hash<H: Hasher>(&self, state: &mut H) {
// Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2)
let mut hcx = self.memory.tcx.get_stable_hashing_context();
let mut hasher = StableHasher::<u64>::new();
self.hash_stable(&mut hcx, &mut hasher);
hasher.finish().hash(state)
}
}
impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>> for EvalSnapshot<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>,
{
fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'b>, hasher: &mut StableHasher<W>) {
let EvalSnapshot{ machine, memory, stack } = self;
(machine, &memory.data, stack).hash_stable(hcx, hasher);
}
}
pub(super) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
/// The set of all `EvalSnapshot` *hashes* observed by this detector.
///
......@@ -258,9 +291,10 @@ pub fn observe_and_analyze(
stack: &[Frame<'mir, 'tcx>],
) -> EvalResult<'tcx, ()> {
let mut fx = FxHasher::default();
(machine, memory, stack).hash(&mut fx);
let hash = fx.finish();
let mut hcx = memory.tcx.get_stable_hashing_context();
let mut hasher = StableHasher::<u64>::new();
(machine, stack).hash_stable(&mut hcx, &mut hasher);
let hash = hasher.finish();
if self.hashes.insert(hash) {
// No collision
......
......@@ -15,17 +15,19 @@
use std::hash::Hash;
use rustc::hir::def_id::DefId;
use rustc::ich::StableHashingContext;
use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
use rustc_data_structures::stable_hasher::HashStable;
use super::{EvalContext, PlaceTy, OpTy};
/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied
pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>> {
/// Additional data that can be accessed via the Memory
type MemoryData: Clone + Eq + Hash;
type MemoryData: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>>;
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash;
......
......@@ -17,7 +17,6 @@
//! short-circuiting the empty case!
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
use std::ptr;
use rustc::ty::{self, Instance, query::TyCtxtAt};
......@@ -26,7 +25,7 @@
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
truncate};
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use syntax::ast::Mutability;
......@@ -91,37 +90,6 @@ fn eq(&self, other: &Self) -> bool {
}
}
impl<'a, 'mir, 'tcx, M> Hash for Memory<'a, 'mir, 'tcx, M>
where M: Machine<'mir, 'tcx>,
'tcx: 'a + 'mir,
{
fn hash<H: Hasher>(&self, state: &mut H) {
let Memory {
data,
alloc_map: _,
tcx: _,
} = self;
data.hash(state);
// We ignore some fields which don't change between evaluation steps.
// Since HashMaps which contain the same items may have different
// iteration orders, we use a commutative operation (in this case
// addition, but XOR would also work), to combine the hash of each
// `Allocation`.
self.alloc_map.iter()
.map(|(&id, alloc)| {
let mut h = FxHasher::default();
id.hash(&mut h);
alloc.hash(&mut h);
h.finish()
})
.fold(0u64, |hash, x| hash.wrapping_add(x))
.hash(state);
}
}
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
Memory {
......
......@@ -81,6 +81,11 @@ pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> {
}
}
impl_stable_hash_for!(enum ::interpret::Value {
Scalar(x),
ScalarPair(x, y),
});
// ScalarPair needs a type to interpret, so we often have a value and a type together
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
......@@ -126,6 +131,11 @@ pub fn to_immediate(self) -> Value {
}
}
impl_stable_hash_for!(enum ::interpret::Operand {
Immediate(x),
Indirect(x),
});
#[derive(Copy, Clone, Debug)]
pub struct OpTy<'tcx> {
crate op: Operand, // ideally we'd make this private, but const_prop needs this
......
......@@ -14,10 +14,12 @@
use std::convert::TryFrom;
use rustc::ich::StableHashingContext;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
use rustc::mir::interpret::{
GlobalId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
......@@ -37,6 +39,12 @@ pub struct MemPlace {
pub extra: Option<Scalar>,
}
impl_stable_hash_for!(struct ::interpret::MemPlace {
ptr,
align,
extra,
});
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum Place {
/// A place referring to a value allocated in the `Memory` system.
......@@ -50,6 +58,18 @@ pub enum Place {
},
}
impl<'a> HashStable<StableHashingContext<'a>> for Place {
fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) {
match self {
Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
Place::Local { frame, local } => {
frame.hash_stable(hcx, hasher);
local.hash_stable(hcx, hasher);
},
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct PlaceTy<'tcx> {
place: Place,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册