]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_metadata/encoder.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_metadata / encoder.rs
index cc1d07b33c7e830b6840e2d4b79045210db44f99..0f067270b80f5cb84c67bac8fc0ae956736ea6fd 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Metadata encoding
-
-#![allow(unused_must_use)] // everything is just a MemWriter, can't fail
-#![allow(non_camel_case_types)]
-
-use astencode::encode_inlined_item;
-use common::*;
 use cstore;
-use decoder;
-use def_key;
-use tyencode;
-use index::{self, IndexData};
+use index::Index;
+use schema::*;
 
-use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls};
+use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
+use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind};
 use rustc::hir::def;
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use middle::dependency_format::Linkage;
-use rustc::dep_graph::{DepGraph, DepNode, DepTask};
-use rustc::ty::subst;
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
+use rustc::middle::dependency_format::Linkage;
+use rustc::middle::lang_items;
+use rustc::mir;
 use rustc::traits::specialization_graph;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::util::IntTypeExt;
 
-use rustc::hir::svh::Svh;
 use rustc::mir::mir_map::MirMap;
-use rustc::session::config::{self, PanicStrategy};
+use rustc::session::config::{self, CrateTypeRustcMacro};
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
-use rustc_serialize::Encodable;
-use std::cell::RefCell;
+use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
+use std::hash::Hash;
+use std::intrinsics;
 use std::io::prelude::*;
-use std::io::{Cursor, SeekFrom};
+use std::io::Cursor;
 use std::rc::Rc;
 use std::u32;
-use syntax::abi::Abi;
-use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
-use syntax::attr::{self,AttrMetaMethods,AttributeMethods};
-use errors::Handler;
+use syntax::ast::{self, CRATE_NODE_ID};
+use syntax::attr;
 use syntax;
-use syntax_pos::BytePos;
-use rbml::writer::Encoder;
+use syntax_pos;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::Visitor;
 use rustc::hir::intravisit;
-use rustc::hir::map::DefKey;
+
+use super::index_builder::{FromId, IndexBuilder, Untracked};
 
 pub struct EncodeContext<'a, 'tcx: 'a> {
-    pub diag: &'a Handler,
+    opaque: opaque::Encoder<'a>,
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    pub reexports: &'a def::ExportMap,
-    pub link_meta: &'a LinkMeta,
-    pub cstore: &'a cstore::CStore,
-    pub type_abbrevs: tyencode::abbrev_map<'tcx>,
-    pub reachable: &'a NodeSet,
-    pub mir_map: &'a MirMap<'tcx>,
-}
-
-impl<'a, 'tcx> EncodeContext<'a,'tcx> {
-    fn local_id(&self, def_id: DefId) -> NodeId {
-        self.tcx.map.as_local_node_id(def_id).unwrap()
+    reexports: &'a def::ExportMap,
+    link_meta: &'a LinkMeta,
+    cstore: &'a cstore::CStore,
+    reachable: &'a NodeSet,
+    mir_map: &'a MirMap<'tcx>,
+
+    lazy_state: LazyState,
+    type_shorthands: FnvHashMap<Ty<'tcx>, usize>,
+    predicate_shorthands: FnvHashMap<ty::Predicate<'tcx>, usize>,
+}
+
+macro_rules! encoder_methods {
+    ($($name:ident($ty:ty);)*) => {
+        $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> {
+            self.opaque.$name(value)
+        })*
     }
 }
 
-/// "interned" entries referenced by id
-#[derive(PartialEq, Eq, Hash)]
-pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
+impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
+    type Error = <opaque::Encoder<'a> as Encoder>::Error;
 
-struct CrateIndex<'a, 'tcx> {
-    dep_graph: &'a DepGraph,
-    items: IndexData,
-    xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
-}
-
-impl<'a, 'tcx> CrateIndex<'a, 'tcx> {
-    /// Records that `id` is being emitted at the current offset.
-    /// This data is later used to construct the item index in the
-    /// metadata so we can quickly find the data for a given item.
-    ///
-    /// Returns a dep-graph task that you should keep live as long as
-    /// the data for this item is being emitted.
-    fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
-        let position = rbml_w.mark_stable_position();
-        self.items.record(id, position);
-        self.dep_graph.in_task(DepNode::MetaData(id))
+    fn emit_nil(&mut self) -> Result<(), Self::Error> {
+        Ok(())
     }
 
-    fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
-        let old_len = self.xrefs.len() as u32;
-        *self.xrefs.entry(xref).or_insert(old_len)
+    encoder_methods! {
+        emit_usize(usize);
+        emit_u64(u64);
+        emit_u32(u32);
+        emit_u16(u16);
+        emit_u8(u8);
+
+        emit_isize(isize);
+        emit_i64(i64);
+        emit_i32(i32);
+        emit_i16(i16);
+        emit_i8(i8);
+
+        emit_bool(bool);
+        emit_f64(f64);
+        emit_f32(f32);
+        emit_char(char);
+        emit_str(&str);
     }
 }
 
-fn encode_name(rbml_w: &mut Encoder, name: Name) {
-    rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str());
-}
-
-fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
-    rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id));
-}
-
-fn encode_def_key(rbml_w: &mut Encoder, key: DefKey) {
-    let simple_key = def_key::simplify_def_key(key);
-    rbml_w.start_tag(tag_def_key);
-    simple_key.encode(rbml_w);
-    rbml_w.end_tag();
-}
-
-/// For every DefId that we create a metadata item for, we include a
-/// serialized copy of its DefKey, which allows us to recreate a path.
-fn encode_def_id_and_key(ecx: &EncodeContext,
-                         rbml_w: &mut Encoder,
-                         def_id: DefId)
-{
-    encode_def_id(rbml_w, def_id);
-    let def_key = ecx.tcx.map.def_key(def_id);
-    encode_def_key(rbml_w, def_key);
-}
-
-fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder,
-                              ecx: &EncodeContext<'a, 'tcx>,
-                              trait_ref: ty::TraitRef<'tcx>,
-                              tag: usize) {
-    rbml_w.start_tag(tag);
-    tyencode::enc_trait_ref(rbml_w.writer, &ecx.ty_str_ctxt(), trait_ref);
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
+impl<'a, 'tcx, T> SpecializedEncoder<Lazy<T>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
+        self.emit_lazy_distance(lazy.position, Lazy::<T>::min_size())
+    }
 }
 
-// Item info table encoding
-fn encode_family(rbml_w: &mut Encoder, c: char) {
-    rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8);
+impl<'a, 'tcx, T> SpecializedEncoder<LazySeq<T>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, seq: &LazySeq<T>) -> Result<(), Self::Error> {
+        self.emit_usize(seq.len)?;
+        if seq.len == 0 {
+            return Ok(());
+        }
+        self.emit_lazy_distance(seq.position, LazySeq::<T>::min_size(seq.len))
+    }
 }
 
-pub fn def_to_u64(did: DefId) -> u64 {
-    assert!(did.index.as_u32() < u32::MAX);
-    (did.krate as u64) << 32 | (did.index.as_usize() as u64)
+impl<'a, 'tcx> SpecializedEncoder<Ty<'tcx>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> {
+        self.encode_with_shorthand(ty, &ty.sty, |ecx| &mut ecx.type_shorthands)
+    }
 }
 
-pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String {
-    format!("{}:{}", did.krate, did.index.as_usize())
+impl<'a, 'tcx> SpecializedEncoder<ty::GenericPredicates<'tcx>> for EncodeContext<'a, 'tcx> {
+    fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>)
+                          -> Result<(), Self::Error> {
+        predicates.parent.encode(self)?;
+        predicates.predicates.len().encode(self)?;
+        for predicate in &predicates.predicates {
+            self.encode_with_shorthand(predicate, predicate, |ecx| &mut ecx.predicate_shorthands)?
+        }
+        Ok(())
+    }
 }
 
-fn encode_item_variances(rbml_w: &mut Encoder,
-                         ecx: &EncodeContext,
-                         id: NodeId) {
-    let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id));
-    rbml_w.start_tag(tag_item_variances);
-    v.encode(rbml_w);
-    rbml_w.end_tag();
-}
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    pub fn position(&self) -> usize {
+        self.opaque.position()
+    }
 
-fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
-                                             ecx: &EncodeContext<'a, 'tcx>,
-                                             index: &mut CrateIndex<'a, 'tcx>,
-                                             id: NodeId) {
-    encode_bounds_and_type(rbml_w,
-                           ecx,
-                           index,
-                           &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
-                           &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
-}
+    fn emit_node<F: FnOnce(&mut Self, usize) -> R, R>(&mut self, f: F) -> R {
+        assert_eq!(self.lazy_state, LazyState::NoNode);
+        let pos = self.position();
+        self.lazy_state = LazyState::NodeStart(pos);
+        let r = f(self, pos);
+        self.lazy_state = LazyState::NoNode;
+        r
+    }
 
-fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
-                                    ecx: &EncodeContext<'a, 'tcx>,
-                                    index: &mut CrateIndex<'a, 'tcx>,
-                                    scheme: &ty::TypeScheme<'tcx>,
-                                    predicates: &ty::GenericPredicates<'tcx>) {
-    encode_generics(rbml_w, ecx, index,
-                    &scheme.generics, &predicates, tag_item_generics);
-    encode_type(ecx, rbml_w, scheme.ty);
-}
+    fn emit_lazy_distance(&mut self, position: usize, min_size: usize)
+                          -> Result<(), <Self as Encoder>::Error> {
+        let min_end = position + min_size;
+        let distance = match self.lazy_state {
+            LazyState::NoNode => {
+                bug!("emit_lazy_distance: outside of a metadata node")
+            }
+            LazyState::NodeStart(start) => {
+                assert!(min_end <= start);
+                start - min_end
+            }
+            LazyState::Previous(last_min_end) => {
+                assert!(last_min_end <= position);
+                position - last_min_end
+            }
+        };
+        self.lazy_state = LazyState::Previous(min_end);
+        self.emit_usize(distance)
+    }
 
-fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
-    let id = def_to_u64(vid);
-    rbml_w.wr_tagged_u64(tag_items_data_item_variant, id);
-    rbml_w.wr_tagged_u64(tag_mod_child, id);
-}
+    pub fn lazy<T: Encodable>(&mut self, value: &T) -> Lazy<T> {
+        self.emit_node(|ecx, pos| {
+            value.encode(ecx).unwrap();
 
-fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                            rbml_w: &mut Encoder,
-                            closure_type: &ty::ClosureTy<'tcx>) {
-    tyencode::enc_closure_ty(rbml_w.writer, &ecx.ty_str_ctxt(), closure_type);
-    rbml_w.mark_stable_position();
-}
+            assert!(pos + Lazy::<T>::min_size() <= ecx.position());
+            Lazy::with_position(pos)
+        })
+    }
 
-fn encode_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                         rbml_w: &mut Encoder,
-                         typ: Ty<'tcx>) {
-    rbml_w.start_tag(tag_items_data_item_type);
-    tyencode::enc_ty(rbml_w.writer, &ecx.ty_str_ctxt(), typ);
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
-}
+    fn lazy_seq<I, T>(&mut self, iter: I) -> LazySeq<T>
+    where I: IntoIterator<Item=T>, T: Encodable {
+        self.emit_node(|ecx, pos| {
+            let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count();
 
-fn encode_disr_val(_: &EncodeContext,
-                   rbml_w: &mut Encoder,
-                   disr_val: ty::Disr) {
-    // convert to u64 so just the number is printed, without any type info
-    rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
-}
+            assert!(pos + LazySeq::<T>::min_size(len) <= ecx.position());
+            LazySeq::with_position_and_length(pos, len)
+        })
+    }
 
-fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
-    rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
-}
+    fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq<T>
+    where I: IntoIterator<Item=&'b T>, T: 'b + Encodable {
+        self.emit_node(|ecx, pos| {
+            let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count();
 
-fn encode_struct_fields(rbml_w: &mut Encoder,
-                        variant: ty::VariantDef) {
-    for f in &variant.fields {
-        if variant.kind == ty::VariantKind::Tuple {
-            rbml_w.start_tag(tag_item_unnamed_field);
-        } else {
-            rbml_w.start_tag(tag_item_field);
-            encode_name(rbml_w, f.name);
-        }
-        encode_struct_field_family(rbml_w, f.vis);
-        encode_def_id(rbml_w, f.did);
-        rbml_w.end_tag();
+            assert!(pos + LazySeq::<T>::min_size(len) <= ecx.position());
+            LazySeq::with_position_and_length(pos, len)
+        })
     }
-}
 
-fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                      rbml_w: &mut Encoder,
-                                      did: DefId,
-                                      vis: &hir::Visibility,
-                                      index: &mut CrateIndex<'a, 'tcx>) {
-    debug!("encode_enum_variant_info(did={:?})", did);
-    let repr_hints = ecx.tcx.lookup_repr_hints(did);
-    let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
-    let mut disr_val = repr_type.initial_discriminant(ecx.tcx);
-    let def = ecx.tcx.lookup_adt_def(did);
-    for variant in &def.variants {
-        let vid = variant.did;
-        let variant_node_id = ecx.local_id(vid);
-
-        for field in &variant.fields {
-            encode_field(ecx, rbml_w, field, index);
+    /// Encode the given value or a previously cached shorthand.
+    fn encode_with_shorthand<T, U, M>(&mut self, value: &T, variant: &U, map: M)
+                                      -> Result<(), <Self as Encoder>::Error>
+    where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap<T, usize>,
+          T: Clone + Eq + Hash,
+          U: Encodable {
+        let existing_shorthand = map(self).get(value).cloned();
+        if let Some(shorthand) = existing_shorthand {
+            return self.emit_usize(shorthand);
         }
 
-        let _task = index.record(vid, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, vid);
-        encode_family(rbml_w, match variant.kind {
-            ty::VariantKind::Struct => 'V',
-            ty::VariantKind::Tuple => 'v',
-            ty::VariantKind::Unit => 'w',
-        });
-        encode_name(rbml_w, variant.name);
-        encode_parent_item(rbml_w, did);
-        encode_visibility(rbml_w, vis);
-
-        let attrs = ecx.tcx.get_attrs(vid);
-        encode_attributes(rbml_w, &attrs);
-        encode_repr_attrs(rbml_w, ecx, &attrs);
+        let start = self.position();
+        variant.encode(self)?;
+        let len = self.position() - start;
 
-        let stab = ecx.tcx.lookup_stability(vid);
-        let depr = ecx.tcx.lookup_deprecation(vid);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
+        // The shorthand encoding uses the same usize as the
+        // discriminant, with an offset so they can't conflict.
+        let discriminant = unsafe {
+            intrinsics::discriminant_value(variant)
+        };
+        assert!(discriminant < SHORTHAND_OFFSET as u64);
+        let shorthand = start + SHORTHAND_OFFSET;
 
-        encode_struct_fields(rbml_w, variant);
+        // Get the number of bits that leb128 could fit
+        // in the same space as the fully encoded type.
+        let leb128_bits = len * 7;
 
-        let specified_disr_val = variant.disr_val;
-        if specified_disr_val != disr_val {
-            encode_disr_val(ecx, rbml_w, specified_disr_val);
-            disr_val = specified_disr_val;
+        // Check that the shorthand is a not longer than the
+        // full encoding itself, i.e. it's an obvious win.
+        if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) {
+            map(self).insert(value.clone(), shorthand);
         }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
-
-        rbml_w.end_tag();
 
-        disr_val = disr_val.wrap_incr();
+        Ok(())
     }
-}
 
-/// Iterates through "auxiliary node IDs", which are node IDs that describe
-/// top-level items that are sub-items of the given item. Specifically:
-///
-/// * For newtype structs, iterates through the node ID of the constructor.
-fn each_auxiliary_node_id<F>(item: &hir::Item, callback: F) -> bool where
-    F: FnOnce(NodeId) -> bool,
-{
-    let mut continue_ = true;
-    match item.node {
-        hir::ItemStruct(ref struct_def, _) => {
-            // If this is a newtype struct, return the constructor.
-            if struct_def.is_tuple() {
-                continue_ = callback(struct_def.id());
-            }
-        }
-        _ => {}
+    /// For every DefId that we create a metadata item for, we include a
+    /// serialized copy of its DefKey, which allows us to recreate a path.
+    fn encode_def_key(&mut self, def_id: DefId) -> Lazy<hir::map::DefKey> {
+        let tcx = self.tcx;
+        self.lazy(&tcx.map.def_key(def_id))
     }
 
-    continue_
-}
-
-fn encode_reexports(ecx: &EncodeContext,
-                    rbml_w: &mut Encoder,
-                    id: NodeId) {
-    debug!("(encoding info for module) encoding reexports for {}", id);
-    match ecx.reexports.get(&id) {
-        Some(exports) => {
-            debug!("(encoding info for module) found reexports for {}", id);
-            for exp in exports {
-                debug!("(encoding info for module) reexport '{}' ({:?}) for \
-                        {}",
-                       exp.name,
-                       exp.def_id,
-                       id);
-                rbml_w.start_tag(tag_items_data_item_reexport);
-                rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
-                                     def_to_u64(exp.def_id));
-                rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
-                                     &exp.name.as_str());
-                rbml_w.end_tag();
-            }
-        },
-        None => debug!("(encoding info for module) found no reexports for {}", id),
+    fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq<ty::Variance> {
+        let tcx = self.tcx;
+        self.lazy_seq(tcx.item_variances(def_id).iter().cloned())
     }
-}
 
-fn encode_info_for_mod(ecx: &EncodeContext,
-                       rbml_w: &mut Encoder,
-                       md: &hir::Mod,
-                       attrs: &[ast::Attribute],
-                       id: NodeId,
-                       name: Name,
-                       vis: &hir::Visibility) {
-    rbml_w.start_tag(tag_items_data_item);
-    encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id));
-    encode_family(rbml_w, 'm');
-    encode_name(rbml_w, name);
-    debug!("(encoding info for module) encoding info for module ID {}", id);
-
-    // Encode info about all the module children.
-    for item_id in &md.item_ids {
-        rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
-
-        let item = ecx.tcx.map.expect_item(item_id.id);
-        each_auxiliary_node_id(item, |auxiliary_node_id| {
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
-            true
-        });
+    fn encode_item_type(&mut self, def_id: DefId) -> Lazy<Ty<'tcx>> {
+        let tcx = self.tcx;
+        self.lazy(&tcx.lookup_item_type(def_id).ty)
     }
 
-    encode_visibility(rbml_w, vis);
-
-    let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id));
-    let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id));
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
+    /// Encode data for the given variant of the given ADT. The
+    /// index of the variant is untracked: this is ok because we
+    /// will have to lookup the adt-def by its id, and that gives us
+    /// the right to access any information in the adt-def (including,
+    /// e.g., the length of the various vectors).
+    fn encode_enum_variant_info(&mut self,
+                                (enum_did, Untracked(index)):
+                                (DefId, Untracked<usize>)) -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let def = tcx.lookup_adt_def(enum_did);
+        let variant = &def.variants[index];
+        let def_id = variant.did;
+
+        let data = VariantData {
+            kind: variant.kind,
+            disr: variant.disr_val.to_u64_unchecked(),
+            struct_ctor: None
+        };
 
-    // Encode the reexports of this module, if this module is public.
-    if *vis == hir::Public {
-        debug!("(encoding info for module) encoding reexports for {}", id);
-        encode_reexports(ecx, rbml_w, id);
+        let enum_id = tcx.map.as_local_node_id(enum_did).unwrap();
+        let enum_vis = &tcx.map.expect_item(enum_id).vis;
+
+        Entry {
+            kind: EntryKind::Variant(self.lazy(&data)),
+            visibility: enum_vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
+            children: self.lazy_seq(variant.fields.iter().map(|f| {
+                assert!(f.did.is_local());
+                f.did.index
+            })),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
+        }
     }
-    encode_attributes(rbml_w, attrs);
-
-    rbml_w.end_tag();
-}
 
-fn encode_struct_field_family(rbml_w: &mut Encoder,
-                              visibility: ty::Visibility) {
-    encode_family(rbml_w, if visibility.is_public() { 'g' } else { 'N' });
-}
+    fn encode_info_for_mod(&mut self,
+                           FromId(id, (md, attrs, vis)):
+                           FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>)
+                           -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let def_id = tcx.map.local_def_id(id);
+
+        let data = ModData {
+            reexports: match self.reexports.get(&id) {
+                Some(exports) if *vis == hir::Public => {
+                    self.lazy_seq_ref(exports)
+                }
+                _ => LazySeq::empty()
+            }
+        };
 
-fn encode_visibility<T: HasVisibility>(rbml_w: &mut Encoder, visibility: T) {
-    let ch = if visibility.is_public() { 'y' } else { 'i' };
-    rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
+        Entry {
+            kind: EntryKind::Mod(self.lazy(&data)),
+            visibility: vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(attrs),
+            children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
+                tcx.map.local_def_id(item_id.id).index
+            })),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: None,
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+
+            ast: None,
+            mir: None
+        }
+    }
 }
 
-trait HasVisibility: Sized {
-    fn is_public(self) -> bool;
+trait Visibility {
+    fn simplify(&self) -> ty::Visibility;
 }
 
-impl<'a> HasVisibility for &'a hir::Visibility {
-    fn is_public(self) -> bool {
-        *self == hir::Public
+impl Visibility for hir::Visibility {
+    fn simplify(&self) -> ty::Visibility {
+        if *self == hir::Public {
+            ty::Visibility::Public
+        } else {
+            ty::Visibility::PrivateExternal
+        }
     }
 }
 
-impl HasVisibility for ty::Visibility {
-    fn is_public(self) -> bool {
-        self == ty::Visibility::Public
+impl Visibility for ty::Visibility {
+    fn simplify(&self) -> ty::Visibility {
+        if *self == ty::Visibility::Public {
+            ty::Visibility::Public
+        } else {
+            ty::Visibility::PrivateExternal
+        }
     }
 }
 
-fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) {
-    rbml_w.start_tag(tag_items_data_item_constness);
-    let ch = match constness {
-        hir::Constness::Const => 'c',
-        hir::Constness::NotConst => 'n',
-    };
-    rbml_w.wr_str(&ch.to_string());
-    rbml_w.end_tag();
-}
-
-fn encode_defaultness(rbml_w: &mut Encoder, defaultness: hir::Defaultness) {
-    let ch = match defaultness {
-        hir::Defaultness::Default => 'd',
-        hir::Defaultness::Final => 'f',
-    };
-    rbml_w.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8);
-}
-
-fn encode_explicit_self(rbml_w: &mut Encoder,
-                        explicit_self: &ty::ExplicitSelfCategory) {
-    let tag = tag_item_trait_method_explicit_self;
-
-    // Encode the base self type.
-    match *explicit_self {
-        ty::ExplicitSelfCategory::Static => {
-            rbml_w.wr_tagged_bytes(tag, &['s' as u8]);
-        }
-        ty::ExplicitSelfCategory::ByValue => {
-            rbml_w.wr_tagged_bytes(tag, &['v' as u8]);
-        }
-        ty::ExplicitSelfCategory::ByBox => {
-            rbml_w.wr_tagged_bytes(tag, &['~' as u8]);
-        }
-        ty::ExplicitSelfCategory::ByReference(_, m) => {
-            // FIXME(#4846) encode custom lifetime
-            let ch = encode_mutability(m);
-            rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]);
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+    fn encode_fields(&mut self,
+                     adt_def_id: DefId) {
+        let def = self.tcx.lookup_adt_def(adt_def_id);
+        for (variant_index, variant) in def.variants.iter().enumerate() {
+            for (field_index, field) in variant.fields.iter().enumerate() {
+                self.record(field.did,
+                            EncodeContext::encode_field,
+                            (adt_def_id, Untracked((variant_index, field_index))));
+            }
         }
     }
+}
 
-    fn encode_mutability(m: hir::Mutability) -> u8 {
-        match m {
-            hir::MutImmutable => 'i' as u8,
-            hir::MutMutable => 'm' as u8,
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    /// Encode data for the given field of the given variant of the
+    /// given ADT. The indices of the variant/field are untracked:
+    /// this is ok because we will have to lookup the adt-def by its
+    /// id, and that gives us the right to access any information in
+    /// the adt-def (including, e.g., the length of the various
+    /// vectors).
+    fn encode_field(&mut self,
+                    (adt_def_id, Untracked((variant_index, field_index))):
+                    (DefId, Untracked<(usize, usize)>)) -> Entry<'tcx> {
+        let tcx = self.tcx;
+        let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index];
+        let field = &variant.fields[field_index];
+
+        let def_id = field.did;
+        let variant_id = tcx.map.as_local_node_id(variant.did).unwrap();
+        let variant_data = tcx.map.expect_variant_data(variant_id);
+
+        Entry {
+            kind: EntryKind::Field,
+            visibility: field.vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
         }
     }
-}
 
-fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
-    rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
-}
+    fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId))
+                          -> Entry<'tcx> {
+        let variant = self.tcx.lookup_adt_def(adt_def_id).struct_variant();
 
-fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                          rbml_w: &mut Encoder,
-                          field: ty::FieldDef<'tcx>,
-                          index: &mut CrateIndex<'a, 'tcx>) {
-    let nm = field.name;
-    let id = ecx.local_id(field.did);
-
-    let _task = index.record(field.did, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-    debug!("encode_field: encoding {} {}", nm, id);
-    encode_struct_field_family(rbml_w, field.vis);
-    encode_name(rbml_w, nm);
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, id);
-    encode_def_id_and_key(ecx, rbml_w, field.did);
-
-    let stab = ecx.tcx.lookup_stability(field.did);
-    let depr = ecx.tcx.lookup_deprecation(field.did);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    rbml_w.end_tag();
-}
+        let data = VariantData {
+            kind: variant.kind,
+            disr: variant.disr_val.to_u64_unchecked(),
+            struct_ctor: Some(def_id.index)
+        };
 
-fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                         rbml_w: &mut Encoder,
-                                         name: Name,
-                                         struct_def: &hir::VariantData,
-                                         index: &mut CrateIndex<'a, 'tcx>,
-                                         struct_id: NodeId) {
-    let ctor_id = struct_def.id();
-    let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
-
-    let _task = index.record(ctor_def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-    encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
-    encode_family(rbml_w, match *struct_def {
-        hir::VariantData::Struct(..) => 'S',
-        hir::VariantData::Tuple(..) => 's',
-        hir::VariantData::Unit(..) => 'u',
-    });
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
-    encode_name(rbml_w, name);
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id));
-
-    let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id));
-    let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id));
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    // indicate that this is a tuple struct ctor, because downstream users will normally want
-    // the tuple struct definition, but without this there is no way for them to tell that
-    // they actually have a ctor rather than a normal function
-    rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]);
-
-    rbml_w.end_tag();
-}
+        Entry {
+            kind: EntryKind::Struct(self.lazy(&data)),
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
+        }
+    }
 
-fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
-                             ecx: &EncodeContext<'a, 'tcx>,
-                             index: &mut CrateIndex<'a, 'tcx>,
-                             generics: &ty::Generics<'tcx>,
-                             predicates: &ty::GenericPredicates<'tcx>,
-                             tag: usize)
-{
-    rbml_w.start_tag(tag);
-
-    for param in &generics.types {
-        rbml_w.start_tag(tag_type_param_def);
-        tyencode::enc_type_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param);
-        rbml_w.mark_stable_position();
-        rbml_w.end_tag();
+    fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics<'tcx>> {
+        let tcx = self.tcx;
+        self.lazy(tcx.lookup_generics(def_id))
     }
 
-    // Region parameters
-    for param in &generics.regions {
-        rbml_w.start_tag(tag_region_param_def);
-        tyencode::enc_region_param_def(rbml_w.writer, &ecx.ty_str_ctxt(), param);
-        rbml_w.mark_stable_position();
-        rbml_w.end_tag();
+    fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
+        let tcx = self.tcx;
+        self.lazy(&tcx.lookup_predicates(def_id))
     }
 
-    encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
+    fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let tcx = self.tcx;
 
-    rbml_w.end_tag();
-}
+        let node_id = tcx.map.as_local_node_id(def_id).unwrap();
+        let ast_item = tcx.map.expect_trait_item(node_id);
+        let trait_item = tcx.impl_or_trait_item(def_id);
 
-fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
-                                             _ecx: &EncodeContext<'a,'tcx>,
-                                             index: &mut CrateIndex<'a, 'tcx>,
-                                             predicates: &ty::GenericPredicates<'tcx>)
-{
-    for (space, _, predicate) in predicates.predicates.iter_enumerated() {
-        let tag = match space {
-            subst::TypeSpace => tag_type_predicate,
-            subst::SelfSpace => tag_self_predicate,
-            subst::FnSpace => tag_fn_predicate
+        let container = |has_body| if has_body {
+            AssociatedContainer::TraitWithDefault
+        } else {
+            AssociatedContainer::TraitRequired
         };
 
-        rbml_w.wr_tagged_u32(tag,
-            index.add_xref(XRef::Predicate(predicate.clone())));
-    }
-}
-
-fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
-                              ecx: &EncodeContext<'a,'tcx>,
-                              index: &mut CrateIndex<'a, 'tcx>,
-                              predicates: &ty::GenericPredicates<'tcx>,
-                              tag: usize)
-{
-    rbml_w.start_tag(tag);
-    encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
-    rbml_w.end_tag();
-}
+        let kind = match trait_item {
+            ty::ConstTraitItem(ref associated_const) => {
+                EntryKind::AssociatedConst(container(associated_const.has_value))
+            }
+            ty::MethodTraitItem(ref method_ty) => {
+                let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
+                    FnData {
+                        constness: hir::Constness::NotConst,
+                        arg_names: self.encode_fn_arg_names(&sig.decl)
+                    }
+                } else {
+                    bug!()
+                };
+                let data = MethodData {
+                    fn_data: fn_data,
+                    container: container(method_ty.has_body),
+                    explicit_self: self.lazy(&method_ty.explicit_self)
+                };
+                EntryKind::Method(self.lazy(&data))
+            }
+            ty::TypeTraitItem(_) => {
+                EntryKind::AssociatedType(container(false))
+            }
+        };
 
-fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                     rbml_w: &mut Encoder,
-                                     index: &mut CrateIndex<'a, 'tcx>,
-                                     method_ty: &ty::Method<'tcx>) {
-    encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
-    encode_name(rbml_w, method_ty.name);
-    encode_generics(rbml_w, ecx, index,
-                    &method_ty.generics, &method_ty.predicates,
-                    tag_method_ty_generics);
-    encode_visibility(rbml_w, method_ty.vis);
-    encode_explicit_self(rbml_w, &method_ty.explicit_self);
-    match method_ty.explicit_self {
-        ty::ExplicitSelfCategory::Static => {
-            encode_family(rbml_w, STATIC_METHOD_FAMILY);
+        Entry {
+            kind: kind,
+            visibility: trait_item.vis().simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&ast_item.attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: match trait_item {
+                ty::ConstTraitItem(_) |
+                ty::MethodTraitItem(_) => {
+                    Some(self.encode_item_type(def_id))
+                }
+                ty::TypeTraitItem(ref associated_type) => {
+                    associated_type.ty.map(|ty| self.lazy(&ty))
+                }
+            },
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: if let ty::ConstTraitItem(_) = trait_item {
+                let trait_def_id = trait_item.container().id();
+                Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item)))
+            } else {
+                None
+            },
+            mir: self.encode_mir(def_id)
         }
-        _ => encode_family(rbml_w, METHOD_FAMILY)
     }
-}
 
-fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                              rbml_w: &mut Encoder,
-                                              index: &mut CrateIndex<'a, 'tcx>,
-                                              associated_const: &ty::AssociatedConst,
-                                              parent_id: NodeId,
-                                              impl_item_opt: Option<&hir::ImplItem>) {
-    debug!("encode_info_for_associated_const({:?},{:?})",
-           associated_const.def_id,
-           associated_const.name);
-
-    let _task = index.record(associated_const.def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-
-    encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
-    encode_name(rbml_w, associated_const.name);
-    encode_visibility(rbml_w, associated_const.vis);
-    encode_family(rbml_w, 'C');
-
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_item_sort(rbml_w, 'C');
-
-    encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                    ecx.local_id(associated_const.def_id));
-
-    let stab = ecx.tcx.lookup_stability(associated_const.def_id);
-    let depr = ecx.tcx.lookup_deprecation(associated_const.def_id);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    if let Some(ii) = impl_item_opt {
-        encode_attributes(rbml_w, &ii.attrs);
-        encode_defaultness(rbml_w, ii.defaultness);
-        encode_inlined_item(ecx,
-                            rbml_w,
-                            InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
-                                                     ii));
-        encode_mir(ecx, rbml_w, ii.id);
-    }
+    fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
+        let ast_item = self.tcx.map.expect_impl_item(node_id);
+        let impl_item = self.tcx.impl_or_trait_item(def_id);
+        let impl_def_id = impl_item.container().id();
 
-    rbml_w.end_tag();
-}
+        let container = match ast_item.defaultness {
+            hir::Defaultness::Default => AssociatedContainer::ImplDefault,
+            hir::Defaultness::Final => AssociatedContainer::ImplFinal
+        };
 
-fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                    rbml_w: &mut Encoder,
-                                    index: &mut CrateIndex<'a, 'tcx>,
-                                    m: &ty::Method<'tcx>,
-                                    is_default_impl: bool,
-                                    parent_id: NodeId,
-                                    impl_item_opt: Option<&hir::ImplItem>) {
-
-    debug!("encode_info_for_method: {:?} {:?}", m.def_id,
-           m.name);
-    let _task = index.record(m.def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-
-    encode_method_ty_fields(ecx, rbml_w, index, m);
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_item_sort(rbml_w, 'r');
-
-    let stab = ecx.tcx.lookup_stability(m.def_id);
-    let depr = ecx.tcx.lookup_deprecation(m.def_id);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    let m_node_id = ecx.local_id(m.def_id);
-    encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id);
-
-    if let Some(impl_item) = impl_item_opt {
-        if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
-            encode_attributes(rbml_w, &impl_item.attrs);
-            let scheme = ecx.tcx.lookup_item_type(m.def_id);
-            let any_types = !scheme.generics.types.is_empty();
-            let needs_inline = any_types || is_default_impl ||
-                               attr::requests_inline(&impl_item.attrs);
-            if needs_inline || sig.constness == hir::Constness::Const {
-                encode_inlined_item(ecx,
-                                    rbml_w,
-                                    InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
-                                                             impl_item));
-                encode_mir(ecx, rbml_w, impl_item.id);
+        let kind = match impl_item {
+            ty::ConstTraitItem(_) => {
+                EntryKind::AssociatedConst(container)
             }
-            encode_constness(rbml_w, sig.constness);
-            encode_defaultness(rbml_w, impl_item.defaultness);
-            encode_method_argument_names(rbml_w, &sig.decl);
-        }
-    }
-
-    rbml_w.end_tag();
-}
-
-fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                             rbml_w: &mut Encoder,
-                                             index: &mut CrateIndex<'a, 'tcx>,
-                                             associated_type: &ty::AssociatedType<'tcx>,
-                                             parent_id: NodeId,
-                                             impl_item_opt: Option<&hir::ImplItem>) {
-    debug!("encode_info_for_associated_type({:?},{:?})",
-           associated_type.def_id,
-           associated_type.name);
-
-    let _task = index.record(associated_type.def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-
-    encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
-    encode_name(rbml_w, associated_type.name);
-    encode_visibility(rbml_w, associated_type.vis);
-    encode_family(rbml_w, 'y');
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_item_sort(rbml_w, 't');
-
-    let stab = ecx.tcx.lookup_stability(associated_type.def_id);
-    let depr = ecx.tcx.lookup_deprecation(associated_type.def_id);
-    encode_stability(rbml_w, stab);
-    encode_deprecation(rbml_w, depr);
-
-    if let Some(ii) = impl_item_opt {
-        encode_attributes(rbml_w, &ii.attrs);
-        encode_defaultness(rbml_w, ii.defaultness);
-    } else {
-        encode_predicates(rbml_w, ecx, index,
-                          &ecx.tcx.lookup_predicates(associated_type.def_id),
-                          tag_item_generics);
-    }
-
-    if let Some(ty) = associated_type.ty {
-        encode_type(ecx, rbml_w, ty);
-    }
-
-    rbml_w.end_tag();
-}
+            ty::MethodTraitItem(ref method_ty) => {
+                let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+                    FnData {
+                        constness: sig.constness,
+                        arg_names: self.encode_fn_arg_names(&sig.decl)
+                    }
+                } else {
+                    bug!()
+                };
+                let data = MethodData {
+                    fn_data: fn_data,
+                    container: container,
+                    explicit_self: self.lazy(&method_ty.explicit_self)
+                };
+                EntryKind::Method(self.lazy(&data))
+            }
+            ty::TypeTraitItem(_) => {
+                EntryKind::AssociatedType(container)
+            }
+        };
 
-fn encode_method_argument_names(rbml_w: &mut Encoder,
-                                decl: &hir::FnDecl) {
-    rbml_w.start_tag(tag_method_argument_names);
-    for arg in &decl.inputs {
-        let tag = tag_method_argument_name;
-        if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
-            let name = path1.node.as_str();
-            rbml_w.wr_tagged_bytes(tag, name.as_bytes());
+        let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item {
+            (true, true)
+        } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+            let generics = self.tcx.lookup_generics(def_id);
+            let types = generics.parent_types as usize + generics.types.len();
+            let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
+            let is_const_fn = sig.constness == hir::Constness::Const;
+            (is_const_fn, needs_inline || is_const_fn)
         } else {
-            rbml_w.wr_tagged_bytes(tag, &[]);
+            (false, false)
+        };
+
+        Entry {
+            kind: kind,
+            visibility: impl_item.vis().simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&ast_item.attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: match impl_item {
+                ty::ConstTraitItem(_) |
+                ty::MethodTraitItem(_) => {
+                    Some(self.encode_item_type(def_id))
+                }
+                ty::TypeTraitItem(ref associated_type) => {
+                    associated_type.ty.map(|ty| self.lazy(&ty))
+                }
+            },
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: if ast {
+                Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item)))
+            } else {
+                None
+            },
+            mir: if mir {
+                self.encode_mir(def_id)
+            } else {
+                None
+            }
         }
     }
-    rbml_w.end_tag();
-}
 
-fn encode_repr_attrs(rbml_w: &mut Encoder,
-                     ecx: &EncodeContext,
-                     attrs: &[ast::Attribute]) {
-    let mut repr_attrs = Vec::new();
-    for attr in attrs {
-        repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(),
-                                                attr));
+    fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
+        self.lazy_seq(decl.inputs.iter().map(|arg| {
+            if let PatKind::Binding(_, ref path1, _) = arg.pat.node {
+                path1.node
+            } else {
+                syntax::parse::token::intern("")
+            }
+        }))
     }
-    rbml_w.start_tag(tag_items_data_item_repr);
-    repr_attrs.encode(rbml_w);
-    rbml_w.end_tag();
-}
 
-fn encode_mir(ecx: &EncodeContext, rbml_w: &mut Encoder, node_id: NodeId) {
-    let def_id = ecx.tcx.map.local_def_id(node_id);
-    if let Some(mir) = ecx.mir_map.map.get(&def_id) {
-        rbml_w.start_tag(tag_mir as usize);
-        rbml_w.emit_opaque(|opaque_encoder| {
-            tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| {
-                Encodable::encode(mir, opaque_encoder)
-            })
-        }).unwrap();
-        rbml_w.end_tag();
+    fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::repr::Mir<'tcx>>> {
+        self.mir_map.map.get(&def_id).map(|mir| self.lazy(mir))
     }
-}
 
-const FN_FAMILY: char = 'f';
-const STATIC_METHOD_FAMILY: char = 'F';
-const METHOD_FAMILY: char = 'h';
-
-// Encodes the inherent implementations of a structure, enumeration, or trait.
-fn encode_inherent_implementations(ecx: &EncodeContext,
-                                   rbml_w: &mut Encoder,
-                                   def_id: DefId) {
-    match ecx.tcx.inherent_impls.borrow().get(&def_id) {
-        None => {}
-        Some(implementations) => {
-            for &impl_def_id in implementations.iter() {
-                rbml_w.start_tag(tag_items_data_item_inherent_impl);
-                encode_def_id(rbml_w, impl_def_id);
-                rbml_w.end_tag();
+    // Encodes the inherent implementations of a structure, enumeration, or trait.
+    fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
+        match self.tcx.inherent_impls.borrow().get(&def_id) {
+            None => LazySeq::empty(),
+            Some(implementations) => {
+                self.lazy_seq(implementations.iter().map(|&def_id| {
+                    assert!(def_id.is_local());
+                    def_id.index
+                }))
             }
         }
     }
-}
 
-fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) {
-    stab_opt.map(|stab| {
-        rbml_w.start_tag(tag_items_data_item_stability);
-        stab.encode(rbml_w).unwrap();
-        rbml_w.end_tag();
-    });
-}
+    fn encode_stability(&mut self, def_id: DefId) -> Option<Lazy<attr::Stability>> {
+        self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab))
+    }
 
-fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option<attr::Deprecation>) {
-    depr_opt.map(|depr| {
-        rbml_w.start_tag(tag_items_data_item_deprecation);
-        depr.encode(rbml_w).unwrap();
-        rbml_w.end_tag();
-    });
-}
+    fn encode_deprecation(&mut self, def_id: DefId) -> Option<Lazy<attr::Deprecation>> {
+        self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr))
+    }
 
-fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option<DefId>) {
-    parent_opt.map(|parent| {
-        rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent));
-    });
-}
+    fn encode_info_for_item(&mut self,
+                            (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> {
+        let tcx = self.tcx;
+
+        debug!("encoding info for item at {}",
+               tcx.sess.codemap().span_to_string(item.span));
+
+        let kind = match item.node {
+            hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
+            hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
+            hir::ItemConst(..) => EntryKind::Const,
+            hir::ItemFn(ref decl, _, constness, ..) => {
+                let data = FnData {
+                    constness: constness,
+                    arg_names: self.encode_fn_arg_names(&decl)
+                };
 
-fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                          rbml_w: &mut Encoder,
-                          xrefs: FnvHashMap<XRef<'tcx>, u32>)
-{
-    let mut xref_positions = vec![0; xrefs.len()];
-    rbml_w.start_tag(tag_xref_data);
-    for (xref, id) in xrefs.into_iter() {
-        xref_positions[id as usize] = rbml_w.mark_stable_position() as u32;
-        match xref {
-            XRef::Predicate(p) => {
-                tyencode::enc_predicate(rbml_w.writer, &ecx.ty_str_ctxt(), &p)
+                EntryKind::Fn(self.lazy(&data))
             }
-        }
-    }
-    rbml_w.mark_stable_position();
-    rbml_w.end_tag();
-
-    rbml_w.start_tag(tag_xref_index);
-    index::write_dense_index(xref_positions, rbml_w.writer);
-    rbml_w.end_tag();
-}
+            hir::ItemMod(ref m) => {
+                return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis)));
+            }
+            hir::ItemForeignMod(_) => EntryKind::ForeignMod,
+            hir::ItemTy(..) => EntryKind::Type,
+            hir::ItemEnum(..) => EntryKind::Enum,
+            hir::ItemStruct(ref struct_def, _) => {
+                let variant = tcx.lookup_adt_def(def_id).struct_variant();
+
+                /* Encode def_ids for each field and method
+                for methods, write all the stuff get_trait_method
+                needs to know*/
+                let struct_ctor = if !struct_def.is_struct() {
+                    Some(tcx.map.local_def_id(struct_def.id()).index)
+                } else {
+                    None
+                };
+                EntryKind::Struct(self.lazy(&VariantData {
+                    kind: variant.kind,
+                    disr: variant.disr_val.to_u64_unchecked(),
+                    struct_ctor: struct_ctor
+                }))
+            }
+            hir::ItemUnion(..) => {
+                let variant = tcx.lookup_adt_def(def_id).struct_variant();
+
+                EntryKind::Union(self.lazy(&VariantData {
+                    kind: variant.kind,
+                    disr: variant.disr_val.to_u64_unchecked(),
+                    struct_ctor: None
+                }))
+            }
+            hir::ItemDefaultImpl(..) => {
+                let data = ImplData {
+                    polarity: hir::ImplPolarity::Positive,
+                    parent_impl: None,
+                    coerce_unsized_kind: None,
+                    trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref))
+                };
 
-fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                  rbml_w: &mut Encoder,
-                                  item: &hir::Item,
-                                  index: &mut CrateIndex<'a, 'tcx>) {
-    let tcx = ecx.tcx;
-
-    debug!("encoding info for item at {}",
-           tcx.sess.codemap().span_to_string(item.span));
-
-    let vis = &item.vis;
-    let def_id = ecx.tcx.map.local_def_id(item.id);
-
-    let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
-        (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
-         tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
-    });
-
-    match item.node {
-      hir::ItemStatic(_, m, _) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        if m == hir::MutMutable {
-            encode_family(rbml_w, 'b');
-        } else {
-            encode_family(rbml_w, 'c');
-        }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_attributes(rbml_w, &item.attrs);
-        rbml_w.end_tag();
-      }
-      hir::ItemConst(_, _) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'C');
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-        encode_mir(ecx, rbml_w, item.id);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-      }
-      hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, FN_FAMILY);
-        let tps_len = generics.ty_params.len();
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
-        if needs_inline || constness == hir::Constness::Const {
-            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-            encode_mir(ecx, rbml_w, item.id);
-        }
-        encode_constness(rbml_w, constness);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_method_argument_names(rbml_w, &decl);
-        rbml_w.end_tag();
-      }
-      hir::ItemMod(ref m) => {
-        let _task = index.record(def_id, rbml_w);
-        encode_info_for_mod(ecx,
-                            rbml_w,
-                            m,
-                            &item.attrs,
-                            item.id,
-                            item.name,
-                            &item.vis);
-      }
-      hir::ItemForeignMod(ref fm) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'n');
-        encode_name(rbml_w, item.name);
-
-        // Encode all the items in this module.
-        for foreign_item in &fm.items {
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
-        }
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-      }
-      hir::ItemTy(..) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'y');
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-      }
-      hir::ItemEnum(ref enum_definition, _) => {
-        let _task = index.record(def_id, rbml_w);
-
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 't');
-        encode_item_variances(rbml_w, ecx, item.id);
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_repr_attrs(rbml_w, ecx, &item.attrs);
-        for v in &enum_definition.variants {
-            encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
-        }
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-        encode_mir(ecx, rbml_w, item.id);
-
-        // Encode inherent implementations for this enumeration.
-        encode_inherent_implementations(ecx, rbml_w, def_id);
-
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-
-        encode_enum_variant_info(ecx,
-                                 rbml_w,
-                                 def_id,
-                                 vis,
-                                 index);
-      }
-      hir::ItemStruct(ref struct_def, _) => {
-        /* Index the class*/
-        let _task = index.record(def_id, rbml_w);
-
-        let def = ecx.tcx.lookup_adt_def(def_id);
-        let variant = def.struct_variant();
-
-        /* Now, make an item for the class itself */
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, match *struct_def {
-            hir::VariantData::Struct(..) => 'S',
-            hir::VariantData::Tuple(..) => 's',
-            hir::VariantData::Unit(..) => 'u',
-        });
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-
-        encode_item_variances(rbml_w, ecx, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_visibility(rbml_w, vis);
-        encode_repr_attrs(rbml_w, ecx, &item.attrs);
-
-        /* Encode def_ids for each field and method
-         for methods, write all the stuff get_trait_method
-        needs to know*/
-        encode_struct_fields(rbml_w, variant);
-
-        encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(def_id, item));
-        encode_mir(ecx, rbml_w, item.id);
-
-        // Encode inherent implementations for this structure.
-        encode_inherent_implementations(ecx, rbml_w, def_id);
-
-        if !struct_def.is_struct() {
-            let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
-            rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
-                                 def_to_u64(ctor_did));
-        }
+                EntryKind::DefaultImpl(self.lazy(&data))
+            }
+            hir::ItemImpl(_, polarity, ..) => {
+                let trait_ref = tcx.impl_trait_ref(def_id);
+                let parent = if let Some(trait_ref) = trait_ref {
+                    let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+                    trait_def.ancestors(def_id).skip(1).next().and_then(|node| {
+                        match node {
+                            specialization_graph::Node::Impl(parent) => Some(parent),
+                            _ => None,
+                        }
+                    })
+                } else {
+                    None
+                };
 
-        rbml_w.end_tag();
+                let data = ImplData {
+                    polarity: polarity,
+                    parent_impl: parent,
+                    coerce_unsized_kind: tcx.custom_coerce_unsized_kinds.borrow()
+                                            .get(&def_id).cloned(),
+                    trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref))
+                };
 
-        for field in &variant.fields {
-            encode_field(ecx, rbml_w, field, index);
-        }
+                EntryKind::Impl(self.lazy(&data))
+            }
+            hir::ItemTrait(..) => {
+                let trait_def = tcx.lookup_trait_def(def_id);
+                let data = TraitData {
+                    unsafety: trait_def.unsafety,
+                    paren_sugar: trait_def.paren_sugar,
+                    has_default_impl: tcx.trait_has_default_impl(def_id),
+                    trait_ref: self.lazy(&trait_def.trait_ref),
+                    super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id))
+                };
 
-        // If this is a tuple-like struct, encode the type of the constructor.
-        if !struct_def.is_struct() {
-            encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def, index, item.id);
-        }
-      }
-      hir::ItemDefaultImpl(unsafety, _) => {
-          let _task = index.record(def_id, rbml_w);
-          rbml_w.start_tag(tag_items_data_item);
-          encode_def_id_and_key(ecx, rbml_w, def_id);
-          encode_family(rbml_w, 'd');
-          encode_name(rbml_w, item.name);
-          encode_unsafety(rbml_w, unsafety);
-
-          let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
-          encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
-          rbml_w.end_tag();
-      }
-      hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
-        let _task = index.record(def_id, rbml_w);
-
-        // We need to encode information about the default methods we
-        // have inherited, so we drive this based on the impl structure.
-        let impl_items = tcx.impl_items.borrow();
-        let items = impl_items.get(&def_id).unwrap();
-
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'i');
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_unsafety(rbml_w, unsafety);
-        encode_polarity(rbml_w, polarity);
-
-        match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) {
-            Some(&kind) => {
-                rbml_w.start_tag(tag_impl_coerce_unsized_kind);
-                kind.encode(rbml_w);
-                rbml_w.end_tag();
+                EntryKind::Trait(self.lazy(&data))
             }
-            None => {}
-        }
+            hir::ItemExternCrate(_) | hir::ItemUse(_) => {
+                bug!("cannot encode info for item {:?}", item)
+            }
+        };
 
