Use StableHasher everywhere
The standard implementations of Hasher have architecture-dependent results when hashing integers. This causes problems when the hashes are stored within metadata - metadata written by one host architecture can't be read by another. To fix that, implement an architecture-independent StableHasher and use it in all places an architecture-independent hasher is needed. Fixes #38177.
This commit is contained in:
parent
01d53df82e
commit
e1d4b8fc8c
14 changed files with 270 additions and 230 deletions
|
@ -10,9 +10,9 @@
|
|||
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use std::fmt::Write;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use syntax::ast;
|
||||
use syntax::symbol::{Symbol, InternedString};
|
||||
use ty::TyCtxt;
|
||||
|
@ -131,7 +131,8 @@ impl DefPath {
|
|||
}
|
||||
|
||||
pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 {
|
||||
let mut state = DefaultHasher::new();
|
||||
debug!("deterministic_hash({:?})", self);
|
||||
let mut state = StableHasher::new();
|
||||
self.deterministic_hash_to(tcx, &mut state);
|
||||
state.finish()
|
||||
}
|
||||
|
@ -377,4 +378,3 @@ impl DefPathData {
|
|||
self.as_interned_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@ use util::nodemap::FxHashMap;
|
|||
use middle::lang_items;
|
||||
|
||||
use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::cmp;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::Hash;
|
||||
use std::intrinsics;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::attr::{self, SignedInt, UnsignedInt};
|
||||
|
@ -349,7 +349,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
/// Creates a hash of the type `Ty` which will be the same no matter what crate
|
||||
/// context it's calculated within. This is used by the `type_id` intrinsic.
|
||||
pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
|
||||
let mut hasher = TypeIdHasher::new(self, DefaultHasher::default());
|
||||
let mut hasher = TypeIdHasher::new(self);
|
||||
hasher.visit_ty(ty);
|
||||
hasher.finish()
|
||||
}
|
||||
|
@ -395,96 +395,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// When hashing a type this ends up affecting properties like symbol names. We
|
||||
/// want these symbol names to be calculated independent of other factors like
|
||||
/// what architecture you're compiling *from*.
|
||||
///
|
||||
/// The hashing just uses the standard `Hash` trait, but the implementations of
|
||||
/// `Hash` for the `usize` and `isize` types are *not* architecture independent
|
||||
/// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and
|
||||
/// `isize` completely when hashing. To ensure that these don't leak in we use a
|
||||
/// custom hasher implementation here which inflates the size of these to a `u64`
|
||||
/// and `i64`.
|
||||
///
|
||||
/// The same goes for endianess: We always convert multi-byte integers to little
|
||||
/// endian before hashing.
|
||||
#[derive(Debug)]
|
||||
pub struct ArchIndependentHasher<H> {
|
||||
inner: H,
|
||||
}
|
||||
|
||||
impl<H> ArchIndependentHasher<H> {
|
||||
pub fn new(inner: H) -> ArchIndependentHasher<H> {
|
||||
ArchIndependentHasher { inner: inner }
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> H {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Hasher> Hasher for ArchIndependentHasher<H> {
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
self.inner.write(bytes)
|
||||
}
|
||||
|
||||
fn finish(&self) -> u64 {
|
||||
self.inner.finish()
|
||||
}
|
||||
|
||||
fn write_u8(&mut self, i: u8) {
|
||||
self.inner.write_u8(i)
|
||||
}
|
||||
fn write_u16(&mut self, i: u16) {
|
||||
self.inner.write_u16(i.to_le())
|
||||
}
|
||||
fn write_u32(&mut self, i: u32) {
|
||||
self.inner.write_u32(i.to_le())
|
||||
}
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.inner.write_u64(i.to_le())
|
||||
}
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
self.inner.write_u64((i as u64).to_le())
|
||||
}
|
||||
fn write_i8(&mut self, i: i8) {
|
||||
self.inner.write_i8(i)
|
||||
}
|
||||
fn write_i16(&mut self, i: i16) {
|
||||
self.inner.write_i16(i.to_le())
|
||||
}
|
||||
fn write_i32(&mut self, i: i32) {
|
||||
self.inner.write_i32(i.to_le())
|
||||
}
|
||||
fn write_i64(&mut self, i: i64) {
|
||||
self.inner.write_i64(i.to_le())
|
||||
}
|
||||
fn write_isize(&mut self, i: isize) {
|
||||
self.inner.write_i64((i as i64).to_le())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> {
|
||||
pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> {
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
state: ArchIndependentHasher<H>,
|
||||
state: StableHasher<W>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self {
|
||||
TypeIdHasher {
|
||||
tcx: tcx,
|
||||
state: ArchIndependentHasher::new(state),
|
||||
}
|
||||
impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W>
|
||||
where W: StableHasherResult
|
||||
{
|
||||
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
|
||||
TypeIdHasher { tcx: tcx, state: StableHasher::new() }
|
||||
}
|
||||
|
||||
pub fn finish(self) -> W {
|
||||
self.state.finish()
|
||||
}
|
||||
|
||||
pub fn hash<T: Hash>(&mut self, x: T) {
|
||||
x.hash(&mut self.state);
|
||||
}
|
||||
|
||||
pub fn finish(self) -> u64 {
|
||||
self.state.finish()
|
||||
}
|
||||
|
||||
fn hash_discriminant_u8<T>(&mut self, x: &T) {
|
||||
let v = unsafe {
|
||||
intrinsics::discriminant_value(x)
|
||||
|
@ -504,13 +434,11 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> {
|
|||
pub fn def_path(&mut self, def_path: &ast_map::DefPath) {
|
||||
def_path.deterministic_hash_to(self.tcx, &mut self.state);
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> H {
|
||||
self.state.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, H> {
|
||||
impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
|
||||
where W: StableHasherResult
|
||||
{
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
// Distinguish between the Ty variants uniformly.
|
||||
self.hash_discriminant_u8(&ty.sty);
|
||||
|
|
|
@ -44,6 +44,8 @@ extern crate serialize as rustc_serialize; // used by deriving
|
|||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
|
||||
pub use rustc_serialize::hex::ToHex;
|
||||
|
||||
pub mod array_vec;
|
||||
pub mod accumulate_vec;
|
||||
pub mod small_vec;
|
||||
|
@ -59,6 +61,7 @@ pub mod indexed_vec;
|
|||
pub mod obligation_forest;
|
||||
pub mod snapshot_map;
|
||||
pub mod snapshot_vec;
|
||||
pub mod stable_hasher;
|
||||
pub mod transitive_relation;
|
||||
pub mod unify;
|
||||
pub mod fnv;
|
||||
|
|
176
src/librustc_data_structures/stable_hasher.rs
Normal file
176
src/librustc_data_structures/stable_hasher.rs
Normal file
|
@ -0,0 +1,176 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::hash::Hasher;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use blake2b::Blake2bHasher;
|
||||
use rustc_serialize::leb128;
|
||||
|
||||
fn write_unsigned_leb128_to_buf(buf: &mut [u8; 16], value: u64) -> usize {
|
||||
leb128::write_unsigned_leb128_to(value, |i, v| buf[i] = v)
|
||||
}
|
||||
|
||||
fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize {
|
||||
leb128::write_signed_leb128_to(value, |i, v| buf[i] = v)
|
||||
}
|
||||
|
||||
/// When hashing something that ends up affecting properties like symbol names. We
|
||||
/// want these symbol names to be calculated independent of other factors like
|
||||
/// what architecture you're compiling *from*.
|
||||
///
|
||||
/// The hashing just uses the standard `Hash` trait, but the implementations of
|
||||
/// `Hash` for the `usize` and `isize` types are *not* architecture independent
|
||||
/// (e.g. they has 4 or 8 bytes). As a result we want to avoid `usize` and
|
||||
/// `isize` completely when hashing.
|
||||
///
|
||||
/// To do that, we encode all integers to be hashed with some
|
||||
/// arch-independent encoding.
|
||||
///
|
||||
/// At the moment, we pass i8/u8 straight through and encode
|
||||
/// all other integers using leb128.
|
||||
///
|
||||
/// This hasher currently always uses the stable Blake2b algorithm
|
||||
/// and allows for variable output lengths through its type
|
||||
/// parameter.
|
||||
#[derive(Debug)]
|
||||
pub struct StableHasher<W> {
|
||||
state: Blake2bHasher,
|
||||
bytes_hashed: u64,
|
||||
width: PhantomData<W>,
|
||||
}
|
||||
|
||||
pub trait StableHasherResult: Sized {
|
||||
fn finish(hasher: StableHasher<Self>) -> Self;
|
||||
}
|
||||
|
||||
impl<W: StableHasherResult> StableHasher<W> {
|
||||
pub fn new() -> Self {
|
||||
StableHasher {
|
||||
state: Blake2bHasher::new(mem::size_of::<W>(), &[]),
|
||||
bytes_hashed: 0,
|
||||
width: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish(self) -> W {
|
||||
W::finish(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl StableHasherResult for [u8; 20] {
|
||||
fn finish(mut hasher: StableHasher<Self>) -> Self {
|
||||
let mut result: [u8; 20] = [0; 20];
|
||||
result.copy_from_slice(hasher.state.finalize());
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl StableHasherResult for u64 {
|
||||
fn finish(mut hasher: StableHasher<Self>) -> Self {
|
||||
hasher.state.finalize();
|
||||
hasher.state.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> StableHasher<W> {
|
||||
#[inline]
|
||||
pub fn finalize(&mut self) -> &[u8] {
|
||||
self.state.finalize()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bytes_hashed(&self) -> u64 {
|
||||
self.bytes_hashed
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_uleb128(&mut self, value: u64) {
|
||||
let mut buf = [0; 16];
|
||||
let len = write_unsigned_leb128_to_buf(&mut buf, value);
|
||||
self.state.write(&buf[..len]);
|
||||
self.bytes_hashed += len as u64;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_ileb128(&mut self, value: i64) {
|
||||
let mut buf = [0; 16];
|
||||
let len = write_signed_leb128_to_buf(&mut buf, value);
|
||||
self.state.write(&buf[..len]);
|
||||
self.bytes_hashed += len as u64;
|
||||
}
|
||||
}
|
||||
|
||||
// For the non-u8 integer cases we leb128 encode them first. Because small
|
||||
// integers dominate, this significantly and cheaply reduces the number of
|
||||
// bytes hashed, which is good because blake2b is expensive.
|
||||
impl<W> Hasher for StableHasher<W> {
|
||||
fn finish(&self) -> u64 {
|
||||
panic!("use StableHasher::finish instead");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
self.state.write(bytes);
|
||||
self.bytes_hashed += bytes.len() as u64;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u8(&mut self, i: u8) {
|
||||
self.state.write_u8(i);
|
||||
self.bytes_hashed += 1;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u16(&mut self, i: u16) {
|
||||
self.write_uleb128(i as u64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u32(&mut self, i: u32) {
|
||||
self.write_uleb128(i as u64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.write_uleb128(i);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
self.write_uleb128(i as u64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i8(&mut self, i: i8) {
|
||||
self.state.write_i8(i);
|
||||
self.bytes_hashed += 1;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i16(&mut self, i: i16) {
|
||||
self.write_ileb128(i as i64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i32(&mut self, i: i32) {
|
||||
self.write_ileb128(i as i64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i64(&mut self, i: i64) {
|
||||
self.write_ileb128(i);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_isize(&mut self, i: isize) {
|
||||
self.write_ileb128(i as i64);
|
||||
}
|
||||
}
|
|
@ -11,9 +11,7 @@
|
|||
use rustc::hir;
|
||||
use rustc::hir::{map as hir_map, FreevarMap, TraitMap};
|
||||
use rustc::hir::lowering::lower_crate;
|
||||
use rustc_data_structures::blake2b::Blake2bHasher;
|
||||
use rustc_data_structures::fmt_wrap::FmtWrap;
|
||||
use rustc::ty::util::ArchIndependentHasher;
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use rustc_mir as mir;
|
||||
use rustc::session::{Session, CompileResult, compile_result_from_err_count};
|
||||
use rustc::session::config::{self, Input, OutputFilenames, OutputType,
|
||||
|
@ -27,6 +25,7 @@ use rustc::util::common::time;
|
|||
use rustc::util::nodemap::{NodeSet, NodeMap};
|
||||
use rustc_borrowck as borrowck;
|
||||
use rustc_incremental::{self, IncrementalHashesMap};
|
||||
use rustc_incremental::ich::Fingerprint;
|
||||
use rustc_resolve::{MakeGlobMap, Resolver};
|
||||
use rustc_metadata::creader::CrateLoader;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
|
@ -1274,7 +1273,7 @@ pub fn compute_crate_disambiguator(session: &Session) -> String {
|
|||
// FIXME(mw): It seems that the crate_disambiguator is used everywhere as
|
||||
// a hex-string instead of raw bytes. We should really use the
|
||||
// smaller representation.
|
||||
let mut hasher = ArchIndependentHasher::new(Blake2bHasher::new(128 / 8, &[]));
|
||||
let mut hasher = StableHasher::<Fingerprint>::new();
|
||||
|
||||
let mut metadata = session.opts.cg.metadata.clone();
|
||||
// We don't want the crate_disambiguator to dependent on the order
|
||||
|
@ -1292,14 +1291,11 @@ pub fn compute_crate_disambiguator(session: &Session) -> String {
|
|||
hasher.write(s.as_bytes());
|
||||
}
|
||||
|
||||
let mut hash_state = hasher.into_inner();
|
||||
let hash_bytes = hash_state.finalize();
|
||||
|
||||
// If this is an executable, add a special suffix, so that we don't get
|
||||
// symbol conflicts when linking against a library of the same name.
|
||||
let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable);
|
||||
|
||||
format!("{:x}{}", FmtWrap(hash_bytes), if is_exe { "-exe" } else {""})
|
||||
format!("{}{}", hasher.finish().to_hex(), if is_exe { "-exe" } else {""})
|
||||
}
|
||||
|
||||
pub fn build_output_filenames(input: &Input,
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::mem;
|
||||
use std::hash::Hasher;
|
||||
use rustc_data_structures::blake2b::Blake2bHasher;
|
||||
use rustc::ty::util::ArchIndependentHasher;
|
||||
use ich::Fingerprint;
|
||||
use rustc_serialize::leb128::write_unsigned_leb128;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IchHasher {
|
||||
state: ArchIndependentHasher<Blake2bHasher>,
|
||||
leb128_helper: Vec<u8>,
|
||||
bytes_hashed: u64,
|
||||
}
|
||||
|
||||
impl IchHasher {
|
||||
pub fn new() -> IchHasher {
|
||||
let hash_size = mem::size_of::<Fingerprint>();
|
||||
IchHasher {
|
||||
state: ArchIndependentHasher::new(Blake2bHasher::new(hash_size, &[])),
|
||||
leb128_helper: vec![],
|
||||
bytes_hashed: 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bytes_hashed(&self) -> u64 {
|
||||
self.bytes_hashed
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Fingerprint {
|
||||
let mut fingerprint = Fingerprint::zero();
|
||||
fingerprint.0.copy_from_slice(self.state.into_inner().finalize());
|
||||
fingerprint
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_uleb128(&mut self, value: u64) {
|
||||
let len = write_unsigned_leb128(&mut self.leb128_helper, 0, value);
|
||||
self.state.write(&self.leb128_helper[0..len]);
|
||||
self.bytes_hashed += len as u64;
|
||||
}
|
||||
}
|
||||
|
||||
// For the non-u8 integer cases we leb128 encode them first. Because small
|
||||
// integers dominate, this significantly and cheaply reduces the number of
|
||||
// bytes hashed, which is good because blake2b is expensive.
|
||||
impl Hasher for IchHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
bug!("Use other finish() implementation to get the full 128-bit hash.");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
self.state.write(bytes);
|
||||
self.bytes_hashed += bytes.len() as u64;
|
||||
}
|
||||
|
||||
// There is no need to leb128-encode u8 values.
|
||||
|
||||
#[inline]
|
||||
fn write_u16(&mut self, i: u16) {
|
||||
self.write_uleb128(i as u64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u32(&mut self, i: u32) {
|
||||
self.write_uleb128(i as u64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.write_uleb128(i);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
self.write_uleb128(i as u64);
|
||||
}
|
||||
}
|
|
@ -36,6 +36,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
|||
use rustc::hir::intravisit as visit;
|
||||
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_data_structures::stable_hasher::StableHasher;
|
||||
use ich::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc::util::common::record_time;
|
||||
use rustc::session::config::DebugInfoLevel::NoDebugInfo;
|
||||
|
@ -43,14 +45,12 @@ use rustc::session::config::DebugInfoLevel::NoDebugInfo;
|
|||
use self::def_path_hash::DefPathHashes;
|
||||
use self::svh_visitor::StrictVersionHashVisitor;
|
||||
use self::caching_codemap_view::CachingCodemapView;
|
||||
use self::hasher::IchHasher;
|
||||
use ich::Fingerprint;
|
||||
|
||||
|
||||
mod def_path_hash;
|
||||
mod svh_visitor;
|
||||
mod caching_codemap_view;
|
||||
pub mod hasher;
|
||||
|
||||
pub type IchHasher = StableHasher<Fingerprint>;
|
||||
|
||||
pub struct IncrementalHashesMap {
|
||||
hashes: FxHashMap<DepNode<DefId>, Fingerprint>,
|
||||
|
@ -244,4 +244,3 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
|
|||
visit::walk_foreign_item(self, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ use std::hash::Hash;
|
|||
|
||||
use super::def_path_hash::DefPathHashes;
|
||||
use super::caching_codemap_view::CachingCodemapView;
|
||||
use super::hasher::IchHasher;
|
||||
use super::IchHasher;
|
||||
|
||||
const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
|
||||
"cfg",
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
|
||||
use rustc_data_structures::stable_hasher;
|
||||
use rustc_data_structures::ToHex;
|
||||
|
||||
const FINGERPRINT_LENGTH: usize = 16;
|
||||
|
||||
|
@ -44,6 +46,10 @@ impl Fingerprint {
|
|||
((self.0[6] as u64) << 48) |
|
||||
((self.0[7] as u64) << 56)
|
||||
}
|
||||
|
||||
pub fn to_hex(&self) -> String {
|
||||
self.0.to_hex()
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Fingerprint {
|
||||
|
@ -79,3 +85,12 @@ impl ::std::fmt::Display for Fingerprint {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl stable_hasher::StableHasherResult for Fingerprint {
|
||||
fn finish(mut hasher: stable_hasher::StableHasher<Self>) -> Self {
|
||||
let mut fingerprint = Fingerprint::zero();
|
||||
fingerprint.0.copy_from_slice(hasher.finalize());
|
||||
fingerprint
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ pub mod ich;
|
|||
pub use assert_dep_graph::assert_dep_graph;
|
||||
pub use calculate_svh::compute_incremental_hashes_map;
|
||||
pub use calculate_svh::IncrementalHashesMap;
|
||||
pub use calculate_svh::hasher::IchHasher;
|
||||
pub use calculate_svh::IchHasher;
|
||||
pub use persist::load_dep_graph;
|
||||
pub use persist::save_dep_graph;
|
||||
pub use persist::save_trans_partition;
|
||||
|
|
|
@ -30,7 +30,7 @@ use super::preds::*;
|
|||
use super::fs::*;
|
||||
use super::dirty_clean;
|
||||
use super::file_format;
|
||||
use calculate_svh::hasher::IchHasher;
|
||||
use calculate_svh::IchHasher;
|
||||
|
||||
pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
incremental_hashes_map: &IncrementalHashesMap,
|
||||
|
|
|
@ -99,8 +99,6 @@
|
|||
|
||||
use common::SharedCrateContext;
|
||||
use monomorphize::Instance;
|
||||
use rustc_data_structures::fmt_wrap::FmtWrap;
|
||||
use rustc_data_structures::blake2b::Blake2bHasher;
|
||||
|
||||
use rustc::middle::weak_lang_items;
|
||||
use rustc::hir::def_id::LOCAL_CRATE;
|
||||
|
@ -135,7 +133,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||
|
||||
let tcx = scx.tcx();
|
||||
|
||||
let mut hasher = ty::util::TypeIdHasher::new(tcx, Blake2bHasher::new(8, &[]));
|
||||
let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
|
||||
|
||||
record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
|
||||
// the main symbol name is not necessarily unique; hash in the
|
||||
|
@ -158,9 +156,7 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||
});
|
||||
|
||||
// 64 bits should be enough to avoid collisions.
|
||||
let mut hasher = hasher.into_inner();
|
||||
let hash_bytes = hasher.finalize();
|
||||
format!("h{:x}", FmtWrap(hash_bytes))
|
||||
format!("h{:016x}", hasher.finish())
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Instance<'tcx> {
|
||||
|
|
|
@ -31,7 +31,7 @@ use rustc::ty::fold::TypeVisitor;
|
|||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::util::TypeIdHasher;
|
||||
use rustc::hir;
|
||||
use rustc_data_structures::blake2b::Blake2bHasher;
|
||||
use rustc_data_structures::ToHex;
|
||||
use {type_of, machine, monomorphize};
|
||||
use common::CrateContext;
|
||||
use type_::Type;
|
||||
|
@ -42,7 +42,6 @@ use util::common::path2cstr;
|
|||
|
||||
use libc::{c_uint, c_longlong};
|
||||
use std::ffi::CString;
|
||||
use std::fmt::Write;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use syntax::ast;
|
||||
|
@ -147,21 +146,11 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
|
||||
// The hasher we are using to generate the UniqueTypeId. We want
|
||||
// something that provides more than the 64 bits of the DefaultHasher.
|
||||
const TYPE_ID_HASH_LENGTH: usize = 20;
|
||||
|
||||
let mut type_id_hasher = TypeIdHasher::new(cx.tcx(),
|
||||
Blake2bHasher::new(TYPE_ID_HASH_LENGTH, &[]));
|
||||
let mut type_id_hasher = TypeIdHasher::<[u8; 20]>::new(cx.tcx());
|
||||
type_id_hasher.visit_ty(type_);
|
||||
let mut hash_state = type_id_hasher.into_inner();
|
||||
let hash: &[u8] = hash_state.finalize();
|
||||
debug_assert!(hash.len() == TYPE_ID_HASH_LENGTH);
|
||||
|
||||
let mut unique_type_id = String::with_capacity(TYPE_ID_HASH_LENGTH * 2);
|
||||
|
||||
for byte in hash.into_iter() {
|
||||
write!(&mut unique_type_id, "{:x}", byte).unwrap();
|
||||
}
|
||||
|
||||
let unique_type_id = type_id_hasher.finish().to_hex();
|
||||
let key = self.unique_id_interner.intern(&unique_type_id);
|
||||
self.type_to_unique_id.insert(type_, UniqueTypeId(key));
|
||||
|
||||
|
|
|
@ -9,18 +9,26 @@
|
|||
// except according to those terms.
|
||||
|
||||
#[inline]
|
||||
pub fn write_to_vec(vec: &mut Vec<u8>, position: &mut usize, byte: u8) {
|
||||
if *position == vec.len() {
|
||||
fn write_to_vec(vec: &mut Vec<u8>, position: usize, byte: u8) {
|
||||
if position == vec.len() {
|
||||
vec.push(byte);
|
||||
} else {
|
||||
vec[*position] = byte;
|
||||
vec[position] = byte;
|
||||
}
|
||||
|
||||
*position += 1;
|
||||
}
|
||||
|
||||
pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value: u64) -> usize {
|
||||
let mut position = start_position;
|
||||
#[inline]
|
||||
/// encodes an integer using unsigned leb128 encoding and stores
|
||||
/// the result using a callback function.
|
||||
///
|
||||
/// The callback `write` is called once for each position
|
||||
/// that is to be written to with the byte to be encoded
|
||||
/// at that position.
|
||||
pub fn write_unsigned_leb128_to<W>(mut value: u64, mut write: W) -> usize
|
||||
where W: FnMut(usize, u8)
|
||||
{
|
||||
let mut position = 0;
|
||||
|
||||
loop {
|
||||
let mut byte = (value & 0x7F) as u8;
|
||||
value >>= 7;
|
||||
|
@ -28,14 +36,19 @@ pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value
|
|||
byte |= 0x80;
|
||||
}
|
||||
|
||||
write_to_vec(out, &mut position, byte);
|
||||
write(position, byte);
|
||||
position += 1;
|
||||
|
||||
if value == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return position - start_position;
|
||||
position
|
||||
}
|
||||
|
||||
pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, value: u64) -> usize {
|
||||
write_unsigned_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -56,9 +69,17 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize)
|
|||
(result, position - start_position)
|
||||
}
|
||||
|
||||
|
||||
pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value: i64) -> usize {
|
||||
let mut position = start_position;
|
||||
#[inline]
|
||||
/// encodes an integer using signed leb128 encoding and stores
|
||||
/// the result using a callback function.
|
||||
///
|
||||
/// The callback `write` is called once for each position
|
||||
/// that is to be written to with the byte to be encoded
|
||||
/// at that position.
|
||||
pub fn write_signed_leb128_to<W>(mut value: i64, mut write: W) -> usize
|
||||
where W: FnMut(usize, u8)
|
||||
{
|
||||
let mut position = 0;
|
||||
|
||||
loop {
|
||||
let mut byte = (value as u8) & 0x7f;
|
||||
|
@ -69,14 +90,19 @@ pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value:
|
|||
byte |= 0x80; // Mark this byte to show that more bytes will follow.
|
||||
}
|
||||
|
||||
write_to_vec(out, &mut position, byte);
|
||||
write(position, byte);
|
||||
position += 1;
|
||||
|
||||
if !more {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return position - start_position;
|
||||
position
|
||||
}
|
||||
|
||||
pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, value: i64) -> usize {
|
||||
write_signed_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue