about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-08-23 19:04:33 +0200
committerRalf Jung <post@ralfj.de>2018-08-27 18:12:49 +0200
commitc141ccf158d8c660ef20a51104b701b4eb37822b (patch)
tree1e27be9f8ec89be350ca2423a7c3e8a5762e1400 /src/librustc
parentb638d8c75f4e38c75c5caa52b10b18a350431687 (diff)
downloadrust-c141ccf158d8c660ef20a51104b701b4eb37822b.tar.gz
rust-c141ccf158d8c660ef20a51104b701b4eb37822b.zip
Miri Memory Work
* Unify the two maps in memory to store the allocation and its kind together.
* Share the handling of statics between CTFE and miri: The miri engine always
  uses "lazy" `AllocType::Static` when encountering a static.  Acessing that
  static invokes CTFE (no matter the machine).  The machine only has any
  influence when writing to a static, which CTFE outright rejects (but miri
  makes a copy-on-write).
* Add an `AllocId` to by-ref consts so miri can use them as operands without
  making copies.
* Move responsibilities around for the `eval_fn_call` machine hook: The hook
  just has to find the MIR (or entirely take care of everything); pushing the
  new stack frame is taken care of by the miri engine.
* Expose the intrinsics and lang items implemented by CTFE so miri does not
  have to reimplement them.
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/ich/impls_ty.rs5
-rw-r--r--src/librustc/mir/interpret/mod.rs16
-rw-r--r--src/librustc/mir/interpret/value.rs84
-rw-r--r--src/librustc/ty/context.rs4
-rw-r--r--src/librustc/ty/structural_impls.rs4
5 files changed, 97 insertions, 16 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f4c46b6ce09..6ee0eb273d6 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -384,7 +384,8 @@ for ::mir::interpret::ConstValue<'gcx> {
                 a.hash_stable(hcx, hasher);
                 b.hash_stable(hcx, hasher);
             }
-            ByRef(alloc, offset) => {
+            ByRef(id, alloc, offset) => {
+                id.hash_stable(hcx, hasher);
                 alloc.hash_stable(hcx, hasher);
                 offset.hash_stable(hcx, hasher);
             }
@@ -446,7 +447,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
         }
         self.undef_mask.hash_stable(hcx, hasher);
         self.align.hash_stable(hcx, hasher);
-        self.runtime_mutability.hash_stable(hcx, hasher);
+        self.mutability.hash_stable(hcx, hasher);
     }
 }
 
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 6458c211ab5..147f9ccad7c 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -393,7 +393,8 @@ impl fmt::Display for AllocId {
 pub enum AllocType<'tcx, M> {
     /// The alloc id is used as a function pointer
     Function(Instance<'tcx>),
-    /// The alloc id points to a static variable
+    /// The alloc id points to a "lazy" static variable that did not get computed (yet).
+    /// This is also used to break the cycle in recursive statics.
     Static(DefId),
     /// The alloc id points to memory
     Memory(M)
@@ -496,13 +497,14 @@ pub struct Allocation {
     pub undef_mask: UndefMask,
     /// The alignment of the allocation to detect unaligned reads.
     pub align: Align,
-    /// Whether the allocation (of a static) should be put into mutable memory when codegenning
-    ///
-    /// Only happens for `static mut` or `static` with interior mutability
-    pub runtime_mutability: Mutability,
+    /// Whether the allocation is mutable.
+    /// Also used by codegen to determine if a static should be put into mutable memory,
+    /// which happens for `static mut` and `static` with interior mutability.
+    pub mutability: Mutability,
 }
 
 impl Allocation {
+    /// Creates a read-only allocation initialized by the given bytes
     pub fn from_bytes(slice: &[u8], align: Align) -> Self {
         let mut undef_mask = UndefMask::new(Size::ZERO);
         undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
@@ -511,7 +513,7 @@ impl Allocation {
             relocations: Relocations::new(),
             undef_mask,
             align,
-            runtime_mutability: Mutability::Immutable,
+            mutability: Mutability::Immutable,
         }
     }
 
@@ -526,7 +528,7 @@ impl Allocation {
             relocations: Relocations::new(),
             undef_mask: UndefMask::new(size),
             align,
-            runtime_mutability: Mutability::Immutable,
+            mutability: Mutability::Mutable,
         }
     }
 }
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 6b34e3f47cc..958c50e69d2 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -14,7 +14,7 @@ use ty::layout::{HasDataLayout, Size};
 use ty::subst::Substs;
 use hir::def_id::DefId;
 
-use super::{EvalResult, Pointer, PointerArithmetic, Allocation};
+use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend};
 
 /// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
 /// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
@@ -32,8 +32,9 @@ pub enum ConstValue<'tcx> {
     ///
     /// The second field may be undef in case of `Option<usize>::None`
     ScalarPair(Scalar, ScalarMaybeUndef),
