]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_metadata/decoder.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_metadata / decoder.rs
index 64b614b56e12fdffe444b86545fb03c77226adaa..ceb6fcb0da8c2fcfb98634566bdd374e8a25da49 100644 (file)
 
 // Decoding metadata from a single crate's metadata
 
-#![allow(non_camel_case_types)]
-
-use self::Family::*;
-
 use astencode::decode_inlined_item;
-use cstore::{self, CrateMetadata};
-use common::*;
-use def_key;
-use encoder::def_to_u64;
-use index;
-use tls_context;
-use tydecode::TyDecoder;
-
-use rustc::hir::svh::Svh;
+use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind};
+use index::Index;
+use schema::*;
+
 use rustc::hir::map as hir_map;
-use rustc::hir::map::DefKey;
+use rustc::hir::map::{DefKey, DefPathData};
 use rustc::util::nodemap::FnvHashMap;
 use rustc::hir;
-use rustc::session::config::PanicStrategy;
+use rustc::hir::intravisit::IdRange;
 
-use middle::cstore::{InlinedItem, LinkagePreference};
-use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls};
-use rustc::hir::def::Def;
-use rustc::hir::def_id::{DefId, DefIndex};
-use middle::lang_items;
-use rustc::ty::subst;
-use rustc::ty::{ImplContainer, TraitContainer};
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
+use rustc::middle::cstore::{InlinedItem, LinkagePreference};
+use rustc::hir::def::{self, Def};
+use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
+use rustc::middle::lang_items;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
 
 use rustc_const_math::ConstInt;
 
-use rustc::mir;
-use rustc::mir::visit::MutVisitor;
+use rustc::mir::repr::Mir;
 
-use std::cell::Cell;
+use std::cell::Ref;
 use std::io;
+use std::mem;
 use std::rc::Rc;
 use std::str;
+use std::u32;
 
-use rbml::reader;
-use rbml;
-use rustc_serialize::Decodable;
+use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque};
 use syntax::attr;
-use syntax::parse::token;
-use syntax::ast;
+use syntax::ast::{self, NodeId};
 use syntax::codemap;
-use syntax::print::pprust;
-use syntax::ptr::P;
-use syntax_pos::{self, Span, BytePos, NO_EXPANSION};
+use syntax_pos::{self, Span, BytePos, Pos};
 
-pub type Cmd<'a> = &'a CrateMetadata;
+pub struct DecodeContext<'a, 'tcx: 'a> {
+    opaque: opaque::Decoder<'a>,
+    tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
+    cdata: Option<&'a CrateMetadata>,
+    from_id_range: IdRange,
+    to_id_range: IdRange,
 
-impl CrateMetadata {
-    fn get_item(&self, item_id: DefIndex) -> Option<rbml::Doc> {
-        self.index.lookup_item(self.data(), item_id).map(|pos| {
-            reader::doc_at(self.data(), pos as usize).unwrap().doc
-        })
-    }
+    // Cache the last used filemap for translating spans as an optimization.
+    last_filemap_index: usize,
 
-    fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc {
-        match self.get_item(item_id) {
-            None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}",
-                         item_id,
-                         self.name,
-                         self.cnum),
-            Some(d) => d
-        }
-    }
+    lazy_state: LazyState
 }
 
-pub fn load_index(data: &[u8]) -> index::Index {
-    let index = reader::get_doc(rbml::Doc::new(data), tag_index);
-    index::Index::from_rbml(index)
-}
+/// Abstract over the various ways one can create metadata decoders.
+pub trait Metadata<'a, 'tcx>: Copy {
+    fn raw_bytes(self) -> &'a [u8];
+    fn cdata(self) -> Option<&'a CrateMetadata> { None }
+    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { None }
 
-pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
-    let doc = rbml::Doc::new(data);
-    reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str())
+    fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
+        let id_range = IdRange {
+            min: NodeId::from_u32(u32::MIN),
+            max: NodeId::from_u32(u32::MAX)
+        };
+        DecodeContext {
+            opaque: opaque::Decoder::new(self.raw_bytes(), pos),
+            cdata: self.cdata(),
+            tcx: self.tcx(),
+            from_id_range: id_range,
+            to_id_range: id_range,
+            last_filemap_index: 0,
+            lazy_state: LazyState::NoNode
+        }
+    }
 }
 
-pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
-    let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index);
-    index::DenseIndex::from_buf(index.data, index.start, index.end)
+impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
+    fn raw_bytes(self) -> &'a [u8] {
+        match *self {
+            MetadataBlob::Inflated(ref vec) => &vec[..],
+            MetadataBlob::Archive(ref ar) => ar.as_slice(),
+        }
+    }
 }
 
-// Go through each item in the metadata and create a map from that
-// item's def-key to the item's DefIndex.
-pub fn load_key_map(data: &[u8]) -> FnvHashMap<DefKey, DefIndex> {
-    let root_doc = rbml::Doc::new(data);
-    let items_doc = reader::get_doc(root_doc, tag_items);
-    let items_data_doc = reader::get_doc(items_doc, tag_items_data);
-    reader::docs(items_data_doc)
-        .filter(|&(tag, _)| tag == tag_items_data_item)
-        .map(|(_, item_doc)| {
-            // load def-key from item
-            let key = item_def_key(item_doc);
-
-            // load def-index from item; we only encode the full def-id,
-            // so just pull out the index
-            let def_id_doc = reader::get_doc(item_doc, tag_def_id);
-            let def_id = untranslated_def_id(def_id_doc);
-            assert!(def_id.is_local()); // local to the crate we are decoding, that is
-
-            (key, def_id.index)
-        })
-        .collect()
+impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata {
+    fn raw_bytes(self) -> &'a [u8] { self.blob.raw_bytes() }
+    fn cdata(self) -> Option<&'a CrateMetadata> { Some(self) }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum Family {
-    ImmStatic,             // c
-    MutStatic,             // b
-    Fn,                    // f
-    StaticMethod,          // F
-    Method,                // h
-    Type,                  // y
-    Mod,                   // m
-    ForeignMod,            // n
-    Enum,                  // t
-    Variant(VariantKind),  // V, v, w
-    Impl,                  // i
-    DefaultImpl,           // d
-    Trait,                 // I
-    Struct(VariantKind),   // S, s, u
-    PublicField,           // g
-    InheritedField,        // N
-    Constant,              // C
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) {
+    fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() }
+    fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) }
+    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { Some(self.1) }
 }
 
-fn item_family(item: rbml::Doc) -> Family {
-    let fam = reader::get_doc(item, tag_items_data_item_family);
-    match reader::doc_as_u8(fam) as char {
-      'C' => Constant,
-      'c' => ImmStatic,
-      'b' => MutStatic,
-      'f' => Fn,
-      'F' => StaticMethod,
-      'h' => Method,
-      'y' => Type,
-      'm' => Mod,
-      'n' => ForeignMod,
-      't' => Enum,
-      'V' => Variant(VariantKind::Struct),
-      'v' => Variant(VariantKind::Tuple),
-      'w' => Variant(VariantKind::Unit),
-      'i' => Impl,
-      'd' => DefaultImpl,
-      'I' => Trait,
-      'S' => Struct(VariantKind::Struct),
-      's' => Struct(VariantKind::Tuple),
-      'u' => Struct(VariantKind::Unit),
-      'g' => PublicField,
-      'N' => InheritedField,
-       c => bug!("unexpected family char: {}", c)
-    }
-}
+// HACK(eddyb) Only used by astencode to customize the from/to IdRange's.
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>, [IdRange; 2]) {
+    fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() }
+    fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) }
+    fn tcx(self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> { Some(self.1) }
 
-fn item_visibility(item: rbml::Doc) -> ty::Visibility {
-    match reader::maybe_get_doc(item, tag_items_data_item_visibility) {
-        None => ty::Visibility::Public,
-        Some(visibility_doc) => {
-            match reader::doc_as_u8(visibility_doc) as char {
-                'y' => ty::Visibility::Public,
-                'i' => ty::Visibility::PrivateExternal,
-                _ => bug!("unknown visibility character")
-            }
-        }
+    fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
+        let mut dcx = (self.0, self.1).decoder(pos);
+        dcx.from_id_range = self.2[0];
+        dcx.to_id_range = self.2[1];
+        dcx
     }
 }
 
-fn fn_constness(item: rbml::Doc) -> hir::Constness {
-    match reader::maybe_get_doc(item, tag_items_data_item_constness) {
-        None => hir::Constness::NotConst,
-        Some(constness_doc) => {
-            match reader::doc_as_u8(constness_doc) as char {
-                'c' => hir::Constness::Const,
-                'n' => hir::Constness::NotConst,
-                _ => bug!("unknown constness character")
-            }
-        }
+impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> {
+    pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> T {
+        let mut dcx = meta.decoder(self.position);
+        dcx.lazy_state = LazyState::NodeStart(self.position);
+        T::decode(&mut dcx).unwrap()
     }
 }
 
-fn item_defaultness(item: rbml::Doc) -> hir::Defaultness {
-    match reader::maybe_get_doc(item, tag_items_data_item_defaultness) {
-        None => hir::Defaultness::Default, // should occur only for default impls on traits
-        Some(defaultness_doc) => {
-            match reader::doc_as_u8(defaultness_doc) as char {
-                'd' => hir::Defaultness::Default,
-                'f' => hir::Defaultness::Final,
-                _ => bug!("unknown defaultness character")
-            }
-        }
+impl<'a, 'tcx: 'a, T: Decodable> LazySeq<T> {
+    pub fn decode<M: Metadata<'a, 'tcx>>(self, meta: M) -> impl Iterator<Item=T> + 'a {
+        let mut dcx = meta.decoder(self.position);
+        dcx.lazy_state = LazyState::NodeStart(self.position);
+        (0..self.len).map(move |_| {
+            T::decode(&mut dcx).unwrap()
+        })
     }
 }
 
-fn item_sort(item: rbml::Doc) -> Option<char> {
-    reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
-        doc.as_str_slice().as_bytes()[0] as char
-    })
-}
+impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx.expect("missing TyCtxt in DecodeContext")
+    }
 
-fn untranslated_def_id(d: rbml::Doc) -> DefId {
-    let id = reader::doc_as_u64(d);
-    let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
-    DefId { krate: (id >> 32) as u32, index: index }
-}
+    pub fn cdata(&self) -> &'a CrateMetadata {
+        self.cdata.expect("missing CrateMetadata in DecodeContext")
+    }
 
-fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
-    let def_id = untranslated_def_id(d);
-    translate_def_id(cdata, def_id)
-}
+    fn with_position<F: FnOnce(&mut Self) -> R, R>(&mut self, pos: usize, f: F) -> R {
+        let new_opaque = opaque::Decoder::new(self.opaque.data, pos);
+        let old_opaque = mem::replace(&mut self.opaque, new_opaque);
+        let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
+        let r = f(self);
+        self.opaque = old_opaque;
+        self.lazy_state = old_state;
+        r
+    }
 
-fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option<DefId> {
-    reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| {
-        translated_def_id(cdata, did)
-    })
+    fn read_lazy_distance(&mut self, min_size: usize)
+                          -> Result<usize, <Self as Decoder>::Error> {
+        let distance = self.read_usize()?;
+        let position = match self.lazy_state {
+            LazyState::NoNode => {
+                bug!("read_lazy_distance: outside of a metadata node")
+            }
+            LazyState::NodeStart(start) => {
+                assert!(distance + min_size <= start);
+                start - distance - min_size
+            }
+            LazyState::Previous(last_min_end) => {
+                last_min_end + distance
+            }
+        };
+        self.lazy_state = LazyState::Previous(position + min_size);
+        Ok(position)
+    }
 }
 
-fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId {
-    translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item))
+macro_rules! decoder_methods {
+    ($($name:ident -> $ty:ty;)*) => {
+        $(fn $name(&mut self) -> Result<$ty, Self::Error> {
+            self.opaque.$name()
+        })*
+    }
 }
 
-fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId {
-    translated_def_id(cdata, reader::get_doc(d, tag_def_id))
-}
+impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
+    type Error = <opaque::Decoder<'doc> as Decoder>::Error;
 
-fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
-    reader::tagged_docs(d, tag_items_data_item_reexport)
-}
+    decoder_methods! {
+        read_nil -> ();
 
-fn variant_disr_val(d: rbml::Doc) -> Option<u64> {
-    reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
-        reader::with_doc_data(val_doc, |data| {
-            str::from_utf8(data).ok().and_then(|s| s.parse().ok())
-        })
-    })
-}
+        read_u64 -> u64;
+        read_u32 -> u32;
+        read_u16 -> u16;
+        read_u8 -> u8;
+        read_usize -> usize;
 
-fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> {
-    let tp = reader::get_doc(doc, tag_items_data_item_type);
-    TyDecoder::with_doc(tcx, cdata.cnum, tp,
-                        &mut |did| translate_def_id(cdata, did))
-        .parse_ty()
-}
+        read_i64 -> i64;
+        read_i32 -> i32;
+        read_i16 -> i16;
+        read_i8 -> i8;
+        read_isize -> isize;
 
-fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
-                            -> Option<Ty<'tcx>> {
-    reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
-        TyDecoder::with_doc(tcx, cdata.cnum, tp,
-                            &mut |did| translate_def_id(cdata, did))
-            .parse_ty()
-    })
-}
+        read_bool -> bool;
+        read_f64 -> f64;
+        read_f32 -> f32;
+        read_char -> char;
+        read_str -> String;
+    }
 
-pub fn item_type<'a, 'tcx>(_item_id: DefId, item: rbml::Doc,
-                           tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> {
-    doc_type(item, tcx, cdata)
+    fn error(&mut self, err: &str) -> Self::Error {
+        self.opaque.error(err)
+    }
 }
 
-fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
-                           -> ty::TraitRef<'tcx> {
-    TyDecoder::with_doc(tcx, cdata.cnum, doc,
-                        &mut |did| translate_def_id(cdata, did))
-        .parse_trait_ref()
+impl<'a, 'tcx, T> SpecializedDecoder<Lazy<T>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<Lazy<T>, Self::Error> {
+        Ok(Lazy::with_position(self.read_lazy_distance(Lazy::<T>::min_size())?))
+    }
 }
 
-fn item_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd)
-                            -> ty::TraitRef<'tcx> {
-    let tp = reader::get_doc(doc, tag_item_trait_ref);
-    doc_trait_ref(tp, tcx, cdata)
+impl<'a, 'tcx, T> SpecializedDecoder<LazySeq<T>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<LazySeq<T>, Self::Error> {
+        let len = self.read_usize()?;
+        let position = if len == 0 {
+            0
+        } else {
+            self.read_lazy_distance(LazySeq::<T>::min_size(len))?
+        };
+        Ok(LazySeq::with_position_and_length(position, len))
+    }
 }
 
-fn item_name(item: rbml::Doc) -> ast::Name {
-    maybe_item_name(item).expect("no item in item_name")
-}
+impl<'a, 'tcx> SpecializedDecoder<NodeId> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<NodeId, Self::Error> {
+        let id = u32::decode(self)?;
 
-fn maybe_item_name(item: rbml::Doc) -> Option<ast::Name> {
-    reader::maybe_get_doc(item, tag_paths_data_name).map(|name| {
-        let string = name.as_str_slice();
-        token::intern(string)
-    })
-}
+        // from_id_range should be non-empty
+        assert!(!self.from_id_range.empty());
+        // Make sure that translating the NodeId will actually yield a
+        // meaningful result
+        if !self.from_id_range.contains(NodeId::from_u32(id)) {
+            bug!("NodeId::decode: {} out of DecodeContext range ({:?} -> {:?})",
+                 id, self.from_id_range, self.to_id_range);
+        }
 
-fn family_to_variant_kind<'tcx>(family: Family) -> Option<ty::VariantKind> {
-    match family {
-        Struct(VariantKind::Struct) | Variant(VariantKind::Struct) =>
-            Some(ty::VariantKind::Struct),
-        Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
-            Some(ty::VariantKind::Tuple),
-        Struct(VariantKind::Unit) | Variant(VariantKind::Unit) =>
-            Some(ty::VariantKind::Unit),
-        _ => None,
+        // Use wrapping arithmetic because otherwise it introduces control flow.
+        // Maybe we should just have the control flow? -- aatch
+        Ok(NodeId::from_u32(id.wrapping_sub(self.from_id_range.min.as_u32())
+                              .wrapping_add(self.to_id_range.min.as_u32())))
     }
 }
 
-fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
-    let fam = item_family(item);
-    match fam {
-        Constant  => {
-            // Check whether we have an associated const item.
-            match item_sort(item) {
-                Some('C') | Some('c') => {
-                    DlDef(Def::AssociatedConst(did))
-                }
-                _ => {
-                    // Regular const item.
-                    DlDef(Def::Const(did))
-                }
-            }
-        }
-        ImmStatic => DlDef(Def::Static(did, false)),
-        MutStatic => DlDef(Def::Static(did, true)),
-        Struct(..) => DlDef(Def::Struct(did)),
-        Fn        => DlDef(Def::Fn(did)),
-        Method | StaticMethod => {
-            DlDef(Def::Method(did))
-        }
-        Type => {
-            if item_sort(item) == Some('t') {
-                let trait_did = item_require_parent_item(cdata, item);
-                DlDef(Def::AssociatedTy(trait_did, did))
-            } else {
-                DlDef(Def::TyAlias(did))
-            }
-        }
-        Mod => DlDef(Def::Mod(did)),
-        ForeignMod => DlDef(Def::ForeignMod(did)),
-        Variant(..) => {
-            let enum_did = item_require_parent_item(cdata, item);
-            DlDef(Def::Variant(enum_did, did))
+impl<'a, 'tcx> SpecializedDecoder<CrateNum> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> {
+        let cnum = CrateNum::from_u32(u32::decode(self)?);
+        if cnum == LOCAL_CRATE {
+            Ok(self.cdata().cnum)
+        } else {
+            Ok(self.cdata().cnum_map.borrow()[cnum])
         }
-        Trait => DlDef(Def::Trait(did)),
-        Enum => DlDef(Def::Enum(did)),
-        Impl | DefaultImpl => DlImpl(did),
-        PublicField | InheritedField => DlField,
     }
 }
 
-fn parse_unsafety(item_doc: rbml::Doc) -> hir::Unsafety {
-    let unsafety_doc = reader::get_doc(item_doc, tag_unsafety);
-    if reader::doc_as_u8(unsafety_doc) != 0 {
-        hir::Unsafety::Unsafe
-    } else {
-        hir::Unsafety::Normal
-    }
-}
-
-fn parse_paren_sugar(item_doc: rbml::Doc) -> bool {
-    let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar);
-    reader::doc_as_u8(paren_sugar_doc) != 0
-}
+impl<'a, 'tcx> SpecializedDecoder<Span> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
+        let lo = BytePos::decode(self)?;
+        let hi = BytePos::decode(self)?;
 
-fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity {
-    let polarity_doc = reader::get_doc(item_doc, tag_polarity);
-    if reader::doc_as_u8(polarity_doc) != 0 {
-        hir::ImplPolarity::Negative
-    } else {
-        hir::ImplPolarity::Positive
-    }
-}
+        let tcx = if let Some(tcx) = self.tcx {
+            tcx
+        } else {
+            return Ok(syntax_pos::mk_sp(lo, hi));
+        };
 
-fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
-    let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
-    reader::tagged_docs(names_doc, tag_associated_type_name)
-        .map(|name_doc| token::intern(name_doc.as_str_slice()))
-        .collect()
-}
+        let (lo, hi) = if lo > hi {
+            // Currently macro expansion sometimes produces invalid Span values
+            // where lo > hi. In order not to crash the compiler when trying to
+            // translate these values, let's transform them into something we
+            // can handle (and which will produce useful debug locations at
+            // least some of the time).
+            // This workaround is only necessary as long as macro expansion is
+            // not fixed. FIXME(#23480)
+            (lo, lo)
+        } else {
+            (lo, hi)
+        };
 
-pub fn get_trait_def<'a, 'tcx>(cdata: Cmd,
-                               item_id: DefIndex,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
-    let unsafety = parse_unsafety(item_doc);
-    let associated_type_names = parse_associated_type_names(item_doc);
-    let paren_sugar = parse_paren_sugar(item_doc);
-
-    ty::TraitDef::new(unsafety,
-                      paren_sugar,
-                      generics,
-                      item_trait_ref(item_doc, tcx, cdata),
-                      associated_type_names)
-}
+        let imported_filemaps = self.cdata().imported_filemaps(&tcx.sess.codemap());
+        let filemap = {
+            // Optimize for the case that most spans within a translated item
+            // originate from the same filemap.
+            let last_filemap = &imported_filemaps[self.last_filemap_index];
+
+            if lo >= last_filemap.original_start_pos &&
+            lo <= last_filemap.original_end_pos &&
+            hi >= last_filemap.original_start_pos &&
+            hi <= last_filemap.original_end_pos {
+                last_filemap
+            } else {
+                let mut a = 0;
+                let mut b = imported_filemaps.len();
 
-pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
-                             item_id: DefIndex,
-                             tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                             -> ty::AdtDefMaster<'tcx>
-{
-    fn expect_variant_kind(family: Family) -> ty::VariantKind {
-        match family_to_variant_kind(family) {
-            Some(kind) => kind,
-            _ => bug!("unexpected family: {:?}", family),
-        }
-    }
-    fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec<ty::VariantDefData<'tcx, 'tcx>> {
-        let mut disr_val = 0;
-        reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| {
-            let did = translated_def_id(cdata, p);
-            let item = cdata.lookup_item(did.index);
+                while b - a > 1 {
+                    let m = (a + b) / 2;
+                    if imported_filemaps[m].original_start_pos > lo {
+                        b = m;
+                    } else {
+                        a = m;
+                    }
+                }
 
-            if let Some(disr) = variant_disr_val(item) {
-                disr_val = disr;
-            }
-            let disr = disr_val;
-            disr_val = disr_val.wrapping_add(1);
-
-            ty::VariantDefData {
-                did: did,
-                name: item_name(item),
-                fields: get_variant_fields(cdata, item),
-                disr_val: ConstInt::Infer(disr),
-                kind: expect_variant_kind(item_family(item)),
+                self.last_filemap_index = a;
+                &imported_filemaps[a]
             }
-        }).collect()
-    }
-    fn get_variant_fields<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec<ty::FieldDefData<'tcx, 'tcx>> {
-        let mut index = 0;
-        reader::tagged_docs(doc, tag_item_field).map(|f| {
-            let ff = item_family(f);
-            match ff {
-                PublicField | InheritedField => {},
-                _ => bug!("expected field, found {:?}", ff)
-            };
-            ty::FieldDefData::new(item_def_id(f, cdata),
-                                  item_name(f),
-                                  struct_field_family_to_visibility(ff))
-        }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| {
-            let ff = item_family(f);
-            let name = token::with_ident_interner(|interner| interner.intern(index.to_string()));
-            index += 1;
-            ty::FieldDefData::new(item_def_id(f, cdata), name,
-                                  struct_field_family_to_visibility(ff))
-        })).collect()
-    }
-    fn get_struct_variant<'tcx>(cdata: Cmd,
-                                doc: rbml::Doc,
-                                did: DefId) -> ty::VariantDefData<'tcx, 'tcx> {
-        ty::VariantDefData {
-            did: did,
-            name: item_name(doc),
-            fields: get_variant_fields(cdata, doc),
-            disr_val: ConstInt::Infer(0),
-            kind: expect_variant_kind(item_family(doc)),
-        }
+        };
+
+        let lo = (lo - filemap.original_start_pos) +
+                  filemap.translated_filemap.start_pos;
+        let hi = (hi - filemap.original_start_pos) +
+                  filemap.translated_filemap.start_pos;
+
+        Ok(syntax_pos::mk_sp(lo, hi))
     }
+}
 
-    let doc = cdata.lookup_item(item_id);
-    let did = DefId { krate: cdata.cnum, index: item_id };
-    let mut ctor_did = None;
-    let (kind, variants) = match item_family(doc) {
-        Enum => {
-            (ty::AdtKind::Enum,
-             get_enum_variants(cdata, doc))
-        }
-        Struct(..) => {
-            // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
-            ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| {
-                translated_def_id(cdata, ctor_doc)
-            });
-            (ty::AdtKind::Struct,
-             vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))])
-        }
-        _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
-                  item_family(doc), did)
-    };
-
-    let adt = tcx.intern_adt_def(did, kind, variants);
-    if let Some(ctor_did) = ctor_did {
-        // Make adt definition available through constructor id as well.
-        tcx.insert_adt_def(ctor_did, adt);
-    }
-
-    // this needs to be done *after* the variant is interned,
-    // to support recursive structures
-    for variant in &adt.variants {
-        if variant.kind == ty::VariantKind::Tuple &&
-            adt.adt_kind() == ty::AdtKind::Enum {
-            // tuple-like enum variant fields aren't real items - get the types
-            // from the ctor.
-            debug!("evaluating the ctor-type of {:?}",
-                   variant.name);
-            let ctor_ty = get_type(cdata, variant.did.index, tcx).ty;
-            debug!("evaluating the ctor-type of {:?}.. {:?}",
-                   variant.name,
-                   ctor_ty);
-            let field_tys = match ctor_ty.sty {
-                ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
-                    ref inputs, ..
-                }), ..}) => {
-                    // tuple-struct constructors don't have escaping regions
-                    assert!(!inputs.has_escaping_regions());
-                    inputs
-                },
-                _ => bug!("tuple-variant ctor is not an ADT")
+// FIXME(#36588) These impls are horribly unsound as they allow
+// the caller to pick any lifetime for 'tcx, including 'static,
+// by using the unspecialized proxies to them.
+
+impl<'a, 'tcx> SpecializedDecoder<Ty<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<Ty<'tcx>, Self::Error> {
+        let tcx = self.tcx();
+
+        // Handle shorthands first, if we have an usize > 0x80.
+        if self.opaque.data[self.opaque.position()] & 0x80 != 0 {
+            let pos = self.read_usize()?;
+            assert!(pos >= SHORTHAND_OFFSET);
+            let key = ty::CReaderCacheKey {
+                cnum: self.cdata().cnum,
+                pos: pos - SHORTHAND_OFFSET
             };
-            for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) {
-                field.fulfill_ty(ty);
+            if let Some(ty) = tcx.rcache.borrow().get(&key).cloned() {
+                return Ok(ty);
             }
+
+            let ty = self.with_position(key.pos, Ty::decode)?;
+            tcx.rcache.borrow_mut().insert(key, ty);
+            Ok(ty)
         } else {
-            for field in &variant.fields {
-                debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
-                let ty = get_type(cdata, field.did.index, tcx).ty;
-                field.fulfill_ty(ty);
-                debug!("evaluating the type of {:?}::{:?}: {:?}",
-                       variant.name, field.name, ty);
-            }
+            Ok(tcx.mk_ty(ty::TypeVariants::decode(self)?))
         }
     }
-
-    adt
 }
 
-pub fn get_predicates<'a, 'tcx>(cdata: Cmd,
-                                item_id: DefIndex,
-                                tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                -> ty::GenericPredicates<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    doc_predicates(item_doc, tcx, cdata, tag_item_generics)
-}
 
-pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd,
-                                      item_id: DefIndex,
-                                      tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                      -> ty::GenericPredicates<'tcx>
-{
-    let item_doc = cdata.lookup_item(item_id);
-    doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
-}
+impl<'a, 'tcx> SpecializedDecoder<ty::GenericPredicates<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<ty::GenericPredicates<'tcx>, Self::Error> {
+        Ok(ty::GenericPredicates {
+            parent: Decodable::decode(self)?,
+            predicates: (0..self.read_usize()?).map(|_| {
+                // Handle shorthands first, if we have an usize > 0x80.
+                if self.opaque.data[self.opaque.position()] & 0x80 != 0 {
+                    let pos = self.read_usize()?;
+                    assert!(pos >= SHORTHAND_OFFSET);
+                    let pos = pos - SHORTHAND_OFFSET;
 
-pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                          -> ty::TypeScheme<'tcx>
-{
-    let item_doc = cdata.lookup_item(id);
-    let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx,
-                      cdata);
-    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
-    ty::TypeScheme {
-        generics: generics,
-        ty: t
+                    self.with_position(pos, ty::Predicate::decode)
+                } else {
+                    ty::Predicate::decode(self)
+                }
+            }).collect::<Result<Vec<_>, _>>()?
+        })
     }
 }
 
-pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option<attr::Stability> {
-    let item = cdata.lookup_item(id);
-    reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
-        let mut decoder = reader::Decoder::new(doc);
-        Decodable::decode(&mut decoder).unwrap()
-    })
+impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> {
+        Ok(self.tcx().mk_substs(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option<attr::Deprecation> {
-    let item = cdata.lookup_item(id);
-    reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| {
-        let mut decoder = reader::Decoder::new(doc);
-        Decodable::decode(&mut decoder).unwrap()
-    })
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::Region, Self::Error> {
+        Ok(self.tcx().mk_region(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_visibility(cdata: Cmd, id: DefIndex) -> ty::Visibility {
-    item_visibility(cdata.lookup_item(id))
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> {
+        Ok(self.tcx().mk_type_list(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option<DefId> {
-    let item = cdata.lookup_item(id);
-    reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| {
-        translated_def_id(cdata, doc)
-    })
+impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::BareFnTy<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<&'tcx ty::BareFnTy<'tcx>, Self::Error> {
+        Ok(self.tcx().mk_bare_fn(Decodable::decode(self)?))
+    }
 }
 
-pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
-    let item = cdata.lookup_item(id);
-    match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
-        let mut decoder = reader::Decoder::new(doc);
-        Decodable::decode(&mut decoder).unwrap()
-    }) {
-        Some(attrs) => attrs,
-        None => Vec::new(),
+impl<'a, 'tcx> SpecializedDecoder<ty::AdtDef<'tcx>> for DecodeContext<'a, 'tcx> {
+    fn specialized_decode(&mut self) -> Result<ty::AdtDef<'tcx>, Self::Error> {
+        let def_id = DefId::decode(self)?;
+        Ok(self.tcx().lookup_adt_def(def_id))
     }
 }
 
-pub fn get_impl_polarity<'tcx>(cdata: Cmd,
-                               id: DefIndex)
-                               -> Option<hir::ImplPolarity>
-{
-    let item_doc = cdata.lookup_item(id);
-    let fam = item_family(item_doc);
-    match fam {
-        Family::Impl => {
-            Some(parse_polarity(item_doc))
-        }
-        _ => None
+impl<'a, 'tcx> MetadataBlob {
+    pub fn is_compatible(&self) -> bool {
+        self.raw_bytes().starts_with(METADATA_HEADER)
     }
-}
 
-pub fn get_custom_coerce_unsized_kind<'tcx>(
-    cdata: Cmd,
-    id: DefIndex)
-    -> Option<ty::adjustment::CustomCoerceUnsized>
-{
-    let item_doc = cdata.lookup_item(id);
-    reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| {
-        let mut decoder = reader::Decoder::new(kind_doc);
-        Decodable::decode(&mut decoder).unwrap()
-    })
-}
+    pub fn get_root(&self) -> CrateRoot {
+        let slice = self.raw_bytes();
+        let offset = METADATA_HEADER.len();
+        let pos = (((slice[offset + 0] as u32) << 24) |
+                   ((slice[offset + 1] as u32) << 16) |
+                   ((slice[offset + 2] as u32) << 8) |
+                   ((slice[offset + 3] as u32) << 0)) as usize;
+        Lazy::with_position(pos).decode(self)
+    }
+
+    /// Go through each item in the metadata and create a map from that
+    /// item's def-key to the item's DefIndex.
+    pub fn load_key_map(&self, index: LazySeq<Index>) -> FnvHashMap<DefKey, DefIndex> {
+        index.iter_enumerated(self.raw_bytes()).map(|(index, item)| {
+            (item.decode(self).def_key.decode(self), index)
+        }).collect()
+    }
 
-pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd,
-                                id: DefIndex,
-                                tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                -> Option<ty::TraitRef<'tcx>>
-{
-    let item_doc = cdata.lookup_item(id);
-    let fam = item_family(item_doc);
-    match fam {
-        Family::Impl | Family::DefaultImpl => {
-            reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| {
-                doc_trait_ref(tp, tcx, cdata)
-            })
+    pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> {
+        write!(out, "=External Dependencies=\n")?;
+        let root = self.get_root();
+        for (i, dep) in root.crate_deps.decode(self).enumerate() {
+            write!(out, "{} {}-{}\n", i + 1, dep.name, dep.hash)?;
         }
-        _ => None
+        write!(out, "\n")?;
+        Ok(())
     }
 }
 
-/// Iterates over the language items in the given crate.
-pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where
-    F: FnMut(DefIndex, usize) -> bool,
-{
-    let root = rbml::Doc::new(cdata.data());
-    let lang_items = reader::get_doc(root, tag_lang_items);
-    reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| {
-        let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
-        let id = reader::doc_as_u32(id_doc) as usize;
-        let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index);
-        let index = DefIndex::from_u32(reader::doc_as_u32(index_doc));
-
-        f(index, id)
-    })
+impl<'tcx> EntryKind<'tcx> {
+    fn to_def(&self, did: DefId) -> Option<Def> {
+        Some(match *self {
+            EntryKind::Const  => Def::Const(did),
+            EntryKind::AssociatedConst(_) => Def::AssociatedConst(did),
+            EntryKind::ImmStatic |
+            EntryKind::ForeignImmStatic => Def::Static(did, false),
+            EntryKind::MutStatic |
+            EntryKind::ForeignMutStatic => Def::Static(did, true),
+            EntryKind::Struct(_) => Def::Struct(did),
+            EntryKind::Union(_) => Def::Union(did),
+            EntryKind::Fn(_) |
+            EntryKind::ForeignFn(_) => Def::Fn(did),
+            EntryKind::Method(_) => Def::Method(did),
+            EntryKind::Type => Def::TyAlias(did),
+            EntryKind::AssociatedType(_) => Def::AssociatedTy(did),
+            EntryKind::Mod(_) => Def::Mod(did),
+            EntryKind::Variant(_) => Def::Variant(did),
+            EntryKind::Trait(_) => Def::Trait(did),
+            EntryKind::Enum => Def::Enum(did),
+
+            EntryKind::ForeignMod |
+            EntryKind::Impl(_) |
+            EntryKind::DefaultImpl(_) |
+            EntryKind::Field |
+            EntryKind::Closure (_) => {
+                return None
+            }
+        })
+    }
 }
 
-fn each_child_of_item_or_crate<F, G>(cdata: Cmd,
-                                     item_doc: rbml::Doc,
-                                     mut get_crate_data: G,
-                                     mut callback: F) where
-    F: FnMut(DefLike, ast::Name, ty::Visibility),
-    G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>,
-{
-    // Iterate over all children.
-    for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) {
-        let child_def_id = translated_def_id(cdata, child_info_doc);
-
-        // This item may be in yet another crate if it was the child of a
-        // reexport.
-        let crate_data = if child_def_id.krate == cdata.cnum {
-            None
-        } else {
-            Some(get_crate_data(child_def_id.krate))
-        };
-        let crate_data = match crate_data {
-            Some(ref cdata) => &**cdata,
-            None => cdata
-        };
+impl<'a, 'tcx> CrateMetadata {
+    fn maybe_entry(&self, item_id: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
+        self.root.index.lookup(self.blob.raw_bytes(), item_id)
+    }
 
-        // Get the item.
-        if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) {
-            // Hand off the item to the callback.
-            let child_name = item_name(child_item_doc);
-            let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
-            let visibility = item_visibility(child_item_doc);
-            callback(def_like, child_name, visibility);
+    fn entry(&self, item_id: DefIndex) -> Entry<'tcx> {
+        match self.maybe_entry(item_id) {
+            None => bug!("entry: id not found: {:?} in crate {:?} with number {}",
+                         item_id,
+                         self.name,
+                         self.cnum),
+            Some(d) => d.decode(self)
         }
     }
 
-    for reexport_doc in reexports(item_doc) {
-        let def_id_doc = reader::get_doc(reexport_doc,
-                                         tag_items_data_item_reexport_def_id);
-        let child_def_id = translated_def_id(cdata, def_id_doc);
-
-        let name_doc = reader::get_doc(reexport_doc,
-                                       tag_items_data_item_reexport_name);
-        let name = name_doc.as_str_slice();
-
-        // This reexport may be in yet another crate.
-        let crate_data = if child_def_id.krate == cdata.cnum {
-            None
-        } else {
-            Some(get_crate_data(child_def_id.krate))
-        };
-        let crate_data = match crate_data {
-            Some(ref cdata) => &**cdata,
-            None => cdata
-        };
-
-        // Get the item.
-        if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) {
-            // Hand off the item to the callback.
-            let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
-            // These items have a public visibility because they're part of
-            // a public re-export.
-            callback(def_like, token::intern(name), ty::Visibility::Public);
+    fn local_def_id(&self, index: DefIndex) -> DefId {
+        DefId {
+            krate: self.cnum,
+            index: index
         }
     }
-}
-
-/// Iterates over each child of the given item.
-pub fn each_child_of_item<F, G>(cdata: Cmd, id: DefIndex, get_crate_data: G, callback: F)
-    where F: FnMut(DefLike, ast::Name, ty::Visibility),
-          G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>,
-{
-    // Find the item.
-    let item_doc = match cdata.get_item(id) {
-        None => return,
-        Some(item_doc) => item_doc,
-    };
-
-    each_child_of_item_or_crate(cdata, item_doc, get_crate_data, callback)
-}
-
-/// Iterates over all the top-level crate items.
-pub fn each_top_level_item_of_crate<F, G>(cdata: Cmd, get_crate_data: G, callback: F)
-    where F: FnMut(DefLike, ast::Name, ty::Visibility),
-          G: FnMut(ast::CrateNum) -> Rc<CrateMetadata>,
-{
-    let root_doc = rbml::Doc::new(cdata.data());
-    let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
-    let crate_items_doc = reader::get_doc(misc_info_doc,
-                                          tag_misc_info_crate_items);
-
-    each_child_of_item_or_crate(cdata,
-                                crate_items_doc,
-                                get_crate_data,
-                                callback)
-}
-
-pub fn get_item_name(cdata: Cmd, id: DefIndex) -> ast::Name {
-    item_name(cdata.lookup_item(id))
-}
-
-pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option<ast::Name> {
-    maybe_item_name(cdata.lookup_item(id))
-}
 
-pub enum FoundAst<'ast> {
-    Found(&'ast InlinedItem),
-    FoundParent(DefId, &'ast hir::Item),
-    NotFound,
-}
-
-pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
-                                    -> FoundAst<'tcx> {
-    debug!("Looking up item: {:?}", id);
-    let item_doc = cdata.lookup_item(id);
-    let item_did = item_def_id(item_doc, cdata);
-    let parent_def_id = DefId {
-        krate: cdata.cnum,
-        index: def_key(cdata, id).parent.unwrap()
-    };
-    let mut parent_def_path = def_path(cdata, id);
-    parent_def_path.data.pop();
-    if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) {
-        let ii = decode_inlined_item(cdata,
-                                     tcx,
-                                     parent_def_path,
-                                     parent_def_id,
-                                     ast_doc,
-                                     item_did);
-        return FoundAst::Found(ii);
-    } else if let Some(parent_did) = item_parent_item(cdata, item_doc) {
-        // Remove the last element from the paths, since we are now
-        // trying to inline the parent.
-        let grandparent_def_id = DefId {
-            krate: cdata.cnum,
-            index: def_key(cdata, parent_def_id.index).parent.unwrap()
-        };
-        let mut grandparent_def_path = parent_def_path;
-        grandparent_def_path.data.pop();
-        let parent_doc = cdata.lookup_item(parent_did.index);
-        if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) {
-            let ii = decode_inlined_item(cdata,
-                                         tcx,
-                                         grandparent_def_path,
-                                         grandparent_def_id,
-                                         ast_doc,
-                                         parent_did);
-            if let &InlinedItem::Item(_, ref i) = ii {
-                return FoundAst::FoundParent(parent_did, i);
-            }
-        }
+    fn item_name(&self, item: &Entry<'tcx>) -> ast::Name {
+        item.def_key.decode(self).disambiguated_data.data.get_opt_name()
+            .expect("no name in item_name")
     }
-    FoundAst::NotFound
-}
 
-pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool {
-    if let Some(item_doc) = cdata.get_item(id) {
-        return reader::maybe_get_doc(item_doc, tag_mir as usize).is_some();
+    pub fn get_def(&self, index: DefIndex) -> Option<Def> {
+        self.entry(index).kind.to_def(self.local_def_id(index))
     }
 
-    false
-}
+    pub fn get_trait_def(&self,
+                         item_id: DefIndex,
+                         tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> {
+        let data = match self.entry(item_id).kind {
+            EntryKind::Trait(data) => data.decode(self),
+            _ => bug!()
+        };
 
-pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd,
-                                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    id: DefIndex)
-                                    -> Option<mir::repr::Mir<'tcx>> {
-    let item_doc = cdata.lookup_item(id);
+        ty::TraitDef::new(data.unsafety, data.paren_sugar,
+                          tcx.lookup_generics(self.local_def_id(item_id)),
+                          data.trait_ref.decode((self, tcx)),
+                          self.def_path(item_id).unwrap().deterministic_hash(tcx))
+    }
 
-    return reader::maybe_get_doc(item_doc, tag_mir as usize).map(|mir_doc| {
-        let dcx = tls_context::DecodingContext {
-            crate_metadata: cdata,
-            tcx: tcx,
+    fn get_variant(&self, item: &Entry<'tcx>, index: DefIndex)
+                   -> (ty::VariantDefData<'tcx, 'tcx>, Option<DefIndex>) {
+        let data = match item.kind {
+            EntryKind::Variant(data) |
+            EntryKind::Struct(data) |
+            EntryKind::Union(data) => data.decode(self),
+            _ => bug!()
         };
-        let mut decoder = reader::Decoder::new(mir_doc);
 
-        let mut mir = decoder.read_opaque(|opaque_decoder, _| {
-            tls::enter_decoding_context(&dcx, opaque_decoder, |_, opaque_decoder| {
-                Decodable::decode(opaque_decoder)
-            })
-        }).unwrap();
-
-        assert!(decoder.position() == mir_doc.end);
+        let fields = item.children.decode(self).map(|index| {
+            let f = self.entry(index);
+            ty::FieldDefData::new(self.local_def_id(index),
+                                  self.item_name(&f),
+                                  f.visibility)
+        }).collect();
+
+        (ty::VariantDefData {
+            did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
+            name: self.item_name(item),
+            fields: fields,
+            disr_val: ConstInt::Infer(data.disr),
+            kind: data.kind,
+        }, data.struct_ctor)
+    }
 
-        let mut def_id_and_span_translator = MirDefIdAndSpanTranslator {
-            crate_metadata: cdata,
-            codemap: tcx.sess.codemap(),
-            last_filemap_index_hint: Cell::new(0),
+    pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                       -> ty::AdtDefMaster<'tcx> {
+        let item = self.entry(item_id);
+        let did = self.local_def_id(item_id);
+        let mut ctor_index = None;
+        let variants = if let EntryKind::Enum = item.kind {
+            item.children.decode(self).map(|index| {
+                let (variant, struct_ctor) = self.get_variant(&self.entry(index), index);
+                assert_eq!(struct_ctor, None);
+                variant
+            }).collect()
+        } else{
+            let (variant, struct_ctor) = self.get_variant(&item, item_id);
+            ctor_index = struct_ctor;
+            vec![variant]
+        };
+        let kind = match item.kind {
+            EntryKind::Enum => ty::AdtKind::Enum,
+            EntryKind::Struct(_) => ty::AdtKind::Struct,
+            EntryKind::Union(_) => ty::AdtKind::Union,
+            _ => bug!("get_adt_def called on a non-ADT {:?}", did)
         };
 
-        def_id_and_span_translator.visit_mir(&mut mir);
-        for promoted in &mut mir.promoted {
-            def_id_and_span_translator.visit_mir(promoted);
+        let adt = tcx.intern_adt_def(did, kind, variants);
+        if let Some(ctor_index) = ctor_index {
+            // Make adt definition available through constructor id as well.
+            tcx.insert_adt_def(self.local_def_id(ctor_index), adt);
         }
 
-        mir
-    });
+        // this needs to be done *after* the variant is interned,
+        // to support recursive structures
+        for variant in &adt.variants {
+            for field in &variant.fields {
+                debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
+                let ty = self.get_type(field.did.index, tcx);
+                field.fulfill_ty(ty);
+                debug!("evaluating the type of {:?}::{:?}: {:?}",
+                       variant.name, field.name, ty);
+            }
+        }
 
-    struct MirDefIdAndSpanTranslator<'cdata, 'codemap> {
-        crate_metadata: Cmd<'cdata>,
-        codemap: &'codemap codemap::CodeMap,
-        last_filemap_index_hint: Cell<usize>
+        adt
     }
 
-    impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v>
-        for MirDefIdAndSpanTranslator<'cdata, 'codemap>
-    {
-        fn visit_def_id(&mut self, def_id: &mut DefId) {
-            *def_id = translate_def_id(self.crate_metadata, *def_id);
-        }
+    pub fn get_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> ty::GenericPredicates<'tcx> {
+        self.entry(item_id).predicates.unwrap().decode((self, tcx))
+    }
 
-        fn visit_span(&mut self, span: &mut Span) {
-            *span = translate_span(self.crate_metadata,
-                                   self.codemap,
-                                   &self.last_filemap_index_hint,
-                                   *span);
+    pub fn get_super_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                -> ty::GenericPredicates<'tcx> {
+        match self.entry(item_id).kind {
+            EntryKind::Trait(data) => {
+                data.decode(self).super_predicates.decode((self, tcx))
+            }
+            _ => bug!()
         }
     }
-}
 
-fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
-    fn get_mutability(ch: u8) -> hir::Mutability {
-        match ch as char {
-            'i' => hir::MutImmutable,
-            'm' => hir::MutMutable,
-            _ => bug!("unknown mutability character: `{}`", ch as char),
-        }
+    pub fn get_generics(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                        -> ty::Generics<'tcx> {
+        self.entry(item_id).generics.unwrap().decode((self, tcx))
     }
 
-    let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self);
-    let string = explicit_self_doc.as_str_slice();
+    pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+        self.entry(id).ty.unwrap().decode((self, tcx))
+    }
 
-    let explicit_self_kind = string.as_bytes()[0];
-    match explicit_self_kind as char {
-        's' => ty::ExplicitSelfCategory::Static,
-        'v' => ty::ExplicitSelfCategory::ByValue,
-        '~' => ty::ExplicitSelfCategory::ByBox,
-        // FIXME(#4846) expl. region
-        '&' => {
-            ty::ExplicitSelfCategory::ByReference(
-                ty::ReEmpty,
-                get_mutability(string.as_bytes()[1]))
-        }
-        _ => bug!("unknown self type code: `{}`", explicit_self_kind as char)
+    pub fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
+        self.entry(id).stability.map(|stab| stab.decode(self))
     }
-}
 
-/// Returns the def IDs of all the items in the given implementation.
-pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex)
-                      -> Vec<ty::ImplOrTraitItemId> {
-    reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| {
-        let def_id = item_def_id(doc, cdata);
-        match item_sort(doc) {
-            Some('C') | Some('c') => ty::ConstTraitItemId(def_id),
-            Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
-            Some('t') => ty::TypeTraitItemId(def_id),
-            _ => bug!("unknown impl item sort"),
-        }
-    }).collect()
-}
+    pub fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
+        self.entry(id).deprecation.map(|depr| depr.decode(self))
+    }
 
-pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name {
-    let doc = cdata.lookup_item(id);
-    item_name(doc)
-}
+    pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
+        self.entry(id).visibility
+    }
 
-pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool {
-    let doc = cdata.lookup_item(id);
-    match item_sort(doc) {
-        Some('r') | Some('p') => {
-            get_explicit_self(doc) == ty::ExplicitSelfCategory::Static
+    fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> {
+        match self.entry(id).kind {
+            EntryKind::Impl(data) => data.decode(self),
+            _ => bug!()
         }
-        _ => false
     }
-}
 
-pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                        -> Option<ty::ImplOrTraitItem<'tcx>> {
-    let item_doc = cdata.lookup_item(id);
-
-    let def_id = item_def_id(item_doc, cdata);
-
-    let container_id = if let Some(id) = item_parent_item(cdata, item_doc) {
-        id
-    } else {
-        return None;
-    };
-    let container_doc = cdata.lookup_item(container_id.index);
-    let container = match item_family(container_doc) {
-        Trait => TraitContainer(container_id),
-        _ => ImplContainer(container_id),
-    };
-
-    let name = item_name(item_doc);
-    let vis = item_visibility(item_doc);
-    let defaultness = item_defaultness(item_doc);
-
-    Some(match item_sort(item_doc) {
-        sort @ Some('C') | sort @ Some('c') => {
-            let ty = doc_type(item_doc, tcx, cdata);
-            ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
-                name: name,
-                ty: ty,
-                vis: vis,
-                defaultness: defaultness,
-                def_id: def_id,
-                container: container,
-                has_value: sort == Some('C')
-            }))
-        }
-        Some('r') | Some('p') => {
-            let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
-            let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
-            let ity = tcx.lookup_item_type(def_id).ty;
-            let fty = match ity.sty {
-                ty::TyFnDef(_, _, fty) => fty,
-                _ => bug!(
-                    "the type {:?} of the method {:?} is not a function?",
-                    ity, name)
-            };
-            let explicit_self = get_explicit_self(item_doc);
-
-            ty::MethodTraitItem(Rc::new(ty::Method::new(name,
-                                                        generics,
-                                                        predicates,
-                                                        fty,
-                                                        explicit_self,
-                                                        vis,
-                                                        defaultness,
-                                                        def_id,
-                                                        container)))
-        }
-        Some('t') => {
-            let ty = maybe_doc_type(item_doc, tcx, cdata);
-            ty::TypeTraitItem(Rc::new(ty::AssociatedType {
-                name: name,
-                ty: ty,
-                vis: vis,
-                defaultness: defaultness,
-                def_id: def_id,
-                container: container,
-            }))
-        }
-        _ => return None
-    })
-}
+    pub fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
+        self.get_impl_data(id).parent_impl
+    }
 
-pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex)
-                              -> Vec<ty::ImplOrTraitItemId> {
-    let item = cdata.lookup_item(id);
-    reader::tagged_docs(item, tag_item_trait_item).map(|mth| {
-        let def_id = item_def_id(mth, cdata);
-        match item_sort(mth) {
-            Some('C') | Some('c') => ty::ConstTraitItemId(def_id),
-            Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
-            Some('t') => ty::TypeTraitItemId(def_id),
-            _ => bug!("unknown trait item sort"),
-        }
-    }).collect()
-}
+    pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity {
+        self.get_impl_data(id).polarity
+    }
 
-pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances {
-    let item_doc = cdata.lookup_item(id);
-    let variance_doc = reader::get_doc(item_doc, tag_item_variances);
-    let mut decoder = reader::Decoder::new(variance_doc);
-    Decodable::decode(&mut decoder).unwrap()
-}
+    pub fn get_custom_coerce_unsized_kind(&self, id: DefIndex)
+                                          -> Option<ty::adjustment::CustomCoerceUnsized> {
+        self.get_impl_data(id).coerce_unsized_kind
+    }
 
-pub fn get_provided_trait_methods<'a, 'tcx>(cdata: Cmd,
-                                            id: DefIndex,
-                                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                            -> Vec<Rc<ty::Method<'tcx>>> {
-    let item = cdata.lookup_item(id);
+    pub fn get_impl_trait(&self,
+                          id: DefIndex,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> Option<ty::TraitRef<'tcx>> {
+        self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx)))
+    }
 
-    reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| {
-        let did = item_def_id(mth_id, cdata);
-        let mth = cdata.lookup_item(did.index);
+    /// Iterates over the language items in the given crate.
+    pub fn get_lang_items(&self) -> Vec<(DefIndex, usize)> {
+        self.root.lang_items.decode(self).collect()
+    }
 
-        if item_sort(mth) == Some('p') {
-            let trait_item = get_impl_or_trait_item(cdata, did.index, tcx);
-            if let Some(ty::MethodTraitItem(ref method)) = trait_item {
-                Some((*method).clone())
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }).collect()
-}
+    /// Iterates over each child of the given item.
+    pub fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F)
+        where F: FnMut(def::Export)
+    {
+        // Find the item.
+        let item = match self.maybe_entry(id) {
+            None => return,
+            Some(item) => item.decode(self),
+        };
 
-pub fn get_associated_consts<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                       -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
-    let item = cdata.lookup_item(id);
+        // Iterate over all children.
+        for child_index in item.children.decode(self) {
+            // Get the item.
+            if let Some(child) = self.maybe_entry(child_index) {
+                let child = child.decode(self);
+                // Hand off the item to the callback.
+                match child.kind {
+                    // FIXME(eddyb) Don't encode these in children.
+                    EntryKind::ForeignMod => {
+                        for child_index in child.children.decode(self) {
+                            callback(def::Export {
+                                def_id: self.local_def_id(child_index),
+                                name: self.item_name(&self.entry(child_index))
+                            });
+                        }
+                        continue;
+                    }
+                    EntryKind::Impl(_) | EntryKind::DefaultImpl(_) => continue,
 
-    [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| {
-        reader::tagged_docs(item, tag).filter_map(|ac_id| {
-            let did = item_def_id(ac_id, cdata);
-            let ac_doc = cdata.lookup_item(did.index);
+                    _ => {}
+                }
 
-            match item_sort(ac_doc) {
-                Some('C') | Some('c') => {
-                    let trait_item = get_impl_or_trait_item(cdata, did.index, tcx);
-                    if let Some(ty::ConstTraitItem(ref ac)) = trait_item {
-                        Some((*ac).clone())
-                    } else {
-                        None
-                    }
+                let def_key = child.def_key.decode(self);
+                if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
+                    callback(def::Export {
+                        def_id: self.local_def_id(child_index),
+                        name: name
+                    });
                 }
-                _ => None
             }
-        })
-    }).collect()
-}
-
-pub fn get_variant_kind(cdata: Cmd, node_id: DefIndex) -> Option<VariantKind>
-{
-    let item = cdata.lookup_item(node_id);
-    family_to_variant_kind(item_family(item))
-}
-
-pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option<DefId>
-{
-    let item = cdata.lookup_item(node_id);
-    reader::maybe_get_doc(item, tag_items_data_item_struct_ctor).
-        map(|ctor_doc| translated_def_id(cdata, ctor_doc))
-}
+        }
 
-/// If node_id is the constructor of a tuple struct, retrieve the NodeId of
-/// the actual type definition, otherwise, return None
-pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
-                                           node_id: DefIndex)
-    -> Option<DefId>
-{
-    let item = cdata.lookup_item(node_id);
-    reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| {
-        item_require_parent_item(cdata, item)
-    })
-}
+        if let EntryKind::Mod(data) = item.kind {
+            for exp in data.decode(self).reexports.decode(self) {
+                callback(exp);
+            }
+        }
+    }
 
-pub fn get_item_attrs(cdata: Cmd,
-                      orig_node_id: DefIndex)
-                      -> Vec<ast::Attribute> {
-    // The attributes for a tuple struct are attached to the definition, not the ctor;
-    // we assume that someone passing in a tuple struct ctor is actually wanting to
-    // look at the definition
-    let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
-    let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id);
-    let item = cdata.lookup_item(node_id);
-    get_attributes(item)
-}
+    pub fn maybe_get_item_ast(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
+                              -> Option<&'tcx InlinedItem> {
+        debug!("Looking up item: {:?}", id);
+        let item_doc = self.entry(id);
+        let item_did = self.local_def_id(id);
+        let parent_def_id = self.local_def_id(self.def_key(id).parent.unwrap());
+        let mut parent_def_path = self.def_path(id).unwrap();
+        parent_def_path.data.pop();
+        item_doc.ast.map(|ast| {
+            let ast = ast.decode(self);
+            decode_inlined_item(self, tcx, parent_def_path, parent_def_id, ast, item_did)
+        })
+    }
 
-pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap<DefId, Vec<ast::Attribute>> {
-    let data = rbml::Doc::new(cdata.data());
-    let fields = reader::get_doc(data, tag_struct_fields);
-    reader::tagged_docs(fields, tag_struct_field).map(|field| {
-        let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id));
-        let attrs = get_attributes(field);
-        (def_id, attrs)
-    }).collect()
-}
+    pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
+        self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
+    }
 
-fn struct_field_family_to_visibility(family: Family) -> ty::Visibility {
-    match family {
-        PublicField => ty::Visibility::Public,
-        InheritedField => ty::Visibility::PrivateExternal,
-        _ => bug!()
+    pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex)
+                              -> Option<Mir<'tcx>> {
+        self.entry(id).mir.map(|mir| mir.decode((self, tcx)))
     }
-}
 
-pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec<ast::Name> {
-    let item = cdata.lookup_item(id);
-    let mut index = 0;
-    reader::tagged_docs(item, tag_item_field).map(|an_item| {
-        item_name(an_item)
-    }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| {
-        let name = token::with_ident_interner(|interner| interner.intern(index.to_string()));
-        index += 1;
-        name
-    })).collect()
-}
+    pub fn get_impl_or_trait_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                  -> Option<ty::ImplOrTraitItem<'tcx>> {
+        let item = self.entry(id);
+        let parent_and_name = || {
+            let def_key = item.def_key.decode(self);
+            (self.local_def_id(def_key.parent.unwrap()),
+             def_key.disambiguated_data.data.get_opt_name().unwrap())
+        };
 
-fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
-    reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let n = token::intern_and_get_ident(nd.as_str_slice());
-        attr::mk_word_item(n)
-    }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
-        let n = token::intern_and_get_ident(nd.as_str_slice());
-        let v = token::intern_and_get_ident(vd.as_str_slice());
-        // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants,
-        // but currently the encoder just drops them
-        attr::mk_name_value_item_str(n, v)
-    })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| {
-        let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
-        let n = token::intern_and_get_ident(nd.as_str_slice());
-        let subitems = get_meta_items(meta_item_doc);
-        attr::mk_list_item(n, subitems)
-    })).collect()
-}
+        Some(match item.kind {
+            EntryKind::AssociatedConst(container) => {
+                let (parent, name) = parent_and_name();
+                ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
+                    name: name,
+                    ty: item.ty.unwrap().decode((self, tcx)),
+                    vis: item.visibility,
+                    defaultness: container.defaultness(),
+                    def_id: self.local_def_id(id),
+                    container: container.with_def_id(parent),
+                    has_value: container.has_body(),
+                }))
+            }
+            EntryKind::Method(data) => {
+                let (parent, name) = parent_and_name();
+                let ity = item.ty.unwrap().decode((self, tcx));
+                let fty = match ity.sty {
+                    ty::TyFnDef(.., fty) => fty,
+                    _ => bug!(
+                        "the type {:?} of the method {:?} is not a function?",
+                        ity, name)
+                };
+
+                let data = data.decode(self);
+                ty::MethodTraitItem(Rc::new(ty::Method {
+                    name: name,
+                    generics: tcx.lookup_generics(self.local_def_id(id)),
+                    predicates: item.predicates.unwrap().decode((self, tcx)),
+                    fty: fty,
+                    explicit_self: data.explicit_self.decode((self, tcx)),
+                    vis: item.visibility,
+                    defaultness: data.container.defaultness(),
+                    has_body: data.container.has_body(),
+                    def_id: self.local_def_id(id),
+                    container: data.container.with_def_id(parent),
+                }))
+            }
+            EntryKind::AssociatedType(container) => {
+                let (parent, name) = parent_and_name();
+                ty::TypeTraitItem(Rc::new(ty::AssociatedType {
+                    name: name,
+                    ty: item.ty.map(|ty| ty.decode((self, tcx))),
+                    vis: item.visibility,
+                    defaultness: container.defaultness(),
+                    def_id: self.local_def_id(id),
+                    container: container.with_def_id(parent),
+                }))
+            }
+            _ => return None
+        })
+    }
 
-fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
-    match reader::maybe_get_doc(md, tag_attributes) {
-        Some(attrs_d) => {
-            reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| {
-                let is_sugared_doc = reader::doc_as_u8(
-                    reader::get_doc(attr_doc, tag_attribute_is_sugared_doc)
-                ) == 1;
-                let meta_items = get_meta_items(attr_doc);
-                // Currently it's only possible to have a single meta item on
-                // an attribute
-                assert_eq!(meta_items.len(), 1);
-                let meta_item = meta_items.into_iter().nth(0).unwrap();
-                attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc)
-            }).collect()
-        },
-        None => vec![],
+    pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
+        self.entry(id).variances.decode(self).collect()
     }
-}
 
-fn list_crate_attributes(md: rbml::Doc, hash: &Svh,
-                         out: &mut io::Write) -> io::Result<()> {
-    write!(out, "=Crate Attributes ({})=\n", *hash)?;
+    pub fn get_variant_kind(&self, node_id: DefIndex) -> Option<ty::VariantKind> {
+        match self.entry(node_id).kind {
+            EntryKind::Struct(data) |
+            EntryKind::Union(data) |
+            EntryKind::Variant(data) => Some(data.decode(self).kind),
+            _ => None
+        }
+    }
 
-    let r = get_attributes(md);
-    for attr in &r {
-        write!(out, "{}\n", pprust::attribute_to_string(attr))?;
+    pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> {
+        match self.entry(node_id).kind {
+            EntryKind::Struct(data) => {
+                data.decode(self).struct_ctor.map(|index| self.local_def_id(index))
+            }
+            _ => None
+        }
     }
 
-    write!(out, "\n\n")
-}
+    pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec<ast::Attribute> {
+        // The attributes for a tuple struct are attached to the definition, not the ctor;
+        // we assume that someone passing in a tuple struct ctor is actually wanting to
+        // look at the definition
+        let mut item = self.entry(node_id);
+        let def_key = item.def_key.decode(self);
+        if def_key.disambiguated_data.data == DefPathData::StructCtor {
+            item = self.entry(def_key.parent.unwrap());
+        }
+        self.get_attributes(&item)
+    }
 
-pub fn get_crate_attributes(data: &[u8]) -> Vec<ast::Attribute> {
-    get_attributes(rbml::Doc::new(data))
-}
+    pub fn get_struct_field_names(&self, id: DefIndex) -> Vec<ast::Name> {
+        self.entry(id).children.decode(self).map(|index| {
+            self.item_name(&self.entry(index))
+        }).collect()
+    }
 
-#[derive(Clone)]
-pub struct CrateDep {
-    pub cnum: ast::CrateNum,
-    pub name: String,
-    pub hash: Svh,
-    pub explicitly_linked: bool,
-}
+    fn get_attributes(&self, item: &Entry<'tcx>) -> Vec<ast::Attribute> {
+        item.attributes.decode(self).map(|mut attr| {
+            // Need new unique IDs: old thread-local IDs won't map to new threads.
+            attr.node.id = attr::mk_attr_id();
+            attr
+        }).collect()
+    }
 
-pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
-    let cratedoc = rbml::Doc::new(data);
-    let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
-
-    fn docstr(doc: rbml::Doc, tag_: usize) -> String {
-        let d = reader::get_doc(doc, tag_);
-        d.as_str_slice().to_string()
-    }
-
-    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(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 {
-            cnum: crate_num as u32 + 1,
-            name: name,
-            hash: hash,
-            explicitly_linked: explicitly_linked,
+    // Translate a DefId from the current compilation environment to a DefId
+    // for an external crate.
+    fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
+        for (local, &global) in self.cnum_map.borrow().iter_enumerated() {
+            if global == did.krate {
+                return Some(DefId { krate: local, index: did.index });
+            }
         }
-    }).collect()
-}
 
-fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
-    write!(out, "=External Dependencies=\n")?;
-    for dep in &get_crate_deps(data) {
-        write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)?;
+        None
     }
-    write!(out, "\n")?;
-    Ok(())
-}
 
-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(reader::doc_as_u64(doc))
-    })
-}
+    pub fn get_inherent_implementations_for_type(&self, id: DefIndex) -> Vec<DefId> {
+        self.entry(id).inherent_impls.decode(self).map(|index| {
+            self.local_def_id(index)
+        }).collect()
+    }
 
-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(reader::doc_as_u64(hashdoc))
-}
+    pub fn get_implementations_for_trait(&self, filter: Option<DefId>, result: &mut Vec<DefId>) {
+        // Do a reverse lookup beforehand to avoid touching the crate_num
+        // hash map in the loop below.
+        let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
+            Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
+            Some(None) => return,
+            None => None
+        };
 
-pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
-    let cratedoc = rbml::Doc::new(data);
-    reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
-        doc.as_str_slice()
-    })
-}
+        // FIXME(eddyb) Make this O(1) instead of O(n).
+        for trait_impls in self.root.impls.decode(self) {
+            if filter.is_some() && filter != Some(trait_impls.trait_id) {
+                continue;
+            }
 
-pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str {
-    let crate_doc = rbml::Doc::new(data);
-    let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
-    let slice: &'a str = disambiguator_doc.as_str_slice();
-    slice
-}
+            result.extend(trait_impls.impls.decode(self).map(|index| {
+                self.local_def_id(index)
+            }));
 
-pub fn get_crate_triple(data: &[u8]) -> Option<String> {
-    let cratedoc = rbml::Doc::new(data);
-    let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple);
-    triple_doc.map(|s| s.as_str().to_string())
-}
+            if filter.is_some() {
+                break;
+            }
+        }
+    }
 
-pub fn get_crate_name(data: &[u8]) -> &str {
-    maybe_get_crate_name(data).expect("no crate name in crate")
-}
+    pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
+        self.entry(id).def_key.decode(self).parent.and_then(|parent_index| {
+            match self.entry(parent_index).kind {
+                EntryKind::Trait(_) => Some(self.local_def_id(parent_index)),
+                _ => None
+            }
+        })
+    }
 
-pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> {
-    let hash = get_crate_hash(bytes);
-    let md = rbml::Doc::new(bytes);
-    list_crate_attributes(md, &hash, out)?;
-    list_crate_deps(bytes, out)
-}
 
-// Translates a def_id from an external crate to a def_id for the current
-// compilation environment. We use this when trying to load types from
-// external crates - if those types further refer to types in other crates
-// then we must translate the crate number from that encoded in the external
-// crate to the correct local crate number.
-pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId {
-    if did.is_local() {
-        return DefId { krate: cdata.cnum, index: did.index };
+    pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> {
+        self.root.native_libraries.decode(self).collect()
     }
 
-    DefId {
-        krate: cdata.cnum_map.borrow()[did.krate],
-        index: did.index
+    pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> {
+        self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| {
+            let cnum = CrateNum::new(i + 1);
+            link.map(|link| (self.cnum_map.borrow()[cnum], link))
+        }).collect()
     }
-}
 
-// Translate a DefId from the current compilation environment to a DefId
-// for an external crate.
-fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
-    for (local, &global) in cdata.cnum_map.borrow().iter_enumerated() {
-        if global == did.krate {
-            return Some(DefId { krate: local, index: did.index });
-        }
+    pub fn get_missing_lang_items(&self) -> Vec<lang_items::LangItem> {
+        self.root.lang_items_missing.decode(self).collect()
     }
 
-    None
-}
-
-/// Translates a `Span` from an extern crate to the corresponding `Span`
-/// within the local crate's codemap.
-pub fn translate_span(cdata: Cmd,
-                      codemap: &codemap::CodeMap,
-                      last_filemap_index_hint: &Cell<usize>,
-                      span: syntax_pos::Span)
-                      -> syntax_pos::Span {
-    let span = if span.lo > span.hi {
-        // Currently macro expansion sometimes produces invalid Span values
-        // where lo > hi. In order not to crash the compiler when trying to
-        // translate these values, let's transform them into something we
-        // can handle (and which will produce useful debug locations at
-        // least some of the time).
-        // This workaround is only necessary as long as macro expansion is
-        // not fixed. FIXME(#23480)
-        syntax_pos::mk_sp(span.lo, span.lo)
-    } else {
-        span
-    };
-
-    let imported_filemaps = cdata.imported_filemaps(&codemap);
-    let filemap = {
-        // Optimize for the case that most spans within a translated item
-        // originate from the same filemap.
-        let last_filemap_index = last_filemap_index_hint.get();
-        let last_filemap = &imported_filemaps[last_filemap_index];
-
-        if span.lo >= last_filemap.original_start_pos &&
-           span.lo <= last_filemap.original_end_pos &&
-           span.hi >= last_filemap.original_start_pos &&
-           span.hi <= last_filemap.original_end_pos {
-            last_filemap
-        } else {
-            let mut a = 0;
-            let mut b = imported_filemaps.len();
+    pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec<ast::Name> {
+        let arg_names = match self.entry(id).kind {
+            EntryKind::Fn(data) |
+            EntryKind::ForeignFn(data) => data.decode(self).arg_names,
+            EntryKind::Method(data) => data.decode(self).fn_data.arg_names,
+            _ => LazySeq::empty()
+        };
+        arg_names.decode(self).collect()
+    }
 
-            while b - a > 1 {
-                let m = (a + b) / 2;
-                if imported_filemaps[m].original_start_pos > span.lo {
-                    b = m;
-                } else {
-                    a = m;
-                }
-            }
+    pub fn get_reachable_ids(&self) -> Vec<DefId> {
+        self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect()
+    }
 
-            last_filemap_index_hint.set(a);
-            &imported_filemaps[a]
-        }
-    };
+    pub fn is_const_fn(&self, id: DefIndex) -> bool {
+        let constness = match self.entry(id).kind {
+            EntryKind::Method(data) => data.decode(self).fn_data.constness,
+            EntryKind::Fn(data) => data.decode(self).constness,
+            _ => hir::Constness::NotConst
+        };
+        constness == hir::Constness::Const
+    }
 
-    let lo = (span.lo - filemap.original_start_pos) +
-              filemap.translated_filemap.start_pos;
-    let hi = (span.hi - filemap.original_start_pos) +
-              filemap.translated_filemap.start_pos;
+    pub fn is_extern_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+        let item = match self.maybe_entry(id) {
+            Some(item) => item.decode(self),
+            None => return false,
+        };
+        let applicable = match item.kind {
+            EntryKind::ImmStatic |
+            EntryKind::MutStatic |
+            EntryKind::ForeignImmStatic |
+            EntryKind::ForeignMutStatic => true,
+
+            EntryKind::Fn(_) | EntryKind::ForeignFn(_) => {
+                self.get_generics(id, tcx).types.is_empty()
+            }
 
-    syntax_pos::mk_sp(lo, hi)
-}
+            _ => false,
+        };
 
-pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
-                                                id: DefIndex,
-                                                mut callback: F)
-    where F: FnMut(DefId),
-{
-    let item_doc = cdata.lookup_item(id);
-    for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) {
-        if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() {
-            callback(item_def_id(impl_doc, cdata));
+        if applicable {
+            attr::contains_extern_indicator(tcx.sess.diagnostic(),
+                                            &self.get_attributes(&item))
+        } else {
+            false
         }
     }
-}
 
-pub fn each_implementation_for_trait<F>(cdata: Cmd,
-                                        def_id: DefId,
-                                        mut callback: F) where
-    F: FnMut(DefId),
-{
-    // Do a reverse lookup beforehand to avoid touching the crate_num
-    // hash map in the loop below.
-    if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) {
-        let def_id_u64 = def_to_u64(crate_local_did);
-
-        let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
-        for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) {
-            let trait_def_id = reader::get_doc(trait_doc, tag_def_id);
-            if reader::doc_as_u64(trait_def_id) != def_id_u64 {
-                continue;
-            }
-            for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) {
-                callback(translated_def_id(cdata, impl_doc));
-            }
+    pub fn is_foreign_item(&self, id: DefIndex) -> bool {
+        match self.entry(id).kind {
+            EntryKind::ForeignImmStatic |
+            EntryKind::ForeignMutStatic |
+            EntryKind::ForeignFn(_) => true,
+            _ => false
         }
     }
-}
 
-pub fn get_trait_of_item<'a, 'tcx>(cdata: Cmd,
-                                   id: DefIndex,
-                                   tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                   -> Option<DefId> {
-    let item_doc = cdata.lookup_item(id);
-    let parent_item_id = match item_parent_item(cdata, item_doc) {
-        None => return None,
-        Some(item_id) => item_id,
-    };
-    let parent_item_doc = cdata.lookup_item(parent_item_id.index);
-    match item_family(parent_item_doc) {
-        Trait => Some(item_def_id(parent_item_doc, cdata)),
-        Impl | DefaultImpl => {
-            reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref)
-                .map(|_| item_trait_ref(parent_item_doc, tcx, cdata).def_id)
+    pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
+        match self.entry(trait_id).kind {
+            EntryKind::Trait(data) => data.decode(self).has_default_impl,
+            _ => bug!()
         }
-        _ => None
     }
-}
-
 
-pub fn get_native_libraries(cdata: Cmd)
-                            -> Vec<(cstore::NativeLibraryKind, String)> {
-    let libraries = reader::get_doc(rbml::Doc::new(cdata.data()),
-                                    tag_native_libraries);
-    reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| {
-        let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
-        let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
-        let kind: cstore::NativeLibraryKind =
-            cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
-        let name = name_doc.as_str().to_string();
-        (kind, name)
-    }).collect()
-}
-
-pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<DefIndex> {
-    reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
-        .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
-}
-
-pub fn each_exported_macro<F>(data: &[u8], mut f: F) where
-    F: FnMut(ast::Name, Vec<ast::Attribute>, Span, String) -> bool,
-{
-    let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
-    for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
-        let name = item_name(macro_doc);
-        let attrs = get_attributes(macro_doc);
-        let span = get_macro_span(macro_doc);
-        let body = reader::get_doc(macro_doc, tag_macro_def_body);
-        if !f(name, attrs, span, body.as_str().to_string()) {
-            break;
+    pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
+        match self.entry(impl_id).kind  {
+            EntryKind::DefaultImpl(_) => true,
+            _ => false
         }
     }
-}
-
-pub fn get_macro_span(doc: rbml::Doc) -> Span {
-    let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo);
-    let lo = BytePos(reader::doc_as_u32(lo_doc));
-    let hi_doc = reader::get_doc(doc, tag_macro_def_span_hi);
-    let hi = BytePos(reader::doc_as_u32(hi_doc));
-    return Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
-}
-
-pub fn get_dylib_dependency_formats(cdata: Cmd)
-    -> Vec<(ast::CrateNum, LinkagePreference)>
-{
-    let formats = reader::get_doc(rbml::Doc::new(cdata.data()),
-                                  tag_dylib_dependency_formats);
-    let mut result = Vec::new();
-
-    debug!("found dylib deps: {}", formats.as_str_slice());
-    for spec in formats.as_str_slice().split(',') {
-        if spec.is_empty() { continue }
-        let cnum = spec.split(':').nth(0).unwrap();
-        let link = spec.split(':').nth(1).unwrap();
-        let cnum: ast::CrateNum = cnum.parse().unwrap();
-        let cnum = cdata.cnum_map.borrow()[cnum];
-        result.push((cnum, if link == "d" {
-            LinkagePreference::RequireDynamic
-        } else {
-            LinkagePreference::RequireStatic
-        }));
-    }
-    return result;
-}
 
-pub fn get_missing_lang_items(cdata: Cmd)
-    -> Vec<lang_items::LangItem>
-{
-    let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items);
-    reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| {
-        lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap()
-    }).collect()
-}
-
-pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec<String> {
-    let method_doc = cdata.lookup_item(id);
-    match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
-        Some(args_doc) => {
-            reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| {
-                name_doc.as_str_slice().to_string()
-            }).collect()
-        },
-        None => vec![],
+    pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind {
+        match self.entry(closure_id).kind {
+            EntryKind::Closure(data) => data.decode(self).kind,
+            _ => bug!()
+        }
     }
-}
 
-pub fn get_reachable_ids(cdata: Cmd) -> Vec<DefId> {
-    let items = reader::get_doc(rbml::Doc::new(cdata.data()),
-                                tag_reachable_ids);
-    reader::tagged_docs(items, tag_reachable_id).map(|doc| {
-        DefId {
-            krate: cdata.cnum,
-            index: DefIndex::from_u32(reader::doc_as_u32(doc)),
+    pub fn closure_ty(&self, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                      -> ty::ClosureTy<'tcx> {
+        match self.entry(closure_id).kind {
+            EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)),
+            _ => bug!()
         }
-    }).collect()
-}
-
-pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    match item_family(item_doc) {
-        Type => true,
-        _ => false,
     }
-}
 
-pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    match fn_constness(item_doc) {
-        hir::Constness::Const => true,
-        hir::Constness::NotConst => false,
+    pub fn def_key(&self, id: DefIndex) -> hir_map::DefKey {
+        debug!("def_key: id={:?}", id);
+        self.entry(id).def_key.decode(self)
     }
-}
 
-pub fn is_extern_item<'a, 'tcx>(cdata: Cmd,
-                                id: DefIndex,
-                                tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                -> bool {
-    let item_doc = match cdata.get_item(id) {
-        Some(doc) => doc,
-        None => return false,
-    };
-    let applicable = match item_family(item_doc) {
-        ImmStatic | MutStatic => true,
-        Fn => {
-            let ty::TypeScheme { generics, .. } = get_type(cdata, id, tcx);
-            let no_generics = generics.types.is_empty();
-            no_generics
-        },
-        _ => false,
-    };
-
-    if applicable {
-        attr::contains_extern_indicator(tcx.sess.diagnostic(),
-                                        &get_attributes(item_doc))
-    } else {
-        false
+    // Returns the path leading to the thing with this `id`. Note that
+    // some def-ids don't wind up in the metadata, so `def_path` sometimes
+    // returns `None`
+    pub fn def_path(&self, id: DefIndex) -> Option<hir_map::DefPath> {
+        debug!("def_path(id={:?})", id);
+        if self.maybe_entry(id).is_some() {
+            Some(hir_map::DefPath::make(self.cnum, id, |parent| self.def_key(parent)))
+        } else {
+            None
+        }
     }
-}
 
-pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    let parent_item_id = match item_parent_item(cdata, item_doc) {
-        None => return false,
-        Some(item_id) => item_id,
-    };
-    let parent_item_doc = cdata.lookup_item(parent_item_id.index);
-    item_family(parent_item_doc) == ForeignMod
-}
-
-pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool {
-    let item_doc = cdata.lookup_item(id);
-    match item_family(item_doc) {
-        Impl => true,
-        _ => false,
-    }
-}
+    /// Imports the codemap from an external crate into the codemap of the crate
+    /// currently being compiled (the "local crate").
+    ///
+    /// The import algorithm works analogous to how AST items are inlined from an
+    /// external crate's metadata:
+    /// For every FileMap in the external codemap an 'inline' copy is created in the
+    /// local codemap. The correspondence relation between external and local
+    /// FileMaps is recorded in the `ImportedFileMap` objects returned from this
+    /// function. When an item from an external crate is later inlined into this
+    /// crate, this correspondence information is used to translate the span
+    /// information of the inlined item so that it refers the correct positions in
+    /// the local codemap (see `<decoder::DecodeContext as SpecializedDecoder<Span>>`).
+    ///
+    /// The import algorithm in the function below will reuse FileMaps already
+    /// existing in the local codemap. For example, even if the FileMap of some
+    /// source file of libstd gets imported many times, there will only ever be
+    /// one FileMap object for the corresponding file in the local codemap.
+    ///
+    /// Note that imported FileMaps do not actually contain the source code of the
+    /// file they represent, just information about length, line breaks, and
+    /// multibyte characters. This information is enough to generate valid debuginfo
+    /// for items inlined from other crates.
+    pub fn imported_filemaps(&'a self, local_codemap: &codemap::CodeMap)
+                             -> Ref<'a, Vec<cstore::ImportedFileMap>> {
+        {
+            let filemaps = self.codemap_import_info.borrow();
+            if !filemaps.is_empty() {
+                return filemaps;
+            }
+        }
 
-fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          cdata: Cmd,
-                          tag: usize)
-                          -> ty::Generics<'tcx>
-{
-    let doc = reader::get_doc(base_doc, tag);
-
-    let mut types = subst::VecPerParamSpace::empty();
-    for p in reader::tagged_docs(doc, tag_type_param_def) {
-        let bd =
-            TyDecoder::with_doc(tcx, cdata.cnum, p,
-                                &mut |did| translate_def_id(cdata, did))
-            .parse_type_param_def();
-        types.push(bd.space, bd);
-    }
-
-    let mut regions = subst::VecPerParamSpace::empty();
-    for p in reader::tagged_docs(doc, tag_region_param_def) {
-        let bd =
-            TyDecoder::with_doc(tcx, cdata.cnum, p,
-                                &mut |did| translate_def_id(cdata, did))
-            .parse_region_param_def();
-        regions.push(bd.space, bd);
-    }
-
-    ty::Generics { types: types, regions: regions }
-}
+        let external_codemap = self.root.codemap.decode(self);
+
+        let imported_filemaps = external_codemap.map(|filemap_to_import| {
+            // Try to find an existing FileMap that can be reused for the filemap to
+            // be imported. A FileMap is reusable if it is exactly the same, just
+            // positioned at a different offset within the codemap.
+            let reusable_filemap = {
+                local_codemap.files
+                             .borrow()
+                             .iter()
+                             .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
+                             .map(|rc| rc.clone())
+            };
 
-fn doc_predicate<'a, 'tcx>(cdata: Cmd,
-                           doc: rbml::Doc,
-                           tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                           -> ty::Predicate<'tcx>
-{
-    let predicate_pos = cdata.xref_index.lookup(
-        cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize;
-    TyDecoder::new(
-        cdata.data(), cdata.cnum, predicate_pos, tcx,
-        &mut |did| translate_def_id(cdata, did)
-    ).parse_predicate()
-}
+            match reusable_filemap {
+                Some(fm) => {
+                    cstore::ImportedFileMap {
+                        original_start_pos: filemap_to_import.start_pos,
+                        original_end_pos: filemap_to_import.end_pos,
+                        translated_filemap: fm
+                    }
+                }
+                None => {
+                    // We can't reuse an existing FileMap, so allocate a new one
+                    // containing the information we need.
+                    let syntax_pos::FileMap {
+                        name,
+                        abs_path,
+                        start_pos,
+                        end_pos,
+                        lines,
+                        multibyte_chars,
+                        ..
+                    } = filemap_to_import;
+
+                    let source_length = (end_pos - start_pos).to_usize();
+
+                    // Translate line-start positions and multibyte character
+                    // position into frame of reference local to file.
+                    // `CodeMap::new_imported_filemap()` will then translate those
+                    // coordinates to their new global frame of reference when the
+                    // offset of the FileMap is known.
+                    let mut lines = lines.into_inner();
+                    for pos in &mut lines {
+                        *pos = *pos - start_pos;
+                    }
+                    let mut multibyte_chars = multibyte_chars.into_inner();
+                    for mbc in &mut multibyte_chars {
+                        mbc.pos = mbc.pos - start_pos;
+                    }
 
-fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc,
-                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            cdata: Cmd,
-                            tag: usize)
-                            -> ty::GenericPredicates<'tcx>
-{
-    let doc = reader::get_doc(base_doc, tag);
+                    let local_version = local_codemap.new_imported_filemap(name,
+                                                                           abs_path,
+                                                                           source_length,
+                                                                           lines,
+                                                                           multibyte_chars);
+                    cstore::ImportedFileMap {
+                        original_start_pos: start_pos,
+                        original_end_pos: end_pos,
+                        translated_filemap: local_version
+                    }
+                }
+            }
+        }).collect();
 
-    let mut predicates = subst::VecPerParamSpace::empty();
-    for predicate_doc in reader::tagged_docs(doc, tag_type_predicate) {
-        predicates.push(subst::TypeSpace,
-                        doc_predicate(cdata, predicate_doc, tcx));
-    }
-    for predicate_doc in reader::tagged_docs(doc, tag_self_predicate) {
-        predicates.push(subst::SelfSpace,
-                        doc_predicate(cdata, predicate_doc, tcx));
+        // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
+        *self.codemap_import_info.borrow_mut() = imported_filemaps;
+        self.codemap_import_info.borrow()
     }
-    for predicate_doc in reader::tagged_docs(doc, tag_fn_predicate) {
-        predicates.push(subst::FnSpace,
-                        doc_predicate(cdata, predicate_doc, tcx));
-    }
-
-    ty::GenericPredicates { predicates: predicates }
 }
 
-pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool {
-    let trait_doc = cdata.lookup_item(trait_id);
-    assert!(item_family(trait_doc) == Family::Trait);
-    let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
-    reader::doc_as_u8(defaulted_doc) != 0
-}
+fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap, fm2: &syntax_pos::FileMap) -> bool {
+    if fm1.byte_length() != fm2.byte_length() {
+        return false;
+    }
 
-pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool {
-    let impl_doc = cdata.lookup_item(impl_id);
-    item_family(impl_doc) == Family::DefaultImpl
-}
+    if fm1.name != fm2.name {
+        return false;
+    }
 
-pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<syntax_pos::FileMap> {
-    let crate_doc = rbml::Doc::new(metadata);
-    let cm_doc = reader::get_doc(crate_doc, tag_codemap);
+    let lines1 = fm1.lines.borrow();
+    let lines2 = fm2.lines.borrow();
 
-    reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| {
-        let mut decoder = reader::Decoder::new(filemap_doc);
-        decoder.read_opaque(|opaque_decoder, _| {
-            Decodable::decode(opaque_decoder)
-        }).unwrap()
-    }).collect()
-}
+    if lines1.len() != lines2.len() {
+        return false;
+    }
 
-pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind {
-    let closure_doc = cdata.lookup_item(closure_id);
-    let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind);
-    let mut decoder = reader::Decoder::new(closure_kind_doc);
-    ty::ClosureKind::decode(&mut decoder).unwrap()
-}
+    for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
+        if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
+            return false;
+        }
+    }
 
-pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                            -> ty::ClosureTy<'tcx> {
-    let closure_doc = cdata.lookup_item(closure_id);
-    let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty);
-    TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did))
-        .parse_closure_ty()
-}
+    let multibytes1 = fm1.multibyte_chars.borrow();
+    let multibytes2 = fm2.multibyte_chars.borrow();
 
-pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey {
-    debug!("def_key: id={:?}", id);
-    let item_doc = cdata.lookup_item(id);
-    item_def_key(item_doc)
-}
+    if multibytes1.len() != multibytes2.len() {
+        return false;
+    }
 
-fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
-    match reader::maybe_get_doc(item_doc, tag_def_key) {
-        Some(def_key_doc) => {
-            let mut decoder = reader::Decoder::new(def_key_doc);
-            let simple_key = def_key::DefKey::decode(&mut decoder).unwrap();
-            let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| {
-                token::intern(name.as_str_slice()).as_str()
-            });
-            def_key::recover_def_key(simple_key, name)
-        }
-        None => {
-            bug!("failed to find block with tag {:?} for item with family {:?}",
-                   tag_def_key,
-                   item_family(item_doc))
+    for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
+        if (mb1.bytes != mb2.bytes) ||
+            ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
+            return false;
         }
     }
-}
 
-pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath {
-    debug!("def_path(id={:?})", id);
-    hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))
-}
-
-pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy {
-    let crate_doc = rbml::Doc::new(data);
-    let strat_doc = reader::get_doc(crate_doc, tag_panic_strategy);
-    match reader::doc_as_u8(strat_doc) {
-        b'U' => PanicStrategy::Unwind,
-        b'A' => PanicStrategy::Abort,
-        b => panic!("unknown panic strategy in metadata: {}", b),
-    }
+    true
 }