Skip to content

Commit 3fc7f85

Browse files
committed
Auto merge of #46562 - michaelwoerister:faster-span-hashing, r=eddyb
incr.comp.: Speed up span hashing by caching expansion context hashes. This PR fixes the performance regressions from #46338. r? @nikomatsakis
2 parents 2974104 + 0b4c2cc commit 3fc7f85

File tree

7 files changed

+99
-44
lines changed

7 files changed

+99
-44
lines changed

src/librustc/ich/hcx.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use hir;
1212
use hir::def_id::{DefId, DefIndex};
1313
use hir::map::DefPathHash;
1414
use hir::map::definitions::Definitions;
15-
use ich::{self, CachingCodemapView};
15+
use ich::{self, CachingCodemapView, Fingerprint};
1616
use middle::cstore::CrateStore;
1717
use ty::{TyCtxt, fast_reject};
1818
use session::Session;
@@ -28,12 +28,13 @@ use syntax::codemap::CodeMap;
2828
use syntax::ext::hygiene::SyntaxContext;
2929
use syntax::symbol::Symbol;
3030
use syntax_pos::{Span, DUMMY_SP};
31+
use syntax_pos::hygiene;
3132

3233
use rustc_data_structures::stable_hasher::{HashStable, StableHashingContextProvider,
3334
StableHasher, StableHasherResult,
3435
ToStableHashKey};
3536
use rustc_data_structures::accumulate_vec::AccumulateVec;
36-
use rustc_data_structures::fx::FxHashSet;
37+
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
3738

3839
thread_local!(static IGNORED_ATTR_NAMES: RefCell<FxHashSet<Symbol>> =
3940
RefCell::new(FxHashSet()));
@@ -337,19 +338,46 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
337338
return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
338339
}
339340

340-
let len = span.hi - span.lo;
341-
342341
std_hash::Hash::hash(&TAG_VALID_SPAN, hasher);
343-
std_hash::Hash::hash(&file_lo.name, hasher);
344-
std_hash::Hash::hash(&line_lo, hasher);
345-
std_hash::Hash::hash(&col_lo, hasher);
346-
std_hash::Hash::hash(&len, hasher);
342+
// We truncate the stable_id hash and line and col numbers. The chances
343+
// of causing a collision this way should be minimal.
344+
std_hash::Hash::hash(&(file_lo.stable_id.0 as u64), hasher);
345+
346+
let col = (col_lo.0 as u64) & 0xFF;
347+
let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
348+
let len = ((span.hi - span.lo).0 as u64) << 32;
349+
let line_col_len = col | line | len;
350+
std_hash::Hash::hash(&line_col_len, hasher);
347351

348352
if span.ctxt == SyntaxContext::empty() {
349353
TAG_NO_EXPANSION.hash_stable(hcx, hasher);
350354
} else {
351355
TAG_EXPANSION.hash_stable(hcx, hasher);
352-
span.ctxt.outer().expn_info().hash_stable(hcx, hasher);
356+
357+
// Since the same expansion context is usually referenced many
358+
// times, we cache a stable hash of it and hash that instead of
359+
// recursing every time.
360+
thread_local! {
361+
static CACHE: RefCell<FxHashMap<hygiene::Mark, u64>> =
362+
RefCell::new(FxHashMap());
363+
}
364+
365+
let sub_hash: u64 = CACHE.with(|cache| {
366+
let mark = span.ctxt.outer();
367+
368+
if let Some(&sub_hash) = cache.borrow().get(&mark) {
369+
return sub_hash;
370+
}
371+
372+
let mut hasher = StableHasher::new();
373+
mark.expn_info().hash_stable(hcx, &mut hasher);
374+
let sub_hash: Fingerprint = hasher.finish();
375+
let sub_hash = sub_hash.to_smaller_hash();
376+
cache.borrow_mut().insert(mark, sub_hash);
377+
sub_hash
378+
});
379+
380+
sub_hash.hash_stable(hcx, hasher);
353381
}
354382
}
355383
}

src/librustc/ich/impls_syntax.rs

