Allow miri allocation interning to work im generic Machines

This is necessary so that the `ComstPropMachine` can intern allocations.
This commit is contained in:
Wesley Wiser 2019-10-27 14:58:00 -04:00
parent f1b882b558
commit 8c406dc29c
3 changed files with 87 additions and 27 deletions

View File

@ -458,7 +458,7 @@ fn from(ptr: Pointer<Tag>) -> Self {
}
}
#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable)]
#[derive(Clone, Copy, Eq, PartialEq, RustcEncodable, RustcDecodable, HashStable, Hash)]
pub enum ScalarMaybeUndef<Tag = (), Id = AllocId> {
Scalar(Scalar<Tag, Id>),
Undef,

View File

@ -3,22 +3,34 @@
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.
use rustc::ty::{Ty, self};
use rustc::mir::interpret::{InterpResult, ErrorHandled};
use rustc::hir;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;
use rustc::hir;
use rustc::mir::interpret::{ErrorHandled, InterpResult};
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use syntax::ast::Mutability;
use super::{
ValueVisitor, MemoryKind, AllocId, MPlaceTy, Scalar,
AllocId, Allocation, InterpCx, Machine, MemoryKind, MPlaceTy, Scalar, ValueVisitor,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
struct InternVisitor<'rt, 'mir, 'tcx> {
struct InternVisitor<'rt, 'mir, 'tcx, M>
where
M: Machine<
'mir,
'tcx,
MemoryKinds = !,
PointerTag = (),
ExtraFnVal = !,
FrameExtra = (),
MemoryExtra = (),
AllocExtra = (),
MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
>,
{
/// The ectx from which we intern.
ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
/// Previously encountered safe references.
ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
/// A list of all encountered allocations. After type-based interning, we traverse this list to
@ -58,18 +70,28 @@ enum InternMode {
/// `immutable` things might become mutable if `ty` is not frozen.
/// `ty` can be `None` if there is no potential interior mutability
/// to account for (e.g. for vtables).
fn intern_shallow<'rt, 'mir, 'tcx>(
ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
fn intern_shallow<'rt, 'mir, 'tcx, M>(
ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
leftover_allocations: &'rt mut FxHashSet<AllocId>,
mode: InternMode,
alloc_id: AllocId,
mutability: Mutability,
ty: Option<Ty<'tcx>>,
) -> InterpResult<'tcx, Option<IsStaticOrFn>> {
trace!(
"InternVisitor::intern {:?} with {:?}",
alloc_id, mutability,
);
) -> InterpResult<'tcx, Option<IsStaticOrFn>>
where
M: Machine<
'mir,
'tcx,
MemoryKinds = !,
PointerTag = (),
ExtraFnVal = !,
FrameExtra = (),
MemoryExtra = (),
AllocExtra = (),
MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
>,
{
trace!("InternVisitor::intern {:?} with {:?}", alloc_id, mutability,);
// remove allocation
let tcx = ecx.tcx;
let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) {
@ -130,7 +152,20 @@ fn intern_shallow<'rt, 'mir, 'tcx>(
Ok(None)
}
impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> {
impl<'rt, 'mir, 'tcx, M> InternVisitor<'rt, 'mir, 'tcx, M>
where
M: Machine<
'mir,
'tcx,
MemoryKinds = !,
PointerTag = (),
ExtraFnVal = !,
FrameExtra = (),
MemoryExtra = (),
AllocExtra = (),
MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
>,
{
fn intern_shallow(
&mut self,
alloc_id: AllocId,
@ -148,15 +183,27 @@ fn intern_shallow(
}
}
impl<'rt, 'mir, 'tcx>
ValueVisitor<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>
impl<'rt, 'mir, 'tcx, M>
ValueVisitor<'mir, 'tcx, M>
for
InternVisitor<'rt, 'mir, 'tcx>
InternVisitor<'rt, 'mir, 'tcx, M>
where
M: Machine<
'mir,
'tcx,
MemoryKinds = !,
PointerTag = (),
ExtraFnVal = !,
FrameExtra = (),
MemoryExtra = (),
AllocExtra = (),
MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
>,
{
type V = MPlaceTy<'tcx>;
#[inline(always)]
fn ecx(&self) -> &CompileTimeEvalContext<'mir, 'tcx> {
fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> {
&self.ecx
}
@ -265,12 +312,25 @@ fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
}
}
pub fn intern_const_alloc_recursive(
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
pub fn intern_const_alloc_recursive<M>(
ecx: &mut InterpCx<'mir, 'tcx, M>,
// The `mutability` of the place, ignoring the type.
place_mut: Option<hir::Mutability>,
ret: MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
) -> InterpResult<'tcx>
where
M: Machine<
'mir,
'tcx,
MemoryKinds = !,
PointerTag = (),
ExtraFnVal = !,
FrameExtra = (),
MemoryExtra = (),
AllocExtra = (),
MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>,
>,
{
let tcx = ecx.tcx;
let (base_mutability, base_intern_mode) = match place_mut {
Some(hir::Mutability::Immutable) => (Mutability::Immutable, InternMode::Static),

View File

@ -27,7 +27,7 @@
/// operations and fat pointers. This idea was taken from rustc's codegen.
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
/// defined on `Immediate`, and do not have to work with a `Place`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash)]
pub enum Immediate<Tag=(), Id=AllocId> {
Scalar(ScalarMaybeUndef<Tag, Id>),
ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
@ -104,7 +104,7 @@ fn deref(&self) -> &Immediate<Tag> {
/// An `Operand` is the result of computing a `mir::Operand`. It can be immediate,
/// or still in memory. The latter is an optimization, to delay reading that chunk of
/// memory and to avoid having to store arbitrary-sized data here.
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, Hash)]
pub enum Operand<Tag=(), Id=AllocId> {
Immediate(Immediate<Tag, Id>),
Indirect(MemPlace<Tag, Id>),
@ -134,7 +134,7 @@ pub fn assert_immediate(self) -> Immediate<Tag>
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct OpTy<'tcx, Tag=()> {
op: Operand<Tag>, // Keep this private, it helps enforce invariants
pub layout: TyLayout<'tcx>,