add support for storing extra data in an allocation
This commit is contained in:
parent
290db47ad6
commit
21934c81f4
7 changed files with 37 additions and 38 deletions
|
@ -524,7 +524,7 @@ impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct Allocation<Tag=()> {
|
||||
pub struct Allocation<Tag=(),Extra=()> {
|
||||
/// The actual bytes of the allocation.
|
||||
/// Note that the bytes of a pointer represent the offset of the pointer
|
||||
pub bytes: Vec<u8>,
|
||||
|
@ -541,9 +541,11 @@ pub struct Allocation<Tag=()> {
|
|||
/// Also used by codegen to determine if a static should be put into mutable memory,
|
||||
/// which happens for `static mut` and `static` with interior mutability.
|
||||
pub mutability: Mutability,
|
||||
/// Extra state for the machine.
|
||||
pub extra: Extra,
|
||||
}
|
||||
|
||||
impl<Tag> Allocation<Tag> {
|
||||
impl<Tag, Extra: Default> Allocation<Tag, Extra> {
|
||||
/// Creates a read-only allocation initialized by the given bytes
|
||||
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
|
||||
let mut undef_mask = UndefMask::new(Size::ZERO);
|
||||
|
@ -554,6 +556,7 @@ impl<Tag> Allocation<Tag> {
|
|||
undef_mask,
|
||||
align,
|
||||
mutability: Mutability::Immutable,
|
||||
extra: Extra::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -569,6 +572,7 @@ impl<Tag> Allocation<Tag> {
|
|||
undef_mask: UndefMask::new(size),
|
||||
align,
|
||||
mutability: Mutability::Mutable,
|
||||
extra: Extra::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
|
|||
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
|
||||
debug!("mk_borrowck_eval_cx: {:?}", instance);
|
||||
let param_env = tcx.param_env(instance.def_id());
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
|
||||
// insert a stack frame so any queries have the correct substs
|
||||
// cannot use `push_stack_frame`; if we do `const_prop` explodes
|
||||
ecx.stack.push(interpret::Frame {
|
||||
|
@ -76,7 +76,7 @@ pub fn mk_eval_cx<'a, 'tcx>(
|
|||
) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
|
||||
debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
|
||||
let span = tcx.def_span(instance.def_id());
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
|
||||
let mir = ecx.load_mir(instance.def)?;
|
||||
// insert a stack frame so any queries have the correct substs
|
||||
ecx.push_stack_frame(
|
||||
|
@ -155,7 +155,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
|||
// and try improving it down the road when more information is available
|
||||
let span = tcx.def_span(cid.instance.def_id());
|
||||
let span = mir.map(|mir| mir.span).unwrap_or(span);
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
|
||||
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
|
||||
let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
|
||||
(r, ecx)
|
||||
}
|
||||
|
@ -336,11 +336,11 @@ type CompileTimeEvalContext<'a, 'mir, 'tcx> =
|
|||
impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
||||
for CompileTimeInterpreter<'a, 'mir, 'tcx>
|
||||
{
|
||||
type MemoryData = ();
|
||||
type MemoryKinds = !;
|
||||
type AllocExtra = ();
|
||||
type PointerTag = ();
|
||||
|
||||
type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
|
||||
type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;
|
||||
|
||||
const STATIC_KIND: Option<!> = None; // no copying of statics allowed
|
||||
|
||||
|
|
|
@ -205,13 +205,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
|
|||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
machine: M,
|
||||
memory_data: M::MemoryData,
|
||||
) -> Self {
|
||||
EvalContext {
|
||||
machine,
|
||||
tcx,
|
||||
param_env,
|
||||
memory: Memory::new(tcx, memory_data),
|
||||
memory: Memory::new(tcx),
|
||||
stack: Vec::new(),
|
||||
vtables: FxHashMap::default(),
|
||||
}
|
||||
|
|
|
@ -62,23 +62,25 @@ pub trait AllocMap<K: Hash + Eq, V> {
|
|||
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
||||
/// and some use case dependent behaviour can instead be applied.
|
||||
pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
||||
/// Additional data that can be accessed via the Memory
|
||||
type MemoryData;
|
||||
|
||||
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
|
||||
type MemoryKinds: ::std::fmt::Debug + Copy + Eq;
|
||||
type MemoryKinds: ::std::fmt::Debug + Copy + Eq + 'static;
|
||||
|
||||
/// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
|
||||
/// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
|
||||
type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
|
||||
|
||||
/// Extra data stored in every allocation.
|
||||
type AllocExtra: ::std::fmt::Debug + Default + Clone;
|
||||
|
||||
/// Memory's allocation map
|
||||
type MemoryMap:
|
||||
AllocMap<AllocId, (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag>)> +
|
||||
AllocMap<
|
||||
AllocId,
|
||||
(MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
|
||||
> +
|
||||
Default +
|
||||
Clone;
|
||||
|
||||
/// Tag tracked alongside every pointer. This is inert for now, in preparation for
|
||||
/// a future implementation of "Stacked Borrows"
|
||||
/// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
|
||||
type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
|
||||
|
||||
/// The memory kind to use for copied statics -- or None if those are not supported.
|
||||
/// Statics are copied under two circumstances: When they are mutated, and when
|
||||
/// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
|
||||
|
@ -127,7 +129,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
|||
fn find_foreign_static(
|
||||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId,
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>>;
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;
|
||||
|
||||
/// Called to turn an allocation obtained from the `tcx` into one that has
|
||||
/// the appropriate tags on each pointer.
|
||||
|
@ -138,7 +140,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
|||
/// owned allocation to the map even when the map is shared.)
|
||||
fn static_with_default_tag(
|
||||
alloc: &'_ Allocation
|
||||
) -> Cow<'_, Allocation<Self::PointerTag>>;
|
||||
) -> Cow<'_, Allocation<Self::PointerTag, Self::AllocExtra>>;
|
||||
|
||||
/// Called for all binary operations on integer(-like) types when one operand is a pointer
|
||||
/// value, and for the `Offset` operation that is inherently about pointers.
|
||||
|
|
|
@ -47,9 +47,6 @@ pub enum MemoryKind<T> {
|
|||
// `Memory` has to depend on the `Machine` because some of its operations
|
||||
// (e.g. `get`) call a `Machine` hook.
|
||||
pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
|
||||
/// Additional data required by the Machine
|
||||
pub data: M::MemoryData,
|
||||
|
||||
/// Allocations local to this instance of the miri engine. The kind
|
||||
/// helps ensure that the same mechanism is used for allocation and
|
||||
/// deallocation. When an allocation is not found here, it is a
|
||||
|
@ -91,11 +88,9 @@ impl<'a, 'b, 'c, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout
|
|||
// carefully copy only the reachable parts.
|
||||
impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>>
|
||||
Clone for Memory<'a, 'mir, 'tcx, M>
|
||||
where M::MemoryData: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Memory {
|
||||
data: self.data.clone(),
|
||||
alloc_map: self.alloc_map.clone(),
|
||||
dead_alloc_map: self.dead_alloc_map.clone(),
|
||||
tcx: self.tcx,
|
||||
|
@ -104,9 +99,8 @@ impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>>
|
|||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
|
||||
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>) -> Self {
|
||||
Memory {
|
||||
data,
|
||||
alloc_map: Default::default(),
|
||||
dead_alloc_map: FxHashMap::default(),
|
||||
tcx,
|
||||
|
@ -123,7 +117,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
|
||||
pub fn allocate_with(
|
||||
&mut self,
|
||||
alloc: Allocation<M::PointerTag>,
|
||||
alloc: Allocation<M::PointerTag, M::AllocExtra>,
|
||||
kind: MemoryKind<M::MemoryKinds>,
|
||||
) -> EvalResult<'tcx, AllocId> {
|
||||
let id = self.tcx.alloc_map.lock().reserve();
|
||||
|
@ -334,7 +328,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
fn get_static_alloc(
|
||||
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
|
||||
id: AllocId,
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag>>> {
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
|
||||
let alloc = tcx.alloc_map.lock().get(id);
|
||||
let def_id = match alloc {
|
||||
Some(AllocType::Memory(mem)) => {
|
||||
|
@ -376,7 +370,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::PointerTag>> {
|
||||
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> {
|
||||
// The error type of the inner closure here is somewhat funny. We have two
|
||||
// ways of "erroring": An actual error, or because we got a reference from
|
||||
// `get_static_alloc` that we can actually use directly without inserting anything anywhere.
|
||||
|
@ -409,7 +403,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
pub fn get_mut(
|
||||
&mut self,
|
||||
id: AllocId,
|
||||
) -> EvalResult<'tcx, &mut Allocation<M::PointerTag>> {
|
||||
) -> EvalResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
|
||||
let tcx = self.tcx;
|
||||
let a = self.alloc_map.get_mut_or(id, || {
|
||||
// Need to make a copy, even if `get_static_alloc` is able
|
||||
|
@ -482,12 +476,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
self.dump_allocs(vec![id]);
|
||||
}
|
||||
|
||||
fn dump_alloc_helper<Tag>(
|
||||
fn dump_alloc_helper<Tag, Extra>(
|
||||
&self,
|
||||
allocs_seen: &mut FxHashSet<AllocId>,
|
||||
allocs_to_print: &mut VecDeque<AllocId>,
|
||||
mut msg: String,
|
||||
alloc: &Allocation<Tag>,
|
||||
alloc: &Allocation<Tag, Extra>,
|
||||
extra: String,
|
||||
) {
|
||||
use std::fmt::Write;
|
||||
|
@ -687,8 +681,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
/// Interning (for CTFE)
|
||||
impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
|
||||
where
|
||||
M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
|
||||
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<()>)>,
|
||||
M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=()>,
|
||||
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
|
||||
{
|
||||
/// mark an allocation as static and initialized, either mutable or not
|
||||
pub fn intern_static(
|
||||
|
|
|
@ -267,7 +267,7 @@ impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
|
|||
where
|
||||
Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
|
||||
M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
|
||||
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag>)>,
|
||||
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
|
||||
{
|
||||
/// Take a value, which represents a (thin or fat) reference, and make it a place.
|
||||
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref`.
|
||||
|
|
|
@ -305,7 +305,7 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
|
|||
type Item = AllocationSnapshot<'a>;
|
||||
|
||||
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
|
||||
let Allocation { bytes, relocations, undef_mask, align, mutability } = self;
|
||||
let Allocation { bytes, relocations, undef_mask, align, mutability, extra: () } = self;
|
||||
|
||||
AllocationSnapshot {
|
||||
bytes,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue