use std::fmt::Write;
-use std::mem;
+use std::hash::{Hash, Hasher};
+use std::{mem, ptr};
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
pub(crate) terminators_remaining: usize,
}
-struct EvalState<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
+pub(crate) struct EvalState<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
/// The virtual memory system.
memory: Memory<'a, 'mir, 'tcx, M>,
stack: Vec<Frame<'mir, 'tcx>>,
}
+impl<'a, 'mir, 'tcx, M> Clone for EvalState<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ fn clone(&self) -> Self {
+ EvalState {
+ memory: self.memory.clone(),
+ stack: self.stack.clone(),
+ }
+ }
+}
+
+impl<'a, 'mir, 'tcx, M> Eq for EvalState<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{}
+
+impl<'a, 'mir, 'tcx, M> PartialEq for EvalState<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.memory == other.memory
+ && self.stack == other.stack
+ }
+}
+
+impl<'a, 'mir, 'tcx, M> Hash for EvalState<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.memory.hash(state);
+ self.stack.hash(state);
+ }
+}
/// A stack frame.
+#[derive(Clone)]
pub struct Frame<'mir, 'tcx: 'mir> {
////////////////////////////////////////////////////////////////////////////////
// Function and callsite information
pub stmt: usize,
}
+impl<'mir, 'tcx: 'mir> Eq for Frame<'mir, 'tcx> {}
+
+impl<'mir, 'tcx: 'mir> PartialEq for Frame<'mir, 'tcx> {
+ fn eq(&self, other: &Self) -> bool {
+ let Frame {
+ mir,
+ instance: _,
+ span: _,
+ return_to_block,
+ return_place,
+ locals,
+ block,
+ stmt,
+ } = self;
+
+ ptr::eq(mir, &other.mir)
+ && *return_to_block == other.return_to_block // TODO: Are these two necessary?
+ && *return_place == other.return_place
+ && *locals == other.locals
+ && *block == other.block
+ && *stmt == other.stmt
+ }
+}
+
+impl<'mir, 'tcx: 'mir> Hash for Frame<'mir, 'tcx> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let Frame {
+ mir,
+ instance: _,
+ span: _,
+ return_to_block,
+ return_place,
+ locals,
+ block,
+ stmt,
+ } = self;
+
+ (mir as *const _ as usize).hash(state);
+ return_to_block.hash(state);
+ return_place.hash(state);
+ locals.hash(state);
+ block.hash(state);
+ stmt.hash(state);
+ }
+}
+
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum StackPopCleanup {
/// The stackframe existed to compute the initial value of a static/constant, make sure it
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.
+use std::hash::Hash;
+
use rustc::mir::interpret::{AllocId, EvalResult, Scalar, Pointer, AccessKind, GlobalId};
use super::{EvalContext, Place, ValTy, Memory};
/// and some use case dependent behaviour can instead be applied
pub trait Machine<'mir, 'tcx>: Sized {
/// Additional data that can be accessed via the Memory
- type MemoryData;
+ type MemoryData: Clone + Eq + Hash;
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
type MemoryKinds: ::std::fmt::Debug + PartialEq + Copy + Clone;
use std::collections::VecDeque;
+use std::hash::{Hash, Hasher};
use std::ptr;
use rustc::hir::def_id::DefId;
use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, Value,
EvalResult, Scalar, EvalErrorKind, GlobalId, AllocType};
pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
-use rustc_data_structures::fx::{FxHashSet, FxHashMap};
+use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
use syntax::ast::Mutability;
// Allocations and pointers
////////////////////////////////////////////////////////////////////////////////
-#[derive(Debug, PartialEq, Copy, Clone)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum MemoryKind<T> {
/// Error if deallocated except during a stack pop
Stack,
pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
}
+impl<'a, 'mir, 'tcx, M> Clone for Memory<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ fn clone(&self) -> Self {
+ Memory {
+ data: self.data.clone(),
+ alloc_kind: self.alloc_kind.clone(),
+ alloc_map: self.alloc_map.clone(),
+ cur_frame: self.cur_frame.clone(),
+ tcx: self.tcx.clone(),
+ }
+ }
+}
+
+impl<'a, 'mir, 'tcx, M> Eq for Memory<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{}
+
+impl<'a, 'mir, 'tcx, M> PartialEq for Memory<'a, 'mir, 'tcx, M>
+ where M: Machine<'mir, 'tcx>,
+ 'tcx: 'a + 'mir,
+{
+ fn eq(&self, other: &Self) -> bool {
+ let Memory {
+ data,
+ alloc_kind,
+ alloc_map,
+ cur_frame,
+ tcx,
+ } = self;
+
+ *data == other.data
+ && *alloc_kind == other.alloc_kind
+ && *alloc_map == other.alloc_map
+ && *cur_frame == other.cur_frame
+ && ptr::eq(tcx, &other.tcx)
+ }
+}
+
+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_kind: _,
+ alloc_map: _,
+ cur_frame,
+ tcx,
+ } = self;
+
+ data.hash(state);
+ cur_frame.hash(state);
+ (tcx as *const _ as usize).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.allocations()
+ .map(|allocs| {
+ let mut h = FxHasher::default();
+ allocs.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 {
for i in 0..size.bytes() {
let defined = undef_mask.get(src.offset + Size::from_bytes(i));
-
+
for j in 0..repeat {
dest_allocation.undef_mask.set(
dest.offset + Size::from_bytes(i + (size.bytes() * j)),
use super::{EvalContext, Machine, ValTy};
use interpret::memory::HasMemory;
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum Place {
/// A place referring to a value allocated in the `Memory` system.
Ptr {
Local { frame: usize, local: mir::Local },
}
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub enum PlaceExtra {
None,
Length(u64),