Skip to content

Commit c141ccf

Browse files
committed
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.
1 parent b638d8c commit c141ccf

File tree

20 files changed

+656
-524
lines changed

20 files changed

+656
-524
lines changed

src/librustc/ich/impls_ty.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,8 @@ for ::mir::interpret::ConstValue<'gcx> {
384384
a.hash_stable(hcx, hasher);
385385
b.hash_stable(hcx, hasher);
386386
}
387-
ByRef(alloc, offset) => {
387+
ByRef(id, alloc, offset) => {
388+
id.hash_stable(hcx, hasher);
388389
alloc.hash_stable(hcx, hasher);
389390
offset.hash_stable(hcx, hasher);
390391
}
@@ -446,7 +447,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::Allocation {
446447
}
447448
self.undef_mask.hash_stable(hcx, hasher);
448449
self.align.hash_stable(hcx, hasher);
449-
self.runtime_mutability.hash_stable(hcx, hasher);
450+
self.mutability.hash_stable(hcx, hasher);
450451
}
451452
}
452453

src/librustc/mir/interpret/mod.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,8 @@ impl fmt::Display for AllocId {
393393
pub enum AllocType<'tcx, M> {
394394
/// The alloc id is used as a function pointer
395395
Function(Instance<'tcx>),
396-
/// The alloc id points to a static variable
396+
/// The alloc id points to a "lazy" static variable that did not get computed (yet).
397+
/// This is also used to break the cycle in recursive statics.
397398
Static(DefId),
398399
/// The alloc id points to memory
399400
Memory(M)
@@ -496,13 +497,14 @@ pub struct Allocation {
496497
pub undef_mask: UndefMask,
497498
/// The alignment of the allocation to detect unaligned reads.
498499
pub align: Align,
499-
/// Whether the allocation (of a static) should be put into mutable memory when codegenning
500-
///
501-
/// Only happens for `static mut` or `static` with interior mutability
502-
pub runtime_mutability: Mutability,
500+
/// Whether the allocation is mutable.
501+
/// Also used by codegen to determine if a static should be put into mutable memory,
502+
/// which happens for `static mut` and `static` with interior mutability.
503+
pub mutability: Mutability,
503504
}
504505

505506
impl Allocation {
507+
/// Creates a read-only allocation initialized by the given bytes
506508
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
507509
let mut undef_mask = UndefMask::new(Size::ZERO);
508510
undef_mask.grow(Size::from_bytes(slice.len() as u64), true);
@@ -511,7 +513,7 @@ impl Allocation {
511513
relocations: Relocations::new(),
512514
undef_mask,
513515
align,
514-
runtime_mutability: Mutability::Immutable,
516+
mutability: Mutability::Immutable,
515517
}
516518
}
517519

@@ -526,7 +528,7 @@ impl Allocation {
526528
relocations: Relocations::new(),
527529
undef_mask: UndefMask::new(size),
528530
align,
529-
runtime_mutability: Mutability::Immutable,
531+
mutability: Mutability::Mutable,
530532
}
531533
}
532534
}

src/librustc/mir/interpret/value.rs

+81-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ty::layout::{HasDataLayout, Size};
1414
use ty::subst::Substs;
1515
use hir::def_id::DefId;
1616

17-
use super::{EvalResult, Pointer, PointerArithmetic, Allocation};
17+
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend};
1818

1919
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
2020
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
@@ -32,8 +32,9 @@ pub enum ConstValue<'tcx> {
3232
///
3333
/// The second field may be undef in case of `Option<usize>::None`
3434
ScalarPair(Scalar, ScalarMaybeUndef),
35-
/// Used only for the remaining cases. An allocation + offset into the allocation
36-
ByRef(&'tcx Allocation, Size),
35+
/// Used only for the remaining cases. An allocation + offset into the allocation.
36+
/// Invariant: The AllocId matches the allocation.
37+
ByRef(AllocId, &'tcx Allocation, Size),
3738
}
3839

3940
impl<'tcx> ConstValue<'tcx> {
@@ -185,6 +186,49 @@ impl<'tcx> Scalar {
185186
_ => err!(InvalidBool),
186187
}
187188
}
189+
190+
fn to_u8(self) -> EvalResult<'static, u8> {
191+
let sz = Size::from_bits(8);
192+
let b = self.to_bits(sz)?;
193+
assert_eq!(b as u8 as u128, b);
194+
Ok(b as u8)
195+
}
196+
197+
fn to_u32(self) -> EvalResult<'static, u32> {
198+
let sz = Size::from_bits(32);
199+
let b = self.to_bits(sz)?;
200+
assert_eq!(b as u32 as u128, b);
201+
Ok(b as u32)
202+
}
203+
204+
fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
205+
let b = self.to_bits(cx.data_layout().pointer_size)?;
206+
assert_eq!(b as u64 as u128, b);
207+
Ok(b as u64)
208+
}
209+
210+
fn to_i8(self) -> EvalResult<'static, i8> {
211+
let sz = Size::from_bits(8);
212+
let b = self.to_bits(sz)?;
213+
let b = sign_extend(b, sz) as i128;
214+
assert_eq!(b as i8 as i128, b);
215+
Ok(b as i8)
216+
}
217+
218+
fn to_i32(self) -> EvalResult<'static, i32> {
219+
let sz = Size::from_bits(32);
220+
let b = self.to_bits(sz)?;
221+
let b = sign_extend(b, sz) as i128;
222+
assert_eq!(b as i32 as i128, b);
223+
Ok(b as i32)
224+
}
225+
226+
fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
227+
let b = self.to_bits(cx.data_layout().pointer_size)?;
228+
let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
229+
assert_eq!(b as i64 as i128, b);
230+
Ok(b as i64)
231+
}
188232
}
189233

