]>
Commit | Line | Data |
---|---|---|
353b0b11 FG |
1 | use crate::base::allocator_kind_for_codegen; |
2 | ||
416331ca | 3 | use std::collections::hash_map::Entry::*; |
ba9703b0 | 4 | |
49aad941 | 5 | use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE}; |
dfeec247 | 6 | use rustc_data_structures::fx::FxHashMap; |
9ffffee4 | 7 | use rustc_hir::def::DefKind; |
04454e1e | 8 | use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; |
ba9703b0 XL |
9 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
10 | use rustc_middle::middle::exported_symbols::{ | |
04454e1e | 11 | metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, |
ba9703b0 | 12 | }; |
353b0b11 | 13 | use rustc_middle::query::LocalCrate; |
49aad941 | 14 | use rustc_middle::query::{ExternProviders, Providers}; |
ba9703b0 XL |
15 | use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; |
16 | use rustc_middle::ty::Instance; | |
353b0b11 | 17 | use rustc_middle::ty::{self, SymbolName, TyCtxt}; |
2b03887a | 18 | use rustc_session::config::{CrateType, OomStrategy}; |
cdc7bbd5 | 19 | use rustc_target::spec::SanitizerSet; |
ea8adc8c | 20 | |
dc9dc135 | 21 | pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { |
f9f354fc | 22 | crates_export_threshold(&tcx.sess.crate_types()) |
476ff2be SL |
23 | } |
24 | ||
f9f354fc | 25 | fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel { |
ea8adc8c | 26 | match crate_type { |
f9f354fc XL |
27 | CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => { |
28 | SymbolExportLevel::C | |
29 | } | |
30 | CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust, | |
476ff2be | 31 | } |
ea8adc8c | 32 | } |
476ff2be | 33 | |
f9f354fc | 34 | pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { |
dfeec247 XL |
35 | if crate_types |
36 | .iter() | |
37 | .any(|&crate_type| crate_export_threshold(crate_type) == SymbolExportLevel::Rust) | |
a1dfa0c6 | 38 | { |
ea8adc8c XL |
39 | SymbolExportLevel::Rust |
40 | } else { | |
41 | SymbolExportLevel::C | |
42 | } | |
43 | } | |
44 | ||
353b0b11 | 45 | fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> { |
94b46f34 | 46 | if !tcx.sess.opts.output_types.should_codegen() { |
f9f354fc | 47 | return Default::default(); |
0531ce1d XL |
48 | } |
49 | ||
50 | // Check to see if this crate is a "special runtime crate". These | |
51 | // crates, implementation details of the standard library, typically | |
52 | // have a bunch of `pub extern` and `#[no_mangle]` functions as the | |
53 | // ABI between them. We don't want their symbols to have a `C` | |
54 | // export level, however, as they're just implementation details. | |
55 | // Down below we'll hardwire all of the symbols to the `Rust` export | |
56 | // level instead. | |
dfeec247 XL |
57 | let special_runtime_crate = |
58 | tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE); | |
0531ce1d | 59 | |
dfeec247 | 60 | let mut reachable_non_generics: DefIdMap<_> = tcx |
17df50a5 | 61 | .reachable_set(()) |
353b0b11 | 62 | .items() |
3dfed10e | 63 | .filter_map(|&def_id| { |
0531ce1d XL |
64 | // We want to ignore some FFI functions that are not exposed from |
65 | // this crate. Reachable FFI functions can be lumped into two | |
66 | // categories: | |
67 | // | |
68 | // 1. Those that are included statically via a static library | |
0731742a | 69 | // 2. Those included otherwise (e.g., dynamically or via a framework) |
0531ce1d XL |
70 | // |
71 | // Although our LLVM module is not literally emitting code for the | |
72 | // statically included symbols, it's an export of our library which | |
73 | // needs to be passed on to the linker and encoded in the metadata. | |
74 | // | |
75 | // As a result, if this id is an FFI item (foreign item) then we only | |
76 | // let it through if it's included statically. | |
9ffffee4 FG |
77 | if let Some(parent_id) = tcx.opt_local_parent(def_id) |
78 | && let DefKind::ForeignMod = tcx.def_kind(parent_id) | |
79 | { | |
80 | let library = tcx.native_library(def_id)?; | |
81 | return library.kind.is_statically_included().then_some(def_id); | |
82 | } | |
476ff2be | 83 | |
9ffffee4 FG |
84 | // Only consider nodes that actually have exported symbols. |
85 | match tcx.def_kind(def_id) { | |
86 | DefKind::Fn | DefKind::Static(_) => {} | |
87 | DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {} | |
88 | _ => return None, | |
89 | }; | |
0531ce1d | 90 | |
9ffffee4 FG |
91 | let generics = tcx.generics_of(def_id); |
92 | if generics.requires_monomorphization(tcx) { | |
93 | return None; | |
94 | } | |
95 | ||
96 | // Functions marked with #[inline] are codegened with "internal" | |
97 | // linkage and are not exported unless marked with an extern | |
98 | // indicator | |
99 | if !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) | |
100 | || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator() | |
101 | { | |
102 | Some(def_id) | |
103 | } else { | |
104 | None | |
3b2f2976 | 105 | } |
0531ce1d | 106 | }) |
83c7162d | 107 | .map(|def_id| { |
f2b60f7d FG |
108 | // We won't link right if this symbol is stripped during LTO. |
109 | let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; | |
110 | let used = name == "rust_eh_personality"; | |
111 | ||
112 | let export_level = if special_runtime_crate { | |
113 | SymbolExportLevel::Rust | |
0531ce1d | 114 | } else { |
f2b60f7d | 115 | symbol_export_level(tcx, def_id.to_def_id()) |
0531ce1d | 116 | }; |
04454e1e | 117 | let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); |
dfeec247 XL |
118 | debug!( |
119 | "EXPORTED SYMBOL (local): {} ({:?})", | |
f9f354fc | 120 | tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())), |
dfeec247 XL |
121 | export_level |
122 | ); | |
9ffffee4 | 123 | let info = SymbolExportInfo { |
04454e1e FG |
124 | level: export_level, |
125 | kind: if tcx.is_static(def_id.to_def_id()) { | |
126 | if codegen_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { | |
127 | SymbolExportKind::Tls | |
128 | } else { | |
129 | SymbolExportKind::Data | |
130 | } | |
131 | } else { | |
132 | SymbolExportKind::Text | |
133 | }, | |
134 | used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) | |
9ffffee4 FG |
135 | || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) |
136 | || used, | |
137 | }; | |
138 | (def_id.to_def_id(), info) | |
0531ce1d | 139 | }) |
353b0b11 | 140 | .into(); |
0531ce1d | 141 | |
17df50a5 | 142 | if let Some(id) = tcx.proc_macro_decls_static(()) { |
04454e1e FG |
143 | reachable_non_generics.insert( |
144 | id.to_def_id(), | |
145 | SymbolExportInfo { | |
146 | level: SymbolExportLevel::C, | |
147 | kind: SymbolExportKind::Data, | |
148 | used: false, | |
149 | }, | |
150 | ); | |
0531ce1d XL |
151 | } |
152 | ||
f9f354fc | 153 | reachable_non_generics |
83c7162d XL |
154 | } |
155 | ||
353b0b11 | 156 | fn is_reachable_non_generic_provider_local(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { |
83c7162d XL |
157 | let export_threshold = threshold(tcx); |
158 | ||
353b0b11 | 159 | if let Some(&info) = tcx.reachable_non_generics(LOCAL_CRATE).get(&def_id.to_def_id()) { |
04454e1e | 160 | info.level.is_below_threshold(export_threshold) |
83c7162d XL |
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 | ||
9c376795 FG |
170 | fn exported_symbols_provider_local( |
171 | tcx: TyCtxt<'_>, | |
353b0b11 | 172 | _: LocalCrate, |
9c376795 | 173 | ) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { |
94b46f34 | 174 | if !tcx.sess.opts.output_types.should_codegen() { |
ba9703b0 | 175 | return &[]; |
83c7162d XL |
176 | } |
177 | ||
9c376795 FG |
178 | // FIXME: Sorting this is unnecessary since we are sorting later anyway. |
179 | // Can we skip the later sorting? | |
353b0b11 FG |
180 | let sorted = tcx.with_stable_hashing_context(|hcx| { |
181 | tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true) | |
9c376795 | 182 | }); |
3b2f2976 | 183 | |
353b0b11 FG |
184 | let mut symbols: Vec<_> = |
185 | sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect(); | |
186 | ||
187 | // Export TLS shims | |
188 | if !tcx.sess.target.dll_tls_export { | |
189 | symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| { | |
190 | tcx.needs_thread_local_shim(def_id).then(|| { | |
191 | ( | |
192 | ExportedSymbol::ThreadLocalShim(def_id), | |
193 | SymbolExportInfo { | |
194 | level: info.level, | |
195 | kind: SymbolExportKind::Text, | |
196 | used: info.used, | |
197 | }, | |
198 | ) | |
199 | }) | |
200 | })) | |
201 | } | |
202 | ||
17df50a5 | 203 | if tcx.entry_fn(()).is_some() { |
487cf647 FG |
204 | let exported_symbol = |
205 | ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); | |
0531ce1d | 206 | |
04454e1e FG |
207 | symbols.push(( |
208 | exported_symbol, | |
209 | SymbolExportInfo { | |
210 | level: SymbolExportLevel::C, | |
211 | kind: SymbolExportKind::Text, | |
212 | used: false, | |
213 | }, | |
214 | )); | |
0531ce1d XL |
215 | } |
216 | ||
353b0b11 FG |
217 | // Mark allocator shim symbols as exported only if they were generated. |
218 | if allocator_kind_for_codegen(tcx).is_some() { | |
487cf647 FG |
219 | for symbol_name in ALLOCATOR_METHODS |
220 | .iter() | |
221 | .map(|method| format!("__rust_{}", method.name)) | |
222 | .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()]) | |
223 | { | |
3dfed10e | 224 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); |
0531ce1d | 225 | |
04454e1e FG |
226 | symbols.push(( |
227 | exported_symbol, | |
228 | SymbolExportInfo { | |
229 | level: SymbolExportLevel::Rust, | |
230 | kind: SymbolExportKind::Text, | |
231 | used: false, | |
232 | }, | |
233 | )); | |
476ff2be | 234 | } |
2b03887a FG |
235 | |
236 | symbols.push(( | |
237 | ExportedSymbol::NoDefId(SymbolName::new(tcx, OomStrategy::SYMBOL)), | |
238 | SymbolExportInfo { | |
239 | level: SymbolExportLevel::Rust, | |
240 | kind: SymbolExportKind::Text, | |
241 | used: false, | |
242 | }, | |
243 | )); | |
49aad941 FG |
244 | |
245 | let exported_symbol = | |
246 | ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE)); | |
247 | symbols.push(( | |
248 | exported_symbol, | |
249 | SymbolExportInfo { | |
250 | level: SymbolExportLevel::Rust, | |
251 | kind: SymbolExportKind::Data, | |
252 | used: false, | |
253 | }, | |
254 | )) | |
0531ce1d | 255 | } |
476ff2be | 256 | |
cdc7bbd5 | 257 | if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() { |
0531ce1d XL |
258 | // These are weak symbols that point to the profile version and the |
259 | // profile name, which need to be treated as exported so LTO doesn't nix | |
260 | // them. | |
dfeec247 XL |
261 | const PROFILER_WEAK_SYMBOLS: [&str; 2] = |
262 | ["__llvm_profile_raw_version", "__llvm_profile_filename"]; | |
a1dfa0c6 XL |
263 | |
264 | symbols.extend(PROFILER_WEAK_SYMBOLS.iter().map(|sym| { | |
3dfed10e | 265 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); |
04454e1e FG |
266 | ( |
267 | exported_symbol, | |
268 | SymbolExportInfo { | |
269 | level: SymbolExportLevel::C, | |
270 | kind: SymbolExportKind::Data, | |
271 | used: false, | |
272 | }, | |
273 | ) | |
a1dfa0c6 | 274 | })); |
0531ce1d | 275 | } |
abe05a73 | 276 | |
064997fb | 277 | if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { |
04454e1e FG |
278 | let mut msan_weak_symbols = Vec::new(); |
279 | ||
dfeec247 | 280 | // Similar to profiling, preserve weak msan symbol during LTO. |
064997fb | 281 | if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) { |
04454e1e FG |
282 | msan_weak_symbols.push("__msan_keep_going"); |
283 | } | |
284 | ||
064997fb | 285 | if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 { |
04454e1e FG |
286 | msan_weak_symbols.push("__msan_track_origins"); |
287 | } | |
dfeec247 | 288 | |
04454e1e | 289 | symbols.extend(msan_weak_symbols.into_iter().map(|sym| { |
3dfed10e | 290 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, sym)); |
04454e1e FG |
291 | ( |
292 | exported_symbol, | |
293 | SymbolExportInfo { | |
294 | level: SymbolExportLevel::C, | |
295 | kind: SymbolExportKind::Data, | |
296 | used: false, | |
297 | }, | |
298 | ) | |
dfeec247 XL |
299 | })); |
300 | } | |
301 | ||
064997fb FG |
302 | if tcx.sess.crate_types().contains(&CrateType::Dylib) |
303 | || tcx.sess.crate_types().contains(&CrateType::ProcMacro) | |
304 | { | |
0531ce1d | 305 | let symbol_name = metadata_symbol_name(tcx); |
3dfed10e | 306 | let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name)); |
abe05a73 | 307 | |
04454e1e FG |
308 | symbols.push(( |
309 | exported_symbol, | |
310 | SymbolExportInfo { | |
064997fb | 311 | level: SymbolExportLevel::C, |
04454e1e | 312 | kind: SymbolExportKind::Data, |
064997fb | 313 | used: true, |
04454e1e FG |
314 | }, |
315 | )); | |
0531ce1d XL |
316 | } |
317 | ||
b7449926 | 318 | if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { |
ba9703b0 XL |
319 | use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; |
320 | use rustc_middle::ty::InstanceDef; | |
83c7162d XL |
321 | |
322 | // Normally, we require that shared monomorphizations are not hidden, | |
323 | // because if we want to re-use a monomorphization from a Rust dylib, it | |
324 | // needs to be exported. | |
325 | // However, on platforms that don't allow for Rust dylibs, having | |
326 | // external linkage is enough for monomorphization to be linked to. | |
29967ef6 | 327 | let need_visibility = tcx.sess.target.dynamic_linking && !tcx.sess.target.only_cdylib; |
83c7162d | 328 | |
17df50a5 | 329 | let (_, cgus) = tcx.collect_and_partition_mono_items(()); |
83c7162d | 330 | |
dfeec247 | 331 | for (mono_item, &(linkage, visibility)) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { |
83c7162d XL |
332 | if linkage != Linkage::External { |
333 | // We can only re-use things with external linkage, otherwise | |
334 | // we'll get a linker error | |
dfeec247 | 335 | continue; |
83c7162d XL |
336 | } |
337 | ||
338 | if need_visibility && visibility == Visibility::Hidden { | |
339 | // If we potentially share things from Rust dylibs, they must | |
340 | // not be hidden | |
dfeec247 | 341 | continue; |
83c7162d XL |
342 | } |
343 | ||
dfeec247 | 344 | match *mono_item { |
3dfed10e | 345 | MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => { |
dfeec247 | 346 | if substs.non_erasable_generics().next().is_some() { |
49aad941 | 347 | let symbol = ExportedSymbol::Generic(def, substs); |
04454e1e FG |
348 | symbols.push(( |
349 | symbol, | |
350 | SymbolExportInfo { | |
351 | level: SymbolExportLevel::Rust, | |
352 | kind: SymbolExportKind::Text, | |
353 | used: false, | |
354 | }, | |
355 | )); | |
dfeec247 XL |
356 | } |
357 | } | |
358 | MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => { | |
359 | // A little sanity-check | |
360 | debug_assert_eq!( | |
361 | substs.non_erasable_generics().next(), | |
362 | Some(GenericArgKind::Type(ty)) | |
363 | ); | |
04454e1e FG |
364 | symbols.push(( |
365 | ExportedSymbol::DropGlue(ty), | |
366 | SymbolExportInfo { | |
367 | level: SymbolExportLevel::Rust, | |
368 | kind: SymbolExportKind::Text, | |
369 | used: false, | |
370 | }, | |
371 | )); | |
dfeec247 XL |
372 | } |
373 | _ => { | |
374 | // Any other symbols don't qualify for sharing | |
83c7162d XL |
375 | } |
376 | } | |
377 | } | |
378 | } | |
379 | ||
0531ce1d | 380 | // Sort so we get a stable incr. comp. hash. |
dfeec247 | 381 | symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); |
2c00a5a8 | 382 | |
ba9703b0 | 383 | tcx.arena.alloc_from_iter(symbols) |
ea8adc8c | 384 | } |
476ff2be | 385 | |
416331ca XL |
386 | fn upstream_monomorphizations_provider( |
387 | tcx: TyCtxt<'_>, | |
17df50a5 | 388 | (): (), |
f9f354fc | 389 | ) -> DefIdMap<FxHashMap<SubstsRef<'_>, CrateNum>> { |
136023e0 | 390 | let cnums = tcx.crates(()); |
83c7162d | 391 | |
a1dfa0c6 | 392 | let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default(); |
83c7162d | 393 | |
dfeec247 XL |
394 | let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn(); |
395 | ||
83c7162d | 396 | for &cnum in cnums.iter() { |
e74abb32 | 397 | for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { |
dfeec247 XL |
398 | let (def_id, substs) = match *exported_symbol { |
399 | ExportedSymbol::Generic(def_id, substs) => (def_id, substs), | |
400 | ExportedSymbol::DropGlue(ty) => { | |
401 | if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id { | |
9ffffee4 | 402 | (drop_in_place_fn_def_id, tcx.mk_substs(&[ty.into()])) |
dfeec247 XL |
403 | } else { |
404 | // `drop_in_place` in place does not exist, don't try | |
405 | // to use it. | |
406 | continue; | |
83c7162d | 407 | } |
dfeec247 | 408 | } |
353b0b11 FG |
409 | ExportedSymbol::NonGeneric(..) |
410 | | ExportedSymbol::ThreadLocalShim(..) | |
411 | | ExportedSymbol::NoDefId(..) => { | |
dfeec247 XL |
412 | // These are no monomorphizations |
413 | continue; | |
414 | } | |
415 | }; | |
416 | ||
417 | let substs_map = instances.entry(def_id).or_default(); | |
418 | ||
419 | match substs_map.entry(substs) { | |
420 | Occupied(mut e) => { | |
421 | // If there are multiple monomorphizations available, | |
422 | // we select one deterministically. | |
423 | let other_cnum = *e.get(); | |
04454e1e | 424 | if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) { |
83c7162d XL |
425 | e.insert(cnum); |
426 | } | |
427 | } | |
dfeec247 XL |
428 | Vacant(e) => { |
429 | e.insert(cnum); | |
430 | } | |
83c7162d XL |
431 | } |
432 | } | |
433 | } | |
434 | ||
f9f354fc | 435 | instances |
83c7162d XL |
436 | } |
437 | ||
416331ca XL |
438 | fn upstream_monomorphizations_for_provider( |
439 | tcx: TyCtxt<'_>, | |
dc9dc135 | 440 | def_id: DefId, |
416331ca | 441 | ) -> Option<&FxHashMap<SubstsRef<'_>, CrateNum>> { |
83c7162d | 442 | debug_assert!(!def_id.is_local()); |
17df50a5 | 443 | tcx.upstream_monomorphizations(()).get(&def_id) |
83c7162d XL |
444 | } |
445 | ||
dfeec247 XL |
446 | fn upstream_drop_glue_for_provider<'tcx>( |
447 | tcx: TyCtxt<'tcx>, | |
448 | substs: SubstsRef<'tcx>, | |
449 | ) -> Option<CrateNum> { | |
450 | if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { | |
451 | tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&substs).cloned()) | |
452 | } else { | |
453 | None | |
454 | } | |
455 | } | |
456 | ||
17df50a5 XL |
457 | fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { |
458 | !tcx.reachable_set(()).contains(&def_id) | |
83c7162d XL |
459 | } |
460 | ||
f035d41b | 461 | pub fn provide(providers: &mut Providers) { |
0531ce1d | 462 | providers.reachable_non_generics = reachable_non_generics_provider; |
83c7162d | 463 | providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; |
0531ce1d | 464 | providers.exported_symbols = exported_symbols_provider_local; |
83c7162d XL |
465 | providers.upstream_monomorphizations = upstream_monomorphizations_provider; |
466 | providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; | |
dfeec247 | 467 | providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; |
17df50a5 | 468 | providers.wasm_import_module_map = wasm_import_module_map; |
0531ce1d | 469 | } |
476ff2be | 470 | |
3c0e092e | 471 | pub fn provide_extern(providers: &mut ExternProviders) { |
83c7162d XL |
472 | providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; |
473 | providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; | |
476ff2be SL |
474 | } |
475 | ||
dc9dc135 | 476 | fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel { |
abe05a73 XL |
477 | // We export anything that's not mangled at the "C" layer as it probably has |
478 | // to do with ABI concerns. We do not, however, apply such treatment to | |
479 | // special symbols in the standard library for various plumbing between | |
480 | // core/std/allocators/etc. For example symbols used to hook up allocation | |
481 | // are not considered for export | |
94b46f34 XL |
482 | let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); |
483 | let is_extern = codegen_fn_attrs.contains_extern_indicator(); | |
484 | let std_internal = | |
485 | codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); | |
0531ce1d | 486 | |
abe05a73 | 487 | if is_extern && !std_internal { |
29967ef6 | 488 | let target = &tcx.sess.target.llvm_target; |
e74abb32 | 489 | // WebAssembly cannot export data symbols, so reduce their export level |
dfeec247 | 490 | if target.contains("emscripten") { |
9ffffee4 | 491 | if let DefKind::Static(_) = tcx.def_kind(sym_def_id) { |
a1dfa0c6 XL |
492 | return SymbolExportLevel::Rust; |
493 | } | |
494 | } | |
495 | ||
476ff2be | 496 | SymbolExportLevel::C |
476ff2be | 497 | } else { |
ea8adc8c | 498 | SymbolExportLevel::Rust |
476ff2be SL |
499 | } |
500 | } | |
dfeec247 XL |
501 | |
502 | /// This is the symbol name of the given instance instantiated in a specific crate. | |
503 | pub fn symbol_name_for_instance_in_crate<'tcx>( | |
504 | tcx: TyCtxt<'tcx>, | |
505 | symbol: ExportedSymbol<'tcx>, | |
506 | instantiating_crate: CrateNum, | |
507 | ) -> String { | |
508 | // If this is something instantiated in the local crate then we might | |
509 | // already have cached the name as a query result. | |
510 | if instantiating_crate == LOCAL_CRATE { | |
511 | return symbol.symbol_name_for_local_instance(tcx).to_string(); | |
512 | } | |
513 | ||
514 | // This is something instantiated in an upstream crate, so we have to use | |
515 | // the slower (because uncached) version of computing the symbol name. | |
516 | match symbol { | |
ba9703b0 XL |
517 | ExportedSymbol::NonGeneric(def_id) => { |
518 | rustc_symbol_mangling::symbol_name_for_instance_in_crate( | |
519 | tcx, | |
520 | Instance::mono(tcx, def_id), | |
521 | instantiating_crate, | |
522 | ) | |
523 | } | |
524 | ExportedSymbol::Generic(def_id, substs) => { | |
525 | rustc_symbol_mangling::symbol_name_for_instance_in_crate( | |
526 | tcx, | |
527 | Instance::new(def_id, substs), | |
528 | instantiating_crate, | |
529 | ) | |
530 | } | |
353b0b11 FG |
531 | ExportedSymbol::ThreadLocalShim(def_id) => { |
532 | rustc_symbol_mangling::symbol_name_for_instance_in_crate( | |
533 | tcx, | |
534 | ty::Instance { | |
535 | def: ty::InstanceDef::ThreadLocalShim(def_id), | |
536 | substs: ty::InternalSubsts::empty(), | |
537 | }, | |
538 | instantiating_crate, | |
539 | ) | |
540 | } | |
ba9703b0 | 541 | ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate( |
dfeec247 XL |
542 | tcx, |
543 | Instance::resolve_drop_in_place(tcx, ty), | |
544 | instantiating_crate, | |
545 | ), | |
546 | ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(), | |
547 | } | |
548 | } | |
17df50a5 | 549 | |
04454e1e FG |
550 | /// This is the symbol name of the given instance as seen by the linker. |
551 | /// | |
552 | /// On 32-bit Windows symbols are decorated according to their calling conventions. | |
553 | pub fn linking_symbol_name_for_instance_in_crate<'tcx>( | |
554 | tcx: TyCtxt<'tcx>, | |
555 | symbol: ExportedSymbol<'tcx>, | |
556 | instantiating_crate: CrateNum, | |
557 | ) -> String { | |
558 | use rustc_target::abi::call::Conv; | |
559 | ||
560 | let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); | |
561 | ||
562 | let target = &tcx.sess.target; | |
563 | if !target.is_like_windows { | |
564 | // Mach-O has a global "_" suffix and `object` crate will handle it. | |
565 | // ELF does not have any symbol decorations. | |
566 | return undecorated; | |
567 | } | |
568 | ||
569 | let x86 = match &target.arch[..] { | |
570 | "x86" => true, | |
571 | "x86_64" => false, | |
572 | // Only x86/64 use symbol decorations. | |
573 | _ => return undecorated, | |
574 | }; | |
575 | ||
576 | let instance = match symbol { | |
577 | ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) | |
578 | if tcx.is_static(def_id) => | |
579 | { | |
580 | None | |
581 | } | |
582 | ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), | |
583 | ExportedSymbol::Generic(def_id, substs) => Some(Instance::new(def_id, substs)), | |
584 | // DropGlue always use the Rust calling convention and thus follow the target's default | |
585 | // symbol decoration scheme. | |
586 | ExportedSymbol::DropGlue(..) => None, | |
587 | // NoDefId always follow the target's default symbol decoration scheme. | |
588 | ExportedSymbol::NoDefId(..) => None, | |
353b0b11 FG |
589 | // ThreadLocalShim always follow the target's default symbol decoration scheme. |
590 | ExportedSymbol::ThreadLocalShim(..) => None, | |
04454e1e FG |
591 | }; |
592 | ||
593 | let (conv, args) = instance | |
594 | .map(|i| { | |
595 | tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty()))) | |
596 | .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed")) | |
597 | }) | |
598 | .map(|fnabi| (fnabi.conv, &fnabi.args[..])) | |
599 | .unwrap_or((Conv::Rust, &[])); | |
600 | ||
f2b60f7d | 601 | // Decorate symbols with prefixes, suffixes and total number of bytes of arguments. |
04454e1e FG |
602 | // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 |
603 | let (prefix, suffix) = match conv { | |
604 | Conv::X86Fastcall => ("@", "@"), | |
605 | Conv::X86Stdcall => ("_", "@"), | |
606 | Conv::X86VectorCall => ("", "@@"), | |
607 | _ => { | |
608 | if x86 { | |
609 | undecorated.insert(0, '_'); | |
610 | } | |
611 | return undecorated; | |
612 | } | |
613 | }; | |
614 | ||
615 | let args_in_bytes: u64 = args | |
616 | .iter() | |
617 | .map(|abi| abi.layout.size.bytes().next_multiple_of(target.pointer_width as u64 / 8)) | |
618 | .sum(); | |
619 | format!("{prefix}{undecorated}{suffix}{args_in_bytes}") | |
620 | } | |
621 | ||
17df50a5 XL |
622 | fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> { |
623 | // Build up a map from DefId to a `NativeLib` structure, where | |
624 | // `NativeLib` internally contains information about | |
625 | // `#[link(wasm_import_module = "...")]` for example. | |
626 | let native_libs = tcx.native_libraries(cnum); | |
627 | ||
628 | let def_id_to_native_lib = native_libs | |
629 | .iter() | |
630 | .filter_map(|lib| lib.foreign_module.map(|id| (id, lib))) | |
631 | .collect::<FxHashMap<_, _>>(); | |
632 | ||
633 | let mut ret = FxHashMap::default(); | |
634 | for (def_id, lib) in tcx.foreign_modules(cnum).iter() { | |
353b0b11 | 635 | let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module()); |
5e7ed085 | 636 | let Some(module) = module else { continue }; |
17df50a5 XL |
637 | ret.extend(lib.foreign_items.iter().map(|id| { |
638 | assert_eq!(id.krate, cnum); | |
639 | (*id, module.to_string()) | |
640 | })); | |
641 | } | |
642 | ||
643 | ret | |
644 | } |