-        for &item_def_id in items {
-            rbml_w.start_tag(tag_item_impl_item);
-            match item_def_id {
-                ty::ConstTraitItemId(item_def_id) => {
-                    encode_def_id(rbml_w, item_def_id);
-                    encode_item_sort(rbml_w, 'C');
+        Entry {
+            kind: kind,
+            visibility: item.vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&item.attrs),
+            children: match item.node {
+                hir::ItemForeignMod(ref fm) => {
+                    self.lazy_seq(fm.items.iter().map(|foreign_item| {
+                        tcx.map.local_def_id(foreign_item.id).index
+                    }))
                 }
-                ty::MethodTraitItemId(item_def_id) => {
-                    encode_def_id(rbml_w, item_def_id);
-                    encode_item_sort(rbml_w, 'r');
+                hir::ItemEnum(..) => {
+                    let def = self.tcx.lookup_adt_def(def_id);
+                    self.lazy_seq(def.variants.iter().map(|v| {
+                        assert!(v.did.is_local());
+                        v.did.index
+                    }))
                 }
-                ty::TypeTraitItemId(item_def_id) => {
-                    encode_def_id(rbml_w, item_def_id);
-                    encode_item_sort(rbml_w, 't');
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) => {
+                    let def = self.tcx.lookup_adt_def(def_id);
+                    self.lazy_seq(def.struct_variant().fields.iter().map(|f| {
+                        assert!(f.did.is_local());
+                        f.did.index
+                    }))
                 }
-            }
-            rbml_w.end_tag();
-        }
-        let did = ecx.tcx.map.local_def_id(item.id);
-        if let Some(trait_ref) = tcx.impl_trait_ref(did) {
-            encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
-
-            let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
-            let parent = trait_def.ancestors(did)
-                .skip(1)
-                .next()
-                .and_then(|node| match node {
-                    specialization_graph::Node::Impl(parent) => Some(parent),
-                    _ => None,
-                });
-            encode_parent_impl(rbml_w, parent);
-        }
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        rbml_w.end_tag();
-
-        // Iterate down the trait items, emitting them. We rely on the
-        // assumption that all of the actually implemented trait items
-        // appear first in the impl structure, in the same order they do
-        // in the ast. This is a little sketchy.
-        let num_implemented_methods = ast_items.len();
-        for (i, &trait_item_def_id) in items.iter().enumerate() {
-            let ast_item = if i < num_implemented_methods {
-                Some(&ast_items[i])
-            } else {
-                None
-            };
-
-            match tcx.impl_or_trait_item(trait_item_def_id.def_id()) {
-                ty::ConstTraitItem(ref associated_const) => {
-                    encode_info_for_associated_const(ecx,
-                                                     rbml_w,
-                                                     index,
-                                                     &associated_const,
-                                                     item.id,
-                                                     ast_item)
+                hir::ItemImpl(..) |
+                hir::ItemTrait(..) => {
+                    self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| {
+                        assert!(def_id.is_local());
+                        def_id.index
+                    }))
                 }
-                ty::MethodTraitItem(ref method_type) => {
-                    encode_info_for_method(ecx,
-                                           rbml_w,
-                                           index,
-                                           &method_type,
-                                           false,
-                                           item.id,
-                                           ast_item)
+                _ => LazySeq::empty()
+            },
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: match item.node {
+                hir::ItemStatic(..) |
+                hir::ItemConst(..) |
+                hir::ItemFn(..) |
+                hir::ItemTy(..) |
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemImpl(..) => {
+                    Some(self.encode_item_type(def_id))
                 }
-                ty::TypeTraitItem(ref associated_type) => {
-                    encode_info_for_associated_type(ecx,
-                                                    rbml_w,
-                                                    index,
-                                                    &associated_type,
-                                                    item.id,
-                                                    ast_item)
+                _ => None
+            },
+            inherent_impls: self.encode_inherent_implementations(def_id),
+            variances: match item.node {
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemTrait(..) => {
+                    self.encode_item_variances(def_id)
                 }
-            }
-        }
-      }
-      hir::ItemTrait(_, _, _, ref ms) => {
-        let _task = index.record(def_id, rbml_w);
-        rbml_w.start_tag(tag_items_data_item);
-        encode_def_id_and_key(ecx, rbml_w, def_id);
-        encode_family(rbml_w, 'I');
-        encode_item_variances(rbml_w, ecx, item.id);
-        let trait_def = tcx.lookup_trait_def(def_id);
-        let trait_predicates = tcx.lookup_predicates(def_id);
-        encode_unsafety(rbml_w, trait_def.unsafety);
-        encode_paren_sugar(rbml_w, trait_def.paren_sugar);
-        encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id));
-        encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
-        encode_generics(rbml_w, ecx, index,
-                        &trait_def.generics, &trait_predicates,
-                        tag_item_generics);
-        encode_predicates(rbml_w, ecx, index,
-                          &tcx.lookup_super_predicates(def_id),
-                          tag_item_super_predicates);
-        encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
-        encode_name(rbml_w, item.name);
-        encode_attributes(rbml_w, &item.attrs);
-        encode_visibility(rbml_w, vis);
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        for &method_def_id in tcx.trait_item_def_ids(def_id).iter() {
-            rbml_w.start_tag(tag_item_trait_item);
-            match method_def_id {
-                ty::ConstTraitItemId(const_def_id) => {
-                    encode_def_id(rbml_w, const_def_id);
-                    encode_item_sort(rbml_w, 'C');
+                _ => LazySeq::empty()
+            },
+            generics: match item.node {
+                hir::ItemStatic(..) |
+                hir::ItemConst(..) |
+                hir::ItemFn(..) |
+                hir::ItemTy(..) |
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemImpl(..) |
+                hir::ItemTrait(..) => {
+                    Some(self.encode_generics(def_id))
+                }
+                _ => None
+            },
+            predicates: match item.node {
+                hir::ItemStatic(..) |
+                hir::ItemConst(..) |
+                hir::ItemFn(..) |
+                hir::ItemTy(..) |
+                hir::ItemEnum(..) |
+                hir::ItemStruct(..) |
+                hir::ItemUnion(..) |
+                hir::ItemImpl(..) |
+                hir::ItemTrait(..) => {
+                    Some(self.encode_predicates(def_id))
+                }
+                _ => None
+            },
+
+            ast: match item.node {
+                hir::ItemConst(..) |
+                hir::ItemFn(_, _, hir::Constness::Const, ..) => {
+                    Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item)))
                 }
-                ty::MethodTraitItemId(method_def_id) => {
-                    encode_def_id(rbml_w, method_def_id);
-                    encode_item_sort(rbml_w, 'r');
+                _ => None
+            },
+            mir: match item.node {
+                hir::ItemConst(..) => {
+                    self.encode_mir(def_id)
                 }
-                ty::TypeTraitItemId(type_def_id) => {
-                    encode_def_id(rbml_w, type_def_id);
-                    encode_item_sort(rbml_w, 't');
+                hir::ItemFn(_, _, constness, _, ref generics, _) => {
+                    let tps_len = generics.ty_params.len();
+                    let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
+                    if needs_inline || constness == hir::Constness::Const {
+                        self.encode_mir(def_id)
+                    } else {
+                        None
+                    }
                 }
+                _ => None
             }
-            rbml_w.end_tag();
-
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(method_def_id.def_id()));
         }
+    }
+}
 
