From e1d4b8fc8c3e991627715916f7285611ec49424e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 14 Dec 2016 01:45:03 +0200 Subject: [PATCH] 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. --- src/librustc/hir/map/definitions.rs | 6 +- src/librustc/ty/util.rs | 104 ++--------- src/librustc_data_structures/lib.rs | 3 + src/librustc_data_structures/stable_hasher.rs | 176 ++++++++++++++++++ src/librustc_driver/driver.rs | 12 +- .../calculate_svh/hasher.rs | 88 --------- src/librustc_incremental/calculate_svh/mod.rs | 9 +- .../calculate_svh/svh_visitor.rs | 2 +- src/librustc_incremental/ich/fingerprint.rs | 15 ++ src/librustc_incremental/lib.rs | 2 +- src/librustc_incremental/persist/save.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 8 +- src/librustc_trans/debuginfo/metadata.rs | 17 +- src/libserialize/leb128.rs | 54 ++++-- 14 files changed, 269 insertions(+), 229 deletions(-) create mode 100644 src/librustc_data_structures/stable_hasher.rs delete mode 100644 src/librustc_incremental/calculate_svh/hasher.rs diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 83d3627d8e616..a684563512da6 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -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() } } - diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e6db35cc3f544..b4ac6b9d2502e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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 { - inner: H, -} - -impl ArchIndependentHasher { - pub fn new(inner: H) -> ArchIndependentHasher { - ArchIndependentHasher { inner: inner } - } - - pub fn into_inner(self) -> H { - self.inner - } +pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + state: StableHasher, } -impl Hasher for ArchIndependentHasher { - 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()) +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() } } - 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> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - state: ArchIndependentHasher, -} -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), - } + pub fn finish(self) -> W { + self.state.finish() } pub fn hash(&mut self, x: T) { x.hash(&mut self.state); } - pub fn finish(self) -> u64 { - self.state.finish() - } - fn hash_discriminant_u8(&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); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index de13b9bf4be10..86f244d65dd42 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -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; diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs new file mode 100644 index 0000000000000..ed97c3dde5eff --- /dev/null +++ b/src/librustc_data_structures/stable_hasher.rs @@ -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 or the MIT license +// , 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 { + state: Blake2bHasher, + bytes_hashed: u64, + width: PhantomData, +} + +pub trait StableHasherResult: Sized { + fn finish(hasher: StableHasher) -> Self; +} + +impl StableHasher { + pub fn new() -> Self { + StableHasher { + state: Blake2bHasher::new(mem::size_of::(), &[]), + bytes_hashed: 0, + width: PhantomData, + } + } + + pub fn finish(self) -> W { + W::finish(self) + } +} + +impl StableHasherResult for [u8; 20] { + fn finish(mut hasher: StableHasher) -> 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 { + hasher.state.finalize(); + hasher.state.finish() + } +} + +impl StableHasher { + #[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 Hasher for StableHasher { + 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); + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8d995e97b95b3..ace00f031859d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -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::::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, diff --git a/src/librustc_incremental/calculate_svh/hasher.rs b/src/librustc_incremental/calculate_svh/hasher.rs deleted file mode 100644 index d7d9c231a91f4..0000000000000 --- a/src/librustc_incremental/calculate_svh/hasher.rs +++ /dev/null @@ -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 or the MIT license -// , 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, - leb128_helper: Vec, - bytes_hashed: u64, -} - -impl IchHasher { - pub fn new() -> IchHasher { - let hash_size = mem::size_of::(); - 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); - } -} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index df65c4d27947b..eb31be4a8ade2 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -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; pub struct IncrementalHashesMap { hashes: FxHashMap, Fingerprint>, @@ -244,4 +244,3 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> { visit::walk_foreign_item(self, item); } } - diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index de52b70f1ec92..ec44e19df10c9 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -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", diff --git a/src/librustc_incremental/ich/fingerprint.rs b/src/librustc_incremental/ich/fingerprint.rs index 005ac3896ce4c..d296d8293fb06 100644 --- a/src/librustc_incremental/ich/fingerprint.rs +++ b/src/librustc_incremental/ich/fingerprint.rs @@ -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 { + let mut fingerprint = Fingerprint::zero(); + fingerprint.0.copy_from_slice(hasher.finalize()); + fingerprint + } +} diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 3cb5244413bc0..ce73b14ef2d02 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -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; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 1ce4bf7f03341..f3bbd02dffa3f 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -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, diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index ff40cfda5ff7c..938848054fee2 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -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::::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> { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 5022e0750e38e..bc9c86c99a3ee 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -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)); diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 8e8e03f1f8ebb..5b72c6d46aceb 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -9,18 +9,26 @@ // except according to those terms. #[inline] -pub fn write_to_vec(vec: &mut Vec, position: &mut usize, byte: u8) { - if *position == vec.len() { +fn write_to_vec(vec: &mut Vec, 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, 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(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, 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, 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, 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(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, 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, start_position: usize, value: i64) -> usize { + write_signed_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v)) } #[inline]