use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::{
- middle::codegen_fn_attrs::CodegenFnAttrFlags,
- mir,
- ty::{self, Instance},
-};
use crate::sync::SynchronizationState;
use crate::*;
/// Change the active thread to some enabled thread.
fn yield_active_thread(&mut self) {
+ // We do not yield immediately, as swapping out the current stack while executing a MIR statement
+ // could lead to all sorts of confusion.
+ // We should only switch stacks between steps.
self.yield_active_thread = true;
}
// Public interface to thread management.
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
- /// A workaround for thread-local statics until
- /// https://github.com/rust-lang/rust/issues/70685 is fixed: change the
- /// thread-local allocation id with a freshly generated allocation id for
- /// the currently active thread.
- fn remap_thread_local_alloc_ids(
- &self,
- val: &mut mir::interpret::ConstValue<'tcx>,
- ) -> InterpResult<'tcx> {
- let this = self.eval_context_ref();
- match *val {
- mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => {
- let alloc_id = ptr.alloc_id;
- let alloc = this.tcx.get_global_alloc(alloc_id);
- let tcx = this.tcx;
- let is_thread_local = |def_id| {
- tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
- };
- match alloc {
- Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => {
- ptr.alloc_id = this.get_or_create_thread_local_alloc_id(def_id)?;
- }
- _ => {}
- }
- }
- _ => {
- // FIXME: Handling only `Scalar` seems to work for now, but at
- // least in principle thread-locals could be in any constant, so
- // we should also consider other cases. However, once
- // https://github.com/rust-lang/rust/issues/70685 gets fixed,
- // this code will have to be rewritten anyway.
- }
- }
- Ok(())
- }
-
/// Get a thread-specific allocation id for the given thread-local static.
/// If needed, allocate a new one.
- ///
- /// FIXME: This method should be replaced as soon as
- /// https://github.com/rust-lang/rust/issues/70685 gets fixed.
fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> {
let this = self.eval_context_ref();
let tcx = this.tcx;
// We need to allocate a thread-specific allocation id for this
// thread-local static.
//
- // At first, we invoke the `const_eval_raw` query and extract the
- // allocation from it. Unfortunately, we have to duplicate the code
- // from `Memory::get_global_alloc` that does this.
- //
+ // At first, we compute the initial value for this static.
// Then we store the retrieved allocation back into the `alloc_map`
// to get a fresh allocation id, which we can use as a
// thread-specific allocation id for the thread-local static.
+ // On first access to that allocation, it will be copied over to the machine memory.
if tcx.is_foreign_item(def_id) {
throw_unsup_format!("foreign thread-local statics are not supported");
}
- // Invoke the `const_eval_raw` query.
- let instance = Instance::mono(tcx.tcx, def_id);
- let gid = GlobalId { instance, promoted: None };
- 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));
- err
- })?;
- let id = raw_const.alloc_id;
- // Extract the allocation from the query result.
- let allocation = tcx.global_alloc(id).unwrap_memory();
+ let allocation = interpret::get_static(*tcx, def_id)?;
// Create a new allocation id for the same allocation in this hacky
// way. Internally, `alloc_map` deduplicates allocations, but this
// is fine because Miri will make a copy before a first mutable