Cleanup the implementation of adjust_global_const.
This commit is contained in:
parent
1d0eb93ebd
commit
688cacbdd7
@ -14,11 +14,9 @@
|
||||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::{
|
||||
middle::codegen_fn_attrs::CodegenFnAttrFlags,
|
||||
mir,
|
||||
ty::{
|
||||
self,
|
||||
Instance,
|
||||
layout::{LayoutCx, LayoutError, TyAndLayout},
|
||||
TyCtxt,
|
||||
},
|
||||
@ -422,53 +420,7 @@ fn adjust_global_const(
|
||||
ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||
mut val: mir::interpret::ConstValue<'tcx>,
|
||||
) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> {
|
||||
match &mut val {
|
||||
mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => {
|
||||
let alloc_id = ptr.alloc_id;
|
||||
let alloc = ecx.tcx.alloc_map.lock().get(alloc_id);
|
||||
let tcx = ecx.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) => {
|
||||
let new_alloc_id = if let Some(new_alloc_id) =
|
||||
ecx.get_thread_local_alloc_id(alloc_id)
|
||||
{
|
||||
new_alloc_id
|
||||
} else {
|
||||
if tcx.is_foreign_item(def_id) {
|
||||
throw_unsup_format!(
|
||||
"Foreign thread-local statics are not supported."
|
||||
)
|
||||
}
|
||||
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));
|
||||
match err {
|
||||
ErrorHandled::Reported => err_inval!(ReferencedConstant),
|
||||
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
|
||||
}
|
||||
})?;
|
||||
let id = raw_const.alloc_id;
|
||||
let mut alloc_map = tcx.alloc_map.lock();
|
||||
let allocation = alloc_map.unwrap_memory(id);
|
||||
let new_alloc_id = alloc_map.create_memory_alloc(allocation);
|
||||
ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id);
|
||||
new_alloc_id
|
||||
};
|
||||
ptr.alloc_id = new_alloc_id;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ecx.remap_thread_local_alloc_ids(&mut val)?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
|
106
src/threads.rs
106
src/threads.rs
@ -7,7 +7,13 @@
|
||||
use log::trace;
|
||||
|
||||
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::*;
|
||||
|
||||
@ -124,9 +130,9 @@ pub struct ThreadManager<'mir, 'tcx> {
|
||||
threads: IndexVec<ThreadId, Thread<'mir, 'tcx>>,
|
||||
/// A counter used to generate unique identifiers for blocksets.
|
||||
blockset_counter: u32,
|
||||
/// A mapping from an allocation id of a thread-local static to an
|
||||
/// allocation id of a thread specific allocation.
|
||||
thread_local_alloc_ids: RefCell<FxHashMap<(AllocId, ThreadId), AllocId>>,
|
||||
/// A mapping from a thread-local static to an allocation id of a thread
|
||||
/// specific allocation.
|
||||
thread_local_alloc_ids: RefCell<FxHashMap<(DefId, ThreadId), AllocId>>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> {
|
||||
@ -145,19 +151,19 @@ fn default() -> Self {
|
||||
impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
|
||||
/// Check if we have an allocation for the given thread local static for the
|
||||
/// active thread.
|
||||
pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option<AllocId> {
|
||||
self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned()
|
||||
pub fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<AllocId> {
|
||||
self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned()
|
||||
}
|
||||
|
||||
/// Set the allocation id as the allocation id of the given thread local
|
||||
/// static for the active thread.
|
||||
pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) {
|
||||
pub fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) {
|
||||
assert!(
|
||||
self.thread_local_alloc_ids
|
||||
.borrow_mut()
|
||||
.insert((static_alloc_id, self.active_thread), new_alloc_id)
|
||||
.insert((def_id, self.active_thread), new_alloc_id)
|
||||
.is_none(),
|
||||
"Bug: a thread local initialized twice for the same thread."
|
||||
"a thread local initialized twice for the same thread"
|
||||
);
|
||||
}
|
||||
|
||||
@ -291,14 +297,88 @@ fn schedule(&mut self) -> InterpResult<'tcx, bool> {
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option<AllocId> {
|
||||
/// 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();
|
||||
this.machine.threads.get_thread_local_alloc_id(static_alloc_id)
|
||||
match val {
|
||||
mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => {
|
||||
let alloc_id = ptr.alloc_id;
|
||||
let alloc = this.tcx.alloc_map.lock().get(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(())
|
||||
}
|
||||
|
||||
fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) {
|
||||
/// 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();
|
||||
this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id)
|
||||
let tcx = this.tcx;
|
||||
if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) {
|
||||
// We already have a thread-specific allocation id for this
|
||||
// thread-local static.
|
||||
Ok(new_alloc_id)
|
||||
} else {
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
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 mut alloc_map = tcx.alloc_map.lock();
|
||||
let allocation = alloc_map.unwrap_memory(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
|
||||
// access.
|
||||
let new_alloc_id = alloc_map.create_memory_alloc(allocation);
|
||||
this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id);
|
||||
Ok(new_alloc_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> {
|
||||
|
Loading…
Reference in New Issue
Block a user