mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
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:
parent
08837d2975
commit
0082fc0ad4
@ -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<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())
|
||||
}
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
@ -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> {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user