ICH: Use 128-bit Blake2b hash instead of 64-bit SipHash for incr. comp. fingerprints.

This commit is contained in:
Michael Woerister 2016-10-07 09:13:11 -04:00
parent 40cd1fdf0a
commit d07523c716
14 changed files with 460 additions and 38 deletions

View file

@ -0,0 +1,286 @@
// 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.
// An implementation of the Blake2b cryptographic hash function.
// The implementation closely follows: https://tools.ietf.org/html/rfc7693
//
// "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and
// SHA-3, yet is at least as secure as the latest standard SHA-3."
// according to their own website :)
//
// Indeed this implementation is two to three times as fast as our SHA-256
// implementation. If you have the luxury of being able to use crates from
// crates.io, you can go there and find still faster implementations.
pub struct Blake2bCtx {
b: [u8; 128],
h: [u64; 8],
t: [u64; 2],
c: usize,
outlen: usize,
}
impl ::std::fmt::Debug for Blake2bCtx {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(fmt, "{:?}", self.h)
}
}
#[inline(always)]
fn b2b_g(v: &mut [u64; 16],
a: usize,
b: usize,
c: usize,
d: usize,
x: u64,
y: u64)
{
v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
v[d] = (v[d] ^ v[a]).rotate_right(32);
v[c] = v[c].wrapping_add(v[d]);
v[b] = (v[b] ^ v[c]).rotate_right(24);
v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
v[d] = (v[d] ^ v[a]).rotate_right(16);
v[c] = v[c].wrapping_add(v[d]);
v[b] = (v[b] ^ v[c]).rotate_right(63);
}
// Initialization vector
const BLAKE2B_IV: [u64; 8] = [
0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
];
fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) {
const SIGMA: [[usize; 16]; 12] = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ],
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ],
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ],
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ],
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ],
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ],
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ],
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ]
];
let mut v: [u64; 16] = [
ctx.h[0],
ctx.h[1],
ctx.h[2],
ctx.h[3],
ctx.h[4],
ctx.h[5],
ctx.h[6],
ctx.h[7],
BLAKE2B_IV[0],
BLAKE2B_IV[1],
BLAKE2B_IV[2],
BLAKE2B_IV[3],
BLAKE2B_IV[4],
BLAKE2B_IV[5],
BLAKE2B_IV[6],
BLAKE2B_IV[7],
];
v[12] ^= ctx.t[0]; // low 64 bits of offset
v[13] ^= ctx.t[1]; // high 64 bits
if last {
v[14] = !v[14];
}
{
// Re-interpret the input buffer in the state as u64s
let m: &mut [u64; 16] = unsafe {
let b: &mut [u8; 128] = &mut ctx.b;
::std::mem::transmute(b)
};
// It's OK to modify the buffer in place since this is the last time
// this data will be accessed before it's overwritten
if cfg!(target_endian = "big") {
for word in &mut m[..] {
*word = word.to_be();
}
}
for i in 0 .. 12 {
b2b_g(&mut v, 0, 4, 8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]);
b2b_g(&mut v, 1, 5, 9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]);
b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]);
b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]);
b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]);
b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]);
b2b_g(&mut v, 2, 7, 8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]);
b2b_g(&mut v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]);
}
}
for i in 0 .. 8 {
ctx.h[i] ^= v[i] ^ v[i + 8];
}
}
pub fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx {
assert!(outlen > 0 && outlen <= 64 && key.len() <= 64);
let mut ctx = Blake2bCtx {
b: [0; 128],
h: BLAKE2B_IV,
t: [0; 2],
c: 0,
outlen: outlen,
};
ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64);
if key.len() > 0 {
blake2b_update(&mut ctx, key);
ctx.c = ctx.b.len();
}
ctx
}
pub fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8])
{
let mut bytes_to_copy = data.len();
let mut space_in_buffer = ctx.b.len() - ctx.c;
while bytes_to_copy > space_in_buffer {
checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer);
ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64);
if ctx.t[0] < (ctx.b.len() as u64) {
ctx.t[1] += 1;
}
blake2b_compress(ctx, false);
ctx.c = 0;
data = &data[space_in_buffer .. ];
bytes_to_copy -= space_in_buffer;
space_in_buffer = ctx.b.len();
}
if bytes_to_copy > 0 {
checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy);
ctx.c += bytes_to_copy;
}
}
pub fn blake2b_final(mut ctx: Blake2bCtx, out: &mut [u8])
{
ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64);
if ctx.t[0] < ctx.c as u64 {
ctx.t[1] += 1;
}
while ctx.c < 128 {
ctx.b[ctx.c] = 0;
ctx.c += 1;
}
blake2b_compress(&mut ctx, true);
if cfg!(target_endian = "big") {
// Make sure that the data is in memory in little endian format, as is
// demanded by BLAKE2
for word in &mut ctx.h {
*word = word.to_le();
}
}
checked_mem_copy(&ctx.h, out, ctx.outlen);
}
#[inline(always)]
fn checked_mem_copy<T1, T2>(from: &[T1], to: &mut [T2], byte_count: usize) {
let from_size = from.len() * ::std::mem::size_of::<T1>();
let to_size = to.len() * ::std::mem::size_of::<T2>();
assert!(from_size >= byte_count);
assert!(to_size >= byte_count);
let from_byte_ptr = from.as_ptr() as * const u8;
let to_byte_ptr = to.as_mut_ptr() as * mut u8;
unsafe {
::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count);
}
}
pub fn blake2b(out: &mut [u8], key: &[u8], data: &[u8])
{
let mut ctx = blake2b_new(out.len(), key);
blake2b_update(&mut ctx, data);
blake2b_final(ctx, out);
}
#[cfg(test)]
fn selftest_seq(out: &mut [u8], seed: u32)
{
let mut a: u32 = 0xDEAD4BADu32.wrapping_mul(seed);
let mut b: u32 = 1;
for i in 0 .. out.len() {
let t: u32 = a.wrapping_add(b);
a = b;
b = t;
out[i] = ((t >> 24) & 0xFF) as u8;
}
}
#[test]
fn blake2b_selftest()
{
// grand hash of hash results
const BLAKE2B_RES: [u8; 32] = [
0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD,
0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56,
0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73,
0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75
];
// parameter sets
const B2B_MD_LEN: [usize; 4] = [20, 32, 48, 64];
const B2B_IN_LEN: [usize; 6] = [0, 3, 128, 129, 255, 1024];
let mut data = [0u8; 1024];
let mut md = [0u8; 64];
let mut key = [0u8; 64];
let mut ctx = blake2b_new(32, &[]);
for i in 0 .. 4 {
let outlen = B2B_MD_LEN[i];
for j in 0 .. 6 {
let inlen = B2B_IN_LEN[j];
selftest_seq(&mut data[.. inlen], inlen as u32); // unkeyed hash
blake2b(&mut md[.. outlen], &[], &data[.. inlen]);
blake2b_update(&mut ctx, &md[.. outlen]); // hash the hash
selftest_seq(&mut key[0 .. outlen], outlen as u32); // keyed hash
blake2b(&mut md[.. outlen], &key[.. outlen], &data[.. inlen]);
blake2b_update(&mut ctx, &md[.. outlen]); // hash the hash
}
}
// compute and compare the hash of hashes
blake2b_final(ctx, &mut md[..]);
for i in 0 .. 32 {
assert_eq!(md[i], BLAKE2B_RES[i]);
}
}

