From 654e3345e535913653a2bad4204c31f9ccedb3c4 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 20 Jun 2021 12:34:26 +0800 Subject: [PATCH] Change miri to use tcx allocated allocations. --- .../rustc_mir/src/interpret/eval_context.rs | 6 --- compiler/rustc_mir/src/interpret/intern.rs | 1 - compiler/rustc_mir/src/interpret/memory.rs | 4 -- .../rustc_mir/src/interpret/terminator.rs | 4 +- compiler/rustc_mir/src/interpret/traits.rs | 50 +++++++++++++------ 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 6f7519e6156..801e4b1e478 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -2,7 +2,6 @@ use std::cell::Cell; use std::fmt; use std::mem; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::vec::IndexVec; @@ -40,10 +39,6 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// The virtual memory system. pub memory: Memory<'mir, 'tcx, M>, - - /// A cache for deduplicating vtables - pub(super) vtables: - FxHashMap<(Ty<'tcx>, Option>), Pointer>, } // The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread @@ -393,7 +388,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { tcx: tcx.at(root_span), param_env, memory: Memory::new(tcx, memory_extra), - vtables: FxHashMap::default(), } } diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs index 23c0fe97c5f..d5fec457fa1 100644 --- a/compiler/rustc_mir/src/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -107,7 +107,6 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: match kind { MemoryKind::Stack | MemoryKind::Machine(const_eval::MemoryKind::Heap) - | MemoryKind::Vtable | MemoryKind::CallerLocation => {} } // Set allocation mutability as appropriate. This is used by LLVM to put things into diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 77de19ac674..94506808a68 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -27,8 +27,6 @@ use crate::util::pretty; pub enum MemoryKind { /// Stack memory. Error if deallocated except during a stack pop. Stack, - /// Memory backing vtables. Error if ever deallocated. - Vtable, /// Memory allocated by `caller_location` intrinsic. Error if ever deallocated. CallerLocation, /// Additional memory kinds a machine wishes to distinguish from the builtin ones. @@ -40,7 +38,6 @@ impl MayLeak for MemoryKind { fn may_leak(self) -> bool { match self { MemoryKind::Stack => false, - MemoryKind::Vtable => true, MemoryKind::CallerLocation => true, MemoryKind::Machine(k) => k.may_leak(), } @@ -51,7 +48,6 @@ impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { MemoryKind::Stack => write!(f, "stack variable"), - MemoryKind::Vtable => write!(f, "vtable"), MemoryKind::CallerLocation => write!(f, "caller location"), MemoryKind::Machine(m) => write!(f, "{}", m), } diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index a5bdeb55e78..aea9933b337 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -459,7 +459,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Find and consult vtable let vtable = receiver_place.vtable(); - let drop_fn = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; + let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; // `*mut receiver_place.layout.ty` is almost the layout that we // want for args[0]: We have to project to field 0 because we want @@ -472,7 +472,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { OpTy::from(ImmTy::from_immediate(receiver_place.ptr.into(), this_receiver_ptr)); trace!("Patched self operand to {:#?}", args[0]); // recurse with concrete function - self.eval_fn_call(drop_fn, caller_abi, &args, ret, unwind) + self.eval_fn_call(fn_val, caller_abi, &args, ret, unwind) } } } diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 072c252be2f..539d767d62a 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -1,14 +1,29 @@ use std::convert::TryFrom; -use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar}; +use rustc_middle::mir::interpret::{ + AllocError, InterpError, InterpResult, Pointer, PointerArithmetic, Scalar, + UndefinedBehaviorInfo, UnsupportedOpInfo, +}; use rustc_middle::ty::{ self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE, }; use rustc_target::abi::{Align, LayoutOf, Size}; +use super::alloc_range; use super::util::ensure_monomorphic_enough; -use super::{FnVal, InterpCx, Machine, MemoryKind}; +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)) + } + } +} 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 @@ -60,10 +75,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `get_vtable` in `rust_codegen_llvm/meth.rs`. // ///////////////////////////////////////////////////////////////////////////////////////// let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap(); - let vtable = self.memory.allocate(vtable_size, ptr_align, MemoryKind::Vtable); - - let drop = Instance::resolve_drop_in_place(tcx, ty); - let drop = self.memory.create_fn_alloc(FnVal::Instance(drop)); + 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 @@ -72,36 +84,42 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .iter() .map(|entry| -> InterpResult<'tcx, _> { match entry { - VtblEntry::MetadataDropInPlace => Ok(Some(drop.into())), + 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 = - ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs) + Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs) .ok_or_else(|| err_inval!(TooGeneric))?; - let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); + let fn_alloc_id = tcx.create_fn_alloc(instance); + let fn_ptr = Pointer::from(fn_alloc_id); Ok(Some(fn_ptr.into())) } } }) .collect::, _>>()?; - let mut vtable_alloc = - self.memory.get_mut(vtable.into(), vtable_size, ptr_align)?.expect("not a ZST"); for (idx, scalar) in scalars.into_iter().enumerate() { if let Some(scalar) = scalar { let idx: u64 = u64::try_from(idx).unwrap(); - vtable_alloc.write_ptr_sized(ptr_size * idx, scalar)?; + vtable + .write_scalar(self, alloc_range(ptr_size * idx, ptr_size), scalar) + .map_err(vtable_alloc_error_to_interp_error)?; } } - M::after_static_mem_initialized(self, vtable, vtable_size)?; + let vtable_id = tcx.create_memory_alloc(tcx.intern_const_alloc(vtable)); + let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_id))?; - self.memory.mark_immutable(vtable.alloc_id)?; - assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none()); + assert!(self.vtables.insert((ty, poly_trait_ref), vtable_ptr).is_none()); - Ok(vtable) + Ok(vtable_ptr) } /// Resolves the function at the specified slot in the provided