-        // Encode inherent implementations for this trait.
-        encode_inherent_implementations(ecx, rbml_w, def_id);
-
-        rbml_w.end_tag();
-
-        // Now output the trait item info for each trait item.
-        let r = tcx.trait_item_def_ids(def_id);
-        for (i, &item_def_id) in r.iter().enumerate() {
-            assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
-
-            let _task = index.record(item_def_id.def_id(), rbml_w);
-            rbml_w.start_tag(tag_items_data_item);
-
-            encode_parent_item(rbml_w, def_id);
-
-            let stab = tcx.lookup_stability(item_def_id.def_id());
-            let depr = tcx.lookup_deprecation(item_def_id.def_id());
-            encode_stability(rbml_w, stab);
-            encode_deprecation(rbml_w, depr);
-
-            let trait_item_type =
-                tcx.impl_or_trait_item(item_def_id.def_id());
-            let is_nonstatic_method;
-            match trait_item_type {
-                ty::ConstTraitItem(associated_const) => {
-                    encode_name(rbml_w, associated_const.name);
-                    encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
-                    encode_visibility(rbml_w, associated_const.vis);
-
-                    encode_family(rbml_w, 'C');
-
-                    encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                    ecx.local_id(associated_const.def_id));
-
-                    is_nonstatic_method = false;
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+    /// In some cases, along with the item itself, we also
+    /// encode some sub-items. Usually we want some info from the item
+    /// so it's easier to do that here then to wait until we would encounter
+    /// normally in the visitor walk.
+    fn encode_addl_info_for_item(&mut self,
+                                 item: &hir::Item) {
+        let def_id = self.tcx.map.local_def_id(item.id);
+        match item.node {
+            hir::ItemStatic(..) |
+            hir::ItemConst(..) |
+            hir::ItemFn(..) |
+            hir::ItemMod(..) |
+            hir::ItemForeignMod(..) |
+            hir::ItemExternCrate(..) |
+            hir::ItemUse(..) |
+            hir::ItemDefaultImpl(..) |
+            hir::ItemTy(..) => {
+                // no sub-item recording needed in these cases
+            }
+            hir::ItemEnum(..) => {
+                self.encode_fields(def_id);
+
+                let def = self.tcx.lookup_adt_def(def_id);
+                for (i, variant) in def.variants.iter().enumerate() {
+                    self.record(variant.did,
+                                EncodeContext::encode_enum_variant_info,
+                                (def_id, Untracked(i)));
                 }
-                ty::MethodTraitItem(method_ty) => {
-                    let method_def_id = item_def_id.def_id();
-
-                    encode_method_ty_fields(ecx, rbml_w, index, &method_ty);
+            }
+            hir::ItemStruct(ref struct_def, _) => {
+                self.encode_fields(def_id);
 
-                    match method_ty.explicit_self {
-                        ty::ExplicitSelfCategory::Static => {
-                            encode_family(rbml_w,
-                                          STATIC_METHOD_FAMILY);
-                        }
-                        _ => {
-                            encode_family(rbml_w,
-                                          METHOD_FAMILY);
-                        }
+                // If this is a tuple-like struct, encode the type of the constructor.
+                match self.tcx.lookup_adt_def(def_id).struct_variant().kind {
+                    ty::VariantKind::Struct => {
+                        // no value for structs like struct Foo { ... }
                     }
-                    encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                    ecx.local_id(method_def_id));
-
-                    is_nonstatic_method = method_ty.explicit_self !=
-                        ty::ExplicitSelfCategory::Static;
-                }
-                ty::TypeTraitItem(associated_type) => {
-                    encode_name(rbml_w, associated_type.name);
-                    encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
-                    encode_item_sort(rbml_w, 't');
-                    encode_family(rbml_w, 'y');
-
-                    if let Some(ty) = associated_type.ty {
-                        encode_type(ecx, rbml_w, ty);
+                    ty::VariantKind::Tuple | ty::VariantKind::Unit => {
+                        // there is a value for structs like `struct
+                        // Foo()` and `struct Foo`
+                        let ctor_def_id = self.tcx.map.local_def_id(struct_def.id());
+                        self.record(ctor_def_id,
+                                    EncodeContext::encode_struct_ctor,
+                                    (def_id, ctor_def_id));
                     }
-
-                    is_nonstatic_method = false;
                 }
             }
-
-            let trait_item = &ms[i];
-            encode_attributes(rbml_w, &trait_item.attrs);
-            match trait_item.node {
-                hir::ConstTraitItem(_, ref default) => {
-                    if default.is_some() {
-                        encode_item_sort(rbml_w, 'C');
-                    } else {
-                        encode_item_sort(rbml_w, 'c');
-                    }
-
-                    encode_inlined_item(ecx, rbml_w,
-                                        InlinedItemRef::TraitItem(def_id, trait_item));
-                    encode_mir(ecx, rbml_w, trait_item.id);
+            hir::ItemUnion(..) => {
+                self.encode_fields(def_id);
+            }
+            hir::ItemImpl(..) => {
+                for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+                    self.record(trait_item_def_id,
+                                EncodeContext::encode_info_for_impl_item,
+                                trait_item_def_id);
                 }
-                hir::MethodTraitItem(ref sig, ref body) => {
-                    // If this is a static method, we've already
-                    // encoded this.
-                    if is_nonstatic_method {
-                        // FIXME: I feel like there is something funny
-                        // going on.
-                        encode_bounds_and_type_for_item(rbml_w, ecx, index,
-                                                        ecx.local_id(item_def_id.def_id()));
-                    }
-
-                    if body.is_some() {
-                        encode_item_sort(rbml_w, 'p');
-                        encode_inlined_item(ecx, rbml_w,
-                                            InlinedItemRef::TraitItem(def_id, trait_item));
-                        encode_mir(ecx, rbml_w, trait_item.id);
-                    } else {
-                        encode_item_sort(rbml_w, 'r');
-                    }
-                    encode_method_argument_names(rbml_w, &sig.decl);
+            }
+            hir::ItemTrait(..) => {
+                for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] {
+                    self.record(item_def_id,
+                                EncodeContext::encode_info_for_trait_item,
+                                item_def_id);
                 }
-
-                hir::TypeTraitItem(..) => {}
             }
-
-            rbml_w.end_tag();
         }
-      }
-      hir::ItemExternCrate(_) | hir::ItemUse(_) => {
-        // these are encoded separately
-      }
     }
 }
 
-fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                          rbml_w: &mut Encoder,
-                                          nitem: &hir::ForeignItem,
-                                          index: &mut CrateIndex<'a, 'tcx>) {
-    debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
-    let def_id = ecx.tcx.map.local_def_id(nitem.id);
-    let abi = ecx.tcx.map.get_foreign_abi(nitem.id);
-
-    let _task = index.record(def_id, rbml_w);
-    rbml_w.start_tag(tag_items_data_item);
-    encode_def_id_and_key(ecx, rbml_w, def_id);
-    let parent_id = ecx.tcx.map.get_parent(nitem.id);
-    encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
-    encode_visibility(rbml_w, &nitem.vis);
-    match nitem.node {
-      hir::ForeignItemFn(ref fndecl, _) => {
-        encode_family(rbml_w, FN_FAMILY);
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
-        encode_name(rbml_w, nitem.name);
-        if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
-            encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(def_id, nitem));
-            encode_mir(ecx, rbml_w, nitem.id);
-        }
-        encode_attributes(rbml_w, &nitem.attrs);
-        let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
-        let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_method_argument_names(rbml_w, &fndecl);
-      }
-      hir::ForeignItemStatic(_, mutbl) => {
-        if mutbl {
-            encode_family(rbml_w, 'b');
-        } else {
-            encode_family(rbml_w, 'c');
-        }
-        encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
-        encode_attributes(rbml_w, &nitem.attrs);
-        let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id));
-        let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id));
-        encode_stability(rbml_w, stab);
-        encode_deprecation(rbml_w, depr);
-        encode_name(rbml_w, nitem.name);
-      }
-    }
-    rbml_w.end_tag();
-}
-
-fn my_visit_expr(expr: &hir::Expr,
-                 rbml_w: &mut Encoder,
-                 ecx: &EncodeContext,
-                 index: &mut CrateIndex) {
-    match expr.node {
-        hir::ExprClosure(..) => {
-            let def_id = ecx.tcx.map.local_def_id(expr.id);
-
-            let _task = index.record(def_id, rbml_w);
-
-            rbml_w.start_tag(tag_items_data_item);
-            encode_def_id_and_key(ecx, rbml_w, def_id);
-            encode_name(rbml_w, syntax::parse::token::intern("<closure>"));
-
-            rbml_w.start_tag(tag_items_closure_ty);
-            write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]);
-            rbml_w.end_tag();
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_info_for_foreign_item(&mut self,
+                                    (def_id, nitem): (DefId, &hir::ForeignItem))
+                                    -> Entry<'tcx> {
+        let tcx = self.tcx;
 
-            rbml_w.start_tag(tag_items_closure_kind);
-            ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
-            rbml_w.end_tag();
+        debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
 
-            assert!(ecx.mir_map.map.contains_key(&def_id));
-            encode_mir(ecx, rbml_w, expr.id);
+        let kind = match nitem.node {
+            hir::ForeignItemFn(ref fndecl, _) => {
+                let data = FnData {
+                    constness: hir::Constness::NotConst,
+                    arg_names: self.encode_fn_arg_names(&fndecl)
+                };
+                EntryKind::ForeignFn(self.lazy(&data))
+            }
+            hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic,
+            hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic
+        };
 
-            rbml_w.end_tag();
+        Entry {
+            kind: kind,
+            visibility: nitem.vis.simplify(),
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&nitem.attrs),
+            children: LazySeq::empty(),
+            stability: self.encode_stability(def_id),
+            deprecation: self.encode_deprecation(def_id),
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
         }
-        _ => { }
     }
 }
 
-struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
-    rbml_w_for_visit_item: &'a mut Encoder<'b>,
-    ecx: &'a EncodeContext<'c, 'tcx>,
-    index: &'a mut CrateIndex<'c, 'tcx>,
+struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> {
+    index: IndexBuilder<'a, 'b, 'tcx>,
 }
 
-impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
+impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         intravisit::walk_expr(self, ex);
-        my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index);
+        self.index.encode_info_for_expr(ex);
     }
-    fn visit_item(&mut self, i: &'tcx hir::Item) {
-        intravisit::walk_item(self, i);
-        encode_info_for_item(self.ecx, self.rbml_w_for_visit_item, i, self.index);
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        intravisit::walk_item(self, item);
+        let def_id = self.index.tcx.map.local_def_id(item.id);
+        match item.node {
+            hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these
+            _ => self.index.record(def_id,
+                                   EncodeContext::encode_info_for_item,
+                                   (def_id, item)),
+        }
+        self.index.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) {
         intravisit::walk_foreign_item(self, ni);
-        encode_info_for_foreign_item(self.ecx, self.rbml_w_for_visit_item, ni, self.index);
+        let def_id = self.index.tcx.map.local_def_id(ni.id);
+        self.index.record(def_id,
+                          EncodeContext::encode_info_for_foreign_item,
+                          (def_id, ni));
     }
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         intravisit::walk_ty(self, ty);
-
-        if let hir::TyImplTrait(_) = ty.node {
-            let rbml_w = &mut *self.rbml_w_for_visit_item;
-            let def_id = self.ecx.tcx.map.local_def_id(ty.id);
-            let _task = self.index.record(def_id, rbml_w);
-            rbml_w.start_tag(tag_items_data_item);
-            encode_def_id_and_key(self.ecx, rbml_w, def_id);
-            encode_family(rbml_w, 'y');
-            encode_bounds_and_type_for_item(rbml_w, self.ecx, self.index, ty.id);
-            rbml_w.end_tag();
-        }
+        self.index.encode_info_for_ty(ty);
     }
 }
 
-fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
-                                   rbml_w: &mut Encoder)
-                                   -> CrateIndex<'a, 'tcx> {
-    let krate = ecx.tcx.map.krate();
-
-    let mut index = CrateIndex {
-        dep_graph: &ecx.tcx.dep_graph,
-        items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
-        xrefs: FnvHashMap()
-    };
-    rbml_w.start_tag(tag_items_data);
-
-    {
-        let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
-        encode_info_for_mod(ecx,
-                            rbml_w,
-                            &krate.module,
-                            &[],
-                            CRATE_NODE_ID,
-                            syntax::parse::token::intern(&ecx.link_meta.crate_name),
-                            &hir::Public);
-    }
-
-    krate.visit_all_items(&mut EncodeVisitor {
-        index: &mut index,
-        ecx: ecx,
-        rbml_w_for_visit_item: &mut *rbml_w,
-    });
-
-    rbml_w.end_tag();
-    index
-}
-
-fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
-    rbml_w.start_tag(tag_index);
-    index.write_index(rbml_w.writer);
-    rbml_w.end_tag();
-}
-
-fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) {
-    if mi.is_word() {
-        let name = mi.name();
-        rbml_w.start_tag(tag_meta_item_word);
-        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
-        rbml_w.end_tag();
-    } else if mi.is_value_str() {
-        let name = mi.name();
-        /* FIXME (#623): support other literal kinds */
-        let value = mi.value_str().unwrap();
-        rbml_w.start_tag(tag_meta_item_name_value);
-        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
-        rbml_w.wr_tagged_str(tag_meta_item_value, &value);
-        rbml_w.end_tag();
-    } else { // it must be a list
-        let name = mi.name();
-        let items = mi.meta_item_list().unwrap();
-        rbml_w.start_tag(tag_meta_item_list);
-        rbml_w.wr_tagged_str(tag_meta_item_name, &name);
-        for inner_item in items {
-            encode_meta_item(rbml_w, &inner_item);
+impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+    fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
+        if let hir::TyImplTrait(_) = ty.node {
+            let def_id = self.tcx.map.local_def_id(ty.id);
+            self.record(def_id,
+                        EncodeContext::encode_info_for_anon_ty,
+                        def_id);
         }
-        rbml_w.end_tag();
     }
-}
 
-fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) {
-    rbml_w.start_tag(tag_attributes);
-    for attr in attrs {
-        rbml_w.start_tag(tag_attribute);
-        rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8);
-        encode_meta_item(rbml_w, attr.meta());
-        rbml_w.end_tag();
+    fn encode_info_for_expr(&mut self, expr: &hir::Expr) {
+        match expr.node {
+            hir::ExprClosure(..) => {
+                let def_id = self.tcx.map.local_def_id(expr.id);
+                self.record(def_id,
+                            EncodeContext::encode_info_for_closure,
+                            def_id);
+            }
+            _ => { }
+        }
     }
-    rbml_w.end_tag();
-}
-
-fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) {
-    let byte: u8 = match unsafety {
-        hir::Unsafety::Normal => 0,
-        hir::Unsafety::Unsafe => 1,
-    };
-    rbml_w.wr_tagged_u8(tag_unsafety, byte);
-}
-
-fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) {
-    let byte: u8 = if paren_sugar {1} else {0};
-    rbml_w.wr_tagged_u8(tag_paren_sugar, byte);
 }
 
-fn encode_defaulted(rbml_w: &mut Encoder, is_defaulted: bool) {
-    let byte: u8 = if is_defaulted {1} else {0};
-    rbml_w.wr_tagged_u8(tag_defaulted_trait, byte);
-}
-
-fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) {
-    rbml_w.start_tag(tag_associated_type_names);
-    for &name in names {
-        rbml_w.wr_tagged_str(tag_associated_type_name, &name.as_str());
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
+        Entry {
+            kind: EntryKind::Type,
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: Some(self.encode_generics(def_id)),
+            predicates: Some(self.encode_predicates(def_id)),
+
+            ast: None,
+            mir: None
+        }
     }
-    rbml_w.end_tag();
-}
-
-fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) {
-    let byte: u8 = match polarity {
-        hir::ImplPolarity::Positive => 0,
-        hir::ImplPolarity::Negative => 1,
-    };
-    rbml_w.wr_tagged_u8(tag_polarity, byte);
-}
 
-fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) {
-    fn get_ordered_deps(cstore: &cstore::CStore)
-                        -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
-        // Pull the cnums and name,vers,hash out of cstore
-        let mut deps = Vec::new();
-        cstore.iter_crate_data(|cnum, val| {
-            deps.push((cnum, val.clone()));
-        });
+    fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
+        let tcx = self.tcx;
 
-        // Sort by cnum
-        deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
+        let data = ClosureData {
+            kind: tcx.closure_kind(def_id),
+            ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id])
+        };
 
-        // Sanity-check the crate numbers
-        let mut expected_cnum = 1;
-        for &(n, _) in &deps {
-            assert_eq!(n, expected_cnum);
-            expected_cnum += 1;
+        Entry {
+            kind: EntryKind::Closure(self.lazy(&data)),
+            visibility: ty::Visibility::Public,
+            def_key: self.encode_def_key(def_id),
+            attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+
+            ty: None,
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+
+            ast: None,
+            mir: self.encode_mir(def_id)
         }
-
-        deps
     }
 
