1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use rustc_data_structures::sync::Lrc;
14 use rustc::ty::Instance;
17 use rustc::hir::CodegenFnAttrFlags;
18 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
19 use rustc_data_structures::fingerprint::Fingerprint;
20 use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
21 use rustc::session::config;
22 use rustc::ty::{TyCtxt, SymbolName};
23 use rustc::ty::query::Providers;
24 use rustc::ty::subst::Substs;
25 use rustc::util::nodemap::{FxHashMap, DefIdMap};
26 use rustc_allocator::ALLOCATOR_METHODS;
27 use rustc_data_structures::indexed_vec::IndexVec;
28 use std::collections::hash_map::Entry::*;
30 pub type ExportedSymbols = FxHashMap<
32 Arc<Vec<(String, SymbolExportLevel)>>,
35 pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
36 crates_export_threshold(&tcx.sess.crate_types.borrow())
39 fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
41 config::CrateType::Executable |
42 config::CrateType::Staticlib |
43 config::CrateType::ProcMacro |
44 config::CrateType::Cdylib => SymbolExportLevel::C,
45 config::CrateType::Rlib |
46 config::CrateType::Dylib => SymbolExportLevel::Rust,
50 pub fn crates_export_threshold(crate_types: &[config::CrateType]) -> SymbolExportLevel {
51 if crate_types.iter().any(|&crate_type|
52 crate_export_threshold(crate_type) == SymbolExportLevel::Rust)
54 SymbolExportLevel::Rust
60 fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
62 -> Lrc<DefIdMap<SymbolExportLevel>>
64 assert_eq!(cnum, LOCAL_CRATE);
66 if !tcx.sess.opts.output_types.should_codegen() {
67 return Default::default();
70 // Check to see if this crate is a "special runtime crate". These
71 // crates, implementation details of the standard library, typically
72 // have a bunch of `pub extern` and `#[no_mangle]` functions as the
73 // ABI between them. We don't want their symbols to have a `C`
74 // export level, however, as they're just implementation details.
75 // Down below we'll hardwire all of the symbols to the `Rust` export
77 let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
78 tcx.is_compiler_builtins(LOCAL_CRATE);
80 let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0
82 .filter_map(|&node_id| {
83 // We want to ignore some FFI functions that are not exposed from
84 // this crate. Reachable FFI functions can be lumped into two
87 // 1. Those that are included statically via a static library
88 // 2. Those included otherwise (e.g., dynamically or via a framework)
90 // Although our LLVM module is not literally emitting code for the
91 // statically included symbols, it's an export of our library which
92 // needs to be passed on to the linker and encoded in the metadata.
94 // As a result, if this id is an FFI item (foreign item) then we only
95 // let it through if it's included statically.
96 match tcx.hir().get(node_id) {
97 Node::ForeignItem(..) => {
98 let def_id = tcx.hir().local_def_id(node_id);
99 if tcx.is_statically_included_foreign_item(def_id) {
106 // Only consider nodes that actually have exported symbols.
107 Node::Item(&hir::Item {
108 node: hir::ItemKind::Static(..),
111 Node::Item(&hir::Item {
112 node: hir::ItemKind::Fn(..), ..
114 Node::ImplItem(&hir::ImplItem {
115 node: hir::ImplItemKind::Method(..),
118 let def_id = tcx.hir().local_def_id(node_id);
119 let generics = tcx.generics_of(def_id);
120 if !generics.requires_monomorphization(tcx) &&
121 // Functions marked with #[inline] are only ever codegened
122 // with "internal" linkage and are never exported.
123 !Instance::mono(tcx, def_id).def.requires_local(tcx) {
134 let export_level = if special_runtime_crate {
135 let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
136 // We can probably do better here by just ensuring that
137 // it has hidden visibility rather than public
138 // visibility, as this is primarily here to ensure it's
139 // not stripped during LTO.
141 // In general though we won't link right if these
142 // symbols are stripped, and LTO currently strips them.
143 if &*name == "rust_eh_personality" ||
144 &*name == "rust_eh_register_frames" ||
145 &*name == "rust_eh_unregister_frames" {
148 SymbolExportLevel::Rust
151 symbol_export_level(tcx, def_id)
153 debug!("EXPORTED SYMBOL (local): {} ({:?})",
154 tcx.symbol_name(Instance::mono(tcx, def_id)),
156 (def_id, export_level)
160 if let Some(id) = *tcx.sess.proc_macro_decls_static.get() {
161 let def_id = tcx.hir().local_def_id(id);
162 reachable_non_generics.insert(def_id, SymbolExportLevel::C);
165 if let Some(id) = *tcx.sess.plugin_registrar_fn.get() {
166 let def_id = tcx.hir().local_def_id(id);
167 reachable_non_generics.insert(def_id, SymbolExportLevel::C);
170 Lrc::new(reachable_non_generics)
173 fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
176 let export_threshold = threshold(tcx);
178 if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
179 level.is_below_threshold(export_threshold)
185 fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
188 tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
191 fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
193 -> Arc<Vec<(ExportedSymbol<'tcx>,
196 assert_eq!(cnum, LOCAL_CRATE);
198 if !tcx.sess.opts.output_types.should_codegen() {
199 return Arc::new(vec![])
202 let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE)
204 .map(|(&def_id, &level)| {
205 (ExportedSymbol::NonGeneric(def_id), level)
209 if tcx.sess.entry_fn.borrow().is_some() {
210 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main"));
212 symbols.push((exported_symbol, SymbolExportLevel::C));
215 if tcx.sess.allocator_kind.get().is_some() {
216 for method in ALLOCATOR_METHODS {
217 let symbol_name = format!("__rust_{}", method.name);
218 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
220 symbols.push((exported_symbol, SymbolExportLevel::Rust));
224 if tcx.sess.opts.debugging_opts.pgo_gen.is_some() {
225 // These are weak symbols that point to the profile version and the
226 // profile name, which need to be treated as exported so LTO doesn't nix
228 const PROFILER_WEAK_SYMBOLS: [&str; 2] = [
229 "__llvm_profile_raw_version",
230 "__llvm_profile_filename",
233 symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| {
234 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
235 (exported_symbol, SymbolExportLevel::C)
239 if tcx.sess.crate_types.borrow().contains(&config::CrateType::Dylib) {
240 let symbol_name = metadata_symbol_name(tcx);
241 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
243 symbols.push((exported_symbol, SymbolExportLevel::Rust));
246 if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
247 use rustc::mir::mono::{Linkage, Visibility, MonoItem};
248 use rustc::ty::InstanceDef;
250 // Normally, we require that shared monomorphizations are not hidden,
251 // because if we want to re-use a monomorphization from a Rust dylib, it
252 // needs to be exported.
253 // However, on platforms that don't allow for Rust dylibs, having
254 // external linkage is enough for monomorphization to be linked to.
255 let need_visibility = tcx.sess.target.target.options.dynamic_linking &&
256 !tcx.sess.target.target.options.only_cdylib;
258 let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
260 for (mono_item, &(linkage, visibility)) in cgus.iter()
261 .flat_map(|cgu| cgu.items().iter()) {
262 if linkage != Linkage::External {
263 // We can only re-use things with external linkage, otherwise
264 // we'll get a linker error
268 if need_visibility && visibility == Visibility::Hidden {
269 // If we potentially share things from Rust dylibs, they must
274 if let &MonoItem::Fn(Instance {
275 def: InstanceDef::Item(def_id),
278 if substs.types().next().is_some() {
279 symbols.push((ExportedSymbol::Generic(def_id, substs),
280 SymbolExportLevel::Rust));
286 // Sort so we get a stable incr. comp. hash.
287 symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
288 symbol1.compare_stable(tcx, symbol2)
294 fn upstream_monomorphizations_provider<'a, 'tcx>(
295 tcx: TyCtxt<'a, 'tcx, 'tcx>,
297 -> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>
299 debug_assert!(cnum == LOCAL_CRATE);
301 let cnums = tcx.all_crate_nums(LOCAL_CRATE);
303 let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
305 let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
306 let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO,
309 for &cnum in cnums.iter() {
310 cnum_stable_ids[cnum] = tcx.def_path_hash(DefId {
312 index: CRATE_DEF_INDEX,
319 for &cnum in cnums.iter() {
320 for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
321 if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol {
322 let substs_map = instances.entry(def_id).or_default();
324 match substs_map.entry(substs) {
326 // If there are multiple monomorphizations available,
327 // we select one deterministically.
328 let other_cnum = *e.get();
329 if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
341 Lrc::new(instances.into_iter()
342 .map(|(key, value)| (key, Lrc::new(value)))
346 fn upstream_monomorphizations_for_provider<'a, 'tcx>(
347 tcx: TyCtxt<'a, 'tcx, 'tcx>,
349 -> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>
351 debug_assert!(!def_id.is_local());
352 tcx.upstream_monomorphizations(LOCAL_CRATE)
357 fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool {
358 if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
359 !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id)
361 bug!("is_unreachable_local_definition called with non-local DefId: {:?}",
366 pub fn provide(providers: &mut Providers) {
367 providers.reachable_non_generics = reachable_non_generics_provider;
368 providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
369 providers.exported_symbols = exported_symbols_provider_local;
370 providers.upstream_monomorphizations = upstream_monomorphizations_provider;
371 providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
374 pub fn provide_extern(providers: &mut Providers) {
375 providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
376 providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
379 fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
380 // We export anything that's not mangled at the "C" layer as it probably has
381 // to do with ABI concerns. We do not, however, apply such treatment to
382 // special symbols in the standard library for various plumbing between
383 // core/std/allocators/etc. For example symbols used to hook up allocation
384 // are not considered for export
385 let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id);
386 let is_extern = codegen_fn_attrs.contains_extern_indicator();
388 codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
390 if is_extern && !std_internal {
391 // Emscripten cannot export statics, so reduce their export level here
392 if tcx.sess.target.target.options.is_like_emscripten {
393 if let Some(Node::Item(&hir::Item {
394 node: hir::ItemKind::Static(..),
396 })) = tcx.hir().get_if_local(sym_def_id) {
397 return SymbolExportLevel::Rust;
403 SymbolExportLevel::Rust