about summary refs log tree commit diff
path: root/compiler/rustc_middle/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-29 15:52:21 +0000
committerbors <bors@rust-lang.org>2021-06-29 15:52:21 +0000
commite98897e5dc9898707bf4331c43b2e76ab7e282fe (patch)
treeb676c09db0f7bbb80996a1e354dc58cc4ec010d5 /compiler/rustc_middle/src
parent8971fff984e7a45ca6cdcd146816b4896a4ab1ea (diff)
parent97772bb1f230f4981c9af6614df1ebc09b12c4f6 (diff)
downloadrust-e98897e5dc9898707bf4331c43b2e76ab7e282fe.tar.gz
rust-e98897e5dc9898707bf4331c43b2e76ab7e282fe.zip
Auto merge of #86475 - crlf0710:miri_vtable_refactor, r=bjorn3
Change vtable memory representation to use tcx allocated allocations.

This fixes https://github.com/rust-lang/rust/issues/86324. However i suspect there's more to change before it can land.

r? `@bjorn3`
cc `@rust-lang/miri`
Diffstat (limited to 'compiler/rustc_middle/src')
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs18
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs106
3 files changed, 113 insertions, 17 deletions
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 892996189a6..16d2ac262d0 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;
@@ -1044,6 +1044,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> {
@@ -1201,6 +1204,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
+    }
+}