place.rs 39.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

R
Ralf Jung 已提交
11 12 13 14 15
//! Computations on places -- field projections, going from mir::Place, and writing
//! into a place.
//! All high-level functions to write to memory work on places as destinations.

use std::convert::TryFrom;
16
use std::hash::Hash;
R
Ralf Jung 已提交
17

18
use rustc::hir;
19
use rustc::mir;
R
Ralf Jung 已提交
20
use rustc::ty::{self, Ty};
21
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
O
Oliver Schneider 已提交
22

23
use super::{
24
    GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
O
Fallout  
Oliver Scherer 已提交
25
    EvalContext, Machine, AllocMap, AllocationExtra,
26
    RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
R
Ralf Jung 已提交
27 28 29
};

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
30
pub struct MemPlace<Tag=(), Id=AllocId> {
R
Ralf Jung 已提交
31 32 33
    /// A place may have an integral pointer for ZSTs, and since it might
    /// be turned back into a reference before ever being dereferenced.
    /// However, it may never be undef.
34
    pub ptr: Scalar<Tag, Id>,
35
    pub align: Align,
36
    /// Metadata for unsized places.  Interpretation is up to the type.
R
Ralf Jung 已提交
37 38
    /// Must not be present for sized types, but can be missing for unsized types
    /// (e.g. `extern type`).
R
Ralf Jung 已提交
39
    pub meta: Option<Scalar<Tag, Id>>,
R
Ralf Jung 已提交
40
}
O
Oliver Schneider 已提交
41

42
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
43
pub enum Place<Tag=(), Id=AllocId> {
44
    /// A place referring to a value allocated in the `Memory` system.
45
    Ptr(MemPlace<Tag, Id>),
O
Oliver Schneider 已提交
46

R
Ralf Jung 已提交
47 48 49 50 51 52
    /// To support alloc-free locals, we are able to write directly to a local.
    /// (Without that optimization, we'd just always be a `MemPlace`.)
    Local {
        frame: usize,
        local: mir::Local,
    },
O
Oliver Schneider 已提交
53 54
}

R
Ralf Jung 已提交
55
#[derive(Copy, Clone, Debug)]
56 57
pub struct PlaceTy<'tcx, Tag=()> {
    place: Place<Tag>,
R
Ralf Jung 已提交
58 59 60
    pub layout: TyLayout<'tcx>,
}

61 62
impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
    type Target = Place<Tag>;
63
    #[inline(always)]
64
    fn deref(&self) -> &Place<Tag> {
R
Ralf Jung 已提交
65 66 67 68 69 70
        &self.place
    }
}

/// A MemPlace with its layout. Constructing it is only possible in this module.
#[derive(Copy, Clone, Debug)]
71 72
pub struct MPlaceTy<'tcx, Tag=()> {
    mplace: MemPlace<Tag>,
R
Ralf Jung 已提交
73 74 75
    pub layout: TyLayout<'tcx>,
}

76 77
impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
    type Target = MemPlace<Tag>;
78
    #[inline(always)]
79
    fn deref(&self) -> &MemPlace<Tag> {
R
Ralf Jung 已提交
80
        &self.mplace
O
Oliver Schneider 已提交
81
    }
R
Ralf Jung 已提交
82 83
}

84
impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
85
    #[inline(always)]
86
    fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
R
Ralf Jung 已提交
87 88 89 90 91 92
        PlaceTy {
            place: Place::Ptr(mplace.mplace),
            layout: mplace.layout
        }
    }
}
O
Oliver Schneider 已提交
93

R
Ralf Jung 已提交
94
impl MemPlace {
95 96 97 98 99 100 101
    #[inline]
    pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
        where Tag: Default
    {
        MemPlace {
            ptr: self.ptr.with_default_tag(),
            align: self.align,
R
Ralf Jung 已提交
102
            meta: self.meta.map(Scalar::with_default_tag),
103 104 105 106 107 108 109 110 111 112 113
        }
    }
}

impl<Tag> MemPlace<Tag> {
    #[inline]
    pub fn erase_tag(self) -> MemPlace
    {
        MemPlace {
            ptr: self.ptr.erase_tag(),
            align: self.align,
R
Ralf Jung 已提交
114
            meta: self.meta.map(Scalar::erase_tag),
115 116 117
        }
    }

R
Ralf Jung 已提交
118
    #[inline(always)]
119
    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
120
        MemPlace {
121 122
            ptr,
            align,
R
Ralf Jung 已提交
123
            meta: None,
O
Oliver Schneider 已提交
124 125 126
        }
    }

127 128
    /// Produces a Place that will error if attempted to be read from or written to
    #[inline(always)]
129
    pub fn null(cx: &impl HasDataLayout) -> Self {
130
        Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap())
131 132
    }

R
Ralf Jung 已提交
133
    #[inline(always)]
134
    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
135 136 137 138
        Self::from_scalar_ptr(ptr.into(), align)
    }

    #[inline(always)]
139
    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
R
Ralf Jung 已提交
140
        assert!(self.meta.is_none());
R
Ralf Jung 已提交
141 142 143
        (self.ptr, self.align)
    }

R
Ralf Jung 已提交
144
    /// metact the ptr part of the mplace
