1
1
use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
2
2
use crate::hir::HirId;
3
3
use syntax::symbol::InternedString;
4
- use crate::ty::{Instance, TyCtxt};
4
+ use syntax::attr::InlineAttr;
5
+ use syntax::source_map::Span;
6
+ use crate::ty::{Instance, InstanceDef, TyCtxt, SymbolName, subst::InternalSubsts};
5
7
use crate::util::nodemap::FxHashMap;
8
+ use crate::ty::print::obsolete::DefPathBasedNames;
9
+ use crate::dep_graph::{WorkProductId, DepNode, WorkProduct, DepConstructor};
6
10
use rustc_data_structures::base_n;
7
11
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
8
12
StableHasher};
9
13
use crate::ich::{Fingerprint, StableHashingContext, NodeIdHashingMode};
14
+ use crate::session::config::OptLevel;
10
15
use std::fmt;
11
16
use std::hash::Hash;
12
17
18
+ /// Describes how a monomorphization will be instantiated in object files.
19
+ #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
20
+ pub enum InstantiationMode {
21
+ /// There will be exactly one instance of the given MonoItem. It will have
22
+ /// external linkage so that it can be linked to from other codegen units.
23
+ GloballyShared {
24
+ /// In some compilation scenarios we may decide to take functions that
25
+ /// are typically `LocalCopy` and instead move them to `GloballyShared`
26
+ /// to avoid codegenning them a bunch of times. In this situation,
27
+ /// however, our local copy may conflict with other crates also
28
+ /// inlining the same function.
29
+ ///
30
+ /// This flag indicates that this situation is occurring, and informs
31
+ /// symbol name calculation that some extra mangling is needed to
32
+ /// avoid conflicts. Note that this may eventually go away entirely if
33
+ /// ThinLTO enables us to *always* have a globally shared instance of a
34
+ /// function within one crate's compilation.
35
+ may_conflict: bool,
36
+ },
37
+
38
+ /// Each codegen unit containing a reference to the given MonoItem will
39
+ /// have its own private copy of the function (with internal linkage).
40
+ LocalCopy,
41
+ }
42
+
13
43
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
14
44
pub enum MonoItem<'tcx> {
15
45
Fn(Instance<'tcx>),
@@ -31,6 +61,166 @@ impl<'tcx> MonoItem<'tcx> {
31
61
MonoItem::GlobalAsm(_) => 1,
32
62
}
33
63
}
64
+
65
+ pub fn is_generic_fn(&self) -> bool {
66
+ match *self {
67
+ MonoItem::Fn(ref instance) => {
68
+ instance.substs.non_erasable_generics().next().is_some()
69
+ }
70
+ MonoItem::Static(..) |
71
+ MonoItem::GlobalAsm(..) => false,
72
+ }
73
+ }
74
+
75
+ pub fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> SymbolName {
76
+ match *self {
77
+ MonoItem::Fn(instance) => tcx.symbol_name(instance),
78
+ MonoItem::Static(def_id) => {
79
+ tcx.symbol_name(Instance::mono(tcx, def_id))
80
+ }
81
+ MonoItem::GlobalAsm(hir_id) => {
82
+ let def_id = tcx.hir().local_def_id_from_hir_id(hir_id);
83
+ SymbolName {
84
+ name: InternedString::intern(&format!("global_asm_{:?}", def_id))
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ pub fn instantiation_mode(&self,
91
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
92
+ -> InstantiationMode {
93
+ let inline_in_all_cgus =
94
+ tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
95
+ tcx.sess.opts.optimize != OptLevel::No
96
+ }) && !tcx.sess.opts.cg.link_dead_code;
97
+
98
+ match *self {
99
+ MonoItem::Fn(ref instance) => {
100
+ let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
101
+ // If this function isn't inlined or otherwise has explicit
102
+ // linkage, then we'll be creating a globally shared version.
103
+ if self.explicit_linkage(tcx).is_some() ||
104
+ !instance.def.requires_local(tcx) ||
105
+ Some(instance.def_id()) == entry_def_id
106
+ {
107
+ return InstantiationMode::GloballyShared { may_conflict: false }
108
+ }
109
+
110
+ // At this point we don't have explicit linkage and we're an
111
+ // inlined function. If we're inlining into all CGUs then we'll
112
+ // be creating a local copy per CGU
113
+ if inline_in_all_cgus {
114
+ return InstantiationMode::LocalCopy
115
+ }
116
+
117
+ // Finally, if this is `#[inline(always)]` we're sure to respect
118
+ // that with an inline copy per CGU, but otherwise we'll be
119
+ // creating one copy of this `#[inline]` function which may
120
+ // conflict with upstream crates as it could be an exported
121
+ // symbol.
122
+ match tcx.codegen_fn_attrs(instance.def_id()).inline {
123
+ InlineAttr::Always => InstantiationMode::LocalCopy,
124
+ _ => {
125
+ InstantiationMode::GloballyShared { may_conflict: true }
126
+ }
127
+ }
128
+ }
129
+ MonoItem::Static(..) |
130
+ MonoItem::GlobalAsm(..) => {
131
+ InstantiationMode::GloballyShared { may_conflict: false }
132
+ }
133
+ }
134
+ }
135
+
136
+ pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
137
+ let def_id = match *self {
138
+ MonoItem::Fn(ref instance) => instance.def_id(),
139
+ MonoItem::Static(def_id) => def_id,
140
+ MonoItem::GlobalAsm(..) => return None,
141
+ };
142
+
143
+ let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
144
+ codegen_fn_attrs.linkage
145
+ }
146
+
147
+ /// Returns `true` if this instance is instantiable - whether it has no unsatisfied
148
+ /// predicates.
149
+ ///
150
+ /// In order to codegen an item, all of its predicates must hold, because
151
+ /// otherwise the item does not make sense. Type-checking ensures that
152
+ /// the predicates of every item that is *used by* a valid item *do*
153
+ /// hold, so we can rely on that.
154
+ ///
155
+ /// However, we codegen collector roots (reachable items) and functions
156
+ /// in vtables when they are seen, even if they are not used, and so they
157
+ /// might not be instantiable. For example, a programmer can define this
158
+ /// public function:
159
+ ///
160
+ /// pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
161
+ /// <&mut () as Clone>::clone(&s);
162
+ /// }
163
+ ///
164
+ /// That function can't be codegened, because the method `<&mut () as Clone>::clone`
165
+ /// does not exist. Luckily for us, that function can't ever be used,
166
+ /// because that would require for `&'a mut (): Clone` to hold, so we
167
+ /// can just not emit any code, or even a linker reference for it.
168
+ ///
169
+ /// Similarly, if a vtable method has such a signature, and therefore can't
170
+ /// be used, we can just not emit it and have a placeholder (a null pointer,
171
+ /// which will never be accessed) in its place.
172
+ pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
173
+ debug!("is_instantiable({:?})", self);
174
+ let (def_id, substs) = match *self {
175
+ MonoItem::Fn(ref instance) => (instance.def_id(), instance.substs),
176
+ MonoItem::Static(def_id) => (def_id, InternalSubsts::empty()),
177
+ // global asm never has predicates
178
+ MonoItem::GlobalAsm(..) => return true
179
+ };
180
+
181
+ tcx.substitute_normalize_and_test_predicates((def_id, &substs))
182
+ }
183
+
184
+ pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug: bool) -> String {
185
+ return match *self {
186
+ MonoItem::Fn(instance) => {
187
+ to_string_internal(tcx, "fn ", instance, debug)
188
+ },
189
+ MonoItem::Static(def_id) => {
190
+ let instance = Instance::new(def_id, tcx.intern_substs(&[]));
191
+ to_string_internal(tcx, "static ", instance, debug)
192
+ },
193
+ MonoItem::GlobalAsm(..) => {
194
+ "global_asm".to_string()
195
+ }
196
+ };
197
+
198
+ fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
199
+ prefix: &str,
200
+ instance: Instance<'tcx>,
201
+ debug: bool)
202
+ -> String {
203
+ let mut result = String::with_capacity(32);
204
+ result.push_str(prefix);
205
+ let printer = DefPathBasedNames::new(tcx, false, false);
206
+ printer.push_instance_as_string(instance, &mut result, debug);
207
+ result
208
+ }
209
+ }
210
+
211
+ pub fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
212
+ match *self {
213
+ MonoItem::Fn(Instance { def, .. }) => {
214
+ tcx.hir().as_local_hir_id(def.def_id())
215
+ }
216
+ MonoItem::Static(def_id) => {
217
+ tcx.hir().as_local_hir_id(def_id)
218
+ }
219
+ MonoItem::GlobalAsm(hir_id) => {
220
+ Some(hir_id)
221
+ }
222
+ }.map(|hir_id| tcx.hir().span_by_hir_id(hir_id))
223
+ }
34
224
}
35
225
36
226
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
@@ -161,6 +351,73 @@ impl<'tcx> CodegenUnit<'tcx> {
161
351
self.size_estimate = Some(size_estimate + delta);
162
352
}
163
353
}
354
+
355
+ pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {
356
+ self.items().contains_key(item)
357
+ }
358
+
359
+ pub fn work_product_id(&self) -> WorkProductId {
360
+ WorkProductId::from_cgu_name(&self.name().as_str())
361
+ }
362
+
363
+ pub fn work_product(&self, tcx: TyCtxt<'_, '_, '_>) -> WorkProduct {
364
+ let work_product_id = self.work_product_id();
365
+ tcx.dep_graph
366
+ .previous_work_product(&work_product_id)
367
+ .unwrap_or_else(|| {
368
+ panic!("Could not find work-product for CGU `{}`", self.name())
369
+ })
370
+ }
371
+
372
+ pub fn items_in_deterministic_order<'a>(&self,
373
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
374
+ -> Vec<(MonoItem<'tcx>,
375
+ (Linkage, Visibility))> {
376
+ // The codegen tests rely on items being process in the same order as
377
+ // they appear in the file, so for local items, we sort by node_id first
378
+ #[derive(PartialEq, Eq, PartialOrd, Ord)]
379
+ pub struct ItemSortKey(Option<HirId>, SymbolName);
380
+
381
+ fn item_sort_key<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
382
+ item: MonoItem<'tcx>) -> ItemSortKey {
383
+ ItemSortKey(match item {
384
+ MonoItem::Fn(ref instance) => {
385
+ match instance.def {
386
+ // We only want to take HirIds of user-defined
387
+ // instances into account. The others don't matter for
388
+ // the codegen tests and can even make item order
389
+ // unstable.
390
+ InstanceDef::Item(def_id) => {
391
+ tcx.hir().as_local_hir_id(def_id)
392
+ }
393
+ InstanceDef::VtableShim(..) |
394
+ InstanceDef::Intrinsic(..) |
395
+ InstanceDef::FnPtrShim(..) |
396
+ InstanceDef::Virtual(..) |
397
+ InstanceDef::ClosureOnceShim { .. } |
398
+ InstanceDef::DropGlue(..) |
399
+ InstanceDef::CloneShim(..) => {
400
+ None
401
+ }
402
+ }
403
+ }
404
+ MonoItem::Static(def_id) => {
405
+ tcx.hir().as_local_hir_id(def_id)
406
+ }
407
+ MonoItem::GlobalAsm(hir_id) => {
408
+ Some(hir_id)
409
+ }
410
+ }, item.symbol_name(tcx))
411
+ }
412
+
413
+ let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect();
414
+ items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
415
+ items
416
+ }
417
+
418
+ pub fn codegen_dep_node(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>) -> DepNode {
419
+ DepNode::new(tcx, DepConstructor::CompileCodegenUnit(self.name().clone()))
420
+ }
164
421
}
165
422
166
423
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> {
0 commit comments