about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2017-07-22 11:28:14 -0700
committerRalf Jung <post@ralfj.de>2017-07-22 11:28:48 -0700
commit4d38f8dffbeca5c5f81c3c72d42d4287c0acb1fc (patch)
treec2230518eed930b1b3b017cafb1892b5d313bbd6 /src
parent40950b2cd18a7a62b14c80d92be60ebf2f6b62a3 (diff)
downloadrust-4d38f8dffbeca5c5f81c3c72d42d4287c0acb1fc.tar.gz
rust-4d38f8dffbeca5c5f81c3c72d42d4287c0acb1fc.zip
move pointer truncation to a common method in memory.rs
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/interpret/cast.rs4
-rw-r--r--src/librustc_mir/interpret/eval_context.rs5
-rw-r--r--src/librustc_mir/interpret/memory.rs107
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs3
-rw-r--r--src/librustc_mir/interpret/traits.rs7
-rw-r--r--src/librustc_mir/interpret/value.rs57
6 files changed, 113 insertions, 70 deletions
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index f33fe3ac889..aff358f815c 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -4,7 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
 use error::{EvalResult, EvalError};
 use eval_context::EvalContext;
 use value::PrimVal;
-use memory::MemoryPointer;
+use memory::{MemoryPointer, HasDataLayout};
 
 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     pub(super) fn cast_primval(
@@ -78,7 +78,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             TyChar => Err(EvalError::InvalidChar(v)),
 
             // No alignment check needed for raw pointers.  But we have to truncate to target ptr size.
-            TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1u128 << self.memory.layout.pointer_size.bits()))),
+            TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
 
             _ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
         }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 49de56fa5b9..3c38f318e4a 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -1226,8 +1226,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         let field_1_ty = self.get_field_ty(ty, 1)?;
         let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
         let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
-        self.memory.write_primval(ptr.offset(field_0, self.memory.layout)?.into(), a, field_0_size)?;
-        self.memory.write_primval(ptr.offset(field_1, self.memory.layout)?.into(), b, field_1_size)?;
+        let layout = self.memory.layout;
+        self.memory.write_primval(ptr.offset(field_0, layout)?.into(), a, field_0_size)?;
+        self.memory.write_primval(ptr.offset(field_1, layout)?.into(), b, field_1_size)?;
         Ok(())
     }
 
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 481744b11c4..00b29d26e97 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -7,7 +7,7 @@ use rustc::ty::layout::{self, TargetDataLayout};
 use syntax::ast::Mutability;
 
 use error::{EvalError, EvalResult};
-use value::{PrimVal, self, Pointer};
+use value::{PrimVal, Pointer};
 use eval_context::EvalContext;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -73,26 +73,26 @@ impl MemoryPointer {
         MemoryPointer { alloc_id, offset }
     }
 
-    pub fn wrapping_signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> Self {
-        MemoryPointer::new(self.alloc_id, value::wrapping_signed_offset(self.offset, i, layout))
+    pub(crate) fn wrapping_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, l: L) -> Self {
+        MemoryPointer::new(self.alloc_id, l.wrapping_signed_offset(self.offset, i))
     }
 
-    pub fn overflowing_signed_offset<'tcx>(self, i: i128, layout: &TargetDataLayout) -> (Self, bool) {
-        let (res, over) = value::overflowing_signed_offset(self.offset, i, layout);
+    pub(crate) fn overflowing_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i128, l: L) -> (Self, bool) {
+        let (res, over) = l.overflowing_signed_offset(self.offset, i);
         (MemoryPointer::new(self.alloc_id, res), over)
     }
 
-    pub fn signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
-        Ok(MemoryPointer::new(self.alloc_id, value::signed_offset(self.offset, i, layout)?))
+    pub(crate) fn signed_offset<'a, 'tcx, L: HasDataLayout<'a>>(self, i: i64, l: L) -> EvalResult<'tcx, Self> {
+        Ok(MemoryPointer::new(self.alloc_id, l.signed_offset(self.offset, i)?))
     }
 
-    pub fn overflowing_offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> (Self, bool) {
-        let (res, over) = value::overflowing_offset(self.offset, i, layout);
+    pub(crate) fn overflowing_offset<'a, L: HasDataLayout<'a>>(self, i: u64, l: L) -> (Self, bool) {
+        let (res, over) = l.overflowing_offset(self.offset, i);
         (MemoryPointer::new(self.alloc_id, res), over)
     }
 
-    pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
-        Ok(MemoryPointer::new(self.alloc_id, value::offset(self.offset, i, layout)?))
+    pub(crate) fn offset<'a, 'tcx, L: HasDataLayout<'a>>(self, i: u64, l: L) -> EvalResult<'tcx, Self> {
+        Ok(MemoryPointer::new(self.alloc_id, l.offset(self.offset, i)?))
     }
 }
 
