From d3b5451991fb1bc09a809547374883340117236b Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Mar 2018 16:48:03 +0100 Subject: [PATCH 01/16] Fix incomplete ICH implementation for ty::subst::UnpackedKind. --- src/librustc/ich/impls_ty.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index da1a2592f14db..f37f2aa9e2db0 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -67,6 +67,7 @@ for ty::subst::UnpackedKind<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); match self { ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher), ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher), From dad194a10d1e05d77516f4052859c2f9315e434a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Mar 2018 16:50:08 +0100 Subject: [PATCH 02/16] Allow for representing exported monomorphizations in crate metadata. --- src/librustc/middle/exported_symbols.rs | 88 +++++++++++++++++------- src/librustc/ty/maps/mod.rs | 2 +- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_metadata/decoder.rs | 12 ++-- src/librustc_metadata/encoder.rs | 12 ++-- src/librustc_metadata/schema.rs | 9 ++- src/librustc_trans/back/symbol_export.rs | 2 +- src/librustc_trans/lib.rs | 1 + 8 files changed, 89 insertions(+), 39 deletions(-) diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index b1418792490fc..2652eb0091cb1 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -9,8 +9,13 @@ // except according to those terms. use hir::def_id::{DefId, LOCAL_CRATE}; +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable, + StableHasherResult}; use std::cmp; +use std::mem; use ty; +use ty::subst::Substs; /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any @@ -40,56 +45,89 @@ impl SymbolExportLevel { } #[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum ExportedSymbol { +pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), + Generic(DefId, &'tcx Substs<'tcx>), NoDefId(ty::SymbolName), } -impl ExportedSymbol { - pub fn symbol_name(&self, tcx: ty::TyCtxt) -> ty::SymbolName { +impl<'tcx> ExportedSymbol<'tcx> { + pub fn symbol_name(&self, + tcx: ty::TyCtxt<'_, 'tcx, '_>) + -> ty::SymbolName { match *self { ExportedSymbol::NonGeneric(def_id) => { tcx.symbol_name(ty::Instance::mono(tcx, def_id)) } + ExportedSymbol::Generic(def_id, substs) => { + tcx.symbol_name(ty::Instance::new(def_id, substs)) + } ExportedSymbol::NoDefId(symbol_name) => { symbol_name } } } - pub fn compare_stable(&self, tcx: ty::TyCtxt, other: &ExportedSymbol) -> cmp::Ordering { + pub fn compare_stable(&self, + tcx: ty::TyCtxt<'_, 'tcx, '_>, + other: &ExportedSymbol<'tcx>) + -> cmp::Ordering { match *self { - ExportedSymbol::NonGeneric(self_def_id) => { - match *other { - ExportedSymbol::NonGeneric(other_def_id) => { - tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id)) - } - ExportedSymbol::NoDefId(_) => { - cmp::Ordering::Less - } + ExportedSymbol::NonGeneric(self_def_id) => match *other { + ExportedSymbol::NonGeneric(other_def_id) => { + tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id)) + } + ExportedSymbol::Generic(..) | + ExportedSymbol::NoDefId(_) => { + cmp::Ordering::Less + } + } + ExportedSymbol::Generic(..) => match *other { + ExportedSymbol::NonGeneric(_) => { + cmp::Ordering::Greater + } + ExportedSymbol::Generic(..) => { + self.symbol_name(tcx).cmp(&other.symbol_name(tcx)) + } + ExportedSymbol::NoDefId(_) => { + cmp::Ordering::Less } } - ExportedSymbol::NoDefId(self_symbol_name) => { - match *other { - ExportedSymbol::NonGeneric(_) => { - cmp::Ordering::Greater - } - ExportedSymbol::NoDefId(ref other_symbol_name) => { - self_symbol_name.cmp(other_symbol_name) - } + ExportedSymbol::NoDefId(self_symbol_name) => match *other { + ExportedSymbol::NonGeneric(_) | + ExportedSymbol::Generic(..) => { + cmp::Ordering::Greater + } + ExportedSymbol::NoDefId(ref other_symbol_name) => { + self_symbol_name.cmp(other_symbol_name) } } } } } -impl_stable_hash_for!(enum self::ExportedSymbol { - NonGeneric(def_id), - NoDefId(symbol_name) -}); - pub fn metadata_symbol_name(tcx: ty::TyCtxt) -> String { format!("rust_metadata_{}_{}", tcx.original_crate_name(LOCAL_CRATE), tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()) } + +impl<'gcx> HashStable> for ExportedSymbol<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ExportedSymbol::NonGeneric(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ExportedSymbol::Generic(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + ExportedSymbol::NoDefId(symbol_name) => { + symbol_name.hash_stable(hcx, hasher); + } + } + } +} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index a992b8acb8b21..786113470770c 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -381,7 +381,7 @@ define_maps! { <'tcx> [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, [] fn exported_symbols: ExportedSymbols(CrateNum) - -> Arc>, + -> Arc, SymbolExportLevel)>>, [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc, Arc>>>), diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f63edf07fa8ba..30055bea635ac 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -268,7 +268,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, return Arc::new(Vec::new()) } - Arc::new(cdata.exported_symbols()) + Arc::new(cdata.exported_symbols(tcx)) } wasm_custom_sections => { Lrc::new(cdata.wasm_custom_sections()) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e938d5c1a97fe..42e208ded49fd 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1065,11 +1065,13 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn exported_symbols(&self) -> Vec<(ExportedSymbol, SymbolExportLevel)> { - self.root - .exported_symbols - .decode(self) - .collect() + pub fn exported_symbols(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> { + let lazy_seq: LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)> = + LazySeq::with_position_and_length(self.root.exported_symbols.position, + self.root.exported_symbols.len); + lazy_seq.decode((self, tcx)).collect() } pub fn wasm_custom_sections(&self) -> Vec { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0da6fc5b9eda1..1b208a512e2a4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1444,13 +1444,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // definition (as that's not defined in this crate). fn encode_exported_symbols(&mut self, exported_symbols: &[(ExportedSymbol, SymbolExportLevel)]) - -> LazySeq<(ExportedSymbol, SymbolExportLevel)> { - + -> EncodedExportedSymbols { // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx)); - self.lazy_seq(exported_symbols + let lazy_seq = self.lazy_seq(exported_symbols .iter() .filter(|&&(ref exported_symbol, _)| { match *exported_symbol { @@ -1460,7 +1459,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { _ => true, } }) - .cloned()) + .cloned()); + + EncodedExportedSymbols { + len: lazy_seq.len, + position: lazy_seq.position, + } } fn encode_wasm_custom_sections(&mut self, statics: &[DefId]) -> LazySeq { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index a7ee0e7e9a961..e3986bb7d91f9 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -15,7 +15,6 @@ use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId, CrateNum}; use rustc::ich::StableHashingContext; -use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary, ForeignModule}; use rustc::middle::lang_items; use rustc::mir; @@ -206,7 +205,7 @@ pub struct CrateRoot { pub codemap: LazySeq, pub def_path_table: Lazy, pub impls: LazySeq, - pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>, + pub exported_symbols: EncodedExportedSymbols, pub wasm_custom_sections: LazySeq, pub index: LazySeq, @@ -531,3 +530,9 @@ impl_stable_hash_for!(struct GeneratorData<'tcx> { layout }); // Tags used for encoding Spans: pub const TAG_VALID_SPAN: u8 = 0; pub const TAG_INVALID_SPAN: u8 = 1; + +#[derive(RustcEncodable, RustcDecodable)] +pub struct EncodedExportedSymbols { + pub position: usize, + pub len: usize, +} diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index d205e6ca4eda6..ce737f1c28c48 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -94,7 +94,7 @@ fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) - -> Arc Arc, SymbolExportLevel)>> { assert_eq!(cnum, LOCAL_CRATE); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index e8a1eb3071a29..f8f2fdd9320d2 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -33,6 +33,7 @@ #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] +#![feature(underscore_lifetimes)] use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; From 435477dc6528932ebf81e038aeceec83aa1c03b4 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Mar 2018 10:18:48 +0100 Subject: [PATCH 03/16] Move export level computation to reachable_non_generics query. --- src/librustc_trans/back/symbol_export.rs | 102 +++++++++++------------ 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index ce737f1c28c48..9843eaf77e738 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -20,7 +20,7 @@ use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadat use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::maps::Providers; -use rustc::util::nodemap::{FxHashMap, DefIdSet}; +use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; pub type ExportedSymbols = FxHashMap< @@ -56,51 +56,12 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType]) fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) - -> Lrc + -> Lrc> { assert_eq!(cnum, LOCAL_CRATE); if !tcx.sess.opts.output_types.should_trans() { - return Lrc::new(DefIdSet()) - } - - let export_threshold = threshold(tcx); - - // We already collect all potentially reachable non-generic items for - // `exported_symbols`. Now we just filter them down to what is actually - // exported for the given crate we are compiling. - let reachable_non_generics = tcx - .exported_symbols(LOCAL_CRATE) - .iter() - .filter_map(|&(exported_symbol, level)| { - if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { - if level.is_below_threshold(export_threshold) { - return Some(def_id) - } - } - - None - }) - .collect(); - - Lrc::new(reachable_non_generics) -} - -fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { - tcx.reachable_non_generics(def_id.krate).contains(&def_id) -} - -fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Arc, - SymbolExportLevel)>> -{ - assert_eq!(cnum, LOCAL_CRATE); - - if !tcx.sess.opts.output_types.should_trans() { - return Arc::new(vec![]) + return Lrc::new(DefIdMap()) } // Check to see if this crate is a "special runtime crate". These @@ -113,7 +74,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE); - let reachable_non_generics: DefIdSet = tcx.reachable_set(LOCAL_CRATE).0 + let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0 .iter() .filter_map(|&node_id| { // We want to ignore some FFI functions that are not exposed from @@ -166,11 +127,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => None } }) - .collect(); - - let mut symbols: Vec<_> = reachable_non_generics - .iter() - .map(|&def_id| { + .map(|def_id| { let export_level = if special_runtime_crate { let name = tcx.symbol_name(Instance::mono(tcx, def_id)); // We can probably do better here by just ensuring that @@ -193,20 +150,59 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("EXPORTED SYMBOL (local): {} ({:?})", tcx.symbol_name(Instance::mono(tcx, def_id)), export_level); - (ExportedSymbol::NonGeneric(def_id), export_level) + (def_id, export_level) }) .collect(); if let Some(id) = tcx.sess.derive_registrar_fn.get() { let def_id = tcx.hir.local_def_id(id); - symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C)); + reachable_non_generics.insert(def_id, SymbolExportLevel::C); } if let Some(id) = tcx.sess.plugin_registrar_fn.get() { let def_id = tcx.hir.local_def_id(id); - symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C)); + reachable_non_generics.insert(def_id, SymbolExportLevel::C); } + Lrc::new(reachable_non_generics) +} + +fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + let export_threshold = threshold(tcx); + + if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { + level.is_below_threshold(export_threshold) + } else { + false + } +} + +fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) +} + +fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Arc, + SymbolExportLevel)>> +{ + assert_eq!(cnum, LOCAL_CRATE); + + if !tcx.sess.opts.output_types.should_trans() { + return Arc::new(vec![]) + } + + let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE) + .iter() + .map(|(&def_id, &level)| { + (ExportedSymbol::NonGeneric(def_id), level) + }) + .collect(); + if let Some(_) = *tcx.sess.entry_fn.borrow() { let symbol_name = "main".to_string(); let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); @@ -254,13 +250,13 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; - providers.is_reachable_non_generic = is_reachable_non_generic_provider; + providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.exported_symbols = exported_symbols_provider_local; providers.symbol_export_level = symbol_export_level_provider; } pub fn provide_extern(providers: &mut Providers) { - providers.is_reachable_non_generic = is_reachable_non_generic_provider; + providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; providers.symbol_export_level = symbol_export_level_provider; } From 4f6d05dc483003e89d17c539eba4fc7a503d6390 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Mar 2018 10:33:42 +0100 Subject: [PATCH 04/16] Allow for re-using monomorphizations from upstream crates. --- src/librustc/dep_graph/dep_node.rs | 3 + src/librustc/ich/impls_ty.rs | 17 ++++- src/librustc/session/config.rs | 2 + src/librustc/ty/context.rs | 8 +++ src/librustc/ty/maps/config.rs | 6 ++ src/librustc/ty/maps/mod.rs | 7 +- src/librustc/ty/maps/plumbing.rs | 7 ++ src/librustc_metadata/cstore_impl.rs | 4 +- src/librustc_mir/monomorphize/collector.rs | 29 ++++++++- src/librustc_mir/monomorphize/partitioning.rs | 8 +++ src/librustc_trans/back/symbol_export.rs | 64 +++++++++++++++++++ src/librustc_trans/callee.rs | 15 +++-- src/librustc_trans_utils/symbol_names.rs | 63 ++++++++++-------- 13 files changed, 195 insertions(+), 38 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index d1f3736556c5d..9172c3067accd 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -657,6 +657,9 @@ define_dep_nodes!( <'tcx> [] ProgramClausesFor(DefId), [] WasmImportModuleMap(CrateNum), [] ForeignModules(CrateNum), + + [] UpstreamMonomorphizations(CrateNum), + [] UpstreamMonomorphizationsFor(DefId), ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f37f2aa9e2db0..f86913490258e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -53,8 +53,21 @@ for &'gcx ty::Slice } } -impl<'a, 'gcx> HashStable> -for ty::subst::Kind<'gcx> { +impl<'a, 'gcx, T> ToStableHashKey> for &'gcx ty::Slice + where T: HashStable> +{ + type KeyType = Fingerprint; + + #[inline] + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint { + let mut hasher = StableHasher::new(); + let mut hcx: StableHashingContext<'a> = hcx.clone(); + self.hash_stable(&mut hcx, &mut hasher); + hasher.finish() + } +} + +impl<'a, 'gcx> HashStable> for ty::subst::Kind<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 59d1a298eaa69..312df69d3188f 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1304,6 +1304,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "embed LLVM bitcode in object files"), strip_debuginfo_if_disabled: Option = (None, parse_opt_bool, [TRACKED], "tell the linker to strip debuginfo when building without debuginfo enabled."), + share_generics: Option = (None, parse_opt_bool, [TRACKED], + "make the current crate share its generic instantiations"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3326af21bd604..8a58dad292420 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1499,6 +1499,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.sess.opts.debugging_opts.mir_emit_validate > 0 || self.use_mir() } + + #[inline] + pub fn share_generics(self) -> bool { + match self.sess.opts.debugging_opts.share_generics { + Some(true) => true, + Some(false) | None => false, + } + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index a08cd57b1f7e2..16866636cd90a 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -131,6 +131,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("collecting available upstream monomorphizations `{:?}`", k) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> { fn describe(_: TyCtxt, k: CrateNum) -> String { format!("all inherent impls defined in crate `{:?}`", k) diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 786113470770c..5f093bc0b488d 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -319,9 +319,14 @@ define_maps! { <'tcx> // // Does not include external symbols that don't have a corresponding DefId, // like the compiler-generated `main` function and so on. - [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc, + [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) + -> Lrc>, [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, + [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) + -> Lrc, CrateNum>>>>, + [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) + -> Option, CrateNum>>>, [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index bc5a14c96f004..b37628c390f51 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -1094,6 +1094,13 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); } DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); } DepKind::ForeignModules => { force!(foreign_modules, krate!()); } + + DepKind::UpstreamMonomorphizations => { + force!(upstream_monomorphizations, krate!()); + } + DepKind::UpstreamMonomorphizationsFor => { + force!(upstream_monomorphizations_for, def_id!()); + } } true diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 30055bea635ac..51088563c7b9c 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -186,9 +186,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, let reachable_non_generics = tcx .exported_symbols(cdata.cnum) .iter() - .filter_map(|&(exported_symbol, _)| { + .filter_map(|&(exported_symbol, export_level)| { if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { - return Some(def_id) + return Some((def_id, export_level)) } else { None } diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 446ef6bd32876..e93b936d4f06e 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -569,7 +569,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( self.tcx, def_id, substs, ty::ClosureKind::FnOnce); - self.output.push(create_fn_mono_item(instance)); + if should_monomorphize_locally(self.tcx, &instance) { + self.output.push(create_fn_mono_item(instance)); + } } _ => bug!(), } @@ -731,14 +733,16 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: ty::InstanceDef::Intrinsic(_) | ty::InstanceDef::CloneShim(..) => return true }; - match tcx.hir.get_if_local(def_id) { + + return match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { false // foreign items are linked against, not translated. } Some(_) => true, None => { if tcx.is_reachable_non_generic(def_id) || - tcx.is_foreign_item(def_id) + tcx.is_foreign_item(def_id) || + is_available_upstream_generic(tcx, def_id, instance.substs) { // We can link to the item in question, no instance needed // in this crate @@ -750,6 +754,25 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: true } } + }; + + fn is_available_upstream_generic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> bool { + debug_assert!(!def_id.is_local()); + + if !tcx.share_generics() { + return false + } + + if substs.types().next().is_none() { + return false + } + + tcx.upstream_monomorphizations_for(def_id) + .map(|set| set.contains_key(substs)) + .unwrap_or(false) } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 3789342b3891d..c3437c8d55b53 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -301,6 +301,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut codegen_units = FxHashMap(); let is_incremental_build = tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet(); + let share_generics = tcx.share_generics(); for trans_item in trans_items { match trans_item.instantiation_mode(tcx) { @@ -362,6 +363,13 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if tcx.lang_items().start_fn() == Some(def_id) { can_be_internalized = false; Visibility::Hidden + } else if instance.substs.types().next().is_some() { + if share_generics { + can_be_internalized = false; + Visibility::Default + } else { + Visibility::Hidden + } } else if def_id.is_local() { if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 9843eaf77e738..69ba55ff8a939 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -20,6 +20,7 @@ use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadat use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::maps::Providers; +use rustc::ty::subst::Substs; use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; @@ -240,6 +241,30 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, symbols.push((exported_symbol, SymbolExportLevel::Rust)); } + if tcx.share_generics() { + use rustc::mir::mono::{Linkage, Visibility, MonoItem}; + use rustc::ty::InstanceDef; + + let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); + + for (mono_item, &(linkage, visibility)) in cgus.iter() + .flat_map(|cgu| cgu.items().iter()) { + if linkage == Linkage::External { + if let &MonoItem::Fn(Instance { + def: InstanceDef::Item(def_id), + substs, + }) = mono_item { + if substs.types().next().is_some() { + assert!(tcx.lang_items().start_fn() == Some(def_id) || + visibility == Visibility::Default); + symbols.push((ExportedSymbol::Generic(def_id, substs), + SymbolExportLevel::Rust)); + } + } + } + } + } + // Sort so we get a stable incr. comp. hash. symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { symbol1.compare_stable(tcx, symbol2) @@ -248,16 +273,55 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Arc::new(symbols) } +fn upstream_monomorphizations_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Lrc, CrateNum>>>> +{ + debug_assert!(cnum == LOCAL_CRATE); + + let cnums = tcx.all_crate_nums(LOCAL_CRATE); + + let mut instances = DefIdMap(); + + for &cnum in cnums.iter() { + for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { + if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { + instances.entry(def_id) + .or_insert_with(|| FxHashMap()) + .insert(substs, cnum); + } + } + } + + Lrc::new(instances.into_iter() + .map(|(key, value)| (key, Lrc::new(value))) + .collect()) +} + +fn upstream_monomorphizations_for_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option, CrateNum>>> +{ + debug_assert!(!def_id.is_local()); + tcx.upstream_monomorphizations(LOCAL_CRATE) + .get(&def_id) + .cloned() +} + pub fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.exported_symbols = exported_symbols_provider_local; providers.symbol_export_level = symbol_export_level_provider; + providers.upstream_monomorphizations = upstream_monomorphizations_provider; } pub fn provide_extern(providers: &mut Providers) { providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; providers.symbol_export_level = symbol_export_level_provider; + providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; } fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 1dcf349e23bd8..84c07abe49b9c 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -148,13 +148,18 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if cx.tcx.is_translated_item(instance_def_id) { - if instance_def_id.is_local() { - if !cx.tcx.is_reachable_non_generic(instance_def_id) { + if cx.tcx.share_generics() && instance.substs.types().next().is_some() { + // If this is a generic function and we are sharing generics + // it will always have Visibility::Default + } else { + if cx.tcx.is_translated_item(instance_def_id) { + if instance_def_id.is_local() { + if !cx.tcx.is_reachable_non_generic(instance_def_id) { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } else { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } - } else { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } } diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index f9f93730255e6..af174f7ce8516 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -100,7 +100,7 @@ use rustc::middle::weak_lang_items; use rustc_mir::monomorphize::Instance; use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode}; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::fold::TypeVisitor; @@ -170,32 +170,45 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(!substs.needs_subst()); substs.visit_with(&mut hasher); - let mut avoid_cross_crate_conflicts = false; - - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - if substs.types().next().is_some() { - avoid_cross_crate_conflicts = true; - } - - // If we're dealing with an instance of a function that's inlined from - // another crate but we're marking it as globally shared to our - // compliation (aka we're not making an internal copy in each of our - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => { - avoid_cross_crate_conflicts = true; - } - _ => {} - } + let is_generic = substs.types().next().is_some(); + let avoid_cross_crate_conflicts = + // If this is an instance of a generic function, we also hash in + // the ID of the instantiating crate. This avoids symbol conflicts + // in case the same instances is emitted in two crates of the same + // project. + is_generic || + + // If we're dealing with an instance of a function that's inlined from + // another crate but we're marking it as globally shared to our + // compliation (aka we're not making an internal copy in each of our + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // and we want to be sure to avoid any symbol conflicts here. + match MonoItem::Fn(instance).instantiation_mode(tcx) { + InstantiationMode::GloballyShared { may_conflict: true } => true, + _ => false, + }; if avoid_cross_crate_conflicts { - hasher.hash(tcx.crate_name.as_str()); - hasher.hash(tcx.sess.local_crate_disambiguator()); + let instantiating_crate = if is_generic { + if !def_id.is_local() && tcx.share_generics() { + // If we are re-using a monomorphization from another crate, + // we have to compute the symbol hash accordingly. + let upstream_monomorphizations = + tcx.upstream_monomorphizations_for(def_id); + + upstream_monomorphizations.and_then(|monos| monos.get(&substs) + .cloned()) + .unwrap_or(LOCAL_CRATE) + } else { + LOCAL_CRATE + } + } else { + LOCAL_CRATE + }; + + hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]); + hasher.hash(&tcx.crate_disambiguator(instantiating_crate)); } }); From 8d95c869747366f384df0776d03e6df79d760584 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Mar 2018 11:56:01 +0100 Subject: [PATCH 05/16] Make generics sharing the default for non-optimized builds. --- src/librustc/ty/context.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 8a58dad292420..3da653eb7ade9 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,7 @@ use dep_graph::DepGraph; use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; -use session::config::{BorrowckMode, OutputFilenames}; +use session::config::{BorrowckMode, OutputFilenames, OptLevel}; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -1503,8 +1503,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn share_generics(self) -> bool { match self.sess.opts.debugging_opts.share_generics { - Some(true) => true, - Some(false) | None => false, + Some(setting) => setting, + None => { + self.sess.opts.incremental.is_some() || + match self.sess.opts.optimize { + OptLevel::No | + OptLevel::Less | + OptLevel::Size | + OptLevel::SizeMin => true, + OptLevel::Default | + OptLevel::Aggressive => false, + } + } } } } From e203b3ab712cb014a4d9dbdefc11cdf91c4d2717 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Mar 2018 12:20:50 +0100 Subject: [PATCH 06/16] Remove the (inaccurate) symbol_export_level query. --- src/librustc/dep_graph/dep_node.rs | 2 -- src/librustc/ty/maps/mod.rs | 1 - src/librustc/ty/maps/plumbing.rs | 1 - src/librustc_mir/monomorphize/partitioning.rs | 3 ++- src/librustc_trans/back/symbol_export.rs | 6 ++---- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 9172c3067accd..10c22c3ed1fa7 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -648,8 +648,6 @@ define_dep_nodes!( <'tcx> [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, - [] GetSymbolExportLevel(DefId), - [] WasmCustomSections(CrateNum), [input] Features, diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 5f093bc0b488d..ac727573a79ef 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -390,7 +390,6 @@ define_maps! { <'tcx> [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc, Arc>>>), - [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel, [] fn is_translated_item: IsTranslatedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index b37628c390f51..398da011f85df 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -1087,7 +1087,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } - DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } DepKind::Features => { force!(features_query, LOCAL_CRATE); } DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index c3437c8d55b53..df07bf0507b76 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -328,7 +328,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut can_be_internalized = true; let default_visibility = |id: DefId| { if tcx.sess.target.target.options.default_hidden_visibility && - tcx.symbol_export_level(id) != SymbolExportLevel::C + tcx.reachable_non_generics(id.krate).get(&id).cloned() != + Some(SymbolExportLevel::C) { Visibility::Hidden } else { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 69ba55ff8a939..8d8daf66c3c04 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -146,7 +146,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SymbolExportLevel::Rust } } else { - tcx.symbol_export_level(def_id) + symbol_export_level(tcx, def_id) }; debug!("EXPORTED SYMBOL (local): {} ({:?})", tcx.symbol_name(Instance::mono(tcx, def_id)), @@ -314,17 +314,15 @@ pub fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.exported_symbols = exported_symbols_provider_local; - providers.symbol_export_level = symbol_export_level_provider; providers.upstream_monomorphizations = upstream_monomorphizations_provider; } pub fn provide_extern(providers: &mut Providers) { providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; - providers.symbol_export_level = symbol_export_level_provider; providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; } -fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { +fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { // We export anything that's not mangled at the "C" layer as it probably has // to do with ABI concerns. We do not, however, apply such treatment to // special symbols in the standard library for various plumbing between From 9b90674d01500b822318aaee7432441be1b7afd9 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Mar 2018 14:44:14 +0100 Subject: [PATCH 07/16] Allow for internalizing monomorphizations that cannot be shared. --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/ty/context.rs | 15 ++++ src/librustc/ty/maps/mod.rs | 1 + src/librustc/ty/maps/plumbing.rs | 3 + src/librustc_mir/monomorphize/partitioning.rs | 85 ++++++++++++++----- src/librustc_trans/back/symbol_export.rs | 16 +++- src/librustc_trans/callee.rs | 43 +++++++++- 7 files changed, 136 insertions(+), 28 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 10c22c3ed1fa7..7c5318a96f5ac 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -561,6 +561,7 @@ define_dep_nodes!( <'tcx> [] ImplParent(DefId), [] TraitOfItem(DefId), [] IsReachableNonGeneric(DefId), + [] IsUnreachableLocalDefinition(DefId), [] IsMirAvailable(DefId), [] ItemAttrs(DefId), [] TransFnAttrs(DefId), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3da653eb7ade9..3e6002cbd5171 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -15,6 +15,7 @@ use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; use session::config::{BorrowckMode, OutputFilenames, OptLevel}; +use session::config::CrateType::*; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -1517,6 +1518,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } + + #[inline] + pub fn local_crate_exports_generics(self) -> bool { + self.sess.crate_types.borrow().iter().any(|crate_type| { + match crate_type { + CrateTypeExecutable | + CrateTypeStaticlib | + CrateTypeProcMacro | + CrateTypeCdylib => false, + CrateTypeRlib | + CrateTypeDylib => true, + } + }) + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index ac727573a79ef..5a23a3b952a42 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -322,6 +322,7 @@ define_maps! { <'tcx> [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc>, [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, + [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) -> Lrc, CrateNum>>>>, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 398da011f85df..65571aa6a692d 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -1003,6 +1003,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ImplParent => { force!(impl_parent, def_id!()); } DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); } DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); } + DepKind::IsUnreachableLocalDefinition => { + force!(is_unreachable_local_definition, def_id!()); + } DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index df07bf0507b76..039ea2f015d21 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -301,7 +301,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut codegen_units = FxHashMap(); let is_incremental_build = tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet(); - let share_generics = tcx.share_generics(); + let export_generics = tcx.share_generics() && + tcx.local_crate_exports_generics(); for trans_item in trans_items { match trans_item.instantiation_mode(tcx) { @@ -326,14 +327,27 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .or_insert_with(make_codegen_unit); let mut can_be_internalized = true; - let default_visibility = |id: DefId| { - if tcx.sess.target.target.options.default_hidden_visibility && - tcx.reachable_non_generics(id.krate).get(&id).cloned() != - Some(SymbolExportLevel::C) - { - Visibility::Hidden - } else { + let default_visibility = |id: DefId, is_generic: bool| { + if !tcx.sess.target.target.options.default_hidden_visibility { + return Visibility::Default + } + + // Generic functions never have export level C + if is_generic { + return Visibility::Hidden + } + + // Things with export level C don't get instantiated in downstream + // crates + if !id.is_local() { + return Visibility::Hidden + } + + if let Some(&SymbolExportLevel::C) = tcx.reachable_non_generics(id.krate) + .get(&id) { Visibility::Default + } else { + Visibility::Hidden } }; let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) { @@ -343,6 +357,11 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, MonoItem::Fn(ref instance) => { let visibility = match instance.def { InstanceDef::Item(def_id) => { + let is_generic = instance.substs + .types() + .next() + .is_some(); + // The `start_fn` lang item is actually a // monomorphized instance of a function in the // standard library, used for the `main` @@ -364,22 +383,46 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if tcx.lang_items().start_fn() == Some(def_id) { can_be_internalized = false; Visibility::Hidden - } else if instance.substs.types().next().is_some() { - if share_generics { - can_be_internalized = false; - Visibility::Default + } else if def_id.is_local() { + if is_generic { + if export_generics { + if tcx.is_unreachable_local_definition(def_id) { + // This instance cannot be used + // from another crate. + Visibility::Hidden + } else { + // This instance might be useful in + // a downstream crate. + can_be_internalized = false; + default_visibility(def_id, true) + } + } else { + // We are not exporting generics or + // the definition is not reachable + // for downstream crates, we can + // internalize its instantiations. + Visibility::Hidden + } } else { - Visibility::Hidden + // This isn't a generic function. + if tcx.is_reachable_non_generic(def_id) { + can_be_internalized = false; + debug_assert!(!is_generic); + default_visibility(def_id, false) + } else { + Visibility::Hidden + } } - } else if def_id.is_local() { - if tcx.is_reachable_non_generic(def_id) { - can_be_internalized = false; - default_visibility(def_id) + } else { + // This is an upstream DefId. + if export_generics && is_generic { + // If it is a upstream monomorphization + // and we export generics, we must make + // it available to downstream crates. + default_visibility(def_id, true) } else { Visibility::Hidden } - } else { - Visibility::Hidden } } InstanceDef::FnPtrShim(..) | @@ -396,7 +439,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, MonoItem::Static(def_id) => { let visibility = if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; - default_visibility(def_id) + default_visibility(def_id, false) } else { Visibility::Hidden }; @@ -406,7 +449,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def_id = tcx.hir.local_def_id(node_id); let visibility = if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; - default_visibility(def_id) + default_visibility(def_id, false) } else { Visibility::Hidden }; diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 8d8daf66c3c04..e6bdcd5d76556 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -241,7 +241,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, symbols.push((exported_symbol, SymbolExportLevel::Rust)); } - if tcx.share_generics() { + if tcx.share_generics() && tcx.local_crate_exports_generics() { use rustc::mir::mono::{Linkage, Visibility, MonoItem}; use rustc::ty::InstanceDef; @@ -249,14 +249,12 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for (mono_item, &(linkage, visibility)) in cgus.iter() .flat_map(|cgu| cgu.items().iter()) { - if linkage == Linkage::External { + if linkage == Linkage::External && visibility == Visibility::Default { if let &MonoItem::Fn(Instance { def: InstanceDef::Item(def_id), substs, }) = mono_item { if substs.types().next().is_some() { - assert!(tcx.lang_items().start_fn() == Some(def_id) || - visibility == Visibility::Default); symbols.push((ExportedSymbol::Generic(def_id, substs), SymbolExportLevel::Rust)); } @@ -310,11 +308,21 @@ fn upstream_monomorphizations_for_provider<'a, 'tcx>( .cloned() } +fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id) + } else { + bug!("is_unreachable_local_definition called with non-local DefId: {:?}", + def_id) + } +} + pub fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.exported_symbols = exported_symbols_provider_local; providers.upstream_monomorphizations = upstream_monomorphizations_provider; + providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; } pub fn provide_extern(providers: &mut Providers) { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 84c07abe49b9c..5fd5cbe3a008a 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -148,16 +148,53 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if cx.tcx.share_generics() && instance.substs.types().next().is_some() { - // If this is a generic function and we are sharing generics - // it will always have Visibility::Default + let is_generic = instance.substs.types().next().is_some(); + + if is_generic { + if cx.tcx.share_generics() { + // We are in share_generics mode. + + if instance_def_id.is_local() { + // This is a definition from the current crate. If the + // definition is unreachable for downstream crates or + // the current crate does not re-export generics, the + // instance has been hidden + if cx.tcx.is_unreachable_local_definition(instance_def_id) || + !cx.tcx.local_crate_exports_generics() { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } else { + if cx.tcx.upstream_monomorphizations_for(instance_def_id) + .map(|set| set.contains_key(instance.substs)) + .unwrap_or(false) { + // This is instantiated in another crate. It cannot be hidden + } else { + // This is a local instantiation of an upstream definition. + // If the current crate does not re-export it, it is hidden. + if !cx.tcx.local_crate_exports_generics() { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } + } + } else { + // When not sharing generics, all instances are in the same + // crate and have hidden visibility + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } } else { + // This is a non-generic function if cx.tcx.is_translated_item(instance_def_id) { + // This is a function that is instantiated in the local crate + if instance_def_id.is_local() { + // This is function that is defined in the local crate. + // If it is not reachable, it is hidden. if !cx.tcx.is_reachable_non_generic(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } else { + // This is a function from an upstream crate that has + // been instantiated here. These are always hidden. llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } From 5316a458b2ebf12aab1922ce905d38df6496ac8a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 7 Mar 2018 12:01:28 +0100 Subject: [PATCH 08/16] Adapt codegen-unit test to shared-generics. --- src/test/codegen-units/partitioning/extern-generic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index bdb31265e2fb2..140b43c85d548 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic +// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y #![allow(dead_code)] #![crate_type="lib"] @@ -59,4 +59,4 @@ mod mod3 { // Make sure the two generic functions from the extern crate get instantiated // once for the current crate //~ TRANS_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function.volatile[External] -//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[Internal] +//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[External] From 213ef111cfdb4bca63b5c37f440b2c028c6ca676 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Mar 2018 18:28:53 +0100 Subject: [PATCH 09/16] Select upstream monomorphizations in a stable way. --- src/librustc_trans/back/symbol_export.rs | 40 +++++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index e6bdcd5d76556..0f88e9cd7b799 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -14,8 +14,8 @@ use std::sync::Arc; use monomorphize::Instance; use rustc::hir; use rustc::hir::TransFnAttrFlags; -use rustc::hir::def_id::CrateNum; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; +use rustc::ich::Fingerprint; use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; @@ -23,6 +23,9 @@ use rustc::ty::maps::Providers; use rustc::ty::subst::Substs; use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; +use rustc_data_structures::indexed_vec::IndexVec; +use syntax::attr; +use std::collections::hash_map::Entry::*; pub type ExportedSymbols = FxHashMap< CrateNum, @@ -282,12 +285,39 @@ fn upstream_monomorphizations_provider<'a, 'tcx>( let mut instances = DefIdMap(); + let cnum_stable_ids: IndexVec = { + let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, + cnums.len() + 1); + + for &cnum in cnums.iter() { + cnum_stable_ids[cnum] = tcx.def_path_hash(DefId { + krate: cnum, + index: CRATE_DEF_INDEX, + }).0; + } + + cnum_stable_ids + }; + for &cnum in cnums.iter() { for &(ref exported_symbol, _) in tcx.exported_symbols(cnum).iter() { if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { - instances.entry(def_id) - .or_insert_with(|| FxHashMap()) - .insert(substs, cnum); + let substs_map = instances.entry(def_id) + .or_insert_with(|| FxHashMap()); + + match substs_map.entry(substs) { + Occupied(mut e) => { + // If there are multiple monomorphizations available, + // we select one deterministically. + let other_cnum = *e.get(); + if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] { + e.insert(cnum); + } + } + Vacant(e) => { + e.insert(cnum); + } + } } } } From a1a986cfae567b1b21dfb8359b585e5aeebf84b8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Mar 2018 11:52:26 +0100 Subject: [PATCH 10/16] Fix some rebasing fallout. --- src/librustc/middle/exported_symbols.rs | 4 ++-- src/librustc_trans/back/symbol_export.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index 2652eb0091cb1..01783eb0ff65f 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -112,9 +112,9 @@ pub fn metadata_symbol_name(tcx: ty::TyCtxt) -> String { tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()) } -impl<'gcx> HashStable> for ExportedSymbol<'gcx> { +impl<'a, 'gcx> HashStable> for ExportedSymbol<'gcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'gcx>, + hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 0f88e9cd7b799..90dec83c1d4d6 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -24,7 +24,6 @@ use rustc::ty::subst::Substs; use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; use rustc_data_structures::indexed_vec::IndexVec; -use syntax::attr; use std::collections::hash_map::Entry::*; pub type ExportedSymbols = FxHashMap< From 2d2cf0306c4d96d4da3d45f566286d0c9b6c82ce Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Mar 2018 14:21:00 +0100 Subject: [PATCH 11/16] Don't internalize generics that are re-exported --- src/librustc_mir/monomorphize/partitioning.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 039ea2f015d21..4ea09ae9f7b52 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -419,6 +419,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // If it is a upstream monomorphization // and we export generics, we must make // it available to downstream crates. + can_be_internalized = false; default_visibility(def_id, true) } else { Visibility::Hidden From 94d36cf2948a999210516ff9001f93277f331d04 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Mar 2018 14:24:03 +0100 Subject: [PATCH 12/16] Make sure that generics are internalized in executables even with -Zshare-generics --- .../local-generics-in-exe-internalized.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/codegen/local-generics-in-exe-internalized.rs diff --git a/src/test/codegen/local-generics-in-exe-internalized.rs b/src/test/codegen/local-generics-in-exe-internalized.rs new file mode 100644 index 0000000000000..162a025c30217 --- /dev/null +++ b/src/test/codegen/local-generics-in-exe-internalized.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes -Zshare-generics=yes + +// Check that local generics are internalized if they are in the same CGU + +// CHECK: define internal {{.*}} @_ZN34local_generics_in_exe_internalized3foo{{.*}} +pub fn foo(x: T, y: T) -> (T, T) { + (x, y) +} + +fn main() { + let _ = foo(0u8, 1u8); +} From 69c7f5ccbb442af38dbdcbd688b13352c2a4f566 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Mar 2018 14:26:49 +0100 Subject: [PATCH 13/16] Add codegen-units test for shared-generics. --- .../auxiliary/shared_generics_aux.rs | 21 +++++++++++++ .../partitioning/shared-generics.rs | 30 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs create mode 100644 src/test/codegen-units/partitioning/shared-generics.rs diff --git a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs new file mode 100644 index 0000000000000..b742da8a9001f --- /dev/null +++ b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs @@ -0,0 +1,21 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Zshare-generics=yes + +#![crate_type="rlib"] + +pub fn generic_fn(x: T, y: T) -> (T, T) { + (x, y) +} + +pub fn use_generic_fn_f32() -> (f32, f32) { + generic_fn(0.0f32, 1.0f32) +} diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs new file mode 100644 index 0000000000000..d352609bfcbe4 --- /dev/null +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -0,0 +1,30 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// compile-flags:-Zprint-trans-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe + +#![crate_type="rlib"] + +// aux-build:shared_generics_aux.rs +extern crate shared_generics_aux; + +//~ TRANS_ITEM fn shared_generics::foo[0] +pub fn foo() { + + //~ TRANS_ITEM fn shared_generics_aux::generic_fn[0] @@ shared_generics_aux.volatile[External] + let _ = shared_generics_aux::generic_fn(0u16, 1u16); + + // This should not generate a monomorphization because it's already + // available in `shared_generics_aux`. + let _ = shared_generics_aux::generic_fn(0.0f32, 3.0f32); +} + +// TRANS_ITEM drop-glue i8 From ec55390387ac068184ded9283aece14aab9bfaf8 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 14 Mar 2018 16:45:06 +0100 Subject: [PATCH 14/16] Update a few comments about symbol visibility. --- src/librustc_mir/monomorphize/collector.rs | 8 ++++ src/librustc_mir/monomorphize/partitioning.rs | 5 ++ src/librustc_trans/callee.rs | 46 +++++++++---------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index e93b936d4f06e..ef018237dbad9 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -762,14 +762,22 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: -> bool { debug_assert!(!def_id.is_local()); + // If we are not in share generics mode, we don't link to upstream + // monomorphizations but always instantiate our own internal versions + // instead. if !tcx.share_generics() { return false } + // If this instance has no type parameters, it cannot be a shared + // monomorphization. Non-generic instances are already handled above + // by `is_reachable_non_generic()` if substs.types().next().is_none() { return false } + // Take a look at the available monomorphizations listed in the metadata + // of upstream crates. tcx.upstream_monomorphizations_for(def_id) .map(|set| set.contains_key(substs)) .unwrap_or(false) diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 4ea09ae9f7b52..da4cb4ec78904 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -301,6 +301,11 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut codegen_units = FxHashMap(); let is_incremental_build = tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet(); + + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. let export_generics = tcx.share_generics() && tcx.local_crate_exports_generics(); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 5fd5cbe3a008a..2c503bdab30a9 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -118,39 +118,31 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // This is sort of subtle. Inside our codegen unit we started off // compilation by predefining all our own `TransItem` instances. That // is, everything we're translating ourselves is already defined. That - // means that anything we're actually translating ourselves will have - // hit the above branch in `get_declared_value`. As a result, we're - // guaranteed here that we're declaring a symbol that won't get defined, - // or in other words we're referencing a foreign value. + // means that anything we're actually translating in this codegen unit + // will have hit the above branch in `get_declared_value`. As a result, + // we're guaranteed here that we're declaring a symbol that won't get + // defined, or in other words we're referencing a value from another + // codegen unit or even another crate. // // So because this is a foreign value we blanket apply an external // linkage directive because it's coming from a different object file. // The visibility here is where it gets tricky. This symbol could be // referencing some foreign crate or foreign library (an `extern` // block) in which case we want to leave the default visibility. We may - // also, though, have multiple codegen units. - // - // In the situation of multiple codegen units this function may be - // referencing a function from another codegen unit. If we're - // indeed referencing a symbol in another codegen unit then we're in one - // of two cases: - // - // * This is a symbol defined in a foreign crate and we're just - // monomorphizing in another codegen unit. In this case this symbols - // is for sure not exported, so both codegen units will be using - // hidden visibility. Hence, we apply a hidden visibility here. - // - // * This is a symbol defined in our local crate. If the symbol in the - // other codegen unit is also not exported then like with the foreign - // case we apply a hidden visibility. If the symbol is exported from - // the foreign object file, however, then we leave this at the - // default visibility as we'll just import it naturally. + // also, though, have multiple codegen units. It could be a + // monomorphization, in which case its expected visibility depends on + // whether we are sharing generics or not. The important thing here is + // that the visibility we apply to the declaration is the same one that + // has been applied to the definition (wherever that definition may be). unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); let is_generic = instance.substs.types().next().is_some(); if is_generic { + // This is a monomorphization. Its expected visibility depends + // on whether we are in share-generics mode. + if cx.tcx.share_generics() { // We are in share_generics mode. @@ -158,19 +150,25 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // This is a definition from the current crate. If the // definition is unreachable for downstream crates or // the current crate does not re-export generics, the - // instance has been hidden + // definition of the instance will have been declared + // as `hidden`. if cx.tcx.is_unreachable_local_definition(instance_def_id) || !cx.tcx.local_crate_exports_generics() { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } else { + // This is a monomorphization of a generic function + // defined in an upstream crate. if cx.tcx.upstream_monomorphizations_for(instance_def_id) .map(|set| set.contains_key(instance.substs)) .unwrap_or(false) { - // This is instantiated in another crate. It cannot be hidden + // This is instantiated in another crate. It cannot + // be `hidden`. } else { // This is a local instantiation of an upstream definition. - // If the current crate does not re-export it, it is hidden. + // If the current crate does not re-export it + // (because it is a C library or an executable), it + // will have been declared `hidden`. if !cx.tcx.local_crate_exports_generics() { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } From 07704a4e1dd5c1b21e0a447d88511d455497b390 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 21 Mar 2018 12:23:57 +0100 Subject: [PATCH 15/16] Allow for re-using hidden monomorphizations on platforms that don't support Rust dylibs. --- src/librustc/ty/context.rs | 2 ++ src/librustc_trans/back/symbol_export.rs | 36 ++++++++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3e6002cbd5171..69b33efdb3542 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1521,6 +1521,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn local_crate_exports_generics(self) -> bool { + debug_assert!(self.share_generics()); + self.sess.crate_types.borrow().iter().any(|crate_type| { match crate_type { CrateTypeExecutable | diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 90dec83c1d4d6..acd2a7657307c 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -247,19 +247,37 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, use rustc::mir::mono::{Linkage, Visibility, MonoItem}; use rustc::ty::InstanceDef; + // Normally, we require that shared monomorphizations are not hidden, + // because if we want to re-use a monomorphization from a Rust dylib, it + // needs to be exported. + // However, on platforms that don't allow for Rust dylibs, having + // external linkage is enough for monomorphization to be linked to. + let need_visibility = tcx.sess.target.target.options.dynamic_linking && + !tcx.sess.target.target.options.only_cdylib; + let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); for (mono_item, &(linkage, visibility)) in cgus.iter() .flat_map(|cgu| cgu.items().iter()) { - if linkage == Linkage::External && visibility == Visibility::Default { - if let &MonoItem::Fn(Instance { - def: InstanceDef::Item(def_id), - substs, - }) = mono_item { - if substs.types().next().is_some() { - symbols.push((ExportedSymbol::Generic(def_id, substs), - SymbolExportLevel::Rust)); - } + if linkage != Linkage::External { + // We can only re-use things with external linkage, otherwise + // we'll get a linker error + continue + } + + if need_visibility && visibility == Visibility::Hidden { + // If we potentially share things from Rust dylibs, they must + // not be hidden + continue + } + + if let &MonoItem::Fn(Instance { + def: InstanceDef::Item(def_id), + substs, + }) = mono_item { + if substs.types().next().is_some() { + symbols.push((ExportedSymbol::Generic(def_id, substs), + SymbolExportLevel::Rust)); } } } From 61991a544f2e673e626e5db7639585fe8aa048b7 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Mar 2018 14:21:50 +0100 Subject: [PATCH 16/16] Update run-make/symbol-visibility to also cover shared-generics --- .../symbol-visibility/Makefile | 42 ++++++++++++++++--- .../symbol-visibility/a_rust_dylib.rs | 7 +++- .../symbol-visibility/an_rlib.rs | 8 +++- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/test/run-make-fulldeps/symbol-visibility/Makefile b/src/test/run-make-fulldeps/symbol-visibility/Makefile index f1ada814bdb80..17d470063fc93 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/Makefile +++ b/src/test/run-make-fulldeps/symbol-visibility/Makefile @@ -23,11 +23,11 @@ COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib endif all: - $(RUSTC) an_rlib.rs - $(RUSTC) a_cdylib.rs - $(RUSTC) a_rust_dylib.rs - $(RUSTC) an_executable.rs - $(RUSTC) a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib + $(RUSTC) -Zshare-generics=no an_rlib.rs + $(RUSTC) -Zshare-generics=no a_cdylib.rs + $(RUSTC) -Zshare-generics=no a_rust_dylib.rs + $(RUSTC) -Zshare-generics=no an_executable.rs + $(RUSTC) -Zshare-generics=no a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib # Check that a cdylib exports its public #[no_mangle] functions [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ] @@ -39,10 +39,15 @@ all: # Check that a Rust dylib exports its monomorphic functions [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + # Check that a Rust dylib does not export generics if -Zshare-generics=no + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "0" ] + # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] + # Check that a Rust dylib does not export generics if -Zshare-generics=no + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "0" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] @@ -57,4 +62,31 @@ all: [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + + + $(RUSTC) -Zshare-generics=yes an_rlib.rs + $(RUSTC) -Zshare-generics=yes a_cdylib.rs + $(RUSTC) -Zshare-generics=yes a_rust_dylib.rs + $(RUSTC) -Zshare-generics=yes an_executable.rs + + # Check that a cdylib exports its public #[no_mangle] functions + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ] + # Check that a cdylib exports the public #[no_mangle] functions of dependencies + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] + # Check that a cdylib DOES NOT export any public Rust functions + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + + # Check that a Rust dylib exports its monomorphic functions, including generics this time + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "1" ] + + # Check that a Rust dylib exports the monomorphic functions from its dependencies + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "1" ] + + # Check that an executable does not export any dynamic symbols + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ] endif diff --git a/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs b/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs index b826211c9a42a..99e748ec2efc8 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs +++ b/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs @@ -17,4 +17,9 @@ pub fn public_rust_function_from_rust_dylib() {} // This should be exported #[no_mangle] -pub extern "C" fn public_c_function_from_rust_dylib() {} +pub extern "C" fn public_c_function_from_rust_dylib() { + let _ = public_generic_function_from_rust_dylib(1u16); +} + +// This should be exported if -Zshare-generics=yes +pub fn public_generic_function_from_rust_dylib(x: T) -> T { x } diff --git a/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs b/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs index cd19500d14021..a1d73afd30b11 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs +++ b/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs @@ -13,4 +13,10 @@ pub fn public_rust_function_from_rlib() {} #[no_mangle] -pub extern "C" fn public_c_function_from_rlib() {} +pub extern "C" fn public_c_function_from_rlib() { + let _ = public_generic_function_from_rlib(0u64); +} + +pub fn public_generic_function_from_rlib(x: T) -> T { + x +}