From 7cfb05fd23b5ecc6a13f4629844ff81ac758497c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 30 Jan 2019 14:16:18 +0100 Subject: [PATCH] Merge `locals` and `local_layouts` fields --- src/librustc_mir/interpret/eval_context.rs | 70 ++++++++++++---------- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/snapshot.rs | 35 ++++++++--- 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 34443bb353e0..d2cabde98634 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -76,8 +76,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> { /// The locals are stored as `Option`s. /// `None` represents a local that is currently dead, while a live local /// can either directly contain `Scalar` or refer to some part of an `Allocation`. - pub locals: IndexVec>, - pub local_layouts: IndexVec>>>, + pub locals: IndexVec>, //////////////////////////////////////////////////////////////////////////////// // Current position within the function @@ -106,9 +105,17 @@ pub enum StackPopCleanup { None { cleanup: bool }, } -// State of a local variable +/// State of a local variable including a memoized layout +#[derive(Clone, PartialEq, Eq)] +pub struct LocalValue<'tcx, Tag=(), Id=AllocId> { + pub state: LocalState, + /// Don't modify if `Some`, this is only used to prevent computing the layout twice + pub layout: Cell>>, +} + +/// State of a local variable #[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub enum LocalValue { +pub enum LocalState { Dead, // Mostly for convenience, we re-use the `Operand` type here. // This is an optimization over just always having a pointer here; @@ -117,18 +124,18 @@ pub enum LocalValue { Live(Operand), } -impl<'tcx, Tag> LocalValue { +impl<'tcx, Tag> LocalValue<'tcx, Tag> { pub fn access(&self) -> EvalResult<'tcx, &Operand> { - match self { - LocalValue::Dead => err!(DeadLocal), - LocalValue::Live(ref val) => Ok(val), + match self.state { + LocalState::Dead => err!(DeadLocal), + LocalState::Live(ref val) => Ok(val), } } pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> { - match self { - LocalValue::Dead => err!(DeadLocal), - LocalValue::Live(ref mut val) => Ok(val), + match self.state { + LocalState::Dead => err!(DeadLocal), + LocalState::Live(ref mut val) => Ok(val), } } } @@ -312,7 +319,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local ) -> EvalResult<'tcx, TyLayout<'tcx>> { - let cell = &frame.local_layouts[local]; + let cell = &frame.locals[local].layout; if cell.get().is_none() { let local_ty = frame.mir.local_decls[local].ty; let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs); @@ -454,7 +461,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // empty local array, we fill it in below, after we are inside the stack frame and // all methods actually know about the frame locals: IndexVec::new(), - local_layouts: IndexVec::from_elem_n(Default::default(), mir.local_decls.len()), span, instance, stmt: 0, @@ -464,14 +470,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc // don't allocate at all for trivial constants if mir.local_decls.len() > 1 { // We put some marker immediate into the locals that we later want to initialize. - // This can be anything except for LocalValue::Dead -- because *that* is the + // This can be anything except for LocalState::Dead -- because *that* is the // value we use for things that we know are initially dead. - let dummy = - LocalValue::Live(Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))); + let dummy = LocalValue { + state: LocalState::Live(Operand::Immediate(Immediate::Scalar( + ScalarMaybeUndef::Undef, + ))), + layout: Cell::new(None), + }; let mut locals = IndexVec::from_elem(dummy, &mir.local_decls); // Return place is handled specially by the `eval_place` functions, and the // entry in `locals` should never be used. Make it dead, to be sure. - locals[mir::RETURN_PLACE] = LocalValue::Dead; + locals[mir::RETURN_PLACE].state = LocalState::Dead; // Now mark those locals as dead that we do not want to initialize match self.tcx.describe_def(instance.def_id()) { // statics and constants don't have `Storage*` statements, no need to look for them @@ -484,7 +494,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc match stmt.kind { StorageLive(local) | StorageDead(local) => { - locals[local] = LocalValue::Dead; + locals[local].state = LocalState::Dead; } _ => {} } @@ -494,13 +504,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } // Finally, properly initialize all those that still have the dummy value for (idx, local) in locals.iter_enumerated_mut() { - match *local { - LocalValue::Live(_) => { + match local.state { + LocalState::Live(_) => { // This needs to be peoperly initialized. let layout = self.layout_of_local(self.frame(), idx)?; - *local = LocalValue::Live(self.uninit_operand(layout)?); + local.state = LocalState::Live(self.uninit_operand(layout)?); } - LocalValue::Dead => { + LocalState::Dead => { // Nothing to do } } @@ -543,7 +553,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } // Deallocate all locals that are backed by an allocation. for local in frame.locals { - self.deallocate_local(local)?; + self.deallocate_local(local.state)?; } // Validate the return value. Do this after deallocating so that we catch dangling // references. @@ -587,31 +597,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn storage_live( &mut self, local: mir::Local - ) -> EvalResult<'tcx, LocalValue> { + ) -> EvalResult<'tcx, LocalState> { assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); trace!("{:?} is now live", local); let layout = self.layout_of_local(self.frame(), local)?; - let init = LocalValue::Live(self.uninit_operand(layout)?); + let init = LocalState::Live(self.uninit_operand(layout)?); // StorageLive *always* kills the value that's currently stored - Ok(mem::replace(&mut self.frame_mut().locals[local], init)) + Ok(mem::replace(&mut self.frame_mut().locals[local].state, init)) } /// Returns the old value of the local. /// Remember to deallocate that! - pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue { + pub fn storage_dead(&mut self, local: mir::Local) -> LocalState { assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); - mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead) + mem::replace(&mut self.frame_mut().locals[local].state, LocalState::Dead) } pub(super) fn deallocate_local( &mut self, - local: LocalValue, + local: LocalState, ) -> EvalResult<'tcx> { // FIXME: should we tell the user that there was a local which was never written to? - if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { + if let LocalState::Live(Operand::Indirect(MemPlace { ptr, .. })) = local { trace!("deallocating local"); let ptr = ptr.to_ptr()?; self.memory.dump_alloc(ptr.alloc_id); diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index e3ab90a60204..6ee7d3309f46 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -18,7 +18,7 @@ mod visitor; pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here pub use self::eval_context::{ - EvalContext, Frame, StackPopCleanup, LocalValue, + EvalContext, Frame, StackPopCleanup, LocalValue, LocalState, }; pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy}; diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 53105266b392..0b5dc9446921 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -7,7 +7,7 @@ use std::hash::{Hash, Hasher}; -use rustc::ich::StableHashingContextProvider; +use rustc::ich::{StableHashingContextProvider, StableHashingContext}; use rustc::mir; use rustc::mir::interpret::{ AllocId, Pointer, Scalar, @@ -19,12 +19,12 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::Align; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use syntax::ast::Mutability; use syntax::source_map::Span; use super::eval_context::{LocalValue, StackPopCleanup}; -use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef}; +use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef, LocalState}; use const_eval::CompileTimeInterpreter; #[derive(Default)] @@ -250,11 +250,11 @@ impl_snapshot_for!(enum Operand { Indirect(m), }); -impl_stable_hash_for!(enum ::interpret::LocalValue { +impl_stable_hash_for!(enum ::interpret::LocalState { Dead, Live(x), }); -impl_snapshot_for!(enum LocalValue { +impl_snapshot_for!(enum LocalState { Live(v), Dead, }); @@ -309,7 +309,7 @@ struct FrameSnapshot<'a, 'tcx: 'a> { span: &'a Span, return_to_block: &'a StackPopCleanup, return_place: Option>>, - locals: IndexVec>>, + locals: IndexVec>>, block: &'a mir::BasicBlock, stmt: usize, } @@ -321,7 +321,6 @@ impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> { return_to_block, return_place -> (return_place.as_ref().map(|r| &**r)), locals, - local_layouts -> _, block, stmt, extra, @@ -340,7 +339,6 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> return_to_block, return_place, locals, - local_layouts: _, block, stmt, extra: _, @@ -358,6 +356,27 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> } } +impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalValue<'tcx> + where Ctx: SnapshotContext<'a>, +{ + type Item = LocalState<(), AllocIdSnapshot<'a>>; + + fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { + self.state.snapshot(ctx) + } +} + + +impl<'a, 'gcx> HashStable> for LocalValue<'gcx> { + fn hash_stable( + &self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher, + ) { + self.state.hash_stable(hcx, hasher); + } +} + impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>> {