From 21934c81f430d1a638279bb5d1d00cbe052a2eee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 09:15:13 +0200 Subject: [PATCH] add support for storing extra data in an allocation --- src/librustc/mir/interpret/mod.rs | 8 +++++-- src/librustc_mir/const_eval.rs | 10 ++++----- src/librustc_mir/interpret/eval_context.rs | 3 +-- src/librustc_mir/interpret/machine.rs | 26 ++++++++++++---------- src/librustc_mir/interpret/memory.rs | 24 ++++++++------------ src/librustc_mir/interpret/place.rs | 2 +- src/librustc_mir/interpret/snapshot.rs | 2 +- 7 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 5eee0fba5fb4..4482d0a69c25 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -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 { +pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer pub bytes: Vec, @@ -541,9 +541,11 @@ pub struct Allocation { /// 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 Allocation { +impl Allocation { /// 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 Allocation { undef_mask, align, mutability: Mutability::Immutable, + extra: Extra::default(), } } @@ -569,6 +572,7 @@ impl Allocation { undef_mask: UndefMask::new(size), align, mutability: Mutability::Mutable, + extra: Extra::default(), } } } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 2cfd058831f0..497c6a2a80e7 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -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, Allocation<()>)>; + type MemoryMap = FxHashMap, Allocation)>; const STATIC_KIND: Option = None; // no copying of statics allowed diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index cf5358a98967..9fb838c28a5a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -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(), } diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 560698f3f57a..790a1f6b7457 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -62,23 +62,25 @@ pub trait AllocMap { /// 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" + /// . + 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, Allocation)> + + AllocMap< + AllocId, + (MemoryKind, Allocation) + > + Default + Clone; - /// Tag tracked alongside every pointer. This is inert for now, in preparation for - /// a future implementation of "Stacked Borrows" - /// . - 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>>; + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>>; /// 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>; + ) -> Cow<'_, Allocation>; /// 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. diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 4b0c0c3ee617..d61f3e385693 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -47,9 +47,6 @@ pub enum MemoryKind { // `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, + alloc: Allocation, kind: MemoryKind, ) -> 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>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { 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> { + pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { // 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> { + ) -> EvalResult<'tcx, &mut Allocation> { 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( + fn dump_alloc_helper( &self, allocs_seen: &mut FxHashSet, allocs_to_print: &mut VecDeque, mut msg: String, - alloc: &Allocation, + alloc: &Allocation, 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, Allocation<()>)>, + M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=()>, + M::MemoryMap: AllocMap, Allocation)>, { /// mark an allocation as static and initialized, either mutable or not pub fn intern_static( diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index e4055947b642..c4f01d8ce31a 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -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, Allocation)>, + M::MemoryMap: AllocMap, Allocation)>, { /// 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`. diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 11d5785bc565..047a0125f78a 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -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,