// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // 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 middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls}; 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::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::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::Encodable; use std::cell::RefCell; use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; 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; use syntax_pos::BytePos; use rbml::writer::Encoder; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, 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() } } /// "interned" entries referenced by id #[derive(PartialEq, Eq, Hash)] pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } struct CrateIndex<'a, 'tcx> { dep_graph: &'a DepGraph, items: IndexData, xrefs: FnvHashMap, 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 add_xref(&mut self, xref: XRef<'tcx>) -> u32 { let old_len = self.xrefs.len() as u32; *self.xrefs.entry(xref).or_insert(old_len) } } 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(); } // 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); } 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) } pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String { format!("{}:{}", did.krate, did.index.as_usize()) } 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(); } 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 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 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); } 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(); } 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 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()); } 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 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(); } } 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); } 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 stab = ecx.tcx.lookup_stability(vid); let depr = ecx.tcx.lookup_deprecation(vid); encode_stability(rbml_w, stab); encode_deprecation(rbml_w, depr); encode_struct_fields(rbml_w, variant); 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; } encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id); rbml_w.end_tag(); disr_val = disr_val.wrap_incr(); } } /// 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(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()); } } _ => {} } 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_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 }); } 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 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); } 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_visibility(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); } trait HasVisibility: Sized { fn is_public(self) -> bool; } impl<'a> HasVisibility for &'a hir::Visibility { fn is_public(self) -> bool { *self == hir::Public } } impl HasVisibility for ty::Visibility { fn is_public(self) -> bool { self == ty::Visibility::Public } } 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]); } } fn encode_mutability(m: hir::Mutability) -> u8 { match m { hir::MutImmutable => 'i' as u8, hir::MutMutable => 'm' as u8, } } } 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_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(); } 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(); } 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(); } // 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(); } encode_predicates_in_current_doc(rbml_w, ecx, index, predicates); rbml_w.end_tag(); } 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 }; 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(); } 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); } _ => 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); } rbml_w.end_tag(); } 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); } 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(); } 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()); } else { rbml_w.wr_tagged_bytes(tag, &[]); } } 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)); } 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(); } } 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(); } } } } 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_deprecation(rbml_w: &mut Encoder, depr_opt: Option) { depr_opt.map(|depr| { rbml_w.start_tag(tag_items_data_item_deprecation); depr.encode(rbml_w).unwrap(); rbml_w.end_tag(); }); } fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option) { parent_opt.map(|parent| { rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent)); }); } fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, xrefs: FnvHashMap, 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) } } } 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(); } 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)); } rbml_w.end_tag(); for field in &variant.fields { encode_field(ecx, rbml_w, field, index); } // 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(); } None => {} } 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'); } ty::MethodTraitItemId(item_def_id) => { encode_def_id(rbml_w, item_def_id); encode_item_sort(rbml_w, 'r'); } ty::TypeTraitItemId(item_def_id) => { encode_def_id(rbml_w, item_def_id); encode_item_sort(rbml_w, 't'); } } 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) } ty::MethodTraitItem(ref method_type) => { encode_info_for_method(ecx, rbml_w, index, &method_type, false, item.id, ast_item) } ty::TypeTraitItem(ref associated_type) => { encode_info_for_associated_type(ecx, rbml_w, index, &associated_type, item.id, ast_item) } } } } 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'); } ty::MethodTraitItemId(method_def_id) => { encode_def_id(rbml_w, method_def_id); encode_item_sort(rbml_w, 'r'); } ty::TypeTraitItemId(type_def_id) => { encode_def_id(rbml_w, type_def_id); encode_item_sort(rbml_w, 't'); } } 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; } ty::MethodTraitItem(method_ty) => { let method_def_id = item_def_id.def_id(); encode_method_ty_fields(ecx, rbml_w, index, &method_ty); match method_ty.explicit_self { ty::ExplicitSelfCategory::Static => { encode_family(rbml_w, STATIC_METHOD_FAMILY); } _ => { encode_family(rbml_w, METHOD_FAMILY); } } 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); } 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::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::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("")); 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(); rbml_w.start_tag(tag_items_closure_kind); ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap(); rbml_w.end_tag(); assert!(ecx.mir_map.map.contains_key(&def_id)); encode_mir(ecx, rbml_w, expr.id); rbml_w.end_tag(); } _ => { } } } 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>, } impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, '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); } 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_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); } 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(); } } } 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); } 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(); } 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()); } 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)> { // 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, expected_cnum); expected_cnum += 1; } 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); } rbml_w.end_tag(); } fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) { rbml_w.start_tag(tag_lang_items); 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(); } } } for i in &ecx.tcx.lang_items.missing { rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32); } 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(); } } } 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_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() { // 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(); } 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(); } } 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> } impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemImpl(..) = item.node { let impl_id = self.tcx.map.local_def_id(item.id); 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); } } } } /// 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); rbml_w.end_tag(); rbml_w.end_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(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()); } 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::>(); rbml_w.wr_tagged_str(tag, &s.join(",")); } None => { rbml_w.wr_tagged_str(tag, ""); } } } 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'); } } } pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec { let mut wr = Cursor::new(Vec::new()); { let mut rbml_w = Encoder::new(&mut wr); encode_metadata_inner(&mut rbml_w, &ecx, krate) } // 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; } } 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); } } // 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 { let mut wr = Cursor::new(Vec::new()); tyencode::enc_ty(&mut wr, &tyencode::ctxt { diag: tcx.sess.diagnostic(), ds: def_id_to_string, tcx: tcx, abbrevs: &RefCell::new(FnvHashMap()) }, t); wr.into_inner() }