Change miri to use tcx allocated allocations.
This commit is contained in:
parent
a5b7511a6c
commit
654e3345e5
5 changed files with 36 additions and 29 deletions
|
@ -2,7 +2,6 @@ use std::cell::Cell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
|
@ -40,10 +39,6 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
|
||||||
|
|
||||||
/// The virtual memory system.
|
/// The virtual memory system.
|
||||||
pub memory: Memory<'mir, 'tcx, M>,
|
pub memory: Memory<'mir, 'tcx, M>,
|
||||||
|
|
||||||
/// A cache for deduplicating vtables
|
|
||||||
pub(super) vtables:
|
|
||||||
FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer<M::PointerTag>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Phantomdata exists to prevent this type from being `Send`. If it were sent across a thread
|
// 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),
|
tcx: tcx.at(root_span),
|
||||||
param_env,
|
param_env,
|
||||||
memory: Memory::new(tcx, memory_extra),
|
memory: Memory::new(tcx, memory_extra),
|
||||||
vtables: FxHashMap::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,6 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
|
||||||
match kind {
|
match kind {
|
||||||
MemoryKind::Stack
|
MemoryKind::Stack
|
||||||
| MemoryKind::Machine(const_eval::MemoryKind::Heap)
|
| MemoryKind::Machine(const_eval::MemoryKind::Heap)
|
||||||
| MemoryKind::Vtable
|
|
||||||
| MemoryKind::CallerLocation => {}
|
| MemoryKind::CallerLocation => {}
|
||||||
}
|
}
|
||||||
// Set allocation mutability as appropriate. This is used by LLVM to put things into
|
// Set allocation mutability as appropriate. This is used by LLVM to put things into
|
||||||
|
|
|
@ -27,8 +27,6 @@ use crate::util::pretty;
|
||||||
pub enum MemoryKind<T> {
|
pub enum MemoryKind<T> {
|
||||||
/// Stack memory. Error if deallocated except during a stack pop.
|
/// Stack memory. Error if deallocated except during a stack pop.
|
||||||
Stack,
|
Stack,
|
||||||
/// Memory backing vtables. Error if ever deallocated.
|
|
||||||
Vtable,
|
|
||||||
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
|
/// Memory allocated by `caller_location` intrinsic. Error if ever deallocated.
|
||||||
CallerLocation,
|
CallerLocation,
|
||||||
/// Additional memory kinds a machine wishes to distinguish from the builtin ones.
|
/// Additional memory kinds a machine wishes to distinguish from the builtin ones.
|
||||||
|
@ -40,7 +38,6 @@ impl<T: MayLeak> MayLeak for MemoryKind<T> {
|
||||||
fn may_leak(self) -> bool {
|
fn may_leak(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
MemoryKind::Stack => false,
|
MemoryKind::Stack => false,
|
||||||
MemoryKind::Vtable => true,
|
|
||||||
MemoryKind::CallerLocation => true,
|
MemoryKind::CallerLocation => true,
|
||||||
MemoryKind::Machine(k) => k.may_leak(),
|
MemoryKind::Machine(k) => k.may_leak(),
|
||||||
}
|
}
|
||||||
|
@ -51,7 +48,6 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
MemoryKind::Stack => write!(f, "stack variable"),
|
MemoryKind::Stack => write!(f, "stack variable"),
|
||||||
MemoryKind::Vtable => write!(f, "vtable"),
|
|
||||||
MemoryKind::CallerLocation => write!(f, "caller location"),
|
MemoryKind::CallerLocation => write!(f, "caller location"),
|
||||||
MemoryKind::Machine(m) => write!(f, "{}", m),
|
MemoryKind::Machine(m) => write!(f, "{}", m),
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,7 +459,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
};
|
};
|
||||||
// Find and consult vtable
|
// Find and consult vtable
|
||||||
let vtable = receiver_place.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
|
// `*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
|
// 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));
|
OpTy::from(ImmTy::from_immediate(receiver_place.ptr.into(), this_receiver_ptr));
|
||||||
trace!("Patched self operand to {:#?}", args[0]);
|
trace!("Patched self operand to {:#?}", args[0]);
|
||||||
// recurse with concrete function
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,29 @@
|
||||||
use std::convert::TryFrom;
|
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::{
|
use rustc_middle::ty::{
|
||||||
self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
|
self, Instance, Ty, VtblEntry, COMMON_VTABLE_ENTRIES, COMMON_VTABLE_ENTRIES_ALIGN,
|
||||||
COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
|
COMMON_VTABLE_ENTRIES_DROPINPLACE, COMMON_VTABLE_ENTRIES_SIZE,
|
||||||
};
|
};
|
||||||
use rustc_target::abi::{Align, LayoutOf, Size};
|
use rustc_target::abi::{Align, LayoutOf, Size};
|
||||||
|
|
||||||
|
use super::alloc_range;
|
||||||
use super::util::ensure_monomorphic_enough;
|
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> {
|
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
|
/// 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`.
|
// `get_vtable` in `rust_codegen_llvm/meth.rs`.
|
||||||
// /////////////////////////////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
|
let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
|
||||||
let vtable = self.memory.allocate(vtable_size, ptr_align, MemoryKind::Vtable);
|
let mut vtable = Allocation::uninit(vtable_size, ptr_align);
|
||||||
|
|
||||||
let drop = Instance::resolve_drop_in_place(tcx, ty);
|
|
||||||
let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));
|
|
||||||
|
|
||||||
// No need to do any alignment checks on the memory accesses below, because we know the
|
// 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
|
// 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()
|
.iter()
|
||||||
.map(|entry| -> InterpResult<'tcx, _> {
|
.map(|entry| -> InterpResult<'tcx, _> {
|
||||||
match entry {
|
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::MetadataSize => Ok(Some(Scalar::from_uint(size, ptr_size).into())),
|
||||||
VtblEntry::MetadataAlign => Ok(Some(Scalar::from_uint(align, ptr_size).into())),
|
VtblEntry::MetadataAlign => Ok(Some(Scalar::from_uint(align, ptr_size).into())),
|
||||||
VtblEntry::Vacant => Ok(None),
|
VtblEntry::Vacant => Ok(None),
|
||||||
VtblEntry::Method(def_id, substs) => {
|
VtblEntry::Method(def_id, substs) => {
|
||||||
// Prepare the fn ptr we write into the vtable.
|
// Prepare the fn ptr we write into the vtable.
|
||||||
let instance =
|
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))?;
|
.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()))
|
Ok(Some(fn_ptr.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
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() {
|
for (idx, scalar) in scalars.into_iter().enumerate() {
|
||||||
if let Some(scalar) = scalar {
|
if let Some(scalar) = scalar {
|
||||||
let idx: u64 = u64::try_from(idx).unwrap();
|
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_ptr).is_none());
|
||||||
assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none());
|
|
||||||
|
|
||||||
Ok(vtable)
|
Ok(vtable_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the function at the specified slot in the provided
|
/// Resolves the function at the specified slot in the provided
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue