about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2017-07-27 09:14:04 -0700
committerRalf Jung <post@ralfj.de>2017-07-27 09:14:04 -0700
commit14c8e834b99ca3d422828b44ed0b2d4a76335be6 (patch)
treed3f3f31a6fd0a25727e2db69bb52c2c685df5298
parent4672cb7bde348a3096bf1e6125d3cff98bf52b4d (diff)
downloadrust-14c8e834b99ca3d422828b44ed0b2d4a76335be6.tar.gz
rust-14c8e834b99ca3d422828b44ed0b2d4a76335be6.zip
use Cell for memory's aligned flag to avoid infecting interfaces with 'fake' mutability
-rw-r--r--src/librustc_mir/interpret/eval_context.rs20
-rw-r--r--src/librustc_mir/interpret/lvalue.rs8
-rw-r--r--src/librustc_mir/interpret/memory.rs52
-rw-r--r--src/librustc_mir/interpret/step.rs2
-rw-r--r--src/librustc_mir/interpret/terminator/intrinsic.rs30
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs44
-rw-r--r--src/librustc_mir/interpret/validation.rs4
-rw-r--r--src/librustc_mir/interpret/value.rs8
8 files changed, 91 insertions, 77 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 5913ff168fc..c1ddfb9ffea 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -1161,7 +1161,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             Lvalue::Ptr { ptr, extra, aligned } => {
                 assert_eq!(extra, LvalueExtra::None);
-                self.write_maybe_aligned(aligned,
+                self.write_maybe_aligned_mut(aligned,
                     |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty))
             }
 
@@ -1193,7 +1193,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             //
             // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
             // knew for certain that there were no outstanding pointers to this allocation.
-            self.write_maybe_aligned(aligned,
+            self.write_maybe_aligned_mut(aligned,
                 |ectx| ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty))?;
 
         } else if let Value::ByRef(src_ptr, aligned) = src_val {
@@ -1208,7 +1208,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             // It is a valid optimization to attempt reading a primitive value out of the
             // source and write that into the destination without making an allocation, so
             // we do so here.
-            self.read_maybe_aligned(aligned, |ectx| {
+            self.read_maybe_aligned_mut(aligned, |ectx| {
                 if let Ok(Some(src_val)) = ectx.try_read_value(src_ptr, dest_ty) {
                     write_dest(ectx, src_val)?;
                 } else {
@@ -1235,7 +1235,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     ) -> EvalResult<'tcx> {
         match value {
             Value::ByRef(ptr, aligned) => {
-                self.read_maybe_aligned(aligned, |ectx| ectx.copy(ptr, dest, dest_ty))
+                self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty))
             },
             Value::ByVal(primval) => {
                 let size = self.type_size(dest_ty)?.expect("dest type must be sized");
@@ -1270,9 +1270,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         let field_1_size = self.type_size(field_1_ty.0)?.expect("pair element type must be sized");
         let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into();
         let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into();
-        self.write_maybe_aligned(!packed,
+        self.write_maybe_aligned_mut(!packed,
             |ectx| ectx.memory.write_primval(field_0_ptr, a, field_0_size))?;
-        self.write_maybe_aligned(!packed,
+        self.write_maybe_aligned_mut(!packed,
             |ectx| ectx.memory.write_primval(field_1_ptr, b, field_1_size))?;
         Ok(())
     }
@@ -1376,7 +1376,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         }
     }
 
-    pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub(super) fn read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
         if let Some(val) = self.try_read_value(ptr, ty)? {
             Ok(val)
         } else {
@@ -1400,7 +1400,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         }
     }
 
-    fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
+    fn try_read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
         use syntax::ast::FloatTy;
 
         let val = match ty.sty {
@@ -1512,7 +1512,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
         match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
-                let ptr = src.into_ptr(&mut self.memory)?;
+                let ptr = src.into_ptr(&self.memory)?;
                 // u64 cast is from usize to u64, which is always good
                 self.write_value(ptr.to_value_with_len(length as u64), dest, dest_ty)
             }
@@ -1526,7 +1526,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty);
                 let trait_ref = self.tcx.erase_regions(&trait_ref);
                 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
-                let ptr = src.into_ptr(&mut self.memory)?;
+                let ptr = src.into_ptr(&self.memory)?;
                 self.write_value(ptr.to_value_with_vtable(vtable), dest, dest_ty)
             },
 
diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs
index da357a6d1e7..4d4db267ecf 100644
--- a/src/librustc_mir/interpret/lvalue.rs
+++ b/src/librustc_mir/interpret/lvalue.rs
@@ -351,17 +351,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         Ok(Lvalue::Ptr { ptr, extra, aligned: aligned && !packed })
     }
 
