Allow for re-using monomorphizations from upstream crates.
This commit is contained in:
parent
435477dc65
commit
4f6d05dc48
13 changed files with 194 additions and 37 deletions
|
@ -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 {
|
||||
|
|
|
@ -53,8 +53,21 @@ for &'gcx ty::Slice<T>
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ty::subst::Kind<'gcx> {
|
||||
impl<'a, 'gcx, T> ToStableHashKey<StableHashingContext<'a>> for &'gcx ty::Slice<T>
|
||||
where T: HashStable<StableHashingContext<'a>>
|
||||
{
|
||||
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<StableHashingContext<'a>> for ty::subst::Kind<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
|
|
|
@ -1304,6 +1304,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
"embed LLVM bitcode in object files"),
|
||||
strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"tell the linker to strip debuginfo when building without debuginfo enabled."),
|
||||
share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"make the current crate share its generic instantiations"),
|
||||
}
|
||||
|
||||
pub fn default_lib_output() -> CrateType {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<DefIdSet>,
|
||||
[] fn reachable_non_generics: ReachableNonGenerics(CrateNum)
|
||||
-> Lrc<DefIdMap<SymbolExportLevel>>,
|
||||
[] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool,
|
||||
|
||||
[] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum)
|
||||
-> Lrc<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>>,
|
||||
[] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId)
|
||||
-> Option<Lrc<FxHashMap<&'tcx Substs<'tcx>, CrateNum>>>,
|
||||
|
||||
[] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DefIdMap<Lrc<FxHashMap<&'tcx Substs<'tcx>, 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<Lrc<FxHashMap<&'tcx Substs<'tcx>, 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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
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 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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue