Skip to content

Commit 691a7f8

Browse files
committed
Auto merge of #56094 - RalfJung:memory-data-revived, r=oli-obk
miri: Memory data revived, Hooks for stack frame push/pop r? @oli-obk
2 parents 45205f2 + 349271a commit 691a7f8

File tree

10 files changed

+258
-135
lines changed

10 files changed

+258
-135
lines changed

src/librustc/mir/interpret/allocation.rs

+151-99
Large diffs are not rendered by default.

src/librustc/ty/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1055,7 +1055,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
10551055
/// Allocates a byte or string literal for `mir::interpret`, read-only
10561056
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
10571057
// create an allocation that just contains these bytes
1058-
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
1058+
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes, ());
10591059
let alloc = self.intern_const_alloc(alloc);
10601060
self.alloc_map.lock().allocate(alloc)
10611061
}

src/librustc_mir/const_eval.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
6565
return_place: None,
6666
return_to_block: StackPopCleanup::Goto(None), // never pop
6767
stmt: 0,
68+
extra: (),
6869
});
6970
Ok(ecx)
7071
}
@@ -353,9 +354,12 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
353354
for CompileTimeInterpreter<'a, 'mir, 'tcx>
354355
{
355356
type MemoryKinds = !;
356-
type AllocExtra = ();
357357
type PointerTag = ();
358358

359+
type FrameExtra = ();
360+
type MemoryExtra = ();
361+
type AllocExtra = ();
362+
359363
type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation)>;
360364

361365
const STATIC_KIND: Option<!> = None; // no copying of statics allowed
@@ -432,16 +436,18 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
432436
}
433437

434438
fn find_foreign_static(
435-
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
436439
_def_id: DefId,
440+
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
441+
_memory_extra: &(),
437442
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
438443
err!(ReadForeignStatic)
439444
}
440445

441446
#[inline(always)]
442-
fn adjust_static_allocation(
443-
alloc: &'_ Allocation
444-
) -> Cow<'_, Allocation<Self::PointerTag>> {
447+
fn adjust_static_allocation<'b>(
448+
alloc: &'b Allocation,
449+
_memory_extra: &(),
450+
) -> Cow<'b, Allocation<Self::PointerTag>> {
445451
// We do not use a tag so we can just cheaply forward the reference
446452
Cow::Borrowed(alloc)
447453
}
@@ -487,6 +493,22 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
487493
) -> EvalResult<'tcx, Pointer> {
488494
Ok(ptr)
489495
}
496+
497+
#[inline(always)]
498+
fn stack_push(
499+
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
500+
) -> EvalResult<'tcx> {
501+
Ok(())
502+
}
503+
504+
/// Called immediately before a stack frame gets popped
505+
#[inline(always)]
506+
fn stack_pop(
507+
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
508+
_extra: (),
509+
) -> EvalResult<'tcx> {
510+
Ok(())
511+
}
490512
}
491513

492514
/// Project to a field of a (variant of a) const

src/librustc_mir/interpret/eval_context.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
4949
pub(crate) memory: Memory<'a, 'mir, 'tcx, M>,
5050

5151
/// The virtual call stack.
52-
pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag>>,
52+
pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
5353

5454
/// A cache for deduplicating vtables
5555
pub(super) vtables: FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), AllocId>,
5656
}
5757

5858
/// A stack frame.
5959
#[derive(Clone)]
60-
pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
60+
pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
6161
////////////////////////////////////////////////////////////////////////////////
6262
// Function and callsite information
6363
////////////////////////////////////////////////////////////////////////////////
@@ -96,6 +96,9 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
9696

9797
/// The index of the currently evaluated statement.
9898
pub stmt: usize,
99+
100+
/// Extra data for the machine
101+
pub extra: Extra,
99102
}
100103

101104
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
@@ -196,7 +199,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
196199
}
197200

198201
#[inline(always)]
199-
pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag>] {
202+
pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>] {
200203
&self.stack
201204
}
202205

@@ -207,12 +210,12 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
207210
}
208211

209212
#[inline(always)]
210-
pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag> {
213+
pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
211214
self.stack.last().expect("no call frames exist")
212215
}
213216

