Skip to content

Commit d5fbdd2

Browse files
committed
Add a AtomicOnce type
1 parent 0ca5730 commit d5fbdd2

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

src/librustc/ty/context.rs

+6-14
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,8 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
5252
StableHasher, StableHasherResult,
5353
StableVec};
5454
use arena::SyncDroplessArena;
55-
use rustc_data_structures::cold_path;
5655
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
57-
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicCell};
56+
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal, AtomicOnce};
5857
use std::any::Any;
5958
use std::borrow::Borrow;
6059
use std::cmp::Ordering;
@@ -1022,7 +1021,7 @@ pub struct GlobalCtxt<'tcx> {
10221021

10231022
pub hir_defs: hir::map::Definitions,
10241023

1025-
hir_map: AtomicCell<Option<&'tcx hir_map::Map<'tcx>>>,
1024+
hir_map: AtomicOnce<&'tcx hir_map::Map<'tcx>>,
10261025

10271026
/// A map from DefPathHash -> DefId. Includes DefIds from the local crate
10281027
/// as well as all upstream crates. Only populated in incremental mode.
@@ -1089,17 +1088,10 @@ impl<'tcx> TyCtxt<'tcx> {
10891088

10901089
#[inline(always)]
10911090
pub fn hir(self) -> &'tcx hir_map::Map<'tcx> {
1092-
let value = self.hir_map.load();
1093-
if unlikely!(value.is_none()) {
1091+
self.hir_map.get_or_init(|| {
10941092
// We can use `with_ignore` here because the hir map does its own tracking
1095-
cold_path(|| self.dep_graph.with_ignore(|| {
1096-
let map = self.hir_map(LOCAL_CRATE);
1097-
self.hir_map.store(Some(map));
1098-
map
1099-
}))
1100-
} else {
1101-
value.unwrap()
1102-
}
1093+
self.dep_graph.with_ignore(|| self.hir_map(LOCAL_CRATE))
1094+
})
11031095
}
11041096

11051097
pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal<Body<'tcx>> {
@@ -1281,7 +1273,7 @@ impl<'tcx> TyCtxt<'tcx> {
12811273
extern_prelude: resolutions.extern_prelude,
12821274
hir_forest,
12831275
hir_defs,
1284-
hir_map: AtomicCell::new(None),
1276+
hir_map: AtomicOnce::new(),
12851277
def_path_hash_to_def_id,
12861278
queries: query::Queries::new(
12871279
providers,

src/librustc_data_structures/sync.rs

+29
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)