+2
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for FileMap {
394394
// Do not hash the source as it is not encoded
395395
src: _,
396396
src_hash,
397+
// The stable id is just a hash of other fields
398+
stable_id: _,
397399
external_src: _,
398400
start_pos,
399401
end_pos: _,

src/librustc/ty/maps/on_disk_cache.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl<'sess> OnDiskCache<'sess> {
176176
let index = FileMapIndex(index as u32);
177177
let file_ptr: *const FileMap = &**file as *const _;
178178
file_to_file_index.insert(file_ptr, index);
179-
file_index_to_stable_id.insert(index, StableFilemapId::new(&file));
179+
file_index_to_stable_id.insert(index, file.stable_id);
180180
}
181181

182182
(file_to_file_index, file_index_to_stable_id)

src/librustc_metadata/decoder.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,7 @@ impl<'a, 'tcx> CrateMetadata {
11241124
let syntax_pos::FileMap { name,
11251125
name_was_remapped,
11261126
src_hash,
1127+
stable_id,
11271128
start_pos,
11281129
end_pos,
11291130
lines,
@@ -1155,6 +1156,7 @@ impl<'a, 'tcx> CrateMetadata {
11551156
name_was_remapped,
11561157
self.cnum.as_u32(),
11571158
src_hash,
1159+
stable_id,
11581160
source_length,
11591161
lines,
11601162
multibyte_chars,

src/libsyntax/codemap.rs

+4-22
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan};
2323
pub use self::ExpnFormat::*;
2424

2525
use rustc_data_structures::fx::FxHashMap;
26-
use rustc_data_structures::stable_hasher::StableHasher;
2726
use std::cell::{RefCell, Ref};
28-
use std::hash::Hash;
2927
use std::path::{Path, PathBuf};
3028
use std::rc::Rc;
3129

@@ -102,24 +100,6 @@ impl FileLoader for RealFileLoader {
102100
}
103101
}
104102

105-
// This is a FileMap identifier that is used to correlate FileMaps between
106-
// subsequent compilation sessions (which is something we need to do during
107-
// incremental compilation).
108-
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
109-
pub struct StableFilemapId(u128);
110-
111-
impl StableFilemapId {
112-
pub fn new(filemap: &FileMap) -> StableFilemapId {
113-
let mut hasher = StableHasher::new();
114-
115-
filemap.name.hash(&mut hasher);
116-
filemap.name_was_remapped.hash(&mut hasher);
117-
filemap.unmapped_path.hash(&mut hasher);
118-
119-
StableFilemapId(hasher.finish())
120-
}
121-
}
122-
123103
// _____________________________________________________________________________
124104
// CodeMap
125105
//
@@ -217,7 +197,7 @@ impl CodeMap {
217197

218198
self.stable_id_to_filemap
219199
.borrow_mut()
220-
.insert(StableFilemapId::new(&filemap), filemap.clone());
200+
.insert(filemap.stable_id, filemap.clone());
221201

222202
filemap
223203
}
@@ -246,6 +226,7 @@ impl CodeMap {
246226
name_was_remapped: bool,
247227
crate_of_origin: u32,
248228
src_hash: u128,
229+
stable_id: StableFilemapId,
249230
source_len: usize,
250231
mut file_local_lines: Vec<BytePos>,
251232
mut file_local_multibyte_chars: Vec<MultiByteChar>,
@@ -276,6 +257,7 @@ impl CodeMap {
276257
crate_of_origin,
277258
src: None,
278259
src_hash,
260+
stable_id,
279261
external_src: RefCell::new(ExternalSource::AbsentOk),
280262
start_pos,
281263
end_pos,
@@ -288,7 +270,7 @@ impl CodeMap {
288270

289271
self.stable_id_to_filemap
290272
.borrow_mut()
291-
.insert(StableFilemapId::new(&filemap), filemap.clone());
273+
.insert(stable_id, filemap.clone());
292274

293275
filemap
294276
}

src/libsyntax_pos/hygiene.rs

+9
Original file line numberDiff line numberDiff line change
@@ -60,22 +60,27 @@ impl Mark {
6060
}
6161

6262
/// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
63+
#[inline]
6364
pub fn root() -> Self {
6465
Mark(0)
6566
}
6667

68+
#[inline]
6769
pub fn as_u32(self) -> u32 {
6870
self.0
6971
}
7072

73+
#[inline]
7174
pub fn from_u32(raw: u32) -> Mark {
7275
Mark(raw)
7376
}
7477

78+
#[inline]
7579
pub fn expn_info(self) -> Option<ExpnInfo> {
7680
HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone())
7781
}
7882

83+
#[inline]
7984
pub fn set_expn_info(self, info: ExpnInfo) {
8085
HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info))
8186
}
@@ -91,10 +96,12 @@ impl Mark {
9196
})
9297
}
9398

99+
#[inline]
94100
pub fn kind(self) -> MarkKind {
95101
HygieneData::with(|data| data.marks[self.0 as usize].kind)
96102
}
97103

104+
#[inline]
98105
pub fn set_kind(self, kind: MarkKind) {
99106
HygieneData::with(|data| data.marks[self.0 as usize].kind = kind)
100107
}
@@ -309,10 +316,12 @@ impl SyntaxContext {
309316
Some(scope)
310317
}
311318

319+
#[inline]
312320
pub fn modern(self) -> SyntaxContext {
313321
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].modern)
314322
}
315323

324+
#[inline]
316325
pub fn outer(self) -> Mark {
317326
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
318327
}

src/libsyntax_pos/lib.rs

