]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/mono.rs
a26468b0fb6ce0560bc1a1cb46c404dddd0a1872
[rust.git] / src / librustc / mir / mono.rs
1 use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
2 use crate::hir::HirId;
3 use syntax::symbol::InternedString;
4 use crate::ty::{Instance, TyCtxt};
5 use crate::util::nodemap::FxHashMap;
6 use rustc_data_structures::base_n;
7 use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
8                                            StableHasher};
9 use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
10 use std::fmt;
11 use std::hash::Hash;
12
13 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
14 pub enum MonoItem<'tcx> {
15     Fn(Instance<'tcx>),
16     Static(DefId),
17     GlobalAsm(HirId),
18 }
19
20 impl<'tcx> MonoItem<'tcx> {
21     pub fn size_estimate<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> usize {
22         match *self {
23             MonoItem::Fn(instance) => {
24                 // Estimate the size of a function based on how many statements
25                 // it contains.
26                 tcx.instance_def_size_estimate(instance.def)
27             },
28             // Conservatively estimate the size of a static declaration
29             // or assembly to be 1.
30             MonoItem::Static(_) |
31             MonoItem::GlobalAsm(_) => 1,
32         }
33     }
34 }
35
36 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
37     fn hash_stable<W: StableHasherResult>(&self,
38                                            hcx: &mut StableHashingContext<'a>,
39                                            hasher: &mut StableHasher<W>) {
40         ::std::mem::discriminant(self).hash_stable(hcx, hasher);
41
42         match *self {
43             MonoItem::Fn(ref instance) => {
44                 instance.hash_stable(hcx, hasher);
45             }
46             MonoItem::Static(def_id) => {
47                 def_id.hash_stable(hcx, hasher);
48             }
49             MonoItem::GlobalAsm(node_id) => {
50                 hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
51                     node_id.hash_stable(hcx, hasher);
52                 })
53             }
54         }
55     }
56 }
57
58 pub struct CodegenUnit<'tcx> {
59     /// A name for this CGU. Incremental compilation requires that
60     /// name be unique amongst **all** crates. Therefore, it should
61     /// contain something unique to this crate (e.g., a module path)
62     /// as well as the crate name and disambiguator.
63     name: InternedString,
64     items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
65     size_estimate: Option<usize>,
66 }
67
68 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
69 pub enum Linkage {
70     External,
71     AvailableExternally,
72     LinkOnceAny,
73     LinkOnceODR,
74     WeakAny,
75     WeakODR,
76     Appending,
77     Internal,
78     Private,
79     ExternalWeak,
80     Common,
81 }
82
83 impl_stable_hash_for!(enum self::Linkage {
84     External,
85     AvailableExternally,
86     LinkOnceAny,
87     LinkOnceODR,
88     WeakAny,
89     WeakODR,
90     Appending,
91     Internal,
92     Private,
93     ExternalWeak,
94     Common
95 });
96
97 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
98 pub enum Visibility {
99     Default,
100     Hidden,
101     Protected,
102 }
103
104 impl_stable_hash_for!(enum self::Visibility {
105     Default,
106     Hidden,
107     Protected
108 });
109
110 impl<'tcx> CodegenUnit<'tcx> {
111     pub fn new(name: InternedString) -> CodegenUnit<'tcx> {
112         CodegenUnit {
113             name: name,
114             items: Default::default(),
115             size_estimate: None,
116         }
117     }
118
119     pub fn name(&self) -> &InternedString {
120         &self.name
121     }
122
123     pub fn set_name(&mut self, name: InternedString) {
124         self.name = name;
125     }
126
127     pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> {
128         &self.items
129     }
130
131     pub fn items_mut(&mut self)
132         -> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>
133     {
134         &mut self.items
135     }
136
137     pub fn mangle_name(human_readable_name: &str) -> String {
138         // We generate a 80 bit hash from the name. This should be enough to
139         // avoid collisions and is still reasonably short for filenames.
140         let mut hasher = StableHasher::new();
141         human_readable_name.hash(&mut hasher);
142         let hash: u128 = hasher.finish();
143         let hash = hash & ((1u128 << 80) - 1);
144         base_n::encode(hash, base_n::CASE_INSENSITIVE)
145     }
146
147     pub fn estimate_size<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
148         // Estimate the size of a codegen unit as (approximately) the number of MIR
149         // statements it corresponds to.
150         self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
151     }
152
153     pub fn size_estimate(&self) -> usize {
154         // Should only be called if `estimate_size` has previously been called.
155         self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
156     }
157
158     pub fn modify_size_estimate(&mut self, delta: usize) {
159         assert!(self.size_estimate.is_some());
160         if let Some(size_estimate) = self.size_estimate {
161             self.size_estimate = Some(size_estimate + delta);
162         }
163     }
164 }
165
166 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
167     fn hash_stable<W: StableHasherResult>(&self,
168                                            hcx: &mut StableHashingContext<'a>,
169                                            hasher: &mut StableHasher<W>) {
170         let CodegenUnit {
171             ref items,
172             name,
173             // The size estimate is not relevant to the hash
174             size_estimate: _,
175         } = *self;
176
177         name.hash_stable(hcx, hasher);
178
179         let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(mono_item, &attrs)| {
180             let mut hasher = StableHasher::new();
181             mono_item.hash_stable(hcx, &mut hasher);
182             let mono_item_fingerprint = hasher.finish();
183             (mono_item_fingerprint, attrs)
184         }).collect();
185
186         items.sort_unstable_by_key(|i| i.0);
187         items.hash_stable(hcx, hasher);
188     }
189 }
190
191 #[derive(Clone, Default)]
192 pub struct Stats {
193     pub n_glues_created: usize,
194     pub n_null_glues: usize,
195     pub n_real_glues: usize,
196     pub n_fns: usize,
197     pub n_inlines: usize,
198     pub n_closures: usize,
199     pub n_llvm_insns: usize,
200     pub llvm_insns: FxHashMap<String, usize>,
201     // (ident, llvm-instructions)
202     pub fn_stats: Vec<(String, usize)>,
203 }
204
205 impl_stable_hash_for!(struct self::Stats {
206     n_glues_created,
207     n_null_glues,
208     n_real_glues,
209     n_fns,
210     n_inlines,
211     n_closures,
212     n_llvm_insns,
213     llvm_insns,
214     fn_stats
215 });
216
217 impl Stats {
218     pub fn extend(&mut self, stats: Stats) {
219         self.n_glues_created += stats.n_glues_created;
220         self.n_null_glues += stats.n_null_glues;
221         self.n_real_glues += stats.n_real_glues;
222         self.n_fns += stats.n_fns;
223         self.n_inlines += stats.n_inlines;
224         self.n_closures += stats.n_closures;
225         self.n_llvm_insns += stats.n_llvm_insns;
226
227         for (k, v) in stats.llvm_insns {
228             *self.llvm_insns.entry(k).or_insert(0) += v;
229         }
230         self.fn_stats.extend(stats.fn_stats);
231     }
232 }
233
234 pub struct CodegenUnitNameBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
235     tcx: TyCtxt<'a, 'gcx, 'tcx>,
236     cache: FxHashMap<CrateNum, String>,
237 }
238
239 impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
240
241     pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
242         CodegenUnitNameBuilder {
243             tcx,
244             cache: Default::default(),
245         }
246     }
247
248     /// CGU names should fulfill the following requirements:
249     /// - They should be able to act as a file name on any kind of file system
250     /// - They should not collide with other CGU names, even for different versions
251     ///   of the same crate.
252     ///
253     /// Consequently, we don't use special characters except for '.' and '-' and we
254     /// prefix each name with the crate-name and crate-disambiguator.
255     ///
256     /// This function will build CGU names of the form:
257     ///
258     /// ```
259     /// <crate-name>.<crate-disambiguator>[-in-<local-crate-id>](-<component>)*[.<special-suffix>]
260     /// <local-crate-id> = <local-crate-name>.<local-crate-disambiguator>
261     /// ```
262     ///
263     /// The '.' before `<special-suffix>` makes sure that names with a special
264     /// suffix can never collide with a name built out of regular Rust
265     /// identifiers (e.g., module paths).
266     pub fn build_cgu_name<I, C, S>(&mut self,
267                                    cnum: CrateNum,
268                                    components: I,
269                                    special_suffix: Option<S>)
270                                    -> InternedString
271         where I: IntoIterator<Item=C>,
272               C: fmt::Display,
273               S: fmt::Display,
274     {
275         let cgu_name = self.build_cgu_name_no_mangle(cnum,
276                                                      components,
277                                                      special_suffix);
278
279         if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
280             cgu_name
281         } else {
282             let cgu_name = &cgu_name.as_str()[..];
283             InternedString::intern(&CodegenUnit::mangle_name(cgu_name))
284         }
285     }
286
287     /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
288     /// resulting name.
289     pub fn build_cgu_name_no_mangle<I, C, S>(&mut self,
290                                              cnum: CrateNum,
291                                              components: I,
292                                              special_suffix: Option<S>)
293                                              -> InternedString
294         where I: IntoIterator<Item=C>,
295               C: fmt::Display,
296               S: fmt::Display,
297     {
298         use std::fmt::Write;
299
300         let mut cgu_name = String::with_capacity(64);
301
302         // Start out with the crate name and disambiguator
303         let tcx = self.tcx;
304         let crate_prefix = self.cache.entry(cnum).or_insert_with(|| {
305             // Whenever the cnum is not LOCAL_CRATE we also mix in the
306             // local crate's ID. Otherwise there can be collisions between CGUs
307             // instantiating stuff for upstream crates.
308             let local_crate_id = if cnum != LOCAL_CRATE {
309                 let local_crate_disambiguator =
310                     format!("{}", tcx.crate_disambiguator(LOCAL_CRATE));
311                 format!("-in-{}.{}",
312                         tcx.crate_name(LOCAL_CRATE),
313                         &local_crate_disambiguator[0 .. 8])
314             } else {
315                 String::new()
316             };
317
318             let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
319             // Using a shortened disambiguator of about 40 bits
320             format!("{}.{}{}",
321                 tcx.crate_name(cnum),
322                 &crate_disambiguator[0 .. 8],
323                 local_crate_id)
324         });
325
326         write!(cgu_name, "{}", crate_prefix).unwrap();
327
328         // Add the components
329         for component in components {
330             write!(cgu_name, "-{}", component).unwrap();
331         }
332
333         if let Some(special_suffix) = special_suffix {
334             // We add a dot in here so it cannot clash with anything in a regular
335             // Rust identifier
336             write!(cgu_name, ".{}", special_suffix).unwrap();
337         }
338
339         InternedString::intern(&cgu_name[..])
340     }
341 }