From 9faa31612fb7a847a1c85836996846b9a6f20116 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 7 Dec 2017 16:46:31 +0100 Subject: [PATCH 1/2] incr.comp.: Speed up span hashing by caching expansion context hashes. --- src/librustc/ich/hcx.rs | 31 ++++++++++++++++++++++++++++--- src/libsyntax_pos/hygiene.rs | 9 +++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 0ef42177c14a8..2d20836814c8f 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -12,7 +12,7 @@ use hir; use hir::def_id::{DefId, DefIndex}; use hir::map::DefPathHash; use hir::map::definitions::Definitions; -use ich::{self, CachingCodemapView}; +use ich::{self, CachingCodemapView, Fingerprint}; use middle::cstore::CrateStore; use ty::{TyCtxt, fast_reject}; use session::Session; @@ -28,12 +28,13 @@ use syntax::codemap::CodeMap; use syntax::ext::hygiene::SyntaxContext; use syntax::symbol::Symbol; use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::hygiene; use rustc_data_structures::stable_hasher::{HashStable, StableHashingContextProvider, StableHasher, StableHasherResult, ToStableHashKey}; use rustc_data_structures::accumulate_vec::AccumulateVec; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; thread_local!(static IGNORED_ATTR_NAMES: RefCell> = RefCell::new(FxHashSet())); @@ -349,7 +350,31 @@ impl<'gcx> HashStable> for Span { TAG_NO_EXPANSION.hash_stable(hcx, hasher); } else { TAG_EXPANSION.hash_stable(hcx, hasher); - span.ctxt.outer().expn_info().hash_stable(hcx, hasher); + + // Since the same expansion context is usually referenced many + // times, we cache a stable hash of it and hash that instead of + // recursing every time. + thread_local! { + static CACHE: RefCell> = + RefCell::new(FxHashMap()); + } + + let sub_hash: u64 = CACHE.with(|cache| { + let mark = span.ctxt.outer(); + + if let Some(&sub_hash) = cache.borrow().get(&mark) { + return sub_hash; + } + + let mut hasher = StableHasher::new(); + mark.expn_info().hash_stable(hcx, &mut hasher); + let sub_hash: Fingerprint = hasher.finish(); + let sub_hash = sub_hash.to_smaller_hash(); + cache.borrow_mut().insert(mark, sub_hash); + sub_hash + }); + + sub_hash.hash_stable(hcx, hasher); } } } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index ab6c3f7d62d76..55342c2768a0e 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -60,22 +60,27 @@ impl Mark { } /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST. + #[inline] pub fn root() -> Self { Mark(0) } + #[inline] pub fn as_u32(self) -> u32 { self.0 } + #[inline] pub fn from_u32(raw: u32) -> Mark { Mark(raw) } + #[inline] pub fn expn_info(self) -> Option { HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone()) } + #[inline] pub fn set_expn_info(self, info: ExpnInfo) { HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info)) } @@ -91,10 +96,12 @@ impl Mark { }) } + #[inline] pub fn kind(self) -> MarkKind { HygieneData::with(|data| data.marks[self.0 as usize].kind) } + #[inline] pub fn set_kind(self, kind: MarkKind) { HygieneData::with(|data| data.marks[self.0 as usize].kind = kind) } @@ -309,10 +316,12 @@ impl SyntaxContext { Some(scope) } + #[inline] pub fn modern(self) -> SyntaxContext { HygieneData::with(|data| data.syntax_contexts[self.0 as usize].modern) } + #[inline] pub fn outer(self) -> Mark { HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) } From 0b4c2cccac30ebcd436e0cfd77b34019c40d4ce3 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 8 Dec 2017 17:07:48 +0100 Subject: [PATCH 2/2] incr.comp.: Do less hashing per Span. --- src/librustc/ich/hcx.rs | 15 ++++--- src/librustc/ich/impls_syntax.rs | 2 + src/librustc/ty/maps/on_disk_cache.rs | 2 +- src/librustc_metadata/decoder.rs | 2 + src/libsyntax/codemap.rs | 26 ++----------- src/libsyntax_pos/lib.rs | 56 +++++++++++++++++++++------ 6 files changed, 62 insertions(+), 41 deletions(-) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 2d20836814c8f..f9fb668110b10 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -338,13 +338,16 @@ impl<'gcx> HashStable> for Span { return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); } - let len = span.hi - span.lo; - std_hash::Hash::hash(&TAG_VALID_SPAN, hasher); - std_hash::Hash::hash(&file_lo.name, hasher); - std_hash::Hash::hash(&line_lo, hasher); - std_hash::Hash::hash(&col_lo, hasher); - std_hash::Hash::hash(&len, hasher); + // We truncate the stable_id hash and line and col numbers. The chances + // of causing a collision this way should be minimal. + std_hash::Hash::hash(&(file_lo.stable_id.0 as u64), hasher); + + let col = (col_lo.0 as u64) & 0xFF; + let line = ((line_lo as u64) & 0xFF_FF_FF) << 8; + let len = ((span.hi - span.lo).0 as u64) << 32; + let line_col_len = col | line | len; + std_hash::Hash::hash(&line_col_len, hasher); if span.ctxt == SyntaxContext::empty() { TAG_NO_EXPANSION.hash_stable(hcx, hasher); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c25aa10eb1e73..dfb90a5d27feb 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -394,6 +394,8 @@ impl<'gcx> HashStable> for FileMap { // Do not hash the source as it is not encoded src: _, src_hash, + // The stable id is just a hash of other fields + stable_id: _, external_src: _, start_pos, end_pos: _, diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 079b518efd898..7d583a3547739 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -176,7 +176,7 @@ impl<'sess> OnDiskCache<'sess> { let index = FileMapIndex(index as u32); let file_ptr: *const FileMap = &**file as *const _; file_to_file_index.insert(file_ptr, index); - file_index_to_stable_id.insert(index, StableFilemapId::new(&file)); + file_index_to_stable_id.insert(index, file.stable_id); } (file_to_file_index, file_index_to_stable_id) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 49a017535ffd1..aa7eee366d29b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1124,6 +1124,7 @@ impl<'a, 'tcx> CrateMetadata { let syntax_pos::FileMap { name, name_was_remapped, src_hash, + stable_id, start_pos, end_pos, lines, @@ -1155,6 +1156,7 @@ impl<'a, 'tcx> CrateMetadata { name_was_remapped, self.cnum.as_u32(), src_hash, + stable_id, source_length, lines, multibyte_chars, diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2c91d60ce9d59..07bba29ca4b04 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -23,9 +23,7 @@ pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; pub use self::ExpnFormat::*; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::StableHasher; use std::cell::{RefCell, Ref}; -use std::hash::Hash; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -102,24 +100,6 @@ impl FileLoader for RealFileLoader { } } -// This is a FileMap identifier that is used to correlate FileMaps between -// subsequent compilation sessions (which is something we need to do during -// incremental compilation). -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] -pub struct StableFilemapId(u128); - -impl StableFilemapId { - pub fn new(filemap: &FileMap) -> StableFilemapId { - let mut hasher = StableHasher::new(); - - filemap.name.hash(&mut hasher); - filemap.name_was_remapped.hash(&mut hasher); - filemap.unmapped_path.hash(&mut hasher); - - StableFilemapId(hasher.finish()) - } -} - // _____________________________________________________________________________ // CodeMap // @@ -217,7 +197,7 @@ impl CodeMap { self.stable_id_to_filemap .borrow_mut() - .insert(StableFilemapId::new(&filemap), filemap.clone()); + .insert(filemap.stable_id, filemap.clone()); filemap } @@ -246,6 +226,7 @@ impl CodeMap { name_was_remapped: bool, crate_of_origin: u32, src_hash: u128, + stable_id: StableFilemapId, source_len: usize, mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec, @@ -276,6 +257,7 @@ impl CodeMap { crate_of_origin, src: None, src_hash, + stable_id, external_src: RefCell::new(ExternalSource::AbsentOk), start_pos, end_pos, @@ -288,7 +270,7 @@ impl CodeMap { self.stable_id_to_filemap .borrow_mut() - .insert(StableFilemapId::new(&filemap), filemap.clone()); + .insert(stable_id, filemap.clone()); filemap } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 2a3812516632a..c3d2f0de21dcd 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -678,6 +678,8 @@ pub struct FileMap { pub src: Option>, /// The source code's hash pub src_hash: u128, + /// The stable id used during incr. comp. + pub stable_id: StableFilemapId, /// The external source code (used for external crates, which will have a `None` /// value as `self.src`. pub external_src: RefCell, @@ -693,15 +695,37 @@ pub struct FileMap { pub non_narrow_chars: RefCell>, } +// This is a FileMap identifier that is used to correlate FileMaps between +// subsequent compilation sessions (which is something we need to do during +// incremental compilation). +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +pub struct StableFilemapId(pub u128); + +impl StableFilemapId { + pub fn new(name: &FileName, + name_was_remapped: bool, + unmapped_path: &FileName) + -> StableFilemapId { + use std::hash::Hash; + + let mut hasher = StableHasher::new(); + name.hash(&mut hasher); + name_was_remapped.hash(&mut hasher); + unmapped_path.hash(&mut hasher); + StableFilemapId(hasher.finish()) + } +} + impl Encodable for FileMap { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_struct("FileMap", 8, |s| { s.emit_struct_field("name", 0, |s| self.name.encode(s))?; s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?; - s.emit_struct_field("src_hash", 6, |s| self.src_hash.encode(s))?; - s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?; - s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?; - s.emit_struct_field("lines", 4, |s| { + s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?; + s.emit_struct_field("stable_id", 3, |s| self.stable_id.encode(s))?; + s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?; + s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?; + s.emit_struct_field("lines", 6, |s| { let lines = self.lines.borrow(); // store the length s.emit_u32(lines.len() as u32)?; @@ -747,10 +771,10 @@ impl Encodable for FileMap { Ok(()) })?; - s.emit_struct_field("multibyte_chars", 5, |s| { + s.emit_struct_field("multibyte_chars", 7, |s| { (*self.multibyte_chars.borrow()).encode(s) })?; - s.emit_struct_field("non_narrow_chars", 7, |s| { + s.emit_struct_field("non_narrow_chars", 8, |s| { (*self.non_narrow_chars.borrow()).encode(s) }) }) @@ -765,11 +789,13 @@ impl Decodable for FileMap { let name_was_remapped: bool = d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?; let src_hash: u128 = - d.read_struct_field("src_hash", 6, |d| Decodable::decode(d))?; + d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?; + let stable_id: StableFilemapId = + d.read_struct_field("stable_id", 3, |d| Decodable::decode(d))?; let start_pos: BytePos = - d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?; - let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?; - let lines: Vec = d.read_struct_field("lines", 4, |d| { + d.read_struct_field("start_pos", 4, |d| Decodable::decode(d))?; + let end_pos: BytePos = d.read_struct_field("end_pos", 5, |d| Decodable::decode(d))?; + let lines: Vec = d.read_struct_field("lines", 6, |d| { let num_lines: u32 = Decodable::decode(d)?; let mut lines = Vec::with_capacity(num_lines as usize); @@ -798,9 +824,9 @@ impl Decodable for FileMap { Ok(lines) })?; let multibyte_chars: Vec = - d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?; + d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?; let non_narrow_chars: Vec = - d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?; + d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?; Ok(FileMap { name, name_was_remapped, @@ -813,6 +839,7 @@ impl Decodable for FileMap { end_pos, src: None, src_hash, + stable_id, external_src: RefCell::new(ExternalSource::AbsentOk), lines: RefCell::new(lines), multibyte_chars: RefCell::new(multibyte_chars), @@ -840,6 +867,10 @@ impl FileMap { hasher.write(src.as_bytes()); let src_hash = hasher.finish(); + let stable_id = StableFilemapId::new(&name, + name_was_remapped, + &unmapped_path); + let end_pos = start_pos.to_usize() + src.len(); FileMap { @@ -849,6 +880,7 @@ impl FileMap { crate_of_origin: 0, src: Some(Rc::new(src)), src_hash, + stable_id, external_src: RefCell::new(ExternalSource::Unneeded), start_pos, end_pos: Pos::from_usize(end_pos),