]> git.lizzy.rs Git - rust.git/commitdiff
machine hooks for stack push and pop, frame machine data
authorRalf Jung <post@ralfj.de>
Thu, 15 Nov 2018 16:14:53 +0000 (17:14 +0100)
committerRalf Jung <post@ralfj.de>
Sun, 25 Nov 2018 09:49:43 +0000 (10:49 +0100)
src/librustc_mir/const_eval.rs
src/librustc_mir/interpret/eval_context.rs
src/librustc_mir/interpret/machine.rs
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/snapshot.rs

index 30c06ba5659f4eb924931985fdb7090042e81c75..291b5c170ef365c328f82240f0e8cada7696a45e 100644 (file)
@@ -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<AllocId, (MemoryKind<!>, Allocation)>;
 
@@ -490,6 +493,22 @@ fn tag_new_allocation(
     ) -> 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
index 2eb5f7c853f8c97447332f6836e928734387f001..d36d530fe78b24ecdaeeddfe23c626373545e3ec 100644 (file)
@@ -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<Frame<'mir, 'tcx, M::PointerTag>>,
+    pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
 
     /// 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 @@ pub fn memory_mut(&mut self) -> &mut Memory<'a, 'mir, 'tcx, M> {
     }
 
     #[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 @@ pub fn cur_frame(&self) -> usize {
     }
 
     #[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 @@ pub fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
 
     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 @@ pub fn push_stack_frame(
         ::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 @@ pub fn push_stack_frame(
             span,
             instance,
             stmt: 0,
+            extra,
         });
 
         // don't allocate at all for trivial constants
@@ -504,6 +509,7 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
         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 {
index bf260c86742321d234423c44922d0b6632ddaf89..2c78807df452fd972d94b048b2b739e9fb137507 100644 (file)
@@ -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 @@ fn escape_to_raw(
     ) -> 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>;
 }
index 539bc6d965fd6bbf1b6196f03a217eadd78ab597..83ceadada65ce68f0e1a62c47a064e6f65a47aee 100644 (file)
@@ -471,7 +471,7 @@ pub fn operand_projection(
     /// 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<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
index 4b63335ad964cba9480d1de819e583631ffa35bb..f9ce7b4319fac9d30231f07f0a93e41ddf6d0930 100644 (file)
@@ -323,6 +323,7 @@ struct FrameSnapshot<'a, 'tcx: 'a> {
     locals,
     block,
     stmt,
+    extra,
 });
 
 impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
@@ -340,6 +341,7 @@ fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
             locals,
             block,
             stmt,
+            extra: _,
         } = self;
 
         FrameSnapshot {