]>
Commit | Line | Data |
---|---|---|
416331ca | 1 | use std::collections::hash_map::Entry::*; |
ea8adc8c XL |
2 | use std::sync::Arc; |
3 | ||
a1dfa0c6 | 4 | use rustc::ty::Instance; |
0531ce1d | 5 | use rustc::hir; |
b7449926 | 6 | use rustc::hir::Node; |
94b46f34 | 7 | use rustc::hir::CodegenFnAttrFlags; |
83c7162d | 8 | use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; |
b7449926 | 9 | use rustc_data_structures::fingerprint::Fingerprint; |
0531ce1d | 10 | use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; |
476ff2be | 11 | use rustc::session::config; |
0531ce1d | 12 | use rustc::ty::{TyCtxt, SymbolName}; |
94b46f34 | 13 | use rustc::ty::query::Providers; |
532ac7d7 | 14 | use rustc::ty::subst::SubstsRef; |
83c7162d | 15 | use rustc::util::nodemap::{FxHashMap, DefIdMap}; |
e74abb32 XL |
16 | use rustc_index::vec::IndexVec; |
17 | use syntax::expand::allocator::ALLOCATOR_METHODS; | |
ea8adc8c XL |
18 | |
19 | pub type ExportedSymbols = FxHashMap< | |
20 | CrateNum, | |
0531ce1d | 21 | Arc<Vec<(String, SymbolExportLevel)>>, |
ea8adc8c XL |
22 | >; |
23 | ||
dc9dc135 | 24 | pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { |
ea8adc8c | 25 | crates_export_threshold(&tcx.sess.crate_types.borrow()) |
476ff2be SL |
26 | } |
27 | ||
ea8adc8c XL |
28 | fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { |
29 | match crate_type { | |
b7449926 XL |
30 | config::CrateType::Executable | |
31 | config::CrateType::Staticlib | | |
32 | config::CrateType::ProcMacro | | |
33 | config::CrateType::Cdylib => SymbolExportLevel::C, | |
34 | config::CrateType::Rlib | | |
35 | config::CrateType::Dylib => SymbolExportLevel::Rust, | |
476ff2be | 36 | } |
ea8adc8c | 37 | } |
476ff2be | 38 | |
a1dfa0c6 XL |
39 | pub fn crates_export_threshold(crate_types: &[config::CrateType]) -> SymbolExportLevel { |
40 | if crate_types.iter().any(|&crate_type| | |
41 | crate_export_threshold(crate_type) == SymbolExportLevel::Rust) | |
42 | { | |
ea8adc8c XL |
43 | SymbolExportLevel::Rust |
44 | } else { | |
45 | SymbolExportLevel::C | |
46 | } | |
47 | } | |
48 | ||
416331ca XL |
49 | fn reachable_non_generics_provider( |
50 | tcx: TyCtxt<'_>, | |
dc9dc135 | 51 | cnum: CrateNum, |
416331ca | 52 | ) -> &DefIdMap<SymbolExportLevel> { |
0531ce1d XL |
53 | assert_eq!(cnum, LOCAL_CRATE); |
54 | ||
94b46f34 | 55 | if !tcx.sess.opts.output_types.should_codegen() { |
dc9dc135 | 56 | return tcx.arena.alloc(Default::default()); |
0531ce1d XL |
57 | } |
58 | ||
59 | // Check to see if this crate is a "special runtime crate". These | |
60 | // crates, implementation details of the standard library, typically | |
61 | // have a bunch of `pub extern` and `#[no_mangle]` functions as the | |
62 | // ABI between them. We don't want their symbols to have a `C` | |
63 | // export level, however, as they're just implementation details. | |
64 | // Down below we'll hardwire all of the symbols to the `Rust` export | |
65 | // level instead. | |
66 | let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || | |
67 | tcx.is_compiler_builtins(LOCAL_CRATE); | |
68 | ||
83c7162d | 69 | let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0 |
0531ce1d | 70 | .iter() |
532ac7d7 | 71 | .filter_map(|&hir_id| { |
0531ce1d XL |
72 | // We want to ignore some FFI functions that are not exposed from |
73 | // this crate. Reachable FFI functions can be lumped into two | |
74 | // categories: | |
75 | // | |
76 | // 1. Those that are included statically via a static library | |
0731742a | 77 | // 2. Those included otherwise (e.g., dynamically or via a framework) |
0531ce1d XL |
78 | // |
79 | // Although our LLVM module is not literally emitting code for the | |
80 | // statically included symbols, it's an export of our library which | |
81 | // needs to be passed on to the linker and encoded in the metadata. | |
82 | // | |
83 | // As a result, if this id is an FFI item (foreign item) then we only | |
84 | // let it through if it's included statically. | |
dc9dc135 | 85 | match tcx.hir().get(hir_id) { |
b7449926 | 86 | Node::ForeignItem(..) => { |
416331ca | 87 | let def_id = tcx.hir().local_def_id(hir_id); |
60c5eb7d | 88 | tcx.is_statically_included_foreign_item(def_id).then_some(def_id) |
0531ce1d | 89 | } |
476ff2be | 90 | |
0531ce1d | 91 | // Only consider nodes that actually have exported symbols. |
b7449926 | 92 | Node::Item(&hir::Item { |
e74abb32 | 93 | kind: hir::ItemKind::Static(..), |
0531ce1d XL |
94 | .. |
95 | }) | | |
b7449926 | 96 | Node::Item(&hir::Item { |
e74abb32 | 97 | kind: hir::ItemKind::Fn(..), .. |
0531ce1d | 98 | }) | |
b7449926 | 99 | Node::ImplItem(&hir::ImplItem { |
e74abb32 | 100 | kind: hir::ImplItemKind::Method(..), |
0531ce1d XL |
101 | .. |
102 | }) => { | |
416331ca | 103 | let def_id = tcx.hir().local_def_id(hir_id); |
0531ce1d | 104 | let generics = tcx.generics_of(def_id); |
94b46f34 XL |
105 | if !generics.requires_monomorphization(tcx) && |
106 | // Functions marked with #[inline] are only ever codegened | |
0531ce1d XL |
107 | // with "internal" linkage and are never exported. |
108 | !Instance::mono(tcx, def_id).def.requires_local(tcx) { | |
109 | Some(def_id) | |
110 | } else { | |
111 | None | |
112 | } | |
113 | } | |
114 | ||
115 | _ => None | |
3b2f2976 | 116 | } |
0531ce1d | 117 | }) |
83c7162d | 118 | .map(|def_id| { |
0531ce1d | 119 | let export_level = if special_runtime_crate { |
e1599b0c | 120 | let name = tcx.symbol_name(Instance::mono(tcx, def_id)).name.as_str(); |
0531ce1d XL |
121 | // We can probably do better here by just ensuring that |
122 | // it has hidden visibility rather than public | |
123 | // visibility, as this is primarily here to ensure it's | |
124 | // not stripped during LTO. | |
125 | // | |
126 | // In general though we won't link right if these | |
127 | // symbols are stripped, and LTO currently strips them. | |
60c5eb7d XL |
128 | if name == "rust_eh_personality" || |
129 | name == "rust_eh_register_frames" || | |
130 | name == "rust_eh_unregister_frames" { | |
0531ce1d XL |
131 | SymbolExportLevel::C |
132 | } else { | |
133 | SymbolExportLevel::Rust | |
134 | } | |
135 | } else { | |
83c7162d | 136 | symbol_export_level(tcx, def_id) |
0531ce1d XL |
137 | }; |
138 | debug!("EXPORTED SYMBOL (local): {} ({:?})", | |
139 | tcx.symbol_name(Instance::mono(tcx, def_id)), | |
140 | export_level); | |
83c7162d | 141 | (def_id, export_level) |
0531ce1d XL |
142 | }) |
143 | .collect(); | |
144 | ||
0731742a XL |
145 | if let Some(id) = tcx.proc_macro_decls_static(LOCAL_CRATE) { |
146 | reachable_non_generics.insert(id, SymbolExportLevel::C); | |
0531ce1d XL |
147 | } |
148 | ||
0731742a XL |
149 | if let Some(id) = tcx.plugin_registrar_fn(LOCAL_CRATE) { |
150 | reachable_non_generics.insert(id, SymbolExportLevel::C); | |
83c7162d XL |
151 | } |
152 | ||
dc9dc135 | 153 | tcx.arena.alloc(reachable_non_generics) |
83c7162d XL |
154 | } |
155 | ||
416331ca | 156 | fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
83c7162d XL |
157 | let export_threshold = threshold(tcx); |
158 | ||
159 | if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { | |
160 | level.is_below_threshold(export_threshold) | |
161 | } else { | |
162 | false | |
0531ce1d | 163 | } |
83c7162d XL |
164 | } |
165 | ||
416331ca | 166 | fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
83c7162d XL |
167 | tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) |
168 | } | |
169 | ||
416331ca XL |
170 | fn exported_symbols_provider_local( |
171 | tcx: TyCtxt<'_>, | |
dc9dc135 | 172 | cnum: CrateNum, |
416331ca | 173 | ) -> Arc<Vec<(ExportedSymbol<'_>, SymbolExportLevel)>> { |
83c7162d XL |
174 | assert_eq!(cnum, LOCAL_CRATE); |
175 | ||
94b46f34 | 176 | if !tcx.sess.opts.output_types.should_codegen() { |
83c7162d XL |
177 | return Arc::new(vec![]) |
178 | } | |
179 | ||
180 | let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE) | |
181 | .iter() | |
182 | .map(|(&def_id, &level)| { | |
183 | (ExportedSymbol::NonGeneric(def_id), level) | |
184 | }) | |
185 | .collect(); | |
3b2f2976 | 186 | |
9fa01778 | 187 | if tcx.entry_fn(LOCAL_CRATE).is_some() { |
8faf50e0 | 188 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main")); |
0531ce1d XL |
189 | |
190 | symbols.push((exported_symbol, SymbolExportLevel::C)); | |
191 | } | |
192 | ||
60c5eb7d | 193 | if tcx.allocator_kind().is_some() { |
0531ce1d XL |
194 | for method in ALLOCATOR_METHODS { |
195 | let symbol_name = format!("__rust_{}", method.name); | |
196 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); | |
197 | ||
198 | symbols.push((exported_symbol, SymbolExportLevel::Rust)); | |
476ff2be | 199 | } |
0531ce1d | 200 | } |
476ff2be | 201 | |
dc9dc135 | 202 | if tcx.sess.opts.cg.profile_generate.enabled() { |
0531ce1d XL |
203 | // These are weak symbols that point to the profile version and the |
204 | // profile name, which need to be treated as exported so LTO doesn't nix | |
205 | // them. | |
0731742a | 206 | const PROFILER_WEAK_SYMBOLS: [&str; 2] = [ |
0531ce1d XL |
207 | "__llvm_profile_raw_version", |
208 | "__llvm_profile_filename", | |
209 | ]; | |
a1dfa0c6 XL |
210 | |
211 | symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { | |
0531ce1d | 212 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym)); |
a1dfa0c6 XL |
213 | (exported_symbol, SymbolExportLevel::C) |
214 | })); | |
0531ce1d | 215 | } |
abe05a73 | 216 | |
b7449926 | 217 | if tcx.sess.crate_types.borrow().contains(&config::CrateType::Dylib) { |
0531ce1d XL |
218 | let symbol_name = metadata_symbol_name(tcx); |
219 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); | |
abe05a73 | 220 | |
0531ce1d XL |
221 | symbols.push((exported_symbol, SymbolExportLevel::Rust)); |
222 | } | |
223 | ||
b7449926 | 224 | if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { |
83c7162d XL |
225 | use rustc::mir::mono::{Linkage, Visibility, MonoItem}; |
226 | use rustc::ty::InstanceDef; | |
227 | ||
228 | // Normally, we require that shared monomorphizations are not hidden, | |
229 | // because if we want to re-use a monomorphization from a Rust dylib, it | |
230 | // needs to be exported. | |
231 | // However, on platforms that don't allow for Rust dylibs, having | |
232 | // external linkage is enough for monomorphization to be linked to. | |
233 | let need_visibility = tcx.sess.target.target.options.dynamic_linking && | |
234 | !tcx.sess.target.target.options.only_cdylib; | |
235 | ||
94b46f34 | 236 | let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); |
83c7162d XL |
237 | |
238 | for (mono_item, &(linkage, visibility)) in cgus.iter() | |
239 | .flat_map(|cgu| cgu.items().iter()) { | |
240 | if linkage != Linkage::External { | |
241 | // We can only re-use things with external linkage, otherwise | |
242 | // we'll get a linker error | |
243 | continue | |
244 | } | |
245 | ||
246 | if need_visibility && visibility == Visibility::Hidden { | |
247 | // If we potentially share things from Rust dylibs, they must | |
248 | // not be hidden | |
249 | continue | |
250 | } | |
251 | ||
252 | if let &MonoItem::Fn(Instance { | |
253 | def: InstanceDef::Item(def_id), | |
254 | substs, | |
255 | }) = mono_item { | |
532ac7d7 | 256 | if substs.non_erasable_generics().next().is_some() { |
83c7162d XL |
257 | symbols.push((ExportedSymbol::Generic(def_id, substs), |
258 | SymbolExportLevel::Rust)); | |
259 | } | |
260 | } | |
261 | } | |
262 | } | |
263 | ||
0531ce1d XL |
264 | // Sort so we get a stable incr. comp. hash. |
265 | symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { | |
266 | symbol1.compare_stable(tcx, symbol2) | |
267 | }); | |
2c00a5a8 | 268 | |
0531ce1d | 269 | Arc::new(symbols) |
ea8adc8c | 270 | } |
476ff2be | 271 | |
416331ca XL |
272 | fn upstream_monomorphizations_provider( |
273 | tcx: TyCtxt<'_>, | |
dc9dc135 | 274 | cnum: CrateNum, |
416331ca | 275 | ) -> &DefIdMap<FxHashMap<SubstsRef<'_>, CrateNum>> { |
83c7162d XL |
276 | debug_assert!(cnum == LOCAL_CRATE); |
277 | ||
278 | let cnums = tcx.all_crate_nums(LOCAL_CRATE); | |
279 | ||
a1dfa0c6 | 280 | let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default(); |
83c7162d XL |
281 | |
282 | let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = { | |
283 | let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, | |
284 | cnums.len() + 1); | |
285 | ||
286 | for &cnum in cnums.iter() { | |
287 | cnum_stable_ids[cnum] = tcx.def_path_hash(DefId { | |
288 | krate: cnum, | |
289 | index: CRATE_DEF_INDEX, | |
290 | }).0; | |
291 | } | |
292 | ||
293 | cnum_stable_ids | |
294 | }; | |
295 | ||
296 | for &cnum in cnums.iter() { | |
e74abb32 | 297 | for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { |
83c7162d | 298 | if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { |
b7449926 | 299 | let substs_map = instances.entry(def_id).or_default(); |
83c7162d XL |
300 | |
301 | match substs_map.entry(substs) { | |
302 | Occupied(mut e) => { | |
303 | // If there are multiple monomorphizations available, | |
304 | // we select one deterministically. | |
305 | let other_cnum = *e.get(); | |
306 | if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] { | |
307 | e.insert(cnum); | |
308 | } | |
309 | } | |
310 | Vacant(e) => { | |
311 | e.insert(cnum); | |
312 | } | |
313 | } | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
dc9dc135 | 318 | tcx.arena.alloc(instances) |
83c7162d XL |
319 | } |
320 | ||
416331ca XL |
321 | fn upstream_monomorphizations_for_provider( |
322 | tcx: TyCtxt<'_>, | |
dc9dc135 | 323 | def_id: DefId, |
416331ca | 324 | ) -> Option<&FxHashMap<SubstsRef<'_>, CrateNum>> { |
83c7162d | 325 | debug_assert!(!def_id.is_local()); |
dc9dc135 | 326 | tcx.upstream_monomorphizations(LOCAL_CRATE).get(&def_id) |
83c7162d XL |
327 | } |
328 | ||
dc9dc135 | 329 | fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: DefId) -> bool { |
532ac7d7 XL |
330 | if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { |
331 | !tcx.reachable_set(LOCAL_CRATE).0.contains(&hir_id) | |
83c7162d XL |
332 | } else { |
333 | bug!("is_unreachable_local_definition called with non-local DefId: {:?}", | |
a1dfa0c6 | 334 | def_id) |
83c7162d XL |
335 | } |
336 | } | |
337 | ||
9fa01778 | 338 | pub fn provide(providers: &mut Providers<'_>) { |
0531ce1d | 339 | providers.reachable_non_generics = reachable_non_generics_provider; |
83c7162d | 340 | providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; |
0531ce1d | 341 | providers.exported_symbols = exported_symbols_provider_local; |
83c7162d XL |
342 | providers.upstream_monomorphizations = upstream_monomorphizations_provider; |
343 | providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; | |
0531ce1d | 344 | } |
476ff2be | 345 | |
9fa01778 | 346 | pub fn provide_extern(providers: &mut Providers<'_>) { |
83c7162d XL |
347 | providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; |
348 | providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; | |
476ff2be SL |
349 | } |
350 | ||
dc9dc135 | 351 | fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { |
abe05a73 XL |
352 | // We export anything that's not mangled at the "C" layer as it probably has |
353 | // to do with ABI concerns. We do not, however, apply such treatment to | |
354 | // special symbols in the standard library for various plumbing between | |
355 | // core/std/allocators/etc. For example symbols used to hook up allocation | |
356 | // are not considered for export | |
94b46f34 XL |
357 | let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); |
358 | let is_extern = codegen_fn_attrs.contains_extern_indicator(); | |
359 | let std_internal = | |
360 | codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); | |
0531ce1d | 361 | |
abe05a73 | 362 | if is_extern && !std_internal { |
e74abb32 XL |
363 | let target = &tcx.sess.target.target.llvm_target; |
364 | // WebAssembly cannot export data symbols, so reduce their export level | |
365 | if target.contains("wasm32") || target.contains("emscripten") { | |
a1dfa0c6 | 366 | if let Some(Node::Item(&hir::Item { |
e74abb32 | 367 | kind: hir::ItemKind::Static(..), |
a1dfa0c6 | 368 | .. |
0731742a | 369 | })) = tcx.hir().get_if_local(sym_def_id) { |
a1dfa0c6 XL |
370 | return SymbolExportLevel::Rust; |
371 | } | |
372 | } | |
373 | ||
476ff2be | 374 | SymbolExportLevel::C |
476ff2be | 375 | } else { |
ea8adc8c | 376 | SymbolExportLevel::Rust |
476ff2be SL |
377 | } |
378 | } |