-    pub(super) fn val_to_lvalue(&mut self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> {
+    pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> {
         Ok(match self.tcx.struct_tail(ty).sty {
             ty::TyDynamic(..) => {
-                let (ptr, vtable) = val.into_ptr_vtable_pair(&mut self.memory)?;
+                let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?;
                 Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable), aligned: true }
             },
             ty::TyStr | ty::TySlice(_) => {
-                let (ptr, len) = val.into_slice(&mut self.memory)?;
+                let (ptr, len) = val.into_slice(&self.memory)?;
                 Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len), aligned: true }
             },
-            _ => Lvalue::Ptr { ptr: val.into_ptr(&mut self.memory)?, extra: LvalueExtra::None, aligned: true },
+            _ => Lvalue::Ptr { ptr: val.into_ptr(&self.memory)?, extra: LvalueExtra::None, aligned: true },
         })
     }
 
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 591f5dc7fe8..2226744c6ab 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -1,6 +1,7 @@
 use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
 use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
 use std::{fmt, iter, ptr, mem, io, ops};
+use std::cell::Cell;
 
 use rustc::ty;
 use rustc::ty::layout::{self, TargetDataLayout, HasDataLayout};
@@ -266,8 +267,8 @@ pub struct Memory<'a, 'tcx> {
 
     /// To avoid having to pass flags to every single memory access, we have some global state saying whether
     /// alignment checking is currently enforced for read and/or write accesses.
-    reads_are_aligned: bool,
-    writes_are_aligned: bool,
+    reads_are_aligned: Cell<bool>,
+    writes_are_aligned: Cell<bool>,
 
     /// The current stack frame.  Used to check accesses against locks.
     cur_frame: usize,
@@ -287,8 +288,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
             literal_alloc_cache: HashMap::new(),
             thread_local: BTreeMap::new(),
             next_thread_local: 0,
-            reads_are_aligned: true,
-            writes_are_aligned: true,
+            reads_are_aligned: Cell::new(true),
+            writes_are_aligned: Cell::new(true),
             cur_frame: usize::max_value(),
         }
     }