R
Ralf Jung 已提交
145
    #[inline(always)]
146
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
B
Bernardo Meurer 已提交
147 148 149
        // At this point, we forget about the alignment information --
        // the place has been turned into a reference, and no matter where it came from,
        // it now must be aligned.
R
Ralf Jung 已提交
150 151
        self.to_scalar_ptr_align().0.to_ptr()
    }
152 153 154 155 156 157 158 159 160 161

    /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
    /// This is the inverse of `ref_to_mplace`.
    #[inline(always)]
    pub fn to_ref(self) -> Immediate<Tag> {
        match self.meta {
            None => Immediate::Scalar(self.ptr.into()),
            Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()),
        }
    }
162 163 164 165 166 167 168 169 170 171 172 173 174

    pub fn offset(
        self,
        offset: Size,
        meta: Option<Scalar<Tag>>,
        cx: &impl HasDataLayout,
    ) -> EvalResult<'tcx, Self> {
        Ok(MemPlace {
            ptr: self.ptr.ptr_offset(offset, cx)?,
            align: self.align.restrict_for_offset(offset),
            meta,
        })
    }
R
Ralf Jung 已提交
175 176
}

177
impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
178 179
    /// Produces a MemPlace that works for ZST but nothing else
    #[inline]
180
    pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
R
Ralf Jung 已提交
181 182
        MPlaceTy {
            mplace: MemPlace::from_scalar_ptr(
183
                Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()),
184
                layout.align.abi
R
Ralf Jung 已提交
185 186 187 188 189
            ),
            layout
        }
    }

190 191 192 193 194 195 196 197 198 199 200 201 202
    pub fn offset(
        self,
        offset: Size,
        meta: Option<Scalar<Tag>>,
        layout: TyLayout<'tcx>,
        cx: &impl HasDataLayout,
    ) -> EvalResult<'tcx, Self> {
        Ok(MPlaceTy {
            mplace: self.mplace.offset(offset, meta, cx)?,
            layout,
        })
    }

R
Ralf Jung 已提交
203
    #[inline]
204
    fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
205
        MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
R
Ralf Jung 已提交
206 207 208
    }

    #[inline]
209
    pub(super) fn len(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
210
        if self.layout.is_unsized() {
R
Ralf Jung 已提交
211
            // We need to consult `meta` metadata
212 213
            match self.layout.ty.sty {
                ty::Slice(..) | ty::Str =>
R
Ralf Jung 已提交
214
                    return self.mplace.meta.unwrap().to_usize(cx),
215
                _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
216
            }
217 218 219 220 221 222
        } else {
            // Go through the layout.  There are lots of types that support a length,
            // e.g. SIMD types.
            match self.layout.fields {
                layout::FieldPlacement::Array { count, .. } => Ok(count),
                _ => bug!("len not supported on sized type {:?}", self.layout.ty),
223 224 225 226 227
            }
        }
    }

    #[inline]
228
    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
229
        match self.layout.ty.sty {
R
Ralf Jung 已提交
230
            ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
231
            _ => bug!("vtable not supported on type {:?}", self.layout.ty),
R
Ralf Jung 已提交
232 233 234 235
        }
    }
}

236
impl<'tcx, Tag: ::std::fmt::Debug> OpTy<'tcx, Tag> {
237
    #[inline(always)]
238
    pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Immediate<Tag>> {
239
        match self.op {
R
Ralf Jung 已提交
240
            Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
241
            Operand::Immediate(imm) => Err(imm),
R
Ralf Jung 已提交
242 243 244
        }
    }

245
    #[inline(always)]
246
    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
247 248 249 250
        self.try_as_mplace().unwrap()
    }
}

251
impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
R
Ralf Jung 已提交
252
    /// Produces a Place that will error if attempted to be read from or written to
253
    #[inline(always)]
254
    pub fn null(cx: &impl HasDataLayout) -> Self {
255
        Place::Ptr(MemPlace::null(cx))
R
Ralf Jung 已提交
256 257
    }

258
    #[inline(always)]
259
    pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
260 261 262
        Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
    }

263
    #[inline(always)]
264
    pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
R
Ralf Jung 已提交
265
        Place::Ptr(MemPlace::from_ptr(ptr, align))
O
Oliver Schneider 已提交
266 267
    }

R
Ralf Jung 已提交
268
    #[inline]
269
    pub fn to_mem_place(self) -> MemPlace<Tag> {
O
Oliver Schneider 已提交
270
        match self {
R
Ralf Jung 已提交
271 272
            Place::Ptr(mplace) => mplace,
            _ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
O
Oliver Schneider 已提交
273 274 275 276

        }
    }

R
Ralf Jung 已提交
277
    #[inline]
278
    pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
R
Ralf Jung 已提交
279
        self.to_mem_place().to_scalar_ptr_align()
280
    }
281

R
Ralf Jung 已提交
282
    #[inline]
283
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
R
Ralf Jung 已提交
284 285 286
        self.to_mem_place().to_ptr()
    }
}
O
Oliver Schneider 已提交
287

288
impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
289
    #[inline]
290
    pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
R
Ralf Jung 已提交
291
        MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
O
Oliver Schneider 已提交
292 293 294
    }
}

295
// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
296 297 298 299
impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
where
    Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
    M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
300
    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
O
Fallout  
Oliver Scherer 已提交
301
    M::AllocExtra: AllocationExtra<Tag>,
302
{
R
Ralf Jung 已提交
303
    /// Take a value, which represents a (thin or fat) reference, and make it a place.
304
    /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
305 306
    /// This does NOT call the "deref" machine hook, so it does NOT count as a
    /// deref as far as Stacked Borrows is concerned.  Use `deref_operand` for that!
R
Ralf Jung 已提交
307
    pub fn ref_to_mplace(
308
        &self,
309
        val: ImmTy<'tcx, M::PointerTag>,
310
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
311 312 313
        let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
        let layout = self.layout_of(pointee_type)?;

314 315
        let mplace = MemPlace {
            ptr: val.to_scalar_ptr()?,
316
            align: layout.align.abi,
317 318 319
            meta: val.to_meta()?,
        };
        Ok(MPlaceTy { mplace, layout })
R
Ralf Jung 已提交
320 321
    }

322 323 324 325 326 327 328 329 330 331 332
    // Take an operand, representing a pointer, and dereference it to a place -- that
    // will always be a MemPlace.  Lives in `place.rs` because it creates a place.
    // This calls the "deref" machine hook, and counts as a deref as far as
    // Stacked Borrows is concerned.
    pub fn deref_operand(
        &self,
        src: OpTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        let val = self.read_immediate(src)?;
        trace!("deref to {} on {:?}", val.layout.ty, *val);
        let mut place = self.ref_to_mplace(val)?;
333
        // Pointer tag tracking might want to adjust the tag.
334 335 336 337 338 339 340
        let mutbl = match val.layout.ty.sty {
            // `builtin_deref` considers boxes immutable, that's useless for our purposes
            ty::Ref(_, _, mutbl) => Some(mutbl),
            ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable),
            ty::RawPtr(_) => None,
            _ => bug!("Unexpected pointer type {}", val.layout.ty.sty),
        };
341 342
        place.mplace.ptr = M::tag_dereference(self, place, mutbl)?;
        Ok(place)
343 344
    }

R
Ralf Jung 已提交
345 346 347 348 349
    /// Offset a pointer to project to a field. Unlike place_field, this is always
    /// possible without allocating, so it can take &self. Also return the field's layout.
    /// This supports both struct and array fields.
    #[inline(always)]
    pub fn mplace_field(
O
Oliver Schneider 已提交
350
        &self,
351
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
352
        field: u64,
353
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
354 355 356 357 358
        // Not using the layout method because we want to compute on u64
        let offset = match base.layout.fields {
            layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
                offsets[usize::try_from(field).unwrap()],
            layout::FieldPlacement::Array { stride, .. } => {
359 360 361
                let len = base.len(self)?;
                assert!(field < len, "Tried to access element {} of array/slice with length {}",
                    field, len);
R
Ralf Jung 已提交
362 363
                stride * field
            }
364
            layout::FieldPlacement::Union(count) => {
B
Bernardo Meurer 已提交
365 366
                assert!(field < count as u64,
                        "Tried to access field {} of union with {} fields", field, count);
367 368 369
                // Offset is always 0
                Size::from_bytes(0)
            }
R
Ralf Jung 已提交
370 371 372
        };
        // the only way conversion can fail if is this is an array (otherwise we already panicked
        // above). In that case, all fields are equal.
R
Ralf Jung 已提交
373
        let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
R
Ralf Jung 已提交
374

375
        // Offset may need adjustment for unsized fields
R
Ralf Jung 已提交
376
        let (meta, offset) = if field_layout.is_unsized() {
377
            // re-use parent metadata to determine dynamic field layout
378 379 380 381 382 383 384
            let align = match self.size_and_align_of(base.meta, field_layout)? {
                Some((_, align)) => align,
                None if offset == Size::ZERO =>
                    // An extern type at offset 0, we fall back to its static alignment.
                    // FIXME: Once we have made decisions for how to handle size and alignment
                    // of `extern type`, this should be adapted.  It is just a temporary hack
                    // to get some code to work that probably ought to work.
385
                    field_layout.align.abi,
386 387 388
                None =>
                    bug!("Cannot compute offset for extern type field at non-0 offset"),
            };
389
            (base.meta, offset.align_to(align))
R
Ralf Jung 已提交
390
        } else {
R
Ralf Jung 已提交
391
            // base.meta could be present; we might be accessing a sized field of an unsized
392 393
            // struct.
            (None, offset)
R
Ralf Jung 已提交
394 395
        };

396 397 398
        // We do not look at `base.layout.align` nor `field_layout.align`, unlike
        // codegen -- mostly to see if we can get away with that
        base.offset(offset, meta, field_layout, self)
O
Oliver Schneider 已提交
399 400
    }

401 402 403 404
    // Iterates over all fields of an array. Much more efficient than doing the
    // same by repeatedly calling `mplace_array`.
    pub fn mplace_array_fields(
        &self,
405 406 407 408
        base: MPlaceTy<'tcx, Tag>,
    ) ->
        EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
    {
409
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
410 411 412 413 414 415
        let stride = match base.layout.fields {
            layout::FieldPlacement::Array { stride, .. } => stride,
            _ => bug!("mplace_array_fields: expected an array layout"),
        };
        let layout = base.layout.field(self, 0)?;
        let dl = &self.tcx.data_layout;
416
        Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
417 418
    }