214217
#[inline(always)]
215-
pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag> {
218+
pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra> {
216219
self.stack.last_mut().expect("no call frames exist")
217220
}
218221

@@ -294,7 +297,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
294297

295298
pub fn layout_of_local(
296299
&self,
297-
frame: &Frame<'mir, 'tcx, M::PointerTag>,
300+
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
298301
local: mir::Local
299302
) -> EvalResult<'tcx, TyLayout<'tcx>> {
300303
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
424427
::log_settings::settings().indentation += 1;
425428

426429
// first push a stack frame so we have access to the local substs
430+
let extra = M::stack_push(self)?;
427431
self.stack.push(Frame {
428432
mir,
429433
block: mir::START_BLOCK,
@@ -435,6 +439,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
435439
span,
436440
instance,
437441
stmt: 0,
442+
extra,
438443
});
439444

440445
// 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
504509
let frame = self.stack.pop().expect(
505510
"tried to pop a stack frame, but there were none",
506511
);
512+
M::stack_pop(self, frame.extra)?;
507513
// Abort early if we do not want to clean up: We also avoid validation in that case,
508514
// because this is CTFE and the final value will be thoroughly validated anyway.
509515
match frame.return_to_block {

src/librustc_mir/interpret/machine.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,16 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
7777
/// The `default()` is used for pointers to consts, statics, vtables and functions.
7878
type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
7979

80+
/// Extra data stored in every call frame.
81+
type FrameExtra;
82+
83+
/// Extra data stored in memory. A reference to this is available when `AllocExtra`
84+
/// gets initialized, so you can e.g. have an `Rc` here if there is global state you
85+
/// need access to in the `AllocExtra` hooks.
86+
type MemoryExtra: Default;
87+
8088
/// Extra data stored in every allocation.
81-
type AllocExtra: AllocationExtra<Self::PointerTag>;
89+
type AllocExtra: AllocationExtra<Self::PointerTag, Self::MemoryExtra>;
8290

8391
/// Memory's allocation map
8492
type MemoryMap:
@@ -136,8 +144,9 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
136144
/// the machine memory. (This relies on `AllocMap::get_or` being able to add the
137145
/// owned allocation to the map even when the map is shared.)
138146
fn find_foreign_static(
139-
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
140147
def_id: DefId,
148+
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
149+
memory_extra: &Self::MemoryExtra,
141150
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;
142151

143152
/// Called to turn an allocation obtained from the `tcx` into one that has
@@ -147,9 +156,10 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
147156
/// allocation (because a copy had to be done to add tags or metadata), machine memory will
148157
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
149158
/// owned allocation to the map even when the map is shared.)
150-
fn adjust_static_allocation(
151-
alloc: &'_ Allocation
152-
) -> Cow<'_, Allocation<Self::PointerTag, Self::AllocExtra>>;
159+
fn adjust_static_allocation<'b>(
160+
alloc: &'b Allocation,
161+
memory_extra: &Self::MemoryExtra,
162+
) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
153163

154164
/// Called for all binary operations on integer(-like) types when one operand is a pointer
155165
/// value, and for the `Offset` operation that is inherently about pointers.
@@ -207,4 +217,15 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
207217
) -> EvalResult<'tcx> {
208218
Ok(())
209219
}
220+
221+
/// Called immediately before a new stack frame got pushed
222+
fn stack_push(
223+
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
224+
) -> EvalResult<'tcx, Self::FrameExtra>;
225+
226+
/// Called immediately after a stack frame gets popped
227+
fn stack_pop(
228+
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
229+
extra: Self::FrameExtra,
230+
) -> EvalResult<'tcx>;
210231
}

src/librustc_mir/interpret/memory.rs

+25-11
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
7373
/// that do not exist any more.
7474
dead_alloc_map: FxHashMap<AllocId, (Size, Align)>,
7575

76+
/// Extra data added by the machine.
77+
pub extra: M::MemoryExtra,
78+
7679
/// Lets us implement `HasDataLayout`, which is awfully convenient.
7780
pub(super) tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
7881
}
@@ -88,13 +91,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> HasDataLayout
8891

8992
// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead
9093
// carefully copy only the reachable parts.
91-
impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>>
92-
Clone for Memory<'a, 'mir, 'tcx, M>
94+
impl<'a, 'mir, 'tcx, M>
95+
Clone
96+
for
97+
Memory<'a, 'mir, 'tcx, M>
98+
where
99+
M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=(), MemoryExtra=()>,
100+
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
93101
{
94102
fn clone(&self) -> Self {
95103
Memory {
96104
alloc_map: self.alloc_map.clone(),
97105
dead_alloc_map: self.dead_alloc_map.clone(),
106+
extra: (),
98107
tcx: self.tcx,
99108
}
100109
}
@@ -103,8 +112,9 @@ impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>>
103112
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
104113
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>) -> Self {
105114
Memory {
106-
alloc_map: Default::default(),
115+
alloc_map: M::MemoryMap::default(),
107116
dead_alloc_map: FxHashMap::default(),
117+
extra: M::MemoryExtra::default(),
108118
tcx,
109119
}
110120
}
@@ -133,7 +143,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
133143
align: Align,
134144
kind: MemoryKind<M::MemoryKinds>,
135145
) -> EvalResult<'tcx, Pointer> {
136-
Ok(Pointer::from(self.allocate_with(Allocation::undef(size, align), kind)?))
146+
let extra = AllocationExtra::memory_allocated(size, &self.extra);
147+
Ok(Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)?))
137148
}
138149

