]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/mono.rs
Ensure StorageDead is created even if variable initialization fails
[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;
12 use syntax::ast::NodeId;
13 use syntax::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::hash::Hash;
21
22 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
23 pub enum MonoItem<'tcx> {
24     Fn(Instance<'tcx>),
25     Static(DefId),
26     GlobalAsm(NodeId),
27 }
28
29 impl<'tcx> MonoItem<'tcx> {
30     pub fn size_estimate<'a>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> usize {
31         match *self {
32             MonoItem::Fn(instance) => {
33                 // Estimate the size of a function based on how many statements
34                 // it contains.
35                 tcx.instance_def_size_estimate(instance.def)
36             },
37             // Conservatively estimate the size of a static declaration
38             // or assembly to be 1.
39             MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
40         }
41     }
42 }
43
44 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
45     fn hash_stable<W: StableHasherResult>(&self,
46                                            hcx: &mut StableHashingContext<'a>,
47                                            hasher: &mut StableHasher<W>) {
48         ::std::mem::discriminant(self).hash_stable(hcx, hasher);
49
50         match *self {
51             MonoItem::Fn(ref instance) => {
52                 instance.hash_stable(hcx, hasher);
53             }
54             MonoItem::Static(def_id) => {
55                 def_id.hash_stable(hcx, hasher);
56             }
57             MonoItem::GlobalAsm(node_id) => {
58                 hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
59                     node_id.hash_stable(hcx, hasher);
60                 })
61             }
62         }
63     }
64 }
65
66 pub struct CodegenUnit<'tcx> {
67     /// A name for this CGU. Incremental compilation requires that
68     /// name be unique amongst **all** crates.  Therefore, it should
69     /// contain something unique to this crate (e.g., a module path)
70     /// as well as the crate name and disambiguator.
71     name: InternedString,
72     items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
73     size_estimate: Option<usize>,
74 }
75
76 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
77 pub enum Linkage {
78     External,
79     AvailableExternally,
80     LinkOnceAny,
81     LinkOnceODR,
82     WeakAny,
83     WeakODR,
84     Appending,
85     Internal,
86     Private,
87     ExternalWeak,
88     Common,
89 }
90
91 impl_stable_hash_for!(enum self::Linkage {
92     External,
93     AvailableExternally,
94     LinkOnceAny,
95     LinkOnceODR,
96     WeakAny,
97     WeakODR,
98     Appending,
99     Internal,
100     Private,
101     ExternalWeak,
102     Common
103 });
104
105 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
106 pub enum Visibility {
107     Default,
108     Hidden,
109     Protected,
110 }
111
112 impl_stable_hash_for!(enum self::Visibility {
113     Default,
114     Hidden,
115     Protected
116 });
117
118 impl<'tcx> CodegenUnit<'tcx> {
119     pub fn new(name: InternedString) -> CodegenUnit<'tcx> {
120         CodegenUnit {
121             name: name,
122             items: FxHashMap(),
123             size_estimate: None,
124         }
125     }
126
127     pub fn name(&self) -> &InternedString {
128         &self.name
129     }
130
131     pub fn set_name(&mut self, name: InternedString) {
132         self.name = name;
133     }
134
135     pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> {
136         &self.items
137     }
138
139     pub fn items_mut(&mut self)
140         -> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>
141     {
142         &mut self.items
143     }
144
145     pub fn mangle_name(human_readable_name: &str) -> String {
146         // We generate a 80 bit hash from the name. This should be enough to
147         // avoid collisions and is still reasonably short for filenames.
148         let mut hasher = StableHasher::new();
149         human_readable_name.hash(&mut hasher);
150         let hash: u128 = hasher.finish();
151         let hash = hash & ((1u128 << 80) - 1);
152         base_n::encode(hash, base_n::CASE_INSENSITIVE)
153     }
154
155     pub fn estimate_size<'a>(&mut self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) {
156         // Estimate the size of a codegen unit as (approximately) the number of MIR
157         // statements it corresponds to.
158         self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
159     }
160
161     pub fn size_estimate(&self) -> usize {
162         // Should only be called if `estimate_size` has previously been called.
163         self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
164     }
165
166     pub fn modify_size_estimate(&mut self, delta: usize) {
167         assert!(self.size_estimate.is_some());
168         if let Some(size_estimate) = self.size_estimate {
169             self.size_estimate = Some(size_estimate + delta);
170         }
171     }
172 }
173
174 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
175     fn hash_stable<W: StableHasherResult>(&self,
176                                            hcx: &mut StableHashingContext<'a>,
177                                            hasher: &mut StableHasher<W>) {
178         let CodegenUnit {
179             ref items,
180             name,
181             // The size estimate is not relevant to the hash
182             size_estimate: _,
183         } = *self;
184
185         name.hash_stable(hcx, hasher);
186
187         let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(mono_item, &attrs)| {
188             let mut hasher = StableHasher::new();
189             mono_item.hash_stable(hcx, &mut hasher);
190             let mono_item_fingerprint = hasher.finish();
191             (mono_item_fingerprint, attrs)
192         }).collect();
193
194         items.sort_unstable_by_key(|i| i.0);
195         items.hash_stable(hcx, hasher);
196     }
197 }
198
199 #[derive(Clone, Default)]
200 pub struct Stats {
201     pub n_glues_created: usize,
202     pub n_null_glues: usize,
203     pub n_real_glues: usize,
204     pub n_fns: usize,
205     pub n_inlines: usize,
206     pub n_closures: usize,
207     pub n_llvm_insns: usize,
208     pub llvm_insns: FxHashMap<String, usize>,
209     // (ident, llvm-instructions)
210     pub fn_stats: Vec<(String, usize)>,
211 }
212
213 impl_stable_hash_for!(struct self::Stats {
214     n_glues_created,
215     n_null_glues,
216     n_real_glues,
217     n_fns,
218     n_inlines,
219     n_closures,
220     n_llvm_insns,
221     llvm_insns,
222     fn_stats
223 });
224
225 impl Stats {
226     pub fn extend(&mut self, stats: Stats) {
227         self.n_glues_created += stats.n_glues_created;
228         self.n_null_glues += stats.n_null_glues;
229         self.n_real_glues += stats.n_real_glues;
230         self.n_fns += stats.n_fns;
231         self.n_inlines += stats.n_inlines;
232         self.n_closures += stats.n_closures;
233         self.n_llvm_insns += stats.n_llvm_insns;
234
235         for (k, v) in stats.llvm_insns {
236             *self.llvm_insns.entry(k).or_insert(0) += v;
237         }
238         self.fn_stats.extend(stats.fn_stats);
239     }
240 }