R
Ralf Jung 已提交
419
    pub fn mplace_subslice(
O
Oliver Schneider 已提交
420
        &self,
421
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
422 423
        from: u64,
        to: u64,
424
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
425
        let len = base.len(self)?; // also asserts that we have a type where this makes sense
R
Ralf Jung 已提交
426 427 428 429 430 431 432 433
        assert!(from <= len - to);

        // Not using layout method because that works with usize, and does not work with slices
        // (that have count 0 in their layout).
        let from_offset = match base.layout.fields {
            layout::FieldPlacement::Array { stride, .. } =>
                stride * from,
            _ => bug!("Unexpected layout of index access: {:#?}", base.layout),
O
Oliver Schneider 已提交
434
        };
R
Ralf Jung 已提交
435

R
Ralf Jung 已提交
436
        // Compute meta and new layout
R
Ralf Jung 已提交
437
        let inner_len = len - to - from;
R
Ralf Jung 已提交
438
        let (meta, ty) = match base.layout.ty.sty {
R
Ralf Jung 已提交
439 440
            // It is not nice to match on the type, but that seems to be the only way to
            // implement this.
V
varkor 已提交
441
            ty::Array(inner, _) =>
442 443
                (None, self.tcx.mk_array(inner, inner_len)),
            ty::Slice(..) => {
444
                let len = Scalar::from_uint(inner_len, self.pointer_size());
445 446
                (Some(len), base.layout.ty)
            }
R
Ralf Jung 已提交
447 448 449 450
            _ =>
                bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
        };
        let layout = self.layout_of(ty)?;
451
        base.offset(from_offset, meta, layout, self)
R
Ralf Jung 已提交
452 453 454 455
    }

    pub fn mplace_downcast(
        &self,
456
        base: MPlaceTy<'tcx, M::PointerTag>,
457
        variant: VariantIdx,
458
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
459
        // Downcasts only change the layout
R
Ralf Jung 已提交
460
        assert!(base.meta.is_none());
R
Ralf Jung 已提交
461
        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
O
Oliver Schneider 已提交
462 463
    }

R
Ralf Jung 已提交
464 465
    /// Project into an mplace
    pub fn mplace_projection(
O
Oliver Schneider 已提交
466
        &self,
467
        base: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
468
        proj_elem: &mir::PlaceElem<'tcx>,
469
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
470
        use rustc::mir::ProjectionElem::*;
R
Ralf Jung 已提交
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
        Ok(match *proj_elem {
            Field(field, _) => self.mplace_field(base, field.index() as u64)?,
            Downcast(_, variant) => self.mplace_downcast(base, variant)?,
            Deref => self.deref_operand(base.into())?,

            Index(local) => {
                let n = *self.frame().locals[local].access()?;
                let n_layout = self.layout_of(self.tcx.types.usize)?;
                let n = self.read_scalar(OpTy { op: n, layout: n_layout })?;
                let n = n.to_bits(self.tcx.data_layout.pointer_size)?;
                self.mplace_field(base, u64::try_from(n).unwrap())?
            }

            ConstantIndex {
                offset,
                min_length,
                from_end,
            } => {
489
                let n = base.len(self)?;
R
Ralf Jung 已提交
490 491 492 493 494 495 496 497 498 499 500 501 502 503
                assert!(n >= min_length as u64);

                let index = if from_end {
                    n - u64::from(offset)
                } else {
                    u64::from(offset)
                };

                self.mplace_field(base, index)?
            }

            Subslice { from, to } =>
                self.mplace_subslice(base, u64::from(from), u64::from(to))?,
        })
O
Oliver Schneider 已提交
504 505
    }

R
Ralf Jung 已提交
506 507
    /// Get the place of a field inside the place, and also the field's type.
    /// Just a convenience function, but used quite a bit.
508 509
    /// This is the only projection that might have a side-effect: We cannot project
    /// into the field of a local `ScalarPair`, we have to first allocate it.
R
Ralf Jung 已提交
510
    pub fn place_field(
O
Oliver Schneider 已提交
511
        &mut self,
512
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
513
        field: u64,
514
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
515 516 517 518
        // FIXME: We could try to be smarter and avoid allocation for fields that span the
        // entire place.
        let mplace = self.force_allocation(base)?;
        Ok(self.mplace_field(mplace, field)?.into())
O
Oliver Schneider 已提交
519 520
    }

R
Ralf Jung 已提交
521
    pub fn place_downcast(
522
        &self,
523
        base: PlaceTy<'tcx, M::PointerTag>,
524
        variant: VariantIdx,
525
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
526 527 528 529 530
        // Downcast just changes the layout
        Ok(match base.place {
            Place::Ptr(mplace) =>
                self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into(),
            Place::Local { .. } => {
531
                let layout = base.layout.for_variant(self, variant);
R
Ralf Jung 已提交
532
                PlaceTy { layout, ..base }
O
Oliver Schneider 已提交
533
            }
R
Ralf Jung 已提交
534
        })
O
Oliver Schneider 已提交
535 536
    }

R
Ralf Jung 已提交
537 538 539
    /// Project into a place
    pub fn place_projection(
        &mut self,
540
        base: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
541
        proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
542
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
543 544 545 546 547 548 549 550 551 552 553 554 555 556
        use rustc::mir::ProjectionElem::*;
        Ok(match *proj_elem {
            Field(field, _) =>  self.place_field(base, field.index() as u64)?,
            Downcast(_, variant) => self.place_downcast(base, variant)?,
            Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
            // For the other variants, we have to force an allocation.
            // This matches `operand_projection`.
            Subslice { .. } | ConstantIndex { .. } | Index(_) => {
                let mplace = self.force_allocation(base)?;
                self.mplace_projection(mplace, proj_elem)?.into()
            }
        })
    }

557 558 559 560 561
    /// Evaluate statics and promoteds to an `MPlace`.  Used to share some code between
    /// `eval_place` and `eval_place_to_op`.
    pub(super) fn eval_place_to_mplace(
        &self,
        mir_place: &mir::Place<'tcx>
562
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
563
        use rustc::mir::Place::*;
564
        Ok(match *mir_place {
565 566
            Promoted(ref promoted) => {
                let instance = self.frame().instance;
R
Ralf Jung 已提交
567
                self.const_eval_raw(GlobalId {
568 569
                    instance,
                    promoted: Some(promoted.0),
R
Ralf Jung 已提交
570
                })?
571 572
            }

O
Oliver Schneider 已提交
573
            Static(ref static_) => {
R
Ralf Jung 已提交
574 575
                let ty = self.monomorphize(static_.ty, self.substs());
                let layout = self.layout_of(ty)?;
576 577 578 579 580
                let instance = ty::Instance::mono(*self.tcx, static_.def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None
                };
R
Ralf Jung 已提交
581
                // Just create a lazy reference, so we can support recursive statics.
R
Ralf Jung 已提交
582
                // tcx takes are of assigning every static one and only one unique AllocId.
R
Ralf Jung 已提交
583 584
                // When the data here is ever actually used, memory will notice,
                // and it knows how to deal with alloc_id that are present in the
R
Ralf Jung 已提交
585 586 587 588 589 590 591 592
                // global table but not in its local memory: It calls back into tcx through
                // a query, triggering the CTFE machinery to actually turn this lazy reference
                // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
                // this EvalContext uses another Machine (e.g., in miri).  This is what we
                // want!  This way, computing statics works concistently between codegen
                // and miri: They use the same query to eventually obtain a `ty::Const`
                // and use that for further computation.
                let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
593
                MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
O
Oliver Schneider 已提交
594 595
            }

596 597 598 599 600 601
            _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
        })
    }

    /// Compute a place.  You should only use this if you intend to write into this
    /// place; for reading, a more efficient alternative is `eval_place_for_read`.
R
Ralf Jung 已提交
602 603 604 605
    pub fn eval_place(
        &mut self,
        mir_place: &mir::Place<'tcx>
    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
606 607
        use rustc::mir::Place::*;
        let place = match *mir_place {
R
Ralf Jung 已提交
608 609 610 611 612 613
            Local(mir::RETURN_PLACE) => match self.frame().return_place {
                Some(return_place) =>
                    // We use our layout to verify our assumption; caller will validate
                    // their layout on return.
                    PlaceTy {
                        place: *return_place,
614
                        layout: self.layout_of_local(self.frame(), mir::RETURN_PLACE)?,
R
Ralf Jung 已提交
615 616
                    },
                None => return err!(InvalidNullPointerUsage),
617 618 619 620 621 622
            },
            Local(local) => PlaceTy {
                place: Place::Local {
                    frame: self.cur_frame(),
                    local,
                },
623
                layout: self.layout_of_local(self.frame(), local)?,
624 625
            },

O
Oliver Schneider 已提交
626 627
            Projection(ref proj) => {
                let place = self.eval_place(&proj.base)?;
R
Ralf Jung 已提交
628
                self.place_projection(place, &proj.elem)?
O
Oliver Schneider 已提交
629
            }
630 631

            _ => self.eval_place_to_mplace(mir_place)?.into(),
O
Oliver Schneider 已提交
632 633
        };

R
Ralf Jung 已提交
634
        self.dump_place(place.place);
O
Oliver Schneider 已提交
635 636 637
        Ok(place)
    }

R
Ralf Jung 已提交
638 639
    /// Write a scalar to a place
    pub fn write_scalar(
O
Oliver Schneider 已提交
640
        &mut self,
641 642
        val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
643
    ) -> EvalResult<'tcx> {
644
        self.write_immediate(Immediate::Scalar(val.into()), dest)
R
Ralf Jung 已提交
645
    }
O
Oliver Schneider 已提交
646

647
    /// Write an immediate to a place
648
    #[inline(always)]
649
    pub fn write_immediate(
R
Ralf Jung 已提交
650
        &mut self,
651
        src: Immediate<M::PointerTag>,
652
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
653
    ) -> EvalResult<'tcx> {
654
        self.write_immediate_no_validate(src, dest)?;
655

R
Ralf Jung 已提交
656
        if M::enforce_validity(self) {
657
            // Data got changed, better make sure it matches the type!
658
            self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
659 660
        }