-    /// Used only for the remaining cases. An allocation + offset into the allocation
-    ByRef(&'tcx Allocation, Size),
+    /// Used only for the remaining cases. An allocation + offset into the allocation.
+    /// Invariant: The AllocId matches the allocation.
+    ByRef(AllocId, &'tcx Allocation, Size),
 }
 
 impl<'tcx> ConstValue<'tcx> {
@@ -185,6 +186,49 @@ impl<'tcx> Scalar {
             _ => err!(InvalidBool),
         }
     }
+
+    fn to_u8(self) -> EvalResult<'static, u8> {
+        let sz = Size::from_bits(8);
+        let b = self.to_bits(sz)?;
+        assert_eq!(b as u8 as u128, b);
+        Ok(b as u8)
+    }
+
+    fn to_u32(self) -> EvalResult<'static, u32> {
+        let sz = Size::from_bits(32);
+        let b = self.to_bits(sz)?;
+        assert_eq!(b as u32 as u128, b);
+        Ok(b as u32)
+    }
+
+    fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
+        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        assert_eq!(b as u64 as u128, b);
+        Ok(b as u64)
+    }
+
+    fn to_i8(self) -> EvalResult<'static, i8> {
+        let sz = Size::from_bits(8);
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
+        assert_eq!(b as i8 as i128, b);
+        Ok(b as i8)
+    }
+
+    fn to_i32(self) -> EvalResult<'static, i32> {
+        let sz = Size::from_bits(32);
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
+        assert_eq!(b as i32 as i128, b);
+        Ok(b as i32)
+    }
+
+    fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
+        let b = self.to_bits(cx.data_layout().pointer_size)?;
+        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
+        assert_eq!(b as i64 as i128, b);
+        Ok(b as i64)
+    }
 }
 
 impl From<Pointer> for Scalar {
@@ -228,6 +272,7 @@ impl From<Scalar> for ScalarMaybeUndef {
 }
 
 impl<'tcx> ScalarMaybeUndef {
+    #[inline]
     pub fn not_undef(self) -> EvalResult<'static, Scalar> {
         match self {
             ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
@@ -235,15 +280,48 @@ impl<'tcx> ScalarMaybeUndef {
         }
     }
 
+    #[inline(always)]
     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
         self.not_undef()?.to_ptr()
     }
 
+    #[inline(always)]
     pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
         self.not_undef()?.to_bits(target_size)
     }
 
+    #[inline(always)]
     pub fn to_bool(self) -> EvalResult<'tcx, bool> {
         self.not_undef()?.to_bool()
     }
+
+    #[inline(always)]
+    pub fn to_u8(self) -> EvalResult<'tcx, u8> {
+        self.not_undef()?.to_u8()
+    }
+
+    #[inline(always)]
+    pub fn to_u32(self) -> EvalResult<'tcx, u32> {
+        self.not_undef()?.to_u32()
+    }
+
+    #[inline(always)]
+    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
+        self.not_undef()?.to_usize(cx)
+    }
+
+    #[inline(always)]
+    pub fn to_i8(self) -> EvalResult<'tcx, i8> {
+        self.not_undef()?.to_i8()
+    }
+
+    #[inline(always)]
+    pub fn to_i32(self) -> EvalResult<'tcx, i32> {
+        self.not_undef()?.to_i32()
+    }
+
+    #[inline(always)]
+    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
+        self.not_undef()?.to_isize(cx)
+    }
 }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 424139e7527..b10e9f14158 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1043,13 +1043,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
 
         let interned = self.global_arenas.const_allocs.alloc(alloc);
-        if let Some(prev) = allocs.replace(interned) {
+        if let Some(prev) = allocs.replace(interned) { // insert into interner
             bug!("Tried to overwrite interned Allocation: {:#?}", prev)
         }
         interned
     }
 
-    /// Allocates a byte or string literal for `mir::interpret`
+    /// Allocates a byte or string literal for `mir::interpret`, read-only
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // create an allocation that just contains these bytes
         let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index e6c10358279..55a1eadb06f 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1139,7 +1139,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
         match *self {
             ConstValue::Scalar(v) => ConstValue::Scalar(v),
             ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
-            ConstValue::ByRef(alloc, offset) => ConstValue::ByRef(alloc, offset),
+            ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset),
             ConstValue::Unevaluated(def_id, substs) => {
                 ConstValue::Unevaluated(def_id, substs.fold_with(folder))
             }
@@ -1150,7 +1150,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
         match *self {
             ConstValue::Scalar(_) |
             ConstValue::ScalarPair(_, _) |
-            ConstValue::ByRef(_, _) => false,
+            ConstValue::ByRef(_, _, _) => false,
             ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
         }
     }