diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs index 1536f884b09..f0294ad633a 100644 --- a/src/librustc/hir/svh.rs +++ b/src/librustc/hir/svh.rs @@ -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; @@ -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(&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()) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 08909861d3f..4f6188ea3c5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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| { diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs index f134f3c3f10..24ecce11487 100644 --- a/src/librustc_incremental/calculate_svh.rs +++ b/src/librustc_incremental/calculate_svh.rs @@ -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(); { @@ -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 } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d7499342bf5..5e4c9f39e35 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1251,7 +1251,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec { 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 { @@ -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 { 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> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1b313aac7ca..928601095b0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -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) { diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 4ecb7a28ef7..a5b1c3d301b 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -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; }