Split exported_symbols for generic and non-generic symbols

This reduces metadata decoder overhead during the monomorphization collector.
This commit is contained in:
bjorn3
2025-06-25 14:19:57 +00:00
parent a17780db7b
commit 753c73a349
10 changed files with 86 additions and 37 deletions

View File

@@ -1794,7 +1794,10 @@ fn for_each_exported_symbols_include_dep<'tcx>(
for (cnum, dep_format) in deps.iter_enumerated() {
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
for &(symbol, info) in tcx.exported_non_generic_symbols(cnum).iter() {
callback(symbol, info, cnum);
}
for &(symbol, info) in tcx.exported_generic_symbols(cnum).iter() {
callback(symbol, info, cnum);
}
}

View File

@@ -164,7 +164,7 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}
fn exported_symbols_provider_local<'tcx>(
fn exported_non_generic_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
_: LocalCrate,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
@@ -296,6 +296,22 @@ fn exported_symbols_provider_local<'tcx>(
));
}
// Sort so we get a stable incr. comp. hash.
symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx));
tcx.arena.alloc_from_iter(symbols)
}
fn exported_generic_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
_: LocalCrate,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
return &[];
}
let mut symbols: Vec<_> = vec![];
if tcx.local_crate_exports_generics() {
use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
use rustc_middle::ty::InstanceKind;
@@ -458,7 +474,7 @@ fn upstream_monomorphizations_provider(
let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn();
for &cnum in cnums.iter() {
for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() {
for (exported_symbol, _) in tcx.exported_generic_symbols(cnum).iter() {
let (def_id, args) = match *exported_symbol {
ExportedSymbol::Generic(def_id, args) => (def_id, args),
ExportedSymbol::DropGlue(ty) => {
@@ -480,10 +496,7 @@ fn upstream_monomorphizations_provider(
ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])),
ExportedSymbol::NonGeneric(..)
| ExportedSymbol::ThreadLocalShim(..)
| ExportedSymbol::NoDefId(..) => {
// These are no monomorphizations
continue;
}
| ExportedSymbol::NoDefId(..) => unreachable!("{exported_symbol:?}"),
};
let args_map = instances.entry(def_id).or_default();
@@ -538,7 +551,8 @@ fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId)
pub(crate) 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.exported_non_generic_symbols = exported_non_generic_symbols_provider_local;
providers.exported_generic_symbols = exported_generic_symbols_provider_local;
providers.upstream_monomorphizations = upstream_monomorphizations_provider;
providers.is_unreachable_local_definition = is_unreachable_local_definition_provider;
providers.upstream_drop_glue_for = upstream_drop_glue_for_provider;

View File

@@ -1124,8 +1124,9 @@ fn start_executing_work<B: ExtraBackendMethods>(
let copy_symbols = |cnum| {
let symbols = tcx
.exported_symbols(cnum)
.exported_non_generic_symbols(cnum)
.iter()
.chain(tcx.exported_generic_symbols(cnum))
.map(|&(s, lvl)| (symbol_name_for_instance_in_crate(tcx, s, cnum), lvl))
.collect();
Arc::new(symbols)

View File

@@ -1496,11 +1496,18 @@ impl<'a> CrateMetadataRef<'a> {
.map(move |v| (self.local_def_id(v.0), v.1))
}
fn exported_symbols<'tcx>(
fn exported_non_generic_symbols<'tcx>(
self,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
tcx.arena.alloc_from_iter(self.root.exported_non_generic_symbols.decode((self, tcx)))
}
fn exported_generic_symbols<'tcx>(
self,
tcx: TyCtxt<'tcx>,
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx)))
}
fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef {

View File

@@ -358,7 +358,7 @@ provide! { tcx, def_id, other, cdata,
specialization_enabled_in => { cdata.root.specialization_enabled_in }
reachable_non_generics => {
let reachable_non_generics = tcx
.exported_symbols(cdata.cnum)
.exported_non_generic_symbols(cdata.cnum)
.iter()
.filter_map(|&(exported_symbol, export_info)| {
if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
@@ -408,15 +408,8 @@ provide! { tcx, def_id, other, cdata,
exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items()) }
stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls().collect()) }
exported_symbols => {
let syms = cdata.exported_symbols(tcx);
// FIXME rust-lang/rust#64319, rust-lang/rust#64872: We want
// to block export of generics from dylibs, but we must fix
// rust-lang/rust#65890 before we can do that robustly.
syms
}
exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) }
exported_generic_symbols => { cdata.exported_generic_symbols(tcx) }
crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }

View File

@@ -677,9 +677,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
stat!("exportable-items", || self.encode_stable_order_of_exportable_impls());
// Encode exported symbols info. This is prefetched in `encode_metadata`.
let exported_symbols = stat!("exported-symbols", || {
self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE))
});
let (exported_non_generic_symbols, exported_generic_symbols) =
stat!("exported-symbols", || {
(
self.encode_exported_symbols(tcx.exported_non_generic_symbols(LOCAL_CRATE)),
self.encode_exported_symbols(tcx.exported_generic_symbols(LOCAL_CRATE)),
)
});
// Encode the hygiene data.
// IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The
@@ -745,7 +749,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
incoherent_impls,
exportable_items,
stable_order_of_exportable_impls,
exported_symbols,
exported_non_generic_symbols,
exported_generic_symbols,
interpret_alloc_index,
tables,
syntax_contexts,
@@ -2356,7 +2361,13 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) {
// Prefetch some queries used by metadata encoding.
// This is not necessary for correctness, but is only done for performance reasons.
// It can be removed if it turns out to cause trouble or be detrimental to performance.
join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE));
join(
|| prefetch_mir(tcx),
|| {
let _ = tcx.exported_non_generic_symbols(LOCAL_CRATE);
let _ = tcx.exported_generic_symbols(LOCAL_CRATE);
},
);
}
with_encode_metadata_header(tcx, path, |ecx| {

View File

@@ -282,7 +282,8 @@ pub(crate) struct CrateRoot {
exportable_items: LazyArray<DefIndex>,
stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>,
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
exported_non_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
exported_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
syntax_contexts: SyntaxContextTable,
expn_data: ExpnDataTable,

View File

@@ -2312,13 +2312,32 @@ rustc_queries! {
separate_provide_extern
}
/// The list of symbols exported from the given crate.
/// The list of non-generic symbols exported from the given crate.
///
/// - All names contained in `exported_symbols(cnum)` are guaranteed to
/// correspond to a publicly visible symbol in `cnum` machine code.
/// - The `exported_symbols` sets of different crates do not intersect.
query exported_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "collecting exported symbols for crate `{}`", cnum}
/// This is separate from exported_generic_symbols to avoid having
/// to deserialize all non-generic symbols too for upstream crates
/// in the upstream_monomorphizations query.
///
/// - All names contained in `exported_non_generic_symbols(cnum)` are
/// guaranteed to correspond to a publicly visible symbol in `cnum`
/// machine code.
/// - The `exported_non_generic_symbols` and `exported_generic_symbols`
/// sets of different crates do not intersect.
query exported_non_generic_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "collecting exported non-generic symbols for crate `{}`", cnum}
cache_on_disk_if { *cnum == LOCAL_CRATE }
separate_provide_extern
}
/// The list of generic symbols exported from the given crate.
///
/// - All names contained in `exported_generic_symbols(cnum)` are
/// guaranteed to correspond to a publicly visible symbol in `cnum`
/// machine code.
/// - The `exported_non_generic_symbols` and `exported_generic_symbols`
/// sets of different crates do not intersect.
query exported_generic_symbols(cnum: CrateNum) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
desc { "collecting exported generic symbols for crate `{}`", cnum}
cache_on_disk_if { *cnum == LOCAL_CRATE }
separate_provide_extern
}

View File

@@ -85,7 +85,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
return (def_id, MiriEntryFnType::Rustc(entry_type));
}
// Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
let sym = tcx.exported_non_generic_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
if sym.symbol_name_for_local_instance(tcx).name == "miri_start" { Some(sym) } else { None }
});
if let Some(ExportedSymbol::NonGeneric(id)) = sym {
@@ -249,10 +249,10 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
// Queries overridden here affect the data stored in `rmeta` files of dependencies,
// which will be used later in non-`MIRI_BE_RUSTC` mode.
config.override_queries = Some(|_, local_providers| {
// `exported_symbols` and `reachable_non_generics` provided by rustc always returns
// `exported_non_generic_symbols` and `reachable_non_generics` provided by rustc always returns
// an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
// In addition we need to add #[used] symbols to exported_symbols for `lookup_link_section`.
local_providers.exported_symbols = |tcx, LocalCrate| {
local_providers.exported_non_generic_symbols = |tcx, LocalCrate| {
let reachable_set = tcx.with_stable_hashing_context(|hcx| {
tcx.reachable_set(()).to_sorted(&hcx, true)
});

View File

@@ -162,7 +162,7 @@ pub fn iter_exported_symbols<'tcx>(
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
// from a Rust crate.
for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
for &(symbol, _export_info) in tcx.exported_non_generic_symbols(cnum) {
if let ExportedSymbol::NonGeneric(def_id) = symbol {
f(cnum, def_id)?;
}