View file

@ -42,6 +42,7 @@ extern crate serialize as rustc_serialize; // used by deriving
extern crate libc;
pub mod bitslice;
pub mod blake2b;
pub mod bitvec;
pub mod graph;
pub mod ivar;

View file

@ -9,20 +9,20 @@
// except according to those terms.
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::mem;
use rustc_data_structures::blake2b;
use ich::Fingerprint;
#[derive(Debug)]
pub struct IchHasher {
// FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
// built to avoid collisions.
state: DefaultHasher,
state: blake2b::Blake2bCtx,
bytes_hashed: u64,
}
impl IchHasher {
pub fn new() -> IchHasher {
IchHasher {
state: DefaultHasher::new(),
state: blake2b::blake2b_new(mem::size_of::<Fingerprint>(), &[]),
bytes_hashed: 0
}
}
@ -30,17 +30,43 @@ impl IchHasher {
pub fn bytes_hashed(&self) -> u64 {
self.bytes_hashed
}
pub fn finish(self) -> Fingerprint {
let mut fingerprint = Fingerprint::zero();
blake2b::blake2b_final(self.state, &mut fingerprint.0);
fingerprint
}
}
impl Hasher for IchHasher {
#[inline]
fn finish(&self) -> u64 {
self.state.finish()
bug!("Use other finish() implementation to get the full 128-bit hash.");
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.state.write(bytes);
blake2b::blake2b_update(&mut self.state, bytes);
self.bytes_hashed += bytes.len() as u64;
}
#[inline]
fn write_u16(&mut self, i: u16) {
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i.to_le()) })
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i.to_le()) })
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i.to_le()) })
}
#[inline]
fn write_usize(&mut self, i: usize) {
// always hash as u64, so we don't depend on the size of `usize`
self.write_u64(i as u64);
}
}

View file

@ -29,7 +29,7 @@
use syntax::ast;
use std::cell::RefCell;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
@ -43,21 +43,22 @@ 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;
mod hasher;
pub mod hasher;
pub struct IncrementalHashesMap {
hashes: FnvHashMap<DepNode<DefId>, u64>,
hashes: FnvHashMap<DepNode<DefId>, Fingerprint>,
// These are the metadata hashes for the current crate as they were stored
// during the last compilation session. They are only loaded if
// -Z query-dep-graph was specified and are needed for auto-tests using
// the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
// check whether some metadata hash has changed in between two revisions.
pub prev_metadata_hashes: RefCell<FnvHashMap<DefId, u64>>,
pub prev_metadata_hashes: RefCell<FnvHashMap<DefId, Fingerprint>>,
}
impl IncrementalHashesMap {
@ -68,11 +69,12 @@ impl IncrementalHashesMap {
}
}
pub fn insert(&mut self, k: DepNode<DefId>, v: u64) -> Option<u64> {
pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
self.hashes.insert(k, v)
}
pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, u64> {
pub fn iter<'a>(&'a self)
-> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
self.hashes.iter()
}
@ -82,9 +84,9 @@ impl IncrementalHashesMap {
}
impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
type Output = u64;
type Output = Fingerprint;
fn index(&self, index: &'a DepNode<DefId>) -> &u64 {
fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
&self.hashes[index]
}
}
@ -141,12 +143,13 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
&mut self.def_path_hashes,
&mut self.codemap,
self.hash_spans));
let bytes_hashed = state.bytes_hashed();
let item_hash = state.finish();
self.hashes.insert(DepNode::Hir(def_id), item_hash);
debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
state.bytes_hashed();
bytes_hashed;
self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
}

View file

@ -0,0 +1,81 @@
// 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 rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
const FINGERPRINT_LENGTH: usize = 16;
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
pub struct Fingerprint(pub [u8; FINGERPRINT_LENGTH]);
impl Fingerprint {
#[inline]
pub fn zero() -> Fingerprint {
Fingerprint([0; FINGERPRINT_LENGTH])
}
pub fn from_smaller_hash(hash: u64) -> Fingerprint {
let mut result = Fingerprint::zero();
result.0[0] = (hash >> 0) as u8;
result.0[1] = (hash >> 8) as u8;
result.0[2] = (hash >> 16) as u8;
result.0[3] = (hash >> 24) as u8;
result.0[4] = (hash >> 32) as u8;
result.0[5] = (hash >> 40) as u8;
result.0[6] = (hash >> 48) as u8;
result.0[7] = (hash >> 56) as u8;
result
}
pub fn to_smaller_hash(&self) -> u64 {
((self.0[0] as u64) << 0) |
((self.0[1] as u64) << 8) |
((self.0[2] as u64) << 16) |
((self.0[3] as u64) << 24) |
((self.0[4] as u64) << 32) |
((self.0[5] as u64) << 40) |
((self.0[6] as u64) << 48) |
((self.0[7] as u64) << 56)
}
}
impl Encodable for Fingerprint {
#[inline]
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
for &byte in &self.0[..] {
s.emit_u8(byte)?;
}
Ok(())
}
}
impl Decodable for Fingerprint {
#[inline]
fn decode<D: Decoder>(d: &mut D) -> Result<Fingerprint, D::Error> {
let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]);
for byte in &mut result.0[..] {
*byte = d.read_u8()?;
}
Ok(result)
}
}
impl ::std::fmt::Display for Fingerprint {
fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
for i in 0 .. self.0.len() {
if i > 0 {
write!(formatter, "::")?;
}
write!(formatter, "{}", self.0[i])?;
}
Ok(())
}
}