661 662 663
        Ok(())
    }

664
    /// Write an immediate to a place.
665 666
    /// If you use this you are responsible for validating that things got copied at the
    /// right type.
667
    fn write_immediate_no_validate(
668
        &mut self,
669
        src: Immediate<M::PointerTag>,
670 671 672 673 674
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx> {
        if cfg!(debug_assertions) {
            // This is a very common path, avoid some checks in release mode
            assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
675 676
            match src {
                Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
677 678
                    assert_eq!(self.pointer_size(), dest.layout.size,
                        "Size mismatch when writing pointer"),
679
                Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) =>
680 681
                    assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
                        "Size mismatch when writing bits"),
682 683
                Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
                Immediate::ScalarPair(_, _) => {
684 685 686 687
                    // FIXME: Can we check anything here?
                }
            }
        }
688
        trace!("write_immediate: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
689

690
        // See if we can avoid an allocation. This is the counterpart to `try_read_immediate`,
R
Ralf Jung 已提交
691
        // but not factored as a separate function.
R
Ralf Jung 已提交
692
        let mplace = match dest.place {
O
Oliver Schneider 已提交
693
            Place::Local { frame, local } => {
R
Ralf Jung 已提交
694 695 696
                match *self.stack[frame].locals[local].access_mut()? {
                    Operand::Immediate(ref mut dest_val) => {
                        // Yay, we can just change the local directly.
697
                        *dest_val = src;
R
Ralf Jung 已提交
698
                        return Ok(());
699
                    },
R
Ralf Jung 已提交
700
                    Operand::Indirect(mplace) => mplace, // already in memory
O
Oliver Schneider 已提交
701
                }
R
Ralf Jung 已提交
702
            },
R
Ralf Jung 已提交
703
            Place::Ptr(mplace) => mplace, // already in memory
O
Oliver Schneider 已提交
704
        };
705
        let dest = MPlaceTy { mplace, layout: dest.layout };
O
Oliver Schneider 已提交
706

R
Ralf Jung 已提交
707
        // This is already in memory, write there.
708
        self.write_immediate_to_mplace_no_validate(src, dest)
O
Oliver Schneider 已提交
709 710
    }

711
    /// Write an immediate to memory.
712 713
    /// If you use this you are responsible for validating that things git copied at the
    /// right type.
714
    fn write_immediate_to_mplace_no_validate(
R
Ralf Jung 已提交
715
        &mut self,
716
        value: Immediate<M::PointerTag>,
717
        dest: MPlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
718
    ) -> EvalResult<'tcx> {
719
        let (ptr, ptr_align) = dest.to_scalar_ptr_align();
B
Bernardo Meurer 已提交
720 721 722 723
        // Note that it is really important that the type here is the right one, and matches the
        // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
        // to handle padding properly, which is only correct if we never look at this data with the
        // wrong type.
724 725

        // Nothing to do for ZSTs, other than checking alignment
726
        if dest.layout.is_zst() {
727
            return self.memory.check_align(ptr, ptr_align);
728 729
        }

730
        // check for integer pointers before alignment to report better errors
731
        let ptr = ptr.to_ptr()?;
732
        self.memory.check_align(ptr.into(), ptr_align)?;
733
        let tcx = &*self.tcx;
734 735 736
        // FIXME: We should check that there are dest.layout.size many bytes available in
        // memory.  The code below is not sufficient, with enough padding it might not
        // cover all the bytes!
R
Ralf Jung 已提交
737
        match value {
738
            Immediate::Scalar(scalar) => {
739 740
                match dest.layout.abi {
                    layout::Abi::Scalar(_) => {}, // fine
741
                    _ => bug!("write_immediate_to_mplace: invalid Scalar layout: {:#?}",
742 743
                            dest.layout)
                }
744
                self.memory.get_mut(ptr.alloc_id)?.write_scalar(
745
                    tcx, ptr, scalar, dest.layout.size
R
Ralf Jung 已提交
746
                )
O
Oliver Schneider 已提交
747
            }
748
            Immediate::ScalarPair(a_val, b_val) => {
R
Ralf Jung 已提交
749 750
                let (a, b) = match dest.layout.abi {
                    layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
751
                    _ => bug!("write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
B
Bernardo Meurer 已提交
752
                              dest.layout)
R
Ralf Jung 已提交
753
                };
754
                let (a_size, b_size) = (a.size(self), b.size(self));
755 756
                let b_offset = a_size.align_to(b.align(self).abi);
                let b_align = ptr_align.restrict_for_offset(b_offset);
757
                let b_ptr = ptr.offset(b_offset, self)?;
758

759
                self.memory.check_align(b_ptr.into(), b_align)?;
760

761 762 763 764
                // It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
                // but that does not work: We could be a newtype around a pair, then the
                // fields do not match the `ScalarPair` components.

765 766
                self.memory
                    .get_mut(ptr.alloc_id)?
767
                    .write_scalar(tcx, ptr, a_val, a_size)?;
768 769
                self.memory
                    .get_mut(b_ptr.alloc_id)?
770
                    .write_scalar(tcx, b_ptr, b_val, b_size)
O
Oliver Schneider 已提交
771
            }
R
Ralf Jung 已提交
772
        }