@@ -540,7 +540,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
         if size == 0 {
             return Ok(&[]);
         }
-        self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
+        self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
         let alloc = self.get(ptr.alloc_id)?;
         assert_eq!(ptr.offset as usize as u64, ptr.offset);
         assert_eq!(size as usize as u64, size);
@@ -1131,6 +1131,7 @@ fn bit_index(bits: u64) -> (usize, usize) {
 
 pub(crate) trait HasMemory<'a, 'tcx> {
     fn memory_mut(&mut self) -> &mut Memory<'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>
@@ -1159,6 +1160,11 @@ impl<'a, 'tcx> HasMemory<'a, 'tcx> for Memory<'a, 'tcx> {
     fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
         self
     }
+
+    #[inline]
+    fn memory(&self) -> &Memory<'a, 'tcx> {
+        self
+    }
 }
 
 impl<'a, 'tcx> HasMemory<'a, 'tcx> for EvalContext<'a, 'tcx> {
@@ -1166,4 +1172,81 @@ impl<'a, 'tcx> HasMemory<'a, 'tcx> for EvalContext<'a, 'tcx> {
     fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx> {
         &mut self.memory
     }
+
+    #[inline]
+    fn memory(&self) -> &Memory<'a, 'tcx> {
+        &self.memory
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Pointer arithmetic
+////////////////////////////////////////////////////////////////////////////////
+
+pub(crate) trait HasDataLayout<'a> : Copy {
+    fn data_layout(self) -> &'a TargetDataLayout;
+
+    // These are not supposed to be overriden.
+
+    //// Trunace the given value to the pointer size; also return whether there was an overflow
+    fn truncate_to_ptr(self, val: u128) -> (u64, bool) {
+        let max_ptr_plus_1 = 1u128 << self.data_layout().pointer_size.bits();
+        ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
+    }
+
+    // Overflow checking only works properly on the range from -u64 to +u64.
+    fn overflowing_signed_offset(self, val: u64, i: i128) -> (u64, bool) {
+        // FIXME: is it possible to over/underflow here?
+        if i < 0 {
+            // trickery to ensure that i64::min_value() works fine
+            // this formula only works for true negative values, it panics for zero!
+            let n = u64::max_value() - (i as u64) + 1;
+            val.overflowing_sub(n)
+        } else {
+            self.overflowing_offset(val, i as u64)
+        }
+    }
+
+    fn overflowing_offset(self, val: u64, i: u64) -> (u64, bool) {
+        let (res, over1) = val.overflowing_add(i);
+        let (res, over2) = self.truncate_to_ptr(res as u128);
+        (res, over1 || over2)
+    }
+
+    fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
+        let (res, over) = self.overflowing_signed_offset(val, i as i128);
+        if over {
+            Err(EvalError::OverflowingMath)
+        } else {
+            Ok(res)
+        }
+    }
+
+    fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
+        let (res, over) = self.overflowing_offset(val, i);
+        if over {
+            Err(EvalError::OverflowingMath)
+        } else {
+            Ok(res)
+        }
+    }
+
+    fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 {
+        self.overflowing_signed_offset(val, i as i128).0
+    }
+}
+
+impl<'a> HasDataLayout<'a> for &'a TargetDataLayout {
+    #[inline]
+    fn data_layout(self) -> &'a TargetDataLayout {
+        self
+    }
+}
+
+impl<'a, 'b, 'tcx, T> HasDataLayout<'a> for &'b T
+    where T: HasMemory<'a, 'tcx> {
+    #[inline]
+    fn data_layout(self) -> &'a TargetDataLayout {
+        self.memory().layout
+    }
 }
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index 73511c38341..2db79b03d00 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -814,8 +814,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 if let Some((name, value)) = new {
                     // +1 for the null terminator
                     let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, Kind::Env)?;
+                    let layout = self.memory.layout;
                     self.memory.write_bytes(value_copy.into(), &value)?;
-                    self.memory.write_bytes(value_copy.offset(value.len() as u64, self.memory.layout)?.into(), &[0])?;
+                    self.memory.write_bytes(value_copy.offset(value.len() as u64, layout)?.into(), &[0])?;
                     if let Some(var) = self.env_vars.insert(name.to_owned(), value_copy) {
                         self.memory.deallocate(var, None, Kind::Env)?;
                     }
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 615ea214595..98059afb9e9 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -57,14 +57,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         let drop = self.memory.create_fn_alloc(drop);
         self.memory.write_ptr(vtable, drop)?;
 
