return_place: None,
return_to_block: StackPopCleanup::Goto(None), // never pop
stmt: 0,
+ extra: (),
});
Ok(ecx)
}
for CompileTimeInterpreter<'a, 'mir, 'tcx>
{
type MemoryKinds = !;
+ type PointerTag = ();
+
+ type FrameExtra = ();
type MemoryExtra = ();
type AllocExtra = ();
- type PointerTag = ();
type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, 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
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>,
/// A stack frame.
#[derive(Clone)]
-pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
+pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
////////////////////////////////////////////////////////////////////////////////
// Function and callsite information
////////////////////////////////////////////////////////////////////////////////
/// The index of the currently evaluated statement.
pub stmt: usize,
+
+ /// Extra data for the machine
+ pub extra: Extra,
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
}
#[inline(always)]
- pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag>] {
+ pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
&self.stack
}
}
#[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")
}
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;
::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,
span,
instance,
stmt: 0,
+ extra,
});
// don't allocate at all for trivial constants
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 {
/// 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.
) -> 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>;
}