View file

@ -0,0 +1,13 @@
// 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.
pub use self::fingerprint::Fingerprint;
mod fingerprint;

View file

@ -45,6 +45,7 @@ const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
mod assert_dep_graph;
mod calculate_svh;
mod persist;
pub mod ich;
pub use assert_dep_graph::assert_dep_graph;
pub use calculate_svh::compute_incremental_hashes_map;

View file

@ -14,6 +14,7 @@ use rustc::dep_graph::{DepNode, WorkProduct, WorkProductId};
use rustc::hir::def_id::DefIndex;
use std::sync::Arc;
use rustc_data_structures::fnv::FnvHashMap;
use ich::Fingerprint;
use super::directory::DefPathIndex;
@ -60,7 +61,7 @@ pub struct SerializedHash {
/// the hash as of previous compilation, computed by code in
/// `hash` module
pub hash: u64,
pub hash: Fingerprint,
}
#[derive(Debug, RustcEncodable, RustcDecodable)]
@ -116,5 +117,5 @@ pub struct SerializedMetadataHash {
pub def_index: DefIndex,
/// the hash itself, computed by `calculate_item_hash`
pub hash: u64,
pub hash: Fingerprint,
}

View file

@ -51,6 +51,7 @@ use rustc_data_structures::fnv::{FnvHashSet, FnvHashMap};
use syntax::parse::token::InternedString;
use syntax_pos::Span;
use rustc::ty::TyCtxt;
use ich::Fingerprint;
use {ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA};
@ -186,8 +187,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
}
pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
prev_metadata_hashes: &FnvHashMap<DefId, u64>,
current_metadata_hashes: &FnvHashMap<DefId, u64>) {
prev_metadata_hashes: &FnvHashMap<DefId, Fingerprint>,
current_metadata_hashes: &FnvHashMap<DefId, Fingerprint>) {
if !tcx.sess.opts.debugging_opts.query_dep_graph {
return;
}
@ -204,8 +205,8 @@ pub fn check_dirty_clean_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub struct DirtyCleanMetadataVisitor<'a, 'tcx:'a, 'm> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
prev_metadata_hashes: &'m FnvHashMap<DefId, u64>,
current_metadata_hashes: &'m FnvHashMap<DefId, u64>,
prev_metadata_hashes: &'m FnvHashMap<DefId, Fingerprint>,
current_metadata_hashes: &'m FnvHashMap<DefId, Fingerprint>,
}
impl<'a, 'tcx, 'm> Visitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {

View file

