Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4415,6 +4415,7 @@ dependencies = [
"rustc_expand",
"rustc_feature",
"rustc_fs_util",
"rustc_hashes",
"rustc_hir",
"rustc_hir_pretty",
"rustc_index",
Expand Down
60 changes: 56 additions & 4 deletions compiler/rustc_hir_id/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::fmt::{self, Write};
use std::hash::Hash;

use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hash::StableHasher;
use rustc_hashes::Hash64;
use rustc_index::IndexVec;
Expand Down Expand Up @@ -46,13 +47,55 @@ impl LocalDefIdMap<PerParentDisambiguatorState> {
}
}

#[derive(Debug, Default)]
pub struct DefPathToIndexMap {
/// Stores mapping from local hash to def indices which are allocated when the order
/// of their allocation is deterministic (see where `commit_end_of_determinism` is called,
/// at the moment of writing it is after prefetch of `hir_crate_items` in `run_required_analysis`).
pub before_parallel_alloc: DefPathHashMap,

/// Stores the same mapping as previous map but is used after the allocation order of def indices
/// is not deterministic, so when serializing metadata we have a ready to use sorted by stable local
/// hash (which does not change between compiler invocations) mapping. We use it for relatively small number
/// of definitions, so the majority of them would be stored in `DefPathHashMap`, which makes insertion
/// and serialization costs of `SortedMap` acceptable.
pub after_parallel_alloc: Option<SortedMap<Hash64, DefIndex>>,
}

impl DefPathToIndexMap {
#[inline]
pub fn get(&self, hash: Hash64) -> Option<DefIndex> {
self.before_parallel_alloc
.get(&hash)
.or_else(|| self.after_parallel_alloc.as_ref().and_then(|map| map.get(&hash).copied()))
}

/// This insert function does not behave like regular `insert` of a `HashMap`,
/// as the return value is used only for printing information about existing
/// def index for local hash before panicking. So we can do not actually insert
/// def index into `det_part` when we are in non-deterministic mode.
#[inline]
pub fn insert(&mut self, hash: Hash64, index: DefIndex) -> Option<DefIndex> {
match self.after_parallel_alloc.as_mut() {
None => self.before_parallel_alloc.insert(&hash, &index),
Some(map) => {
if let Some(existing) = self.before_parallel_alloc.get(&hash) {
return Some(existing);
}

map.insert(hash, index)
}
}
}
}

#[derive(Debug)]
pub struct Definitions {
stable_crate_id: StableCrateId,
def_id_to_key: IndexVec<LocalDefId, DefKey>,
// We do only store the local hash, as all the definitions are from the current crate.
def_path_hashes: IndexVec<LocalDefId, Hash64>,
def_path_hash_to_index: DefPathHashMap,
def_path_hash_to_index: DefPathToIndexMap,
}

/// A unique identifier that we can use to lookup a definition
Expand Down Expand Up @@ -249,6 +292,15 @@ pub enum DefPathData {
}

