Skip to content

Commit 1fb7884

Browse files
committed
Adds RmetaLinkCache a per-link cache that uses path as the key of decoded lib.rmeta-link archive members, and routes add_archive read through it so each rlib link metadata is decoded at most once per link. This is a demand that originated from the discussion in #156735 and we split it out as its own PR. It gives that PR a decode once path tp read instead of reparsing each rlib per crate once native_lib_filenames moves to a link time read.
1 parent f7da3c0 commit 1fb7884

3 files changed

Lines changed: 85 additions & 43 deletions

File tree

compiler/rustc_codegen_ssa/src/back/archive.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ fn find_binutils_dlltool(sess: &Session) -> OsString {
311311
}
312312

313313
pub enum AddArchiveKind<'a> {
314-
Rlib(/*skip*/ &'a dyn Fn(&str, ArchiveEntryKind) -> bool),
314+
Rlib { skip: &'a dyn Fn(&str, ArchiveEntryKind) -> bool, cache: &'a rmeta_link::RmetaLinkCache },
315315
Other,
316316
}
317317

@@ -482,7 +482,9 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
482482
let archive = ArchiveFile::parse(&*archive_map)
483483
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
484484
let metadata_link = match ar_kind {
485-
AddArchiveKind::Rlib(..) => rmeta_link::read(&archive, &archive_map, &archive_path),
485+
AddArchiveKind::Rlib { cache, .. } => cache.get_or_insert_with(&archive_path, || {
486+
rmeta_link::read(&archive, &archive_map, &archive_path)
487+
}),
486488
AddArchiveKind::Other => None,
487489
};
488490
let archive_index = self.src_archives.len();
@@ -513,7 +515,7 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
513515
ArchiveEntryKind::Other
514516
};
515517
let drop = match ar_kind {
516-
AddArchiveKind::Rlib(skip) => skip(&file_name, kind),
518+
AddArchiveKind::Rlib { skip, .. } => skip(&file_name, kind),
517519
AddArchiveKind::Other => false,
518520
};
519521
if !drop {

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub fn link_binary(
8686
let _timer = sess.timer("link_binary");
8787
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
8888
let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
89+
let rmeta_link_cache = rmeta_link::RmetaLinkCache::default();
8990
for &crate_type in &crate_info.crate_types {
9091
// Ignore executable crates if we have -Z no-codegen, as they will error.
9192
if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen())
@@ -139,6 +140,7 @@ pub fn link_binary(
139140
link_staticlib(
140141
sess,
141142
archive_builder_builder,
143+
&rmeta_link_cache,
142144
&compiled_modules,
143145
&crate_info,
144146
&metadata,
@@ -150,6 +152,7 @@ pub fn link_binary(
150152
link_natively(
151153
sess,
152154
archive_builder_builder,
155+
&rmeta_link_cache,
153156
crate_type,
154157
&out_filename,
155158
&compiled_modules,
@@ -502,6 +505,7 @@ fn link_rlib<'a>(
502505
fn link_staticlib(
503506
sess: &Session,
504507
archive_builder_builder: &dyn ArchiveBuilderBuilder,
508+
rmeta_link_cache: &rmeta_link::RmetaLinkCache,
505509
compiled_modules: &CompiledModules,
506510
crate_info: &CrateInfo,
507511
metadata: &EncodedMetadata,
@@ -531,24 +535,27 @@ fn link_staticlib(
531535
let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect();
532536
ab.add_archive(
533537
path,
534-
AddArchiveKind::Rlib(&|fname: &str, entry_kind| {
535-
// Ignore metadata and rmeta-link files.
536-
if fname == METADATA_FILENAME || fname == rmeta_link::FILENAME {
537-
return true;
538-
}
538+
AddArchiveKind::Rlib {
539+
skip: &|fname: &str, entry_kind| {
540+
// Ignore metadata and rmeta-link files.
541+
if fname == METADATA_FILENAME || fname == rmeta_link::FILENAME {
542+
return true;
543+
}
539544

540-
// Don't include Rust objects if LTO is enabled.
541-
if lto && entry_kind == ArchiveEntryKind::RustObj {
542-
return true;
543-
}
545+
// Don't include Rust objects if LTO is enabled.
546+
if lto && entry_kind == ArchiveEntryKind::RustObj {
547+
return true;
548+
}
544549

545-
// Skip objects for bundled libs.
546-
if bundled_libs.contains(&Symbol::intern(fname)) {
547-
return true;
548-
}
550+
// Skip objects for bundled libs.
551+
if bundled_libs.contains(&Symbol::intern(fname)) {
552+
return true;
553+
}
549554

550-
false
551-
}),
555+
false
556+
},
557+
cache: rmeta_link_cache,
558+
},
552559
)
553560
.unwrap();
554561

@@ -939,6 +946,7 @@ fn report_linker_output(
939946
fn link_natively(
940947
sess: &Session,
941948
archive_builder_builder: &dyn ArchiveBuilderBuilder,
949+
rmeta_link_cache: &rmeta_link::RmetaLinkCache,
942950
crate_type: CrateType,
943951
out_filename: &Path,
944952
compiled_modules: &CompiledModules,
@@ -965,6 +973,7 @@ fn link_natively(
965973
flavor,
966974
sess,
967975
archive_builder_builder,
976+
rmeta_link_cache,
968977
crate_type,
969978
tmpdir,
970979
temp_filename,
@@ -2491,6 +2500,7 @@ fn linker_with_args(
24912500
flavor: LinkerFlavor,
24922501
sess: &Session,
24932502
archive_builder_builder: &dyn ArchiveBuilderBuilder,
2503+
rmeta_link_cache: &rmeta_link::RmetaLinkCache,
24942504
crate_type: CrateType,
24952505
tmpdir: &Path,
24962506
out_filename: &Path,
@@ -2619,6 +2629,7 @@ fn linker_with_args(
26192629
cmd,
26202630
sess,
26212631
archive_builder_builder,
2632+
rmeta_link_cache,
26222633
crate_info,
26232634
crate_type,
26242635
tmpdir,
@@ -3055,6 +3066,7 @@ fn add_upstream_rust_crates(
30553066
cmd: &mut dyn Linker,
30563067
sess: &Session,
30573068
archive_builder_builder: &dyn ArchiveBuilderBuilder,
3069+
rmeta_link_cache: &rmeta_link::RmetaLinkCache,
30583070
crate_info: &CrateInfo,
30593071
crate_type: CrateType,
30603072
tmpdir: &Path,
@@ -3107,6 +3119,7 @@ fn add_upstream_rust_crates(
31073119
cmd,
31083120
sess,
31093121
archive_builder_builder,
3122+
rmeta_link_cache,
31103123
crate_info,
31113124
tmpdir,
31123125
cnum,
@@ -3238,6 +3251,7 @@ fn add_static_crate(
32383251
cmd: &mut dyn Linker,
32393252
sess: &Session,
32403253
archive_builder_builder: &dyn ArchiveBuilderBuilder,
3254+
rmeta_link_cache: &rmeta_link::RmetaLinkCache,
32413255
crate_info: &CrateInfo,
32423256
tmpdir: &Path,
32433257
cnum: CrateNum,
@@ -3268,33 +3282,36 @@ fn add_static_crate(
32683282
let mut archive = archive_builder_builder.new_archive_builder(sess);
32693283
if let Err(error) = archive.add_archive(
32703284
cratepath,
3271-
AddArchiveKind::Rlib(&|f, entry_kind| {
3272-
if f == METADATA_FILENAME || f == rmeta_link::FILENAME {
3273-
return true;
3274-
}
3285+
AddArchiveKind::Rlib {
3286+
skip: &|f, entry_kind| {
3287+
if f == METADATA_FILENAME || f == rmeta_link::FILENAME {
3288+
return true;
3289+
}
32753290

3276-
// If we're performing LTO and this is a rust-generated object
3277-
// file, then we don't need the object file as it's part of the
3278-
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
3279-
// though, so we let that object file slide.
3280-
if upstream_rust_objects_already_included
3281-
&& entry_kind == ArchiveEntryKind::RustObj
3282-
&& is_builtins
3283-
{
3284-
return true;
3285-
}
3291+
// If we're performing LTO and this is a rust-generated object
3292+
// file, then we don't need the object file as it's part of the
3293+
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
3294+
// though, so we let that object file slide.
3295+
if upstream_rust_objects_already_included
3296+
&& entry_kind == ArchiveEntryKind::RustObj
3297+
&& is_builtins
3298+
{
3299+
return true;
3300+
}
32863301

3287-
// We skip native libraries because:
3288-
// 1. This native libraries won't be used from the generated rlib,
3289-
// so we can throw them away to avoid the copying work.
3290-
// 2. We can't allow it to be a single remaining entry in archive
3291-
// as some linkers may complain on that.
3292-
if bundled_lib_file_names.contains(&Symbol::intern(f)) {
3293-
return true;
3294-
}
3302+
// We skip native libraries because:
3303+
// 1. This native libraries won't be used from the generated rlib,
3304+
// so we can throw them away to avoid the copying work.
3305+
// 2. We can't allow it to be a single remaining entry in archive
3306+
// as some linkers may complain on that.
3307+
if bundled_lib_file_names.contains(&Symbol::intern(f)) {
3308+
return true;
3309+
}
32953310

3296-
false
3297-
}),
3311+
false
3312+
},
3313+
cache: rmeta_link_cache,
3314+
},
32983315
) {
32993316
sess.dcx()
33003317
.emit_fatal(errors::RlibArchiveBuildFailure { path: cratepath.clone(), error });

compiler/rustc_codegen_ssa/src/back/rmeta_link.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
//! and potentially other data collected and used when building or linking a rlib.
33
//! See <https://github.com/rust-lang/rust/issues/138243>.
44
5-
use std::path::Path;
5+
use std::cell::RefCell;
6+
use std::path::{Path, PathBuf};
7+
use std::rc::Rc;
68

79
use object::read::archive::ArchiveFile;
10+
use rustc_data_structures::fx::FxHashMap;
811
use rustc_serialize::opaque::mem_encoder::MemEncoder;
912
use rustc_serialize::opaque::{MAGIC_END_BYTES, MemDecoder};
1013
use rustc_serialize::{Decodable, Encodable};
@@ -54,3 +57,23 @@ pub fn read_from_data(archive_data: &[u8], rlib_path: &Path) -> Option<RmetaLink
5457
let archive = ArchiveFile::parse(archive_data).ok()?;
5558
read(&archive, archive_data, rlib_path)
5659
}
60+
61+
#[derive(Default)]
62+
pub struct RmetaLinkCache {
63+
cache: RefCell<FxHashMap<PathBuf, Option<Rc<RmetaLink>>>>,
64+
}
65+
66+
impl RmetaLinkCache {
67+
pub fn get_or_insert_with(
68+
&self,
69+
rlib_path: &Path,
70+
load: impl FnOnce() -> Option<RmetaLink>,
71+
) -> Option<Rc<RmetaLink>> {
72+
if let Some(cached) = self.cache.borrow().get(rlib_path) {
73+
return cached.clone();
74+
}
75+
let loaded = load().map(Rc::new);
76+
self.cache.borrow_mut().insert(rlib_path.to_path_buf(), loaded.clone());
77+
loaded
78+
}
79+
}

0 commit comments

Comments
 (0)