diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 35d58d2f638bf..f0365fb0e754f 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -18,7 +18,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
use crate::interpret::{
self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
- OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
+ OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind,
};
use super::error::*;
@@ -471,11 +471,40 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
&ecx.machine.stack
}
- #[inline(always)]
- fn stack_mut<'a>(
+ fn push_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
+ ) {
+ ecx.machine.stack.push(frame);
+ }
+
+ fn pop_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ ) -> Option> {
+ ecx.machine.stack.pop()
+ }
+
+ fn frame<'a>(
+ ecx: &'a InterpCx<'mir, 'tcx, Self>,
+ ) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
+ ecx.machine.stack.last().expect("no call frames exist")
+ }
+
+ fn frame_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
- ) -> &'a mut Vec> {
- &mut ecx.machine.stack
+ ) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
+ ecx.machine.stack.last_mut().expect("no call frames exist")
+ }
+
+ fn access_local_mut<'a>(
+ ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+ frame: usize,
+ local: mir::Local,
+ ) -> InterpResult<'tcx, &'a mut Operand>
+ where
+ 'tcx: 'mir,
+ {
+ ecx.machine.stack[frame].locals[local].access_mut()
}
fn before_access_global(
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index f7d64f6d4f48a..170ac59936189 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -426,11 +426,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
M::stack(self)
}
- #[inline(always)]
- pub(crate) fn stack_mut(
- &mut self,
- ) -> &mut Vec> {
- M::stack_mut(self)
+ pub(crate) fn push_frame(&mut self, frame: Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>) {
+ M::push_frame(self, frame)
+ }
+
+ pub(crate) fn pop_frame(&mut self) -> Option> {
+ M::pop_frame(self)
}
#[inline(always)]
@@ -442,12 +443,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
#[inline(always)]
pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> {
- self.stack().last().expect("no call frames exist")
+ M::frame(self)
}
#[inline(always)]
pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> {
- self.stack_mut().last_mut().expect("no call frames exist")
+ M::frame_mut(self)
}
#[inline(always)]
@@ -690,7 +691,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
extra: (),
};
let frame = M::init_frame_extra(self, pre_frame)?;
- self.stack_mut().push(frame);
+ self.push_frame(frame);
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
for ct in &body.required_consts {
@@ -830,8 +831,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// All right, now it is time to actually pop the frame.
// Note that its locals are gone already, but that's fine.
- let frame =
- self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
+ let frame = self.pop_frame().expect("tried to pop a stack frame, but there were none");
// Report error from return value copy, if any.
copy_ret_result?;
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 351152eba01f6..2f3dba30ac6f9 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -222,17 +222,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
///
/// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut
/// Frame`.
- #[inline]
fn access_local_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
frame: usize,
local: mir::Local,
) -> InterpResult<'tcx, &'a mut Operand>
where
- 'tcx: 'mir,
- {
- ecx.stack_mut()[frame].locals[local].access_mut()
- }
+ 'tcx: 'mir;
/// Called before a basic block terminator is executed.
/// You can use this to detect endlessly running programs.
@@ -394,10 +390,22 @@ pub trait Machine<'mir, 'tcx>: Sized {
ecx: &'a InterpCx<'mir, 'tcx, Self>,
) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>];
- /// Mutably borrow the current thread's stack.
- fn stack_mut<'a>(
+ fn push_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
+ );
+
+ fn pop_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ ) -> Option>;
+
+ fn frame<'a>(
+ ecx: &'a InterpCx<'mir, 'tcx, Self>,
+ ) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>;
+
+ fn frame_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
- ) -> &'a mut Vec>;
+ ) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>;
/// Called immediately after a stack frame got pushed and its locals got initialized.
fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 57e40e168fa48..28b2d7106cc2e 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -517,7 +517,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
match res {
Err(err) => {
- self.stack_mut().pop();
+ self.pop_frame();
Err(err)
}
Ok(()) => Ok(()),
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 4e4515888454b..2507d54b8ee28 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -305,11 +305,29 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
&ecx.machine.stack
}
- #[inline(always)]
- fn stack_mut<'a>(
+ fn push_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
+ ) {
+ ecx.machine.stack.push(frame);
+ }
+
+ fn pop_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ ) -> Option> {
+ ecx.machine.stack.pop()
+ }
+
+ fn frame<'a>(
+ ecx: &'a InterpCx<'mir, 'tcx, Self>,
+ ) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
+ ecx.machine.stack.last().expect("no call frames exist")
+ }
+
+ fn frame_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
- ) -> &'a mut Vec> {
- &mut ecx.machine.stack
+ ) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
+ ecx.machine.stack.last_mut().expect("no call frames exist")
}
}
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index 45903107f1710..eb599e8c426e9 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -6,3 +6,4 @@ pub mod init_once;
pub mod thread;
mod vector_clock;
pub mod weak_memory;
+mod stack;
diff --git a/src/tools/miri/src/concurrency/stack.rs b/src/tools/miri/src/concurrency/stack.rs
new file mode 100644
index 0000000000000..01636b8c2d171
--- /dev/null
+++ b/src/tools/miri/src/concurrency/stack.rs
@@ -0,0 +1,47 @@
+use crate::*;
+
+/// An encapsulated call stack, so encapsulated to enable efficient caching of metadata about the
+/// contained `Frame`.
+pub struct Stack<'mir, 'tcx> {
+ frames: Vec>>,
+}
+
+impl<'mir, 'tcx> Stack<'mir, 'tcx> {
+ pub fn new() -> Self {
+ Stack { frames: Vec::new() }
+ }
+
+ /// Does this `Stack` contain any `Frame`s?
+ pub fn is_empty(&self) -> bool {
+ self.frames.is_empty()
+ }
+
+ /// Borrow the call frames of a `Stack`.
+ pub fn frames(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
+ &self.frames[..]
+ }
+
+ /// Mutably borrow the call frames of a `Stack`.
+ pub fn frames_mut(&mut self) -> &mut [Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
+ &mut self.frames[..]
+ }
+
+ /// Push a new `Frame` onto a `Stack`.
+ pub fn push(&mut self, frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>) {
+ self.frames.push(frame);
+ }
+
+ /// Try to pop a `Frame` from a `Stack`.
+ pub fn pop(&mut self) -> Option>> {
+ self.frames.pop()
+ }
+}
+
+impl VisitTags for Stack<'_, '_> {
+ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+ let Stack { frames } = self;
+ for frame in frames {
+ frame.visit_tags(visit);
+ }
+ }
+}
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index ac5dcbf0f4f2f..27ca5560c7ee4 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -16,6 +16,7 @@ use rustc_target::spec::abi::Abi;
use crate::concurrency::data_race;
use crate::concurrency::sync::SynchronizationState;
+use crate::concurrency::stack::Stack;
use crate::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -116,7 +117,7 @@ pub struct Thread<'mir, 'tcx> {
thread_name: Option>,
/// The virtual call stack.
- stack: Vec>>,
+ stack: Stack<'mir, 'tcx>,
/// The join status.
join_status: ThreadJoinStatus,
@@ -166,7 +167,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
Self {
state: ThreadState::Enabled,
thread_name: None,
- stack: Vec::new(),
+ stack: Stack::new(),
join_status: ThreadJoinStatus::Joinable,
panic_payload: None,
last_error: None,
@@ -189,9 +190,7 @@ impl VisitTags for Thread<'_, '_> {
panic_payload.visit_tags(visit);
last_error.visit_tags(visit);
- for frame in stack {
- frame.visit_tags(visit)
- }
+ stack.visit_tags(visit);
}
}
@@ -345,20 +344,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
/// Borrow the stack of the active thread.
pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
- &self.threads[self.active_thread].stack
+ self.threads[self.active_thread].stack.frames()
}
/// Mutably borrow the stack of the active thread.
- fn active_thread_stack_mut(
- &mut self,
- ) -> &mut Vec>> {
- &mut self.threads[self.active_thread].stack
+ pub fn active_thread_stack_mut(&mut self) -> &mut [Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
+ self.threads[self.active_thread].stack.frames_mut()
}
pub fn all_stacks(
&self,
) -> impl Iterator- >]> {
- self.threads.iter().map(|t| &t.stack[..])
+ self.threads.iter().map(|t| t.stack.frames())
}
/// Create a new thread and returns its id.
@@ -561,10 +558,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
// this allows us to have a deterministic scheduler.
for thread in self.threads.indices() {
match self.timeout_callbacks.entry(thread) {
- Entry::Occupied(entry) =>
+ Entry::Occupied(entry) => {
if entry.get().call_time.get_wait_time(clock) == Duration::new(0, 0) {
return Some((thread, entry.remove().callback));
- },
+ }
+ }
Entry::Vacant(_) => {}
}
}
@@ -863,13 +861,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
#[inline]
- fn active_thread_stack_mut(
- &mut self,
- ) -> &mut Vec>> {
+ fn active_thread_stack_mut(&mut self) -> &mut [Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
let this = self.eval_context_mut();
this.machine.threads.active_thread_stack_mut()
}
+ fn push_frame(&mut self, frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>) {
+ let this = self.eval_context_mut();
+ this.machine.threads.active_thread_mut().stack.push(frame);
+ }
+
+ fn pop_frame(&mut self) -> Option>> {
+ let this = self.eval_context_mut();
+ this.machine.threads.active_thread_mut().stack.pop()
+ }
+
/// Set the name of the current thread. The buffer must not include the null terminator.
#[inline]
fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) {
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 231a99c1d034e..68ace289837cc 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1138,10 +1138,40 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
ecx.active_thread_stack()
}
- fn stack_mut<'a>(
+ fn push_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
+ ) {
+ ecx.push_frame(frame);
+ }
+
+ fn pop_frame(
+ ecx: &mut InterpCx<'mir, 'tcx, Self>,
+ ) -> Option> {
+ ecx.pop_frame()
+ }
+
+ fn frame<'a>(
+ ecx: &'a InterpCx<'mir, 'tcx, Self>,
+ ) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
+ ecx.active_thread_stack().last().expect("no call frames exist")
+ }
+
+ fn frame_mut<'a>(
+ ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+ ) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
+ ecx.active_thread_stack_mut().last_mut().expect("no call frames exist")
+ }
+
+ fn access_local_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
- ) -> &'a mut Vec> {
- ecx.active_thread_stack_mut()
+ frame: usize,
+ local: mir::Local,
+ ) -> InterpResult<'tcx, &'a mut Operand>
+ where
+ 'tcx: 'mir,
+ {
+ ecx.active_thread_stack_mut()[frame].locals[local].access_mut()
}
fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {