Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8cbc022
incr.comp.: Include header when loading cache files in order to get t…
michaelwoerister Nov 13, 2017
c08e03a
incr.comp.: Add position() method to TyEncoder.
michaelwoerister Nov 13, 2017
bc96d9d
incr.comp.: Implement UseSpecializedXXcodable for DefIndex and DefId.
michaelwoerister Nov 13, 2017
9ac1026
incr.comp.: Properly use ty::codec::decode_cnum() in rustc_metadata::…
michaelwoerister Nov 13, 2017
3bd333c
incr.comp.: Add CacheEncoder for encoding query results into the incr…
michaelwoerister Nov 13, 2017
15db165
incr.comp.: Implement TyDecoder for on_disk_cache::CacheDecoder.
michaelwoerister Nov 14, 2017
bedb44c
incr.comp.: Allow for mapping from prev-session-CrateNums to current-…
michaelwoerister Nov 14, 2017
de0317e
incr.comp.: Encode DefPathTables for reconstructing DefIds.
michaelwoerister Nov 14, 2017
2087d5e
incr.comp.: Do some verification on data decoded from incr. comp. cache.
michaelwoerister Nov 14, 2017
4bfab89
incr.comp.: Store the query result index which records where query re…
michaelwoerister Nov 14, 2017
0b14383
incr.comp.: Add 'tcx to QueryDescription.
michaelwoerister Nov 14, 2017
2c1aedd
incr.comp.: Cache TypeckTables and add -Zincremental-queries flag.
michaelwoerister Nov 14, 2017
279b6df
incr.comp.: Refactor query cache serialization to be more re-usable.
michaelwoerister Nov 15, 2017
13582c6
incr.comp.: Add missing [input] annotation for DepNode::MaybeUnusedEx…
michaelwoerister Nov 15, 2017
2f50e62
incr.comp.: Only save and load query result cache when -Zincremental-…
michaelwoerister Nov 15, 2017
24e54dd
Introduce LocalDefId which provides a type-level guarantee that the D…
michaelwoerister Nov 16, 2017
2f44ef2
incr.comp.: Encode DefIds as DefPathHashes instead of recomputing tho…
michaelwoerister Nov 16, 2017
723028f
incr.comp.: Remove some code duplication around TyDecoder by factorin…
michaelwoerister Nov 16, 2017
cb1ff24
incr.comp.: Remove default serialization implementations for things i…
michaelwoerister Nov 16, 2017
4c4f7a3
Fix some tidy errors in ty::codec.
michaelwoerister Nov 16, 2017
0a1f6dd
Add doc comment for LocalDefId.
michaelwoerister Nov 16, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustc/hir/def_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 27 additions & 2 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<S: Encoder>(&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: Decoder>(d: &mut D) -> Result<HirId, D::Error> {
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
Expand Down
243 changes: 232 additions & 11 deletions src/librustc/ty/maps/on_disk_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<_, _> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have this new variable here? It doesn't serve an obvious purpose. =)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does in later commits where this block is used to limit the scope of the CacheDecoder.

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<BytePos, StableFilemapId>,
struct CacheDecoder<'a, 'tcx: 'a, 'x> {
tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
opaque: opaque::Decoder<'x>,
codemap: &'x CodeMap,
prev_filemap_starts: &'x BTreeMap<BytePos, StableFilemapId>,
cnum_map: &'x IndexVec<CrateNum, Option<CrateNum>>,
prev_def_path_tables: &'x Vec<DefPathTable>,
}

impl<'a> CacheDecoder<'a> {
impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> {
fn find_filemap_prev_bytepos(&self,
prev_bytepos: BytePos)
-> Option<(BytePos, StableFilemapId)> {
Expand All @@ -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! {
Expand Down Expand Up @@ -232,7 +247,65 @@ impl<'sess> Decoder for CacheDecoder<'sess> {
}
}

impl<'a> SpecializedDecoder<Span> 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<F>(&mut self,
shorthand: usize,
or_insert_with: F)
-> Result<ty::Ty<'tcx>, Self::Error>
where F: FnOnce(&mut Self) -> Result<ty::Ty<'tcx>, 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<F, R>(&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<Span> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
let lo = BytePos::decode(self)?;
let hi = BytePos::decode(self)?;
Expand All @@ -249,6 +322,142 @@ impl<'a> SpecializedDecoder<Span> for CacheDecoder<'a> {
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<CrateNum> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
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<DefIndex> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<DefIndex, Self::Error> {
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<DefId> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<DefId, Self::Error> {
// 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<hir::HirId> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<hir::HirId, Self::Error> {
// 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<NodeId> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
let hir_id = hir::HirId::decode(self)?;
Ok(self.tcx().hir.hir_to_node_id(hir_id))
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<ty::Ty<'tcx>> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<ty::Ty<'tcx>, Self::Error> {
ty_codec::decode_ty(self)
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<ty::GenericPredicates<'tcx>>
for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<ty::GenericPredicates<'tcx>, Self::Error> {
ty_codec::decode_predicates(self)
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx Substs<'tcx>> for CacheDecoder<'a, 'tcx, 'x> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we forget one of these impls, what happens? I think it panics? (These impls are copy-n-paste, I assume.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, most of them should panic.

fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> {
ty_codec::decode_substs(self)
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<ty::Region<'tcx>> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<ty::Region<'tcx>, Self::Error> {
ty_codec::decode_region(self)
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<&'tcx ty::Slice<ty::Ty<'tcx>>>
for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<ty::Ty<'tcx>>, 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<ty::ExistentialPredicate<'tcx>>>
for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self)
-> Result<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>, Self::Error> {
ty_codec::decode_existential_predicate_slice(self)
}
}

impl<'a, 'tcx, 'x> SpecializedDecoder<ByteArray<'tcx>> for CacheDecoder<'a, 'tcx, 'x> {
fn specialized_decode(&mut self) -> Result<ByteArray<'tcx>, 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 -------------------------------------------------------------------

Expand All @@ -258,6 +467,7 @@ struct CacheEncoder<'enc, 'tcx, E>
encoder: &'enc mut E,
type_shorthands: FxHashMap<ty::Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
definitions: &'enc Definitions,
}

impl<'enc, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'enc, 'tcx, E>
Expand Down Expand Up @@ -289,6 +499,17 @@ impl<'enc, 'tcx, E> SpecializedEncoder<ty::GenericPredicates<'tcx>>
}
}

// 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<NodeId> 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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this basically copy-n-paste from the other encoders? (Not criticizing, just trying to understand.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer: this impl, anyway, is not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I thought about writing a macro in ty::codec that would instantiate these implementations. Upfront, I wasn't sure though how many of them would end up just being copies.

hir_id.encode(self)
}
}

macro_rules! encoder_methods {
($($name:ident($ty:ty);)*) => {
$(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
Expand Down