1
Fork 0

Move ICH to rustc_query_system.

This commit is contained in:
Camille GILLOT 2020-11-14 16:35:31 +01:00
parent 2d38c53767
commit c355b2e5cd
11 changed files with 30 additions and 39 deletions

View file

@ -10,12 +10,16 @@ doctest = false
rustc_arena = { path = "../rustc_arena" }
tracing = "0.1"
rustc-rayon-core = "0.3.1"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_macros = { path = "../rustc_macros" }
rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
parking_lot = "0.11"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }

View file

@ -0,0 +1,209 @@
use crate::ich;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::definitions::{DefPathHash, Definitions};
use rustc_session::cstore::CrateStore;
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
ich::IGNORED_ATTRIBUTES.iter().copied().collect()
}
/// This is the context state available during incr. comp. hashing. It contains
/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
/// things (e.g., each `DefId`/`DefPath` is only hashed once).
#[derive(Clone)]
pub struct StableHashingContext<'a> {
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
pub(super) body_resolver: BodyResolver<'a>,
hash_spans: bool,
hash_bodies: bool,
pub(super) node_id_hashing_mode: NodeIdHashingMode,
// Very often, we are hashing something that does not need the
// `CachingSourceMapView`, so we initialize it lazily.
raw_source_map: &'a SourceMap,
caching_source_map: Option<CachingSourceMapView<'a>>,
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum NodeIdHashingMode {
Ignore,
HashDefPath,
}
/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
/// We could also just store a plain reference to the `hir::Crate` but we want
/// to avoid that the crate is used to get untracked access to all of the HIR.
#[derive(Clone, Copy)]
pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
impl<'tcx> BodyResolver<'tcx> {
/// Returns a reference to the `hir::Body` with the given `BodyId`.
/// **Does not do any tracking**; use carefully.
pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
self.0.body(id)
}
}
impl<'a> StableHashingContext<'a> {
/// The `krate` here is only used for mapping `BodyId`s to `Body`s.
/// Don't use it for anything else or you'll run the risk of
/// leaking data out of the tracking system.
#[inline]
fn new_with_or_without_spans(
sess: &'a Session,
krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
always_ignore_spans: bool,
) -> Self {
let hash_spans_initial =
!always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
StableHashingContext {
body_resolver: BodyResolver(krate),
definitions,
cstore,
caching_source_map: None,
raw_source_map: sess.source_map(),
hash_spans: hash_spans_initial,
hash_bodies: true,
node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
}
}
#[inline]
pub fn new(
sess: &'a Session,
krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
) -> Self {
Self::new_with_or_without_spans(
sess,
krate,
definitions,
cstore,
/*always_ignore_spans=*/ false,
)
}
#[inline]
pub fn ignore_spans(
sess: &'a Session,
krate: &'a hir::Crate<'a>,
definitions: &'a Definitions,
cstore: &'a dyn CrateStore,
) -> Self {
let always_ignore_spans = true;
Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
}
#[inline]
pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
let prev_hash_bodies = self.hash_bodies;
self.hash_bodies = hash_bodies;
f(self);
self.hash_bodies = prev_hash_bodies;
}
#[inline]
pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
let prev_hash_spans = self.hash_spans;
self.hash_spans = hash_spans;
f(self);
self.hash_spans = prev_hash_spans;
}
#[inline]
pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
&mut self,
mode: NodeIdHashingMode,
f: F,
) {
let prev = self.node_id_hashing_mode;
self.node_id_hashing_mode = mode;
f(self);
self.node_id_hashing_mode = prev;
}
#[inline]
pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
if let Some(def_id) = def_id.as_local() {
self.local_def_path_hash(def_id)
} else {
self.cstore.def_path_hash(def_id)
}
}
#[inline]
pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
self.definitions.def_path_hash(def_id)
}
#[inline]
pub fn hash_bodies(&self) -> bool {
self.hash_bodies
}
#[inline]
pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
match self.caching_source_map {
Some(ref mut sm) => sm,
ref mut none => {
*none = Some(CachingSourceMapView::new(self.raw_source_map));
none.as_mut().unwrap()
}
}
}
#[inline]
pub fn is_ignored_attr(&self, name: Symbol) -> bool {
thread_local! {
static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
}
IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
}
}
impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
panic!("Node IDs should not appear in incremental state");
}
}
impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
fn hash_spans(&self) -> bool {
self.hash_spans
}
#[inline]
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
self.def_path_hash(def_id)
}
#[inline]
fn def_span(&self, def_id: LocalDefId) -> Span {
self.definitions.def_span(def_id)
}
fn span_data_to_lines_and_cols(
&mut self,
span: &SpanData,
) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
self.source_map().span_data_to_lines_and_cols(span)
}
}
impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}

View file

@ -0,0 +1,150 @@
//! This module contains `HashStable` implementations for various HIR data
//! types in no particular order.
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_hir as hir;
use rustc_hir::definitions::DefPathHash;
use smallvec::SmallVec;
use std::mem;
impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
#[inline]
fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
let hcx = self;
match hcx.node_id_hashing_mode {
NodeIdHashingMode::Ignore => {
// Don't do anything.
}
NodeIdHashingMode::HashDefPath => {
let hir::HirId { owner, local_id } = hir_id;
hcx.local_def_path_hash(owner).hash_stable(hcx, hasher);
local_id.hash_stable(hcx, hasher);
}
}
}
fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
let hcx = self;
if hcx.hash_bodies() {
hcx.body_resolver.body(id).hash_stable(hcx, hasher);
}
}
fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) {
let hcx = self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
id.hash_stable(hcx, hasher);
})
}
fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) {
let hcx = self;
let hir::Mod { inner: ref inner_span, ref item_ids } = *module;
inner_span.hash_stable(hcx, hasher);
// Combining the `DefPathHash`s directly is faster than feeding them
// into the hasher. Because we use a commutative combine, we also don't
// have to sort the array.
let item_ids_hash = item_ids
.iter()
.map(|id| {
let def_path_hash = id.to_stable_hash_key(hcx);
def_path_hash.0
})
.fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b));
item_ids.len().hash_stable(hcx, hasher);
item_ids_hash.hash_stable(hcx, hasher);
}
fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
self.while_hashing_hir_bodies(true, |hcx| {
let hir::Expr { hir_id: _, ref span, ref kind } = *expr;
span.hash_stable(hcx, hasher);
kind.hash_stable(hcx, hasher);
})
}
fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) {
self.while_hashing_hir_bodies(true, |hcx| {
let hir::Ty { hir_id: _, ref kind, ref span } = *ty;
kind.hash_stable(hcx, hasher);
span.hash_stable(hcx, hasher);
})
}
fn hash_hir_visibility_kind(
&mut self,
vis: &hir::VisibilityKind<'_>,
hasher: &mut StableHasher,
) {
let hcx = self;
mem::discriminant(vis).hash_stable(hcx, hasher);
match *vis {
hir::VisibilityKind::Public | hir::VisibilityKind::Inherited => {
// No fields to hash.
}
hir::VisibilityKind::Crate(sugar) => {
sugar.hash_stable(hcx, hasher);
}
hir::VisibilityKind::Restricted { ref path, hir_id } => {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
hir_id.hash_stable(hcx, hasher);
});
path.hash_stable(hcx, hasher);
}
}
}
fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
let prev_hash_node_ids = self.node_id_hashing_mode;
self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
f(self);
self.node_id_hashing_mode = prev_hash_node_ids;
}
}
impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let hir::Body { params, value, generator_kind } = self;
hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| {
params.hash_stable(hcx, hasher);
value.hash_stable(hcx, hasher);
generator_kind.hash_stable(hcx, hasher);
});
}
}
impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
let hir::TraitCandidate { def_id, import_ids } = self;
def_id.hash_stable(hcx, hasher);
import_ids.hash_stable(hcx, hasher);
});
}
}
impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
let hir::TraitCandidate { def_id, import_ids } = self;
(
hcx.def_path_hash(*def_id),
import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
)
}
}

View file

@ -0,0 +1,146 @@
//! This module contains `HashStable` implementations for various data types
//! from `rustc_ast` in no particular order.
use crate::ich::StableHashingContext;
use rustc_ast as ast;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_span::{BytePos, NormalizedPos, SourceFile};
use std::assert_matches::assert_matches;
use smallvec::SmallVec;
impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}
impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
if self.is_empty() {
self.len().hash_stable(hcx, hasher);
return;
}
// Some attributes are always ignored during hashing.
let filtered: SmallVec<[&ast::Attribute; 8]> = self
.iter()
.filter(|attr| {
!attr.is_doc_comment()
&& !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))
})
.collect();
filtered.len().hash_stable(hcx, hasher);
for attr in filtered {
attr.hash_stable(hcx, hasher);
}
}
}
impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {
fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) {
// Make sure that these have been filtered out.
debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name)));
debug_assert!(!attr.is_doc_comment());
let ast::Attribute { kind, id: _, style, span } = attr;
if let ast::AttrKind::Normal(item, tokens) = kind {
item.hash_stable(self, hasher);
style.hash_stable(self, hasher);
span.hash_stable(self, hasher);
assert_matches!(
tokens.as_ref(),
None,
"Tokens should have been removed during lowering!"
);
} else {
unreachable!();
}
}
}
impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let SourceFile {
name: _, // We hash the smaller name_hash instead of this
name_hash,
cnum,
// Do not hash the source as it is not encoded
src: _,
ref src_hash,
external_src: _,
start_pos,
end_pos: _,
ref lines,
ref multibyte_chars,
ref non_narrow_chars,
ref normalized_pos,
} = *self;
(name_hash as u64).hash_stable(hcx, hasher);
src_hash.hash_stable(hcx, hasher);
// We only hash the relative position within this source_file
lines.len().hash_stable(hcx, hasher);
for &line in lines.iter() {
stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
}
// We only hash the relative position within this source_file
multibyte_chars.len().hash_stable(hcx, hasher);
for &char_pos in multibyte_chars.iter() {
stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher);
}
non_narrow_chars.len().hash_stable(hcx, hasher);
for &char_pos in non_narrow_chars.iter() {
stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
}
normalized_pos.len().hash_stable(hcx, hasher);
for &char_pos in normalized_pos.iter() {
stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher);
}
cnum.hash_stable(hcx, hasher);
}
}
fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 {
pos.0 - source_file_start.0
}
fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) {
let rustc_span::MultiByteChar { pos, bytes } = mbc;
(pos.0 - source_file_start.0, bytes as u32)
}
fn stable_non_narrow_char(
swc: rustc_span::NonNarrowChar,
source_file_start: BytePos,
) -> (u32, u32) {
let pos = swc.pos();
let width = swc.width();
(pos.0 - source_file_start.0, width as u32)
}
fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) {
let NormalizedPos { pos, diff } = np;
(pos.0 - source_file_start.0, diff)
}
impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
// Unfortunately we cannot exhaustively list fields here, since the
// struct is macro generated.
self.declared_lang_features.hash_stable(hcx, hasher);
self.declared_lib_features.hash_stable(hcx, hasher);
self.walk_feature_fields(|feature_name, value| {
feature_name.hash_stable(hcx, hasher);
value.hash_stable(hcx, hasher);
});
}
}

View file

@ -0,0 +1,19 @@
//! ICH - Incremental Compilation Hash
pub use self::hcx::{NodeIdHashingMode, StableHashingContext};
use rustc_span::symbol::{sym, Symbol};
mod hcx;
mod impls_hir;
mod impls_syntax;
pub const IGNORED_ATTRIBUTES: &[Symbol] = &[
sym::cfg,
sym::rustc_if_this_changed,
sym::rustc_then_this_would_need,
sym::rustc_dirty,
sym::rustc_clean,
sym::rustc_partition_reused,
sym::rustc_partition_codegened,
sym::rustc_expected_cgu_reuse,
];

View file

@ -1,3 +1,4 @@
#![feature(assert_matches)]
#![feature(bool_to_option)]
#![feature(core_intrinsics)]
#![feature(hash_raw_entry)]
@ -14,4 +15,5 @@ extern crate rustc_macros;
pub mod cache;
pub mod dep_graph;
pub mod ich;
pub mod query;