use std::hash::Hash;
use rustc::mir;
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_hir::def_id::DefId;
+use rustc::ty::{self, Ty};
use rustc_span::Span;
use super::{
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
- /// Called before a basic block terminator is executed.
- /// You can use this to detect endlessly running programs.
- fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
-
/// Entry point to all function calls.
///
/// Returns either the mir to use for the call, or `None` if execution should
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx>;
- /// Called for read access to a foreign static item.
- ///
- /// This will only be called once per static and machine; the result is cached in
- /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
- /// owned allocation to the map even when the map is shared.)
- ///
- /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
- fn find_foreign_static(
- tcx: TyCtxt<'tcx>,
- def_id: DefId,
- ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;
-
/// Called for all binary operations where the LHS has pointer type.
///
/// Returns a (value, overflowed) pair if the operation succeeded
) -> InterpResult<'tcx>;
/// Called to read the specified `local` from the `frame`.
+ #[inline]
fn access_local(
_ecx: &InterpCx<'mir, 'tcx, Self>,
frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
frame.locals[local].access()
}
+ /// Called before a basic block terminator is executed.
+ /// You can use this to detect endlessly running programs.
+ #[inline]
+ fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
+ Ok(())
+ }
+
/// Called before a `Static` value is accessed.
+ #[inline]
fn before_access_static(
_memory_extra: &Self::MemoryExtra,
_allocation: &Allocation,
Ok(())
}
+ /// Called for *every* memory access to determine the real ID of the given allocation.
+ /// This provides a way for the machine to "redirect" certain allocations as it sees fit.
+ ///
+ /// This is used by Miri to redirect extern statics to real allocations.
+ ///
+ /// This function must be idempotent.
+ #[inline]
+ fn canonical_alloc_id(
+ _mem: &Memory<'mir, 'tcx, Self>,
+ id: AllocId,
+ ) -> AllocId {
+ id
+ }
+
/// Called to initialize the "extra" state of an allocation and make the pointers
/// it contains (in relocations) tagged. The way we construct allocations is
/// to always first construct it without extra and then add the extra.
Ok(())
}
- /// Called immediately before a new stack frame got pushed
+ /// Called immediately before a new stack frame got pushed.
fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>;
/// Called immediately after a stack frame gets popped
/// The `GlobalAlloc::Memory` branch here is still reachable though; when a static
/// contains a reference to memory that was created during its evaluation (i.e., not to
/// another static), those inner references only exist in "resolved" form.
+ ///
+ /// Assumes `id` is already canonical.
fn get_static_alloc(
memory_extra: &M::MemoryExtra,
tcx: TyCtxtAt<'tcx>,
Some(GlobalAlloc::Static(def_id)) => {
// We got a "lazy" static that has not been computed yet.
if tcx.is_foreign_item(def_id) {
- trace!("static_alloc: foreign item {:?}", def_id);
- M::find_foreign_static(tcx.tcx, def_id)?
- } else {
- trace!("static_alloc: Need to compute {:?}", def_id);
- let instance = Instance::mono(tcx.tcx, def_id);
- let gid = GlobalId { instance, promoted: None };
- // use the raw query here to break validation cycles. Later uses of the static
- // will call the full query anyway
- let raw_const =
- tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
- // no need to report anything, the const_eval call takes care of that
- // for statics
- assert!(tcx.is_static(def_id));
- match err {
- ErrorHandled::Reported => err_inval!(ReferencedConstant),
- ErrorHandled::TooGeneric => err_inval!(TooGeneric),
- }
- })?;
- // Make sure we use the ID of the resolved memory, not the lazy one!
- let id = raw_const.alloc_id;
- let allocation = tcx.alloc_map.lock().unwrap_memory(id);
-
- M::before_access_static(memory_extra, allocation)?;
- Cow::Borrowed(allocation)
+ trace!("get_static_alloc: foreign item {:?}", def_id);
+ throw_unsup!(ReadForeignStatic)
}
+ trace!("get_static_alloc: Need to compute {:?}", def_id);
+ let instance = Instance::mono(tcx.tcx, def_id);
+ let gid = GlobalId { instance, promoted: None };
+ // use the raw query here to break validation cycles. Later uses of the static
+ // will call the full query anyway
+ let raw_const =
+ tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| {
+ // no need to report anything, the const_eval call takes care of that
+ // for statics
+ assert!(tcx.is_static(def_id));
+ match err {
+ ErrorHandled::Reported => err_inval!(ReferencedConstant),
+ ErrorHandled::TooGeneric => err_inval!(TooGeneric),
+ }
+ })?;
+ // Make sure we use the ID of the resolved memory, not the lazy one!
+ let id = raw_const.alloc_id;
+ let allocation = tcx.alloc_map.lock().unwrap_memory(id);
+
+ M::before_access_static(memory_extra, allocation)?;
+ Cow::Borrowed(allocation)
}
};
// We got tcx memory. Let the machine initialize its "extra" stuff.
&self,
id: AllocId,
) -> InterpResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> {
+ let id = M::canonical_alloc_id(self, id);
// The error type of the inner closure here is somewhat funny. We have two
// ways of "erroring": An actual error, or because we got a reference from
// `get_static_alloc` that we can actually use directly without inserting anything anywhere.
&mut self,
id: AllocId,
) -> InterpResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
+ let id = M::canonical_alloc_id(self, id);
let tcx = self.tcx;
let memory_extra = &self.extra;
let a = self.alloc_map.get_mut_or(id, || {
id: AllocId,
liveness: AllocCheck,
) -> InterpResult<'static, (Size, Align)> {
+ let id = M::canonical_alloc_id(self, id);
// # Regular allocations
// Don't use `self.get_raw` here as that will
// a) cause cycles in case `id` refers to a static
}
}
+ /// Assumes `id` is already canonical.
fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
trace!("reading fn ptr: {}", id);
if let Some(extra) = self.extra_fn_ptr_map.get(&id) {
if ptr.offset.bytes() != 0 {
throw_unsup!(InvalidFunctionPointer)
}
- self.get_fn_alloc(ptr.alloc_id).ok_or_else(|| err_unsup!(ExecuteMemory).into())
+ let id = M::canonical_alloc_id(self, ptr.alloc_id);
+ self.get_fn_alloc(id).ok_or_else(|| err_unsup!(ExecuteMemory).into())
}
pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {