Skip to content

Commit 61cec55

Browse files
Allow for re-using monomorphizations from upstream crates.
1 parent f3ca261 commit 61cec55

File tree

13 files changed

+195
-38
lines changed

13 files changed

+195
-38
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,9 @@ define_dep_nodes!( <'tcx>
650650
[input] Features,
651651

652652
[] ProgramClausesFor(DefId),
653+
654+
[] UpstreamMonomorphizations(CrateNum),
655+
[] UpstreamMonomorphizationsFor(DefId),
653656
);
654657

655658
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {

src/librustc/ich/impls_ty.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,21 @@ for &'gcx ty::Slice<T>
5353
}
5454
}
5555

56-
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
57-
for ty::subst::Kind<'gcx> {
56+
impl<'a, 'gcx, T> ToStableHashKey<StableHashingContext<'a>> for &'gcx ty::Slice<T>
57+
where T: HashStable<StableHashingContext<'a>>
58+
{
59+
type KeyType = Fingerprint;
60+
61+
#[inline]
62+
fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint {
63+
let mut hasher = StableHasher::new();
64+
let mut hcx: StableHashingContext<'a> = hcx.clone();
65+
self.hash_stable(&mut hcx, &mut hasher);
66+
hasher.finish()
67+
}
68+
}
69+
70+
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::subst::Kind<'gcx> {
5871
fn hash_stable<W: StableHasherResult>(&self,
5972
hcx: &mut StableHashingContext<'a>,
6073
hasher: &mut StableHasher<W>) {

src/librustc/session/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
12901290
"format compiler diagnostics in a way that's better suitable for UI testing"),
12911291
embed_bitcode: bool = (false, parse_bool, [TRACKED],
12921292
"embed LLVM bitcode in object files"),
1293+
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1294+
"make the current crate share its generic instantiations"),
12931295
}
12941296

12951297
pub fn default_lib_output() -> CrateType {

src/librustc/ty/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
14731473
self.sess.opts.debugging_opts.mir_emit_validate > 0 ||
14741474
self.use_mir()
14751475
}
1476+
1477+
#[inline]
1478+
pub fn share_generics(self) -> bool {
1479+
match self.sess.opts.debugging_opts.share_generics {
1480+
Some(true) => true,
1481+
Some(false) | None => false,
1482+
}
1483+
}
14761484
}
14771485

14781486
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {

src/librustc/ty/maps/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> {
131131
}
132132
}
133133

134+
impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> {
135+
fn describe(_: TyCtxt, k: CrateNum) -> String {
136+
format!("collecting available upstream monomorphizations `{:?}`", k)
137+
}
138+
}
139+
134140
impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> {
135141
fn describe(_: TyCtxt, k: CrateNum) -> String {
136142
format!("all inherent impls defined in crate `{:?}`", k)

src/librustc/ty/maps/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,14 @@ define_maps! { <'tcx>
311311
//
312312
// Does not include external symbols that don't have a corresponding DefId,
313313
// like the compiler-generated `main` function and so on.
314-
[] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc<DefIdSet>,
314+
[] fn reachable_non_generics: ReachableNonGenerics(CrateNum)
315+
-> Lrc<DefIdMap<SymbolExportLevel>>,
315316
[] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool,
316317

318+
[] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum)
319+
-> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>,
320+
[] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId)
321+
-> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>,
317322

318323
[] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,
319324
[] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,

src/librustc/ty/maps/plumbing.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,13 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
937937
DepKind::Features => { force!(features_query, LOCAL_CRATE); }
938938

939939
DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); }
940+
941+
DepKind::UpstreamMonomorphizations => {
942+
force!(upstream_monomorphizations, krate!());
943+
}
944+
DepKind::UpstreamMonomorphizationsFor => {
945+
force!(upstream_monomorphizations_for, def_id!());
946+
}
940947
}
941948

942949
true

