From 133aeacf2f28b985bba88eebc08c7a9924453738 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 30 Nov 2016 10:03:42 -0500 Subject: [PATCH] Refactor symbol export list generation. --- src/librustc/middle/cstore.rs | 3 + src/librustc_metadata/cstore_impl.rs | 8 + src/librustc_trans/back/linker.rs | 54 ++--- src/librustc_trans/back/lto.rs | 65 ++++-- src/librustc_trans/back/symbol_export.rs | 185 +++++++++++++++++ src/librustc_trans/back/write.rs | 9 +- src/librustc_trans/base.rs | 210 +++++++++----------- src/librustc_trans/lib.rs | 3 +- src/test/run-make/sepcomp-inlining/Makefile | 4 +- 9 files changed, 371 insertions(+), 170 deletions(-) create mode 100644 src/librustc_trans/back/symbol_export.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 34224b924b9..4357518b332 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -328,6 +328,7 @@ fn dylib_dependency_formats(&self, cnum: CrateNum) fn crate_hash(&self, cnum: CrateNum) -> Svh; fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option; fn native_libraries(&self, cnum: CrateNum) -> Vec; fn exported_symbols(&self, cnum: CrateNum) -> Vec; fn is_no_builtins(&self, cnum: CrateNum) -> bool; @@ -491,6 +492,8 @@ fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol { bug!("crate_disambiguator") } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option + { bug!("derive_registrar_fn") } fn native_libraries(&self, cnum: CrateNum) -> Vec { bug!("native_libraries") } fn exported_symbols(&self, cnum: CrateNum) -> Vec { bug!("exported_symbols") } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2965e545eca..aca1d2f7612 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -306,6 +306,14 @@ fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option }) } + fn derive_registrar_fn(&self, cnum: CrateNum) -> Option + { + self.get_crate_data(cnum).root.macro_derive_registrar.map(|index| DefId { + krate: cnum, + index: index + }) + } + fn native_libraries(&self, cnum: CrateNum) -> Vec { self.get_crate_data(cnum).get_native_libraries() diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index b8d5fc9042f..933813ac4d9 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -17,11 +17,11 @@ 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; @@ -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)) @@ -473,43 +473,29 @@ fn subsystem(&mut self, subsystem: &str) { } fn exported_symbols(scx: &SharedCrateContext, - exported_symbols: &[String], + exported_symbols: &ExportedSymbols, crate_type: CrateType) -> Vec { - // 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 } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 46b1241de36..1960b368278 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -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; @@ -24,8 +26,23 @@ 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 { @@ -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 = 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. @@ -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))) @@ -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 = 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, diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs new file mode 100644 index 00000000000..2290cb0f487 --- /dev/null +++ b/src/librustc_trans/back/symbol_export.rs @@ -0,0 +1,185 @@ +// 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 symbol_map::SymbolMap; +use util::nodemap::FxHashMap; +use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; +use rustc::session::config; +use syntax::attr; +use trans_item::TransItem; + +/// The SymbolExportLevel of a symbols specifies from which kinds of crates +/// the symbol will be exported. `C` symbols will be exported from any +/// kind of crate, including cdylibs which export very few things. +/// `Rust` will only be exported if the crate produced is a Rust +/// dylib. +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum SymbolExportLevel { + C, + Rust, +} + +/// The set of symbols exported from each crate in the crate graph. +pub struct ExportedSymbols { + exports: FxHashMap>, +} + +impl ExportedSymbols { + + pub fn empty() -> ExportedSymbols { + ExportedSymbols { + exports: FxHashMap(), + } + } + + pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + symbol_map: &SymbolMap<'tcx>) + -> ExportedSymbols { + let mut local_crate: Vec<_> = scx + .exported_symbols() + .iter() + .map(|&node_id| { + scx.tcx().map.local_def_id(node_id) + }) + .map(|def_id| { + (symbol_for_def_id(scx, def_id, symbol_map), + export_level(scx, def_id)) + }) + .collect(); + + if scx.sess().entry_fn.borrow().is_some() { + local_crate.push(("main".to_string(), SymbolExportLevel::C)); + } + + if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) { + local_crate.push((scx.metadata_symbol_name(), + SymbolExportLevel::Rust)); + } + + let mut exports = FxHashMap(); + exports.insert(LOCAL_CRATE, local_crate); + + for cnum in scx.sess().cstore.crates() { + debug_assert!(cnum != LOCAL_CRATE); + + if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() || + scx.sess().cstore.derive_registrar_fn(cnum).is_some() { + continue; + } + + let crate_exports = scx + .sess() + .cstore + .exported_symbols(cnum) + .iter() + .map(|&def_id| { + debug!("EXTERN-SYMBOL: {:?}", def_id); + let name = Instance::mono(scx, def_id).symbol_name(scx); + (name, export_level(scx, def_id)) + }) + .collect(); + + exports.insert(cnum, crate_exports); + } + + return ExportedSymbols { + exports: exports + }; + + fn export_level(scx: &SharedCrateContext, + sym_def_id: DefId) + -> SymbolExportLevel { + let attrs = scx.tcx().get_attrs(sym_def_id); + if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) { + SymbolExportLevel::C + } else { + SymbolExportLevel::Rust + } + } + } + + pub fn exported_symbols(&self, + cnum: CrateNum) + -> &[(String, SymbolExportLevel)] { + match self.exports.get(&cnum) { + Some(exports) => &exports[..], + None => &[] + } + } + + pub fn for_each_exported_symbol(&self, + cnum: CrateNum, + export_threshold: SymbolExportLevel, + mut f: F) + where F: FnMut(&str, SymbolExportLevel) + { + for &(ref name, export_level) in self.exported_symbols(cnum) { + if is_below_threshold(export_level, export_threshold) { + f(&name[..], export_level) + } + } + } +} + +pub fn crate_export_threshold(crate_type: config::CrateType) + -> SymbolExportLevel { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeCdylib => SymbolExportLevel::C, + config::CrateTypeProcMacro | + config::CrateTypeRlib | + config::CrateTypeMetadata | + config::CrateTypeDylib => SymbolExportLevel::Rust, + } +} + +pub fn crates_export_threshold(crate_types: &[config::CrateType]) + -> SymbolExportLevel { + if crate_types.iter().any(|&crate_type| { + crate_export_threshold(crate_type) == SymbolExportLevel::Rust + }) { + SymbolExportLevel::Rust + } else { + SymbolExportLevel::C + } +} + +pub fn is_below_threshold(level: SymbolExportLevel, + threshold: SymbolExportLevel) + -> bool { + if threshold == SymbolExportLevel::Rust { + // We export everything from Rust dylibs + true + } else { + level == SymbolExportLevel::C + } +} + +fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, + def_id: DefId, + 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/back/write.rs b/src/librustc_trans/back/write.rs index 84bba64dd70..ffab0bde7ab 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,6 +10,7 @@ use back::lto; use back::link::{get_linker, remove}; +use back::symbol_export::ExportedSymbols; use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; use session::Session; @@ -328,7 +329,7 @@ fn set_flags(&mut self, sess: &Session, trans: &CrateTranslation) { struct CodegenContext<'a> { // Extra resources used for LTO: (sess, reachable). This will be `None` // when running in a worker thread. - lto_ctxt: Option<(&'a Session, &'a [String])>, + lto_ctxt: Option<(&'a Session, &'a ExportedSymbols)>, // Handler to use for diagnostics produced during codegen. handler: &'a Handler, // LLVM passes added by plugins. @@ -343,7 +344,9 @@ struct CodegenContext<'a> { } impl<'a> CodegenContext<'a> { - fn new_with_session(sess: &'a Session, exported_symbols: &'a [String]) -> CodegenContext<'a> { + fn new_with_session(sess: &'a Session, + exported_symbols: &'a ExportedSymbols) + -> CodegenContext<'a> { CodegenContext { lto_ctxt: Some((sess, exported_symbols)), handler: sess.diagnostic(), @@ -997,7 +1000,7 @@ fn execute_work_item(cgcx: &CodegenContext, } fn run_work_singlethreaded(sess: &Session, - exported_symbols: &[String], + exported_symbols: &ExportedSymbols, work_items: Vec) { let cgcx = CodegenContext::new_with_session(sess, exported_symbols); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 74e6a1dac80..a31b61e42c4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -33,10 +33,10 @@ use assert_module_sources; use back::link; use back::linker::LinkerInfo; +use back::symbol_export::{self, ExportedSymbols}; use llvm::{Linkage, ValueRef, Vector, get_param}; use llvm; -use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use rustc::ty::subst::Substs; use rustc::traits; @@ -84,7 +84,6 @@ use arena::TypedArena; use libc::c_uint; use std::ffi::{CStr, CString}; -use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::ptr; use std::rc::Rc; @@ -1313,16 +1312,23 @@ enum MetadataKind { fn internalize_symbols<'a, 'tcx>(sess: &Session, ccxs: &CrateContextList<'a, 'tcx>, symbol_map: &SymbolMap<'tcx>, - exported_symbols: &FxHashSet<&str>) { + exported_symbols: &ExportedSymbols) { + let export_threshold = + symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + + let exported_symbols = exported_symbols + .exported_symbols(LOCAL_CRATE) + .iter() + .filter(|&&(_, export_level)| { + symbol_export::is_below_threshold(export_level, export_threshold) + }) + .map(|&(ref name, _)| &name[..]) + .collect::>(); + let scx = ccxs.shared(); let tcx = scx.tcx(); - // In incr. comp. mode, we can't necessarily see all refs since we - // don't generate LLVM IR for reused modules, so skip this - // step. Later we should get smarter. - if sess.opts.debugging_opts.incremental.is_some() { - return; - } + let incr_comp = sess.opts.debugging_opts.incremental.is_some(); // 'unsafe' because we are holding on to CStr's from the LLVM module within // this block. @@ -1330,34 +1336,43 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let mut referenced_somewhere = FxHashSet(); // Collect all symbols that need to stay externally visible because they - // are referenced via a declaration in some other codegen unit. - for ccx in ccxs.iter_need_trans() { - for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { - let linkage = llvm::LLVMRustGetLinkage(val); - // We only care about external declarations (not definitions) - // and available_externally definitions. - let is_available_externally = linkage == llvm::Linkage::AvailableExternallyLinkage; - let is_decl = llvm::LLVMIsDeclaration(val) != 0; - - if is_decl || is_available_externally { - let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); - referenced_somewhere.insert(symbol_name); + // are referenced via a declaration in some other codegen unit. In + // incremental compilation, we don't need to collect. See below for more + // information. + if !incr_comp { + for ccx in ccxs.iter_need_trans() { + for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { + let linkage = llvm::LLVMRustGetLinkage(val); + // We only care about external declarations (not definitions) + // and available_externally definitions. + let is_available_externally = + linkage == llvm::Linkage::AvailableExternallyLinkage; + let is_decl = llvm::LLVMIsDeclaration(val) == llvm::True; + + if is_decl || is_available_externally { + let symbol_name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + referenced_somewhere.insert(symbol_name); + } } } } // Also collect all symbols for which we cannot adjust linkage, because - // it is fixed by some directive in the source code (e.g. #[no_mangle]). - let linkage_fixed_explicitly: FxHashSet<_> = scx - .translation_items() - .borrow() - .iter() - .cloned() - .filter(|trans_item|{ - trans_item.explicit_linkage(tcx).is_some() - }) - .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) - .collect(); + // it is fixed by some directive in the source code. + let (locally_defined_symbols, linkage_fixed_explicitly) = { + let mut locally_defined_symbols = FxHashSet(); + let mut linkage_fixed_explicitly = FxHashSet(); + + for trans_item in scx.translation_items().borrow().iter() { + let symbol_name = symbol_map.get_or_compute(scx, *trans_item); + if trans_item.explicit_linkage(tcx).is_some() { + linkage_fixed_explicitly.insert(symbol_name.clone()); + } + locally_defined_symbols.insert(symbol_name); + } + + (locally_defined_symbols, linkage_fixed_explicitly) + }; // Examine each external definition. If the definition is not used in // any other compilation unit, and is not reachable from other crates, @@ -1369,23 +1384,46 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) || (linkage == llvm::Linkage::LinkOnceODRLinkage) || (linkage == llvm::Linkage::WeakODRLinkage); - let is_definition = llvm::LLVMIsDeclaration(val) == 0; - - // If this is a definition (as opposed to just a declaration) - // and externally visible, check if we can internalize it - if is_definition && is_externally_visible { - let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); - let name_str = name_cstr.to_str().unwrap(); - let name_cow = Cow::Borrowed(name_str); - - let is_referenced_somewhere = referenced_somewhere.contains(&name_cstr); - let is_reachable = exported_symbols.contains(&name_str); - let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow); - - if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage { - llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage); - llvm::LLVMSetDLLStorageClass(val, - llvm::DLLStorageClass::Default); + + if !is_externally_visible { + // This symbol is not visible outside of its codegen unit, + // so there is nothing to do for it. + continue; + } + + let name_cstr = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let name_str = name_cstr.to_str().unwrap(); + + if exported_symbols.contains(&name_str) { + // This symbol is explicitly exported, so we can't + // mark it as internal or hidden. + continue; + } + + let is_declaration = llvm::LLVMIsDeclaration(val) == llvm::True; + + if is_declaration { + if locally_defined_symbols.contains(name_str) { + // Only mark declarations from the current crate as hidden. + // Otherwise we would mark things as hidden that are + // imported from other crates or native libraries. + llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden); + } + } else { + let has_fixed_linkage = linkage_fixed_explicitly.contains(name_str); + + if !has_fixed_linkage { + // In incremental compilation mode, we can't be sure that + // we saw all references because we don't know what's in + // cached compilation units, so we always assume that the + // given item has been referenced. + if incr_comp || referenced_somewhere.contains(&name_cstr) { + llvm::LLVMRustSetVisibility(val, llvm::Visibility::Hidden); + } else { + llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage); + } + + llvm::LLVMSetDLLStorageClass(val, llvm::DLLStorageClass::Default); llvm::UnsetComdat(val); } } @@ -1602,13 +1640,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) { - let linker_info = LinkerInfo::new(&shared_ccx, &[]); + let linker_info = LinkerInfo::new(&shared_ccx, &ExportedSymbols::empty()); return CrateTranslation { modules: modules, metadata_module: metadata_module, link: link_meta, metadata: metadata, - exported_symbols: vec![], + exported_symbols: ExportedSymbols::empty(), no_builtins: no_builtins, linker_info: linker_info, windows_subsystem: None, @@ -1688,56 +1726,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let sess = shared_ccx.sess(); - let mut exported_symbols = shared_ccx.exported_symbols().iter().map(|&id| { - let def_id = shared_ccx.tcx().map.local_def_id(id); - symbol_for_def_id(def_id, &shared_ccx, &symbol_map) - }).collect::>(); - - if sess.entry_fn.borrow().is_some() { - exported_symbols.push("main".to_string()); - } - - if sess.crate_types.borrow().contains(&config::CrateTypeDylib) { - exported_symbols.push(shared_ccx.metadata_symbol_name()); - } - // For the purposes of LTO or when creating a cdylib, we add to the - // reachable set all of the upstream reachable extern fns. These functions - // are all part of the public ABI of the final product, so we need to - // preserve them. - // - // Note that this happens even if LTO isn't requested or we're not creating - // a cdylib. In those cases, though, we're not even reading the - // `exported_symbols` list later on so it should be ok. - for cnum in sess.cstore.crates() { - let syms = sess.cstore.exported_symbols(cnum); - exported_symbols.extend(syms.into_iter().filter(|&def_id| { - let applicable = match sess.cstore.describe_def(def_id) { - Some(Def::Static(..)) => true, - Some(Def::Fn(_)) => { - shared_ccx.tcx().item_generics(def_id).types.is_empty() - } - _ => false - }; - - if applicable { - let attrs = shared_ccx.tcx().get_attrs(def_id); - attr::contains_extern_indicator(sess.diagnostic(), &attrs) - } else { - false - } - }).map(|did| { - symbol_for_def_id(did, &shared_ccx, &symbol_map) - })); - } + let exported_symbols = ExportedSymbols::compute_from(&shared_ccx, + &symbol_map); + // Now that we have all symbols that are exported from the CGUs of this + // crate, we can run the `internalize_symbols` pass. time(shared_ccx.sess().time_passes(), "internalize symbols", || { internalize_symbols(sess, &crate_context_list, &symbol_map, - &exported_symbols.iter() - .map(|s| &s[..]) - .collect()) + &exported_symbols); }); if tcx.sess.opts.debugging_opts.print_type_sizes { @@ -2107,22 +2106,3 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a (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/lib.rs b/src/librustc_trans/lib.rs index 8a7ab16ee2b..e2da635b159 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -78,6 +78,7 @@ pub mod back { pub mod linker; pub mod link; pub mod lto; + pub mod symbol_export; pub mod symbol_names; pub mod write; pub mod msvc; @@ -169,7 +170,7 @@ pub struct CrateTranslation { pub metadata_module: ModuleTranslation, pub link: middle::cstore::LinkMeta, pub metadata: Vec, - pub exported_symbols: Vec, + pub exported_symbols: back::symbol_export::ExportedSymbols, pub no_builtins: bool, pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile index ef43b0d97e4..720dfff2c04 100644 --- a/src/test/run-make/sepcomp-inlining/Makefile +++ b/src/test/run-make/sepcomp-inlining/Makefile @@ -10,5 +10,5 @@ all: $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ i32\ .*normal)" -eq "2" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ hidden\ i32\ .*normal)" -eq "1" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ hidden\ i32\ .*normal)" -eq "2" ] -- 2.44.0