139150
pub fn reallocate(
@@ -309,15 +320,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
309320
/// this machine use the same pointer tag, so it is indirected through
310321
/// `M::static_with_default_tag`.
311322
fn get_static_alloc(
312-
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
313323
id: AllocId,
324+
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
325+
memory_extra: &M::MemoryExtra,
314326
) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
315327
let alloc = tcx.alloc_map.lock().get(id);
316328
let def_id = match alloc {
317329
Some(AllocType::Memory(mem)) => {
318330
// We got tcx memory. Let the machine figure out whether and how to
319331
// turn that into memory with the right pointer tag.
320-
return Ok(M::adjust_static_allocation(mem))
332+
return Ok(M::adjust_static_allocation(mem, memory_extra))
321333
}
322334
Some(AllocType::Function(..)) => {
323335
return err!(DerefFunctionPointer)
@@ -331,7 +343,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
331343
// We got a "lazy" static that has not been computed yet, do some work
332344
trace!("static_alloc: Need to compute {:?}", def_id);
333345
if tcx.is_foreign_item(def_id) {
334-
return M::find_foreign_static(tcx, def_id);
346+
return M::find_foreign_static(def_id, tcx, memory_extra);
335347
}
336348
let instance = Instance::mono(tcx.tcx, def_id);
337349
let gid = GlobalId {
@@ -351,7 +363,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
351363
let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id);
352364
// We got tcx memory. Let the machine figure out whether and how to
353365
// turn that into memory with the right pointer tag.
354-
M::adjust_static_allocation(allocation)
366+
M::adjust_static_allocation(allocation, memory_extra)
355367
})
356368
}
357369

@@ -361,7 +373,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
361373
// `get_static_alloc` that we can actually use directly without inserting anything anywhere.
362374
// So the error type is `EvalResult<'tcx, &Allocation<M::PointerTag>>`.
363375
let a = self.alloc_map.get_or(id, || {
364-
let alloc = Self::get_static_alloc(self.tcx, id).map_err(Err)?;
376+
let alloc = Self::get_static_alloc(id, self.tcx, &self.extra).map_err(Err)?;
365377
match alloc {
366378
Cow::Borrowed(alloc) => {
367379
// We got a ref, cheaply return that as an "error" so that the
@@ -390,10 +402,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
390402
id: AllocId,
391403
) -> EvalResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
392404
let tcx = self.tcx;
405+
let memory_extra = &self.extra;
393406
let a = self.alloc_map.get_mut_or(id, || {
394407
// Need to make a copy, even if `get_static_alloc` is able
395408
// to give us a cheap reference.
396-
let alloc = Self::get_static_alloc(tcx, id)?;
409+
let alloc = Self::get_static_alloc(id, tcx, memory_extra)?;
397410
if alloc.mutability == Mutability::Immutable {
398411
return err!(ModifiedConstantMemory);
399412
}
@@ -601,7 +614,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
601614
/// Interning (for CTFE)
602615
impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
603616
where
604-
M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=()>,
617+
M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=(), MemoryExtra=()>,
618+
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
605619
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
606620
{
607621
/// mark an allocation as static and initialized, either mutable or not

src/librustc_mir/interpret/operand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
471471
/// When you know the layout of the local in advance, you can pass it as last argument
472472
pub fn access_local(
473473
&self,
474-
frame: &super::Frame<'mir, 'tcx, M::PointerTag>,
474+
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
475475
local: mir::Local,
476476
layout: Option<TyLayout<'tcx>>,
477477
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {

src/librustc_mir/interpret/place.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,12 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
295295
// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
296296
impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
297297
where
298+
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
298299
Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
299300
M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
301+
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
300302
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
301-
M::AllocExtra: AllocationExtra<Tag>,
303+
M::AllocExtra: AllocationExtra<Tag, M::MemoryExtra>,
302304
{
303305
/// Take a value, which represents a (thin or fat) reference, and make it a place.
304306
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.

src/librustc_mir/interpret/snapshot.rs

+2
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ impl_stable_hash_for!(impl<'tcx, 'mir: 'tcx> for struct Frame<'mir, 'tcx> {
323323
locals,
324324
block,
325325
stmt,
326+
extra,
326327
});
327328

328329
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>
340341
locals,
341342
block,
342343
stmt,
344+
extra: _,
343345
} = self;
344346

345347
FrameSnapshot {

0 commit comments

Comments
 (0)