diff options
| author | Ralf Jung <post@ralfj.de> | 2018-08-23 19:04:33 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2018-08-27 18:12:49 +0200 |
| commit | c141ccf158d8c660ef20a51104b701b4eb37822b (patch) | |
| tree | 1e27be9f8ec89be350ca2423a7c3e8a5762e1400 /src/librustc/mir | |
| parent | b638d8c75f4e38c75c5caa52b10b18a350431687 (diff) | |
| download | rust-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/mir')
| -rw-r--r-- | src/librustc/mir/interpret/mod.rs | 16 | ||||
| -rw-r--r-- | src/librustc/mir/interpret/value.rs | 84 |
2 files changed, 90 insertions, 10 deletions
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) + } } |
