From 261faf3ce22ce930d48ecbbf872d46a613b1f0ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 17:14:53 +0100 Subject: [PATCH] machine hooks for stack push and pop, frame machine data --- src/librustc_mir/const_eval.rs | 21 ++++++++++++++++++++- src/librustc_mir/interpret/eval_context.rs | 18 ++++++++++++------ src/librustc_mir/interpret/machine.rs | 14 ++++++++++++++ src/librustc_mir/interpret/operand.rs | 2 +- src/librustc_mir/interpret/snapshot.rs | 2 ++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 30c06ba5659f..291b5c170ef3 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -65,6 +65,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( return_place: None, return_to_block: StackPopCleanup::Goto(None), // never pop stmt: 0, + extra: (), }); Ok(ecx) } @@ -353,9 +354,11 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> for CompileTimeInterpreter<'a, 'mir, 'tcx> { type MemoryKinds = !; + type PointerTag = (); + + type FrameExtra = (); type MemoryExtra = (); type AllocExtra = (); - type PointerTag = (); type MemoryMap = FxHashMap, Allocation)>; @@ -490,6 +493,22 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> ) -> EvalResult<'tcx, Pointer> { Ok(ptr) } + + #[inline(always)] + fn stack_push( + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ) -> EvalResult<'tcx> { + Ok(()) + } + + /// Called immediately before a stack frame gets popped + #[inline(always)] + fn stack_pop( + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _extra: (), + ) -> EvalResult<'tcx> { + Ok(()) + } } /// Project to a field of a (variant of a) const diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 2eb5f7c853f8..d36d530fe78b 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -49,7 +49,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { pub(crate) memory: Memory<'a, 'mir, 'tcx, M>, /// The virtual call stack. - pub(crate) stack: Vec>, + pub(crate) stack: Vec>, /// A cache for deduplicating vtables pub(super) vtables: FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), AllocId>, @@ -57,7 +57,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> { /// A stack frame. #[derive(Clone)] -pub struct Frame<'mir, 'tcx: 'mir, Tag=()> { +pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> { //////////////////////////////////////////////////////////////////////////////// // Function and callsite information //////////////////////////////////////////////////////////////////////////////// @@ -96,6 +96,9 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=()> { /// The index of the currently evaluated statement. pub stmt: usize, + + /// Extra data for the machine + pub extra: Extra, } #[derive(Clone, Debug, Eq, PartialEq, Hash)] @@ -196,7 +199,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } #[inline(always)] - pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag>] { + pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] { &self.stack } @@ -207,12 +210,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc } #[inline(always)] - pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag> { + pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { self.stack.last().expect("no call frames exist") } #[inline(always)] - pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag> { + pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> { self.stack.last_mut().expect("no call frames exist") } @@ -294,7 +297,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc pub fn layout_of_local( &self, - frame: &Frame<'mir, 'tcx, M::PointerTag>, + frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local ) -> EvalResult<'tcx, TyLayout<'tcx>> { let local_ty = frame.mir.local_decls[local].ty; @@ -424,6 +427,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc ::log_settings::settings().indentation += 1; // first push a stack frame so we have access to the local substs + let extra = M::stack_push(self)?; self.stack.push(Frame { mir, block: mir::START_BLOCK, @@ -435,6 +439,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc span, instance, stmt: 0, + extra, }); // don't allocate at all for trivial constants @@ -504,6 +509,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc let frame = self.stack.pop().expect( "tried to pop a stack frame, but there were none", ); + M::stack_pop(self, frame.extra)?; // Abort early if we do not want to clean up: We also avoid validation in that case, // because this is CTFE and the final value will be thoroughly validated anyway. match frame.return_to_block { diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index bf260c867423..2c78807df452 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -77,6 +77,9 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { /// The `default()` is used for pointers to consts, statics, vtables and functions. type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static; + /// Extra data stored in every call frame. + type FrameExtra; + /// Extra data stored in memory. A reference to this is available when `AllocExtra` /// gets initialized, so you can e.g. have an `Rc` here if there is global state you /// need access to in the `AllocExtra` hooks. @@ -213,4 +216,15 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized { ) -> EvalResult<'tcx> { Ok(()) } + + /// Called immediately before a new stack frame got pushed + fn stack_push( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ) -> EvalResult<'tcx, Self::FrameExtra>; + + /// Called immediately after a stack frame gets popped + fn stack_pop( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + extra: Self::FrameExtra, + ) -> EvalResult<'tcx>; } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 539bc6d965fd..83ceadada65c 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -471,7 +471,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> /// When you know the layout of the local in advance, you can pass it as last argument pub fn access_local( &self, - frame: &super::Frame<'mir, 'tcx, M::PointerTag>, + frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 4b63335ad964..f9ce7b4319fa 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -323,6 +323,7 @@ impl_stable_hash_for!(impl<'tcx, 'mir: 'tcx> for struct Frame<'mir, 'tcx> { locals, block, stmt, + extra, }); impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> @@ -340,6 +341,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx> locals, block, stmt, + extra: _, } = self; FrameSnapshot {