diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 58a9ea06410..b2eefca7fe2 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -32,6 +32,10 @@ newtype_index!(CrateNum /// A CrateNum value that indicates that something is wrong. const INVALID_CRATE = u32::MAX - 1, + + /// A special CrateNum that we use for the tcx.rcache when decoding from + /// the incr. comp. cache. + const RESERVED_FOR_INCR_COMP_CACHE = u32::MAX - 2, }); impl CrateNum { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c9b1d70e7b6..3bc2736586f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -45,6 +45,7 @@ use ty::AdtKind; use rustc_data_structures::indexed_vec; +use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::BTreeMap; use std::fmt; @@ -85,13 +86,37 @@ pub mod svh; /// the local_id part of the HirId changing, which is a very useful property in /// incremental compilation where we have to persist things through changes to /// the code base. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, - RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct HirId { pub owner: DefIndex, pub local_id: ItemLocalId, } +impl serialize::UseSpecializedEncodable for HirId { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + let HirId { + owner, + local_id, + } = *self; + + owner.encode(s)?; + local_id.encode(s) + } +} + +impl serialize::UseSpecializedDecodable for HirId { + fn default_decode(d: &mut D) -> Result { + let owner = DefIndex::decode(d)?; + let local_id = ItemLocalId::decode(d)?; + + Ok(HirId { + owner, + local_id + }) + } +} + + /// An `ItemLocalId` uniquely identifies something within a given "item-like", /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no /// guarantee that the numerical value of a given `ItemLocalId` corresponds to diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 8d65fd50ee5..20bddb15603 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -9,21 +9,29 @@ // except according to those terms. use dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::Idx; use errors::Diagnostic; +use hir; +use hir::def_id::{CrateNum, DefIndex, DefId, RESERVED_FOR_INCR_COMP_CACHE, + LOCAL_CRATE}; +use hir::map::definitions::{Definitions, DefPathTable}; +use middle::const_val::ByteArray; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, - SpecializedDecoder, SpecializedEncoder}; + SpecializedDecoder, SpecializedEncoder, + UseSpecializedDecodable}; use session::Session; use std::borrow::Cow; use std::cell::RefCell; use std::collections::BTreeMap; use std::mem; +use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; use syntax_pos::{BytePos, Span, NO_EXPANSION, DUMMY_SP}; use ty; -use ty::codec::{self as ty_codec}; +use ty::codec::{self as ty_codec, TyDecoder}; use ty::context::TyCtxt; +use ty::subst::Substs; /// `OnDiskCache` provides an interface to incr. comp. data cached from the /// previous compilation session. This data will eventually include the results @@ -65,9 +73,12 @@ impl<'sess> OnDiskCache<'sess> { let prev_diagnostics = { let mut decoder = CacheDecoder { + tcx: None, opaque: decoder, codemap: sess.codemap(), prev_filemap_starts: &header.prev_filemap_starts, + cnum_map: &IndexVec::new(), + prev_def_path_tables: &Vec::new(), }; let prev_diagnostics: FxHashMap<_, _> = { @@ -110,6 +121,7 @@ impl<'sess> OnDiskCache<'sess> { encoder, type_shorthands: FxHashMap(), predicate_shorthands: FxHashMap(), + definitions: tcx.hir.definitions(), }; let prev_filemap_starts: BTreeMap<_, _> = self @@ -174,13 +186,16 @@ impl<'sess> OnDiskCache<'sess> { /// A decoder that can read the incr. comp. cache. It is similar to the one /// we use for crate metadata decoding in that it can rebase spans and /// eventually will also handle things that contain `Ty` instances. -struct CacheDecoder<'a> { - opaque: opaque::Decoder<'a>, - codemap: &'a CodeMap, - prev_filemap_starts: &'a BTreeMap, +struct CacheDecoder<'a, 'tcx: 'a, 'x> { + tcx: Option>, + opaque: opaque::Decoder<'x>, + codemap: &'x CodeMap, + prev_filemap_starts: &'x BTreeMap, + cnum_map: &'x IndexVec>, + prev_def_path_tables: &'x Vec, } -impl<'a> CacheDecoder<'a> { +impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { fn find_filemap_prev_bytepos(&self, prev_bytepos: BytePos) -> Option<(BytePos, StableFilemapId)> { @@ -200,7 +215,7 @@ macro_rules! decoder_methods { } } -impl<'sess> Decoder for CacheDecoder<'sess> { +impl<'a, 'tcx, 'x> Decoder for CacheDecoder<'a, 'tcx, 'x> { type Error = String; decoder_methods! { @@ -232,7 +247,65 @@ impl<'sess> Decoder for CacheDecoder<'sess> { } } -impl<'a> SpecializedDecoder for CacheDecoder<'a> { +impl<'a, 'tcx: 'a, 'x> ty_codec::TyDecoder<'a, 'tcx> for CacheDecoder<'a, 'tcx, 'x> { + + #[inline] + fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx.expect("missing TyCtxt in CacheDecoder") + } + + #[inline] + fn position(&self) -> usize { + self.opaque.position() + } + + #[inline] + fn peek_byte(&self) -> u8 { + self.opaque.data[self.opaque.position()] + } + + fn cached_ty_for_shorthand(&mut self, + shorthand: usize, + or_insert_with: F) + -> Result, Self::Error> + where F: FnOnce(&mut Self) -> Result, Self::Error> + { + let tcx = self.tcx(); + + let cache_key = ty::CReaderCacheKey { + cnum: RESERVED_FOR_INCR_COMP_CACHE, + pos: shorthand, + }; + + if let Some(&ty) = tcx.rcache.borrow().get(&cache_key) { + return Ok(ty); + } + + let ty = or_insert_with(self)?; + tcx.rcache.borrow_mut().insert(cache_key, ty); + Ok(ty) + } + + fn with_position(&mut self, pos: usize, f: F) -> R + where F: FnOnce(&mut Self) -> R + { + debug_assert!(pos < self.opaque.data.len()); + + let new_opaque = opaque::Decoder::new(self.opaque.data, pos); + let old_opaque = mem::replace(&mut self.opaque, new_opaque); + let r = f(self); + self.opaque = old_opaque; + r + } + + fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum { + self.cnum_map[cnum].unwrap_or_else(|| { + bug!("Could not find new CrateNum for {:?}", cnum) + }) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { let lo = BytePos::decode(self)?; let hi = BytePos::decode(self)?; @@ -249,6 +322,142 @@ impl<'a> SpecializedDecoder for CacheDecoder<'a> { } } +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + let cnum = CrateNum::from_u32(u32::decode(self)?); + let mapped = self.map_encoded_cnum_to_current(cnum); + Ok(mapped) + } +} + +// This impl makes sure that we get a runtime error when we try decode a +// DefIndex that is not contained in a DefId. Such a case would be problematic +// because we would not know how to transform the DefIndex to the current +// context. +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + bug!("Trying to decode DefIndex outside the context of a DefId") + } +} + +// Both the CrateNum and the DefIndex of a DefId can change in between two +// compilation sessions. We use the DefPathHash, which is stable across +// sessions, to map the old DefId to the new one. +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + // Decode the unmapped CrateNum + let prev_cnum = CrateNum::default_decode(self)?; + + // Decode the unmapped DefIndex + let def_index = DefIndex::default_decode(self)?; + + // Unmapped CrateNum and DefIndex are valid keys for the *cached* + // DefPathTables, so we use them to look up the DefPathHash. + let def_path_hash = self.prev_def_path_tables[prev_cnum.index()] + .def_path_hash(def_index); + + // Using the DefPathHash, we can lookup the new DefId + Ok(self.tcx().def_path_hash_to_def_id.as_ref().unwrap()[&def_path_hash]) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + // Decode the unmapped DefIndex of the HirId. + let def_index = DefIndex::default_decode(self)?; + + // Use the unmapped DefIndex to look up the DefPathHash in the cached + // DefPathTable. For HirIds we know that we always have to look in the + // *local* DefPathTable. + let def_path_hash = self.prev_def_path_tables[LOCAL_CRATE.index()] + .def_path_hash(def_index); + + // Use the DefPathHash to map to the current DefId. + let def_id = self.tcx() + .def_path_hash_to_def_id + .as_ref() + .unwrap()[&def_path_hash]; + + // The ItemLocalId needs no remapping. + let local_id = hir::ItemLocalId::decode(self)?; + + // Reconstruct the HirId and look up the corresponding NodeId in the + // context of the current session. + Ok(hir::HirId { + owner: def_id.index, + local_id + }) + } +} + +// NodeIds are not stable across compilation sessions, so we store them in their +// HirId representation. This allows use to map them to the current NodeId. +impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result { + let hir_id = hir::HirId::decode(self)?; + Ok(self.tcx().hir.hir_to_node_id(hir_id)) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder> for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + ty_codec::decode_ty(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder> +for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + ty_codec::decode_predicates(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx Substs<'tcx>> for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { + ty_codec::decode_substs(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder> for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + ty_codec::decode_region(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx ty::Slice>> +for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice>, Self::Error> { + ty_codec::decode_ty_slice(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx ty::AdtDef> for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> { + ty_codec::decode_adt_def(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx ty::Slice>> + for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) + -> Result<&'tcx ty::Slice>, Self::Error> { + ty_codec::decode_existential_predicate_slice(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder> for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + ty_codec::decode_byte_array(self) + } +} + +impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx ty::Const<'tcx>> +for CacheDecoder<'a, 'tcx, 'x> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { + ty_codec::decode_const(self) + } +} + //- ENCODING ------------------------------------------------------------------- @@ -258,6 +467,7 @@ struct CacheEncoder<'enc, 'tcx, E> encoder: &'enc mut E, type_shorthands: FxHashMap, usize>, predicate_shorthands: FxHashMap, usize>, + definitions: &'enc Definitions, } impl<'enc, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'tcx, E> @@ -289,6 +499,17 @@ impl<'enc, 'tcx, E> SpecializedEncoder> } } +// NodeIds are not stable across compilation sessions, so we store them in their +// HirId representation. This allows use to map them to the current NodeId. +impl<'enc, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'tcx, E> + where E: 'enc + ty_codec::TyEncoder +{ + fn specialized_encode(&mut self, node_id: &NodeId) -> Result<(), Self::Error> { + let hir_id = self.definitions.node_to_hir_id(*node_id); + hir_id.encode(self) + } +} + macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {