Skip to content

Commit 7f940ef

Browse files
committed
Auto merge of rust-lang#72256 - ecstatic-morse:once-cell, r=Mark-Simulacrum
Use `once_cell` crate instead of custom data structure Internally, we use the [`Once`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/sync/struct.Once.html) type for shared data that is initialized exactly once and only read from afterwards. `Once` uses a `parking_lot::Mutex` when the parallel compiler is enabled and a `RefCell` when it is not. This PR switches to the [`once_cell`](https://crates.io/crates/once_cell) crate, which also uses a `parking_lot::Mutex` for its `sync` version (because we enable the `parking_lot` feature) but has zero overhead for its `unsync` one. This PR adds `once_cell` to the list of whitelisted dependencies. I think this is acceptable because it is already used in `rustc_driver`, is owned by a well-known community member (cc @matklad), and has a stable release. cc @rust-lang/compiler `once_cell` has a slightly more minimal API than `Once`, which allows for initialization to be either optimistic (evaluate the initializer and then synchronize) or pessimistic (synchronize and then evaluate the initializer). `once_cell`'s `get_or_init` is always pessimistic. The optimistic version is only used once in the current `master`. r? @Mark-Simulacrum
2 parents 215f2d3 + 307153e commit 7f940ef

File tree

43 files changed

+139
-249
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+139
-249
lines changed

Cargo.lock

+4
Original file line numberDiff line numberDiff line change
@@ -2327,6 +2327,9 @@ name = "once_cell"
23272327
version = "1.1.0"
23282328
source = "registry+https://github.com/rust-lang/crates.io-index"
23292329
checksum = "d6a04cb71e910d0034815600180f62a95bf6e67942d7ab52a166a68c7d7e9cd0"
2330+
dependencies = [
2331+
"parking_lot 0.9.0",
2332+
]
23302333

23312334
[[package]]
23322335
name = "opaque-debug"
@@ -3791,6 +3794,7 @@ dependencies = [
37913794
"libc",
37923795
"log",
37933796
"measureme",
3797+
"once_cell",
37943798
"parking_lot 0.10.2",
37953799
"rustc-hash",
37963800
"rustc-rayon",

src/librustc_ast_lowering/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ pub fn lower_crate<'a, 'hir>(
269269
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
270270

271271
LoweringContext {
272-
crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
272+
crate_root: sess.parse_sess.injected_crate_name.get().copied(),
273273
sess,
274274
resolver,
275275
nt_to_tokenstream,

src/librustc_codegen_llvm/context.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ pub unsafe fn create_module(
174174
llvm::LLVMRustSetModulePICLevel(llmod);
175175
// PIE is potentially more effective than PIC, but can only be used in executables.
176176
// If all our outputs are executables, then we can relax PIC to PIE.
177-
if sess.crate_types.get().iter().all(|ty| *ty == CrateType::Executable) {
177+
if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
178178
llvm::LLVMRustSetModulePIELevel(llmod);
179179
}
180180
}

src/librustc_codegen_ssa/back/link.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
5353
) {
5454
let _timer = sess.timer("link_binary");
5555
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
56-
for &crate_type in sess.crate_types.borrow().iter() {
56+
for &crate_type in sess.crate_types().iter() {
5757
// Ignore executable crates if we have -Z no-codegen, as they will error.
5858
if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen())
5959
&& !output_metadata
@@ -875,11 +875,8 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
875875

876876
// If we're only producing artifacts that are archives, no need to preserve
877877
// the objects as they're losslessly contained inside the archives.
878-
let output_linked = sess
879-
.crate_types
880-
.borrow()
881-
.iter()
882-
.any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
878+
let output_linked =
879+
sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
883880
if !output_linked {
884881
return false;
885882
}

src/librustc_codegen_ssa/back/linker.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ impl LinkerInfo {
4444
LinkerInfo {
4545
exports: tcx
4646
.sess
47-
.crate_types
48-
.borrow()
47+
.crate_types()
4948
.iter()
5049
.map(|&c| (c, exported_symbols(tcx, c)))
5150
.collect(),

src/librustc_codegen_ssa/back/symbol_export.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_middle::ty::{SymbolName, TyCtxt};
1818
use rustc_session::config::{CrateType, Sanitizer};
1919

2020
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
21-
crates_export_threshold(&tcx.sess.crate_types.borrow())
21+
crates_export_threshold(&tcx.sess.crate_types())
2222
}
2323

2424
fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
@@ -212,7 +212,7 @@ fn exported_symbols_provider_local(
212212
}));
213213
}
214214

215-
if tcx.sess.crate_types.borrow().contains(&CrateType::Dylib) {
215+
if tcx.sess.crate_types().contains(&CrateType::Dylib) {
216216
let symbol_name = metadata_symbol_name(tcx);
217217
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
218218

src/librustc_codegen_ssa/back/write.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ pub struct CompiledModules {
382382

383383
fn need_bitcode_in_object(sess: &Session) -> bool {
384384
let requested_for_rlib = sess.opts.cg.embed_bitcode
385-
&& sess.crate_types.borrow().contains(&CrateType::Rlib)
385+
&& sess.crate_types().contains(&CrateType::Rlib)
386386
&& sess.opts.output_types.contains_key(&OutputType::Exe);
387387
let forced_by_target = sess.target.target.options.forces_embed_bitcode;
388388
requested_for_rlib || forced_by_target
@@ -991,7 +991,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
991991
};
992992
let cgcx = CodegenContext::<B> {
993993
backend: backend.clone(),
994-
crate_types: sess.crate_types.borrow().clone(),
994+
crate_types: sess.crate_types().to_vec(),
995995
each_linked_rlib_for_lto,
996996
lto: sess.lto(),
997997
no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
@@ -1812,7 +1812,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
18121812
);
18131813

18141814
tcx.sess.target.target.options.is_like_msvc &&
1815-
tcx.sess.crate_types.borrow().iter().any(|ct| *ct == CrateType::Rlib) &&
1815+
tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
18161816
// ThinLTO can't handle this workaround in all cases, so we don't
18171817
// emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
18181818
// dynamic linking when linker plugin LTO is enabled.

src/librustc_codegen_ssa/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR
948948
match compute_per_cgu_lto_type(
949949
&tcx.sess.lto(),
950950
&tcx.sess.opts,
951-
&tcx.sess.crate_types.borrow(),
951+
&tcx.sess.crate_types(),
952952
ModuleKind::Regular,
953953
) {
954954
ComputedLtoType::No => CguReuse::PostLto,

src/librustc_data_structures/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ indexmap = "1"
1515
log = "0.4"
1616
jobserver_crate = { version = "0.1.13", package = "jobserver" }
1717
lazy_static = "1"
18+
once_cell = { version = "1", features = ["parking_lot"] }
1819
rustc_serialize = { path = "../libserialize", package = "serialize" }
1920
graphviz = { path = "../libgraphviz" }
2021
cfg-if = "0.1.2"

src/librustc_data_structures/sync.rs

+4-129
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
use crate::owning_ref::{Erased, OwningRef};
2121
use std::collections::HashMap;
2222
use std::hash::{BuildHasher, Hash};
23-
use std::marker::PhantomData;
2423
use std::ops::{Deref, DerefMut};
2524

2625
pub use std::sync::atomic::Ordering;
@@ -230,6 +229,8 @@ cfg_if! {
230229
pub use std::cell::RefMut as LockGuard;
231230
pub use std::cell::RefMut as MappedLockGuard;
232231

232+
pub use once_cell::unsync::OnceCell;
233+
233234
use std::cell::RefCell as InnerRwLock;
234235
use std::cell::RefCell as InnerLock;
235236

@@ -313,6 +314,8 @@ cfg_if! {
313314
pub use parking_lot::MutexGuard as LockGuard;
314315
pub use parking_lot::MappedMutexGuard as MappedLockGuard;
315316

317+
pub use once_cell::sync::OnceCell;
318+
316319
pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
317320

318321
pub use crossbeam_utils::atomic::AtomicCell;
@@ -432,134 +435,6 @@ impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S>
432435
}
433436
}
434437

435-
/// A type whose inner value can be written once and then will stay read-only
436-
// This contains a PhantomData<T> since this type conceptually owns a T outside the Mutex once
437-
// initialized. This ensures that Once<T> is Sync only if T is. If we did not have PhantomData<T>
438-
// we could send a &Once<Cell<bool>> to multiple threads and call `get` on it to get access
439-
// to &Cell<bool> on those threads.
440-
pub struct Once<T>(Lock<Option<T>>, PhantomData<T>);
441-
442-
impl<T> Once<T> {
443-
/// Creates an Once value which is uninitialized
444-
#[inline(always)]
445-
pub fn new() -> Self {
446-
Once(Lock::new(None), PhantomData)
447-
}
448-
449-
/// Consumes the value and returns Some(T) if it was initialized
450-
#[inline(always)]
451-
pub fn into_inner(self) -> Option<T> {
452-
self.0.into_inner()
453-
}
454-
455-
/// Tries to initialize the inner value to `value`.
456-
/// Returns `None` if the inner value was uninitialized and `value` was consumed setting it
457-
/// otherwise if the inner value was already set it returns `value` back to the caller
458-
#[inline]
459-
pub fn try_set(&self, value: T) -> Option<T> {
460-
let mut lock = self.0.lock();
461-
if lock.is_some() {
462-
return Some(value);
463-
}
464-
*lock = Some(value);
465-
None
466-
}
467-
468-
/// Tries to initialize the inner value to `value`.
469-
/// Returns `None` if the inner value was uninitialized and `value` was consumed setting it
470-
/// otherwise if the inner value was already set it asserts that `value` is equal to the inner
471-
/// value and then returns `value` back to the caller
472-
#[inline]
473-
pub fn try_set_same(&self, value: T) -> Option<T>
474-
where
475-
T: Eq,
476-
{
477-
let mut lock = self.0.lock();
478-
if let Some(ref inner) = *lock {
479-
assert!(*inner == value);
480-
return Some(value);
481-
}
482-
*lock = Some(value);
483-
None
484-
}
485-
486-
/// Tries to initialize the inner value to `value` and panics if it was already initialized
487-
#[inline]
488-
pub fn set(&self, value: T) {
489-
assert!(self.try_set(value).is_none());
490-
}
491-
492-
/// Initializes the inner value if it wasn't already done by calling the provided closure. It
493-
/// ensures that no-one else can access the value in the mean time by holding a lock for the
494-
/// duration of the closure.
495-
/// A reference to the inner value is returned.
496-
#[inline]
497-
pub fn init_locking<F: FnOnce() -> T>(&self, f: F) -> &T {
498-
{
499-
let mut lock = self.0.lock();
500-
if lock.is_none() {
501-
*lock = Some(f());
502-
}
503-
}
504-
505-
self.borrow()
506-
}
507-
508-
/// Tries to initialize the inner value by calling the closure without ensuring that no-one
509-
/// else can access it. This mean when this is called from multiple threads, multiple
510-
/// closures may concurrently be computing a value which the inner value should take.
511-
/// Only one of these closures are used to actually initialize the value.
512-
/// If some other closure already set the value,
513-
/// we return the value our closure computed wrapped in a `Option`.
514-
/// If our closure set the value, `None` is returned.
515-
/// If the value is already initialized, the closure is not called and `None` is returned.
516-
#[inline]
517-
pub fn init_nonlocking<F: FnOnce() -> T>(&self, f: F) -> Option<T> {
518-
if self.0.lock().is_some() { None } else { self.try_set(f()) }
519-
}
520-
521-
/// Tries to initialize the inner value by calling the closure without ensuring that no-one
522-
/// else can access it. This mean when this is called from multiple threads, multiple
523-
/// closures may concurrently be computing a value which the inner value should take.
524-
/// Only one of these closures are used to actually initialize the value.
525-
/// If some other closure already set the value, we assert that it our closure computed
526-
/// a value equal to the value already set and then
527-
/// we return the value our closure computed wrapped in a `Option`.
528-
/// If our closure set the value, `None` is returned.
529-
/// If the value is already initialized, the closure is not called and `None` is returned.
530-
#[inline]
531-
pub fn init_nonlocking_same<F: FnOnce() -> T>(&self, f: F) -> Option<T>
532-
where
533-
T: Eq,
534-
{
535-
if self.0.lock().is_some() { None } else { self.try_set_same(f()) }
536-
}
537-
538-
/// Tries to get a reference to the inner value, returns `None` if it is not yet initialized
539-
#[inline(always)]
540-
pub fn try_get(&self) -> Option<&T> {
541-
let lock = &*self.0.lock();
542-
if let Some(ref inner) = *lock {
543-
// This is safe since we won't mutate the inner value
544-
unsafe { Some(&*(inner as *const T)) }
545-
} else {
546-
None
547-
}
548-
}
549-
550-
/// Gets reference to the inner value, panics if it is not yet initialized
551-
#[inline(always)]
552-
pub fn get(&self) -> &T {
553-
self.try_get().expect("value was not set")
554-
}
555-
556-
/// Gets reference to the inner value, panics if it is not yet initialized
557-
#[inline(always)]
558-
pub fn borrow(&self) -> &T {
559-
self.get()
560-
}
561-
}
562-
563438
#[derive(Debug)]
564439
pub struct Lock<T>(InnerLock<T>);
565440

src/librustc_driver/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ impl RustcDefaultCalls {
586586
if let Input::File(file) = compiler.input() {
587587
// FIXME: #![crate_type] and #![crate_name] support not implemented yet
588588
let attrs = vec![];
589-
sess.crate_types.set(collect_crate_types(sess, &attrs));
589+
sess.init_crate_types(collect_crate_types(sess, &attrs));
590590
let outputs = compiler.build_output_filenames(&sess, &attrs);
591591
let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
592592
sess.fatal(&format!("failed to read rlink file: {}", err));

src/librustc_driver/pretty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ pub fn print_after_parsing(
396396
annotation.pp_ann(),
397397
false,
398398
parse.edition,
399-
parse.injected_crate_name.try_get().is_some(),
399+
parse.injected_crate_name.get().is_some(),
400400
)
401401
})
402402
} else {
@@ -438,7 +438,7 @@ pub fn print_after_hir_lowering<'tcx>(
438438
annotation.pp_ann(),
439439
true,
440440
parse.edition,
441-
parse.injected_crate_name.try_get().is_some(),
441+
parse.injected_crate_name.get().is_some(),
442442
)
443443
})
444444
}

0 commit comments

Comments
 (0)