]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/symbol_export.rs
Replace Rc with Lrc for shared data
[rust.git] / src / librustc_trans / 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 base;
15 use monomorphize::Instance;
16 use rustc::hir::def_id::CrateNum;
17 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
18 use rustc::middle::exported_symbols::SymbolExportLevel;
19 use rustc::session::config;
20 use rustc::ty::TyCtxt;
21 use rustc::ty::maps::Providers;
22 use rustc::util::nodemap::FxHashMap;
23 use rustc_allocator::ALLOCATOR_METHODS;
24 use rustc_back::LinkerFlavor;
25 use syntax::attr;
26
27 pub type ExportedSymbols = FxHashMap<
28     CrateNum,
29     Arc<Vec<(String, Option<DefId>, SymbolExportLevel)>>,
30 >;
31
32 pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
33     crates_export_threshold(&tcx.sess.crate_types.borrow())
34 }
35
36 pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
37     format!("rust_metadata_{}_{}",
38             tcx.crate_name(LOCAL_CRATE),
39             tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex())
40 }
41
42 fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
43     match crate_type {
44         config::CrateTypeExecutable |
45         config::CrateTypeStaticlib  |
46         config::CrateTypeProcMacro  |
47         config::CrateTypeCdylib     => SymbolExportLevel::C,
48         config::CrateTypeRlib       |
49         config::CrateTypeDylib      => SymbolExportLevel::Rust,
50     }
51 }
52
53 pub fn crates_export_threshold(crate_types: &[config::CrateType])
54                                       -> SymbolExportLevel {
55     if crate_types.iter().any(|&crate_type| {
56         crate_export_threshold(crate_type) == SymbolExportLevel::Rust
57     }) {
58         SymbolExportLevel::Rust
59     } else {
60         SymbolExportLevel::C
61     }
62 }
63
64 pub fn provide(providers: &mut Providers) {
65     providers.exported_symbol_ids = |tcx, cnum| {
66         let export_threshold = threshold(tcx);
67         Lrc::new(tcx.exported_symbols(cnum)
68             .iter()
69             .filter_map(|&(_, id, level)| {
70                 id.and_then(|id| {
71                     if level.is_below_threshold(export_threshold) {
72                         Some(id)
73                     } else {
74                         None
75                     }
76                 })
77             })
78             .collect())
79     };
80
81     providers.is_exported_symbol = |tcx, id| {
82         tcx.exported_symbol_ids(id.krate).contains(&id)
83     };
84
85     providers.exported_symbols = |tcx, cnum| {
86         assert_eq!(cnum, LOCAL_CRATE);
87         let local_exported_symbols = base::find_exported_symbols(tcx);
88
89         let mut local_crate: Vec<_> = local_exported_symbols
90             .iter()
91             .map(|&node_id| {
92                 tcx.hir.local_def_id(node_id)
93             })
94             .map(|def_id| {
95                 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
96                 let export_level = export_level(tcx, def_id);
97                 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
98                 (str::to_owned(&name), Some(def_id), export_level)
99             })
100             .collect();
101
102         if let Some(_) = *tcx.sess.entry_fn.borrow() {
103             local_crate.push(("main".to_string(),
104                               None,
105                               SymbolExportLevel::C));
106         }
107
108         if tcx.sess.allocator_kind.get().is_some() {
109             for method in ALLOCATOR_METHODS {
110                 local_crate.push((format!("__rust_{}", method.name),
111                                   None,
112                                   SymbolExportLevel::Rust));
113             }
114         }
115
116         if let Some(id) = tcx.sess.derive_registrar_fn.get() {
117             let def_id = tcx.hir.local_def_id(id);
118             let disambiguator = tcx.sess.local_crate_disambiguator();
119             let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator);
120             local_crate.push((registrar, Some(def_id), SymbolExportLevel::C));
121         }
122
123         if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
124             local_crate.push((metadata_symbol_name(tcx),
125                               None,
126                               SymbolExportLevel::Rust));
127         }
128
129         // Sort so we get a stable incr. comp. hash.
130         local_crate.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| {
131             name1.cmp(name2)
132         });
133
134         Arc::new(local_crate)
135     };
136
137     providers.symbol_export_level = export_level;
138 }
139
140 pub fn provide_extern(providers: &mut Providers) {
141     providers.exported_symbols = |tcx, cnum| {
142         // If this crate is a plugin and/or a custom derive crate, then
143         // we're not even going to link those in so we skip those crates.
144         if tcx.plugin_registrar_fn(cnum).is_some() ||
145            tcx.derive_registrar_fn(cnum).is_some() {
146             return Arc::new(Vec::new())
147         }
148
149         // Check to see if this crate is a "special runtime crate". These
150         // crates, implementation details of the standard library, typically
151         // have a bunch of `pub extern` and `#[no_mangle]` functions as the
152         // ABI between them. We don't want their symbols to have a `C`
153         // export level, however, as they're just implementation details.
154         // Down below we'll hardwire all of the symbols to the `Rust` export
155         // level instead.
156         let special_runtime_crate =
157             tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
158
159         // Dealing with compiler-builtins and wasm right now is super janky.
160         // There's no linker! As a result we need all of the compiler-builtins
161         // exported symbols to make their way through all the way to the end of
162         // compilation. We want to make sure that LLVM doesn't remove them as
163         // well because we may or may not need them in the final output
164         // artifact. For now just force them to always get exported at the C
165         // layer, and we'll worry about gc'ing them later.
166         let compiler_builtins_and_binaryen =
167             tcx.is_compiler_builtins(cnum) &&
168             tcx.sess.linker_flavor() == LinkerFlavor::Binaryen;
169
170         let mut crate_exports: Vec<_> = tcx
171             .exported_symbol_ids(cnum)
172             .iter()
173             .map(|&def_id| {
174                 let name = tcx.symbol_name(Instance::mono(tcx, def_id));
175                 let export_level = if compiler_builtins_and_binaryen &&
176                                       tcx.contains_extern_indicator(def_id) {
177                     SymbolExportLevel::C
178                 } else if special_runtime_crate {
179                     // We can probably do better here by just ensuring that
180                     // it has hidden visibility rather than public
181                     // visibility, as this is primarily here to ensure it's
182                     // not stripped during LTO.
183                     //
184                     // In general though we won't link right if these
185                     // symbols are stripped, and LTO currently strips them.
186                     if &*name == "rust_eh_personality" ||
187                        &*name == "rust_eh_register_frames" ||
188                        &*name == "rust_eh_unregister_frames" {
189                         SymbolExportLevel::C
190                     } else {
191                         SymbolExportLevel::Rust
192                     }
193                 } else {
194                     export_level(tcx, def_id)
195                 };
196                 debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
197                 (str::to_owned(&name), Some(def_id), export_level)
198             })
199             .collect();
200
201         // Sort so we get a stable incr. comp. hash.
202         crate_exports.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| {
203             name1.cmp(name2)
204         });
205
206         Arc::new(crate_exports)
207     };
208     providers.symbol_export_level = export_level;
209 }
210
211 fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
212     // We export anything that's not mangled at the "C" layer as it probably has
213     // to do with ABI concerns. We do not, however, apply such treatment to
214     // special symbols in the standard library for various plumbing between
215     // core/std/allocators/etc. For example symbols used to hook up allocation
216     // are not considered for export
217     let is_extern = tcx.contains_extern_indicator(sym_def_id);
218     let std_internal = attr::contains_name(&tcx.get_attrs(sym_def_id),
219                                            "rustc_std_internal_symbol");
220     if is_extern && !std_internal {
221         SymbolExportLevel::C
222     } else {
223         SymbolExportLevel::Rust
224     }
225 }