diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 5dc319aa5f9bc1c9373bd2ec549937a3d79ff33a..3fc7fe5128877cca4eca0934be2ca208d004fb25 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -80,6 +80,7 @@ use mir; use monomorphize::{self, Instance}; use partitioning::{self, PartitioningStrategy, CodegenUnit}; +use symbol_map::SymbolMap; use symbol_names_test; use trans_item::TransItem; use tvec; @@ -97,6 +98,7 @@ use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; +use std::rc::Rc; use std::str; use std::{i8, i16, i32, i64}; use syntax_pos::{Span, DUMMY_SP}; @@ -2588,14 +2590,18 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); - let codegen_units = collect_and_partition_translation_items(&shared_ccx); + let (codegen_units, symbol_map) = + collect_and_partition_translation_items(&shared_ccx); let codegen_unit_count = codegen_units.len(); assert!(tcx.sess.opts.cg.codegen_units == codegen_unit_count || tcx.sess.opts.debugging_opts.incremental.is_some()); - let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units); + let symbol_map = Rc::new(symbol_map); + let crate_context_list = CrateContextList::new(&shared_ccx, + codegen_units, + symbol_map.clone()); let modules = crate_context_list.iter() .map(|ccx| ModuleTranslation { name: String::from(&ccx.codegen_unit().name[..]), @@ -2693,8 +2699,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let sess = shared_ccx.sess(); let mut reachable_symbols = shared_ccx.reachable().iter().map(|&id| { let def_id = shared_ccx.tcx().map.local_def_id(id); - Instance::mono(&shared_ccx, def_id).symbol_name(&shared_ccx) + symbol_for_def_id(def_id, &shared_ccx, &symbol_map) }).collect::>(); + if sess.entry_fn.borrow().is_some() { reachable_symbols.push("main".to_string()); } @@ -2716,7 +2723,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_symbols.extend(syms.into_iter().filter(|did| { sess.cstore.is_extern_item(shared_ccx.tcx(), *did) }).map(|did| { - Instance::mono(&shared_ccx, did).symbol_name(&shared_ccx) + symbol_for_def_id(did, &shared_ccx, &symbol_map) })); } @@ -2810,7 +2817,7 @@ fn visit_item(&mut self, i: &hir::Item) { } fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) - -> Vec> { + -> (Vec>, SymbolMap<'tcx>) { let time_passes = scx.sess().time_passes(); let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { @@ -2833,10 +2840,13 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a None => TransItemCollectionMode::Lazy }; - let (items, inlining_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(&scx, collection_mode) + let (items, inlining_map) = + time(time_passes, "translation item collection", || { + collector::collect_crate_translation_items(&scx, collection_mode) }); + let symbol_map = SymbolMap::build(scx, items.iter().cloned()); + let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() { PartitioningStrategy::PerModule } else { @@ -2910,5 +2920,24 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a } } - codegen_units + (codegen_units, symbol_map) +} + +fn symbol_for_def_id<'a, 'tcx>(def_id: DefId, + scx: &SharedCrateContext<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>) + -> String { + // Just try to look things up in the symbol map. If nothing's there, we + // recompute. + if let Some(node_id) = scx.tcx().map.as_local_node_id(def_id) { + if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) { + return sym.to_owned(); + } + } + + let instance = Instance::mono(scx, def_id); + + symbol_map.get(TransItem::Fn(instance)) + .map(str::to_owned) + .unwrap_or_else(|| instance.symbol_name(scx)) } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 9ea65532b35b61c8c3a1cd35deda4ca89861ad34..b7cf43a437169a937a64670778145475c1c295f5 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -46,6 +46,7 @@ use machine::llalign_of_min; use meth; use monomorphize::{self, Instance}; +use trans_item::TransItem; use type_::Type; use type_of; use value::Value; @@ -536,11 +537,18 @@ fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool { // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let sym = instance.symbol_name(ccx.shared()); + // Let's see if we can get the symbol name from the symbol_map, so we don't + // have to recompute it. + let mut sym_data = String::new(); + let sym = ccx.symbol_map().get(TransItem::Fn(instance)).unwrap_or_else(|| { + sym_data = instance.symbol_name(ccx.shared()); + &sym_data[..] + }); + let llptrty = type_of::type_of(ccx, fn_ptr_ty); - let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { + let llfn = if let Some(llfn) = declare::get_declared_value(ccx, sym) { if let Some(span) = local_item { - if declare::get_defined_value(ccx, &sym).is_some() { + if declare::get_defined_value(ccx, sym).is_some() { ccx.sess().span_fatal(span, &format!("symbol `{}` is already defined", sym)); } @@ -558,7 +566,7 @@ fn is_named_tuple_constructor(tcx: TyCtxt, def_id: DefId) -> bool { llfn } } else { - let llfn = declare::declare_fn(ccx, &sym, ty); + let llfn = declare::declare_fn(ccx, sym, ty); assert_eq!(common::val_ty(llfn), llptrty); debug!("get_fn: not casting pointer!"); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 1a38baeff37841ba3559d05acc7bd49489323313..3f18c61fbd26caada391283588bcc08ebfb6ae20 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -1013,14 +1013,16 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) return Datum::new(g, ty, Lvalue::new("static")); } - let sym = instance.symbol_name(ccx.shared()); - let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { + let llty = type_of::type_of(ccx, ty); let (g, attrs) = match ccx.tcx().map.get(id) { hir_map::NodeItem(&hir::Item { ref attrs, span, node: hir::ItemStatic(..), .. }) => { + let sym = ccx.symbol_map() + .get(TransItem::Static(id)) + .expect("Local statics should always be in the SymbolMap"); // Make sure that this is never executed for something inlined. assert!(!ccx.external_srcs().borrow().contains_key(&id)); @@ -1028,16 +1030,16 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) .items .contains_key(&TransItem::Static(id)); if defined_in_current_codegen_unit { - if declare::get_declared_value(ccx, &sym).is_none() { + if declare::get_declared_value(ccx, sym).is_none() { span_bug!(span, "trans: Static not properly pre-defined?"); } } else { - if declare::get_declared_value(ccx, &sym).is_some() { + if declare::get_declared_value(ccx, sym).is_some() { span_bug!(span, "trans: Conflicting symbol names for static?"); } } - let g = declare::define_global(ccx, &sym, llty).unwrap(); + let g = declare::define_global(ccx, sym, llty).unwrap(); (g, attrs) } @@ -1045,6 +1047,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) hir_map::NodeForeignItem(&hir::ForeignItem { ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { + let sym = instance.symbol_name(ccx.shared()); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -1079,7 +1082,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) real_name.push_str(&sym); let g2 = declare::define_global(ccx, &real_name, llty).unwrap_or_else(||{ ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", sym)) + &format!("symbol `{}` is already defined", &sym)) }); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); @@ -1104,6 +1107,8 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) g } else { + let sym = instance.symbol_name(ccx.shared()); + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global let g = declare::declare_global(ccx, &sym, type_of::type_of(ccx, ty)); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 7f6e8fa035ab735e3dff6b8fd0f1c81b117dc9e2..64e0351610f24441a12c7aa45b9899ad6c0ca49f 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -35,6 +35,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use session::config::NoDebugInfo; use session::Session; +use symbol_map::SymbolMap; use util::sha2::Sha256; use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap}; @@ -171,6 +172,8 @@ pub struct LocalCrateContext<'tcx> { /// Depth of the current type-of computation - used to bail out type_of_depth: Cell, + + symbol_map: Rc>, } // Implement DepTrackingMapConfig for `trait_cache` @@ -197,12 +200,13 @@ pub struct CrateContextList<'a, 'tcx: 'a> { impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> { pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>, - codegen_units: Vec>) + codegen_units: Vec>, + symbol_map: Rc>) -> CrateContextList<'a, 'tcx> { CrateContextList { shared: shared_ccx, local_ccxs: codegen_units.into_iter().map(|codegen_unit| { - LocalCrateContext::new(shared_ccx, codegen_unit) + LocalCrateContext::new(shared_ccx, codegen_unit, symbol_map.clone()) }).collect() } } @@ -512,7 +516,8 @@ pub fn metadata_symbol_name(&self) -> String { impl<'tcx> LocalCrateContext<'tcx> { fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>) + codegen_unit: CodegenUnit<'tcx>, + symbol_map: Rc>) -> LocalCrateContext<'tcx> { unsafe { // Append ".rs" to LLVM module identifier. @@ -571,6 +576,7 @@ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>, intrinsics: RefCell::new(FnvHashMap()), n_llvm_insns: Cell::new(0), type_of_depth: Cell::new(0), + symbol_map: symbol_map, }; let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = { @@ -890,6 +896,10 @@ pub fn get_mir(&self, def_id: DefId) -> Option> { self.shared.get_mir(def_id) } + pub fn symbol_map(&self) -> &SymbolMap<'tcx> { + &*self.local().symbol_map + } + pub fn translation_items(&self) -> &RefCell, TransItemState>> { &self.shared.translation_items } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index c465edc7311af7e23976d4770cc46ca9dd9055ed..fa0a1fdc37523dbff9f012d6a0bb33f82baf93a1 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -122,6 +122,7 @@ pub mod back { mod mir; mod monomorphize; mod partitioning; +mod symbol_map; mod symbol_names_test; mod trans_item; mod tvec; diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 832acfe14bedc7ac163734df070a440af9d6b14f..8a2cc53432d86e1f55621e62987df52bde35cef3 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -84,19 +84,24 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, monomorphizing.insert(fn_id, depth + 1); } - let symbol = instance.symbol_name(ccx.shared()); + // Let's see if we can get the symbol name from the symbol_map, so we don't + // have to recompute it. + let mut sym_data = String::new(); + let symbol = ccx.symbol_map().get(TransItem::Fn(instance)).unwrap_or_else(|| { + sym_data = instance.symbol_name(ccx.shared()); + &sym_data[..] + }); debug!("monomorphize_fn mangled to {}", symbol); - assert!(declare::get_defined_value(ccx, &symbol).is_none()); + assert!(declare::get_defined_value(ccx, symbol).is_none()); // FIXME(nagisa): perhaps needs a more fine grained selection? - let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty); + let lldecl = declare::define_internal_fn(ccx, symbol, mono_ty); // FIXME(eddyb) Doubt all extern fn should allow unwinding. attributes::unwind(lldecl, true); ccx.instances().borrow_mut().insert(instance, lldecl); - // we can only monomorphize things in this crate (or inlined into it) let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap(); let map_node = errors::expect( diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs new file mode 100644 index 0000000000000000000000000000000000000000..4f82b54c76b02328c709245337fa7ba8ede98843 --- /dev/null +++ b/src/librustc_trans/symbol_map.rs @@ -0,0 +1,115 @@ +// Copyright 2016 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. + +use context::SharedCrateContext; +use monomorphize::Instance; +use rustc::ty::TyCtxt; +use syntax::codemap::Span; +use trans_item::TransItem; +use util::nodemap::FnvHashMap; + + +// In the SymbolMap we collect the symbol names of all translation items of +// the current crate. + +pub struct SymbolMap<'tcx> { + index: FnvHashMap, (usize, usize)>, + arena: String, +} + +impl<'tcx> SymbolMap<'tcx> { + + pub fn build<'a, I>(scx: &SharedCrateContext<'a, 'tcx>, + trans_items: I) + -> SymbolMap<'tcx> + where I: Iterator> + { + // Check for duplicate symbol names + let mut symbols: Vec<_> = trans_items.map(|trans_item| { + (trans_item, trans_item.compute_symbol_name(scx)) + }).collect(); + + (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{ + sym1.cmp(sym2) + }); + + for pair in (&symbols[..]).windows(2) { + let sym1 = &pair[0].1; + let sym2 = &pair[1].1; + + if *sym1 == *sym2 { + let trans_item1 = pair[0].0; + let trans_item2 = pair[1].0; + + let span1 = get_span(scx.tcx(), trans_item1); + let span2 = get_span(scx.tcx(), trans_item2); + + // Deterministically select one of the spans for error reporting + let span = match (span1, span2) { + (Some(span1), Some(span2)) => { + Some(if span1.lo.0 > span2.lo.0 { + span1 + } else { + span2 + }) + } + (Some(span), None) | + (None, Some(span)) => Some(span), + _ => None + }; + + let error_message = format!("symbol `{}` is already defined", sym1); + + if let Some(span) = span { + scx.sess().span_fatal(span, &error_message) + } else { + scx.sess().fatal(&error_message) + } + } + } + + let mut symbol_map = SymbolMap { + index: FnvHashMap(), + arena: String::with_capacity(1024), + }; + + for (trans_item, symbol) in symbols { + let start_index = symbol_map.arena.len(); + symbol_map.arena.push_str(&symbol[..]); + let end_index = symbol_map.arena.len(); + let prev_entry = symbol_map.index.insert(trans_item, + (start_index, end_index)); + if prev_entry.is_some() { + bug!("TransItem encountered twice?") + } + } + + fn get_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + trans_item: TransItem<'tcx>) -> Option { + match trans_item { + TransItem::Fn(Instance { def, .. }) => { + tcx.map.as_local_node_id(def) + } + TransItem::Static(node_id) => Some(node_id), + TransItem::DropGlue(_) => None, + }.map(|node_id| { + tcx.map.span(node_id) + }) + } + + symbol_map + } + + pub fn get(&self, trans_item: TransItem<'tcx>) -> Option<&str> { + self.index.get(&trans_item).map(|&(start_index, end_index)| { + &self.arena[start_index .. end_index] + }) + } +} diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index a07deda2b1e5e8c20c7fda052999499d425b6cc9..4fa0ba03005abb80fa7ccc81c5e2f8eee5673464 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -17,7 +17,7 @@ use attributes; use base; use consts; -use context::CrateContext; +use context::{CrateContext, SharedCrateContext}; use declare; use glue::DropGlueKind; use llvm; @@ -64,7 +64,6 @@ fn hash(&self, s: &mut H) { } } - impl<'a, 'tcx> TransItem<'tcx> { pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) { @@ -108,15 +107,20 @@ pub fn predefine(&self, self.to_raw_string(), ccx.codegen_unit().name); + let symbol_name = ccx.symbol_map() + .get(*self) + .expect("Name not present in SymbolMap?"); + debug!("symbol {}", symbol_name); + match *self { TransItem::Static(node_id) => { - TransItem::predefine_static(ccx, node_id, linkage); + TransItem::predefine_static(ccx, node_id, linkage, symbol_name); } TransItem::Fn(instance) => { - TransItem::predefine_fn(ccx, instance, linkage); + TransItem::predefine_fn(ccx, instance, linkage, symbol_name); } TransItem::DropGlue(dg) => { - TransItem::predefine_drop_glue(ccx, dg, linkage); + TransItem::predefine_drop_glue(ccx, dg, linkage, symbol_name); } } @@ -128,7 +132,8 @@ pub fn predefine(&self, fn predefine_static(ccx: &CrateContext<'a, 'tcx>, node_id: ast::NodeId, - linkage: llvm::Linkage) { + linkage: llvm::Linkage, + symbol_name: &str) { let def_id = ccx.tcx().map.local_def_id(node_id); let ty = ccx.tcx().lookup_item_type(def_id).ty; let llty = type_of::type_of(ccx, ty); @@ -137,13 +142,9 @@ fn predefine_static(ccx: &CrateContext<'a, 'tcx>, hir::map::NodeItem(&hir::Item { span, node: hir::ItemStatic(..), .. }) => { - let instance = Instance::mono(ccx.shared(), def_id); - let sym = instance.symbol_name(ccx.shared()); - debug!("symbol {}", sym); - - let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { + let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", sym)) + &format!("symbol `{}` is already defined", symbol_name)) }); llvm::SetLinkage(g, linkage); @@ -155,7 +156,8 @@ fn predefine_static(ccx: &CrateContext<'a, 'tcx>, fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>, - linkage: llvm::Linkage) { + linkage: llvm::Linkage, + symbol_name: &str) { assert!(!instance.substs.types.needs_infer() && !instance.substs.types.has_param_types()); @@ -186,10 +188,7 @@ fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, hir_map::NodeImplItem(&hir::ImplItem { ref attrs, node: hir::ImplItemKind::Method(..), .. }) => { - let symbol = instance.symbol_name(ccx.shared()); - debug!("symbol {}", symbol); - - let lldecl = declare::declare_fn(ccx, &symbol, mono_ty); + let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); llvm::SetLinkage(lldecl, linkage); attributes::from_fn_attrs(ccx, attrs, lldecl); base::set_link_section(ccx, lldecl, attrs); @@ -203,7 +202,8 @@ fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>, dg: glue::DropGlueKind<'tcx>, - linkage: llvm::Linkage) { + linkage: llvm::Linkage, + symbol_name: &str) { let tcx = ccx.tcx(); assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty())); let t = dg.ty(); @@ -220,21 +220,31 @@ fn predefine_drop_glue(ccx: &CrateContext<'a, 'tcx>, fn_ty.args[0].original_ty = type_of::type_of(ccx, t).ptr_to(); let llfnty = fn_ty.llvm_type(ccx); - let prefix = match dg { - DropGlueKind::Ty(_) => "drop", - DropGlueKind::TyContents(_) => "drop_contents", - }; - - let symbol = - symbol_names::exported_name_from_type_and_prefix(ccx.shared(), t, prefix); - debug!(" symbol: {}", symbol); - assert!(declare::get_defined_value(ccx, &symbol).is_none()); - let llfn = declare::declare_cfn(ccx, &symbol, llfnty); + assert!(declare::get_defined_value(ccx, symbol_name).is_none()); + let llfn = declare::declare_cfn(ccx, symbol_name, llfnty); + llvm::SetLinkage(llfn, linkage); attributes::set_frame_pointer_elimination(ccx, llfn); - llvm::SetLinkage(llfn, linkage); ccx.drop_glues().borrow_mut().insert(dg, (llfn, fn_ty)); } + pub fn compute_symbol_name(&self, + scx: &SharedCrateContext<'a, 'tcx>) -> String { + match *self { + TransItem::Fn(instance) => instance.symbol_name(scx), + TransItem::Static(node_id) => { + let def_id = scx.tcx().map.local_def_id(node_id); + Instance::mono(scx, def_id).symbol_name(scx) + } + TransItem::DropGlue(dg) => { + let prefix = match dg { + DropGlueKind::Ty(_) => "drop", + DropGlueKind::TyContents(_) => "drop_contents", + }; + symbol_names::exported_name_from_type_and_prefix(scx, dg.ty(), prefix) + } + } + } + pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { match *self { TransItem::Fn(ref instance) => {