+44-12
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,8 @@ pub struct FileMap {
678678
pub src: Option<Rc<String>>,
679679
/// The source code's hash
680680
pub src_hash: u128,
681+
/// The stable id used during incr. comp.
682+
pub stable_id: StableFilemapId,
681683
/// The external source code (used for external crates, which will have a `None`
682684
/// value as `self.src`.
683685
pub external_src: RefCell<ExternalSource>,
@@ -693,15 +695,37 @@ pub struct FileMap {
693695
pub non_narrow_chars: RefCell<Vec<NonNarrowChar>>,
694696
}
695697

698+
// This is a FileMap identifier that is used to correlate FileMaps between
699+
// subsequent compilation sessions (which is something we need to do during
700+
// incremental compilation).
701+
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
702+
pub struct StableFilemapId(pub u128);
703+
704+
impl StableFilemapId {
705+
pub fn new(name: &FileName,
706+
name_was_remapped: bool,
707+
unmapped_path: &FileName)
708+
-> StableFilemapId {
709+
use std::hash::Hash;
710+
711+
let mut hasher = StableHasher::new();
712+
name.hash(&mut hasher);
713+
name_was_remapped.hash(&mut hasher);
714+
unmapped_path.hash(&mut hasher);
715+
StableFilemapId(hasher.finish())
716+
}
717+
}
718+
696719
impl Encodable for FileMap {
697720
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
698721
s.emit_struct("FileMap", 8, |s| {
699722
s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
700723
s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
701-
s.emit_struct_field("src_hash", 6, |s| self.src_hash.encode(s))?;
702-
s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
703-
s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
704-
s.emit_struct_field("lines", 4, |s| {
724+
s.emit_struct_field("src_hash", 2, |s| self.src_hash.encode(s))?;
725+
s.emit_struct_field("stable_id", 3, |s| self.stable_id.encode(s))?;
726+
s.emit_struct_field("start_pos", 4, |s| self.start_pos.encode(s))?;
727+
s.emit_struct_field("end_pos", 5, |s| self.end_pos.encode(s))?;
728+
s.emit_struct_field("lines", 6, |s| {
705729
let lines = self.lines.borrow();
706730
// store the length
707731
s.emit_u32(lines.len() as u32)?;
@@ -747,10 +771,10 @@ impl Encodable for FileMap {
747771

748772
Ok(())
749773
})?;
750-
s.emit_struct_field("multibyte_chars", 5, |s| {
774+
s.emit_struct_field("multibyte_chars", 7, |s| {
751775
(*self.multibyte_chars.borrow()).encode(s)
752776
})?;
753-
s.emit_struct_field("non_narrow_chars", 7, |s| {
777+
s.emit_struct_field("non_narrow_chars", 8, |s| {
754778
(*self.non_narrow_chars.borrow()).encode(s)
755779
})
756780
})
@@ -765,11 +789,13 @@ impl Decodable for FileMap {
765789
let name_was_remapped: bool =
766790
d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
767791
let src_hash: u128 =
768-
d.read_struct_field("src_hash", 6, |d| Decodable::decode(d))?;
792+
d.read_struct_field("src_hash", 2, |d| Decodable::decode(d))?;
793+
let stable_id: StableFilemapId =
794+
d.read_struct_field("stable_id", 3, |d| Decodable::decode(d))?;
769795
let start_pos: BytePos =
770-
d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
771-
let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
772-
let lines: Vec<BytePos> = d.read_struct_field("lines", 4, |d| {
796+
d.read_struct_field("start_pos", 4, |d| Decodable::decode(d))?;
797+
let end_pos: BytePos = d.read_struct_field("end_pos", 5, |d| Decodable::decode(d))?;
798+
let lines: Vec<BytePos> = d.read_struct_field("lines", 6, |d| {
773799
let num_lines: u32 = Decodable::decode(d)?;
774800
let mut lines = Vec::with_capacity(num_lines as usize);
775801

@@ -798,9 +824,9 @@ impl Decodable for FileMap {
798824
Ok(lines)
799825
})?;
800826
let multibyte_chars: Vec<MultiByteChar> =
801-
d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
827+
d.read_struct_field("multibyte_chars", 7, |d| Decodable::decode(d))?;
802828
let non_narrow_chars: Vec<NonNarrowChar> =
803-
d.read_struct_field("non_narrow_chars", 7, |d| Decodable::decode(d))?;
829+
d.read_struct_field("non_narrow_chars", 8, |d| Decodable::decode(d))?;
804830
Ok(FileMap {
805831
name,
806832
name_was_remapped,
@@ -813,6 +839,7 @@ impl Decodable for FileMap {
813839
end_pos,
814840
src: None,
815841
src_hash,
842+
stable_id,
816843
external_src: RefCell::new(ExternalSource::AbsentOk),
817844
lines: RefCell::new(lines),
818845
multibyte_chars: RefCell::new(multibyte_chars),
@@ -840,6 +867,10 @@ impl FileMap {
840867
hasher.write(src.as_bytes());
841868
let src_hash = hasher.finish();
842869

870+
let stable_id = StableFilemapId::new(&name,
871+
name_was_remapped,
872+
&unmapped_path);
873+
843874
let end_pos = start_pos.to_usize() + src.len();
844875

845876
FileMap {
@@ -849,6 +880,7 @@ impl FileMap {
849880
crate_of_origin: 0,
850881
src: Some(Rc::new(src)),
851882
src_hash,
883+
stable_id,
852884
external_src: RefCell::new(ExternalSource::Unneeded),
853885
start_pos,
854886
end_pos: Pos::from_usize(end_pos),

0 commit comments

Comments
 (0)