-        self.memory.write_usize(vtable.offset(ptr_size, self.memory.layout)?, size)?;
-        self.memory.write_usize(vtable.offset(ptr_size * 2, self.memory.layout)?, align)?;
+        let layout = self.memory.layout;
+        self.memory.write_usize(vtable.offset(ptr_size, layout)?, size)?;
+        self.memory.write_usize(vtable.offset(ptr_size * 2, layout)?, align)?;
 
         for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() {
             if let Some((def_id, substs)) = method {
                 let instance = eval_context::resolve(self.tcx, def_id, substs);
                 let fn_ptr = self.memory.create_fn_alloc(instance);
-                self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64), self.memory.layout)?, fn_ptr)?;
+                self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64), layout)?, fn_ptr)?;
             }
         }
 
diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs
index 606a3516485..7420ae1256a 100644
--- a/src/librustc_mir/interpret/value.rs
+++ b/src/librustc_mir/interpret/value.rs
@@ -1,10 +1,8 @@
 #![allow(unknown_lints)]
 #![allow(float_cmp)]
 
-use rustc::ty::layout::TargetDataLayout;
-
 use error::{EvalError, EvalResult};
-use memory::{Memory, MemoryPointer, HasMemory};
+use memory::{Memory, MemoryPointer, HasMemory, HasDataLayout};
 
 pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
     f32::from_bits(bytes as u32)
@@ -61,33 +59,33 @@ impl<'tcx> Pointer {
         self.primval
     }
 
-    pub(crate) fn signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
+    pub(crate) fn signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, layout: L) -> EvalResult<'tcx, Self> {
         match self.primval {
             PrimVal::Bytes(b) => {
                 assert_eq!(b as u64 as u128, b);
-                Ok(Pointer::from(PrimVal::Bytes(signed_offset(b as u64, i, layout)? as u128)))
+                Ok(Pointer::from(PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128)))
             },
             PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from),
             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
         }
     }
 
-    pub(crate) fn offset(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
+    pub(crate) fn offset<'a, L: HasDataLayout<'a>>(self, i: u64, layout: L) -> EvalResult<'tcx, Self> {
         match self.primval {
             PrimVal::Bytes(b) => {
                 assert_eq!(b as u64 as u128, b);
-                Ok(Pointer::from(PrimVal::Bytes(offset(b as u64, i, layout)? as u128)))
+                Ok(Pointer::from(PrimVal::Bytes(layout.offset(b as u64, i)? as u128)))
             },
             PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
         }
     }
 
-    pub(crate) fn wrapping_signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
+    pub(crate) fn wrapping_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, layout: L) -> EvalResult<'tcx, Self> {
         match self.primval {
             PrimVal::Bytes(b) => {
                 assert_eq!(b as u64 as u128, b);
-                Ok(Pointer::from(PrimVal::Bytes(wrapping_signed_offset(b as u64, i, layout) as u128)))
+                Ok(Pointer::from(PrimVal::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128)))
             },
             PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))),
             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
@@ -323,47 +321,6 @@ impl<'tcx> PrimVal {
     }
 }
 
-// Overflow checking only works properly on the range from -u64 to +u64.
-pub fn overflowing_signed_offset<'tcx>(val: u64, i: i128, layout: &TargetDataLayout) -> (u64, bool) {
-    // FIXME: is it possible to over/underflow here?
-    if i < 0 {
-        // trickery to ensure that i64::min_value() works fine
-        // this formula only works for true negative values, it panics for zero!
-        let n = u64::max_value() - (i as u64) + 1;
-        val.overflowing_sub(n)
-    } else {
-        overflowing_offset(val, i as u64, layout)
-    }
-}
-
-pub fn overflowing_offset<'tcx>(val: u64, i: u64, layout: &TargetDataLayout) -> (u64, bool) {
-    let (res, over) = val.overflowing_add(i);
-    ((res as u128 % (1u128 << layout.pointer_size.bits())) as u64,
-     over || res as u128 >= (1u128 << layout.pointer_size.bits()))
-}
-
-pub fn signed_offset<'tcx>(val: u64, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, u64> {
-    let (res, over) = overflowing_signed_offset(val, i as i128, layout);
-    if over {
-        Err(EvalError::OverflowingMath)
-    } else {
-        Ok(res)
-    }
-}
-
-pub fn offset<'tcx>(val: u64, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, u64> {
-    let (res, over) = overflowing_offset(val, i, layout);
-    if over {
-        Err(EvalError::OverflowingMath)
-    } else {
-        Ok(res)
-    }
-}
-
-pub fn wrapping_signed_offset<'tcx>(val: u64, i: i64, layout: &TargetDataLayout) -> u64 {
-    overflowing_signed_offset(val, i as i128, layout).0
-}
-
 impl PrimValKind {
     pub fn is_int(self) -> bool {
         use self::PrimValKind::*;