Skip to content

Commit b1d14ca

Browse files
committed
Use mmap for metadata loading
This can have a significant improvement on compilation times. In addition it reduces the memory consumption. Fixes rust-lang#927
1 parent 578fcde commit b1d14ca

File tree

3 files changed

+56
-27
lines changed

3 files changed

+56
-27
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch
1616
cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
1717
target-lexicon = "0.11.0"
1818
gimli = { version = "0.23.0", default-features = false, features = ["write"]}
19-
object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "coff", "elf", "macho", "pe"] }
19+
object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
2020

2121
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
2222
indexmap = "1.0.2"
2323
libloading = { version = "0.6.0", optional = true }
2424
smallvec = "1.6.1"
25+
memmap2 = "0.2.1"
2526

2627
# Uncomment to use local checkout of cranelift
2728
#[patch."https://github.com/bytecodealliance/wasmtime/"]

src/metadata.rs

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! Reading and writing of the rustc metadata for rlibs and dylibs
22
3-
use std::convert::TryFrom;
43
use std::fs::File;
4+
use std::ops::Deref;
55
use std::path::Path;
66

77
use rustc_codegen_ssa::METADATA_FILENAME;
8-
use rustc_data_structures::owning_ref::OwningRef;
8+
use rustc_data_structures::owning_ref::{OwningRef, StableAddress};
99
use rustc_data_structures::rustc_erase_owner;
1010
use rustc_data_structures::sync::MetadataRef;
1111
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
@@ -17,38 +17,56 @@ use crate::backend::WriteMetadata;
1717

1818
pub(crate) struct CraneliftMetadataLoader;
1919

20+
struct StableMmap(memmap2::Mmap);
21+
22+
impl Deref for StableMmap {
23+
type Target = [u8];
24+
25+
fn deref(&self) -> &[u8] {
26+
&*self.0
27+
}
28+
}
29+
30+
unsafe impl StableAddress for StableMmap {}
31+
32+
fn load_metadata_with(
33+
path: &Path,
34+
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
35+
) -> Result<MetadataRef, String> {
36+
let file = File::open(path).map_err(|e| format!("{:?}", e))?;
37+
let data = unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file) }
38+
.map_err(|e| format!("{:?}", e))?;
39+
let metadata = OwningRef::new(StableMmap(data)).try_map(f)?;
40+
return Ok(rustc_erase_owner!(metadata.map_owner_box()));
41+
}
42+
2043
impl MetadataLoader for CraneliftMetadataLoader {
2144
fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
22-
let mut archive = ar::Archive::new(File::open(path).map_err(|e| format!("{:?}", e))?);
23-
// Iterate over all entries in the archive:
24-
while let Some(entry_result) = archive.next_entry() {
25-
let mut entry = entry_result.map_err(|e| format!("{:?}", e))?;
26-
if entry.header().identifier() == METADATA_FILENAME.as_bytes() {
27-
let mut buf = Vec::with_capacity(
28-
usize::try_from(entry.header().size())
29-
.expect("Rlib metadata file too big to load into memory."),
30-
);
31-
::std::io::copy(&mut entry, &mut buf).map_err(|e| format!("{:?}", e))?;
32-
let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
33-
return Ok(rustc_erase_owner!(buf.map_owner_box()));
45+
load_metadata_with(path, |data| {
46+
let archive = object::read::archive::ArchiveFile::parse(&*data)
47+
.map_err(|e| format!("{:?}", e))?;
48+
49+
for entry_result in archive.members() {
50+
let entry = entry_result.map_err(|e| format!("{:?}", e))?;
51+
if entry.name() == METADATA_FILENAME.as_bytes() {
52+
return Ok(entry.data());
53+
}
3454
}
35-
}
3655

37-
Err("couldn't find metadata entry".to_string())
56+
Err("couldn't find metadata entry".to_string())
57+
})
3858
}
3959

4060
fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
4161
use object::{Object, ObjectSection};
42-
let file = std::fs::read(path).map_err(|e| format!("read:{:?}", e))?;
43-
let file = object::File::parse(&file).map_err(|e| format!("parse: {:?}", e))?;
44-
let buf = file
45-
.section_by_name(".rustc")
46-
.ok_or("no .rustc section")?
47-
.data()
48-
.map_err(|e| format!("failed to read .rustc section: {:?}", e))?
49-
.to_owned();
50-
let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
51-
Ok(rustc_erase_owner!(buf.map_owner_box()))
62+
63+
load_metadata_with(path, |data| {
64+
let file = object::File::parse(&data).map_err(|e| format!("parse: {:?}", e))?;
65+
file.section_by_name(".rustc")
66+
.ok_or("no .rustc section")?
67+
.data()
68+
.map_err(|e| format!("failed to read .rustc section: {:?}", e))
69+
})
5270
}
5371
}
5472

0 commit comments

Comments
 (0)