Skip to content

Commit 22fe237

Browse files
committed
Encapsulate interpreter stack(s) a bit better
1 parent 6b8d9dd commit 22fe237

File tree

9 files changed

+186
-47
lines changed

9 files changed

+186
-47
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
1818

1919
use crate::interpret::{
2020
self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
21-
OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
21+
OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind,
2222
};
2323

2424
use super::error::*;
@@ -471,11 +471,40 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
471471
&ecx.machine.stack
472472
}
473473

474-
#[inline(always)]
475-
fn stack_mut<'a>(
474+
fn push_frame(
475+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
476+
frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
477+
) {
478+
ecx.machine.stack.push(frame);
479+
}
480+
481+
fn pop_frame(
482+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
483+
) -> Option<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
484+
ecx.machine.stack.pop()
485+
}
486+
487+
fn frame<'a>(
488+
ecx: &'a InterpCx<'mir, 'tcx, Self>,
489+
) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
490+
ecx.machine.stack.last().expect("no call frames exist")
491+
}
492+
493+
fn frame_mut<'a>(
476494
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
477-
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
478-
&mut ecx.machine.stack
495+
) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
496+
ecx.machine.stack.last_mut().expect("no call frames exist")
497+
}
498+
499+
fn access_local_mut<'a>(
500+
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
501+
frame: usize,
502+
local: mir::Local,
503+
) -> InterpResult<'tcx, &'a mut Operand<Self::Provenance>>
504+
where
505+
'tcx: 'mir,
506+
{
507+
ecx.machine.stack[frame].locals[local].access_mut()
479508
}
480509

481510
fn before_access_global(

compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -426,11 +426,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
426426
M::stack(self)
427427
}
428428

429-
#[inline(always)]
430-
pub(crate) fn stack_mut(
431-
&mut self,
432-
) -> &mut Vec<Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>> {
433-
M::stack_mut(self)
429+
pub(crate) fn push_frame(&mut self, frame: Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>) {
430+
M::push_frame(self, frame)
431+
}
432+
433+
pub(crate) fn pop_frame(&mut self) -> Option<Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>> {
434+
M::pop_frame(self)
434435
}
435436

436437
#[inline(always)]
@@ -442,12 +443,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
442443

443444
#[inline(always)]
444445
pub fn frame(&self) -> &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> {
445-
self.stack().last().expect("no call frames exist")
446+
M::frame(self)
446447
}
447448

448449
#[inline(always)]
449450
pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::Provenance, M::FrameExtra> {
450-
self.stack_mut().last_mut().expect("no call frames exist")
451+
M::frame_mut(self)
451452
}
452453

453454
#[inline(always)]
@@ -690,7 +691,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
690691
extra: (),
691692
};
692693
let frame = M::init_frame_extra(self, pre_frame)?;
693-
self.stack_mut().push(frame);
694+
self.push_frame(frame);
694695

695696
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
696697
for ct in &body.required_consts {
@@ -830,8 +831,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
830831

831832
// All right, now it is time to actually pop the frame.
832833
// Note that its locals are gone already, but that's fine.
833-
let frame =
834-
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
834+
let frame = self.pop_frame().expect("tried to pop a stack frame, but there were none");
835835
// Report error from return value copy, if any.
836836
copy_ret_result?;
837837

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,17 +222,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
222222
///
223223
/// Due to borrow checker trouble, we indicate the `frame` as an index rather than an `&mut
224224
/// Frame`.
225-
#[inline]
226225
fn access_local_mut<'a>(
227226
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
228227
frame: usize,
229228
local: mir::Local,
230229
) -> InterpResult<'tcx, &'a mut Operand<Self::Provenance>>
231230
where
232-
'tcx: 'mir,
233-
{
234-
ecx.stack_mut()[frame].locals[local].access_mut()
235-
}
231+
'tcx: 'mir;
236232

237233
/// Called before a basic block terminator is executed.
238234
/// You can use this to detect endlessly running programs.
@@ -394,10 +390,22 @@ pub trait Machine<'mir, 'tcx>: Sized {
394390
ecx: &'a InterpCx<'mir, 'tcx, Self>,
395391
) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>];
396392

397-
/// Mutably borrow the current thread's stack.
398-
fn stack_mut<'a>(
393+
fn push_frame(
394+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
395+
frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
396+
);
397+
398+
fn pop_frame(
399+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
400+
) -> Option<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>;
401+
402+
fn frame<'a>(
403+
ecx: &'a InterpCx<'mir, 'tcx, Self>,
404+
) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>;
405+
406+
fn frame_mut<'a>(
399407
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
400-
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>>;
408+
) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>;
401409

402410
/// Called immediately after a stack frame got pushed and its locals got initialized.
403411
fn after_stack_push(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {

compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
517517
};
518518
match res {
519519
Err(err) => {
520-
self.stack_mut().pop();
520+
self.pop_frame();
521521
Err(err)
522522
}
523523
Ok(()) => Ok(()),

compiler/rustc_mir_transform/src/const_prop.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,29 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
305305
&ecx.machine.stack
306306
}
307307

308-
#[inline(always)]
309-
fn stack_mut<'a>(
308+
fn push_frame(
309+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
310+
frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
311+
) {
312+
ecx.machine.stack.push(frame);
313+
}
314+
315+
fn pop_frame(
316+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
317+
) -> Option<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
318+
ecx.machine.stack.pop()
319+
}
320+
321+
fn frame<'a>(
322+
ecx: &'a InterpCx<'mir, 'tcx, Self>,
323+
) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
324+
ecx.machine.stack.last().expect("no call frames exist")
325+
}
326+
327+
fn frame_mut<'a>(
310328
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
311-
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
312-
&mut ecx.machine.stack
329+
) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
330+
ecx.machine.stack.last_mut().expect("no call frames exist")
313331
}
314332
}
315333

src/tools/miri/src/concurrency/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ pub mod init_once;
66
pub mod thread;
77
mod vector_clock;
88
pub mod weak_memory;
9+
mod stack;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use crate::*;
2+
3+
/// An encapsulated call stack, so encapsulated to enable efficient caching of metadata about the
4+
/// contained `Frame`.
5+
pub struct Stack<'mir, 'tcx> {
6+
frames: Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>>,
7+
}
8+
9+
impl<'mir, 'tcx> Stack<'mir, 'tcx> {
10+
pub fn new() -> Self {
11+
Stack { frames: Vec::new() }
12+
}
13+
14+
/// Does this `Stack` contain any `Frame`s?
15+
pub fn is_empty(&self) -> bool {
16+
self.frames.is_empty()
17+
}
18+
19+
/// Borrow the call frames of a `Stack`.
20+
pub fn frames(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
21+
&self.frames[..]
22+
}
23+
24+
/// Mutably borrow the call frames of a `Stack`.
25+
pub fn frames_mut(&mut self) -> &mut [Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
26+
&mut self.frames[..]
27+
}
28+
29+
/// Push a new `Frame` onto a `Stack`.
30+
pub fn push(&mut self, frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>) {
31+
self.frames.push(frame);
32+
}
33+
34+
/// Try to pop a `Frame` from a `Stack`.
35+
pub fn pop(&mut self) -> Option<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
36+
self.frames.pop()
37+
}
38+
}
39+
40+
impl VisitTags for Stack<'_, '_> {
41+
fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
42+
let Stack { frames } = self;
43+
for frame in frames {
44+
frame.visit_tags(visit);
45+
}
46+
}
47+
}

src/tools/miri/src/concurrency/thread.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_target::spec::abi::Abi;
1616

1717
use crate::concurrency::data_race;
1818
use crate::concurrency::sync::SynchronizationState;
19+
use crate::concurrency::stack::Stack;
1920
use crate::*;
2021

