Skip to content

Commit 197cc1e

Browse files
Add projection query for upstream drop-glue instances.
This reduces the amount of invalidated data when new types are add to upstream crates.
1 parent 2ceb92b commit 197cc1e

File tree

8 files changed

+138
-98
lines changed

8 files changed

+138
-98
lines changed
+7-23
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
use crate::ich::StableHashingContext;
21
use crate::ty::subst::SubstsRef;
3-
use crate::ty::{self, TyCtxt};
4-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2+
use crate::ty::{self, Ty, TyCtxt};
53
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
6-
use std::mem;
4+
use rustc_macros::HashStable;
75

86
/// The SymbolExportLevel of a symbols specifies from which kinds of crates
97
/// the symbol will be exported. `C` symbols will be exported from any
@@ -23,10 +21,11 @@ impl SymbolExportLevel {
2321
}
2422
}
2523

26-
#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
24+
#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
2725
pub enum ExportedSymbol<'tcx> {
2826
NonGeneric(DefId),
2927
Generic(DefId, SubstsRef<'tcx>),
28+
DropGlue(Ty<'tcx>),
3029
NoDefId(ty::SymbolName),
3130
}
3231

@@ -39,6 +38,9 @@ impl<'tcx> ExportedSymbol<'tcx> {
3938
ExportedSymbol::Generic(def_id, substs) => {
4039
tcx.symbol_name(ty::Instance::new(def_id, substs))
4140
}
41+
ExportedSymbol::DropGlue(ty) => {
42+
tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty))
43+
}
4244
ExportedSymbol::NoDefId(symbol_name) => symbol_name,
4345
}
4446
}
@@ -51,21 +53,3 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
5153
tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()
5254
)
5355
}
54-
55-
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ExportedSymbol<'tcx> {
56-
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
57-
mem::discriminant(self).hash_stable(hcx, hasher);
58-
match *self {
59-
ExportedSymbol::NonGeneric(def_id) => {
60-
def_id.hash_stable(hcx, hasher);
61-
}
62-
ExportedSymbol::Generic(def_id, substs) => {
63-
def_id.hash_stable(hcx, hasher);
64-
substs.hash_stable(hcx, hasher);
65-
}
66-
ExportedSymbol::NoDefId(symbol_name) => {
67-
symbol_name.hash_stable(hcx, hasher);
68-
}
69-
}
70-
}
71-
}

src/librustc/query/mod.rs

+34
Original file line numberDiff line numberDiff line change
@@ -776,13 +776,47 @@ rustc_queries! {
776776
}
777777

778778
Codegen {
779+
/// The entire set of monomorphizations the local crate can safely link
780+
/// to because they are exported from upstream crates. Do not depend on
781+
/// this directly, as its value changes anytime a monomorphization gets
782+
/// added or removed in any upstream crate. Instead use the narrower
783+
/// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
784+
/// better, `Instance::upstream_monomorphization()`.
779785
query upstream_monomorphizations(
780786
k: CrateNum
781787
) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
782788
desc { "collecting available upstream monomorphizations `{:?}`", k }
783789
}
790+
791+
/// Returns the set of upstream monomorphizations available for the
792+
/// generic function identified by the given `def_id`. The query makes
793+
/// sure to make a stable selection if the same monomorphization is
794+
/// available in multiple upstream crates.
795+
///
796+
/// You likely want to call `Instance::upstream_monomorphization()`
797+
/// instead of invoking this query directly.
784798
query upstream_monomorphizations_for(_: DefId)
785799
-> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {}
800+
801+
/// Returns the upstream crate that exports drop-glue for the given
802+
/// type (`substs` is expected to be a single-item list containing the
803+
/// type one wants drop-glue for).
804+
///
805+
/// This is a subset of `upstream_monomorphizations_for` in order to
806+
/// increase dep-tracking granularity. Otherwise adding or removing any
807+
/// type with drop-glue in any upstream crate would invalidate all
808+
/// functions calling drop-glue of an upstream type.
809+
///
810+
/// You likely want to call `Instance::upstream_monomorphization()`
811+
/// instead of invoking this query directly.
812+
///
813+
/// NOTE: This query could easily be extended to also support other
814+
/// common functions that have are large set of monomorphizations
815+
/// (like `Clone::clone` for example).
816+
query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option<CrateNum> {
817+
desc { "available upstream drop-glue for `{:?}`", substs }
818+
no_force
819+
}
786820
}
787821

788822
Other {

src/librustc/ty/instance.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::traits;
44
use crate::ty::print::{FmtPrinter, Printer};
55
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
66
use rustc_hir::def::Namespace;
7-
use rustc_hir::def_id::DefId;
7+
use rustc_hir::def_id::{CrateNum, DefId};
88
use rustc_macros::HashStable;
99
use rustc_target::spec::abi::Abi;
1010

@@ -91,6 +91,40 @@ impl<'tcx> Instance<'tcx> {
9191
let ty = tcx.type_of(self.def.def_id());
9292
tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty)
9393
}
94+
95+
/// Finds a crate that contains a monomorphization of this instance that
96+
/// can be linked to from the local crate. A return value of `None` means
97+
/// no upstream crate provides such an exported monomorphization.
98+
///
99+
/// This method already takes into account the global `-Zshare-generics`
100+
/// setting, always returning `None` if `share-generics` is off.
101+
pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
102+
// If we are not in share generics mode, we don't link to upstream
103+
// monomorphizations but always instantiate our own internal versions
104+
// instead.
105+
if !tcx.sess.opts.share_generics() {
106+
return None;
107+
}
108+
109+
// If this is an item that is defined in the local crate, no upstream
110+
// crate can know about it/provide a monomorphization.
111+
if self.def_id().is_local() {
112+
return None;
113+
}
114+
115+
// If this a non-generic instance, it cannot be a shared monomorphization.
116+
if self.substs.non_erasable_generics().next().is_none() {
117+
return None;
118+
}
119+
120+
match self.def {
121+
InstanceDef::Item(def_id) => tcx
122+
.upstream_monomorphizations_for(def_id)
123+
.and_then(|monos| monos.get(&self.substs).cloned()),
124+
InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs),
125+
_ => None,
126+
}
127+
}
94128
}
95129

96130
impl<'tcx> InstanceDef<'tcx> {

src/librustc/ty/query/keys.rs

+9
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ impl Key for (DefId, SimplifiedType) {
116116
}
117117
}
118118

119+
impl<'tcx> Key for SubstsRef<'tcx> {
120+
fn query_crate(&self) -> CrateNum {
121+
LOCAL_CRATE
122+
}
123+
fn default_span(&self, _: TyCtxt<'_>) -> Span {
124+
DUMMY_SP
125+
}
126+
}
127+
119128
impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
120129
fn query_crate(&self) -> CrateNum {
121130
self.0.krate

src/librustc_codegen_llvm/callee.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
130130
} else {
131131
// This is a monomorphization of a generic function
132132
// defined in an upstream crate.
133-
if cx
134-
.tcx
135-
.upstream_monomorphizations_for(instance_def_id)
136-
.map(|set| set.contains_key(instance.substs))
137-
.unwrap_or(false)
138-
{
133+
if instance.upstream_monomorphization(tcx).is_some() {
139134
// This is instantiated in another crate. It cannot
140135
// be `hidden`.
141136
} else {

src/librustc_codegen_ssa/back/symbol_export.rs

+48-15
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,13 @@ fn exported_symbols_provider_local(
255255
symbols.push((symbol, SymbolExportLevel::Rust));
256256
}
257257
}
258-
MonoItem::Fn(Instance { def: InstanceDef::DropGlue(def_id, Some(ty)), substs }) => {
258+
MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => {
259259
// A little sanity-check
260260
debug_assert_eq!(
261261
substs.non_erasable_generics().next(),
262262
Some(GenericArgKind::Type(ty))
263263
);
264-
let symbol = ExportedSymbol::Generic(def_id, substs);
265-
symbols.push((symbol, SymbolExportLevel::Rust));
264+
symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportLevel::Rust));
266265
}
267266
_ => {
268267
// Any other symbols don't qualify for sharing
@@ -298,24 +297,41 @@ fn upstream_monomorphizations_provider(
298297
cnum_stable_ids
299298
};
300299

300+
let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
301+
301302
for &cnum in cnums.iter() {
302303
for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
303-
if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol {
304-
let substs_map = instances.entry(def_id).or_default();
305-
306-
match substs_map.entry(substs) {
307-
Occupied(mut e) => {
308-
// If there are multiple monomorphizations available,
309-
// we select one deterministically.
310-
let other_cnum = *e.get();
311-
if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
312-
e.insert(cnum);
313-
}
304+
let (def_id, substs) = match *exported_symbol {
305+
ExportedSymbol::Generic(def_id, substs) => (def_id, substs),
306+
ExportedSymbol::DropGlue(ty) => {
307+
if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id {
308+
(drop_in_place_fn_def_id, tcx.intern_substs(&[ty.into()]))
309+
} else {
310+
// `drop_in_place` in place does not exist, don't try
311+
// to use it.
312+
continue;
314313
}
315-
Vacant(e) => {
314+
}
315+
ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => {
316+
// These are no monomorphizations
317+
continue;
318+
}
319+
};
320+
321+
let substs_map = instances.entry(def_id).or_default();
322+
323+
match substs_map.entry(substs) {
324+
Occupied(mut e) => {
325+
// If there are multiple monomorphizations available,
326+
// we select one deterministically.
327+
let other_cnum = *e.get();
328+
if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
316329
e.insert(cnum);
317330
}
318331
}
332+
Vacant(e) => {
333+
e.insert(cnum);
334+
}
319335
}
320336
}
321337
}
@@ -331,6 +347,17 @@ fn upstream_monomorphizations_for_provider(
331347
tcx.upstream_monomorphizations(LOCAL_CRATE).get(&def_id)
332348
}
333349

350+
fn upstream_drop_glue_for_provider<'tcx>(
351+
tcx: TyCtxt<'tcx>,
352+
substs: SubstsRef<'tcx>,
353+
) -> Option<CrateNum> {
354+
if let Some(def_id) = tcx.lang_items().drop_in_place_fn() {
355+
tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&substs).cloned())
356+
} else {
357+
None
358+
}
359+
}
360+
334361
fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
335362
if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) {
336363
!tcx.reachable_set(LOCAL_CRATE).contains(&hir_id)
@@ -345,6 +372,7 @@ pub fn provide(providers: &mut Providers<'_>) {
345372
providers.exported_symbols = exported_symbols_provider_local;
346373
providers.upstream_monomorphizations = upstream_monomorphizations_provider;
347374
providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
375+
providers.upstream_drop_glue_for = upstream_drop_glue_for_provider;
348376
}
349377

350378
pub fn provide_extern(providers: &mut Providers<'_>) {
@@ -405,6 +433,11 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
405433
Instance::new(def_id, substs),
406434
instantiating_crate,
407435
),
436+
ExportedSymbol::DropGlue(ty) => symbol_names::symbol_name_for_instance_in_crate(
437+
tcx,
438+
Instance::resolve_drop_in_place(tcx, ty),
439+
instantiating_crate,
440+
),
408441
ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(),
409442
}
410443
}

src/librustc_codegen_utils/symbol_names.rs

+3-22
Original file line numberDiff line numberDiff line change
@@ -126,29 +126,10 @@ fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::Symb
126126
// This closure determines the instantiating crate for instances that
127127
// need an instantiating-crate-suffix for their symbol name, in order
128128
// to differentiate between local copies.
129-
//
130-
// For generics we might find re-usable upstream instances. For anything
131-
// else we rely on their being a local copy available.
132-
133129
if is_generic(instance.substs) {
134-
let def_id = instance.def_id();
135-
136-
if !def_id.is_local() && tcx.sess.opts.share_generics() {
137-
// If we are re-using a monomorphization from another crate,
138-
// we have to compute the symbol hash accordingly.
139-
let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id);
140-
141-
upstream_monomorphizations
142-
.and_then(|monos| monos.get(&instance.substs).cloned())
143-
// If there is no instance available upstream, there'll be
144-
// one in the current crate.
145-
.unwrap_or(LOCAL_CRATE)
146-
} else {
147-
// For generic functions defined in the current crate, there
148-
// can be no upstream instances. Also, if we don't share
149-
// generics, we'll instantiate a local copy too.
150-
LOCAL_CRATE
151-
}
130+
// For generics we might find re-usable upstream instances. If there
131+
// is one, we rely on the symbol being instantiated locally.
132+
instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE)
152133
} else {
153134
// For non-generic things that need to avoid naming conflicts, we
154135
// always instantiate a copy in the local crate.

src/librustc_mir/monomorphize/collector.rs

+1-31
Original file line numberDiff line numberDiff line change
@@ -737,9 +737,7 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx
737737
return true;
738738
}
739739

740-
if tcx.is_reachable_non_generic(def_id)
741-
|| is_available_upstream_generic(tcx, def_id, instance.substs)
742-
{
740+
if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() {
743741
// We can link to the item in question, no instance needed
744742
// in this crate.
745743
return false;
@@ -750,34 +748,6 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx
750748
}
751749

752750
return true;
753-
754-
fn is_available_upstream_generic<'tcx>(
755-
tcx: TyCtxt<'tcx>,
756-
def_id: DefId,
757-
substs: SubstsRef<'tcx>,
758-
) -> bool {
759-
debug_assert!(!def_id.is_local());
760-
761-
// If we are not in share generics mode, we don't link to upstream
762-
// monomorphizations but always instantiate our own internal versions
763-
// instead.
764-
if !tcx.sess.opts.share_generics() {
765-
return false;
766-
}
767-
768-
// If this instance has non-erasable parameters, it cannot be a shared
769-
// monomorphization. Non-generic instances are already handled above
770-
// by `is_reachable_non_generic()`.
771-
if substs.non_erasable_generics().next().is_none() {
772-
return false;
773-
}
774-
775-
// Take a look at the available monomorphizations listed in the metadata
776-
// of upstream crates.
777-
tcx.upstream_monomorphizations_for(def_id)
778-
.map(|set| set.contains_key(substs))
779-
.unwrap_or(false)
780-
}
781751
}
782752

783753
/// For a given pair of source and target type that occur in an unsizing coercion,

0 commit comments

Comments
 (0)