src/librustc_metadata/cstore_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
185185
let reachable_non_generics = tcx
186186
.exported_symbols(cdata.cnum)
187187
.iter()
188-
.filter_map(|&(exported_symbol, _)| {
188+
.filter_map(|&(exported_symbol, export_level)| {
189189
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
190-
return Some(def_id)
190+
return Some((def_id, export_level))
191191
} else {
192192
None
193193
}

src/librustc_mir/monomorphize/collector.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
569569
ty::TyClosure(def_id, substs) => {
570570
let instance = monomorphize::resolve_closure(
571571
self.tcx, def_id, substs, ty::ClosureKind::FnOnce);
572-
self.output.push(create_fn_mono_item(instance));
572+
if should_monomorphize_locally(self.tcx, &instance) {
573+
self.output.push(create_fn_mono_item(instance));
574+
}
573575
}
574576
_ => bug!(),
575577
}
@@ -731,14 +733,16 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
731733
ty::InstanceDef::Intrinsic(_) |
732734
ty::InstanceDef::CloneShim(..) => return true
733735
};
734-
match tcx.hir.get_if_local(def_id) {
736+
737+
return match tcx.hir.get_if_local(def_id) {
735738
Some(hir_map::NodeForeignItem(..)) => {
736739
false // foreign items are linked against, not translated.
737740
}
738741
Some(_) => true,
739742
None => {
740743
if tcx.is_reachable_non_generic(def_id) ||
741-
tcx.is_foreign_item(def_id)
744+
tcx.is_foreign_item(def_id) ||
745+
is_available_upstream_generic(tcx, def_id, instance.substs)
742746
{
743747
// We can link to the item in question, no instance needed
744748
// in this crate
@@ -750,6 +754,25 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
750754
true
751755
}
752756
}
757+
};
758+
759+
fn is_available_upstream_generic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
760+
def_id: DefId,
761+
substs: &'tcx Substs<'tcx>)
762+
-> bool {
763+
debug_assert!(!def_id.is_local());
764+
765+
if !tcx.share_generics() {
766+
return false
767+
}
768+
769+
if substs.types().next().is_none() {
770+
return false
771+
}
772+
773+
tcx.upstream_monomorphizations_for(def_id)
774+
.map(|set| set.contains_key(substs))
775+
.unwrap_or(false)
753776
}
754777
}
755778

src/librustc_mir/monomorphize/partitioning.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
301301
let mut codegen_units = FxHashMap();
302302
let is_incremental_build = tcx.sess.opts.incremental.is_some();
303303
let mut internalization_candidates = FxHashSet();
304+
let share_generics = tcx.share_generics();
304305

305306
for trans_item in trans_items {
306307
match trans_item.instantiation_mode(tcx) {
@@ -362,6 +363,13 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
362363
if tcx.lang_items().start_fn() == Some(def_id) {
363364
can_be_internalized = false;
364365
Visibility::Hidden
366+
} else if instance.substs.types().next().is_some() {
367+
if share_generics {
368+
can_be_internalized = false;
369+
Visibility::Default
370+
} else {
371+
Visibility::Hidden
372+
}
365373
} else if def_id.is_local() {
366374
if tcx.is_reachable_non_generic(def_id) {
367375
can_be_internalized = false;

src/librustc_trans/back/symbol_export.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadat
2020
use rustc::session::config;
2121
use rustc::ty::{TyCtxt, SymbolName};
2222
use rustc::ty::maps::Providers;
23+
use rustc::ty::subst::Substs;
2324
use rustc::util::nodemap::{FxHashMap, DefIdMap};
2425
use rustc_allocator::ALLOCATOR_METHODS;
2526

@@ -226,6 +227,30 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
226227
symbols.push((exported_symbol, SymbolExportLevel::Rust));
227228
}
228229

230+
if tcx.share_generics() {
231+
use rustc::mir::mono::{Linkage, Visibility, MonoItem};
232+
use rustc::ty::InstanceDef;
233+
234+
let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE);
235+
236+
for (mono_item, &(linkage, visibility)) in cgus.iter()
237+
.flat_map(|cgu| cgu.items().iter()) {
238+
if linkage == Linkage::External {
239+
if let &MonoItem::Fn(Instance {
240+
def: InstanceDef::Item(def_id),
241+
substs,
242+
}) = mono_item {
243+
if substs.types().next().is_some() {
244+
assert!(tcx.lang_items().start_fn() == Some(def_id) ||
245+
visibility == Visibility::Default);
246+
symbols.push((ExportedSymbol::Generic(def_id, substs),
247+
SymbolExportLevel::Rust));
248+
}
249+
}
250+
}
251+
}
252+
}
253+
229254
// Sort so we get a stable incr. comp. hash.
230255
symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
231256
symbol1.compare_stable(tcx, symbol2)
@@ -234,16 +259,55 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
234259
Arc::new(symbols)
235260
}
236261

262+
fn upstream_monomorphizations_provider<'a, 'tcx>(
263+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
264+
cnum: CrateNum)
265+
-> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>
266+
{
267+
debug_assert!(cnum == LOCAL_CRATE);
268+
269+
let cnums = tcx.all_crate_nums(LOCAL_CRATE);
270+
271+
let mut instances = DefIdMap();
272+
273+
for &cnum in cnums.iter() {
274+
for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
275+
if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol {
276+
instances.entry(def_id)
277+
.or_insert_with(|| FxHashMap())
278+
.insert(substs, cnum);
279+
}
280+
}
281+
}
282+
283+
Lrc::new(instances.into_iter()
284+
.map(|(key, value)| (key, Lrc::new(value)))
285+
.collect())
286+
}
287+
288+
fn upstream_monomorphizations_for_provider<'a, 'tcx>(
289+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
290+
def_id: DefId)
291+
-> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>
292+
{
293+
debug_assert!(!def_id.is_local());
294+
tcx.upstream_monomorphizations(LOCAL_CRATE)
295+
.get(&def_id)
296+
.cloned()
297+
}
298+
237299
pub fn provide(providers: &mut Providers) {
238300
providers.reachable_non_generics = reachable_non_generics_provider;
239301
providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
240302
providers.exported_symbols = exported_symbols_provider_local;
241303
providers.symbol_export_level = symbol_export_level_provider;
304+
providers.upstream_monomorphizations = upstream_monomorphizations_provider;
242305
}
243306