2122
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -116,7 +117,7 @@ pub struct Thread<'mir, 'tcx> {
116117
thread_name: Option<Vec<u8>>,
117118

118119
/// The virtual call stack.
119-
stack: Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>>,
120+
stack: Stack<'mir, 'tcx>,
120121

121122
/// The join status.
122123
join_status: ThreadJoinStatus,
@@ -166,7 +167,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> {
166167
Self {
167168
state: ThreadState::Enabled,
168169
thread_name: None,
169-
stack: Vec::new(),
170+
stack: Stack::new(),
170171
join_status: ThreadJoinStatus::Joinable,
171172
panic_payload: None,
172173
last_error: None,
@@ -189,9 +190,7 @@ impl VisitTags for Thread<'_, '_> {
189190

190191
panic_payload.visit_tags(visit);
191192
last_error.visit_tags(visit);
192-
for frame in stack {
193-
frame.visit_tags(visit)
194-
}
193+
stack.visit_tags(visit);
195194
}
196195
}
197196

@@ -345,20 +344,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
345344

346345
/// Borrow the stack of the active thread.
347346
pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
348-
&self.threads[self.active_thread].stack
347+
self.threads[self.active_thread].stack.frames()
349348
}
350349

351350
/// Mutably borrow the stack of the active thread.
352-
fn active_thread_stack_mut(
353-
&mut self,
354-
) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
355-
&mut self.threads[self.active_thread].stack
351+
pub fn active_thread_stack_mut(&mut self) -> &mut [Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
352+
self.threads[self.active_thread].stack.frames_mut()
356353
}
357354

358355
pub fn all_stacks(
359356
&self,
360357
) -> impl Iterator<Item = &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>]> {
361-
self.threads.iter().map(|t| &t.stack[..])
358+
self.threads.iter().map(|t| t.stack.frames())
362359
}
363360

364361
/// Create a new thread and returns its id.
@@ -561,10 +558,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
561558
// this allows us to have a deterministic scheduler.
562559
for thread in self.threads.indices() {
563560
match self.timeout_callbacks.entry(thread) {
564-
Entry::Occupied(entry) =>
561+
Entry::Occupied(entry) => {
565562
if entry.get().call_time.get_wait_time(clock) == Duration::new(0, 0) {
566563
return Some((thread, entry.remove().callback));
567-
},
564+
}
565+
}
568566
Entry::Vacant(_) => {}
569567
}
570568
}
@@ -863,13 +861,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
863861
}
864862

865863
#[inline]
866-
fn active_thread_stack_mut(
867-
&mut self,
868-
) -> &mut Vec<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
864+
fn active_thread_stack_mut(&mut self) -> &mut [Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] {
869865
let this = self.eval_context_mut();
870866
this.machine.threads.active_thread_stack_mut()
871867
}
872868

869+
fn push_frame(&mut self, frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>) {
870+
let this = self.eval_context_mut();
871+
this.machine.threads.active_thread_mut().stack.push(frame);
872+
}
873+
874+
fn pop_frame(&mut self) -> Option<Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> {
875+
let this = self.eval_context_mut();
876+
this.machine.threads.active_thread_mut().stack.pop()
877+
}
878+
873879
/// Set the name of the current thread. The buffer must not include the null terminator.
874880
#[inline]
875881
fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec<u8>) {

src/tools/miri/src/machine.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,10 +1138,40 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
11381138
ecx.active_thread_stack()
11391139
}
11401140

1141-
fn stack_mut<'a>(
1141+
fn push_frame(
1142+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
1143+
frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
1144+
) {
1145+
ecx.push_frame(frame);
1146+
}
1147+
1148+
fn pop_frame(
1149+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
1150+
) -> Option<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
1151+
ecx.pop_frame()
1152+
}
1153+
1154+
fn frame<'a>(
1155+
ecx: &'a InterpCx<'mir, 'tcx, Self>,
1156+
) -> &'a Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
1157+
ecx.active_thread_stack().last().expect("no call frames exist")
1158+
}
1159+
1160+
fn frame_mut<'a>(
1161+
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
1162+
) -> &'a mut Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra> {
1163+
ecx.active_thread_stack_mut().last_mut().expect("no call frames exist")
1164+
}
1165+
1166+
fn access_local_mut<'a>(
11421167
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
1143-
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
1144-
ecx.active_thread_stack_mut()
1168+
frame: usize,
1169+
local: mir::Local,
1170+
) -> InterpResult<'tcx, &'a mut Operand<Self::Provenance>>
1171+
where
1172+
'tcx: 'mir,
1173+
{
1174+
ecx.active_thread_stack_mut()[frame].locals[local].access_mut()
11451175
}
11461176

11471177
fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {

0 commit comments

Comments
 (0)