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

Implement Hash in terms of HashStable for EvalSnapshot

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