1 use rustc::ty::{self, Ty};
2 use rustc::ty::layout::{Size, Align, LayoutOf};
3 use rustc::mir::interpret::{Scalar, Value, Pointer, EvalResult};
5 use syntax::ast::Mutability;
7 use super::{EvalContext, Machine, MemoryKind};
9 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
10 /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
13 /// The `trait_ref` encodes the erased self type. Hence if we are
14 /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
15 /// `trait_ref` would map `T:Trait`.
19 trait_ref: ty::PolyTraitRef<'tcx>,
20 ) -> EvalResult<'tcx, Pointer> {
21 debug!("get_vtable(trait_ref={:?})", trait_ref);
23 let layout = self.layout_of(trait_ref.self_ty())?;
24 assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
25 let size = layout.size.bytes();
26 let align = layout.align.abi();
28 let ptr_size = self.memory.pointer_size();
29 let ptr_align = self.tcx.data_layout.pointer_align;
30 let methods = self.tcx.vtable_methods(trait_ref);
31 let vtable = self.memory.allocate(
32 ptr_size * (3 + methods.len() as u64),
37 let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
38 let drop = self.memory.create_fn_alloc(drop);
39 self.memory.write_ptr_sized_unsigned(vtable, ptr_align, drop.into())?;
41 let size_ptr = vtable.offset(ptr_size, &self)?;
42 self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bits {
44 defined: ptr_size.bits() as u8,
46 let align_ptr = vtable.offset(ptr_size * 2, &self)?;
47 self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bits {
49 defined: ptr_size.bits() as u8,
52 for (i, method) in methods.iter().enumerate() {
53 if let Some((def_id, substs)) = *method {
54 let instance = self.resolve(def_id, substs)?;
55 let fn_ptr = self.memory.create_fn_alloc(instance);
56 let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?;
57 self.memory.write_ptr_sized_unsigned(method_ptr, ptr_align, fn_ptr.into())?;
61 self.memory.mark_static_initialized(
63 Mutability::Immutable,
69 pub fn read_drop_type_from_vtable(
72 ) -> EvalResult<'tcx, Option<ty::Instance<'tcx>>> {
73 // we don't care about the pointee type, we just want a pointer
74 let pointer_align = self.tcx.data_layout.pointer_align;
75 let pointer_size = self.tcx.data_layout.pointer_size.bits() as u8;
76 match self.read_ptr(vtable, pointer_align, self.tcx.mk_nil_ptr())? {
77 // some values don't need to call a drop impl, so the value is null
78 Value::Scalar(Scalar::Bits { bits: 0, defined} ) if defined == pointer_size => Ok(None),
79 Value::Scalar(Scalar::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some),
80 _ => err!(ReadBytesAsPointer),
84 pub fn read_size_and_align_from_vtable(
87 ) -> EvalResult<'tcx, (Size, Align)> {
88 let pointer_size = self.memory.pointer_size();
89 let pointer_align = self.tcx.data_layout.pointer_align;
90 let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bits(pointer_size)? as u64;
91 let align = self.memory.read_ptr_sized(
92 vtable.offset(pointer_size * 2, self)?,
94 )?.to_bits(pointer_size)? as u64;
95 Ok((Size::from_bytes(size), Align::from_bytes(align, align).unwrap()))