Skip to content

Commit

Permalink
change svh to store a u64
Browse files Browse the repository at this point in the history
We used to store a u64 converted to a String for some reason. Now we
don't.
  • Loading branch information
nikomatsakis committed May 18, 2016
1 parent 08837d2 commit 0082fc0
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 55 deletions.
66 changes: 21 additions & 45 deletions src/librustc/hir/svh.rs
Expand Up @@ -10,60 +10,34 @@

//! Calculation and management of a Strict Version Hash for crates
//!
//! # Today's ABI problem
//!
//! In today's implementation of rustc, it is incredibly difficult to achieve
//! forward binary compatibility without resorting to C-like interfaces. Within
//! rust code itself, abi details such as symbol names suffer from a variety of
//! unrelated factors to code changing such as the "def id drift" problem. This
//! ends up yielding confusing error messages about metadata mismatches and
//! such.
//!
//! The core of this problem is when an upstream dependency changes and
//! downstream dependents are not recompiled. This causes compile errors because
//! the upstream crate's metadata has changed but the downstream crates are
//! still referencing the older crate's metadata.
//!
//! This problem exists for many reasons, the primary of which is that rust does
//! not currently support forwards ABI compatibility (in place upgrades of a
//! crate).
//!
//! # SVH and how it alleviates the problem
//!
//! With all of this knowledge on hand, this module contains the implementation
//! of a notion of a "Strict Version Hash" for a crate. This is essentially a
//! hash of all contents of a crate which can somehow be exposed to downstream
//! crates.
//!
//! This hash is currently calculated by just hashing the AST, but this is
//! obviously wrong (doc changes should not result in an incompatible ABI).
//! Implementation-wise, this is required at this moment in time.
//!
//! By encoding this strict version hash into all crate's metadata, stale crates
//! can be detected immediately and error'd about by rustc itself.
//!
//! # Relevant links
//!
//! Original issue: https://github.com/rust-lang/rust/issues/10207
//! The SVH is used for incremental compilation to track when HIR
//! nodes have changed between compilations, and also to detect
//! mismatches where we have two versions of the same crate that were
//! compiled from distinct sources.

use std::fmt;
use std::hash::{Hash, Hasher};

#[derive(Clone, Eq, Hash, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Svh {
hash: String,
hash: u64,
}

impl Svh {
/// Create a new `Svh` given the hash. If you actually want to
/// compute the SVH from some HIR, you want the `calculate_svh`
/// function found in `librustc_trans`.
pub fn new(hash: String) -> Svh {
assert!(hash.len() == 16);
/// function found in `librustc_incremental`.
pub fn new(hash: u64) -> Svh {
Svh { hash: hash }
}

pub fn from_hash(hash: u64) -> Svh {
return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect());
pub fn as_u64(&self) -> u64 {
self.hash
}

pub fn to_string(&self) -> String {
let hash = self.hash;
return (0..64).step_by(4).map(|i| hex(hash >> i)).collect();

fn hex(b: u64) -> char {
let b = (b & 0xf) as u8;
Expand All @@ -74,14 +48,16 @@ impl Svh {
b as char
}
}
}

pub fn as_str<'a>(&'a self) -> &'a str {
&self.hash
impl Hash for Svh {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.hash.to_le().hash(state);
}
}

impl fmt::Display for Svh {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(self.as_str())
f.pad(&self.to_string())
}
}
2 changes: 1 addition & 1 deletion src/librustc/ty/util.rs
Expand Up @@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} else {
tcx.sess.cstore.crate_hash(did.krate)
};
h.as_str().hash(state);
h.hash(state);
did.index.hash(state);
};
let mt = |state: &mut SipHasher, mt: TypeAndMut| {
Expand Down
13 changes: 10 additions & 3 deletions src/librustc_incremental/calculate_svh.rs
Expand Up @@ -72,12 +72,14 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
attr.node.value.hash(&mut state);
}

Svh::from_hash(state.finish())
Svh::new(state.finish())
}

fn calculate_item_hash(self, def_id: DefId) -> u64 {
assert!(def_id.is_local());

debug!("calculate_item_hash(def_id={:?})", def_id);

let mut state = SipHasher::new();

{
Expand All @@ -89,11 +91,16 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
intravisit::walk_crate(&mut visit, krate);
} else {
let node_id = self.map.as_local_node_id(def_id).unwrap();
visit.visit_item(self.map.expect_item(node_id));
let item = self.map.expect_item(node_id);
visit.visit_item(item);
}
}

state.finish()
let hash = state.finish();

debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash);

hash
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/librustc_metadata/decoder.rs
Expand Up @@ -1251,7 +1251,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {

reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
let name = docstr(depdoc, tag_crate_dep_crate_name);
let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash));
let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash)));
let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
let explicitly_linked = reader::doc_as_u8(doc) != 0;
CrateDep {
Expand All @@ -1275,14 +1275,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
let cratedoc = rbml::Doc::new(data);
reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| {
Svh::new(doc.as_str_slice().to_string())
Svh::new(reader::doc_as_u64(doc))
})
}

pub fn get_crate_hash(data: &[u8]) -> Svh {
let cratedoc = rbml::Doc::new(data);
let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
Svh::new(hashdoc.as_str_slice().to_string())
Svh::new(reader::doc_as_u64(hashdoc))
}

pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_metadata/encoder.rs
Expand Up @@ -1793,14 +1793,14 @@ fn encode_crate_dep(rbml_w: &mut Encoder,
rbml_w.start_tag(tag_crate_dep);
rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
let hash = decoder::get_crate_hash(dep.data());
rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str());
rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
dep.explicitly_linked.get() as u8);
rbml_w.end_tag();
}

fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str());
rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64());
}

fn encode_rustc_version(rbml_w: &mut Encoder) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/loader.rs
Expand Up @@ -620,7 +620,7 @@ impl<'a> Context<'a> {
info!("Rejecting via hash: expected {} got {}", *myhash, hash);
self.rejected_via_hash.push(CrateMismatch {
path: libpath.to_path_buf(),
got: myhash.as_str().to_string()
got: myhash.to_string()
});
return None;
}
Expand Down

0 comments on commit 0082fc0

Please sign in to comment.