diff options
| author | Charles Lew <crlf0710@gmail.com> | 2021-06-20 17:43:25 +0800 | 
|---|---|---|
| committer | Charles Lew <crlf0710@gmail.com> | 2021-06-28 19:39:48 +0800 | 
| commit | d3ff497bec60687e3e1bdde383bd0b9dc74b5870 (patch) | |
| tree | f12696156730de79bc337241e6a2dc4e9cfad0e3 | |
| parent | 654e3345e535913653a2bad4204c31f9ccedb3c4 (diff) | |
| download | rust-d3ff497bec60687e3e1bdde383bd0b9dc74b5870.tar.gz rust-d3ff497bec60687e3e1bdde383bd0b9dc74b5870.zip  | |
Update other codegens to use tcx managed vtable allocations.
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/common.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/constant.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/unsize.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/vtable.rs | 106 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/common.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/meth.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/traits/consts.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/vtable.rs | 106 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/interpret/traits.rs | 97 | 
12 files changed, 143 insertions, 249 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 488ff6e1349..a8a0bb52a24 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -233,7 +233,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) module: &'m mut dyn Module, pub(crate) tcx: TyCtxt<'tcx>, pub(crate) pointer_type: Type, // Cached from module - pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>, + pub(crate) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer>, pub(crate) constants_cx: ConstantCx, pub(crate) instance: Instance<'tcx>, diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 3ba12c4e96d..a87b3703949 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -249,7 +249,7 @@ pub(crate) fn codegen_const_value<'tcx>( } } -fn pointer_for_allocation<'tcx>( +pub(crate) fn pointer_for_allocation<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, alloc: &'tcx Allocation, ) -> crate::pointer::Pointer { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 6aadaf8a7ca..b817bf4aff7 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -98,7 +98,7 @@ mod prelude { pub(crate) use cranelift_codegen::isa::{self, CallConv}; pub(crate) use cranelift_codegen::Context; pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; - pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module}; + pub(crate) use cranelift_module::{self, DataContext, FuncId, Linkage, Module}; pub(crate) use crate::abi::*; pub(crate) use crate::base::{codegen_operand, codegen_place}; diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 042583cd572..b9d379c6117 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -31,9 +31,7 @@ pub(crate) fn unsized_info<'tcx>( // change to the vtable. old_info.expect("unsized_info: missing old info for trait upcast") } - (_, &ty::Dynamic(ref data, ..)) => { - crate::vtable::get_vtable(fx, fx.layout_of(source), data.principal()) - } + (_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()), _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 4d1ee47b41e..12f7092d935 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -4,7 +4,7 @@ // FIXME dedup this logic between miri, cg_llvm and cg_clif use crate::prelude::*; -use ty::VtblEntry; +use super::constant::pointer_for_allocation; fn vtable_memflags() -> MemFlags { let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap. @@ -66,105 +66,19 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( pub(crate) fn get_vtable<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - layout: TyAndLayout<'tcx>, + ty: Ty<'tcx>, trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, ) -> Value { - let data_id = if let Some(data_id) = fx.vtables.get(&(layout.ty, trait_ref)) { - *data_id + let vtable_ptr = if let Some(vtable_ptr) = fx.vtables.get(&(ty, trait_ref)) { + *vtable_ptr } else { - let data_id = build_vtable(fx, layout, trait_ref); - fx.vtables.insert((layout.ty, trait_ref), data_id); - data_id - }; - - let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - fx.bcx.ins().global_value(fx.pointer_type, local_data_id) -} - -fn build_vtable<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - layout: TyAndLayout<'tcx>, - trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, -) -> DataId { - let tcx = fx.tcx; - let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; + let vtable_alloc_id = fx.tcx.vtable_allocation(ty, trait_ref); + let vtable_allocation = fx.tcx.global_alloc(vtable_alloc_id).unwrap_memory(); + let vtable_ptr = pointer_for_allocation(fx, vtable_allocation); - let drop_in_place_fn = import_function( - tcx, - fx.module, - Instance::resolve_drop_in_place(tcx, layout.ty).polymorphize(fx.tcx), - ); - - let vtable_entries = if let Some(trait_ref) = trait_ref { - tcx.vtable_entries(trait_ref.with_self_ty(tcx, layout.ty)) - } else { - ty::COMMON_VTABLE_ENTRIES + fx.vtables.insert((ty, trait_ref), vtable_ptr); + vtable_ptr }; - let mut data_ctx = DataContext::new(); - let mut data = ::std::iter::repeat(0u8) - .take(vtable_entries.len() * usize_size) - .collect::<Vec<u8>>() - .into_boxed_slice(); - - for (idx, entry) in vtable_entries.iter().enumerate() { - match entry { - VtblEntry::MetadataSize => { - write_usize(fx.tcx, &mut data, idx, layout.size.bytes()); - } - VtblEntry::MetadataAlign => { - write_usize(fx.tcx, &mut data, idx, layout.align.abi.bytes()); - } - VtblEntry::MetadataDropInPlace | VtblEntry::Vacant | VtblEntry::Method(_, _) => {} - } - } - data_ctx.define(data); - - for (idx, entry) in vtable_entries.iter().enumerate() { - match entry { - VtblEntry::MetadataDropInPlace => { - let func_ref = fx.module.declare_func_in_data(drop_in_place_fn, &mut data_ctx); - data_ctx.write_function_addr((idx * usize_size) as u32, func_ref); - } - VtblEntry::Method(def_id, substs) => { - let func_id = import_function( - tcx, - fx.module, - Instance::resolve_for_vtable(tcx, ParamEnv::reveal_all(), *def_id, substs) - .unwrap() - .polymorphize(fx.tcx), - ); - let func_ref = fx.module.declare_func_in_data(func_id, &mut data_ctx); - data_ctx.write_function_addr((idx * usize_size) as u32, func_ref); - } - VtblEntry::MetadataSize | VtblEntry::MetadataAlign | VtblEntry::Vacant => {} - } - } - - data_ctx.set_align(fx.tcx.data_layout.pointer_align.pref.bytes()); - - let data_id = fx.module.declare_anonymous_data(false, false).unwrap(); - - fx.module.define_data(data_id, &data_ctx).unwrap(); - - data_id -} - -fn write_usize(tcx: TyCtxt<'_>, buf: &mut [u8], idx: usize, num: u64) { - let pointer_size = - tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.usize)).unwrap().size.bytes() as usize; - let target = &mut buf[idx * pointer_size..(idx + 1) * pointer_size]; - - match tcx.data_layout.endian { - rustc_target::abi::Endian::Little => match pointer_size { - 4 => target.copy_from_slice(&(num as u32).to_le_bytes()), - 8 => target.copy_from_slice(&(num as u64).to_le_bytes()), - _ => todo!("pointer size {} is not yet supported", pointer_size), - }, - rustc_target::abi::Endian::Big => match pointer_size { - 4 => target.copy_from_slice(&(num as u32).to_be_bytes()), - 8 => target.copy_from_slice(&(num as u64).to_be_bytes()), - _ => todo!("pointer size {} is not yet supported", pointer_size), - }, - } + vtable_ptr.get_addr(fx) } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 58af9d4cd04..df5ad8ecc27 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -282,6 +282,10 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } + fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value { + const_alloc_to_llvm(self, alloc) + } + fn from_const_alloc( &self, layout: TyAndLayout<'tcx>, diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 4f0de729704..63245a94c8e 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -1,6 +1,6 @@ use crate::traits::*; -use rustc_middle::ty::{self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES}; +use rustc_middle::ty::{self, Ty}; use rustc_target::abi::call::FnAbi; #[derive(Copy, Clone, Debug)] @@ -70,48 +70,13 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( return val; } - // Not in the cache; build it. - let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space)); - - let vtable_entries = if let Some(trait_ref) = trait_ref { - tcx.vtable_entries(trait_ref.with_self_ty(tcx, ty)) - } else { - COMMON_VTABLE_ENTRIES - }; - - let layout = cx.layout_of(ty); - // ///////////////////////////////////////////////////////////////////////////////////////////// - // If you touch this code, be sure to also make the corresponding changes to - // `get_vtable` in `rust_mir/interpret/traits.rs`. - // ///////////////////////////////////////////////////////////////////////////////////////////// - let components: Vec<_> = vtable_entries - .iter() - .map(|entry| match entry { - VtblEntry::MetadataDropInPlace => { - cx.get_fn_addr(Instance::resolve_drop_in_place(cx.tcx(), ty)) - } - VtblEntry::MetadataSize => cx.const_usize(layout.size.bytes()), - VtblEntry::MetadataAlign => cx.const_usize(layout.align.abi.bytes()), - VtblEntry::Vacant => nullptr, - VtblEntry::Method(def_id, substs) => cx.get_fn_addr( - ty::Instance::resolve_for_vtable( - cx.tcx(), - ty::ParamEnv::reveal_all(), - *def_id, - substs, - ) - .unwrap() - .polymorphize(cx.tcx()), - ), - }) - .collect(); - - let vtable_const = cx.const_struct(&components, false); + let vtable_alloc_id = tcx.vtable_allocation(ty, trait_ref); + let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); + let vtable_const = cx.const_data_from_alloc(vtable_allocation); let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); cx.create_vtable_metadata(ty, vtable); - cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 6b58dea794b..20f66187123 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -26,6 +26,8 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option<u128>; + fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value; + fn scalar_to_backend(&self, cv: Scalar, layout: &abi::Scalar, llty: Self::Type) -> Self::Value; fn from_const_alloc( &self, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 77f955e93b9..a5a03ce0a4b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -11,7 +11,7 @@ use crate::middle; use crate::middle::cstore::{CrateStoreDyn, EncodedMetadata}; use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault}; use crate::middle::stability; -use crate::mir::interpret::{self, Allocation, ConstValue, Scalar}; +use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::thir::Thir; use crate::traits; @@ -1045,6 +1045,9 @@ pub struct GlobalCtxt<'tcx> { output_filenames: Arc<OutputFilenames>, pub main_def: Option<MainDefinition>, + + pub(super) vtables_cache: + Lock<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>>, } impl<'tcx> TyCtxt<'tcx> { @@ -1202,6 +1205,7 @@ impl<'tcx> TyCtxt<'tcx> { alloc_map: Lock::new(interpret::AllocMap::new()), output_filenames: Arc::new(output_filenames), main_def: resolutions.main_def, + vtables_cache: Default::default(), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a2abbec7492..859a940a625 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -18,6 +18,7 @@ pub use adt::*; pub use assoc::*; pub use closure::*; pub use generics::*; +pub use vtable::*; use crate::hir::exports::ExportMap; use crate::ich::StableHashingContext; @@ -94,6 +95,7 @@ pub mod relate; pub mod subst; pub mod trait_def; pub mod util; +pub mod vtable; pub mod walk; mod adt; @@ -2009,19 +2011,3 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> { fmt::Display::fmt(&self.name, fmt) } } - -#[derive(Clone, Copy, Debug, PartialEq, HashStable)] -pub enum VtblEntry<'tcx> { - MetadataDropInPlace, - MetadataSize, - MetadataAlign, - Vacant, - Method(DefId, SubstsRef<'tcx>), -} - -pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] = - &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; - -pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0; -pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1; -pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs new file mode 100644 index 00000000000..3a35d8c88a4 --- /dev/null +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -0,0 +1,106 @@ +use std::convert::TryFrom; + +use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; +use crate::ty::fold::TypeFoldable; +use crate::ty::{self, DefId, SubstsRef, Ty, TyCtxt}; +use rustc_ast::Mutability; + +#[derive(Clone, Copy, Debug, PartialEq, HashStable)] +pub enum VtblEntry<'tcx> { + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Vacant, + Method(DefId, SubstsRef<'tcx>), +} + +pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] = + &[VtblEntry::MetadataDropInPlace, VtblEntry::MetadataSize, VtblEntry::MetadataAlign]; + +pub const COMMON_VTABLE_ENTRIES_DROPINPLACE: usize = 0; +pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1; +pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; + +impl<'tcx> TyCtxt<'tcx> { + /// Retrieves an allocation that represents the contents of a vtable. + /// There's a cache within `TyCtxt` so it will be deduplicated. + pub fn vtable_allocation( + self, + ty: Ty<'tcx>, + poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + ) -> AllocId { + let tcx = self; + let vtables_cache = tcx.vtables_cache.lock(); + if let Some(alloc_id) = vtables_cache.get(&(ty, poly_trait_ref)).cloned() { + return alloc_id; + } + drop(vtables_cache); + + // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674 + assert!( + !ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst()) + ); + let param_env = ty::ParamEnv::reveal_all(); + let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { + let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); + let trait_ref = tcx.erase_regions(trait_ref); + + tcx.vtable_entries(trait_ref) + } else { + COMMON_VTABLE_ENTRIES + }; + + let layout = + tcx.layout_of(param_env.and(ty)).expect("failed to build vtable representation"); + assert!(!layout.is_unsized(), "can't create a vtable for an unsized type"); + let size = layout.size.bytes(); + let align = layout.align.abi.bytes(); + + let ptr_size = tcx.data_layout.pointer_size; + let ptr_align = tcx.data_layout.pointer_align.abi; + + let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); + let mut vtable = Allocation::uninit(vtable_size, ptr_align); + + // No need to do any alignment checks on the memory accesses below, because we know the + // allocation is correctly aligned as we created it above. Also we're only offsetting by + // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. + + for (idx, entry) in vtable_entries.iter().enumerate() { + let idx: u64 = u64::try_from(idx).unwrap(); + let scalar = match entry { + VtblEntry::MetadataDropInPlace => { + let instance = ty::Instance::resolve_drop_in_place(tcx, ty); + let fn_alloc_id = tcx.create_fn_alloc(instance); + let fn_ptr = Pointer::from(fn_alloc_id); + fn_ptr.into() + } + VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(), + VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(), + VtblEntry::Vacant => continue, + VtblEntry::Method(def_id, substs) => { + // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674 + assert!(!substs.needs_subst()); + + // Prepare the fn ptr we write into the vtable. + let instance = + ty::Instance::resolve_for_vtable(tcx, param_env, *def_id, substs) + .expect("resolution failed during building vtable representation") + .polymorphize(tcx); + let fn_alloc_id = tcx.create_fn_alloc(instance); + let fn_ptr = Pointer::from(fn_alloc_id); + fn_ptr.into() + } + }; + vtable + .write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar) + .expect("failed to build vtable representation"); + } + + vtable.mutability = Mutability::Not; + let alloc_id = tcx.create_memory_alloc(tcx.intern_const_alloc(vtable)); + let mut vtables_cache = self.vtables_cache.lock(); + vtables_cache.insert((ty, poly_trait_ref), alloc_id); + alloc_id + } +} diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 539d767d62a..5332e615bc8 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -1,29 +1,14 @@ use std::convert::TryFrom; -use rustc_middle::mir::interpret::{ - AllocError, InterpError, InterpResult, Pointer, PointerArithmetic, Scalar, - UndefinedBehaviorInfo, UnsupportedOpInfo, -}; +use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar}; use rustc_middle::ty::{ - self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN, + self, Ty, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE, }; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, Size}; -use super::alloc_range; use super::util::ensure_monomorphic_enough; -use super::{Allocation, FnVal, InterpCx, Machine}; - -fn vtable_alloc_error_to_interp_error<'tcx>(error: AllocError) -> InterpError<'tcx> { - match error { - AllocError::ReadPointerAsBytes => { - InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes) - } - AllocError::InvalidUninitBytes(_info) => { - InterpError::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(None)) - } - } -} +use super::{FnVal, InterpCx, Machine}; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -45,79 +30,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ensure_monomorphic_enough(*self.tcx, ty)?; ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; - if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) { - // This means we guarantee that there are no duplicate vtables, we will - // always use the same vtable for the same (Type, Trait) combination. - // That's not what happens in rustc, but emulating per-crate deduplication - // does not sound like it actually makes anything any better. - return Ok(vtable); - } - - let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { - let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty); - let trait_ref = self.tcx.erase_regions(trait_ref); - - self.tcx.vtable_entries(trait_ref) - } else { - COMMON_VTABLE_ENTRIES - }; - - let layout = self.layout_of(ty)?; - assert!(!layout.is_unsized(), "can't create a vtable for an unsized type"); - let size = layout.size.bytes(); - let align = layout.align.abi.bytes(); - - let tcx = *self.tcx; - let ptr_size = self.pointer_size(); - let ptr_align = tcx.data_layout.pointer_align.abi; - // ///////////////////////////////////////////////////////////////////////////////////////// - // If you touch this code, be sure to also make the corresponding changes to - // `get_vtable` in `rust_codegen_llvm/meth.rs`. - // ///////////////////////////////////////////////////////////////////////////////////////// - let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); - let mut vtable = Allocation::uninit(vtable_size, ptr_align); - - // No need to do any alignment checks on the memory accesses below, because we know the - // allocation is correctly aligned as we created it above. Also we're only offsetting by - // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. - let scalars = vtable_entries - .iter() - .map(|entry| -> InterpResult<'tcx, _> { - match entry { - VtblEntry::MetadataDropInPlace => { - let instance = Instance::resolve_drop_in_place(tcx, ty); - let fn_alloc_id = tcx.create_fn_alloc(instance); - let fn_ptr = Pointer::from(fn_alloc_id); - Ok(Some(fn_ptr.into())) - } - VtblEntry::MetadataSize => Ok(Some(Scalar::from_uint(size, ptr_size).into())), - VtblEntry::MetadataAlign => Ok(Some(Scalar::from_uint(align, ptr_size).into())), - VtblEntry::Vacant => Ok(None), - VtblEntry::Method(def_id, substs) => { - // Prepare the fn ptr we write into the vtable. - let instance = - Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs) - .ok_or_else(|| err_inval!(TooGeneric))?; - let fn_alloc_id = tcx.create_fn_alloc(instance); - let fn_ptr = Pointer::from(fn_alloc_id); - Ok(Some(fn_ptr.into())) - } - } - }) - .collect::<Result<Vec<_>, _>>()?; - for (idx, scalar) in scalars.into_iter().enumerate() { - if let Some(scalar) = scalar { - let idx: u64 = u64::try_from(idx).unwrap(); - vtable - .write_scalar(self, alloc_range(ptr_size * idx, ptr_size), scalar) - .map_err(vtable_alloc_error_to_interp_error)?; - } - } - - let vtable_id = tcx.create_memory_alloc(tcx.intern_const_alloc(vtable)); - let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_id))?; + let vtable_allocation = self.tcx.vtable_allocation(ty, poly_trait_ref); - assert!(self.vtables.insert((ty, poly_trait_ref), vtable_ptr).is_none()); + let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?; Ok(vtable_ptr) }  | 
