Skip to content

Commit c53210c

Browse files
author
Vytautas Astrauskas
committed
Make the necessary changes to support concurrency in Miri.
1 parent df768c5 commit c53210c

18 files changed

+135
-57
lines changed

src/librustc_mir/const_eval/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Error for ConstEvalErrKind {}
5050
/// Turn an interpreter error into something to report to the user.
5151
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
5252
/// Should be called only if the error is actually going to to be reported!
53-
pub fn error_to_const_error<'mir, 'tcx, M: Machine<'mir, 'tcx>>(
53+
pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>(
5454
ecx: &InterpCx<'mir, 'tcx, M>,
5555
mut error: InterpErrorInfo<'tcx>,
5656
) -> ConstEvalErr<'tcx> {

src/librustc_mir/const_eval/machine.rs

+24-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::interpret::{
1919

2020
use super::error::*;
2121

22-
impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> {
22+
impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
2323
/// Evaluate a const function where all arguments (if any) are zero-sized types.
2424
/// The evaluation is memoized thanks to the query system.
2525
///
@@ -86,12 +86,15 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter> {
8686
}
8787

8888
/// Extra machine state for CTFE, and the Machine instance
89-
pub struct CompileTimeInterpreter {
89+
pub struct CompileTimeInterpreter<'mir, 'tcx> {
9090
/// For now, the number of terminators that can be evaluated before we throw a resource
9191
/// exhuastion error.
9292
///
9393
/// Setting this to `0` disables the limit and allows the interpreter to run forever.
9494
pub steps_remaining: usize,
95+
96+
/// The virtual call stack.
97+
pub(crate) stack: Vec<Frame<'mir, 'tcx, (), ()>>,
9598
}
9699

97100
#[derive(Copy, Clone, Debug)]
@@ -100,9 +103,9 @@ pub struct MemoryExtra {
100103
pub(super) can_access_statics: bool,
101104
}
102105

103-
impl CompileTimeInterpreter {
106+
impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
104107
pub(super) fn new(const_eval_limit: usize) -> Self {
105-
CompileTimeInterpreter { steps_remaining: const_eval_limit }
108+
CompileTimeInterpreter { steps_remaining: const_eval_limit, stack: Vec::new() }
106109
}
107110
}
108111

@@ -156,7 +159,8 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
156159
}
157160
}
158161

159-
crate type CompileTimeEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, CompileTimeInterpreter>;
162+
crate type CompileTimeEvalContext<'mir, 'tcx> =
163+
InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>;
160164

161165
impl interpret::MayLeak for ! {
162166
#[inline(always)]
@@ -166,7 +170,7 @@ impl interpret::MayLeak for ! {
166170
}
167171
}
168172

169-
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter {
173+
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
170174
type MemoryKind = !;
171175
type PointerTag = ();
172176
type ExtraFnVal = !;
@@ -186,6 +190,20 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter {
186190
false
187191
}
188192

193+
#[inline(always)]
194+
fn stack(
195+
ecx: &'a InterpCx<'mir, 'tcx, Self>,
196+
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
197+
&ecx.machine.stack
198+
}
199+
200+
#[inline(always)]
201+
fn stack_mut(
202+
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
203+
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
204+
&mut ecx.machine.stack
205+
}
206+
189207
#[inline(always)]
190208
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
191209
false // for now, we don't enforce validity

src/librustc_mir/interpret/cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
1212
use rustc_span::symbol::sym;
1313
use rustc_target::abi::{LayoutOf, Size, Variants};
1414

15-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
15+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1616
pub fn cast(
1717
&mut self,
1818
src: OpTy<'tcx, M::PointerTag>,

src/librustc_mir/interpret/eval_context.rs

+20-17
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
3939
/// The virtual memory system.
4040
pub memory: Memory<'mir, 'tcx, M>,
4141

42-
/// The virtual call stack.
43-
pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
44-
4542
/// A cache for deduplicating vtables
4643
pub(super) vtables:
4744
FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Pointer<M::PointerTag>>,
@@ -295,7 +292,7 @@ pub(super) fn from_known_layout<'tcx>(
295292
}
296293
}
297294

298-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
295+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
299296
pub fn new(
300297
tcx: TyCtxtAt<'tcx>,
301298
param_env: ty::ParamEnv<'tcx>,
@@ -307,7 +304,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
307304
tcx,
308305
param_env,
309306
memory: Memory::new(tcx, memory_extra),
310-
stack: Vec::new(),
311307
vtables: FxHashMap::default(),
312308
}
313309
}
@@ -348,23 +344,29 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
348344

349345
#[inline(always)]
350346
pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
351-
&self.stack
347+
M::stack(self)
348+
}
349+
350+
#[inline(always)]
351+
pub fn stack_mut(&mut self) -> &mut Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>> {
352+
M::stack_mut(self)
352353
}
353354

354355
#[inline(always)]
355356
pub fn cur_frame(&self) -> usize {
356-
assert!(!self.stack.is_empty());
357-
self.stack.len() - 1
357+
let stack = self.stack();
358+
assert!(!stack.is_empty());
359+
stack.len() - 1
358360
}
359361

360362
#[inline(always)]
361363
pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
362-
self.stack.last().expect("no call frames exist")
364+
self.stack().last().expect("no call frames exist")
363365
}
364366

365367
#[inline(always)]
366368
pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
367-
self.stack.last_mut().expect("no call frames exist")
369+
self.stack_mut().last_mut().expect("no call frames exist")
368370
}
369371

370372
#[inline(always)]
@@ -595,7 +597,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
595597
return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
596598
return_to_block: StackPopCleanup,
597599
) -> InterpResult<'tcx> {
598-
if !self.stack.is_empty() {
600+
if !self.stack().is_empty() {
599601
info!("PAUSING({}) {}", self.cur_frame(), self.frame().instance);
600602
}
601603
::log_settings::settings().indentation += 1;
@@ -614,7 +616,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
614616
extra: (),
615617
};
616618
let frame = M::init_frame_extra(self, pre_frame)?;
617-
self.stack.push(frame);
619+
self.stack_mut().push(frame);
618620

619621
// don't allocate at all for trivial constants
620622
if body.local_decls.len() > 1 {
@@ -649,7 +651,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
649651
M::after_stack_push(self)?;
650652
info!("ENTERING({}) {}", self.cur_frame(), self.frame().instance);
651653

652-
if self.stack.len() > *self.tcx.sess.recursion_limit.get() {
654+
if self.stack().len() > *self.tcx.sess.recursion_limit.get() {
653655
throw_exhaust!(StackFrameLimitReached)
654656
} else {
655657
Ok(())
@@ -719,7 +721,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
719721
);
720722

721723
::log_settings::settings().indentation -= 1;
722-
let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
724+
let frame =
725+
self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
723726

724727
// Now where do we jump next?
725728

@@ -734,7 +737,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
734737
};
735738

736739
if !cleanup {
737-
assert!(self.stack.is_empty(), "only the topmost frame should ever be leaked");
740+
assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
738741
assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
739742
assert!(!unwinding, "tried to skip cleanup during unwinding");
740743
// Leak the locals, skip validation, skip machine hook.
@@ -783,7 +786,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
783786
}
784787
}
785788

786-
if !self.stack.is_empty() {
789+
if !self.stack().is_empty() {
787790
info!(
788791
"CONTINUING({}) {} (unwinding = {})",
789792
self.cur_frame(),
@@ -899,7 +902,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
899902
}
900903
write!(msg, ":").unwrap();
901904

902-
match self.stack[frame].locals[local].value {
905+
match self.stack()[frame].locals[local].value {
903906
LocalValue::Dead => write!(msg, " is dead").unwrap(),
904907
LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(),
905908
LocalValue::Live(Operand::Indirect(mplace)) => match mplace.ptr {

src/librustc_mir/interpret/intern.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> InternVisitor<'rt, 'mir
148148
}
149149
}
150150

151-
impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
151+
impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
152152
for InternVisitor<'rt, 'mir, 'tcx, M>
153153
{
154154
type V = MPlaceTy<'tcx>;
@@ -284,7 +284,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
284284
intern_kind: InternKind,
285285
ret: MPlaceTy<'tcx>,
286286
ignore_interior_mut_in_const_validation: bool,
287-
) -> InterpResult<'tcx> {
287+
) -> InterpResult<'tcx>
288+
where
289+
'tcx: 'mir,
290+
{
288291
let tcx = ecx.tcx;
289292
let (base_mutability, base_intern_mode) = match intern_kind {
290293
// `static mut` doesn't care about interior mutability, it's mutable anyway

src/librustc_mir/interpret/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ crate fn eval_nullary_intrinsic<'tcx>(
7373
})
7474
}
7575

76-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
76+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7777
/// Returns `true` if emulation happened.
7878
pub fn emulate_intrinsic(
7979
&mut self,

src/librustc_mir/interpret/intrinsics/caller_location.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ use crate::interpret::{
1010
MPlaceTy, MemoryKind, Scalar,
1111
};
1212

13-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
13+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1414
/// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
1515
/// frame which is not `#[track_caller]`.
1616
crate fn find_closest_untracked_caller_location(&self) -> Span {
17-
self.stack
17+
self.stack()
1818
.iter()
1919
.rev()
2020
// Find first non-`#[track_caller]` frame.

src/librustc_mir/interpret/machine.rs

+24
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,16 @@ pub trait Machine<'mir, 'tcx>: Sized {
120120
/// Whether memory accesses should be alignment-checked.
121121
fn enforce_alignment(memory_extra: &Self::MemoryExtra) -> bool;
122122

123+
/// Borrow the current thread's stack.
124+
fn stack(
125+
ecx: &'a InterpCx<'mir, 'tcx, Self>,
126+
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>];
127+
128+
/// Mutably borrow the current thread's stack.
129+
fn stack_mut(
130+
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
131+
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>>;
132+
123133
/// Whether to enforce the validity invariant
124134
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
125135

@@ -230,6 +240,20 @@ pub trait Machine<'mir, 'tcx>: Sized {
230240
id
231241
}
232242

243+
/// In Rust, thread locals are just special statics. Therefore, the compiler
244+
/// uses the same code for allocating both. However, in Miri we want to have
245+
/// a property that each allocation has a unique id and, therefore, we
246+
/// generate a fresh allocation id for each thread. This function takes a
247+
/// potentially thread local allocation id and resolves the original static
248+
/// allocation id that can be used to compute the value of the static.
249+
#[inline]
250+
fn resolve_thread_local_allocation_id(
251+
_memory_extra: &Self::MemoryExtra,
252+
id: AllocId,
253+
) -> AllocId {
254+
id
255+
}
256+
233257
/// Called to initialize the "extra" state of an allocation and make the pointers
234258
/// it contains (in relocations) tagged. The way we construct allocations is
235259
/// to always first construct it without extra and then add the extra.

src/librustc_mir/interpret/memory.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
429429
id: AllocId,
430430
is_write: bool,
431431
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
432-
let alloc = tcx.alloc_map.lock().get(id);
432+
let alloc =
433+
tcx.alloc_map.lock().get(M::resolve_thread_local_allocation_id(memory_extra, id));
433434
let (alloc, def_id) = match alloc {
434435
Some(GlobalAlloc::Memory(mem)) => {
435436
// Memory of a constant or promoted or anonymous memory referenced by a static.
@@ -592,7 +593,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
592593
// # Statics
593594
// Can't do this in the match argument, we may get cycle errors since the lock would
594595
// be held throughout the match.
595-
let alloc = self.tcx.alloc_map.lock().get(id);
596+
let alloc =
597+
self.tcx.alloc_map.lock().get(M::resolve_thread_local_allocation_id(&self.extra, id));
596598
match alloc {
597599
Some(GlobalAlloc::Static(did)) => {
598600
// Use size and align of the type.

src/librustc_mir/interpret/operand.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag> {
208208
}
209209
}
210210

211-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
211+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
212212
/// Normalice `place.ptr` to a `Pointer` if this is a place and not a ZST.
213213
/// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
214214
#[inline]
@@ -439,7 +439,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
439439
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
440440
let op = match *place {
441441
Place::Ptr(mplace) => Operand::Indirect(mplace),
442-
Place::Local { frame, local } => *self.access_local(&self.stack[frame], local, None)?,
442+
Place::Local { frame, local } => {
443+
*self.access_local(&self.stack()[frame], local, None)?
444+
}
443445
};
444446
Ok(OpTy { op, layout: place.layout })
445447
}

src/librustc_mir/interpret/operator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_target::abi::LayoutOf;
99

1010
use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
1111

12-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
12+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1313
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
1414
/// and a boolean signifying the potential overflow to the destination.
1515
pub fn binop_with_overflow(
@@ -45,7 +45,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4545
}
4646
}
4747

48-
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
48+
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4949
fn binary_char_op(
5050
&self,
5151
bin_op: mir::BinOp,

0 commit comments

Comments
 (0)