@@ -796,7 +797,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
 impl<'a, 'tcx> Memory<'a, 'tcx> {
     fn get_bytes_unchecked(&self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &[u8]> {
         // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
-        if self.reads_are_aligned {
+        if self.reads_are_aligned.get() {
             self.check_align(ptr.into(), align)?;
         }
         if size == 0 {
@@ -813,7 +814,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
 
     fn get_bytes_unchecked_mut(&mut self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &mut [u8]> {
         // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
-        if self.writes_are_aligned {
+        if self.writes_are_aligned.get() {
             self.check_align(ptr.into(), align)?;
         }
         if size == 0 {
@@ -909,10 +910,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn copy(&mut self, src: Pointer, dest: Pointer, size: u64, align: u64, nonoverlapping: bool) -> EvalResult<'tcx> {
         if size == 0 {
             // Empty accesses don't need to be valid pointers, but they should still be aligned
-            if self.reads_are_aligned {
+            if self.reads_are_aligned.get() {
                 self.check_align(src, align)?;
             }
-            if self.writes_are_aligned {
+            if self.writes_are_aligned.get() {
                 self.check_align(dest, align)?;
             }
             return Ok(());
@@ -968,7 +969,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> {
         if size == 0 {
             // Empty accesses don't need to be valid pointers, but they should still be non-NULL
-            if self.reads_are_aligned {
+            if self.reads_are_aligned.get() {
                 self.check_align(ptr, 1)?;
             }
             return Ok(&[]);
@@ -979,7 +980,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx> {
         if src.is_empty() {
             // Empty accesses don't need to be valid pointers, but they should still be non-NULL
-            if self.writes_are_aligned {
+            if self.writes_are_aligned.get() {
                 self.check_align(ptr, 1)?;
             }
             return Ok(());
@@ -992,7 +993,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> {
         if count == 0 {
             // Empty accesses don't need to be valid pointers, but they should still be non-NULL
-            if self.writes_are_aligned {
+            if self.writes_are_aligned.get() {
                 self.check_align(ptr, 1)?;
             }
             return Ok(());
@@ -1399,23 +1400,36 @@ pub(crate) trait HasMemory<'a, 'tcx> {
     fn memory(&self) -> &Memory<'a, 'tcx>;
 
     // These are not supposed to be overriden.
-    fn read_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
+    fn read_maybe_aligned<F, T>(&self, aligned: bool, f: F) -> EvalResult<'tcx, T>
+        where F: FnOnce(&Self) -> EvalResult<'tcx, T>
+    {
+        let old = self.memory().reads_are_aligned.get();
+        // Do alignment checking if *all* nested calls say it has to be aligned.
+        self.memory().reads_are_aligned.set(old && aligned);
+        let t = f(self);
+        self.memory().reads_are_aligned.set(old);
+        t
+    }
+
+    fn read_maybe_aligned_mut<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
         where F: FnOnce(&mut Self) -> EvalResult<'tcx, T>
     {
-        let old = self.memory_mut().reads_are_aligned;
-        self.memory_mut().reads_are_aligned = old && aligned;
+        let old = self.memory().reads_are_aligned.get();
+        // Do alignment checking if *all* nested calls say it has to be aligned.
+        self.memory().reads_are_aligned.set(old && aligned);
         let t = f(self);
-        self.memory_mut().reads_are_aligned = old;
+        self.memory().reads_are_aligned.set(old);
         t
     }
 
-    fn write_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
+    fn write_maybe_aligned_mut<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
         where F: FnOnce(&mut Self) -> EvalResult<'tcx, T>
     {
-        let old = self.memory_mut().writes_are_aligned;
-        self.memory_mut().writes_are_aligned = old && aligned;
+        let old = self.memory().writes_are_aligned.get();
+        // Do alignment checking if *all* nested calls say it has to be aligned.
+        self.memory().writes_are_aligned.set(old && aligned);
         let t = f(self);
-        self.memory_mut().writes_are_aligned = old;
+        self.memory().writes_are_aligned.set(old);
         t
     }
 }
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 075fab36f64..b78945155f1 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -108,7 +108,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                             trace!("struct wrapped nullable pointer type: {}", ty);
                             // only the pointer part of a fat pointer is used for this space optimization
                             let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
-                            self.write_maybe_aligned(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?;
+                            self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?;
                         }
                     },
 
diff --git a/src/librustc_mir/interpret/terminator/intrinsic.rs b/src/librustc_mir/interpret/terminator/intrinsic.rs
index 2be5b7666f0..69dd41c82aa 100644
--- a/src/librustc_mir/interpret/terminator/intrinsic.rs
+++ b/src/librustc_mir/interpret/terminator/intrinsic.rs
@@ -45,7 +45,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "arith_offset" => {
                 let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
                 self.write_ptr(dest, result_ptr, dest_ty)?;
             }
@@ -61,7 +61,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "atomic_load_acq" |
             "volatile_load" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 self.write_value(Value::by_ref(ptr), dest, ty)?;
             }
 
@@ -70,7 +70,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "atomic_store_rel" |
             "volatile_store" => {
                 let ty = substs.type_at(0);
-                let dest = arg_vals[0].into_ptr(&mut self.memory)?;
+                let dest = arg_vals[0].into_ptr(&self.memory)?;
                 self.write_value_to_ptr(arg_vals[1], dest, ty)?;
             }
 
@@ -80,7 +80,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             _ if intrinsic_name.starts_with("atomic_xchg") => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let change = self.value_to_primval(arg_vals[1], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
@@ -94,7 +94,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             _ if intrinsic_name.starts_with("atomic_cxchg") => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let expect_old = self.value_to_primval(arg_vals[1], ty)?;
                 let change = self.value_to_primval(arg_vals[2], ty)?;
                 let old = self.read_value(ptr, ty)?;
@@ -115,7 +115,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | "atomic_xadd_acqrel" | "atomic_xadd_relaxed" |
             "atomic_xsub" | "atomic_xsub_acq" | "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let change = self.value_to_primval(arg_vals[1], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
@@ -148,8 +148,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     // TODO: We do not even validate alignment for the 0-bytes case.  libstd relies on this in vec::IntoIter::next.
                     // Also see the write_bytes intrinsic.
                     let elem_align = self.type_align(elem_ty)?;
-                    let src = arg_vals[0].into_ptr(&mut self.memory)?;
-                    let dest = arg_vals[1].into_ptr(&mut self.memory)?;
+                    let src = arg_vals[0].into_ptr(&self.memory)?;
+                    let dest = arg_vals[1].into_ptr(&self.memory)?;
                     self.memory.copy(src, dest, count * elem_size, elem_align, intrinsic_name.ends_with("_nonoverlapping"))?;
                 }
             }
@@ -176,7 +176,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "discriminant_value" => {
                 let ty = substs.type_at(0);
-                let adt_ptr = arg_vals[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let adt_ptr = arg_vals[0].into_ptr(&self.memory)?.to_ptr()?;
                 let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
                 self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
             }
@@ -297,7 +297,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "move_val_init" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 self.write_value_to_ptr(arg_vals[1], ptr, ty)?;
             }
 
@@ -310,7 +310,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "offset" => {
                 let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
                 self.write_ptr(dest, result_ptr, dest_ty)?;
             }
@@ -399,7 +399,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "transmute" => {
                 let src_ty = substs.type_at(0);
                 let ptr = self.force_allocation(dest)?.to_ptr()?;
-                self.write_maybe_aligned(/*aligned*/false, |ectx| {
+                self.write_maybe_aligned_mut(/*aligned*/false, |ectx| {
                     ectx.write_value_to_ptr(arg_vals[0], ptr.into(), src_ty)
                 })?;
             }
@@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 let ty_align = self.type_align(ty)?;
                 let val_byte = self.value_to_primval(arg_vals[1], u8)?.to_u128()? as u8;
                 let size = self.type_size(ty)?.expect("write_bytes() type must be sized");
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
                 if count > 0 {
                     // HashMap relies on write_bytes on a NULL ptr with count == 0 to work
@@ -550,7 +550,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     Ok((size, align.abi()))
                 }
                 ty::TyDynamic(..) => {
-                    let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?;
+                    let (_, vtable) = value.into_ptr_vtable_pair(&self.memory)?;
                     // the second entry in the vtable is the dynamic size of the object.
                     self.read_size_and_align_from_vtable(vtable)
                 }
@@ -558,7 +558,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 ty::TySlice(_) | ty::TyStr => {
                     let elem_ty = ty.sequence_element_type(self.tcx);
                     let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
-                    let (_, len) = value.into_slice(&mut self.memory)?;
+                    let (_, len) = value.into_slice(&self.memory)?;
                     let align = self.type_align(elem_ty)?;
                     Ok((len * elem_size, align as u64))
                 }
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index e5b6d371381..b9b72ca34ac 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -397,7 +397,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             },
             ty::InstanceDef::Virtual(_, idx) => {
                 let ptr_size = self.memory.pointer_size();
-                let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&mut self.memory)?;
+                let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&self.memory)?;
                 let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3), &self)?)?;
                 let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?;
                 let mut arg_operands = arg_operands.to_vec();
@@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         Ok(false)
     }
 
-    pub fn read_discriminant_value(&mut self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
+    pub fn read_discriminant_value(&self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
         use rustc::ty::layout::Layout::*;
         let adt_layout = self.type_layout(adt_ty)?;
         //trace!("read_discriminant_value {:#?}", adt_layout);
@@ -577,7 +577,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
             }
             "alloc::heap::::__rust_dealloc" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                 let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
                 let align = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if old_size == 0 {
@@ -589,7 +589,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?;
             }
             "alloc::heap::::__rust_realloc" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                 let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
                 let old_align = self.value_to_primval(args[2], usize)?.to_u64()?;
                 let new_size = self.value_to_primval(args[3], usize)?.to_u64()?;
@@ -665,7 +665,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "free" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?;
+                let ptr = args[0].into_ptr(&self.memory)?;
                 if !ptr.is_null()? {
                     self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?;
                 }
@@ -679,8 +679,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "dlsym" => {
-                let _handle = args[0].into_ptr(&mut self.memory)?;
-                let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
+                let _handle = args[0].into_ptr(&self.memory)?;
+                let symbol = args[1].into_ptr(&self.memory)?.to_ptr()?;
                 let symbol_name = self.memory.read_c_str(symbol)?;
                 let err = format!("bad c unicode symbol: {:?}", symbol_name);
                 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
@@ -691,8 +691,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
                 // We abort on panic, so not much is going on here, but we still have to call the closure
                 let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
-                let f = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
-                let data = args[1].into_ptr(&mut self.memory)?;
+                let f = args[0].into_ptr(&self.memory)?.to_ptr()?;
+                let data = args[1].into_ptr(&self.memory)?;
                 let f_instance = self.memory.get_fn(f)?;
                 self.write_null(dest, dest_ty)?;
 
@@ -723,8 +723,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "memcmp" => {
-                let left = args[0].into_ptr(&mut self.memory)?;
-                let right = args[1].into_ptr(&mut self.memory)?;
+                let left = args[0].into_ptr(&self.memory)?;
+                let right = args[1].into_ptr(&self.memory)?;
                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
 
                 let result = {
@@ -743,7 +743,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "memrchr" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?;
+                let ptr = args[0].into_ptr(&self.memory)?;
                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
@@ -755,7 +755,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "memchr" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?;
+                let ptr = args[0].into_ptr(&self.memory)?;
                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
@@ -768,7 +768,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "getenv" => {
                 let result = {
-                    let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                    let name_ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                     let name = self.memory.read_c_str(name_ptr)?;
                     match self.env_vars.get(name) {
                         Some(&var) => PrimVal::Ptr(var),
@@ -781,7 +781,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "unsetenv" => {
                 let mut success = None;
                 {
-                    let name_ptr = args[0].into_ptr(&mut self.memory)?;
+                    let name_ptr = args[0].into_ptr(&self.memory)?;
                     if !name_ptr.is_null()? {
                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
                         if !name.is_empty() && !name.contains(&b'=') {
@@ -802,8 +802,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "setenv" => {
                 let mut new = None;
                 {
-                    let name_ptr = args[0].into_ptr(&mut self.memory)?;
-                    let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
+                    let name_ptr = args[0].into_ptr(&self.memory)?;
+                    let value_ptr = args[1].into_ptr(&self.memory)?.to_ptr()?;
                     let value = self.memory.read_c_str(value_ptr)?;
                     if !name_ptr.is_null()? {
                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
@@ -829,7 +829,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "write" => {
                 let fd = self.value_to_primval(args[0], usize)?.to_u64()?;
-                let buf = args[1].into_ptr(&mut self.memory)?;
+                let buf = args[1].into_ptr(&self.memory)?;
                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
                 let result = if fd == 1 || fd == 2 { // stdout/stderr
@@ -846,7 +846,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "strlen" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                 let n = self.memory.read_c_str(ptr)?.len();
                 self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
             }
@@ -889,10 +889,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             // Hook pthread calls that go to the thread-local storage memory subsystem
             "pthread_key_create" => {
-                let key_ptr = args[0].into_ptr(&mut self.memory)?;
+                let key_ptr = args[0].into_ptr(&self.memory)?;
 
                 // Extract the function type out of the signature (that seems easier than constructing it ourselves...)
-                let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() {
+                let dtor = match args[1].into_ptr(&self.memory)?.into_inner_primval() {
                     PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
                     PrimVal::Bytes(0) => None,
                     PrimVal::Bytes(_) => return Err(EvalError::ReadBytesAsPointer),
@@ -934,7 +934,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "pthread_setspecific" => {
                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
                 let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
-                let new_ptr = args[1].into_ptr(&mut self.memory)?;
+                let new_ptr = args[1].into_ptr(&self.memory)?;
                 self.memory.store_tls(key, new_ptr)?;
                 
                 // Return success (0)
diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs
index 4c9e239299d..8c3cc185250 100644
--- a/src/librustc_mir/interpret/validation.rs
+++ b/src/librustc_mir/interpret/validation.rs
@@ -151,7 +151,7 @@ std::sync::atomic::AtomicBool::get_mut$|\
     fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, re: Option<CodeExtent>, mutbl: Mutability, mode: ValidationMode) -> EvalResult<'tcx> {
         // Check alignment and non-NULLness
         let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
-        let ptr = val.into_ptr(&mut self.memory)?;
+        let ptr = val.into_ptr(&self.memory)?;
         self.memory.check_align(ptr, align)?;
 
         // Recurse
@@ -309,7 +309,7 @@ std::sync::atomic::AtomicBool::get_mut$|\
                 self.validate_ptr(val, query.ty.boxed_ty(), query.re, query.mutbl, mode)
             }
             TyFnPtr(_sig) => {
-                let ptr = self.read_lvalue(query.lval)?.into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = self.read_lvalue(query.lval)?.into_ptr(&self.memory)?.to_ptr()?;
                 self.memory.get_fn(ptr)?;
                 // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                 Ok(())
diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs
index a4115ddb5cc..302ea0abec3 100644
--- a/src/librustc_mir/interpret/value.rs
+++ b/src/librustc_mir/interpret/value.rs
@@ -167,7 +167,7 @@ impl<'a, 'tcx: 'a> Value {
 
     /// Convert the value into a pointer (or a pointer-sized integer).  If the value is a ByRef,
     /// this may have to perform a load.
-    pub(super) fn into_ptr(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
+    pub(super) fn into_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
         use self::Value::*;
         match *self {
             ByRef(ptr, aligned) => {
@@ -179,7 +179,7 @@ impl<'a, 'tcx: 'a> Value {
 
     pub(super) fn into_ptr_vtable_pair(
         &self,
-        mem: &mut Memory<'a, 'tcx>
+        mem: &Memory<'a, 'tcx>
     ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
         use self::Value::*;
         match *self {
@@ -197,11 +197,11 @@ impl<'a, 'tcx: 'a> Value {
         }
     }
 
-    pub(super) fn into_slice(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
+    pub(super) fn into_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
         use self::Value::*;
         match *self {
             ByRef(ref_ptr, aligned) => {
-                mem.write_maybe_aligned(aligned, |mem| {
+                mem.read_maybe_aligned(aligned, |mem| {
                     let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
                     let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
                     Ok((ptr, len))