Remove GCX_PTR.

We store an `ImplicitCtxt` pointer in a thread-local value (TLV). This allows
implicit access to a `GlobalCtxt` and some other things.

We also store a `GlobalCtxt` pointer in `GCX_PTR`. This is always the same
`GlobalCtxt` as the one within the `ImplicitCtxt` pointer in TLV. `GCX_PTR`
is only used in the parallel compiler's `handle_deadlock()` function.

This commit does the following.
- It removes `GCX_PTR`.
- It also adds `ImplicitCtxt::new()`, which constructs an `ImplicitCtxt` from a
  `GlobalCtxt`. `ImplicitCtxt::new()` + `tls::enter_context()` is now
  equivalent to the old `tls::enter_global()`.
- Makes `tls::get_tlv()` public for the parallel compiler, because it's
  now used in `handle_deadlock()`.
This commit is contained in:
Nicholas Nethercote 2020-07-31 13:01:29 +10:00
parent f042d749b0
commit d93277b915
7 changed files with 33 additions and 75 deletions

View File

@ -3677,7 +3677,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"scoped-tls",
"smallvec 1.4.0",
"tracing",
]

View File

@ -752,7 +752,8 @@ impl<'tcx> QueryContext<'tcx> {
where
F: FnOnce(TyCtxt<'tcx>) -> R,
{
ty::tls::enter_global(self.0, f)
let icx = ty::tls::ImplicitCtxt::new(self.0);
ty::tls::enter_context(&icx, |_| f(icx.tcx))
}
pub fn print_stats(&mut self) {
@ -811,8 +812,9 @@ pub fn create_global_ctxt<'tcx>(
});
// Do some initialization of the DepGraph that can only be done with the tcx available.
ty::tls::enter_global(&gcx, |tcx| {
tcx.sess.time("dep_graph_tcx_init", || rustc_incremental::dep_graph_tcx_init(tcx));
let icx = ty::tls::ImplicitCtxt::new(&gcx);
ty::tls::enter_context(&icx, |_| {
icx.tcx.sess.time("dep_graph_tcx_init", || rustc_incremental::dep_graph_tcx_init(icx.tcx));
});
QueryContext(gcx)

View File

@ -10,10 +10,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
#[cfg(parallel_compiler)]
use rustc_data_structures::jobserver;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
use rustc_metadata::dynamic_lib::DynamicLibrary;
use rustc_middle::ty;
use rustc_resolve::{self, Resolver};
use rustc_session as session;
use rustc_session::config::{self, CrateType};
@ -144,12 +143,10 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
let main_handler = move || {
rustc_ast::with_session_globals(edition, || {
ty::tls::GCX_PTR.set(&Lock::new(0), || {
if let Some(stderr) = stderr {
io::set_panic(Some(box Sink(stderr.clone())));
}
f()
})
if let Some(stderr) = stderr {
io::set_panic(Some(box Sink(stderr.clone())));
}
f()
})
};
@ -163,6 +160,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
stderr: &Option<Arc<Mutex<Vec<u8>>>>,
f: F,
) -> R {
use rustc_middle::ty;
crate::callbacks::setup_callbacks();
let mut config = rayon::ThreadPoolBuilder::new()
@ -189,12 +187,10 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
let main_handler = move |thread: rayon::ThreadBuilder| {
rustc_ast::SESSION_GLOBALS.set(ast_session_globals, || {
rustc_span::SESSION_GLOBALS.set(span_session_globals, || {
ty::tls::GCX_PTR.set(&Lock::new(0), || {
if let Some(stderr) = stderr {
io::set_panic(Some(box Sink(stderr.clone())));
}
thread.run()
})
if let Some(stderr) = stderr {
io::set_panic(Some(box Sink(stderr.clone())));
}
thread.run()
})
})
};

View File

@ -12,7 +12,6 @@ doctest = false
[dependencies]
rustc_arena = { path = "../librustc_arena" }
bitflags = "1.2.1"
scoped-tls = "1.0"
log = { package = "tracing", version = "0.1" }
rustc-rayon-core = "0.3.0"
polonius-engine = "0.12.0"

View File

@ -55,8 +55,6 @@
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate scoped_tls;
#[macro_use]
extern crate rustc_macros;
#[macro_use]
extern crate rustc_data_structures;

View File

@ -1632,7 +1632,6 @@ pub mod tls {
use crate::ty::query;
use rustc_data_structures::sync::{self, Lock};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_data_structures::OnDrop;
use rustc_errors::Diagnostic;
use std::mem;
@ -1649,8 +1648,7 @@ pub mod tls {
/// in this module.
#[derive(Clone)]
pub struct ImplicitCtxt<'a, 'tcx> {
/// The current `TyCtxt`. Initially created by `enter_global` and updated
/// by `enter_local` with a new local interner.
/// The current `TyCtxt`.
pub tcx: TyCtxt<'tcx>,
/// The current query job, if any. This is updated by `JobOwner::start` in
@ -1669,6 +1667,13 @@ pub mod tls {
pub task_deps: Option<&'a Lock<TaskDeps>>,
}
impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
let tcx = TyCtxt { gcx };
ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None }
}
}
/// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
/// to `value` during the call to `f`. It is restored to its previous value after.
/// This is used to set the pointer to the new `ImplicitCtxt`.
@ -1682,7 +1687,7 @@ pub mod tls {
/// This is used to get the pointer to the current `ImplicitCtxt`.
#[cfg(parallel_compiler)]
#[inline]
fn get_tlv() -> usize {
pub fn get_tlv() -> usize {
rayon_core::tlv::get()
}
@ -1699,7 +1704,7 @@ pub mod tls {
#[inline]
fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
let old = get_tlv();
let _reset = OnDrop(move || TLV.with(|tlv| tlv.set(old)));
let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
TLV.with(|tlv| tlv.set(value));
f()
}
@ -1720,50 +1725,6 @@ pub mod tls {
set_tlv(context as *const _ as usize, || f(&context))
}
/// Enters `GlobalCtxt` by setting up librustc_ast callbacks and
/// creating a initial `TyCtxt` and `ImplicitCtxt`.
/// This happens once per rustc session and `TyCtxt`s only exists
/// inside the `f` function.
pub fn enter_global<'tcx, F, R>(gcx: &'tcx GlobalCtxt<'tcx>, f: F) -> R
where
F: FnOnce(TyCtxt<'tcx>) -> R,
{
// Update `GCX_PTR` to indicate there's a `GlobalCtxt` available.
GCX_PTR.with(|lock| {
*lock.lock() = gcx as *const _ as usize;
});
// Set `GCX_PTR` back to 0 when we exit.
let _on_drop = OnDrop(move || {
GCX_PTR.with(|lock| *lock.lock() = 0);
});
let tcx = TyCtxt { gcx };
let icx =
ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None };
enter_context(&icx, |_| f(tcx))
}
scoped_thread_local! {
/// Stores a pointer to the `GlobalCtxt` if one is available.
/// This is used to access the `GlobalCtxt` in the deadlock handler given to Rayon.
pub static GCX_PTR: Lock<usize>
}
/// Creates a `TyCtxt` and `ImplicitCtxt` based on the `GCX_PTR` thread local.
/// This is used in the deadlock handler.
pub unsafe fn with_global<F, R>(f: F) -> R
where
F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
{
let gcx = GCX_PTR.with(|lock| *lock.lock());
assert!(gcx != 0);
let gcx = &*(gcx as *const GlobalCtxt<'_>);
let tcx = TyCtxt { gcx };
let icx =
ImplicitCtxt { query: None, diagnostics: None, tcx, layout_depth: 0, task_deps: None };
enter_context(&icx, |_| f(tcx))
}
/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
#[inline]
pub fn with_context_opt<F, R>(f: F) -> R

View File

@ -10,18 +10,21 @@ use std::thread;
pub unsafe fn handle_deadlock() {
let registry = rayon_core::Registry::current();
let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| gcx_ptr as *const _);
let gcx_ptr = &*gcx_ptr;
let context = tls::get_tlv();
assert!(context != 0);
rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
let span_session_globals = rustc_span::SESSION_GLOBALS.with(|ssg| ssg as *const _);
let span_session_globals = &*span_session_globals;
let ast_session_globals = rustc_ast::attr::SESSION_GLOBALS.with(|asg| asg as *const _);
let ast_session_globals = &*ast_session_globals;
thread::spawn(move || {
tls::GCX_PTR.set(gcx_ptr, || {
tls::enter_context(icx, |_| {
rustc_ast::attr::SESSION_GLOBALS.set(ast_session_globals, || {
rustc_span::SESSION_GLOBALS
.set(span_session_globals, || tls::with_global(|tcx| deadlock(tcx, &registry)))
rustc_span::SESSION_GLOBALS.set(span_session_globals, || {
tls::with_context(|icx| deadlock(icx.tcx, &registry))
})
});
})
});