impl Definitions {
/// This function indicates that the order of def id allocations
/// may be non-deterministic after it was called.
pub fn commit_end_of_determinism(&mut self) {
assert!(
self.def_path_hash_to_index.after_parallel_alloc.replace(Default::default()).is_none(),
"this function should be called only once"
)
}

#[inline(always)]
pub fn def_key(&self, id: LocalDefId) -> DefKey {
self.def_id_to_key[id]
Expand Down Expand Up @@ -323,7 +375,7 @@ impl Definitions {
// Check for hash collisions of DefPathHashes. These should be
// exceedingly rare.
if let Some(existing) =
self.def_path_hash_to_index.insert(&local_hash, &def_id.local_def_index)
self.def_path_hash_to_index.insert(local_hash, def_id.local_def_index)
{
let def_path1 = self.def_path(LocalDefId { local_def_index: existing });
let def_path2 = self.def_path(def_id);
Expand Down Expand Up @@ -411,11 +463,11 @@ impl Definitions {
pub fn local_def_path_hash_to_def_id(&self, hash: DefPathHash) -> Option<LocalDefId> {
debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
self.def_path_hash_to_index
.get(&hash.local_hash())
.get(hash.local_hash())
.map(|local_def_index| LocalDefId { local_def_index })
}

pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
pub fn def_path_hash_to_def_index_map(&self) -> &DefPathToIndexMap {
&self.def_path_hash_to_index
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
// to use `hir_crate_items`.
tcx.ensure_done().hir_crate_items(());

tcx.untracked().definitions.write().commit_end_of_determinism();

rustc_passes::delegation::check_glob_and_list_delegations_target_expr(tcx);

let sess = tcx.sess;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hashes = { path = "../rustc_hashes" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_index = { path = "../rustc_index" }
Expand Down
34 changes: 25 additions & 9 deletions compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use rustc_data_structures::owned_slice::OwnedSlice;
use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_hashes::Hash64;
use rustc_hir::def_path_hash_map::Config as HashMapConfig;
use rustc_hir::definitions::DefPathToIndexMap;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::def_id::{DefIndex, DefPathHash};

use crate::rmeta::EncodeContext;
use crate::rmeta::decoder::BlobDecodeContext;

pub(crate) enum DefPathHashMapRef<'tcx> {
OwnedFromMetadata(odht::HashTable<HashMapConfig, OwnedSlice>),
BorrowedFromTcx(&'tcx DefPathHashMap),
OwnedFromMetadata(odht::HashTable<HashMapConfig, OwnedSlice>, SortedMap<Hash64, DefIndex>),
BorrowedFromTcx(&'tcx DefPathToIndexMap),
}

impl DefPathHashMapRef<'_> {
Expand All @@ -17,8 +20,11 @@ impl DefPathHashMapRef<'_> {
&self,
def_path_hash: &DefPathHash,
) -> Option<DefIndex> {
match *self {
DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(&def_path_hash.local_hash()),
match self {
DefPathHashMapRef::OwnedFromMetadata(det_map, non_det_map) => {
let hash = &def_path_hash.local_hash();
det_map.get(hash).or_else(|| non_det_map.get(hash).copied())
}
DefPathHashMapRef::BorrowedFromTcx(_) => {
panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization")
}
Expand All @@ -29,12 +35,18 @@ impl DefPathHashMapRef<'_> {
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
match *self {
DefPathHashMapRef::BorrowedFromTcx(def_path_hash_map) => {
let bytes = def_path_hash_map.raw_bytes();
DefPathHashMapRef::BorrowedFromTcx(map) => {
let bytes = map.before_parallel_alloc.raw_bytes();
e.emit_usize(bytes.len());
e.emit_raw_bytes(bytes);

map.after_parallel_alloc
.as_ref()
.expect("must be set before metadata encoding")
.range(..)
.encode(e);
}
DefPathHashMapRef::OwnedFromMetadata(_) => {
DefPathHashMapRef::OwnedFromMetadata(..) => {
panic!("DefPathHashMap::OwnedFromMetadata variant only exists for deserialization")
}
}
Expand All @@ -55,6 +67,10 @@ impl<'a> Decodable<BlobDecodeContext<'a>> for DefPathHashMapRef<'static> {
let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| {
panic!("decode error: {e}");
});
DefPathHashMapRef::OwnedFromMetadata(inner)

let elements = Vec::<(Hash64, DefIndex)>::decode(d);
let non_det_map = SortedMap::from_presorted_elements(elements);

DefPathHashMapRef::OwnedFromMetadata(inner, non_det_map)
}
}
4 changes: 1 addition & 3 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1377,9 +1377,7 @@ impl<'tcx> TyCtxt<'tcx> {
self.untracked.definitions.freeze()
}

pub fn def_path_hash_to_def_index_map(
self,
) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
pub fn def_path_hash_to_def_index_map(self) -> &'tcx rustc_hir::definitions::DefPathToIndexMap {
// Create a dependency to the crate to be sure we re-execute this when the amount of
// definitions change.
self.ensure_ok().hir_crate_items(());
Expand Down
Loading