244307
pub fn provide_extern(providers: &mut Providers) {
245308
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
246309
providers.symbol_export_level = symbol_export_level_provider;
310+
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
247311
}
248312

249313
fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {

src/librustc_trans/callee.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,18 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
148148
unsafe {
149149
llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
150150

151-
if cx.tcx.is_translated_item(instance_def_id) {
152-
if instance_def_id.is_local() {
153-
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
151+
if cx.tcx.share_generics() && instance.substs.types().next().is_some() {
152+
// If this is a generic function and we are sharing generics
153+
// it will always have Visibility::Default
154+
} else {
155+
if cx.tcx.is_translated_item(instance_def_id) {
156+
if instance_def_id.is_local() {
157+
if !cx.tcx.is_reachable_non_generic(instance_def_id) {
158+
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
159+
}
160+
} else {
154161
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
155162
}
156-
} else {
157-
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
158163
}
159164
}
160165
}

src/librustc_trans_utils/symbol_names.rs

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
use rustc::middle::weak_lang_items;
101101
use rustc_mir::monomorphize::Instance;
102102
use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode};
103-
use rustc::hir::def_id::DefId;
103+
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
104104
use rustc::hir::map as hir_map;
105105
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
106106
use rustc::ty::fold::TypeVisitor;
@@ -170,32 +170,45 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
170170
assert!(!substs.needs_subst());
171171
substs.visit_with(&mut hasher);
172172

173-
let mut avoid_cross_crate_conflicts = false;
174-
175-
// If this is an instance of a generic function, we also hash in
176-
// the ID of the instantiating crate. This avoids symbol conflicts
177-
// in case the same instances is emitted in two crates of the same
178-
// project.
179-
if substs.types().next().is_some() {
180-
avoid_cross_crate_conflicts = true;
181-
}
182-
183-
// If we're dealing with an instance of a function that's inlined from
184-
// another crate but we're marking it as globally shared to our
185-
// compliation (aka we're not making an internal copy in each of our
186-
// codegen units) then this symbol may become an exported (but hidden
187-
// visibility) symbol. This means that multiple crates may do the same
188-
// and we want to be sure to avoid any symbol conflicts here.
189-
match MonoItem::Fn(instance).instantiation_mode(tcx) {
190-
InstantiationMode::GloballyShared { may_conflict: true } => {
191-
avoid_cross_crate_conflicts = true;
192-
}
193-
_ => {}
194-
}
173+
let is_generic = substs.types().next().is_some();
174+
let avoid_cross_crate_conflicts =
175+
// If this is an instance of a generic function, we also hash in
176+
// the ID of the instantiating crate. This avoids symbol conflicts
177+
// in case the same instances is emitted in two crates of the same
178+
// project.
179+
is_generic ||
180+
181+
// If we're dealing with an instance of a function that's inlined from
182+
// another crate but we're marking it as globally shared to our
183+
// compliation (aka we're not making an internal copy in each of our
184+
// codegen units) then this symbol may become an exported (but hidden
185+
// visibility) symbol. This means that multiple crates may do the same
186+
// and we want to be sure to avoid any symbol conflicts here.
187+
match MonoItem::Fn(instance).instantiation_mode(tcx) {
188+
InstantiationMode::GloballyShared { may_conflict: true } => true,
189+
_ => false,
190+
};
195191

196192
if avoid_cross_crate_conflicts {
197-
hasher.hash(tcx.crate_name.as_str());
198-
hasher.hash(tcx.sess.local_crate_disambiguator());
193+
let instantiating_crate = if is_generic {
194+
if !def_id.is_local() && tcx.share_generics() {
195+
// If we are re-using a monomorphization from another crate,
196+
// we have to compute the symbol hash accordingly.
197+
let upstream_monomorphizations =
198+
tcx.upstream_monomorphizations_for(def_id);
199+
200+
upstream_monomorphizations.and_then(|monos| monos.get(&substs)
201+
.cloned())
202+
.unwrap_or(LOCAL_CRATE)
203+
} else {
204+
LOCAL_CRATE
205+
}
206+
} else {
207+
LOCAL_CRATE
208+
};
209+
210+
hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]);
211+
hasher.hash(&tcx.crate_disambiguator(instantiating_crate));
199212
}
200213
});
201214

0 commit comments

Comments
 (0)