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