Skip to content

Commit b98633b

Browse files
Store callbacks in global statics
The callbacks have precisely two states: the default, and the one present throughout almost all of the rustc run (the filled in value which has access to TyCtxt). We used to store this as a thread local, and reset it on each thread to the non-default value. But this is somewhat wasteful, since there is no reason to set it globally -- while the callbacks themselves access TLS, they do not do so in a manner that fails in when we do not have TLS to work with.
1 parent ed33453 commit b98633b

File tree

9 files changed

+95
-73
lines changed

9 files changed

+95
-73
lines changed

src/librustc/ty/context.rs

+1-55
Original file line numberDiff line numberDiff line change
@@ -1623,13 +1623,11 @@ pub mod tls {
16231623

16241624
use crate::dep_graph::TaskDeps;
16251625
use crate::ty::query;
1626-
use errors::{Diagnostic, TRACK_DIAGNOSTICS};
1626+
use errors::Diagnostic;
16271627
use rustc_data_structures::sync::{self, Lock, Lrc};
16281628
use rustc_data_structures::thin_vec::ThinVec;
16291629
use rustc_data_structures::OnDrop;
1630-
use std::fmt;
16311630
use std::mem;
1632-
use syntax_pos;
16331631

16341632
#[cfg(not(parallel_compiler))]
16351633
use std::cell::Cell;
@@ -1705,58 +1703,6 @@ pub mod tls {
17051703
TLV.with(|tlv| tlv.get())
17061704
}
17071705

1708-
/// This is a callback from libsyntax as it cannot access the implicit state
1709-
/// in librustc otherwise.
1710-
fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1711-
with_opt(|tcx| {
1712-
if let Some(tcx) = tcx {
1713-
write!(f, "{}", tcx.sess.source_map().span_to_string(span))
1714-
} else {
1715-
syntax_pos::default_span_debug(span, f)
1716-
}
1717-
})
1718-
}
1719-
1720-
/// This is a callback from libsyntax as it cannot access the implicit state
1721-
/// in librustc otherwise. It is used to when diagnostic messages are
1722-
/// emitted and stores them in the current query, if there is one.
1723-
fn track_diagnostic(diagnostic: &Diagnostic) {
1724-
with_context_opt(|icx| {
1725-
if let Some(icx) = icx {
1726-
if let Some(ref diagnostics) = icx.diagnostics {
1727-
let mut diagnostics = diagnostics.lock();
1728-
diagnostics.extend(Some(diagnostic.clone()));
1729-
}
1730-
}
1731-
})
1732-
}
1733-
1734-
/// Sets up the callbacks from libsyntax on the current thread.
1735-
pub fn with_thread_locals<F, R>(f: F) -> R
1736-
where
1737-
F: FnOnce() -> R,
1738-
{
1739-
syntax_pos::SPAN_DEBUG.with(|span_dbg| {
1740-
let original_span_debug = span_dbg.get();
1741-
span_dbg.set(span_debug);
1742-
1743-
let _on_drop = OnDrop(move || {
1744-
span_dbg.set(original_span_debug);
1745-
});
1746-
1747-
TRACK_DIAGNOSTICS.with(|current| {
1748-
let original = current.get();
1749-
current.set(track_diagnostic);
1750-
1751-
let _on_drop = OnDrop(move || {
1752-
current.set(original);
1753-
});
1754-
1755-
f()
1756-
})
1757-
})
1758-
}
1759-
17601706
/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
17611707
#[inline]
17621708
pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R

src/librustc/ty/query/job.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,8 @@ pub unsafe fn handle_deadlock() {
438438
thread::spawn(move || {
439439
tls::GCX_PTR.set(gcx_ptr, || {
440440
syntax_pos::GLOBALS.set(syntax_pos_globals, || {
441-
syntax_pos::GLOBALS.set(syntax_pos_globals, || {
442-
tls::with_thread_locals(|| tls::with_global(|tcx| deadlock(tcx, &registry)))
443-
})
441+
syntax_pos::GLOBALS
442+
.set(syntax_pos_globals, || tls::with_global(|tcx| deadlock(tcx, &registry)))
444443
})
445444
})
446445
});
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::marker::PhantomData;
2+
use std::sync::atomic::{AtomicPtr, Ordering};
3+
4+
/// This is essentially an `AtomicPtr` but is guaranteed to always be valid
5+
pub struct AtomicRef<T: 'static>(AtomicPtr<T>, PhantomData<&'static T>);
6+
7+
impl<T: 'static> AtomicRef<T> {
8+
pub const fn new(initial: &'static T) -> AtomicRef<T> {
9+
AtomicRef(AtomicPtr::new(initial as *const T as *mut T), PhantomData)
10+
}
11+
12+
pub fn swap(&self, new: &'static T) -> &'static T {
13+
// We never allow storing anything but a `'static` reference so it's safe to
14+
// return it for the same.
15+
unsafe { &*self.0.swap(new as *const T as *mut T, Ordering::SeqCst) }
16+
}
17+
}
18+
19+
impl<T: 'static> std::ops::Deref for AtomicRef<T> {
20+
type Target = T;
21+
fn deref(&self) -> &Self::Target {
22+
// We never allow storing anything but a `'static` reference so it's safe to lend
23+
// it out for any amount of time.
24+
unsafe { &*self.0.load(Ordering::SeqCst) }
25+
}
26+
}

src/librustc_data_structures/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,12 @@ pub mod thin_vec;
8989
pub mod tiny_list;
9090
pub mod transitive_relation;
9191
pub use ena::unify;
92+
mod atomic_ref;
9293
pub mod fingerprint;
9394
pub mod profiling;
9495
pub mod vec_linked_list;
9596
pub mod work_queue;
97+
pub use atomic_ref::AtomicRef;
9698

9799
pub struct OnDrop<F: Fn()>(pub F);
98100

src/librustc_errors/lib.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use registry::Registry;
1717
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
1818
use rustc_data_structures::stable_hasher::StableHasher;
1919
use rustc_data_structures::sync::{self, Lock, Lrc};
20+
use rustc_data_structures::AtomicRef;
2021
use syntax_pos::source_map::SourceMap;
2122
use syntax_pos::{Loc, MultiSpan, Span};
2223

2324
use std::borrow::Cow;
24-
use std::cell::Cell;
2525
use std::panic;
2626
use std::path::Path;
2727
use std::{error, fmt};
@@ -313,8 +313,8 @@ pub enum StashKey {
313313

314314
fn default_track_diagnostic(_: &Diagnostic) {}
315315

316-
thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
317-
Cell::new(default_track_diagnostic));
316+
pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
317+
AtomicRef::new(&(default_track_diagnostic as fn(&_)));
318318

