]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/place.rs
Switch wasm math symbols to their original names
[rust.git] / src / librustc_mir / interpret / place.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Computations on places -- field projections, going from mir::Place, and writing
12 //! into a place.
13 //! All high-level functions to write to memory work on places as destinations.
14
15 use std::convert::TryFrom;
16 use std::mem;
17
18 use rustc::ich::StableHashingContext;
19 use rustc::mir;
20 use rustc::ty::{self, Ty};
21 use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
22 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
23
24 use rustc::mir::interpret::{
25     GlobalId, AllocId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
26 };
27 use super::{EvalContext, Machine, Value, ValTy, Operand, OpTy, MemoryKind};
28
29 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
30 pub struct MemPlace<Id=AllocId> {
31     /// A place may have an integral pointer for ZSTs, and since it might
32     /// be turned back into a reference before ever being dereferenced.
33     /// However, it may never be undef.
34     pub ptr: Scalar<Id>,
35     pub align: Align,
36     /// Metadata for unsized places.  Interpretation is up to the type.
37     /// Must not be present for sized types, but can be missing for unsized types
38     /// (e.g. `extern type`).
39     pub extra: Option<Scalar<Id>>,
40 }
41
42 impl_stable_hash_for!(struct ::interpret::MemPlace {
43     ptr,
44     align,
45     extra,
46 });
47
48 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
49 pub enum Place<Id=AllocId> {
50     /// A place referring to a value allocated in the `Memory` system.
51     Ptr(MemPlace<Id>),
52
53     /// To support alloc-free locals, we are able to write directly to a local.
54     /// (Without that optimization, we'd just always be a `MemPlace`.)
55     Local {
56         frame: usize,
57         local: mir::Local,
58     },
59 }
60
61 // Can't use the macro here because that does not support named enum fields.
62 impl<'a> HashStable<StableHashingContext<'a>> for Place {
63     fn hash_stable<W: StableHasherResult>(
64         &self, hcx: &mut StableHashingContext<'a>,
65         hasher: &mut StableHasher<W>)
66     {
67         mem::discriminant(self).hash_stable(hcx, hasher);
68         match self {
69             Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
70
71             Place::Local { frame, local } => {
72                 frame.hash_stable(hcx, hasher);
73                 local.hash_stable(hcx, hasher);
74             },
75         }
76     }
77 }
78 #[derive(Copy, Clone, Debug)]
79 pub struct PlaceTy<'tcx> {
80     place: Place,
81     pub layout: TyLayout<'tcx>,
82 }
83
84 impl<'tcx> ::std::ops::Deref for PlaceTy<'tcx> {
85     type Target = Place;
86     #[inline(always)]
87     fn deref(&self) -> &Place {
88         &self.place
89     }
90 }
91
92 /// A MemPlace with its layout. Constructing it is only possible in this module.
93 #[derive(Copy, Clone, Debug)]
94 pub struct MPlaceTy<'tcx> {
95     mplace: MemPlace,
96     pub layout: TyLayout<'tcx>,
97 }
98
99 impl<'tcx> ::std::ops::Deref for MPlaceTy<'tcx> {
100     type Target = MemPlace;
101     #[inline(always)]
102     fn deref(&self) -> &MemPlace {
103         &self.mplace
104     }
105 }
106
107 impl<'tcx> From<MPlaceTy<'tcx>> for PlaceTy<'tcx> {
108     #[inline(always)]
109     fn from(mplace: MPlaceTy<'tcx>) -> Self {
110         PlaceTy {
111             place: Place::Ptr(mplace.mplace),
112             layout: mplace.layout
113         }
114     }
115 }
116
117 impl MemPlace {
118     #[inline(always)]
119     pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
120         MemPlace {
121             ptr,
122             align,
123             extra: None,
124         }
125     }
126
127     #[inline(always)]
128     pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
129         Self::from_scalar_ptr(ptr.into(), align)
130     }
131
132     #[inline(always)]
133     pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
134         assert_eq!(self.extra, None);
135         (self.ptr, self.align)
136     }
137
138     /// Extract the ptr part of the mplace
139     #[inline(always)]
140     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
141         // At this point, we forget about the alignment information --
142         // the place has been turned into a reference, and no matter where it came from,
143         // it now must be aligned.
144         self.to_scalar_ptr_align().0.to_ptr()
145     }
146
147     /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
148     /// This is the inverse of `ref_to_mplace`.
149     pub fn to_ref(self) -> Value {
150         // We ignore the alignment of the place here -- special handling for packed structs ends
151         // at the `&` operator.
152         match self.extra {
153             None => Value::Scalar(self.ptr.into()),
154             Some(extra) => Value::ScalarPair(self.ptr.into(), extra.into()),
155         }
156     }
157 }
158
159 impl<'tcx> MPlaceTy<'tcx> {
160     #[inline]
161     fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
162         MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
163     }
164
165     #[inline]
166     pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
167         if self.layout.is_unsized() {
168             // We need to consult `extra` metadata
169             match self.layout.ty.sty {
170                 ty::Slice(..) | ty::Str =>
171                     return self.extra.unwrap().to_usize(cx),
172                 _ => bug!("len not supported on unsized type {:?}", self.layout.ty),
173             }
174         } else {
175             // Go through the layout.  There are lots of types that support a length,
176             // e.g. SIMD types.
177             match self.layout.fields {
178                 layout::FieldPlacement::Array { count, .. } => Ok(count),
179                 _ => bug!("len not supported on sized type {:?}", self.layout.ty),
180             }
181         }
182     }
183
184     #[inline]
185     pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> {
186         match self.layout.ty.sty {
187             ty::Dynamic(..) => self.extra.unwrap().to_ptr(),
188             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
189         }
190     }
191 }
192
193 impl<'tcx> OpTy<'tcx> {
194     #[inline(always)]
195     pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx>, Value> {
196         match *self {
197             Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
198             Operand::Immediate(value) => Err(value),
199         }
200     }
201
202     #[inline(always)]
203     pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
204         self.try_as_mplace().unwrap()
205     }
206 }
207
208 impl<'tcx> Place {
209     /// Produces a Place that will error if attempted to be read from or written to
210     #[inline]
211     pub fn null(cx: impl HasDataLayout) -> Self {
212         Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1, 1).unwrap())
213     }
214
215     #[inline]
216     pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
217         Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
218     }
219
220     #[inline]
221     pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
222         Place::Ptr(MemPlace::from_ptr(ptr, align))
223     }
224
225     #[inline]
226     pub fn to_mem_place(self) -> MemPlace {
227         match self {
228             Place::Ptr(mplace) => mplace,
229             _ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
230
231         }
232     }
233
234     #[inline]
235     pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
236         self.to_mem_place().to_scalar_ptr_align()
237     }
238
239     #[inline]
240     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
241         self.to_mem_place().to_ptr()
242     }
243 }
244
245 impl<'tcx> PlaceTy<'tcx> {
246     /// Produces a Place that will error if attempted to be read from or written to
247     #[inline]
248     pub fn null(cx: impl HasDataLayout, layout: TyLayout<'tcx>) -> Self {
249         PlaceTy { place: Place::from_scalar_ptr(Scalar::ptr_null(cx), layout.align), layout }
250     }
251
252     #[inline]
253     pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
254         MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
255     }
256 }
257
258 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
259     /// Take a value, which represents a (thin or fat) reference, and make it a place.
260     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref`.
261     pub fn ref_to_mplace(
262         &self, val: ValTy<'tcx>
263     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
264         let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
265         let layout = self.layout_of(pointee_type)?;
266         let align = layout.align;
267         let mplace = match *val {
268             Value::Scalar(ptr) =>
269                 MemPlace { ptr: ptr.not_undef()?, align, extra: None },
270             Value::ScalarPair(ptr, extra) =>
271                 MemPlace { ptr: ptr.not_undef()?, align, extra: Some(extra.not_undef()?) },
272         };
273         Ok(MPlaceTy { mplace, layout })
274     }
275
276     /// Offset a pointer to project to a field. Unlike place_field, this is always
277     /// possible without allocating, so it can take &self. Also return the field's layout.
278     /// This supports both struct and array fields.
279     #[inline(always)]
280     pub fn mplace_field(
281         &self,
282         base: MPlaceTy<'tcx>,
283         field: u64,
284     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
285         // Not using the layout method because we want to compute on u64
286         let offset = match base.layout.fields {
287             layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
288                 offsets[usize::try_from(field).unwrap()],
289             layout::FieldPlacement::Array { stride, .. } => {
290                 let len = base.len(self)?;
291                 assert!(field < len, "Tried to access element {} of array/slice with length {}",
292                     field, len);
293                 stride * field
294             }
295             layout::FieldPlacement::Union(count) => {
296                 assert!(field < count as u64,
297                         "Tried to access field {} of union with {} fields", field, count);
298                 // Offset is always 0
299                 Size::from_bytes(0)
300             }
301         };
302         // the only way conversion can fail if is this is an array (otherwise we already panicked
303         // above). In that case, all fields are equal.
304         let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
305
306         // Offset may need adjustment for unsized fields
307         let (extra, offset) = if field_layout.is_unsized() {
308             // re-use parent metadata to determine dynamic field layout
309             let (_, align) = self.size_and_align_of(base.extra, field_layout)?;
310             (base.extra, offset.abi_align(align))
311
312         } else {
313             // base.extra could be present; we might be accessing a sized field of an unsized
314             // struct.
315             (None, offset)
316         };
317
318         let ptr = base.ptr.ptr_offset(offset, self)?;
319         let align = base.align.min(field_layout.align); // only use static information
320
321         Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
322     }
323
324     // Iterates over all fields of an array. Much more efficient than doing the
325     // same by repeatedly calling `mplace_array`.
326     pub fn mplace_array_fields(
327         &self,
328         base: MPlaceTy<'tcx>,
329     ) -> EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx>>> + 'a> {
330         let len = base.len(self)?; // also asserts that we have a type where this makes sense
331         let stride = match base.layout.fields {
332             layout::FieldPlacement::Array { stride, .. } => stride,
333             _ => bug!("mplace_array_fields: expected an array layout"),
334         };
335         let layout = base.layout.field(self, 0)?;
336         let dl = &self.tcx.data_layout;
337         Ok((0..len).map(move |i| {
338             let ptr = base.ptr.ptr_offset(i * stride, dl)?;
339             Ok(MPlaceTy {
340                 mplace: MemPlace { ptr, align: base.align, extra: None },
341                 layout
342             })
343         }))
344     }
345
346     pub fn mplace_subslice(
347         &self,
348         base: MPlaceTy<'tcx>,
349         from: u64,
350         to: u64,
351     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
352         let len = base.len(self)?; // also asserts that we have a type where this makes sense
353         assert!(from <= len - to);
354
355         // Not using layout method because that works with usize, and does not work with slices
356         // (that have count 0 in their layout).
357         let from_offset = match base.layout.fields {
358             layout::FieldPlacement::Array { stride, .. } =>
359                 stride * from,
360             _ => bug!("Unexpected layout of index access: {:#?}", base.layout),
361         };
362         let ptr = base.ptr.ptr_offset(from_offset, self)?;
363
364         // Compute extra and new layout
365         let inner_len = len - to - from;
366         let (extra, ty) = match base.layout.ty.sty {
367             // It is not nice to match on the type, but that seems to be the only way to
368             // implement this.
369             ty::Array(inner, _) =>
370                 (None, self.tcx.mk_array(inner, inner_len)),
371             ty::Slice(..) => {
372                 let len = Scalar::from_uint(inner_len, self.pointer_size());
373                 (Some(len), base.layout.ty)
374             }
375             _ =>
376                 bug!("cannot subslice non-array type: `{:?}`", base.layout.ty),
377         };
378         let layout = self.layout_of(ty)?;
379
380         Ok(MPlaceTy {
381             mplace: MemPlace { ptr, align: base.align, extra },
382             layout
383         })
384     }
385
386     pub fn mplace_downcast(
387         &self,
388         base: MPlaceTy<'tcx>,
389         variant: usize,
390     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
391         // Downcasts only change the layout
392         assert_eq!(base.extra, None);
393         Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
394     }
395
396     /// Project into an mplace
397     pub fn mplace_projection(
398         &self,
399         base: MPlaceTy<'tcx>,
400         proj_elem: &mir::PlaceElem<'tcx>,
401     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
402         use rustc::mir::ProjectionElem::*;
403         Ok(match *proj_elem {
404             Field(field, _) => self.mplace_field(base, field.index() as u64)?,
405             Downcast(_, variant) => self.mplace_downcast(base, variant)?,
406             Deref => self.deref_operand(base.into())?,
407
408             Index(local) => {
409                 let n = *self.frame().locals[local].access()?;
410                 let n_layout = self.layout_of(self.tcx.types.usize)?;
411                 let n = self.read_scalar(OpTy { op: n, layout: n_layout })?;
412                 let n = n.to_bits(self.tcx.data_layout.pointer_size)?;
413                 self.mplace_field(base, u64::try_from(n).unwrap())?
414             }
415
416             ConstantIndex {
417                 offset,
418                 min_length,
419                 from_end,
420             } => {
421                 let n = base.len(self)?;
422                 assert!(n >= min_length as u64);
423
424                 let index = if from_end {
425                     n - u64::from(offset)
426                 } else {
427                     u64::from(offset)
428                 };
429
430                 self.mplace_field(base, index)?
431             }
432
433             Subslice { from, to } =>
434                 self.mplace_subslice(base, u64::from(from), u64::from(to))?,
435         })
436     }
437
438     /// Get the place of a field inside the place, and also the field's type.
439     /// Just a convenience function, but used quite a bit.
440     pub fn place_field(
441         &mut self,
442         base: PlaceTy<'tcx>,
443         field: u64,
444     ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
445         // FIXME: We could try to be smarter and avoid allocation for fields that span the
446         // entire place.
447         let mplace = self.force_allocation(base)?;
448         Ok(self.mplace_field(mplace, field)?.into())
449     }
450
451     pub fn place_downcast(
452         &mut self,
453         base: PlaceTy<'tcx>,
454         variant: usize,
455     ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
456         // Downcast just changes the layout
457         Ok(match base.place {
458             Place::Ptr(mplace) =>
459                 self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into(),
460             Place::Local { .. } => {
461                 let layout = base.layout.for_variant(&self, variant);
462                 PlaceTy { layout, ..base }
463             }
464         })
465     }
466
467     /// Project into a place
468     pub fn place_projection(
469         &mut self,
470         base: PlaceTy<'tcx>,
471         proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
472     ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
473         use rustc::mir::ProjectionElem::*;
474         Ok(match *proj_elem {
475             Field(field, _) =>  self.place_field(base, field.index() as u64)?,
476             Downcast(_, variant) => self.place_downcast(base, variant)?,
477             Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
478             // For the other variants, we have to force an allocation.
479             // This matches `operand_projection`.
480             Subslice { .. } | ConstantIndex { .. } | Index(_) => {
481                 let mplace = self.force_allocation(base)?;
482                 self.mplace_projection(mplace, proj_elem)?.into()
483             }
484         })
485     }
486
487     /// Evaluate statics and promoteds to an `MPlace`.  Used to share some code between
488     /// `eval_place` and `eval_place_to_op`.
489     pub(super) fn eval_place_to_mplace(
490         &self,
491         mir_place: &mir::Place<'tcx>
492     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
493         use rustc::mir::Place::*;
494         Ok(match *mir_place {
495             Promoted(ref promoted) => {
496                 let instance = self.frame().instance;
497                 let op = self.global_to_op(GlobalId {
498                     instance,
499                     promoted: Some(promoted.0),
500                 })?;
501                 let mplace = op.to_mem_place(); // these are always in memory
502                 let ty = self.monomorphize(promoted.1, self.substs());
503                 MPlaceTy {
504                     mplace,
505                     layout: self.layout_of(ty)?,
506                 }
507             }
508
509             Static(ref static_) => {
510                 let ty = self.monomorphize(static_.ty, self.substs());
511                 let layout = self.layout_of(ty)?;
512                 let instance = ty::Instance::mono(*self.tcx, static_.def_id);
513                 let cid = GlobalId {
514                     instance,
515                     promoted: None
516                 };
517                 // Just create a lazy reference, so we can support recursive statics.
518                 // tcx takes are of assigning every static one and only one unique AllocId.
519                 // When the data here is ever actually used, memory will notice,
520                 // and it knows how to deal with alloc_id that are present in the
521                 // global table but not in its local memory: It calls back into tcx through
522                 // a query, triggering the CTFE machinery to actually turn this lazy reference
523                 // into a bunch of bytes.  IOW, statics are evaluated with CTFE even when
524                 // this EvalContext uses another Machine (e.g., in miri).  This is what we
525                 // want!  This way, computing statics works concistently between codegen
526                 // and miri: They use the same query to eventually obtain a `ty::Const`
527                 // and use that for further computation.
528                 let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
529                 MPlaceTy::from_aligned_ptr(alloc.into(), layout)
530             }
531
532             _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
533         })
534     }
535
536     /// Compute a place.  You should only use this if you intend to write into this
537     /// place; for reading, a more efficient alternative is `eval_place_for_read`.
538     pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
539         use rustc::mir::Place::*;
540         let place = match *mir_place {
541             Local(mir::RETURN_PLACE) => PlaceTy {
542                 place: self.frame().return_place,
543                 layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
544             },
545             Local(local) => PlaceTy {
546                 place: Place::Local {
547                     frame: self.cur_frame(),
548                     local,
549                 },
550                 layout: self.layout_of_local(self.cur_frame(), local)?,
551             },
552
553             Projection(ref proj) => {
554                 let place = self.eval_place(&proj.base)?;
555                 self.place_projection(place, &proj.elem)?
556             }
557
558             _ => self.eval_place_to_mplace(mir_place)?.into(),
559         };
560
561         self.dump_place(place.place);
562         Ok(place)
563     }
564
565     /// Write a scalar to a place
566     pub fn write_scalar(
567         &mut self,
568         val: impl Into<ScalarMaybeUndef>,
569         dest: PlaceTy<'tcx>,
570     ) -> EvalResult<'tcx> {
571         self.write_value(Value::Scalar(val.into()), dest)
572     }
573
574     /// Write a value to a place
575     pub fn write_value(
576         &mut self,
577         src_val: Value,
578         dest: PlaceTy<'tcx>,
579     ) -> EvalResult<'tcx> {
580         trace!("write_value: {:?} <- {:?}", *dest, src_val);
581         // See if we can avoid an allocation. This is the counterpart to `try_read_value`,
582         // but not factored as a separate function.
583         let mplace = match dest.place {
584             Place::Local { frame, local } => {
585                 match *self.stack[frame].locals[local].access_mut()? {
586                     Operand::Immediate(ref mut dest_val) => {
587                         // Yay, we can just change the local directly.
588                         *dest_val = src_val;
589                         return Ok(());
590                     },
591                     Operand::Indirect(mplace) => mplace, // already in memory
592                 }
593             },
594             Place::Ptr(mplace) => mplace, // already in memory
595         };
596
597         // This is already in memory, write there.
598         let dest = MPlaceTy { mplace, layout: dest.layout };
599         self.write_value_to_mplace(src_val, dest)
600     }
601
602     /// Write a value to memory
603     fn write_value_to_mplace(
604         &mut self,
605         value: Value,
606         dest: MPlaceTy<'tcx>,
607     ) -> EvalResult<'tcx> {
608         let (ptr, ptr_align) = dest.to_scalar_ptr_align();
609         // Note that it is really important that the type here is the right one, and matches the
610         // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
611         // to handle padding properly, which is only correct if we never look at this data with the
612         // wrong type.
613
614         // Nothing to do for ZSTs, other than checking alignment
615         if dest.layout.size.bytes() == 0 {
616             self.memory.check_align(ptr, ptr_align)?;
617             return Ok(());
618         }
619
620         let ptr = ptr.to_ptr()?;
621         match value {
622             Value::Scalar(scalar) => {
623                 self.memory.write_scalar(
624                     ptr, ptr_align.min(dest.layout.align), scalar, dest.layout.size
625                 )
626             }
627             Value::ScalarPair(a_val, b_val) => {
628                 let (a, b) = match dest.layout.abi {
629                     layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
630                     _ => bug!("write_value_to_mplace: invalid ScalarPair layout: {:#?}",
631                               dest.layout)
632                 };
633                 let (a_size, b_size) = (a.size(&self), b.size(&self));
634                 let (a_align, b_align) = (a.align(&self), b.align(&self));
635                 let b_offset = a_size.abi_align(b_align);
636                 let b_ptr = ptr.offset(b_offset, &self)?.into();
637
638                 self.memory.write_scalar(ptr, ptr_align.min(a_align), a_val, a_size)?;
639                 self.memory.write_scalar(b_ptr, ptr_align.min(b_align), b_val, b_size)
640             }
641         }
642     }
643
644     /// Copy the data from an operand to a place
645     pub fn copy_op(
646         &mut self,
647         src: OpTy<'tcx>,
648         dest: PlaceTy<'tcx>,
649     ) -> EvalResult<'tcx> {
650         assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
651             "Cannot copy unsized data");
652         assert_eq!(src.layout.size, dest.layout.size,
653             "Size mismatch when copying!\nsrc: {:#?}\ndest: {:#?}", src, dest);
654
655         // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
656         let (src_ptr, src_align) = match self.try_read_value(src)? {
657             Ok(src_val) =>
658                 // Yay, we got a value that we can write directly.  We write with the
659                 // *source layout*, because that was used to load, and if they do not match
660                 // this is a transmute we want to support.
661                 return self.write_value(src_val, PlaceTy { place: *dest, layout: src.layout }),
662             Err(mplace) => mplace.to_scalar_ptr_align(),
663         };
664         // Slow path, this does not fit into an immediate. Just memcpy.
665         trace!("copy_op: {:?} <- {:?}", *dest, *src);
666         let (dest_ptr, dest_align) = self.force_allocation(dest)?.to_scalar_ptr_align();
667         self.memory.copy(
668             src_ptr, src_align,
669             dest_ptr, dest_align,
670             src.layout.size, false
671         )
672     }
673
674     /// Make sure that a place is in memory, and return where it is.
675     /// This is essentially `force_to_memplace`.
676     pub fn force_allocation(
677         &mut self,
678         place: PlaceTy<'tcx>,
679     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
680         let mplace = match place.place {
681             Place::Local { frame, local } => {
682                 match *self.stack[frame].locals[local].access()? {
683                     Operand::Indirect(mplace) => mplace,
684                     Operand::Immediate(value) => {
685                         // We need to make an allocation.
686                         // FIXME: Consider not doing anything for a ZST, and just returning
687                         // a fake pointer?  Are we even called for ZST?
688
689                         // We need the layout of the local.  We can NOT use the layout we got,
690                         // that might e.g. be an inner field of a struct with `Scalar` layout,
691                         // that has different alignment than the outer field.
692                         let local_layout = self.layout_of_local(frame, local)?;
693                         let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
694                         self.write_value_to_mplace(value, ptr)?;
695                         let mplace = ptr.mplace;
696                         // Update the local
697                         *self.stack[frame].locals[local].access_mut()? =
698                             Operand::Indirect(mplace);
699                         mplace
700                     }
701                 }
702             }
703             Place::Ptr(mplace) => mplace
704         };
705         // Return with the original layout, so that the caller can go on
706         Ok(MPlaceTy { mplace, layout: place.layout })
707     }
708
709     pub fn allocate(
710         &mut self,
711         layout: TyLayout<'tcx>,
712         kind: MemoryKind<M::MemoryKinds>,
713     ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
714         assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
715         let ptr = self.memory.allocate(layout.size, layout.align, kind)?;
716         Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
717     }
718
719     pub fn write_discriminant_index(
720         &mut self,
721         variant_index: usize,
722         dest: PlaceTy<'tcx>,
723     ) -> EvalResult<'tcx> {
724         match dest.layout.variants {
725             layout::Variants::Single { index } => {
726                 assert_eq!(index, variant_index);
727             }
728             layout::Variants::Tagged { ref tag, .. } => {
729                 let adt_def = dest.layout.ty.ty_adt_def().unwrap();
730                 assert!(variant_index < adt_def.variants.len());
731                 let discr_val = adt_def
732                     .discriminant_for_variant(*self.tcx, variant_index)
733                     .val;
734
735                 // raw discriminants for enums are isize or bigger during
736                 // their computation, but the in-memory tag is the smallest possible
737                 // representation
738                 let size = tag.value.size(self.tcx.tcx);
739                 let shift = 128 - size.bits();
740                 let discr_val = (discr_val << shift) >> shift;
741
742                 let discr_dest = self.place_field(dest, 0)?;
743                 self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
744             }
745             layout::Variants::NicheFilling {
746                 dataful_variant,
747                 ref niche_variants,
748                 niche_start,
749                 ..
750             } => {
751                 assert!(variant_index < dest.layout.ty.ty_adt_def().unwrap().variants.len());
752                 if variant_index != dataful_variant {
753                     let niche_dest =
754                         self.place_field(dest, 0)?;
755                     let niche_value = ((variant_index - niche_variants.start()) as u128)
756                         .wrapping_add(niche_start);
757                     self.write_scalar(
758                         Scalar::from_uint(niche_value, niche_dest.layout.size),
759                         niche_dest
760                     )?;
761                 }
762             }
763         }
764
765         Ok(())
766     }
767
768     /// Every place can be read from, so we can turm them into an operand
769     #[inline(always)]
770     pub fn place_to_op(&self, place: PlaceTy<'tcx>) -> EvalResult<'tcx, OpTy<'tcx>> {
771         let op = match place.place {
772             Place::Ptr(mplace) => {
773                 Operand::Indirect(mplace)
774             }
775             Place::Local { frame, local } =>
776                 *self.stack[frame].locals[local].access()?
777         };
778         Ok(OpTy { op, layout: place.layout })
779     }
780
781     /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
782     /// Also return some more information so drop doesn't have to run the same code twice.
783     pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx>)
784     -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx>)> {
785         let vtable = mplace.vtable()?; // also sanity checks the type
786         let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
787         let layout = self.layout_of(ty)?;
788
789         // More sanity checks
790         if cfg!(debug_assertions) {
791             let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
792             assert_eq!(size, layout.size);
793             assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
794         }
795
796         let mplace = MPlaceTy {
797             mplace: MemPlace { extra: None, ..*mplace },
798             layout
799         };
800         Ok((instance, mplace))
801     }
802 }