diff options
| author | Camille GILLOT <gillot.camille@gmail.com> | 2019-11-23 14:39:00 +0100 |
|---|---|---|
| committer | Camille GILLOT <gillot.camille@gmail.com> | 2019-11-23 18:09:36 +0100 |
| commit | 7e411e7f55a6050fb690f2c4e46b002a46502031 (patch) | |
| tree | 3466e240135f93f33e1ed37cfb4cfeff012d404d | |
| parent | ea0c354758b334985169b35575fcbb8ca0a6f2f3 (diff) | |
| download | rust-7e411e7f55a6050fb690f2c4e46b002a46502031.tar.gz rust-7e411e7f55a6050fb690f2c4e46b002a46502031.zip | |
Implement HashStable for Span in libsyntax_pos.
| -rw-r--r-- | src/librustc/ich/hcx.rs | 93 | ||||
| -rw-r--r-- | src/libsyntax_pos/lib.rs | 100 |
2 files changed, 100 insertions, 93 deletions
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 55c02074fce..8b35839c182 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -2,25 +2,23 @@ use crate::hir; use crate::hir::def_id::{DefId, DefIndex}; use crate::hir::map::DefPathHash; use crate::hir::map::definitions::Definitions; -use crate::ich::{self, CachingSourceMapView, Fingerprint}; +use crate::ich::{self, CachingSourceMapView}; use crate::middle::cstore::CrateStore; use crate::ty::{TyCtxt, fast_reject}; use crate::session::Session; use std::cmp::Ord; -use std::hash as std_hash; -use std::cell::RefCell; use syntax::ast; use syntax::source_map::SourceMap; use syntax::symbol::Symbol; -use syntax_pos::{Span, DUMMY_SP}; -use syntax_pos::hygiene::{self, SyntaxContext}; +use syntax_pos::{SourceFile, BytePos}; use rustc_data_structures::stable_hasher::{ HashStable, StableHasher, ToStableHashKey, }; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::sync::Lrc; use smallvec::SmallVec; fn compute_ignored_attr_names() -> FxHashSet<Symbol> { @@ -281,85 +279,14 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::NodeId { } impl<'a> syntax_pos::HashStableContext for StableHashingContext<'a> { - /// Hashes a span in a stable way. We can't directly hash the span's `BytePos` - /// fields (that would be similar to hashing pointers, since those are just - /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column) - /// triple, which stays the same even if the containing `SourceFile` has moved - /// within the `SourceMap`. - /// Also note that we are hashing byte offsets for the column, not unicode - /// codepoint offsets. For the purpose of the hash that's sufficient. - /// Also, hashing filenames is expensive so we avoid doing it twice when the - /// span starts and ends in the same file, which is almost always the case. - fn hash_stable_span(&mut self, span: &Span, hasher: &mut StableHasher) { - const TAG_VALID_SPAN: u8 = 0; - const TAG_INVALID_SPAN: u8 = 1; - const TAG_EXPANSION: u8 = 0; - const TAG_NO_EXPANSION: u8 = 1; - - if !self.hash_spans { - return - } - - if *span == DUMMY_SP { - return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); - } - - // If this is not an empty or invalid span, we want to hash the last - // position that belongs to it, as opposed to hashing the first - // position past it. - let span = span.data(); - let (file_lo, line_lo, col_lo) = match self.source_map() - .byte_pos_to_line_and_col(span.lo) { - Some(pos) => pos, - None => { - return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); - } - }; - - if !file_lo.contains(span.hi) { - return std_hash::Hash::hash(&TAG_INVALID_SPAN, hasher); - } - - std_hash::Hash::hash(&TAG_VALID_SPAN, hasher); - // We truncate the stable ID hash and line and column numbers. The chances - // of causing a collision this way should be minimal. - std_hash::Hash::hash(&(file_lo.name_hash 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::root() { - TAG_NO_EXPANSION.hash_stable(self, hasher); - } else { - TAG_EXPANSION.hash_stable(self, 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::ExpnId, u64>> = Default::default(); - } - - let sub_hash: u64 = CACHE.with(|cache| { - let expn_id = span.ctxt.outer_expn(); - - if let Some(&sub_hash) = cache.borrow().get(&expn_id) { - return sub_hash; - } - - let mut hasher = StableHasher::new(); - expn_id.expn_data().hash_stable(self, &mut hasher); - let sub_hash: Fingerprint = hasher.finish(); - let sub_hash = sub_hash.to_smaller_hash(); - cache.borrow_mut().insert(expn_id, sub_hash); - sub_hash - }); + fn hash_spans(&self) -> bool { + self.hash_spans + } - sub_hash.hash_stable(self, hasher); - } + fn byte_pos_to_line_and_col(&mut self, byte: BytePos) + -> Option<(Lrc<SourceFile>, usize, BytePos)> + { + self.source_map().byte_pos_to_line_and_col(byte) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index a24a2555bff..66f25770722 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -37,10 +37,12 @@ mod analyze_source_file; pub mod fatal_error; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::fx::FxHashMap; use std::borrow::Cow; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::cmp::{self, Ordering}; use std::fmt; use std::hash::{Hasher, Hash}; @@ -247,14 +249,6 @@ impl Ord for Span { } } -impl<CTX> HashStable<CTX> for Span - where CTX: HashStableContext -{ - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - ctx.hash_stable_span(self, hasher) - } -} - /// A collection of spans. Spans have two orthogonal attributes: /// /// - They can be *primary spans*. In this case they are the locus of @@ -1577,5 +1571,91 @@ fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize { /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in librustc. pub trait HashStableContext { - fn hash_stable_span(&mut self, span: &Span, hasher: &mut StableHasher); + fn hash_spans(&self) -> bool; + fn byte_pos_to_line_and_col(&mut self, byte: BytePos) + -> Option<(Lrc<SourceFile>, usize, BytePos)>; +} + +impl<CTX> HashStable<CTX> for Span + where CTX: HashStableContext +{ + /// Hashes a span in a stable way. We can't directly hash the span's `BytePos` + /// fields (that would be similar to hashing pointers, since those are just + /// offsets into the `SourceMap`). Instead, we hash the (file name, line, column) + /// triple, which stays the same even if the containing `SourceFile` has moved + /// within the `SourceMap`. + /// Also note that we are hashing byte offsets for the column, not unicode + /// codepoint offsets. For the purpose of the hash that's sufficient. + /// Also, hashing filenames is expensive so we avoid doing it twice when the + /// span starts and ends in the same file, which is almost always the case. + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + const TAG_VALID_SPAN: u8 = 0; + const TAG_INVALID_SPAN: u8 = 1; + const TAG_EXPANSION: u8 = 0; + const TAG_NO_EXPANSION: u8 = 1; + + if !ctx.hash_spans() { + return + } + + if *self == DUMMY_SP { + return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher); + } + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span = self.data(); + let (file_lo, line_lo, col_lo) = match ctx.byte_pos_to_line_and_col(span.lo) { + Some(pos) => pos, + None => { + return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher); + } + }; + + if !file_lo.contains(span.hi) { + return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher); + } + + std::hash::Hash::hash(&TAG_VALID_SPAN, hasher); + // We truncate the stable ID hash and line and column numbers. The chances + // of causing a collision this way should be minimal. + std::hash::Hash::hash(&(file_lo.name_hash 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::root() { + TAG_NO_EXPANSION.hash_stable(ctx, hasher); + } else { + TAG_EXPANSION.hash_stable(ctx, 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::ExpnId, u64>> = Default::default(); + } + + let sub_hash: u64 = CACHE.with(|cache| { + let expn_id = span.ctxt.outer_expn(); + + if let Some(&sub_hash) = cache.borrow().get(&expn_id) { + return sub_hash; + } + + let mut hasher = StableHasher::new(); + expn_id.expn_data().hash_stable(ctx, &mut hasher); + let sub_hash: Fingerprint = hasher.finish(); + let sub_hash = sub_hash.to_smaller_hash(); + cache.borrow_mut().insert(expn_id, sub_hash); + sub_hash + }); + + sub_hash.hash_stable(ctx, hasher); + } + } } |
