mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-06 04:08: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
|
//! 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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| {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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> {
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user