}
// `Memory` has to depend on the `Machine` because some of its operations
-// (e.g. `get`) call a `Machine` hook.
+// (e.g., `get`) call a `Machine` hook.
pub struct Memory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
/// Allocations local to this instance of the miri engine. The kind
/// helps ensure that the same mechanism is used for allocation and
/// that do not exist any more.
dead_alloc_map: FxHashMap<AllocId, (Size, Align)>,
+ /// Extra data added by the machine.
+ pub extra: M::MemoryExtra,
+
/// Lets us implement `HasDataLayout`, which is awfully convenient.
pub(super) tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
}
// FIXME: Really we shouldn't clone memory, ever. Snapshot machinery should instead
// carefully copy only the reachable parts.
-impl<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>>
- Clone for Memory<'a, 'mir, 'tcx, M>
+impl<'a, 'mir, 'tcx, M>
+ Clone
+for
+ Memory<'a, 'mir, 'tcx, M>
+where
+ M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=(), MemoryExtra=()>,
+ M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
{
fn clone(&self) -> Self {
Memory {
alloc_map: self.alloc_map.clone(),
dead_alloc_map: self.dead_alloc_map.clone(),
+ extra: (),
tcx: self.tcx,
}
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>) -> Self {
Memory {
- alloc_map: Default::default(),
+ alloc_map: M::MemoryMap::default(),
dead_alloc_map: FxHashMap::default(),
+ extra: M::MemoryExtra::default(),
tcx,
}
}
align: Align,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx, Pointer> {
- Ok(Pointer::from(self.allocate_with(Allocation::undef(size, align), kind)?))
+ let extra = AllocationExtra::memory_allocated(size, &self.extra);
+ Ok(Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)?))
}
pub fn reallocate(
/// this machine use the same pointer tag, so it is indirected through
/// `M::static_with_default_tag`.
fn get_static_alloc(
- tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
id: AllocId,
+ tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
+ memory_extra: &M::MemoryExtra,
) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
let alloc = tcx.alloc_map.lock().get(id);
let def_id = match alloc {
Some(AllocType::Memory(mem)) => {
// We got tcx memory. Let the machine figure out whether and how to
// turn that into memory with the right pointer tag.
- return Ok(M::adjust_static_allocation(mem))
+ return Ok(M::adjust_static_allocation(mem, memory_extra))
}
Some(AllocType::Function(..)) => {
return err!(DerefFunctionPointer)
// We got a "lazy" static that has not been computed yet, do some work
trace!("static_alloc: Need to compute {:?}", def_id);
if tcx.is_foreign_item(def_id) {
- return M::find_foreign_static(tcx, def_id);
+ return M::find_foreign_static(def_id, tcx, memory_extra);
}
let instance = Instance::mono(tcx.tcx, def_id);
let gid = GlobalId {
let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id);
// We got tcx memory. Let the machine figure out whether and how to
// turn that into memory with the right pointer tag.
- M::adjust_static_allocation(allocation)
+ M::adjust_static_allocation(allocation, memory_extra)
})
}
// `get_static_alloc` that we can actually use directly without inserting anything anywhere.
// So the error type is `EvalResult<'tcx, &Allocation<M::PointerTag>>`.
let a = self.alloc_map.get_or(id, || {
- let alloc = Self::get_static_alloc(self.tcx, id).map_err(Err)?;
+ let alloc = Self::get_static_alloc(id, self.tcx, &self.extra).map_err(Err)?;
match alloc {
Cow::Borrowed(alloc) => {
// We got a ref, cheaply return that as an "error" so that the
id: AllocId,
) -> EvalResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
let tcx = self.tcx;
+ let memory_extra = &self.extra;
let a = self.alloc_map.get_mut_or(id, || {
// Need to make a copy, even if `get_static_alloc` is able
// to give us a cheap reference.
- let alloc = Self::get_static_alloc(tcx, id)?;
+ let alloc = Self::get_static_alloc(id, tcx, memory_extra)?;
if alloc.mutability == Mutability::Immutable {
return err!(ModifiedConstantMemory);
}
- let kind = M::STATIC_KIND.expect(
- "An allocation is being mutated but the machine does not expect that to happen"
- );
- Ok((MemoryKind::Machine(kind), alloc.into_owned()))
+ match M::STATIC_KIND {
+ Some(kind) => Ok((MemoryKind::Machine(kind), alloc.into_owned())),
+ None => err!(ModifiedStatic),
+ }
});
// Unpack the error type manually because type inference doesn't
// work otherwise (and we cannot help it because `impl Trait`)
/// Interning (for CTFE)
impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
where
- M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=()>,
+ M: Machine<'a, 'mir, 'tcx, PointerTag=(), AllocExtra=(), MemoryExtra=()>,
+ // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
{
/// mark an allocation as static and initialized, either mutable or not