-    // We're just going to write a list of crate 'name-hash-version's, with
-    // the assumption that they are numbered 1 to n.
-    // FIXME (#2166): This is not nearly enough to support correct versioning
-    // but is enough to get transitive crate dependencies working.
-    rbml_w.start_tag(tag_crate_deps);
-    for (_cnum, dep) in get_ordered_deps(cstore) {
-        encode_crate_dep(rbml_w, &dep);
+    fn encode_info_for_items(&mut self) -> Index {
+        let krate = self.tcx.map.krate();
+        let mut index = IndexBuilder::new(self);
+        index.record(DefId::local(CRATE_DEF_INDEX),
+                     EncodeContext::encode_info_for_mod,
+                     FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public)));
+        let mut visitor = EncodeVisitor {
+            index: index,
+        };
+        krate.visit_all_items(&mut visitor);
+        visitor.index.into_items()
     }
-    rbml_w.end_tag();
-}
 
-fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_lang_items);
+    fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq<ast::Attribute> {
+        self.lazy_seq_ref(attrs)
+    }
 
-    for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() {
-        if let Some(def_id) = opt_def_id {
-            if def_id.is_local() {
-                rbml_w.start_tag(tag_lang_items_item);
-                rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32);
-                rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32());
-                rbml_w.end_tag();
+    fn encode_crate_deps(&mut self) -> LazySeq<CrateDep> {
+        fn get_ordered_deps(cstore: &cstore::CStore)
+                            -> Vec<(CrateNum, Rc<cstore::CrateMetadata>)> {
+            // Pull the cnums and name,vers,hash out of cstore
+            let mut deps = Vec::new();
+            cstore.iter_crate_data(|cnum, val| {
+                deps.push((cnum, val.clone()));
+            });
+
+            // Sort by cnum
+            deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0));
+
+            // Sanity-check the crate numbers
+            let mut expected_cnum = 1;
+            for &(n, _) in &deps {
+                assert_eq!(n, CrateNum::new(expected_cnum));
+                expected_cnum += 1;
             }
+
+            deps
         }
-    }
 
-    for i in &ecx.tcx.lang_items.missing {
-        rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32);
+        // We're just going to write a list of crate 'name-hash-version's, with
+        // the assumption that they are numbered 1 to n.
+        // FIXME (#2166): This is not nearly enough to support correct versioning
+        // but is enough to get transitive crate dependencies working.
+        let deps = get_ordered_deps(self.cstore);
+        self.lazy_seq(deps.iter().map(|&(_, ref dep)| {
+            CrateDep {
+                name: syntax::parse::token::intern(dep.name()),
+                hash: dep.hash(),
+                explicitly_linked: dep.explicitly_linked.get()
+            }
+        }))
     }
 
-    rbml_w.end_tag();   // tag_lang_items
-}
-
-fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_native_libraries);
-
-    for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() {
-        match kind {
-            cstore::NativeStatic => {} // these libraries are not propagated
-            cstore::NativeFramework | cstore::NativeUnknown => {
-                rbml_w.start_tag(tag_native_libraries_lib);
-                rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32);
-                rbml_w.wr_tagged_str(tag_native_libraries_name, lib);
-                rbml_w.end_tag();
+    fn encode_lang_items(&mut self)
+                         -> (LazySeq<(DefIndex, usize)>, LazySeq<lang_items::LangItem>) {
+        let tcx = self.tcx;
+        let lang_items = tcx.lang_items.items().iter();
+        (self.lazy_seq(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
+            if let Some(def_id) = opt_def_id {
+                if def_id.is_local() {
+                    return Some((def_id.index, i));
+                }
             }
-        }
+            None
+        })), self.lazy_seq_ref(&tcx.lang_items.missing))
     }
 
-    rbml_w.end_tag();
-}
-
-fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    match ecx.tcx.sess.plugin_registrar_fn.get() {
-        Some(id) => {
-            let def_id = ecx.tcx.map.local_def_id(id);
-            rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32());
-        }
-        None => {}
+    fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> {
+        let used_libraries = self.tcx.sess.cstore.used_libraries();
+        self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| {
+            match kind {
+                cstore::NativeStatic => None, // these libraries are not propagated
+                cstore::NativeFramework | cstore::NativeUnknown => {
+                    Some((kind, lib))
+                }
+            }
+        }))
     }
-}
-
-fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_codemap);
-    let codemap = ecx.tcx.sess.codemap();
-
-    for filemap in &codemap.files.borrow()[..] {
 
-        if filemap.lines.borrow().is_empty() || filemap.is_imported() {
+    fn encode_codemap(&mut self) -> LazySeq<syntax_pos::FileMap> {
+        let codemap = self.tcx.sess.codemap();
+        let all_filemaps = codemap.files.borrow();
+        self.lazy_seq_ref(all_filemaps.iter().filter(|filemap| {
             // No need to export empty filemaps, as they can't contain spans
             // that need translation.
             // Also no need to re-export imported filemaps, as any downstream
             // crate will import them from their original source.
-            continue;
-        }
-
-        rbml_w.start_tag(tag_codemap_filemap);
-        rbml_w.emit_opaque(|opaque_encoder| {
-            filemap.encode(opaque_encoder)
-        }).unwrap();
-        rbml_w.end_tag();
+            !filemap.lines.borrow().is_empty() && !filemap.is_imported()
+        }).map(|filemap| &**filemap))
     }
 
-    rbml_w.end_tag();
-}
-
-/// Serialize the text of the exported macros
-fn encode_macro_defs(rbml_w: &mut Encoder,
-                     krate: &hir::Crate) {
-    rbml_w.start_tag(tag_macro_defs);
-    for def in &krate.exported_macros {
-        rbml_w.start_tag(tag_macro_def);
-
-        encode_name(rbml_w, def.name);
-        encode_attributes(rbml_w, &def.attrs);
-        let &BytePos(lo) = &def.span.lo;
-        let &BytePos(hi) = &def.span.hi;
-        rbml_w.wr_tagged_u32(tag_macro_def_span_lo, lo);
-        rbml_w.wr_tagged_u32(tag_macro_def_span_hi, hi);
-
-        rbml_w.wr_tagged_str(tag_macro_def_body,
-                             &::syntax::print::pprust::tts_to_string(&def.body));
-
-        rbml_w.end_tag();
-    }
-    rbml_w.end_tag();
-}
-
-fn encode_struct_field_attrs(ecx: &EncodeContext,
-                             rbml_w: &mut Encoder,
-                             krate: &hir::Crate) {
-    struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
-        ecx: &'a EncodeContext<'b, 'tcx>,
-        rbml_w: &'a mut Encoder<'c>,
-    }
-
-    impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> {
-        fn visit_struct_field(&mut self, field: &hir::StructField) {
-            self.rbml_w.start_tag(tag_struct_field);
-            let def_id = self.ecx.tcx.map.local_def_id(field.id);
-            encode_def_id(self.rbml_w, def_id);
-            encode_attributes(self.rbml_w, &field.attrs);
-            self.rbml_w.end_tag();
-        }
+    /// Serialize the text of the exported macros
+    fn encode_macro_defs(&mut self) -> LazySeq<MacroDef> {
+        let tcx = self.tcx;
+        self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| {
+            MacroDef {
+                name: def.name,
+                attrs: def.attrs.to_vec(),
+                span: def.span,
+                body: ::syntax::print::pprust::tts_to_string(&def.body)
+            }
+        }))
     }
-
-    rbml_w.start_tag(tag_struct_fields);
-    krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w });
-    rbml_w.end_tag();
 }
 
-
-
 struct ImplVisitor<'a, 'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    impls: FnvHashMap<DefId, Vec<DefId>>
+    impls: FnvHashMap<DefId, Vec<DefIndex>>
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
@@ -1681,333 +1185,221 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
             if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) {
                 self.impls.entry(trait_ref.def_id)
                     .or_insert(vec![])
-                    .push(impl_id);
+                    .push(impl_id.index);
             }
         }
     }
 }
 
-/// Encodes an index, mapping each trait to its (local) implementations.
-fn encode_impls<'a>(ecx: &'a EncodeContext,
-                    krate: &hir::Crate,
-                    rbml_w: &'a mut Encoder) {
-    let mut visitor = ImplVisitor {
-        tcx: ecx.tcx,
-        impls: FnvHashMap()
-    };
-    krate.visit_all_items(&mut visitor);
-
-    rbml_w.start_tag(tag_impls);
-    for (trait_, trait_impls) in visitor.impls {
-        rbml_w.start_tag(tag_impls_trait);
-        encode_def_id(rbml_w, trait_);
-        for impl_ in trait_impls {
-            rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_));
-        }
-        rbml_w.end_tag();
-    }
-    rbml_w.end_tag();
-}
-
-fn encode_misc_info(ecx: &EncodeContext,
-                    krate: &hir::Crate,
-                    rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_misc_info);
-    rbml_w.start_tag(tag_misc_info_crate_items);
-    for item_id in &krate.module.item_ids {
-        rbml_w.wr_tagged_u64(tag_mod_child,
-                             def_to_u64(ecx.tcx.map.local_def_id(item_id.id)));
-
-        let item = ecx.tcx.map.expect_item(item_id.id);
-        each_auxiliary_node_id(item, |auxiliary_node_id| {
-            rbml_w.wr_tagged_u64(tag_mod_child,
-                                 def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
-            true
-        });
-    }
-
-    // Encode reexports for the root module.
-    encode_reexports(ecx, rbml_w, 0);
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+    /// Encodes an index, mapping each trait to its (local) implementations.
+    fn encode_impls(&mut self) -> LazySeq<TraitImpls> {
+        let mut visitor = ImplVisitor {
+            tcx: self.tcx,
+            impls: FnvHashMap()
+        };
+        self.tcx.map.krate().visit_all_items(&mut visitor);
 
-    rbml_w.end_tag();
-    rbml_w.end_tag();
-}
+        let all_impls: Vec<_> = visitor.impls.into_iter().map(|(trait_def_id, impls)| {
+            TraitImpls {
+                trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index),
+                impls: self.lazy_seq(impls)
+            }
+        }).collect();
 
-// Encodes all reachable symbols in this crate into the metadata.
-//
-// This pass is seeded off the reachability list calculated in the
-// middle::reachable module but filters out items that either don't have a
-// symbol associated with them (they weren't translated) or if they're an FFI
-// definition (as that's not defined in this crate).
-fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) {
-    rbml_w.start_tag(tag_reachable_ids);
-    for &id in ecx.reachable {
-        let def_id = ecx.tcx.map.local_def_id(id);
-        rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32());
+        self.lazy_seq(all_impls)
     }
-    rbml_w.end_tag();
-}
-
-fn encode_crate_dep(rbml_w: &mut Encoder,
-                    dep: &cstore::CrateMetadata) {
-    rbml_w.start_tag(tag_crate_dep);
-    rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
-    let hash = decoder::get_crate_hash(dep.data());
-    rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
-    rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
-                        dep.explicitly_linked.get() as u8);
-    rbml_w.end_tag();
-}
-
-fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
-    rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64());
-}
-
-fn encode_rustc_version(rbml_w: &mut Encoder) {
-    rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version());
-}
-
-fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) {
-    rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name);
-}
 
-fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) {
-    rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator);
-}
-
-fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) {
-    rbml_w.wr_tagged_str(tag_crate_triple, triple);
-}
-
-fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) {
-    let tag = tag_dylib_dependency_formats;
-    match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
-        Some(arr) => {
-            let s = arr.iter().enumerate().filter_map(|(i, slot)| {
-                let kind = match *slot {
-                    Linkage::NotLinked |
-                    Linkage::IncludedFromDylib => return None,
-                    Linkage::Dynamic => "d",
-                    Linkage::Static => "s",
-                };
-                Some(format!("{}:{}", i + 1, kind))
-            }).collect::<Vec<String>>();
-            rbml_w.wr_tagged_str(tag, &s.join(","));
-        }
-        None => {
-            rbml_w.wr_tagged_str(tag, "");
-        }
+    // Encodes all reachable symbols in this crate into the metadata.
+    //
+    // This pass is seeded off the reachability list calculated in the
+    // middle::reachable module but filters out items that either don't have a
+    // symbol associated with them (they weren't translated) or if they're an FFI
+    // definition (as that's not defined in this crate).
+    fn encode_reachable(&mut self) -> LazySeq<DefIndex> {
+        let reachable = self.reachable;
+        let tcx = self.tcx;
+        self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index))
     }
-}
 
-fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) {
-    match ecx.tcx.sess.opts.cg.panic {
-        PanicStrategy::Unwind => {
-            rbml_w.wr_tagged_u8(tag_panic_strategy, b'U');
-        }
-        PanicStrategy::Abort => {
-            rbml_w.wr_tagged_u8(tag_panic_strategy, b'A');
+    fn encode_dylib_dependency_formats(&mut self) -> LazySeq<Option<LinkagePreference>> {
+        match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) {
+            Some(arr) => {
+                self.lazy_seq(arr.iter().map(|slot| {
+                    match *slot {
+                        Linkage::NotLinked |
+                        Linkage::IncludedFromDylib => None,
+
+                        Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
+                        Linkage::Static => Some(LinkagePreference::RequireStatic),
+                    }
+                }))
+            }
+            None => LazySeq::empty()
         }
     }
-}
 
-pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec<u8> {
-    let mut wr = Cursor::new(Vec::new());
+    fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
+        let mut i = self.position();
+        let crate_deps = self.encode_crate_deps();
+        let dylib_dependency_formats = self.encode_dylib_dependency_formats();
+        let dep_bytes = self.position() - i;
+
+        // Encode the language items.
+        i = self.position();
+        let (lang_items, lang_items_missing) = self.encode_lang_items();
+        let lang_item_bytes = self.position() - i;
+
+        // Encode the native libraries used
+        i = self.position();
+        let native_libraries = self.encode_native_libraries();
+        let native_lib_bytes = self.position() - i;
+
+        // Encode codemap
+        i = self.position();
+        let codemap = self.encode_codemap();
+        let codemap_bytes = self.position() - i;
+
+        // Encode macro definitions
+        i = self.position();
+        let macro_defs = self.encode_macro_defs();
+        let macro_defs_bytes = self.position() - i;
+
+        // Encode the def IDs of impls, for coherence checking.
+        i = self.position();
+        let impls = self.encode_impls();
+        let impl_bytes = self.position() - i;
+
+        // Encode reachability info.
+        i = self.position();
+        let reachable_ids = self.encode_reachable();
+        let reachable_bytes = self.position() - i;
+
+        // Encode and index the items.
+        i = self.position();
+        let items = self.encode_info_for_items();
+        let item_bytes = self.position() - i;
+
+        i = self.position();
+        let index = items.write_index(&mut self.opaque.cursor);
+        let index_bytes = self.position() - i;
+
+        let tcx = self.tcx;
+        let link_meta = self.link_meta;
+        let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro);
+        let root = self.lazy(&CrateRoot {
+            rustc_version: RUSTC_VERSION.to_string(),
+            name: link_meta.crate_name.clone(),
+            triple: tcx.sess.opts.target_triple.clone(),
+            hash: link_meta.crate_hash,
+            disambiguator: tcx.sess.local_crate_disambiguator().to_string(),
+            panic_strategy: tcx.sess.opts.cg.panic.clone(),
+            plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| {
+                tcx.map.local_def_id(id).index
+            }),
+            macro_derive_registrar: if is_rustc_macro {
+                let id = tcx.sess.derive_registrar_fn.get().unwrap();
+                Some(tcx.map.local_def_id(id).index)
+            } else {
+                None
+            },
+
+            crate_deps: crate_deps,
+            dylib_dependency_formats: dylib_dependency_formats,
+            lang_items: lang_items,
+            lang_items_missing: lang_items_missing,
+            native_libraries: native_libraries,
+            codemap: codemap,
+            macro_defs: macro_defs,
+            impls: impls,
+            reachable_ids: reachable_ids,
+            index: index,
+        });
 
-    {
-        let mut rbml_w = Encoder::new(&mut wr);
-        encode_metadata_inner(&mut rbml_w, &ecx, krate)
-    }
+        let total_bytes = self.position();
 
-    // RBML compacts the encoded bytes whenever appropriate,
-    // so there are some garbages left after the end of the data.
-    let metalen = wr.seek(SeekFrom::Current(0)).unwrap() as usize;
-    let mut v = wr.into_inner();
-    v.truncate(metalen);
-    assert_eq!(v.len(), metalen);
-
-    // And here we run into yet another obscure archive bug: in which metadata
-    // loaded from archives may have trailing garbage bytes. Awhile back one of
-    // our tests was failing sporadically on the OSX 64-bit builders (both nopt
-    // and opt) by having rbml generate an out-of-bounds panic when looking at
-    // metadata.
-    //
-    // Upon investigation it turned out that the metadata file inside of an rlib
-    // (and ar archive) was being corrupted. Some compilations would generate a
-    // metadata file which would end in a few extra bytes, while other
-    // compilations would not have these extra bytes appended to the end. These
-    // extra bytes were interpreted by rbml as an extra tag, so they ended up
-    // being interpreted causing the out-of-bounds.
-    //
-    // The root cause of why these extra bytes were appearing was never
-    // discovered, and in the meantime the solution we're employing is to insert
-    // the length of the metadata to the start of the metadata. Later on this
-    // will allow us to slice the metadata to the precise length that we just
-    // generated regardless of trailing bytes that end up in it.
-    //
-    // We also need to store the metadata encoding version here, because
-    // rlibs don't have it. To get older versions of rustc to ignore
-    // this metadata, there are 4 zero bytes at the start, which are
-    // treated as a length of 0 by old compilers.
-
-    let len = v.len();
-    let mut result = vec![];
-    result.push(0);
-    result.push(0);
-    result.push(0);
-    result.push(0);
-    result.extend(metadata_encoding_version.iter().cloned());
-    result.push((len >> 24) as u8);
-    result.push((len >> 16) as u8);
-    result.push((len >>  8) as u8);
-    result.push((len >>  0) as u8);
-    result.extend(v);
-    result
-}
-
-fn encode_metadata_inner(rbml_w: &mut Encoder,
-                         ecx: &EncodeContext,
-                         krate: &hir::Crate) {
-    struct Stats {
-        attr_bytes: u64,
-        dep_bytes: u64,
-        lang_item_bytes: u64,
-        native_lib_bytes: u64,
-        plugin_registrar_fn_bytes: u64,
-        codemap_bytes: u64,
-        macro_defs_bytes: u64,
-        impl_bytes: u64,
-        misc_bytes: u64,
-        item_bytes: u64,
-        index_bytes: u64,
-        xref_bytes: u64,
-        zero_bytes: u64,
-        total_bytes: u64,
-    }
-    let mut stats = Stats {
-        attr_bytes: 0,
-        dep_bytes: 0,
-        lang_item_bytes: 0,
-        native_lib_bytes: 0,
-        plugin_registrar_fn_bytes: 0,
-        codemap_bytes: 0,
-        macro_defs_bytes: 0,
-        impl_bytes: 0,
-        misc_bytes: 0,
-        item_bytes: 0,
-        index_bytes: 0,
-        xref_bytes: 0,
-        zero_bytes: 0,
-        total_bytes: 0,
-    };
-
-    encode_rustc_version(rbml_w);
-    encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
-    encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
-    encode_hash(rbml_w, &ecx.link_meta.crate_hash);
-    encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator());
-    encode_dylib_dependency_formats(rbml_w, &ecx);
-    encode_panic_strategy(rbml_w, &ecx);
-
-    let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_attributes(rbml_w, &krate.attrs);
-    stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_crate_deps(rbml_w, ecx.cstore);
-    stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the language items.
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_lang_items(&ecx, rbml_w);
-    stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the native libraries used
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_native_libraries(&ecx, rbml_w);
-    stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the plugin registrar function
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_plugin_registrar_fn(&ecx, rbml_w);
-    stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode codemap
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_codemap(&ecx, rbml_w);
-    stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode macro definitions
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_macro_defs(rbml_w, krate);
-    stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode the def IDs of impls, for coherence checking.
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_impls(&ecx, krate, rbml_w);
-    stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode miscellaneous info.
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_misc_info(&ecx, krate, rbml_w);
-    encode_reachable(&ecx, rbml_w);
-    stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    // Encode and index the items.
-    rbml_w.start_tag(tag_items);
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    let index = encode_info_for_items(&ecx, rbml_w);
-    stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-    rbml_w.end_tag();
-
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_item_index(rbml_w, index.items);
-    stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-    encode_xrefs(&ecx, rbml_w, index.xrefs);
-    stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
-
-    encode_struct_field_attrs(&ecx, rbml_w, krate);
-
-    stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
-
-    if ecx.tcx.sess.meta_stats() {
-        for e in rbml_w.writer.get_ref() {
-            if *e == 0 {
-                stats.zero_bytes += 1;
+        if self.tcx.sess.meta_stats() {
+            let mut zero_bytes = 0;
+            for e in self.opaque.cursor.get_ref() {
+                if *e == 0 {
+                    zero_bytes += 1;
+                }
             }
+
+            println!("metadata stats:");
+            println!("             dep bytes: {}", dep_bytes);
+            println!("       lang item bytes: {}", lang_item_bytes);
+            println!("          native bytes: {}", native_lib_bytes);
+            println!("         codemap bytes: {}", codemap_bytes);
+            println!("       macro def bytes: {}", macro_defs_bytes);
+            println!("            impl bytes: {}", impl_bytes);
+            println!("       reachable bytes: {}", reachable_bytes);
+            println!("            item bytes: {}", item_bytes);
+            println!("           index bytes: {}", index_bytes);
+            println!("            zero bytes: {}", zero_bytes);
+            println!("           total bytes: {}", total_bytes);
         }
 
-        println!("metadata stats:");
-        println!("       attribute bytes: {}", stats.attr_bytes);
-        println!("             dep bytes: {}", stats.dep_bytes);
-        println!("       lang item bytes: {}", stats.lang_item_bytes);
-        println!("          native bytes: {}", stats.native_lib_bytes);
-        println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes);
-        println!("         codemap bytes: {}", stats.codemap_bytes);
-        println!("       macro def bytes: {}", stats.macro_defs_bytes);
-        println!("            impl bytes: {}", stats.impl_bytes);
-        println!("            misc bytes: {}", stats.misc_bytes);
-        println!("            item bytes: {}", stats.item_bytes);
-        println!("           index bytes: {}", stats.index_bytes);
-        println!("            xref bytes: {}", stats.xref_bytes);
-        println!("            zero bytes: {}", stats.zero_bytes);
-        println!("           total bytes: {}", stats.total_bytes);
+        root
     }
 }
 
-// Get the encoded string for a type
-pub fn encoded_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            t: Ty<'tcx>,
-                            def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String)
-                            -> Vec<u8> {
-    let mut wr = Cursor::new(Vec::new());
-    tyencode::enc_ty(&mut wr, &tyencode::ctxt {
-        diag: tcx.sess.diagnostic(),
-        ds: def_id_to_string,
+// NOTE(eddyb) The following comment was preserved for posterity, even
+// though it's no longer relevant as EBML (which uses nested & tagged
+// "documents") was replaced with a scheme that can't go out of bounds.
+//
+// And here we run into yet another obscure archive bug: in which metadata
+// loaded from archives may have trailing garbage bytes. Awhile back one of
+// our tests was failing sporadically on the OSX 64-bit builders (both nopt
+// and opt) by having ebml generate an out-of-bounds panic when looking at
+// metadata.
+//
+// Upon investigation it turned out that the metadata file inside of an rlib
+// (and ar archive) was being corrupted. Some compilations would generate a
+// metadata file which would end in a few extra bytes, while other
+// compilations would not have these extra bytes appended to the end. These
+// extra bytes were interpreted by ebml as an extra tag, so they ended up
+// being interpreted causing the out-of-bounds.
+//
+// The root cause of why these extra bytes were appearing was never
+// discovered, and in the meantime the solution we're employing is to insert
+// the length of the metadata to the start of the metadata. Later on this
+// will allow us to slice the metadata to the precise length that we just
+// generated regardless of trailing bytes that end up in it.
+
+pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 cstore: &cstore::CStore,
+                                 reexports: &def::ExportMap,
+                                 link_meta: &LinkMeta,
+                                 reachable: &NodeSet,
+                                 mir_map: &MirMap<'tcx>) -> Vec<u8> {
+    let mut cursor = Cursor::new(vec![]);
+    cursor.write_all(METADATA_HEADER).unwrap();
+
+    // Will be filed with the root position after encoding everything.
+    cursor.write_all(&[0, 0, 0, 0]).unwrap();
+
+    let root = EncodeContext {
+        opaque: opaque::Encoder::new(&mut cursor),
         tcx: tcx,
-        abbrevs: &RefCell::new(FnvHashMap())
-    }, t);
-    wr.into_inner()
+        reexports: reexports,
+        link_meta: link_meta,
+        cstore: cstore,
+        reachable: reachable,
+        mir_map: mir_map,
+        lazy_state: LazyState::NoNode,
+        type_shorthands: Default::default(),
+        predicate_shorthands: Default::default()
+    }.encode_crate_root();
+    let mut result = cursor.into_inner();
+
+    // Encode the root position.
+    let header = METADATA_HEADER.len();
+    let pos = root.position;
+    result[header + 0] = (pos >> 24) as u8;
+    result[header + 1] = (pos >> 16) as u8;
+    result[header + 2] = (pos >>  8) as u8;
+    result[header + 3] = (pos >>  0) as u8;
+
+    result
 }