| // 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 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<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 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<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()); |
| } |
| } |
| _ => {} |
| } |
| |
| 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<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); |
| } |
| |
| 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) { |
| if let Some(mir) = ecx.mir_map.map.get(&node_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<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_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_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) |
| } |
| } |
| } |
| 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(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(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(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(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(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(); |
| |
| 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(&expr.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 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<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, 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<DefId, Vec<DefId>> |
| } |
| |
| 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::<Vec<String>>(); |
| 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<u8> { |
| 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<u8> { |
| 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() |
| } |