Skip to content

Commit

Permalink
Auto merge of #46562 - michaelwoerister:faster-span-hashing, r=eddyb
Browse files Browse the repository at this point in the history
incr.comp.: Speed up span hashing by caching expansion context hashes.

This PR fixes the performance regressions from #46338.

r? @nikomatsakis
  • Loading branch information
bors committed Dec 14, 2017
2 parents 2974104 + 0b4c2cc commit 3fc7f85
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 44 deletions.
46 changes: 37 additions & 9 deletions src/librustc/ich/hcx.rs
Expand Up @@ -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;
Expand All @@ -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<FxHashSet<Symbol>> =
RefCell::new(FxHashSet()));
Expand Down Expand Up @@ -337,19 +338,46 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> 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);
} 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<FxHashMap<hygiene::Mark, u64>> =
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);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ich/impls_syntax.rs
Expand Up @@ -394,6 +394,8 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> 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: _,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/maps/on_disk_cache.rs
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_metadata/decoder.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -1155,6 +1156,7 @@ impl<'a, 'tcx> CrateMetadata {
name_was_remapped,
self.cnum.as_u32(),
src_hash,
stable_id,
source_length,
lines,
multibyte_chars,
Expand Down
26 changes: 4 additions & 22 deletions src/libsyntax/codemap.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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<BytePos>,
mut file_local_multibyte_chars: Vec<MultiByteChar>,
Expand Down Expand Up @@ -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,
Expand All @@ -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
}
Expand Down
9 changes: 9 additions & 0 deletions src/libsyntax_pos/hygiene.rs
Expand Up @@ -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<ExpnInfo> {
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))
}
Expand All @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
56 changes: 44 additions & 12 deletions src/libsyntax_pos/lib.rs
Expand Up @@ -678,6 +678,8 @@ pub struct FileMap {
pub src: Option<Rc<String>>,
/// 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<ExternalSource>,
Expand All @@ -693,15 +695,37 @@ pub struct FileMap {
pub non_narrow_chars: RefCell<Vec<NonNarrowChar>>,
}

// 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<S: Encoder>(&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)?;
Expand Down Expand Up @@ -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)
})
})
Expand All @@ -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<BytePos> = 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<BytePos> = d.read_struct_field("lines", 6, |d| {
let num_lines: u32 = Decodable::decode(d)?;
let mut lines = Vec::with_capacity(num_lines as usize);

Expand Down Expand Up @@ -798,9 +824,9 @@ impl Decodable for FileMap {
Ok(lines)
})?;
let multibyte_chars: Vec<MultiByteChar> =
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<NonNarrowChar> =
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,
Expand All @@ -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),
Expand Down Expand Up @@ -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 {
Expand All @@ -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),
Expand Down

0 comments on commit 3fc7f85

Please sign in to comment.