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.
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.
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,
19 use ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
23 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
24 pub enum MonoItem<'tcx> {
30 impl<'tcx> MonoItem<'tcx> {
31 pub fn size_estimate<'a>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> usize {
33 MonoItem::Fn(instance) => {
34 // Estimate the size of a function based on how many statements
36 tcx.instance_def_size_estimate(instance.def)
38 // Conservatively estimate the size of a static declaration
39 // or assembly to be 1.
41 MonoItem::GlobalAsm(_) => 1,
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);
53 MonoItem::Fn(ref instance) => {
54 instance.hash_stable(hcx, hasher);
56 MonoItem::Static(def_id) => {
57 def_id.hash_stable(hcx, hasher);
59 MonoItem::GlobalAsm(node_id) => {
60 hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
61 node_id.hash_stable(hcx, hasher);
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.
74 items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
75 size_estimate: Option<usize>,
78 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
93 impl_stable_hash_for!(enum self::Linkage {
107 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
108 pub enum Visibility {
114 impl_stable_hash_for!(enum self::Visibility {
120 impl<'tcx> CodegenUnit<'tcx> {
121 pub fn new(name: InternedString) -> CodegenUnit<'tcx> {
124 items: Default::default(),
129 pub fn name(&self) -> &InternedString {
133 pub fn set_name(&mut self, name: InternedString) {
137 pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> {
141 pub fn items_mut(&mut self)
142 -> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>
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)
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());
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")
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);
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>) {
183 // The size estimate is not relevant to the hash
187 name.hash_stable(hcx, hasher);
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)
196 items.sort_unstable_by_key(|i| i.0);
197 items.hash_stable(hcx, hasher);
201 #[derive(Clone, Default)]
203 pub n_glues_created: usize,
204 pub n_null_glues: usize,
205 pub n_real_glues: 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)>,
215 impl_stable_hash_for!(struct self::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;
237 for (k, v) in stats.llvm_insns {
238 *self.llvm_insns.entry(k).or_insert(0) += v;
240 self.fn_stats.extend(stats.fn_stats);
244 pub struct CodegenUnitNameBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
245 tcx: TyCtxt<'a, 'gcx, 'tcx>,
246 cache: FxHashMap<CrateNum, String>,
249 impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
251 pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
252 CodegenUnitNameBuilder {
254 cache: Default::default(),
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.
263 /// Consequently, we don't use special characters except for '.' and '-' and we
264 /// prefix each name with the crate-name and crate-disambiguator.
266 /// This function will build CGU names of the form:
269 /// <crate-name>.<crate-disambiguator>[-in-<local-crate-id>](-<component>)*[.<special-suffix>]
270 /// <local-crate-id> = <local-crate-name>.<local-crate-disambiguator>
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,
279 special_suffix: Option<S>)
281 where I: IntoIterator<Item=C>,
285 let cgu_name = self.build_cgu_name_no_mangle(cnum,
289 if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
292 let cgu_name = &cgu_name.as_str()[..];
293 Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
297 /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
299 pub fn build_cgu_name_no_mangle<I, C, S>(&mut self,
302 special_suffix: Option<S>)
304 where I: IntoIterator<Item=C>,
310 let mut cgu_name = String::with_capacity(64);
312 // Start out with the crate name and disambiguator
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));
322 tcx.crate_name(LOCAL_CRATE),
323 &local_crate_disambiguator[0 .. 8])
328 let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
329 // Using a shortened disambiguator of about 40 bits
331 tcx.crate_name(cnum),
332 &crate_disambiguator[0 .. 8],
336 write!(cgu_name, "{}", crate_prefix).unwrap();
338 // Add the components
339 for component in components {
340 write!(cgu_name, "-{}", component).unwrap();
343 if let Some(special_suffix) = special_suffix {
344 // We add a dot in here so it cannot clash with anything in a regular
346 write!(cgu_name, ".{}", special_suffix).unwrap();
349 Symbol::intern(&cgu_name[..]).as_interned_str()