Skip to content

Commit

Permalink
trans: Internalize symbols at the trans-item level, without relying o…
Browse files Browse the repository at this point in the history
…n LLVM.
  • Loading branch information
michaelwoerister committed Jul 13, 2017
1 parent 1ebfab5 commit 2f07eb3
Show file tree
Hide file tree
Showing 11 changed files with 383 additions and 265 deletions.
8 changes: 3 additions & 5 deletions src/librustc_trans/back/linker.rs
Expand Up @@ -19,7 +19,7 @@ use std::process::Command;
use context::SharedCrateContext;

use back::archive;
use back::symbol_export::{self, ExportedSymbols};
use back::symbol_export::ExportedSymbols;
use rustc::middle::dependency_format::Linkage;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use rustc_back::LinkerFlavor;
Expand Down Expand Up @@ -687,10 +687,8 @@ fn exported_symbols(scx: &SharedCrateContext,
exported_symbols: &ExportedSymbols,
crate_type: CrateType)
-> Vec<String> {
let export_threshold = symbol_export::crate_export_threshold(crate_type);

let mut symbols = Vec::new();
exported_symbols.for_each_exported_symbol(LOCAL_CRATE, export_threshold, |name, _| {
exported_symbols.for_each_exported_symbol(LOCAL_CRATE, |name, _, _| {
symbols.push(name.to_owned());
});

Expand All @@ -702,7 +700,7 @@ fn exported_symbols(scx: &SharedCrateContext,
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
// ... we add its symbol list to our export list.
exported_symbols.for_each_exported_symbol(cnum, export_threshold, |name, _| {
exported_symbols.for_each_exported_symbol(cnum, |name, _, _| {
symbols.push(name.to_owned());
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/back/lto.rs
Expand Up @@ -66,7 +66,7 @@ pub fn run(cgcx: &CodegenContext,
let export_threshold =
symbol_export::crates_export_threshold(&cgcx.crate_types);

let symbol_filter = &|&(ref name, level): &(String, _)| {
let symbol_filter = &|&(ref name, _, level): &(String, _, _)| {
if symbol_export::is_below_threshold(level, export_threshold) {
let mut bytes = Vec::with_capacity(name.len() + 1);
bytes.extend(name.bytes());
Expand Down
112 changes: 72 additions & 40 deletions src/librustc_trans/back/symbol_export.rs
Expand Up @@ -8,10 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use context::SharedCrateContext;
use monomorphize::Instance;
use rustc::util::nodemap::FxHashMap;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::util::nodemap::{FxHashMap, NodeSet};
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
use rustc::session::config;
use rustc::ty::TyCtxt;
use syntax::attr;
Expand All @@ -28,59 +27,87 @@ pub enum SymbolExportLevel {
}

/// The set of symbols exported from each crate in the crate graph.
#[derive(Debug)]
pub struct ExportedSymbols {
exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
pub export_threshold: SymbolExportLevel,
exports: FxHashMap<CrateNum, Vec<(String, DefId, SymbolExportLevel)>>,
local_exports: NodeSet,
}

impl ExportedSymbols {
pub fn empty() -> ExportedSymbols {
ExportedSymbols {
export_threshold: SymbolExportLevel::C,
exports: FxHashMap(),
local_exports: NodeSet(),
}
}

pub fn compute<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> ExportedSymbols {
let mut local_crate: Vec<_> = scx
.exported_symbols()
pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
local_exported_symbols: &NodeSet)
-> ExportedSymbols {
let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow());

let mut local_crate: Vec<_> = local_exported_symbols
.iter()
.map(|&node_id| {
scx.tcx().hir.local_def_id(node_id)
tcx.hir.local_def_id(node_id)
})
.map(|def_id| {
let name = scx.tcx().symbol_name(Instance::mono(scx.tcx(), def_id));
let export_level = export_level(scx, def_id);
let name = tcx.symbol_name(Instance::mono(tcx, def_id));
let export_level = export_level(tcx, def_id);
debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
(str::to_owned(&name), export_level)
(str::to_owned(&name), def_id, export_level)
})
.collect();

if scx.sess().entry_fn.borrow().is_some() {
local_crate.push(("main".to_string(), SymbolExportLevel::C));
let mut local_exports = local_crate
.iter()
.filter_map(|&(_, def_id, level)| {
if is_below_threshold(level, export_threshold) {
tcx.hir.as_local_node_id(def_id)
} else {
None
}
})
.collect::<NodeSet>();

const INVALID_DEF_ID: DefId = DefId {
krate: INVALID_CRATE,
index: CRATE_DEF_INDEX,
};

if let Some(_) = *tcx.sess.entry_fn.borrow() {
local_crate.push(("main".to_string(),
INVALID_DEF_ID,
SymbolExportLevel::C));
}

if let Some(id) = scx.sess().derive_registrar_fn.get() {
let def_id = scx.tcx().hir.local_def_id(id);
if let Some(id) = tcx.sess.derive_registrar_fn.get() {
let def_id = tcx.hir.local_def_id(id);
let idx = def_id.index;
let disambiguator = scx.sess().local_crate_disambiguator();
let registrar = scx.sess().generate_derive_registrar_symbol(disambiguator, idx);
local_crate.push((registrar, SymbolExportLevel::C));
let disambiguator = tcx.sess.local_crate_disambiguator();
let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
local_crate.push((registrar, def_id, SymbolExportLevel::C));
local_exports.insert(id);
}

if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
local_crate.push((metadata_symbol_name(scx.tcx()),
if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
local_crate.push((metadata_symbol_name(tcx),
INVALID_DEF_ID,
SymbolExportLevel::Rust));
}

let mut exports = FxHashMap();
exports.insert(LOCAL_CRATE, local_crate);

for cnum in scx.sess().cstore.crates() {
for cnum in tcx.sess.cstore.crates() {
debug_assert!(cnum != LOCAL_CRATE);

// If this crate is a plugin and/or a custom derive crate, then
// we're not even going to link those in so we skip those crates.
if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
if tcx.sess.cstore.plugin_registrar_fn(cnum).is_some() ||
tcx.sess.cstore.derive_registrar_fn(cnum).is_some() {
continue;
}

Expand All @@ -92,16 +119,16 @@ impl ExportedSymbols {
// Down below we'll hardwire all of the symbols to the `Rust` export
// level instead.
let special_runtime_crate =
scx.tcx().is_panic_runtime(cnum.as_def_id()) ||
scx.sess().cstore.is_compiler_builtins(cnum);
tcx.is_panic_runtime(cnum.as_def_id()) ||
tcx.sess.cstore.is_compiler_builtins(cnum);

let crate_exports = scx
.sess()
let crate_exports = tcx
.sess
.cstore
.exported_symbols(cnum)
.iter()
.map(|&def_id| {
let name = scx.tcx().symbol_name(Instance::mono(scx.tcx(), def_id));
let name = tcx.symbol_name(Instance::mono(tcx, def_id));
let export_level = if special_runtime_crate {
// We can probably do better here by just ensuring that
// it has hidden visibility rather than public
Expand All @@ -118,35 +145,41 @@ impl ExportedSymbols {
SymbolExportLevel::Rust
}
} else {
export_level(scx, def_id)
export_level(tcx, def_id)
};
debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
(str::to_owned(&name), export_level)
(str::to_owned(&name), def_id, export_level)
})
.collect();

exports.insert(cnum, crate_exports);
}

return ExportedSymbols {
exports: exports
export_threshold,
exports,
local_exports,
};

fn export_level(scx: &SharedCrateContext,
fn export_level(tcx: TyCtxt,
sym_def_id: DefId)
-> SymbolExportLevel {
let attrs = scx.tcx().get_attrs(sym_def_id);
if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
let attrs = tcx.get_attrs(sym_def_id);
if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) {
SymbolExportLevel::C
} else {
SymbolExportLevel::Rust
}
}
}

pub fn local_exports(&self) -> &NodeSet {
&self.local_exports
}

pub fn exported_symbols(&self,
cnum: CrateNum)
-> &[(String, SymbolExportLevel)] {
-> &[(String, DefId, SymbolExportLevel)] {
match self.exports.get(&cnum) {
Some(exports) => exports,
None => &[]
Expand All @@ -155,13 +188,12 @@ impl ExportedSymbols {

pub fn for_each_exported_symbol<F>(&self,
cnum: CrateNum,
export_threshold: SymbolExportLevel,
mut f: F)
where F: FnMut(&str, SymbolExportLevel)
where F: FnMut(&str, DefId, SymbolExportLevel)
{
for &(ref name, export_level) in self.exported_symbols(cnum) {
if is_below_threshold(export_level, export_threshold) {
f(&name, export_level)
for &(ref name, def_id, export_level) in self.exported_symbols(cnum) {
if is_below_threshold(export_level, self.export_threshold) {
f(&name, def_id, export_level)
}
}
}
Expand Down

0 comments on commit 2f07eb3

Please sign in to comment.