1 use crate::hir
::def_id
::{DefId, CrateNum, LOCAL_CRATE}
;
3 use syntax
::symbol
::Symbol
;
4 use syntax
::attr
::InlineAttr
;
5 use syntax
::source_map
::Span
;
6 use crate::ty
::{Instance, InstanceDef, TyCtxt, SymbolName, subst::InternalSubsts}
;
7 use crate::util
::nodemap
::FxHashMap
;
8 use crate::ty
::print
::obsolete
::DefPathBasedNames
;
9 use crate::dep_graph
::{WorkProductId, DepNode, WorkProduct, DepConstructor}
;
10 use rustc_data_structures
::base_n
;
11 use rustc_data_structures
::stable_hasher
::{HashStable, StableHasher}
;
12 use crate::ich
::{Fingerprint, StableHashingContext, NodeIdHashingMode}
;
13 use crate::session
::config
::OptLevel
;
17 /// Describes how a monomorphization will be instantiated in object files.
19 pub enum InstantiationMode
{
20 /// There will be exactly one instance of the given MonoItem. It will have
21 /// external linkage so that it can be linked to from other codegen units.
23 /// In some compilation scenarios we may decide to take functions that
24 /// are typically `LocalCopy` and instead move them to `GloballyShared`
25 /// to avoid codegenning them a bunch of times. In this situation,
26 /// however, our local copy may conflict with other crates also
27 /// inlining the same function.
29 /// This flag indicates that this situation is occurring, and informs
30 /// symbol name calculation that some extra mangling is needed to
31 /// avoid conflicts. Note that this may eventually go away entirely if
32 /// ThinLTO enables us to *always* have a globally shared instance of a
33 /// function within one crate's compilation.
37 /// Each codegen unit containing a reference to the given MonoItem will
38 /// have its own private copy of the function (with internal linkage).
42 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
43 pub enum MonoItem
<'tcx
> {
49 impl<'tcx
> MonoItem
<'tcx
> {
50 pub fn size_estimate(&self, tcx
: TyCtxt
<'tcx
>) -> usize {
52 MonoItem
::Fn(instance
) => {
53 // Estimate the size of a function based on how many statements
55 tcx
.instance_def_size_estimate(instance
.def
)
57 // Conservatively estimate the size of a static declaration
58 // or assembly to be 1.
60 MonoItem
::GlobalAsm(_
) => 1,
64 pub fn is_generic_fn(&self) -> bool
{
66 MonoItem
::Fn(ref instance
) => {
67 instance
.substs
.non_erasable_generics().next().is_some()
69 MonoItem
::Static(..) |
70 MonoItem
::GlobalAsm(..) => false,
74 pub fn symbol_name(&self, tcx
: TyCtxt
<'tcx
>) -> SymbolName
{
76 MonoItem
::Fn(instance
) => tcx
.symbol_name(instance
),
77 MonoItem
::Static(def_id
) => {
78 tcx
.symbol_name(Instance
::mono(tcx
, def_id
))
80 MonoItem
::GlobalAsm(hir_id
) => {
81 let def_id
= tcx
.hir().local_def_id(hir_id
);
83 name
: Symbol
::intern(&format
!("global_asm_{:?}", def_id
))
89 pub fn instantiation_mode(&self, tcx
: TyCtxt
<'tcx
>) -> InstantiationMode
{
90 let inline_in_all_cgus
=
91 tcx
.sess
.opts
.debugging_opts
.inline_in_all_cgus
.unwrap_or_else(|| {
92 tcx
.sess
.opts
.optimize
!= OptLevel
::No
93 }) && !tcx
.sess
.opts
.cg
.link_dead_code
;
96 MonoItem
::Fn(ref instance
) => {
97 let entry_def_id
= tcx
.entry_fn(LOCAL_CRATE
).map(|(id
, _
)| id
);
98 // If this function isn't inlined or otherwise has explicit
99 // linkage, then we'll be creating a globally shared version.
100 if self.explicit_linkage(tcx
).is_some() ||
101 !instance
.def
.requires_local(tcx
) ||
102 Some(instance
.def_id()) == entry_def_id
104 return InstantiationMode
::GloballyShared { may_conflict: false }
107 // At this point we don't have explicit linkage and we're an
108 // inlined function. If we're inlining into all CGUs then we'll
109 // be creating a local copy per CGU
110 if inline_in_all_cgus
{
111 return InstantiationMode
::LocalCopy
114 // Finally, if this is `#[inline(always)]` we're sure to respect
115 // that with an inline copy per CGU, but otherwise we'll be
116 // creating one copy of this `#[inline]` function which may
117 // conflict with upstream crates as it could be an exported
119 match tcx
.codegen_fn_attrs(instance
.def_id()).inline
{
120 InlineAttr
::Always
=> InstantiationMode
::LocalCopy
,
122 InstantiationMode
::GloballyShared { may_conflict: true }
126 MonoItem
::Static(..) |
127 MonoItem
::GlobalAsm(..) => {
128 InstantiationMode
::GloballyShared { may_conflict: false }
133 pub fn explicit_linkage(&self, tcx
: TyCtxt
<'tcx
>) -> Option
<Linkage
> {
134 let def_id
= match *self {
135 MonoItem
::Fn(ref instance
) => instance
.def_id(),
136 MonoItem
::Static(def_id
) => def_id
,
137 MonoItem
::GlobalAsm(..) => return None
,
140 let codegen_fn_attrs
= tcx
.codegen_fn_attrs(def_id
);
141 codegen_fn_attrs
.linkage
144 /// Returns `true` if this instance is instantiable - whether it has no unsatisfied
147 /// In order to codegen an item, all of its predicates must hold, because
148 /// otherwise the item does not make sense. Type-checking ensures that
149 /// the predicates of every item that is *used by* a valid item *do*
150 /// hold, so we can rely on that.
152 /// However, we codegen collector roots (reachable items) and functions
153 /// in vtables when they are seen, even if they are not used, and so they
154 /// might not be instantiable. For example, a programmer can define this
157 /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
158 /// <&mut () as Clone>::clone(&s);
161 /// That function can't be codegened, because the method `<&mut () as Clone>::clone`
162 /// does not exist. Luckily for us, that function can't ever be used,
163 /// because that would require for `&'a mut (): Clone` to hold, so we
164 /// can just not emit any code, or even a linker reference for it.
166 /// Similarly, if a vtable method has such a signature, and therefore can't
167 /// be used, we can just not emit it and have a placeholder (a null pointer,
168 /// which will never be accessed) in its place.
169 pub fn is_instantiable(&self, tcx
: TyCtxt
<'tcx
>) -> bool
{
170 debug
!("is_instantiable({:?})", self);
171 let (def_id
, substs
) = match *self {
172 MonoItem
::Fn(ref instance
) => (instance
.def_id(), instance
.substs
),
173 MonoItem
::Static(def_id
) => (def_id
, InternalSubsts
::empty()),
174 // global asm never has predicates
175 MonoItem
::GlobalAsm(..) => return true
178 tcx
.substitute_normalize_and_test_predicates((def_id
, &substs
))
181 pub fn to_string(&self, tcx
: TyCtxt
<'tcx
>, debug
: bool
) -> String
{
183 MonoItem
::Fn(instance
) => {
184 to_string_internal(tcx
, "fn ", instance
, debug
)
186 MonoItem
::Static(def_id
) => {
187 let instance
= Instance
::new(def_id
, tcx
.intern_substs(&[]));
188 to_string_internal(tcx
, "static ", instance
, debug
)
190 MonoItem
::GlobalAsm(..) => {
191 "global_asm".to_string()
195 fn to_string_internal
<'tcx
>(
198 instance
: Instance
<'tcx
>,
201 let mut result
= String
::with_capacity(32);
202 result
.push_str(prefix
);
203 let printer
= DefPathBasedNames
::new(tcx
, false, false);
204 printer
.push_instance_as_string(instance
, &mut result
, debug
);
209 pub fn local_span(&self, tcx
: TyCtxt
<'tcx
>) -> Option
<Span
> {
211 MonoItem
::Fn(Instance { def, .. }
) => {
212 tcx
.hir().as_local_hir_id(def
.def_id())
214 MonoItem
::Static(def_id
) => {
215 tcx
.hir().as_local_hir_id(def_id
)
217 MonoItem
::GlobalAsm(hir_id
) => {
220 }.map(|hir_id
| tcx
.hir().span(hir_id
))
224 impl<'a
, 'tcx
> HashStable
<StableHashingContext
<'a
>> for MonoItem
<'tcx
> {
225 fn hash_stable(&self, hcx
: &mut StableHashingContext
<'a
>, hasher
: &mut StableHasher
) {
226 ::std
::mem
::discriminant(self).hash_stable(hcx
, hasher
);
229 MonoItem
::Fn(ref instance
) => {
230 instance
.hash_stable(hcx
, hasher
);
232 MonoItem
::Static(def_id
) => {
233 def_id
.hash_stable(hcx
, hasher
);
235 MonoItem
::GlobalAsm(node_id
) => {
236 hcx
.with_node_id_hashing_mode(NodeIdHashingMode
::HashDefPath
, |hcx
| {
237 node_id
.hash_stable(hcx
, hasher
);
244 pub struct CodegenUnit
<'tcx
> {
245 /// A name for this CGU. Incremental compilation requires that
246 /// name be unique amongst **all** crates. Therefore, it should
247 /// contain something unique to this crate (e.g., a module path)
248 /// as well as the crate name and disambiguator.
250 items
: FxHashMap
<MonoItem
<'tcx
>, (Linkage
, Visibility
)>,
251 size_estimate
: Option
<usize>,
254 #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable)]
269 #[derive(Copy, Clone, PartialEq, Debug, HashStable)]
270 pub enum Visibility
{
276 impl<'tcx
> CodegenUnit
<'tcx
> {
277 pub fn new(name
: Symbol
) -> CodegenUnit
<'tcx
> {
280 items
: Default
::default(),
285 pub fn name(&self) -> Symbol
{
289 pub fn set_name(&mut self, name
: Symbol
) {
293 pub fn items(&self) -> &FxHashMap
<MonoItem
<'tcx
>, (Linkage
, Visibility
)> {
297 pub fn items_mut(&mut self)
298 -> &mut FxHashMap
<MonoItem
<'tcx
>, (Linkage
, Visibility
)>
303 pub fn mangle_name(human_readable_name
: &str) -> String
{
304 // We generate a 80 bit hash from the name. This should be enough to
305 // avoid collisions and is still reasonably short for filenames.
306 let mut hasher
= StableHasher
::new();
307 human_readable_name
.hash(&mut hasher
);
308 let hash
: u128
= hasher
.finish();
309 let hash
= hash
& ((1u128 << 80) - 1);
310 base_n
::encode(hash
, base_n
::CASE_INSENSITIVE
)
313 pub fn estimate_size(&mut self, tcx
: TyCtxt
<'tcx
>) {
314 // Estimate the size of a codegen unit as (approximately) the number of MIR
315 // statements it corresponds to.
316 self.size_estimate
= Some(self.items
.keys().map(|mi
| mi
.size_estimate(tcx
)).sum());
319 pub fn size_estimate(&self) -> usize {
320 // Should only be called if `estimate_size` has previously been called.
321 self.size_estimate
.expect("estimate_size must be called before getting a size_estimate")
324 pub fn modify_size_estimate(&mut self, delta
: usize) {
325 assert
!(self.size_estimate
.is_some());
326 if let Some(size_estimate
) = self.size_estimate
{
327 self.size_estimate
= Some(size_estimate
+ delta
);
331 pub fn contains_item(&self, item
: &MonoItem
<'tcx
>) -> bool
{
332 self.items().contains_key(item
)
335 pub fn work_product_id(&self) -> WorkProductId
{
336 WorkProductId
::from_cgu_name(&self.name().as_str())
339 pub fn work_product(&self, tcx
: TyCtxt
<'_
>) -> WorkProduct
{
340 let work_product_id
= self.work_product_id();
342 .previous_work_product(&work_product_id
)
344 panic
!("Could not find work-product for CGU `{}`", self.name())
348 pub fn items_in_deterministic_order(
351 ) -> Vec
<(MonoItem
<'tcx
>, (Linkage
, Visibility
))> {
352 // The codegen tests rely on items being process in the same order as
353 // they appear in the file, so for local items, we sort by node_id first
354 #[derive(PartialEq, Eq, PartialOrd, Ord)]
355 pub struct ItemSortKey(Option
<HirId
>, SymbolName
);
357 fn item_sort_key
<'tcx
>(tcx
: TyCtxt
<'tcx
>, item
: MonoItem
<'tcx
>) -> ItemSortKey
{
358 ItemSortKey(match item
{
359 MonoItem
::Fn(ref instance
) => {
361 // We only want to take HirIds of user-defined
362 // instances into account. The others don't matter for
363 // the codegen tests and can even make item order
365 InstanceDef
::Item(def_id
) => {
366 tcx
.hir().as_local_hir_id(def_id
)
368 InstanceDef
::VtableShim(..) |
369 InstanceDef
::ReifyShim(..) |
370 InstanceDef
::Intrinsic(..) |
371 InstanceDef
::FnPtrShim(..) |
372 InstanceDef
::Virtual(..) |
373 InstanceDef
::ClosureOnceShim { .. }
|
374 InstanceDef
::DropGlue(..) |
375 InstanceDef
::CloneShim(..) => {
380 MonoItem
::Static(def_id
) => {
381 tcx
.hir().as_local_hir_id(def_id
)
383 MonoItem
::GlobalAsm(hir_id
) => {
386 }, item
.symbol_name(tcx
))
389 let mut items
: Vec
<_
> = self.items().iter().map(|(&i
, &l
)| (i
, l
)).collect();
390 items
.sort_by_cached_key(|&(i
, _
)| item_sort_key(tcx
, i
));
394 pub fn codegen_dep_node(&self, tcx
: TyCtxt
<'tcx
>) -> DepNode
{
395 DepNode
::new(tcx
, DepConstructor
::CompileCodegenUnit(self.name().clone()))
399 impl<'a
, 'tcx
> HashStable
<StableHashingContext
<'a
>> for CodegenUnit
<'tcx
> {
400 fn hash_stable(&self, hcx
: &mut StableHashingContext
<'a
>, hasher
: &mut StableHasher
) {
404 // The size estimate is not relevant to the hash
408 name
.hash_stable(hcx
, hasher
);
410 let mut items
: Vec
<(Fingerprint
, _
)> = items
.iter().map(|(mono_item
, &attrs
)| {
411 let mut hasher
= StableHasher
::new();
412 mono_item
.hash_stable(hcx
, &mut hasher
);
413 let mono_item_fingerprint
= hasher
.finish();
414 (mono_item_fingerprint
, attrs
)
417 items
.sort_unstable_by_key(|i
| i
.0);
418 items
.hash_stable(hcx
, hasher
);
422 pub struct CodegenUnitNameBuilder
<'tcx
> {
424 cache
: FxHashMap
<CrateNum
, String
>,
427 impl CodegenUnitNameBuilder
<'tcx
> {
428 pub fn new(tcx
: TyCtxt
<'tcx
>) -> Self {
429 CodegenUnitNameBuilder
{
431 cache
: Default
::default(),
435 /// CGU names should fulfill the following requirements:
436 /// - They should be able to act as a file name on any kind of file system
437 /// - They should not collide with other CGU names, even for different versions
438 /// of the same crate.
440 /// Consequently, we don't use special characters except for '.' and '-' and we
441 /// prefix each name with the crate-name and crate-disambiguator.
443 /// This function will build CGU names of the form:
446 /// <crate-name>.<crate-disambiguator>[-in-<local-crate-id>](-<component>)*[.<special-suffix>]
447 /// <local-crate-id> = <local-crate-name>.<local-crate-disambiguator>
450 /// The '.' before `<special-suffix>` makes sure that names with a special
451 /// suffix can never collide with a name built out of regular Rust
452 /// identifiers (e.g., module paths).
453 pub fn build_cgu_name
<I
, C
, S
>(&mut self,
456 special_suffix
: Option
<S
>)
458 where I
: IntoIterator
<Item
=C
>,
462 let cgu_name
= self.build_cgu_name_no_mangle(cnum
,
466 if self.tcx
.sess
.opts
.debugging_opts
.human_readable_cgu_names
{
469 let cgu_name
= &cgu_name
.as_str();
470 Symbol
::intern(&CodegenUnit
::mangle_name(cgu_name
))
474 /// Same as `CodegenUnit::build_cgu_name()` but will never mangle the
476 pub fn build_cgu_name_no_mangle
<I
, C
, S
>(&mut self,
479 special_suffix
: Option
<S
>)
481 where I
: IntoIterator
<Item
=C
>,
487 let mut cgu_name
= String
::with_capacity(64);
489 // Start out with the crate name and disambiguator
491 let crate_prefix
= self.cache
.entry(cnum
).or_insert_with(|| {
492 // Whenever the cnum is not LOCAL_CRATE we also mix in the
493 // local crate's ID. Otherwise there can be collisions between CGUs
494 // instantiating stuff for upstream crates.
495 let local_crate_id
= if cnum
!= LOCAL_CRATE
{
496 let local_crate_disambiguator
=
497 format
!("{}", tcx
.crate_disambiguator(LOCAL_CRATE
));
499 tcx
.crate_name(LOCAL_CRATE
),
500 &local_crate_disambiguator
[0 .. 8])
505 let crate_disambiguator
= tcx
.crate_disambiguator(cnum
).to_string();
506 // Using a shortened disambiguator of about 40 bits
508 tcx
.crate_name(cnum
),
509 &crate_disambiguator
[0 .. 8],
513 write
!(cgu_name
, "{}", crate_prefix
).unwrap();
515 // Add the components
516 for component
in components
{
517 write
!(cgu_name
, "-{}", component
).unwrap();
520 if let Some(special_suffix
) = special_suffix
{
521 // We add a dot in here so it cannot clash with anything in a regular
523 write
!(cgu_name
, ".{}", special_suffix
).unwrap();
526 Symbol
::intern(&cgu_name
[..])