libcore: Remove mutable fields from hash

This commit is contained in:
Patrick Walton 2013-05-03 11:30:30 -07:00
parent 2961997f16
commit 4dc1c2976d
6 changed files with 160 additions and 111 deletions

View file

@ -19,12 +19,16 @@
* CPRNG like rand::rng. * CPRNG like rand::rng.
*/ */
use io; #[cfg(stage0)]
use io::Writer; use cast;
use rt::io::Writer;
use to_bytes::IterBytes; use to_bytes::IterBytes;
use uint; use uint;
use vec; use vec;
// Alias `SipState` to `State`.
pub use State = hash::SipState;
/** /**
* Types that can meaningfully be hashed should implement this. * Types that can meaningfully be hashed should implement this.
* *
@ -65,20 +69,32 @@ impl<A:Hash> HashUtil for A {
/// Streaming hash-functions should implement this. /// Streaming hash-functions should implement this.
pub trait Streaming { pub trait Streaming {
fn input(&self, (&const [u8])); fn input(&mut self, &[u8]);
// These can be refactored some when we have default methods. // These can be refactored some when we have default methods.
fn result_bytes(&self) -> ~[u8]; fn result_bytes(&mut self) -> ~[u8];
fn result_str(&self) -> ~str; fn result_str(&mut self) -> ~str;
fn result_u64(&self) -> u64; fn result_u64(&mut self) -> u64;
fn reset(&self); fn reset(&mut self);
}
// XXX: Ugly workaround for bootstrapping.
#[cfg(stage0)]
fn transmute_for_stage0<'a>(bytes: &'a [const u8]) -> &'a [u8] {
unsafe {
cast::transmute(bytes)
}
}
#[cfg(not(stage0))]
fn transmute_for_stage0<'a>(bytes: &'a [u8]) -> &'a [u8] {
bytes
} }
impl<A:IterBytes> Hash for A { impl<A:IterBytes> Hash for A {
#[inline(always)] #[inline(always)]
fn hash_keyed(&self, k0: u64, k1: u64) -> u64 { fn hash_keyed(&self, k0: u64, k1: u64) -> u64 {
let s = &State(k0, k1); let mut s = State::new(k0, k1);
for self.iter_bytes(true) |bytes| { for self.iter_bytes(true) |bytes| {
s.input(bytes); s.input(transmute_for_stage0(bytes));
} }
s.result_u64() s.result_u64()
} }
@ -86,32 +102,56 @@ impl<A:IterBytes> Hash for A {
fn hash_keyed_2<A: IterBytes, fn hash_keyed_2<A: IterBytes,
B: IterBytes>(a: &A, b: &B, k0: u64, k1: u64) -> u64 { B: IterBytes>(a: &A, b: &B, k0: u64, k1: u64) -> u64 {
let s = &State(k0, k1); let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| { s.input(bytes); } for a.iter_bytes(true) |bytes| {
for b.iter_bytes(true) |bytes| { s.input(bytes); } s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64() s.result_u64()
} }
fn hash_keyed_3<A: IterBytes, fn hash_keyed_3<A: IterBytes,
B: IterBytes, B: IterBytes,
C: IterBytes>(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 { C: IterBytes>(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 {
let s = &State(k0, k1); let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| { s.input(bytes); } for a.iter_bytes(true) |bytes| {
for b.iter_bytes(true) |bytes| { s.input(bytes); } s.input(transmute_for_stage0(bytes));
for c.iter_bytes(true) |bytes| { s.input(bytes); } }
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for c.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64() s.result_u64()
} }
fn hash_keyed_4<A: IterBytes, fn hash_keyed_4<A: IterBytes,
B: IterBytes, B: IterBytes,
C: IterBytes, C: IterBytes,
D: IterBytes>(a: &A, b: &B, c: &C, d: &D, k0: u64, k1: u64) D: IterBytes>(
-> u64 { a: &A,
let s = &State(k0, k1); b: &B,
for a.iter_bytes(true) |bytes| { s.input(bytes); } c: &C,
for b.iter_bytes(true) |bytes| { s.input(bytes); } d: &D,
for c.iter_bytes(true) |bytes| { s.input(bytes); } k0: u64,
for d.iter_bytes(true) |bytes| { s.input(bytes); } k1: u64)
-> u64 {
let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for c.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for d.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64() s.result_u64()
} }
@ -119,58 +159,68 @@ fn hash_keyed_5<A: IterBytes,
B: IterBytes, B: IterBytes,
C: IterBytes, C: IterBytes,
D: IterBytes, D: IterBytes,
E: IterBytes>(a: &A, b: &B, c: &C, d: &D, e: &E, E: IterBytes>(
k0: u64, k1: u64) -> u64 { a: &A,
let s = &State(k0, k1); b: &B,
for a.iter_bytes(true) |bytes| { s.input(bytes); } c: &C,
for b.iter_bytes(true) |bytes| { s.input(bytes); } d: &D,
for c.iter_bytes(true) |bytes| { s.input(bytes); } e: &E,
for d.iter_bytes(true) |bytes| { s.input(bytes); } k0: u64,
for e.iter_bytes(true) |bytes| { s.input(bytes); } k1: u64)
-> u64 {
let mut s = State::new(k0, k1);
for a.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for b.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for c.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for d.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
for e.iter_bytes(true) |bytes| {
s.input(transmute_for_stage0(bytes));
}
s.result_u64() s.result_u64()
} }
// Implement State as SipState
pub type State = SipState;
#[inline(always)]
pub fn State(k0: u64, k1: u64) -> State {
SipState(k0, k1)
}
#[inline(always)] #[inline(always)]
pub fn default_state() -> State { pub fn default_state() -> State {
State(0,0) State::new(0, 0)
} }
struct SipState { struct SipState {
k0: u64, k0: u64,
k1: u64, k1: u64,
mut length: uint, // how many bytes we've processed length: uint, // how many bytes we've processed
mut v0: u64, // hash state v0: u64, // hash state
mut v1: u64, v1: u64,
mut v2: u64, v2: u64,
mut v3: u64, v3: u64,
mut tail: [u8, ..8], // unprocessed bytes tail: [u8, ..8], // unprocessed bytes
mut ntail: uint, // how many bytes in tail are valid ntail: uint, // how many bytes in tail are valid
} }
#[inline(always)] impl SipState {
fn SipState(key0: u64, key1: u64) -> SipState { #[inline(always)]
let state = SipState { fn new(key0: u64, key1: u64) -> SipState {
k0 : key0, let mut state = SipState {
k1 : key1, k0: key0,
mut length : 0u, k1: key1,
mut v0 : 0u64, length: 0,
mut v1 : 0u64, v0: 0,
mut v2 : 0u64, v1: 0,
mut v3 : 0u64, v2: 0,
mut tail : [0u8,0,0,0,0,0,0,0], v3: 0,
mut ntail : 0u, tail: [ 0, 0, 0, 0, 0, 0, 0, 0 ],
}; ntail: 0,
(&state).reset(); };
state state.reset();
state
}
} }
// sadly, these macro definitions can't appear later, // sadly, these macro definitions can't appear later,
@ -207,12 +257,10 @@ macro_rules! compress (
) )
impl io::Writer for SipState { impl Writer for SipState {
// Methods for io::writer // Methods for io::writer
#[inline(always)] #[inline(always)]
fn write(&self, msg: &const [u8]) { fn write(&mut self, msg: &[u8]) {
let length = msg.len(); let length = msg.len();
self.length += length; self.length += length;
@ -272,29 +320,19 @@ impl io::Writer for SipState {
self.ntail = left; self.ntail = left;
} }
fn seek(&self, _x: int, _s: io::SeekStyle) { fn flush(&mut self) {
fail!(); // No-op
}
fn tell(&self) -> uint {
self.length
}
fn flush(&self) -> int {
0
}
fn get_type(&self) -> io::WriterType {
io::File
} }
} }
impl Streaming for SipState { impl Streaming for SipState {
#[inline(always)] #[inline(always)]
fn input(&self, buf: &const [u8]) { fn input(&mut self, buf: &[u8]) {
self.write(buf); self.write(buf);
} }
#[inline(always)] #[inline(always)]
fn result_u64(&self) -> u64 { fn result_u64(&mut self) -> u64 {
let mut v0 = self.v0; let mut v0 = self.v0;
let mut v1 = self.v1; let mut v1 = self.v1;
let mut v2 = self.v2; let mut v2 = self.v2;
@ -324,7 +362,7 @@ impl Streaming for SipState {
return (v0 ^ v1 ^ v2 ^ v3); return (v0 ^ v1 ^ v2 ^ v3);
} }
fn result_bytes(&self) -> ~[u8] { fn result_bytes(&mut self) -> ~[u8] {
let h = self.result_u64(); let h = self.result_u64();
~[(h >> 0) as u8, ~[(h >> 0) as u8,
(h >> 8) as u8, (h >> 8) as u8,
@ -337,7 +375,7 @@ impl Streaming for SipState {
] ]
} }
fn result_str(&self) -> ~str { fn result_str(&mut self) -> ~str {
let r = self.result_bytes(); let r = self.result_bytes();
let mut s = ~""; let mut s = ~"";
for vec::each(r) |b| { for vec::each(r) |b| {
@ -347,7 +385,7 @@ impl Streaming for SipState {
} }
#[inline(always)] #[inline(always)]
fn reset(&self) { fn reset(&mut self) {
self.length = 0; self.length = 0;
self.v0 = self.k0 ^ 0x736f6d6570736575; self.v0 = self.k0 ^ 0x736f6d6570736575;
self.v1 = self.k1 ^ 0x646f72616e646f6d; self.v1 = self.k1 ^ 0x646f72616e646f6d;
@ -529,4 +567,4 @@ mod tests {
val & !(0xff << (byte * 8)) val & !(0xff << (byte * 8))
} }
} }
} }

View file

@ -22,9 +22,9 @@ use util::ppaux;
use core::hash::Streaming; use core::hash::Streaming;
use core::hash; use core::hash;
use core::io::WriterUtil;
use core::libc::{c_int, c_uint}; use core::libc::{c_int, c_uint};
use core::os::consts::{macos, freebsd, linux, android, win32}; use core::os::consts::{macos, freebsd, linux, android, win32};
use core::rt::io::Writer;
use core::run; use core::run;
use syntax::ast; use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name}; use syntax::ast_map::{path, path_mod, path_name};
@ -41,6 +41,11 @@ pub enum output_type {
output_type_exe, output_type_exe,
} }
fn write_string<W:Writer>(writer: &mut W, string: &str) {
let buffer = str::as_bytes_slice(string);
writer.write(buffer);
}
pub fn llvm_err(sess: Session, msg: ~str) -> ! { pub fn llvm_err(sess: Session, msg: ~str) -> ! {
unsafe { unsafe {
let cstr = llvm::LLVMRustGetLastError(); let cstr = llvm::LLVMRustGetLastError();
@ -458,9 +463,11 @@ pub mod write {
* *
*/ */
pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, pub fn build_link_meta(sess: Session,
symbol_hasher: &hash::State) -> LinkMeta { c: &ast::crate,
output: &Path,
symbol_hasher: &mut hash::State)
-> LinkMeta {
struct ProvidedMetas { struct ProvidedMetas {
name: Option<@str>, name: Option<@str>,
vers: Option<@str>, vers: Option<@str>,
@ -498,7 +505,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
} }
// This calculates CMH as defined above // This calculates CMH as defined above
fn crate_meta_extras_hash(symbol_hasher: &hash::State, fn crate_meta_extras_hash(symbol_hasher: &mut hash::State,
cmh_items: ~[@ast::meta_item], cmh_items: ~[@ast::meta_item],
dep_hashes: ~[~str]) -> @str { dep_hashes: ~[~str]) -> @str {
fn len_and_str(s: &str) -> ~str { fn len_and_str(s: &str) -> ~str {
@ -511,17 +518,17 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
let cmh_items = attr::sort_meta_items(cmh_items); let cmh_items = attr::sort_meta_items(cmh_items);
fn hash(symbol_hasher: &hash::State, m: &@ast::meta_item) { fn hash(symbol_hasher: &mut hash::State, m: &@ast::meta_item) {
match m.node { match m.node {
ast::meta_name_value(key, value) => { ast::meta_name_value(key, value) => {
symbol_hasher.write_str(len_and_str(*key)); write_string(symbol_hasher, len_and_str(*key));
symbol_hasher.write_str(len_and_str_lit(value)); write_string(symbol_hasher, len_and_str_lit(value));
} }
ast::meta_word(name) => { ast::meta_word(name) => {
symbol_hasher.write_str(len_and_str(*name)); write_string(symbol_hasher, len_and_str(*name));
} }
ast::meta_list(name, ref mis) => { ast::meta_list(name, ref mis) => {
symbol_hasher.write_str(len_and_str(*name)); write_string(symbol_hasher, len_and_str(*name));
for mis.each |m_| { for mis.each |m_| {
hash(symbol_hasher, m_); hash(symbol_hasher, m_);
} }
@ -535,7 +542,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
} }
for dep_hashes.each |dh| { for dep_hashes.each |dh| {
symbol_hasher.write_str(len_and_str(*dh)); write_string(symbol_hasher, len_and_str(*dh));
} }
// tjc: allocation is unfortunate; need to change core::hash // tjc: allocation is unfortunate; need to change core::hash
@ -596,23 +603,26 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
} }
} }
pub fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str { pub fn truncated_hash_result(symbol_hasher: &mut hash::State) -> ~str {
symbol_hasher.result_str() symbol_hasher.result_str()
} }
// This calculates STH for a symbol, as defined above // This calculates STH for a symbol, as defined above
pub fn symbol_hash(tcx: ty::ctxt, symbol_hasher: &hash::State, t: ty::t, pub fn symbol_hash(tcx: ty::ctxt,
link_meta: LinkMeta) -> @str { symbol_hasher: &mut hash::State,
t: ty::t,
link_meta: LinkMeta)
-> @str {
// NB: do *not* use abbrevs here as we want the symbol names // NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate. // to be independent of one another in the crate.
symbol_hasher.reset(); symbol_hasher.reset();
symbol_hasher.write_str(link_meta.name); write_string(symbol_hasher, link_meta.name);
symbol_hasher.write_str(~"-"); write_string(symbol_hasher, ~"-");
symbol_hasher.write_str(link_meta.extras_hash); write_string(symbol_hasher, link_meta.extras_hash);
symbol_hasher.write_str(~"-"); write_string(symbol_hasher, ~"-");
symbol_hasher.write_str(encoder::encoded_ty(tcx, t)); write_string(symbol_hasher, encoder::encoded_ty(tcx, t));
let mut hash = truncated_hash_result(symbol_hasher); let mut hash = truncated_hash_result(symbol_hasher);
// Prefix with _ so that it never blends into adjacent digits // Prefix with _ so that it never blends into adjacent digits
str::unshift_char(&mut hash, '_'); str::unshift_char(&mut hash, '_');

View file

@ -2987,9 +2987,8 @@ pub fn trans_crate(sess: session::Session,
emap2: resolve::ExportMap2, emap2: resolve::ExportMap2,
maps: astencode::Maps) -> (ModuleRef, LinkMeta) { maps: astencode::Maps) -> (ModuleRef, LinkMeta) {
let symbol_hasher = @hash::default_state(); let symbol_hasher = @mut hash::default_state();
let link_meta = let link_meta = link::build_link_meta(sess, crate, output, symbol_hasher);
link::build_link_meta(sess, crate, output, symbol_hasher);
let reachable = reachable::find_reachable( let reachable = reachable::find_reachable(
&crate.node.module, &crate.node.module,
emap2, emap2,

View file

@ -207,7 +207,7 @@ pub struct CrateContext {
adt_reprs: @mut HashMap<ty::t, @adt::Repr>, adt_reprs: @mut HashMap<ty::t, @adt::Repr>,
names: namegen, names: namegen,
next_addrspace: addrspace_gen, next_addrspace: addrspace_gen,
symbol_hasher: @hash::State, symbol_hasher: @mut hash::State,
type_hashcodes: @mut HashMap<ty::t, @str>, type_hashcodes: @mut HashMap<ty::t, @str>,
type_short_names: @mut HashMap<ty::t, ~str>, type_short_names: @mut HashMap<ty::t, ~str>,
all_llvm_symbols: @mut HashSet<@~str>, all_llvm_symbols: @mut HashSet<@~str>,

View file

@ -230,6 +230,7 @@ pub fn future_writer_factory(
let markdown_ch = markdown_ch.clone(); let markdown_ch = markdown_ch.clone();
do task::spawn || { do task::spawn || {
let (writer, future) = future_writer(); let (writer, future) = future_writer();
let mut future = future;
writer_ch.send(writer); writer_ch.send(writer);
let s = future.get(); let s = future.get();
markdown_ch.send((copy page, s)); markdown_ch.send((copy page, s));

View file

@ -11,6 +11,7 @@
use core::*; use core::*;
use core::cmp::Ord; use core::cmp::Ord;
use core::hash::Streaming; use core::hash::Streaming;
use core::rt::io::Writer;
use rustc::driver::{driver, session}; use rustc::driver::{driver, session};
use rustc::driver::session::{lib_crate, unknown_crate}; use rustc::driver::session::{lib_crate, unknown_crate};
use rustc::metadata::filesearch; use rustc::metadata::filesearch;
@ -367,9 +368,9 @@ pub fn error(msg: ~str) {
} }
pub fn hash(data: ~str) -> ~str { pub fn hash(data: ~str) -> ~str {
let hasher = &hash::default_state(); let mut hasher = hash::default_state();
let buffer = str::as_bytes_slice(data);
hasher.write_str(data); hasher.write(buffer);
hasher.result_str() hasher.result_str()
} }