Skip to content

Commit

Permalink
Refactor symbol export list generation.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelwoerister committed Dec 5, 2016
1 parent 5fd7c2b commit 133aeac
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 170 deletions.
3 changes: 3 additions & 0 deletions src/librustc/middle/cstore.rs
Expand Up @@ -328,6 +328,7 @@ pub trait CrateStore<'tcx> {
fn crate_hash(&self, cnum: CrateNum) -> Svh;
fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol;
fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>;
fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId>;
fn is_no_builtins(&self, cnum: CrateNum) -> bool;
Expand Down Expand Up @@ -491,6 +492,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
-> Symbol { bug!("crate_disambiguator") }
fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
{ bug!("plugin_registrar_fn") }
fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
{ bug!("derive_registrar_fn") }
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
{ bug!("native_libraries") }
fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId> { bug!("exported_symbols") }
Expand Down
8 changes: 8 additions & 0 deletions src/librustc_metadata/cstore_impl.rs
Expand Up @@ -306,6 +306,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
})
}

fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
{
self.get_crate_data(cnum).root.macro_derive_registrar.map(|index| DefId {
krate: cnum,
index: index
})
}

fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
{
self.get_crate_data(cnum).get_native_libraries()
Expand Down
54 changes: 20 additions & 34 deletions src/librustc_trans/back/linker.rs
Expand Up @@ -17,11 +17,11 @@ use std::path::{Path, PathBuf};
use std::process::Command;

use context::SharedCrateContext;
use monomorphize::Instance;

use back::archive;
use back::symbol_export::{self, ExportedSymbols};
use middle::dependency_format::Linkage;
use rustc::hir::def_id::CrateNum;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use session::Session;
use session::config::CrateType;
use session::config;
Expand All @@ -34,7 +34,7 @@ pub struct LinkerInfo {

impl<'a, 'tcx> LinkerInfo {
pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
exports: &[String]) -> LinkerInfo {
exports: &ExportedSymbols) -> LinkerInfo {
LinkerInfo {
exports: scx.sess().crate_types.borrow().iter().map(|&c| {
(c, exported_symbols(scx, exports, c))
Expand Down Expand Up @@ -473,43 +473,29 @@ impl<'a> Linker for MsvcLinker<'a> {
}

fn exported_symbols(scx: &SharedCrateContext,
exported_symbols: &[String],
exported_symbols: &ExportedSymbols,
crate_type: CrateType)
-> Vec<String> {
// See explanation in GnuLinker::export_symbols, for
// why we don't ever need dylib symbols on non-MSVC.
if crate_type == CrateType::CrateTypeDylib ||
crate_type == CrateType::CrateTypeProcMacro {
if !scx.sess().target.target.options.is_like_msvc {
return vec![];
}
}

let mut symbols = exported_symbols.to_vec();
let export_threshold = symbol_export::crate_export_threshold(crate_type);

// If we're producing anything other than a dylib then the `reachable` array
// above is the exhaustive set of symbols we should be exporting.
//
// For dylibs, however, we need to take a look at how all upstream crates
// are linked into this dynamic library. For all statically linked
// libraries we take all their reachable symbols and emit them as well.
if crate_type != CrateType::CrateTypeDylib {
return symbols
}
let mut symbols = Vec::new();
exported_symbols.for_each_exported_symbol(LOCAL_CRATE, export_threshold, |name, _| {
symbols.push(name.to_owned());
});

let cstore = &scx.sess().cstore;
let formats = scx.sess().dependency_formats.borrow();
let deps = formats[&crate_type].iter();
symbols.extend(deps.enumerate().filter_map(|(i, f)| {
if *f == Linkage::Static {
Some(CrateNum::new(i + 1))
} else {
None

for (index, dep_format) in deps.enumerate() {
let cnum = CrateNum::new(index + 1);
// 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, _| {
symbols.push(name.to_owned());
})
}
}).flat_map(|cnum| {
cstore.exported_symbols(cnum)
}).map(|did| -> String {
Instance::mono(scx, did).symbol_name(scx)
}));
}

symbols
}
65 changes: 50 additions & 15 deletions src/librustc_trans/back/lto.rs
Expand Up @@ -8,14 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::link;
use super::write;
use back::link;
use back::write;
use back::symbol_export::{self, ExportedSymbols};
use rustc::session::{self, config};
use llvm;
use llvm::archive_ro::ArchiveRO;
use llvm::{ModuleRef, TargetMachineRef, True, False};
use rustc::util::common::time;
use rustc::util::common::path2cstr;
use rustc::hir::def_id::LOCAL_CRATE;
use back::write::{ModuleConfig, with_llvm_pmb};

use libc;
Expand All @@ -24,8 +26,23 @@ use flate;
use std::ffi::CString;
use std::path::Path;

pub fn run(sess: &session::Session, llmod: ModuleRef,
tm: TargetMachineRef, exported_symbols: &[String],
pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
match crate_type {
config::CrateTypeExecutable |
config::CrateTypeStaticlib |
config::CrateTypeCdylib => true,

config::CrateTypeDylib |
config::CrateTypeRlib |
config::CrateTypeMetadata |
config::CrateTypeProcMacro => false,
}
}

pub fn run(sess: &session::Session,
llmod: ModuleRef,
tm: TargetMachineRef,
exported_symbols: &ExportedSymbols,
config: &ModuleConfig,
temp_no_opt_bc_filename: &Path) {
if sess.opts.cg.prefer_dynamic {
Expand All @@ -38,17 +55,31 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,

// Make sure we actually can run LTO
for crate_type in sess.crate_types.borrow().iter() {
match *crate_type {
config::CrateTypeExecutable |
config::CrateTypeCdylib |
config::CrateTypeStaticlib => {}
_ => {
sess.fatal("lto can only be run for executables and \
if !crate_type_allows_lto(*crate_type) {
sess.fatal("lto can only be run for executables and \
static library outputs");
}
}
}

let export_threshold =
symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]);

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());
Some(CString::new(bytes).unwrap())
} else {
None
}
};

let mut symbol_white_list: Vec<CString> = exported_symbols
.exported_symbols(LOCAL_CRATE)
.iter()
.filter_map(symbol_filter)
.collect();

// For each of our upstream dependencies, find the corresponding rlib and
// load the bitcode from the archive. Then merge it into the current LLVM
// module that we've got.
Expand All @@ -58,6 +89,11 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
return;
}

symbol_white_list.extend(
exported_symbols.exported_symbols(cnum)
.iter()
.filter_map(symbol_filter));

let archive = ArchiveRO::open(&path).expect("wanted an rlib");
let bytecodes = archive.iter().filter_map(|child| {
child.ok().and_then(|c| c.name().map(|name| (name, c)))
Expand Down Expand Up @@ -119,10 +155,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
});

// Internalize everything but the exported symbols of the current module
let cstrs: Vec<CString> = exported_symbols.iter().map(|s| {
CString::new(s.clone()).unwrap()
}).collect();
let arr: Vec<*const libc::c_char> = cstrs.iter().map(|c| c.as_ptr()).collect();
let arr: Vec<*const libc::c_char> = symbol_white_list.iter()
.map(|c| c.as_ptr())
.collect();
let ptr = arr.as_ptr();
unsafe {
llvm::LLVMRustRunRestrictionPass(llmod,
Expand Down

0 comments on commit 133aeac

Please sign in to comment.