about summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src/interpret/traits.rs
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2022-07-17 16:02:49 -0400
committerRalf Jung <post@ralfj.de>2022-07-20 17:12:04 -0400
commitfe00573324854e5681546b660bbbaf4e1ec38eb2 (patch)
tree226774fcd3c885bc7cdafde8a5aa0425c762b651 /compiler/rustc_const_eval/src/interpret/traits.rs
parenta10d8e458118b3feac96fe5e56c25e70cee99b88 (diff)
downloadrust-fe00573324854e5681546b660bbbaf4e1ec38eb2.tar.gz
rust-fe00573324854e5681546b660bbbaf4e1ec38eb2.zip
make use of symbolic vtables in interpreter
Diffstat (limited to 'compiler/rustc_const_eval/src/interpret/traits.rs')
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs133
1 files changed, 24 insertions, 109 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index e4052b61782..bddca2a20ed 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,14 +1,10 @@
-use std::convert::TryFrom;
-
-use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic};
-use rustc_middle::ty::{
-    self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
-    COMMON_VTABLE_ENTRIES_SIZE,
-};
+use rustc_middle::mir::interpret::{InterpResult, Pointer};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_target::abi::{Align, Size};
 
 use super::util::ensure_monomorphic_enough;
-use super::{FnVal, InterpCx, Machine};
+use super::{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
@@ -17,8 +13,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// The `trait_ref` encodes the erased self type. Hence, if we are
     /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
     /// `trait_ref` would map `T: Trait`.
-    pub fn get_vtable(
-        &mut self,
+    pub fn get_vtable_ptr(
+        &self,
         ty: Ty<'tcx>,
         poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
     ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
@@ -30,114 +26,33 @@ 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)?;
 
-        let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref));
-
-        let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?;
-
+        let vtable_symbolic_allocation = self.tcx.create_vtable_alloc(ty, poly_trait_ref);
+        let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?;
         Ok(vtable_ptr.into())
     }
 
-    /// Resolves the function at the specified slot in the provided
-    /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`)
-    /// corresponds to the first method declared in the trait of the provided vtable.
-    pub fn get_vtable_slot(
+    /// Returns a high-level representation of the entires of the given vtable.
+    pub fn get_vtable_entries(
         &self,
         vtable: Pointer<Option<M::Provenance>>,
-        idx: u64,
-    ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
-        let ptr_size = self.pointer_size();
-        let vtable_slot = vtable.offset(ptr_size * idx, self)?;
-        let vtable_slot = self
-            .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
-            .expect("cannot be a ZST");
-        let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?;
-        self.get_ptr_fn(fn_ptr)
+    ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
+        let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
+        Ok(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 {
+            TyCtxt::COMMON_VTABLE_ENTRIES
+        })
     }
 
-    /// Returns the drop fn instance as well as the actual dynamic type.
-    pub fn read_drop_type_from_vtable(
-        &self,
-        vtable: Pointer<Option<M::Provenance>>,
-    ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
-        let pointer_size = self.pointer_size();
-        // We don't care about the pointee type; we just want a pointer.
-        let vtable = self
-            .get_ptr_alloc(
-                vtable,
-                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
-                self.tcx.data_layout.pointer_align.abi,
-            )?
-            .expect("cannot be a ZST");
-        let drop_fn = vtable
-            .read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())?
-            .check_init()?;
-        // We *need* an instance here, no other kind of function value, to be able
-        // to determine the type.
-        let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?;
-        trace!("Found drop fn: {:?}", drop_instance);
-        let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
-        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig);
-        // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
-        let args = fn_sig.inputs();
-        if args.len() != 1 {
-            throw_ub!(InvalidVtableDropFn(fn_sig));
-        }
-        let ty =
-            args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty;
-        Ok((drop_instance, ty))
-    }
-
-    pub fn read_size_and_align_from_vtable(
+    pub fn get_vtable_size_and_align(
         &self,
         vtable: Pointer<Option<M::Provenance>>,
     ) -> InterpResult<'tcx, (Size, Align)> {
-        let pointer_size = self.pointer_size();
-        // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
-        // the size, and the align (which we read below).
-        let vtable = self
-            .get_ptr_alloc(
-                vtable,
-                pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
-                self.tcx.data_layout.pointer_align.abi,
-            )?
-            .expect("cannot be a ZST");
-        let size = vtable
-            .read_integer(alloc_range(
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(),
-                pointer_size,
-            ))?
-            .check_init()?;
-        let size = size.to_machine_usize(self)?;
-        let size = Size::from_bytes(size);
-        let align = vtable
-            .read_integer(alloc_range(
-                pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(),
-                pointer_size,
-            ))?
-            .check_init()?;
-        let align = align.to_machine_usize(self)?;
-        let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
-
-        if size > self.max_size_of_val() {
-            throw_ub!(InvalidVtableSize);
-        }
-        Ok((size, align))
-    }
-
-    pub fn read_new_vtable_after_trait_upcasting_from_vtable(
-        &self,
-        vtable: Pointer<Option<M::Provenance>>,
-        idx: u64,
-    ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
-        let pointer_size = self.pointer_size();
-
-        let vtable_slot = vtable.offset(pointer_size * idx, self)?;
-        let new_vtable = self
-            .get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
-            .expect("cannot be a ZST");
-
-        let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?;
-
-        Ok(new_vtable)
+        let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
+        let layout = self.layout_of(ty)?;
+        assert!(!layout.is_unsized(), "there are no vtables for unsized types");
+        Ok((layout.size, layout.align.abi))
     }
 }