change svh to store a u64

We used to store a u64 converted to a String for some reason. Now we
don't.
This commit is contained in:
Niko Matsakis 2016-05-06 05:01:09 -04:00
parent 08837d2975
commit 0082fc0ad4
6 changed files with 38 additions and 55 deletions

View File

@ -10,60 +10,34 @@
//! Calculation and management of a Strict Version Hash for crates //! Calculation and management of a Strict Version Hash for crates
//! //!
//! # Today's ABI problem //! The SVH is used for incremental compilation to track when HIR
//! //! nodes have changed between compilations, and also to detect
//! In today's implementation of rustc, it is incredibly difficult to achieve //! mismatches where we have two versions of the same crate that were
//! forward binary compatibility without resorting to C-like interfaces. Within //! compiled from distinct sources.
//! 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
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher};
#[derive(Clone, Eq, Hash, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Svh { pub struct Svh {
hash: String, hash: u64,
} }
impl Svh { impl Svh {
/// Create a new `Svh` given the hash. If you actually want to /// Create a new `Svh` given the hash. If you actually want to
/// compute the SVH from some HIR, you want the `calculate_svh` /// compute the SVH from some HIR, you want the `calculate_svh`
/// function found in `librustc_trans`. /// function found in `librustc_incremental`.
pub fn new(hash: String) -> Svh { pub fn new(hash: u64) -> Svh {
assert!(hash.len() == 16);
Svh { hash: hash } Svh { hash: hash }
} }
pub fn from_hash(hash: u64) -> Svh { pub fn as_u64(&self) -> u64 {
return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect()); 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 { fn hex(b: u64) -> char {
let b = (b & 0xf) as u8; let b = (b & 0xf) as u8;
@ -74,14 +48,16 @@ impl Svh {
b as char b as char
} }
} }
}
pub fn as_str<'a>(&'a self) -> &'a str { impl Hash for Svh {
&self.hash fn hash<H>(&self, state: &mut H) where H: Hasher {
self.hash.to_le().hash(state);
} }
} }
impl fmt::Display for Svh { impl fmt::Display for Svh {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(self.as_str()) f.pad(&self.to_string())
} }
} }

View File

@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} else { } else {
tcx.sess.cstore.crate_hash(did.krate) tcx.sess.cstore.crate_hash(did.krate)
}; };
h.as_str().hash(state); h.hash(state);
did.index.hash(state); did.index.hash(state);
}; };
let mt = |state: &mut SipHasher, mt: TypeAndMut| { let mt = |state: &mut SipHasher, mt: TypeAndMut| {

View File

@ -72,12 +72,14 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
attr.node.value.hash(&mut state); attr.node.value.hash(&mut state);
} }
Svh::from_hash(state.finish()) Svh::new(state.finish())
} }
fn calculate_item_hash(self, def_id: DefId) -> u64 { fn calculate_item_hash(self, def_id: DefId) -> u64 {
assert!(def_id.is_local()); assert!(def_id.is_local());
debug!("calculate_item_hash(def_id={:?})", def_id);
let mut state = SipHasher::new(); let mut state = SipHasher::new();
{ {
@ -89,11 +91,16 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
intravisit::walk_crate(&mut visit, krate); intravisit::walk_crate(&mut visit, krate);
} else { } else {
let node_id = self.map.as_local_node_id(def_id).unwrap(); 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
} }
} }

View File

@ -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)| { reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
let name = docstr(depdoc, tag_crate_dep_crate_name); 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 doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
let explicitly_linked = reader::doc_as_u8(doc) != 0; let explicitly_linked = reader::doc_as_u8(doc) != 0;
CrateDep { 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<Svh> { pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
let cratedoc = rbml::Doc::new(data); let cratedoc = rbml::Doc::new(data);
reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { 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 { pub fn get_crate_hash(data: &[u8]) -> Svh {
let cratedoc = rbml::Doc::new(data); let cratedoc = rbml::Doc::new(data);
let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); 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> { pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {

View File

@ -1793,14 +1793,14 @@ fn encode_crate_dep(rbml_w: &mut Encoder,
rbml_w.start_tag(tag_crate_dep); rbml_w.start_tag(tag_crate_dep);
rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
let hash = decoder::get_crate_hash(dep.data()); 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, rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
dep.explicitly_linked.get() as u8); dep.explicitly_linked.get() as u8);
rbml_w.end_tag(); rbml_w.end_tag();
} }
fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { 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) { fn encode_rustc_version(rbml_w: &mut Encoder) {

View File

@ -620,7 +620,7 @@ impl<'a> Context<'a> {
info!("Rejecting via hash: expected {} got {}", *myhash, hash); info!("Rejecting via hash: expected {} got {}", *myhash, hash);
self.rejected_via_hash.push(CrateMismatch { self.rejected_via_hash.push(CrateMismatch {
path: libpath.to_path_buf(), path: libpath.to_path_buf(),
got: myhash.as_str().to_string() got: myhash.to_string()
}); });
return None; return None;
} }