O
Oliver Schneider 已提交
773 774
    }

775 776 777
    /// Copy the data from an operand to a place.  This does not support transmuting!
    /// Use `copy_op_transmute` if the layouts could disagree.
    #[inline(always)]
R
Ralf Jung 已提交
778
    pub fn copy_op(
O
Oliver Schneider 已提交
779
        &mut self,
780 781
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
782
    ) -> EvalResult<'tcx> {
783 784
        self.copy_op_no_validate(src, dest)?;

R
Ralf Jung 已提交
785
        if M::enforce_validity(self) {
786
            // Data got changed, better make sure it matches the type!
787
            self.validate_operand(self.place_to_op(dest)?, vec![], None, /*const_mode*/false)?;
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
        }

        Ok(())
    }

    /// Copy the data from an operand to a place.  This does not support transmuting!
    /// Use `copy_op_transmute` if the layouts could disagree.
    /// Also, if you use this you are responsible for validating that things git copied at the
    /// right type.
    fn copy_op_no_validate(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx> {
        debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
803
            "Cannot copy unsized data");
804 805 806 807
        // We do NOT compare the types for equality, because well-typed code can
        // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
        assert!(src.layout.details == dest.layout.details,
            "Layout mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
R
Ralf Jung 已提交
808 809

        // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
810
        let src = match self.try_read_immediate(src)? {
811 812
            Ok(src_val) => {
                // Yay, we got a value that we can write directly.
813
                return self.write_immediate_no_validate(src_val, dest);
814 815
            }
            Err(mplace) => mplace,
R
Ralf Jung 已提交
816 817
        };
        // Slow path, this does not fit into an immediate. Just memcpy.
818 819
        trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);

820
        let dest = self.force_allocation(dest)?;
821
        let (src_ptr, src_align) = src.to_scalar_ptr_align();
822
        let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
R
Ralf Jung 已提交
823 824 825
        self.memory.copy(
            src_ptr, src_align,
            dest_ptr, dest_align,
826
            dest.layout.size, false
827
        )?;
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862

        Ok(())
    }

    /// Copy the data from an operand to a place.  The layouts may disagree, but they must
    /// have the same size.
    pub fn copy_op_transmute(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx> {
        if src.layout.details == dest.layout.details {
            // Fast path: Just use normal `copy_op`
            return self.copy_op(src, dest);
        }
        // We still require the sizes to match
        debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
            "Cannot copy unsized data");
        assert!(src.layout.size == dest.layout.size,
            "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);

        // The hard case is `ScalarPair`.  `src` is already read from memory in this case,
        // using `src.layout` to figure out which bytes to use for the 1st and 2nd field.
        // We have to write them to `dest` at the offsets they were *read at*, which is
        // not necessarily the same as the offsets in `dest.layout`!
        // Hence we do the copy with the source layout on both sides.  We also make sure to write
        // into memory, because if `dest` is a local we would not even have a way to write
        // at the `src` offsets; the fact that we came from a different layout would
        // just be lost.
        let dest = self.force_allocation(dest)?;
        self.copy_op_no_validate(
            src,
            PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
        )?;

R
Ralf Jung 已提交
863
        if M::enforce_validity(self) {
864
            // Data got changed, better make sure it matches the type!
865
            self.validate_operand(dest.into(), vec![], None, /*const_mode*/false)?;
866
        }
867

868
        Ok(())
O
Oliver Schneider 已提交
869 870
    }

R
Ralf Jung 已提交
871
    /// Make sure that a place is in memory, and return where it is.
872 873
    /// If the place currently refers to a local that doesn't yet have a matching allocation,
    /// create such an allocation.
R
Ralf Jung 已提交
874 875
    /// This is essentially `force_to_memplace`.
    pub fn force_allocation(
O
Oliver Schneider 已提交
876
        &mut self,
877 878
        place: PlaceTy<'tcx, M::PointerTag>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
879 880
        let mplace = match place.place {
            Place::Local { frame, local } => {
881 882 883 884 885 886 887 888
                match *self.stack[frame].locals[local].access()? {
                    Operand::Indirect(mplace) => mplace,
                    Operand::Immediate(value) => {
                        // We need to make an allocation.
                        // FIXME: Consider not doing anything for a ZST, and just returning
                        // a fake pointer?  Are we even called for ZST?

                        // We need the layout of the local.  We can NOT use the layout we got,
R
Ralf Jung 已提交
889 890
                        // that might e.g. be an inner field of a struct with `Scalar` layout,
                        // that has different alignment than the outer field.
891
                        let local_layout = self.layout_of_local(&self.stack[frame], local)?;
892
                        let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
893 894
                        // We don't have to validate as we can assume the local
                        // was already valid for its type.
895
                        self.write_immediate_to_mplace_no_validate(value, ptr)?;
896 897 898 899 900 901 902
                        let mplace = ptr.mplace;
                        // Update the local
                        *self.stack[frame].locals[local].access_mut()? =
                            Operand::Indirect(mplace);
                        mplace
                    }
                }
R
Ralf Jung 已提交
903 904 905 906 907
            }
            Place::Ptr(mplace) => mplace
        };
        // Return with the original layout, so that the caller can go on
        Ok(MPlaceTy { mplace, layout: place.layout })
O
Oliver Schneider 已提交
908 909
    }

R
Ralf Jung 已提交
910
    pub fn allocate(
O
Oliver Schneider 已提交
911
        &mut self,
R
Ralf Jung 已提交
912 913
        layout: TyLayout<'tcx>,
        kind: MemoryKind<M::MemoryKinds>,
914
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
O
Oliver Schneider 已提交
915 916
        if layout.is_unsized() {
            assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type");
917
            // FIXME: What should we do here? We should definitely also tag!
918
            Ok(MPlaceTy::dangling(layout, self))
O
Oliver Schneider 已提交
919
        } else {
920
            let ptr = self.memory.allocate(layout.size, layout.align.abi, kind)?;
921
            let ptr = M::tag_new_allocation(self, ptr, kind)?;
O
Oliver Schneider 已提交
922 923
            Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
        }
R
Ralf Jung 已提交
924
    }
O
Oliver Schneider 已提交
925

926
    pub fn write_discriminant_index(
R
Ralf Jung 已提交
927
        &mut self,
928
        variant_index: VariantIdx,
929
        dest: PlaceTy<'tcx, M::PointerTag>,
R
Ralf Jung 已提交
930 931 932
    ) -> EvalResult<'tcx> {
        match dest.layout.variants {
            layout::Variants::Single { index } => {
R
Ralf Jung 已提交
933
                assert_eq!(index, variant_index);
O
Oliver Schneider 已提交
934
            }
R
Ralf Jung 已提交
935
            layout::Variants::Tagged { ref tag, .. } => {
936
                let adt_def = dest.layout.ty.ty_adt_def().unwrap();
937
                assert!(variant_index.as_usize() < adt_def.variants.len());
938
                let discr_val = adt_def
R
Ralf Jung 已提交
939 940 941 942 943 944
                    .discriminant_for_variant(*self.tcx, variant_index)
                    .val;

                // raw discriminants for enums are isize or bigger during
                // their computation, but the in-memory tag is the smallest possible
                // representation
945
                let size = tag.value.size(self);
R
Ralf Jung 已提交
946 947 948 949
                let shift = 128 - size.bits();
                let discr_val = (discr_val << shift) >> shift;

                let discr_dest = self.place_field(dest, 0)?;
950
                self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
O
Oliver Schneider 已提交
951
            }
R
Ralf Jung 已提交
952 953 954 955 956
            layout::Variants::NicheFilling {
                dataful_variant,
                ref niche_variants,
                niche_start,
                ..
O
Oliver Schneider 已提交
957
            } => {
958 959 960
                assert!(
                    variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
                );
R
Ralf Jung 已提交
961 962 963
                if variant_index != dataful_variant {
                    let niche_dest =
                        self.place_field(dest, 0)?;
964 965
                    let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                    let niche_value = (niche_value as u128)
R
Ralf Jung 已提交
966
                        .wrapping_add(niche_start);
967 968 969 970
                    self.write_scalar(
                        Scalar::from_uint(niche_value, niche_dest.layout.size),
                        niche_dest
                    )?;
R
Ralf Jung 已提交
971
                }
O
Oliver Schneider 已提交
972
            }
973
        }
R
Ralf Jung 已提交
974 975

        Ok(())
O
Oliver Schneider 已提交
976 977
    }

