2019-02-05 11:20:45 -06:00
|
|
|
use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
|
2017-09-12 11:04:46 -07:00
|
|
|
use syntax::ast::NodeId;
|
2018-07-10 19:16:22 +02:00
|
|
|
use syntax::symbol::{Symbol, InternedString};
|
2019-02-05 11:20:45 -06:00
|
|
|
use crate::ty::{Instance, TyCtxt};
|
|
|
|
use crate::util::nodemap::FxHashMap;
|
2018-01-08 12:30:52 +01:00
|
|
|
use rustc_data_structures::base_n;
|
2017-09-18 12:14:52 +02:00
|
|
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
|
|
|
|
StableHasher};
|
2019-02-05 11:20:45 -06:00
|
|
|
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
|
2018-07-10 19:16:22 +02:00
|
|
|
use std::fmt;
|
2018-01-08 12:30:52 +01:00
|
|
|
use std::hash::Hash;
|
2017-09-12 11:04:46 -07:00
|
|
|
|
|
|
|
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
|
2017-10-25 17:04:24 +02:00
|
|
|
pub enum MonoItem<'tcx> {
|
2017-09-12 11:04:46 -07:00
|
|
|
Fn(Instance<'tcx>),
|
2018-02-19 13:29:22 +01:00
|
|
|
Static(DefId),
|
2017-09-12 11:04:46 -07:00
|
|
|
GlobalAsm(NodeId),
|
|
|
|
}
|
|
|
|
|
2018-01-15 18:28:34 +00:00
|
|
|
impl<'tcx> MonoItem<'tcx> {
|
|
|
|
pub fn size_estimate<'a>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> usize {
|
|
|
|
match *self {
|
|
|
|
MonoItem::Fn(instance) => {
|
|
|
|
// Estimate the size of a function based on how many statements
|
|
|
|
// it contains.
|
2018-01-19 00:32:58 +00:00
|
|
|
tcx.instance_def_size_estimate(instance.def)
|
2018-01-15 18:28:34 +00:00
|
|
|
},
|
|
|
|
// Conservatively estimate the size of a static declaration
|
|
|
|
// or assembly to be 1.
|
2018-06-01 10:20:00 -07:00
|
|
|
MonoItem::Static(_) |
|
2018-07-13 11:30:47 -07:00
|
|
|
MonoItem::GlobalAsm(_) => 1,
|
2018-01-15 18:28:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-16 10:16:38 +01:00
|
|
|
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
|
2017-09-18 12:14:52 +02:00
|
|
|
fn hash_stable<W: StableHasherResult>(&self,
|
2018-01-16 10:16:38 +01:00
|
|
|
hcx: &mut StableHashingContext<'a>,
|
2017-09-18 12:14:52 +02:00
|
|
|
hasher: &mut StableHasher<W>) {
|
|
|
|
::std::mem::discriminant(self).hash_stable(hcx, hasher);
|
|
|
|
|
|
|
|
match *self {
|
2017-10-25 17:04:24 +02:00
|
|
|
MonoItem::Fn(ref instance) => {
|
2017-09-18 12:14:52 +02:00
|
|
|
instance.hash_stable(hcx, hasher);
|
|
|
|
}
|
2018-07-13 11:30:47 -07:00
|
|
|
MonoItem::Static(def_id) => {
|
2018-02-19 13:29:22 +01:00
|
|
|
def_id.hash_stable(hcx, hasher);
|
|
|
|
}
|
2017-10-25 17:04:24 +02:00
|
|
|
MonoItem::GlobalAsm(node_id) => {
|
2017-09-18 12:14:52 +02:00
|
|
|
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
|
|
|
node_id.hash_stable(hcx, hasher);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-12 11:04:46 -07:00
|
|
|
pub struct CodegenUnit<'tcx> {
|
|
|
|
/// A name for this CGU. Incremental compilation requires that
|
|
|
|
/// name be unique amongst **all** crates. Therefore, it should
|
|
|
|
/// contain something unique to this crate (e.g., a module path)
|
|
|
|
/// as well as the crate name and disambiguator.
|
|
|
|
name: InternedString,
|
2017-10-25 17:04:24 +02:00
|
|
|
items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
|
2018-01-15 18:28:34 +00:00
|
|
|
size_estimate: Option<usize>,
|
2017-09-12 11:04:46 -07:00
|
|
|
}
|
|
|
|
|
2018-02-27 22:08:46 -05:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
2017-09-12 11:04:46 -07:00
|
|
|
pub enum Linkage {
|
|
|
|
External,
|
|
|
|
AvailableExternally,
|
|
|
|
LinkOnceAny,
|
|
|
|
LinkOnceODR,
|
|
|
|
WeakAny,
|
|
|
|
WeakODR,
|
|
|
|
Appending,
|
|
|
|
Internal,
|
|
|
|
Private,
|
|
|
|
ExternalWeak,
|
|
|
|
Common,
|
|
|
|
}
|
|
|
|
|
2017-09-18 12:14:52 +02:00
|
|
|
impl_stable_hash_for!(enum self::Linkage {
|
|
|
|
External,
|
|
|
|
AvailableExternally,
|
|
|
|
LinkOnceAny,
|
|
|
|
LinkOnceODR,
|
|
|
|
WeakAny,
|
|
|
|
WeakODR,
|
|
|
|
Appending,
|
|
|
|
Internal,
|
|
|
|
Private,
|
|
|
|
ExternalWeak,
|
|
|
|
Common
|
|
|
|
});
|
|
|
|
|
2017-09-12 11:04:46 -07:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
|
|
|
pub enum Visibility {
|
|
|
|
Default,
|
|
|
|
Hidden,
|
|
|
|
Protected,
|
|
|
|
}
|
|
|
|
|
2017-09-18 12:14:52 +02:00
|
|
|
impl_stable_hash_for!(enum self::Visibility {
|
|
|
|
Default,
|
|
|
|
Hidden,
|
|
|
|
Protected
|
|
|
|
});
|
|
|
|
|
2017-09-12 11:04:46 -07:00
|
|
|
impl<'tcx> CodegenUnit<'tcx> {
|
|
|
|
pub fn new(name: InternedString) -> CodegenUnit<'tcx> {
|
|
|
|
CodegenUnit {
|
|
|
|
name: name,
|
2018-10-16 16:57:53 +02:00
|
|
|
items: Default::default(),
|
2018-01-15 18:28:34 +00:00
|
|
|
size_estimate: None,
|
2017-09-12 11:04:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn name(&self) -> &InternedString {
|
|
|
|
&self.name
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_name(&mut self, name: InternedString) {
|
|
|
|
self.name = name;
|
|
|
|
}
|
|
|
|
|
2017-10-25 17:04:24 +02:00
|
|
|
pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)> {
|
2017-09-12 11:04:46 -07:00
|
|
|
&self.items
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn items_mut(&mut self)
|
2017-10-25 17:04:24 +02:00
|
|
|
-> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>
|
2017-09-12 11:04:46 -07:00
|
|
|
{
|
|
|
|
&mut self.items
|
|
|
|
}
|
2018-01-08 12:30:52 +01:00
|
|
|
|
|
|
|
pub fn mangle_name(human_readable_name: &str) -> String {
|
|
|
|
// We generate a 80 bit hash from the name. This should be enough to
|
|
|
|
// avoid collisions and is still reasonably short for filenames.
|
|
|
|
let mut hasher = StableHasher::new();
|
|
|
|
human_readable_name.hash(&mut hasher);
|
|
|
|
let hash: u128 = hasher.finish();
|
|
|
|
let hash = hash & ((1u128 << 80) - 1);
|
|
|
|
base_n::encode(hash, base_n::CASE_INSENSITIVE)
|
|
|
|
}
|
2018-01-15 18:28:34 +00:00
|
|
|
|
|
|
|
pub fn estimate_size<'a>(&mut self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) {
|
|
|
|
// Estimate the size of a codegen unit as (approximately) the number of MIR
|
|
|
|
// statements it corresponds to.
|
|
|
|
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn size_estimate(&self) -> usize {
|
|
|
|
// Should only be called if `estimate_size` has previously been called.
|
2018-01-19 11:51:48 +00:00
|
|
|
self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
|
2018-01-15 18:28:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn modify_size_estimate(&mut self, delta: usize) {
|
|
|
|
assert!(self.size_estimate.is_some());
|
|
|
|
if let Some(size_estimate) = self.size_estimate {
|
|
|
|
self.size_estimate = Some(size_estimate + delta);
|
|
|
|
}
|
|
|
|
}
|
2017-09-12 11:04:46 -07:00
|
|
|
}
|
2017-09-13 20:26:39 -07:00
|
|
|
|
2018-01-16 10:16:38 +01:00
|
|
|
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
|
2017-09-18 12:14:52 +02:00
|
|
|
fn hash_stable<W: StableHasherResult>(&self,
|
2018-01-16 10:16:38 +01:00
|
|
|
hcx: &mut StableHashingContext<'a>,
|
2017-09-18 12:14:52 +02:00
|
|
|
hasher: &mut StableHasher<W>) {
|
|
|
|
let CodegenUnit {
|
|
|
|
ref items,
|
|
|
|
name,
|
2018-01-19 11:51:48 +00:00
|
|
|
// The size estimate is not relevant to the hash
|
|
|
|
size_estimate: _,
|
2017-09-18 12:14:52 +02:00
|
|
|
} = *self;
|
|
|
|
|
|
|
|
name.hash_stable(hcx, hasher);
|
|
|
|
|
2018-05-08 16:10:16 +03:00
|
|
|
let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(mono_item, &attrs)| {
|
2017-09-18 12:14:52 +02:00
|
|
|
let mut hasher = StableHasher::new();
|
2018-05-08 16:10:16 +03:00
|
|
|
mono_item.hash_stable(hcx, &mut hasher);
|
|
|
|
let mono_item_fingerprint = hasher.finish();
|
|
|
|
(mono_item_fingerprint, attrs)
|
2017-09-18 12:14:52 +02:00
|
|
|
}).collect();
|
|
|
|
|
|
|
|
items.sort_unstable_by_key(|i| i.0);
|
|
|
|
items.hash_stable(hcx, hasher);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-13 20:26:39 -07:00
|
|
|
#[derive(Clone, Default)]
|
|
|
|
pub struct Stats {
|
|
|
|
pub n_glues_created: usize,
|
|
|
|
pub n_null_glues: usize,
|
|
|
|
pub n_real_glues: usize,
|
|
|
|
pub n_fns: usize,
|
|
|
|
pub n_inlines: usize,
|
|
|
|
pub n_closures: usize,
|
|
|
|
pub n_llvm_insns: usize,
|
|
|
|
pub llvm_insns: FxHashMap<String, usize>,
|
|
|
|
// (ident, llvm-instructions)
|
|
|
|
pub fn_stats: Vec<(String, usize)>,
|
|
|
|
}
|
|
|
|
|
2017-09-18 12:14:52 +02:00
|
|
|
impl_stable_hash_for!(struct self::Stats {
|
|
|
|
n_glues_created,
|
|
|
|
n_null_glues,
|
|
|
|
n_real_glues,
|
|
|
|
n_fns,
|
|
|
|
n_inlines,
|
|
|
|
n_closures,
|
|
|
|
n_llvm_insns,
|
|
|
|
llvm_insns,
|
|
|
|
fn_stats
|
|
|
|
});
|
|
|
|
|
2017-09-13 20:26:39 -07:00
|
|
|
impl Stats {
|
|
|
|
pub fn extend(&mut self, stats: Stats) {
|
|
|
|
self.n_glues_created += stats.n_glues_created;
|
|
|
|
self.n_null_glues += stats.n_null_glues;
|
|
|
|
self.n_real_glues += stats.n_real_glues;
|
|
|
|
self.n_fns += stats.n_fns;
|
|
|
|
self.n_inlines += stats.n_inlines;
|
|
|
|
self.n_closures += stats.n_closures;
|
|
|
|
self.n_llvm_insns += stats.n_llvm_insns;
|
|
|
|
|
|
|
|
for (k, v) in stats.llvm_insns {
|
|
|
|
*self.llvm_insns.entry(k).or_insert(0) += v;
|
|
|
|
}
|
|
|
|
self.fn_stats.extend(stats.fn_stats);
|
|
|
|
}
|
|
|
|
}
|
2018-08-14 17:55:22 +02:00
|
|
|
|
|
|
|
pub struct CodegenUnitNameBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|
|
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|
|
|
cache: FxHashMap<CrateNum, String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> {
|
|
|
|
|
|
|
|
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
|
|
|
|
CodegenUnitNameBuilder {
|
|
|
|
tcx,
|
2018-10-16 16:57:53 +02:00
|
|
|
cache: Default::default(),
|
2018-08-14 17:55:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// CGU names should fulfill the following requirements:
|
|
|
|
/// - They should be able to act as a file name on any kind of file system
|
|
|
|
/// - They should not collide with other CGU names, even for different versions
|
|
|
|
/// of the same crate.
|
|
|
|
///
|
|
|
|
/// Consequently, we don't use special characters except for '.' and '-' and we
|
|
|
|
/// prefix each name with the crate-name and crate-disambiguator.
|
|
|
|
///
|
|
|
|
/// This function will build CGU names of the form:
|
|
|
|
///
|
|
|
|
/// ```
|
2018-09-12 12:46:48 +02:00
|
|
|
/// <crate-name>.<crate-disambiguator>[-in-<local-crate-id>](-<component>)*[.<special-suffix>]
|
|
|
|
/// <local-crate-id> = <local-crate-name>.<local-crate-disambiguator>
|
2018-08-14 17:55:22 +02:00
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The '.' before `<special-suffix>` makes sure that names with a special
|
|
|
|
/// suffix can never collide with a name built out of regular Rust
|
2018-11-27 02:59:49 +00:00
|
|
|
/// identifiers (e.g., module paths).
|
2018-08-14 17:55:22 +02:00
|
|
|
pub fn build_cgu_name<I, C, S>(&mut self,
|
|
|
|
cnum: CrateNum,
|
|
|
|
components: I,
|
|
|
|
special_suffix: Option<S>)
|
|
|
|
-> InternedString
|
|
|
|
where I: IntoIterator<Item=C>,
|
|
|
|
C: fmt::Display,
|
|
|
|
S: fmt::Display,
|
|
|
|
{
|
|
|
|
let cgu_name = self.build_cgu_name_no_mangle(cnum,
|
|
|
|
components,
|
|
|
|
special_suffix);
|
|
|
|
|
|
|
|
if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
|
|
|
|
cgu_name
|
|
|
|
} else {
|
|
|
|
let cgu_name = &cgu_name.as_str()[..];
|
|
|
|
Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
|
|
|
|
/// resulting name.
|
|
|
|
pub fn build_cgu_name_no_mangle<I, C, S>(&mut self,
|
|
|
|
cnum: CrateNum,
|
|
|
|
components: I,
|
|
|
|
special_suffix: Option<S>)
|
|
|
|
-> InternedString
|
|
|
|
where I: IntoIterator<Item=C>,
|
|
|
|
C: fmt::Display,
|
|
|
|
S: fmt::Display,
|
|
|
|
{
|
|
|
|
use std::fmt::Write;
|
|
|
|
|
|
|
|
let mut cgu_name = String::with_capacity(64);
|
|
|
|
|
|
|
|
// Start out with the crate name and disambiguator
|
|
|
|
let tcx = self.tcx;
|
|
|
|
let crate_prefix = self.cache.entry(cnum).or_insert_with(|| {
|
2018-09-12 12:46:48 +02:00
|
|
|
// Whenever the cnum is not LOCAL_CRATE we also mix in the
|
|
|
|
// local crate's ID. Otherwise there can be collisions between CGUs
|
|
|
|
// instantiating stuff for upstream crates.
|
|
|
|
let local_crate_id = if cnum != LOCAL_CRATE {
|
|
|
|
let local_crate_disambiguator =
|
|
|
|
format!("{}", tcx.crate_disambiguator(LOCAL_CRATE));
|
|
|
|
format!("-in-{}.{}",
|
|
|
|
tcx.crate_name(LOCAL_CRATE),
|
|
|
|
&local_crate_disambiguator[0 .. 8])
|
|
|
|
} else {
|
|
|
|
String::new()
|
|
|
|
};
|
|
|
|
|
2018-10-03 15:07:18 +02:00
|
|
|
let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
|
2018-08-14 17:55:22 +02:00
|
|
|
// Using a shortened disambiguator of about 40 bits
|
2018-09-12 12:46:48 +02:00
|
|
|
format!("{}.{}{}",
|
|
|
|
tcx.crate_name(cnum),
|
|
|
|
&crate_disambiguator[0 .. 8],
|
|
|
|
local_crate_id)
|
2018-08-14 17:55:22 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
write!(cgu_name, "{}", crate_prefix).unwrap();
|
|
|
|
|
|
|
|
// Add the components
|
|
|
|
for component in components {
|
|
|
|
write!(cgu_name, "-{}", component).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(special_suffix) = special_suffix {
|
|
|
|
// We add a dot in here so it cannot clash with anything in a regular
|
|
|
|
// Rust identifier
|
|
|
|
write!(cgu_name, ".{}", special_suffix).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
Symbol::intern(&cgu_name[..]).as_interned_str()
|
|
|
|
}
|
|
|
|
}
|