319319
#[derive(Copy, Clone, Default)]
320320
pub struct HandlerFlags {
@@ -734,9 +734,7 @@ impl HandlerInner {
734734
return;
735735
}
736736

737-
TRACK_DIAGNOSTICS.with(|track_diagnostics| {
738-
track_diagnostics.get()(diagnostic);
739-
});
737+
(*TRACK_DIAGNOSTICS)(diagnostic);
740738

741739
if let Some(ref code) = diagnostic.code {
742740
self.emitted_diagnostic_codes.insert(code.clone());

src/librustc_interface/callbacks.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//! Throughout the compiler tree, there are several places which want to have
2+
//! access to state or queries while being inside crates that are dependencies
3+
//! of librustc. To facilitate this, we have the
4+
//! `rustc_data_structures::AtomicRef` type, which allows us to setup a global
5+
//! static which can then be set in this file at program startup.
6+
//!
7+
//! See `SPAN_DEBUG` for an example of how to set things up.
8+
//!
9+
//! The functions in this file should fall back to the default set in their
10+
//! origin crate when the `TyCtxt` is not present in TLS.
11+
12+
use rustc::ty::tls;
13+
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
14+
use std::fmt;
15+
use syntax_pos;
16+
17+
/// This is a callback from libsyntax as it cannot access the implicit state
18+
/// in librustc otherwise.
19+
fn span_debug(span: syntax_pos::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
tls::with_opt(|tcx| {
21+
if let Some(tcx) = tcx {
22+
write!(f, "{}", tcx.sess.source_map().span_to_string(span))
23+
} else {
24+
syntax_pos::default_span_debug(span, f)
25+
}
26+
})
27+
}
28+
29+
/// This is a callback from libsyntax as it cannot access the implicit state
30+
/// in librustc otherwise. It is used to when diagnostic messages are
31+
/// emitted and stores them in the current query, if there is one.
32+
fn track_diagnostic(diagnostic: &Diagnostic) {
33+
tls::with_context_opt(|icx| {
34+
if let Some(icx) = icx {
35+
if let Some(ref diagnostics) = icx.diagnostics {
36+
let mut diagnostics = diagnostics.lock();
37+
diagnostics.extend(Some(diagnostic.clone()));
38+
}
39+
}
40+
})
41+
}
42+
43+
/// Sets up the callbacks in prior crates which we want to refer to the
44+
/// TyCtxt in.
45+
pub fn setup_callbacks() {
46+
syntax_pos::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
47+
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
48+
}

src/librustc_interface/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#[cfg(unix)]
1212
extern crate libc;
1313

14+
mod callbacks;
1415
pub mod interface;
1516
mod passes;
1617
mod proc_macro_decls;

src/librustc_interface/util.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,15 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
145145
cfg = cfg.stack_size(size);
146146
}
147147

148+
crate::callbacks::setup_callbacks();
149+
148150
scoped_thread(cfg, || {
149151
syntax::with_globals(edition, || {
150152
ty::tls::GCX_PTR.set(&Lock::new(0), || {
151153
if let Some(stderr) = stderr {
152154
io::set_panic(Some(box Sink(stderr.clone())));
153155
}
154-
ty::tls::with_thread_locals(|| f())
156+
f()
155157
})
156158
})
157159
})
@@ -167,6 +169,7 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
167169
use rayon::{ThreadBuilder, ThreadPool, ThreadPoolBuilder};
168170

169171
let gcx_ptr = &Lock::new(0);
172+
crate::callbacks::setup_callbacks();
170173

171174
let mut config = ThreadPoolBuilder::new()
172175
.thread_name(|_| "rustc".to_string())
@@ -194,9 +197,7 @@ pub fn spawn_thread_pool<F: FnOnce() -> R + Send, R: Send>(
194197
if let Some(stderr) = stderr {
195198
io::set_panic(Some(box Sink(stderr.clone())));
196199
}
197-
ty::tls::with_thread_locals(|| {
198-
ty::tls::GCX_PTR.set(gcx_ptr, || thread.run())
199-
})
200+
ty::tls::GCX_PTR.set(gcx_ptr, || thread.run())
200201
})
201202
})
202203
};

src/libsyntax_pos/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(specialization)]
1414
#![feature(step_trait)]
1515

16+
use rustc_data_structures::AtomicRef;
1617
use rustc_macros::HashStable_Generic;
1718
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
1819

@@ -41,7 +42,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
4142
use rustc_data_structures::sync::{Lock, Lrc};
4243

4344
use std::borrow::Cow;
44-
use std::cell::{Cell, RefCell};
45+
use std::cell::RefCell;
4546
use std::cmp::{self, Ordering};
4647
use std::fmt;
4748
use std::hash::{Hash, Hasher};
@@ -665,13 +666,13 @@ pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result
665666

666667
impl fmt::Debug for Span {
667668
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
668-
SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f))
669+
(*SPAN_DEBUG)(*self, f)
669670
}
670671
}
671672

672673
impl fmt::Debug for SpanData {
673674
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
674-
SPAN_DEBUG.with(|span_debug| span_debug.get()(Span::new(self.lo, self.hi, self.ctxt), f))
675+
(*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt), f)
675676
}
676677
}
677678

@@ -1503,8 +1504,8 @@ pub struct FileLines {
15031504
pub lines: Vec<LineInfo>,
15041505
}
15051506

1506-
thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
1507-
Cell::new(default_span_debug));
1507+
pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
1508+
AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
15081509

15091510
#[derive(Debug)]
15101511
pub struct MacroBacktrace {

0 commit comments

Comments
 (0)