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;
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};
};
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[..]),
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::<Vec<_>>();
+
if sess.entry_fn.borrow().is_some() {
reachable_symbols.push("main".to_string());
}
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)
}));
}
}
fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
- -> Vec<CodegenUnit<'tcx>> {
+ -> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
let time_passes = scx.sess().time_passes();
let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items {
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 {
}
}
- 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))
}
use machine::llalign_of_min;
use meth;
use monomorphize::{self, Instance};
+use trans_item::TransItem;
use type_::Type;
use type_of;
use value::Value;
// 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));
}
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!");
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));
.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)
}
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
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);
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));
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};
/// Depth of the current type-of computation - used to bail out
type_of_depth: Cell<usize>,
+
+ symbol_map: Rc<SymbolMap<'tcx>>,
}
// Implement DepTrackingMapConfig for `trait_cache`
impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> {
pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>,
- codegen_units: Vec<CodegenUnit<'tcx>>)
+ codegen_units: Vec<CodegenUnit<'tcx>>,
+ symbol_map: Rc<SymbolMap<'tcx>>)
-> 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()
}
}
impl<'tcx> LocalCrateContext<'tcx> {
fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
- codegen_unit: CodegenUnit<'tcx>)
+ codegen_unit: CodegenUnit<'tcx>,
+ symbol_map: Rc<SymbolMap<'tcx>>)
-> LocalCrateContext<'tcx> {
unsafe {
// Append ".rs" to LLVM module identifier.
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) = {
self.shared.get_mir(def_id)
}
+ pub fn symbol_map(&self) -> &SymbolMap<'tcx> {
+ &*self.local().symbol_map
+ }
+
pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
&self.shared.translation_items
}
mod mir;
mod monomorphize;
mod partitioning;
+mod symbol_map;
mod symbol_names_test;
mod trans_item;
mod tvec;
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(
--- /dev/null
+// 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 <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.
+
+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<TransItem<'tcx>, (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<Item=TransItem<'tcx>>
+ {
+ // 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<Span> {
+ 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]
+ })
+ }
+}
use attributes;
use base;
use consts;
-use context::CrateContext;
+use context::{CrateContext, SharedCrateContext};
use declare;
use glue::DropGlueKind;
use llvm;
}
}
-
impl<'a, 'tcx> TransItem<'tcx> {
pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
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);
}
}
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);
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);
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());
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);
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();
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) => {