Skip to content

Commit ce9cd15

Browse files
committed
provide machine hooks for creating references and accessing memory
1 parent 5b71857 commit ce9cd15

File tree

7 files changed

+103
-32
lines changed

7 files changed

+103
-32
lines changed

src/librustc_mir/const_eval.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc::mir::interpret::{
3333
Scalar, Allocation, AllocId, ConstValue,
3434
};
3535
use interpret::{self,
36-
PlaceTy, MemPlace, OpTy, Operand, Value,
36+
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Value,
3737
EvalContext, StackPopCleanup, MemoryKind,
3838
snapshot,
3939
};
@@ -464,6 +464,15 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
464464
&ecx.stack[..],
465465
)
466466
}
467+
468+
#[inline(always)]
469+
fn tag_reference(
470+
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
471+
_place: MPlaceTy<'tcx, Self::PointerTag>,
472+
_borrow_kind: mir::BorrowKind,
473+
) -> EvalResult<'tcx, Self::PointerTag> {
474+
Ok(())
475+
}
467476
}
468477

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

src/librustc_mir/interpret/machine.rs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,19 @@ use std::borrow::{Borrow, Cow};
1616
use std::hash::Hash;
1717

1818
use rustc::hir::def_id::DefId;
19-
use rustc::mir::interpret::{Allocation, AllocId, EvalResult, Scalar};
2019
use rustc::mir;
21-
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
20+
use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt};
2221

23-
use super::{EvalContext, PlaceTy, OpTy, MemoryKind};
22+
use super::{
23+
Allocation, AllocId, EvalResult, Scalar,
24+
EvalContext, PlaceTy, OpTy, MPlaceTy, Pointer, MemoryKind,
25+
};
26+
27+
/// Classifying memory accesses
28+
pub enum MemoryAccess {
29+
Read,
30+
Write,
31+
}
2432

2533
/// Whether this kind of memory is allowed to leak
2634
pub trait MayLeak: Copy {
@@ -160,15 +168,47 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
160168
right_layout: TyLayout<'tcx>,
161169
) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
162170

163-
/// Heap allocations via the `box` keyword
164-
///
165-
/// Returns a pointer to the allocated memory
171+
/// Heap allocations via the `box` keyword.
166172
fn box_alloc(
167173
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
168174
dest: PlaceTy<'tcx, Self::PointerTag>,
169175
) -> EvalResult<'tcx>;
170176

177+
/// Hook for performing extra checks on a memory access.
178+
///
179+
/// Takes read-only access to the allocation so we can keep all the memory read
180+
/// operations take `&self`. Use a `RefCell` in `AllocExtra` if you
181+
/// need to mutate.
182+
#[inline]
183+
fn memory_accessed(
184+
_alloc: &Allocation<Self::PointerTag, Self::AllocExtra>,
185+
_ptr: Pointer<Self::PointerTag>,
186+
_size: Size,
187+
_access: MemoryAccess,
188+
) -> EvalResult<'tcx> {
189+
Ok(())
190+
}
191+
192+
/// Hook for performing extra checks when memory gets deallocated.
193+
#[inline]
194+
fn memory_deallocated(
195+
_alloc: &mut Allocation<Self::PointerTag, Self::AllocExtra>,
196+
_id: AllocId,
197+
) -> EvalResult<'tcx> {
198+
Ok(())
199+
}
200+
201+
/// Executed when evaluating the `&` operator: Creating a new reference.
202+
/// This has the chance to adjust the tag. It is only ever called if the
203+
/// pointer in `place` is really a pointer, not another scalar.
204+
fn tag_reference(
205+
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
206+
place: MPlaceTy<'tcx, Self::PointerTag>,
207+
borrow_kind: mir::BorrowKind,
208+
) -> EvalResult<'tcx, Self::PointerTag>;
209+
171210
/// Execute a validation operation
211+
#[inline]
172212
fn validation_op(
173213
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
174214
_op: ::rustc::mir::ValidationOp,

src/librustc_mir/interpret/memory.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,16 @@ use std::borrow::Cow;
2222

2323
use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
2424
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
25-
use rustc::mir::interpret::{
26-
Pointer, AllocId, Allocation, ConstValue, GlobalId,
27-
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
28-
truncate
29-
};
30-
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
25+
pub use rustc::mir::interpret::{truncate, write_target_uint, read_target_uint};
3126
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
3227

3328
use syntax::ast::Mutability;
3429

35-
use super::{Machine, AllocMap, MayLeak, ScalarMaybeUndef};
30+
use super::{
31+
Pointer, AllocId, Allocation, ConstValue, GlobalId,
32+
EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
33+
Machine, MemoryAccess, AllocMap, MayLeak, ScalarMaybeUndef,
34+
};
3635

3736
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
3837
pub enum MemoryKind<T> {
@@ -197,7 +196,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
197196
return err!(DeallocateNonBasePtr);
198197
}
199198

200-
let (alloc_kind, alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
199+
let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
201200
Some(alloc) => alloc,
202201
None => {
203202
// Deallocating static memory -- always an error
@@ -232,6 +231,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
232231
}
233232
}
234233

234+
// Let the machine take some extra action
235+
M::memory_deallocated(&mut alloc, ptr.alloc_id)?;
236+
235237
// Don't forget to remember size and align of this now-dead allocation
236238
let old = self.dead_alloc_map.insert(
237239
ptr.alloc_id,
@@ -632,6 +634,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
632634
}
633635

634636
let alloc = self.get(ptr.alloc_id)?;
637+
M::memory_accessed(alloc, ptr, size, MemoryAccess::Read)?;
638+
635639
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
636640
assert_eq!(size.bytes() as usize as u64, size.bytes());
637641
let offset = ptr.offset.bytes() as usize;
@@ -676,6 +680,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
676680
self.clear_relocations(ptr, size)?;
677681

678682
let alloc = self.get_mut(ptr.alloc_id)?;
683+
M::memory_accessed(alloc, ptr, size, MemoryAccess::Write)?;
684+
679685
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
680686
assert_eq!(size.bytes() as usize as u64, size.bytes());
681687
let offset = ptr.offset.bytes() as usize;

src/librustc_mir/interpret/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ mod traits;
2424
mod validity;
2525
mod intrinsics;
2626

27+
pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
28+
2729
pub use self::eval_context::{
2830
EvalContext, Frame, StackPopCleanup, LocalValue,
2931
};
@@ -32,7 +34,7 @@ pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
3234

3335
pub use self::memory::{Memory, MemoryKind};
3436

35-
pub use self::machine::{Machine, AllocMap, MayLeak};
37+
pub use self::machine::{Machine, AllocMap, MemoryAccess, MayLeak};
3638

3739
pub use self::operand::{ScalarMaybeUndef, Value, ValTy, Operand, OpTy};
3840

src/librustc_mir/interpret/place.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,6 @@ impl<Tag> MemPlace<Tag> {
144144
// it now must be aligned.
145145
self.to_scalar_ptr_align().0.to_ptr()
146146
}
147-
148-
/// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
149-
/// This is the inverse of `ref_to_mplace`.
150-
pub fn to_ref(self) -> Value<Tag> {
151-
// We ignore the alignment of the place here -- special handling for packed structs ends
152-
// at the `&` operator.
153-
match self.meta {
154-
None => Value::Scalar(self.ptr.into()),
155-
Some(meta) => Value::ScalarPair(self.ptr.into(), meta.into()),
156-
}
157-
}
158147
}
159148

160149
impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
@@ -270,9 +259,10 @@ where
270259
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
271260
{
272261
/// Take a value, which represents a (thin or fat) reference, and make it a place.
273-
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref`.
262+
/// Alignment is just based on the type. This is the inverse of `create_ref`.
274263
pub fn ref_to_mplace(
275-
&self, val: ValTy<'tcx, M::PointerTag>
264+
&self,
265+
val: ValTy<'tcx, M::PointerTag>,
276266
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
277267
let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
278268
let layout = self.layout_of(pointee_type)?;
@@ -286,6 +276,26 @@ where
286276
Ok(MPlaceTy { mplace, layout })
287277
}
288278

279+
/// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
280+
/// This is the inverse of `ref_to_mplace`.
281+
pub fn create_ref(
282+
&mut self,
283+
place: MPlaceTy<'tcx, M::PointerTag>,
284+
borrow_kind: mir::BorrowKind,
285+
) -> EvalResult<'tcx, Value<M::PointerTag>> {
286+
let ptr = match place.ptr {
287+
Scalar::Ptr(ptr) => {
288+
let tag = M::tag_reference(self, place, borrow_kind)?;
289+
Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))
290+
},
291+
scalar @ Scalar::Bits { .. } => scalar,
292+
};
293+
Ok(match place.meta {
294+
None => Value::Scalar(ptr.into()),
295+
Some(meta) => Value::ScalarPair(ptr.into(), meta.into()),
296+
})
297+
}
298+
289299
/// Offset a pointer to project to a field. Unlike place_field, this is always
290300
/// possible without allocating, so it can take &self. Also return the field's layout.
291301
/// This supports both struct and array fields.

src/librustc_mir/interpret/step.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
248248
)?;
249249
}
250250

251-
Ref(_, _, ref place) => {
251+
Ref(_, borrow_kind, ref place) => {
252252
let src = self.eval_place(place)?;
253-
let val = self.force_allocation(src)?.to_ref();
253+
let val = self.force_allocation(src)?;
254+
let val = self.create_ref(val, borrow_kind)?;
254255
self.write_value(val, dest)?;
255256
}
256257

src/librustc_mir/interpret/terminator.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
446446
};
447447

448448
let arg = OpTy {
449-
op: Operand::Immediate(place.to_ref()),
449+
op: Operand::Immediate(self.create_ref(
450+
place,
451+
mir::BorrowKind::Mut { allow_two_phase_borrow: false }
452+
)?),
450453
layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
451454
};
452455

0 commit comments

Comments
 (0)