]> git.proxmox.com Git - rustc.git/blob - src/librustc_codegen_llvm/back/symbol_export.rs
New upstream version 1.28.0~beta.14+dfsg1
[rustc.git] / src / librustc_codegen_llvm / back / symbol_export.rs
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.
4 //
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.
10
11 use rustc_data_structures::sync::Lrc;
12 use std::sync::Arc;
13
14 use monomorphize::Instance;
15 use rustc::hir;
16 use rustc::hir::CodegenFnAttrFlags;
17 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
18 use rustc::ich::Fingerprint;
19 use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
20 use rustc::session::config;
21 use rustc::ty::{TyCtxt, SymbolName};
22 use rustc::ty::query::Providers;
23 use rustc::ty::subst::Substs;
24 use rustc::util::nodemap::{FxHashMap, DefIdMap};
25 use rustc_allocator::ALLOCATOR_METHODS;
26 use rustc_data_structures::indexed_vec::IndexVec;
27 use std::collections::hash_map::Entry::*;
28
29 pub type ExportedSymbols = FxHashMap<
30 CrateNum,
31 Arc<Vec<(String, SymbolExportLevel)>>,
32 >;
33
34 pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
35 crates_export_threshold(&tcx.sess.crate_types.borrow())
36 }
37
38 fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
39 match crate_type {
40 config::CrateTypeExecutable |
41 config::CrateTypeStaticlib |
42 config::CrateTypeProcMacro |
43 config::CrateTypeCdylib => SymbolExportLevel::C,
44 config::CrateTypeRlib |
45 config::CrateTypeDylib => SymbolExportLevel::Rust,
46 }
47 }
48
49 pub fn crates_export_threshold(crate_types: &[config::CrateType])
50 -> SymbolExportLevel {
51 if crate_types.iter().any(|&crate_type| {
52 crate_export_threshold(crate_type) == SymbolExportLevel::Rust
53 }) {
54 SymbolExportLevel::Rust
55 } else {
56 SymbolExportLevel::C
57 }
58 }
59
60 fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
61 cnum: CrateNum)
62 -> Lrc<DefIdMap<SymbolExportLevel>>
63 {
64 assert_eq!(cnum, LOCAL_CRATE);
65
66 if !tcx.sess.opts.output_types.should_codegen() {
67 return Lrc::new(DefIdMap())
68 }
69
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
76 // level instead.
77 let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
78 tcx.is_compiler_builtins(LOCAL_CRATE);
79
80 let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0
81 .iter()
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
85 // categories:
86 //
87 // 1. Those that are included statically via a static library
88 // 2. Those included otherwise (e.g. dynamically or via a framework)
89 //
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.
93 //
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 hir::map::NodeForeignItem(..) => {
98 let def_id = tcx.hir.local_def_id(node_id);
99 if tcx.is_statically_included_foreign_item(def_id) {
100 Some(def_id)
101 } else {
102 None
103 }
104 }
105
106 // Only consider nodes that actually have exported symbols.
107 hir::map::NodeItem(&hir::Item {
108 node: hir::ItemStatic(..),
109 ..
110 }) |
111 hir::map::NodeItem(&hir::Item {
112 node: hir::ItemFn(..), ..
113 }) |
114 hir::map::NodeImplItem(&hir::ImplItem {
115 node: hir::ImplItemKind::Method(..),
116 ..
117 }) => {
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) {
124 Some(def_id)
125 } else {
126 None
127 }
128 }
129
130 _ => None
131 }
132 })
133 .map(|def_id| {
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.
140 //
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" {
146 SymbolExportLevel::C
147 } else {
148 SymbolExportLevel::Rust
149 }
150 } else {
151 symbol_export_level(tcx, def_id)
152 };
153 debug!("EXPORTED SYMBOL (local): {} ({:?})",
154 tcx.symbol_name(Instance::mono(tcx, def_id)),
155 export_level);
156 (def_id, export_level)
157 })
158 .collect();
159
160 if let Some(id) = *tcx.sess.derive_registrar_fn.get() {
161 let def_id = tcx.hir.local_def_id(id);
162 reachable_non_generics.insert(def_id, SymbolExportLevel::C);
163 }
164
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);
168 }
169
170 Lrc::new(reachable_non_generics)
171 }
172
173 fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
174 def_id: DefId)
175 -> bool {
176 let export_threshold = threshold(tcx);
177
178 if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
179 level.is_below_threshold(export_threshold)
180 } else {
181 false
182 }
183 }
184
185 fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
186 def_id: DefId)
187 -> bool {
188 tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
189 }
190
191 fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
192 cnum: CrateNum)
193 -> Arc<Vec<(ExportedSymbol<'tcx>,
194 SymbolExportLevel)>>
195 {
196 assert_eq!(cnum, LOCAL_CRATE);
197
198 if !tcx.sess.opts.output_types.should_codegen() {
199 return Arc::new(vec![])
200 }
201
202 let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE)
203 .iter()
204 .map(|(&def_id, &level)| {
205 (ExportedSymbol::NonGeneric(def_id), level)
206 })
207 .collect();
208
209 if let Some(_) = *tcx.sess.entry_fn.borrow() {
210 let symbol_name = "main".to_string();
211 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
212
213 symbols.push((exported_symbol, SymbolExportLevel::C));
214 }
215
216 if tcx.sess.allocator_kind.get().is_some() {
217 for method in ALLOCATOR_METHODS {
218 let symbol_name = format!("__rust_{}", method.name);
219 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
220
221 symbols.push((exported_symbol, SymbolExportLevel::Rust));
222 }
223 }
224
225 if tcx.sess.opts.debugging_opts.pgo_gen.is_some() {
226 // These are weak symbols that point to the profile version and the
227 // profile name, which need to be treated as exported so LTO doesn't nix
228 // them.
229 const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [
230 "__llvm_profile_raw_version",
231 "__llvm_profile_filename",
232 ];
233 for sym in &PROFILER_WEAK_SYMBOLS {
234 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
235 symbols.push((exported_symbol, SymbolExportLevel::C));
236 }
237 }
238
239 if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
240 let symbol_name = metadata_symbol_name(tcx);
241 let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
242
243 symbols.push((exported_symbol, SymbolExportLevel::Rust));
244 }
245
246 if tcx.share_generics() && tcx.local_crate_exports_generics() {
247 use rustc::mir::mono::{Linkage, Visibility, MonoItem};
248 use rustc::ty::InstanceDef;
249
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;
257
258 let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
259
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
265 continue
266 }
267
268 if need_visibility && visibility == Visibility::Hidden {
269 // If we potentially share things from Rust dylibs, they must
270 // not be hidden
271 continue
272 }
273
274 if let &MonoItem::Fn(Instance {
275 def: InstanceDef::Item(def_id),
276 substs,
277 }) = mono_item {
278 if substs.types().next().is_some() {
279 symbols.push((ExportedSymbol::Generic(def_id, substs),
280 SymbolExportLevel::Rust));
281 }
282 }
283 }
284 }
285
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)
289 });
290
291 Arc::new(symbols)
292 }
293
294 fn upstream_monomorphizations_provider<'a, 'tcx>(
295 tcx: TyCtxt<'a, 'tcx, 'tcx>,
296 cnum: CrateNum)
297 -> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>
298 {
299 debug_assert!(cnum == LOCAL_CRATE);
300
301 let cnums = tcx.all_crate_nums(LOCAL_CRATE);
302
303 let mut instances = DefIdMap();
304
305 let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
306 let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO,
307 cnums.len() + 1);
308
309 for &cnum in cnums.iter() {
310 cnum_stable_ids[cnum] = tcx.def_path_hash(DefId {
311 krate: cnum,
312 index: CRATE_DEF_INDEX,
313 }).0;
314 }
315
316 cnum_stable_ids
317 };
318
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)
323 .or_insert_with(|| FxHashMap());
324
325 match substs_map.entry(substs) {
326 Occupied(mut e) => {
327 // If there are multiple monomorphizations available,
328 // we select one deterministically.
329 let other_cnum = *e.get();
330 if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
331 e.insert(cnum);
332 }
333 }
334 Vacant(e) => {
335 e.insert(cnum);
336 }
337 }
338 }
339 }
340 }
341
342 Lrc::new(instances.into_iter()
343 .map(|(key, value)| (key, Lrc::new(value)))
344 .collect())
345 }
346
347 fn upstream_monomorphizations_for_provider<'a, 'tcx>(
348 tcx: TyCtxt<'a, 'tcx, 'tcx>,
349 def_id: DefId)
350 -> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>
351 {
352 debug_assert!(!def_id.is_local());
353 tcx.upstream_monomorphizations(LOCAL_CRATE)
354 .get(&def_id)
355 .cloned()
356 }
357
358 fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool {
359 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
360 !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id)
361 } else {
362 bug!("is_unreachable_local_definition called with non-local DefId: {:?}",
363 def_id)
364 }
365 }
366
367 pub fn provide(providers: &mut Providers) {
368 providers.reachable_non_generics = reachable_non_generics_provider;
369 providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
370 providers.exported_symbols = exported_symbols_provider_local;
371 providers.upstream_monomorphizations = upstream_monomorphizations_provider;
372 providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
373 }
374
375 pub fn provide_extern(providers: &mut Providers) {
376 providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
377 providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
378 }
379
380 fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
381 // We export anything that's not mangled at the "C" layer as it probably has
382 // to do with ABI concerns. We do not, however, apply such treatment to
383 // special symbols in the standard library for various plumbing between
384 // core/std/allocators/etc. For example symbols used to hook up allocation
385 // are not considered for export
386 let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id);
387 let is_extern = codegen_fn_attrs.contains_extern_indicator();
388 let std_internal =
389 codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
390
391 if is_extern && !std_internal {
392 SymbolExportLevel::C
393 } else {
394 SymbolExportLevel::Rust
395 }
396 }