Skip to content

Commit 43af481

Browse files
committed
Add a AtomicOnce type
1 parent ac51008 commit 43af481

File tree

2 files changed

+36
-15
lines changed

2 files changed

+36
-15
lines changed

src/librustc/ty/context.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,8 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
5050
StableHasher, StableHasherResult,
5151
StableVec};
5252
use arena::{TypedArena, SyncDroplessArena};
53-
use rustc_data_structures::cold_path;
5453
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
55-
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicCell};
54+
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicOnce};
5655
use std::any::Any;
5756
use std::borrow::Borrow;
5857
use std::cmp::Ordering;
@@ -1031,7 +1030,7 @@ pub struct GlobalCtxt<'tcx> {
10311030

10321031
pub hir_defs: hir::map::Definitions,
10331032

1034-
hir_map: AtomicCell<Option<&'tcx hir_map::Map<'tcx>>>,
1033+
hir_map: AtomicOnce<&'tcx hir_map::Map<'tcx>>,
10351034

10361035
/// A map from DefPathHash -> DefId. Includes DefIds from the local crate
10371036
/// as well as all upstream crates. Only populated in incremental mode.
@@ -1104,18 +1103,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11041103
}
11051104

11061105
#[inline(always)]
1107-
pub fn hir(self) -> &'a hir_map::Map<'gcx> {
1108-
let value = self.hir_map.load();
1109-
if unlikely!(value.is_none()) {
1106+
pub fn hir(self) -> &'gcx hir_map::Map<'gcx> {
1107+
self.hir_map.get_or_init(|| {
11101108
// We can use `with_ignore` here because the hir map does its own tracking
1111-
cold_path(|| self.dep_graph.with_ignore(|| {
1112-
let map = self.hir_map(LOCAL_CRATE);
1113-
self.hir_map.store(Some(map));
1114-
map
1115-
}))
1116-
} else {
1117-
value.unwrap()
1118-
}
1109+
self.dep_graph.with_ignore(|| self.hir_map(LOCAL_CRATE))
1110+
})
11191111
}
11201112

11211113
pub fn alloc_generics(self, generics: ty::Generics) -> &'gcx ty::Generics {
@@ -1307,7 +1299,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
13071299
extern_prelude: resolutions.extern_prelude,
13081300
hir_forest,
13091301
hir_defs,
1310-
hir_map: AtomicCell::new(None),
1302+
hir_map: AtomicOnce::new(),
13111303
def_path_hash_to_def_id,
13121304
queries: query::Queries::new(
13131305
providers,

src/librustc_data_structures/sync.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::collections::HashMap;
2121
use std::hash::{Hash, BuildHasher};
2222
use std::marker::PhantomData;
2323
use std::ops::{Deref, DerefMut};
24+
use crate::cold_path;
2425
use crate::owning_ref::{Erased, OwningRef};
2526

2627
pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
@@ -573,6 +574,34 @@ impl<T> Once<T> {
573574
}
574575
}
575576

577+
/// A type whose inner value can be written once and then will stay read-only
578+
pub struct AtomicOnce<T: Copy>(AtomicCell<Option<T>>);
579+
580+
impl<T: Copy> AtomicOnce<T> {
581+
/// Creates an AtomicOnce value which is uninitialized
582+
#[inline]
583+
pub fn new() -> Self {
584+
AtomicOnce(AtomicCell::new(None))
585+
}
586+
587+
/// Gets the inner value. If the value is not already initalized.
588+
/// It will be initalized by the closure. The closure may be called
589+
/// concurrently by many threads.
590+
#[inline(always)]
591+
pub fn get_or_init(&self, f: impl FnOnce() -> T) -> T {
592+
let value = self.0.load();
593+
if unlikely!(value.is_none()) {
594+
cold_path(|| {
595+
let value = f();
596+
self.0.store(Some(value));
597+
value
598+
})
599+
} else {
600+
value.unwrap()
601+
}
602+
}
603+
}
604+
576605
#[derive(Debug)]
577606
pub struct Lock<T>(InnerLock<T>);
578607

0 commit comments

Comments
 (0)