R
Ralf Jung 已提交
978
    /// Every place can be read from, so we can turm them into an operand
979
    #[inline(always)]
R
Ralf Jung 已提交
980 981 982 983
    pub fn place_to_op(
        &self,
        place: PlaceTy<'tcx, M::PointerTag>
    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
R
Ralf Jung 已提交
984 985 986 987 988 989 990 991
        let op = match place.place {
            Place::Ptr(mplace) => {
                Operand::Indirect(mplace)
            }
            Place::Local { frame, local } =>
                *self.stack[frame].locals[local].access()?
        };
        Ok(OpTy { op, layout: place.layout })
O
Oliver Schneider 已提交
992
    }
993

994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
    pub fn raw_const_to_mplace(
        &self,
        raw: RawConst<'tcx>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        // This must be an allocation in `tcx`
        assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some());
        let layout = self.layout_of(raw.ty)?;
        Ok(MPlaceTy::from_aligned_ptr(
            Pointer::new(raw.alloc_id, Size::ZERO).with_default_tag(),
            layout,
        ))
    }

1007 1008
    /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
    /// Also return some more information so drop doesn't have to run the same code twice.
1009 1010
    pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
1011 1012 1013 1014 1015
        let vtable = mplace.vtable()?; // also sanity checks the type
        let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
        let layout = self.layout_of(ty)?;

        // More sanity checks
1016 1017 1018
        if cfg!(debug_assertions) {
            let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
            assert_eq!(size, layout.size);
1019
            // only ABI alignment is preserved
1020
            assert_eq!(align, layout.align.abi);
1021
        }
1022 1023

        let mplace = MPlaceTy {
R
Ralf Jung 已提交
1024
            mplace: MemPlace { meta: None, ..*mplace },
1025
            layout
1026 1027
        };
        Ok((instance, mplace))
1028
    }
O
Oliver Schneider 已提交
1029
}