@ -18,6 +18,7 @@ use rustc_serialize::Decodable;
use rustc_serialize::opaque::Decoder;
use IncrementalHashesMap;
use ich::Fingerprint;
use super::data::*;
use super::fs::*;
use super::file_format;
@ -25,7 +26,7 @@ use super::file_format;
pub struct HashContext<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
incremental_hashes_map: &'a IncrementalHashesMap,
item_metadata_hashes: FnvHashMap<DefId, u64>,
item_metadata_hashes: FnvHashMap<DefId, Fingerprint>,
crate_hashes: FnvHashMap<CrateNum, Svh>,
}
@ -50,7 +51,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
}
}
pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<u64> {
pub fn hash(&mut self, dep_node: &DepNode<DefId>) -> Option<Fingerprint> {
match *dep_node {
DepNode::Krate => {
Some(self.incremental_hashes_map[dep_node])
@ -89,7 +90,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
}
}
fn metadata_hash(&mut self, def_id: DefId) -> u64 {
fn metadata_hash(&mut self, def_id: DefId) -> Fingerprint {
debug!("metadata_hash(def_id={:?})", def_id);
assert!(!def_id.is_local());
@ -102,14 +103,15 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
// check whether we did not find detailed metadata for this
// krate; in that case, we just use the krate's overall hash
if let Some(&hash) = self.crate_hashes.get(&def_id.krate) {
debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash);
if let Some(&svh) = self.crate_hashes.get(&def_id.krate) {
debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, svh);
// micro-"optimization": avoid a cache miss if we ask
// for metadata from this particular def-id again.
self.item_metadata_hashes.insert(def_id, hash.as_u64());
let fingerprint = svh_to_fingerprint(svh);
self.item_metadata_hashes.insert(def_id, fingerprint);
return hash.as_u64();
return fingerprint;
}
// otherwise, load the data and repeat.
@ -206,3 +208,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
Ok(())
}
}
fn svh_to_fingerprint(svh: Svh) -> Fingerprint {
Fingerprint::from_smaller_hash(svh.as_u64())
}

View file

@ -22,6 +22,7 @@ use std::fs;
use std::path::{Path};
use IncrementalHashesMap;
use ich::Fingerprint;
use super::data::*;
use super::directory::*;
use super::dirty_clean;
@ -315,7 +316,7 @@ fn delete_dirty_work_product(tcx: TyCtxt,
fn load_prev_metadata_hashes(tcx: TyCtxt,
retraced: &RetracedDefIdDirectory,
output: &mut FnvHashMap<DefId, u64>) {
output: &mut FnvHashMap<DefId, Fingerprint>) {
if !tcx.sess.opts.debugging_opts.query_dep_graph {
return
}

View file

@ -14,6 +14,7 @@ use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::graph::{DepthFirstTraversal, INCOMING, NodeIndex};
use super::hash::*;
use ich::Fingerprint;
/// A data-structure that makes it easy to enumerate the hashable
/// predecessors of any given dep-node.
@ -26,7 +27,7 @@ pub struct Predecessors<'query> {
// - Keys: some hashable node
// - Values: the hash thereof
pub hashes: FnvHashMap<&'query DepNode<DefId>, u64>,
pub hashes: FnvHashMap<&'query DepNode<DefId>, Fingerprint>,
}
impl<'q> Predecessors<'q> {

View file

@ -16,13 +16,13 @@ use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_serialize::Encodable as RustcEncodable;
use rustc_serialize::opaque::Encoder;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use std::io::{self, Cursor, Write};
use std::fs::{self, File};
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use IncrementalHashesMap;
use ich::Fingerprint;
use super::data::*;
use super::directory::*;
use super::hash::*;
@ -30,6 +30,7 @@ use super::preds::*;
use super::fs::*;
use super::dirty_clean;
use super::file_format;
use calculate_svh::hasher::IchHasher;
pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
incremental_hashes_map: &IncrementalHashesMap,
@ -185,7 +186,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
svh: Svh,
preds: &Predecessors,
builder: &mut DefIdDirectoryBuilder,
current_metadata_hashes: &mut FnvHashMap<DefId, u64>,
current_metadata_hashes: &mut FnvHashMap<DefId, Fingerprint>,
encoder: &mut Encoder)
-> io::Result<()> {
// For each `MetaData(X)` node where `X` is local, accumulate a
@ -233,7 +234,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
// is the det. hash of the def-path. This is convenient
// because we can sort this to get a stable ordering across
// compilations, even if the def-ids themselves have changed.
let mut hashes: Vec<(DepNode<u64>, u64)> = sources.iter()
let mut hashes: Vec<(DepNode<u64>, Fingerprint)> = sources.iter()
.map(|dep_node| {
let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))).unwrap();
let hash = preds.hashes[dep_node];
@ -242,7 +243,7 @@ pub fn encode_metadata_hashes(tcx: TyCtxt,
.collect();
hashes.sort();
let mut state = DefaultHasher::new();
let mut state = IchHasher::new();
hashes.hash(&mut state);
let hash = state.finish();

View file

@ -130,7 +130,7 @@ pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
-> LinkMeta {
let r = LinkMeta {
crate_name: name.to_owned(),
crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate]),
crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()),
};
info!("{:?}", r);
return r;