machine hooks for stack push and pop, frame machine data

This commit is contained in:
Ralf Jung 2018-11-15 17:14:53 +01:00
parent 53ed3b7956
commit 261faf3ce2
5 changed files with 49 additions and 8 deletions

View 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 @@ 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

View 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 @@ 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 {

View 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 @@ 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>;
}

View file

@ -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<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {

View file

@ -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 {