190234
impl From<Pointer> for Scalar {
@@ -228,22 +272,56 @@ impl From<Scalar> for ScalarMaybeUndef {
228272
}
229273

230274
impl<'tcx> ScalarMaybeUndef {
275+
#[inline]
231276
pub fn not_undef(self) -> EvalResult<'static, Scalar> {
232277
match self {
233278
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
234279
ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
235280
}
236281
}
237282

283+
#[inline(always)]
238284
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
239285
self.not_undef()?.to_ptr()
240286
}
241287

288+
#[inline(always)]
242289
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
243290
self.not_undef()?.to_bits(target_size)
244291
}
245292

293+
#[inline(always)]
246294
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
247295
self.not_undef()?.to_bool()
248296
}
297+
298+
#[inline(always)]
299+
pub fn to_u8(self) -> EvalResult<'tcx, u8> {
300+
self.not_undef()?.to_u8()
301+
}
302+
303+
#[inline(always)]
304+
pub fn to_u32(self) -> EvalResult<'tcx, u32> {
305+
self.not_undef()?.to_u32()
306+
}
307+
308+
#[inline(always)]
309+
pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
310+
self.not_undef()?.to_usize(cx)
311+
}
312+
313+
#[inline(always)]
314+
pub fn to_i8(self) -> EvalResult<'tcx, i8> {
315+
self.not_undef()?.to_i8()
316+
}
317+
318+
#[inline(always)]
319+
pub fn to_i32(self) -> EvalResult<'tcx, i32> {
320+
self.not_undef()?.to_i32()
321+
}
322+
323+
#[inline(always)]
324+
pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
325+
self.not_undef()?.to_isize(cx)
326+
}
249327
}

src/librustc/ty/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1043,13 +1043,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
10431043
}
10441044

10451045
let interned = self.global_arenas.const_allocs.alloc(alloc);
1046-
if let Some(prev) = allocs.replace(interned) {
1046+
if let Some(prev) = allocs.replace(interned) { // insert into interner
10471047
bug!("Tried to overwrite interned Allocation: {:#?}", prev)
10481048
}
10491049
interned
10501050
}
10511051

1052-
/// Allocates a byte or string literal for `mir::interpret`
1052+
/// Allocates a byte or string literal for `mir::interpret`, read-only
10531053
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
10541054
// create an allocation that just contains these bytes
10551055
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);

src/librustc/ty/structural_impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1139,7 +1139,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
11391139
match *self {
11401140
ConstValue::Scalar(v) => ConstValue::Scalar(v),
11411141
ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
1142-
ConstValue::ByRef(alloc, offset) => ConstValue::ByRef(alloc, offset),
1142+
ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset),
11431143
ConstValue::Unevaluated(def_id, substs) => {
11441144
ConstValue::Unevaluated(def_id, substs.fold_with(folder))
11451145
}
@@ -1150,7 +1150,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
11501150
match *self {
11511151
ConstValue::Scalar(_) |
11521152
ConstValue::ScalarPair(_, _) |
1153-
ConstValue::ByRef(_, _) => false,
1153+
ConstValue::ByRef(_, _, _) => false,
11541154
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
11551155
}
11561156
}

src/librustc_codegen_llvm/mir/constant.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub fn scalar_to_llvm(
5757
let base_addr = match alloc_type {
5858
Some(AllocType::Memory(alloc)) => {
5959
let init = const_alloc_to_llvm(cx, alloc);
60-
if alloc.runtime_mutability == Mutability::Mutable {
60+
if alloc.mutability == Mutability::Mutable {
6161
consts::addr_of_mut(cx, init, alloc.align, None)
6262
} else {
6363
consts::addr_of(cx, init, alloc.align, None)
@@ -134,7 +134,7 @@ pub fn codegen_static_initializer(
134134
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
135135

136136
let alloc = match static_.val {
137-
ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc,
137+
ConstValue::ByRef(_, alloc, n) if n.bytes() == 0 => alloc,
138138
_ => bug!("static const eval returned {:#?}", static_),
139139
};
140140
Ok((const_alloc_to_llvm(cx, alloc), alloc))

src/librustc_codegen_llvm/mir/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl OperandRef<'ll, 'tcx> {
126126
};
127127
OperandValue::Pair(a_llval, b_llval)
128128
},
129-
ConstValue::ByRef(alloc, offset) => {
129+
ConstValue::ByRef(_, alloc, offset) => {
130130
return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
131131
},
132132
};

src/librustc_codegen_llvm/mir/place.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
458458
let layout = cx.layout_of(self.monomorphize(&ty));
459459
match bx.tcx().const_eval(param_env.and(cid)) {
460460
Ok(val) => match val.val {
461-
mir::interpret::ConstValue::ByRef(alloc, offset) => {
461+
mir::interpret::ConstValue::ByRef(_, alloc, offset) => {
462462
PlaceRef::from_const_alloc(bx, layout, alloc, offset)
463463
}
464464
_ => bug!("promoteds should have an allocation: {:?}", val),

0 commit comments

Comments
 (0)