|
10 | 10 |
|
11 | 11 | //! Finds crate binaries and loads their metadata |
12 | 12 |
|
13 | | -use back::archive::{Archive, METADATA_FILENAME}; |
| 13 | +use back::archive::{ArchiveRO, METADATA_FILENAME}; |
14 | 14 | use driver::session::Session; |
15 | 15 | use lib::llvm::{False, llvm, ObjectFile, mk_section_iter}; |
16 | | -use metadata::cstore::{MetadataBlob, MetadataVec}; |
| 16 | +use metadata::cstore::{MetadataBlob, MetadataVec, MetadataArchive}; |
17 | 17 | use metadata::decoder; |
18 | 18 | use metadata::encoder; |
19 | 19 | use metadata::filesearch::{FileMatches, FileDoesntMatch}; |
@@ -61,6 +61,12 @@ pub struct Library { |
61 | 61 | metadata: MetadataBlob, |
62 | 62 | } |
63 | 63 |
|
| 64 | +pub struct ArchiveMetadata { |
| 65 | + priv archive: ArchiveRO, |
| 66 | + // See comments in ArchiveMetadata::new for why this is static |
| 67 | + priv data: &'static [u8], |
| 68 | +} |
| 69 | + |
64 | 70 | impl Context { |
65 | 71 | pub fn load_library_crate(&self) -> Library { |
66 | 72 | match self.find_library_crate() { |
@@ -102,7 +108,7 @@ impl Context { |
102 | 108 | if candidate && existing { |
103 | 109 | FileMatches |
104 | 110 | } else if candidate { |
105 | | - match get_metadata_section(self.sess, self.os, path) { |
| 111 | + match get_metadata_section(self.os, path) { |
106 | 112 | Some(cvec) => |
107 | 113 | if crate_matches(cvec.as_slice(), self.name, |
108 | 114 | self.version, self.hash) { |
@@ -248,11 +254,60 @@ fn crate_matches(crate_data: &[u8], |
248 | 254 | } |
249 | 255 | } |
250 | 256 |
|
251 | | -fn get_metadata_section(sess: Session, os: Os, |
252 | | - filename: &Path) -> Option<MetadataBlob> { |
| 257 | +impl ArchiveMetadata { |
| 258 | + fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> { |
| 259 | + let data: &'static [u8] = { |
| 260 | + let data = match ar.read(METADATA_FILENAME) { |
| 261 | + Some(data) => data, |
| 262 | + None => { |
| 263 | + debug!("didn't find '{}' in the archive", METADATA_FILENAME); |
| 264 | + return None; |
| 265 | + } |
| 266 | + }; |
| 267 | + // This data is actually a pointer inside of the archive itself, but |
| 268 | + // we essentially want to cache it because the lookup inside the |
| 269 | + // archive is a fairly expensive operation (and it's queried for |
| 270 | + // *very* frequently). For this reason, we transmute it to the |
| 271 | + // static lifetime to put into the struct. Note that the buffer is |
| 272 | + // never actually handed out with a static lifetime, but rather the |
| 273 | + // buffer is loaned with the lifetime of this containing object. |
| 274 | + // Hence, we're guaranteed that the buffer will never be used after |
| 275 | + // this object is dead, so this is a safe operation to transmute and |
| 276 | + // store the data as a static buffer. |
| 277 | + unsafe { cast::transmute(data) } |
| 278 | + }; |
| 279 | + Some(ArchiveMetadata { |
| 280 | + archive: ar, |
| 281 | + data: data, |
| 282 | + }) |
| 283 | + } |
| 284 | + |
| 285 | + pub fn as_slice<'a>(&'a self) -> &'a [u8] { self.data } |
| 286 | +} |
| 287 | + |
| 288 | +// Just a small wrapper to time how long reading metadata takes. |
| 289 | +fn get_metadata_section(os: Os, filename: &Path) -> Option<MetadataBlob> { |
| 290 | + use extra::time; |
| 291 | + let start = time::precise_time_ns(); |
| 292 | + let ret = get_metadata_section_imp(os, filename); |
| 293 | + info!("reading {} => {}ms", filename.filename_display(), |
| 294 | + (time::precise_time_ns() - start) / 1000000); |
| 295 | + return ret; |
| 296 | +} |
| 297 | + |
| 298 | +fn get_metadata_section_imp(os: Os, filename: &Path) -> Option<MetadataBlob> { |
253 | 299 | if filename.filename_str().unwrap().ends_with(".rlib") { |
254 | | - let archive = Archive::open(sess, filename.clone()); |
255 | | - return Some(MetadataVec(archive.read(METADATA_FILENAME))); |
| 300 | + // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap |
| 301 | + // internally to read the file. We also avoid even using a memcpy by |
| 302 | + // just keeping the archive along while the metadata is in use. |
| 303 | + let archive = match ArchiveRO::open(filename) { |
| 304 | + Some(ar) => ar, |
| 305 | + None => { |
| 306 | + debug!("llvm didn't like `{}`", filename.display()); |
| 307 | + return None; |
| 308 | + } |
| 309 | + }; |
| 310 | + return ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)); |
256 | 311 | } |
257 | 312 | unsafe { |
258 | 313 | let mb = filename.with_c_str(|buf| { |
@@ -322,13 +377,13 @@ pub fn read_meta_section_name(os: Os) -> &'static str { |
322 | 377 | } |
323 | 378 |
|
324 | 379 | // A diagnostic function for dumping crate metadata to an output stream |
325 | | -pub fn list_file_metadata(sess: Session, |
326 | | - intr: @ident_interner, |
| 380 | +pub fn list_file_metadata(intr: @ident_interner, |
327 | 381 | os: Os, |
328 | 382 | path: &Path, |
329 | 383 | out: @mut io::Writer) { |
330 | | - match get_metadata_section(sess, os, path) { |
331 | | - option::Some(bytes) => decoder::list_crate_metadata(intr, bytes.as_slice(), |
| 384 | + match get_metadata_section(os, path) { |
| 385 | + option::Some(bytes) => decoder::list_crate_metadata(intr, |
| 386 | + bytes.as_slice(), |
332 | 387 | out), |
333 | 388 | option::None => { |
334 | 389 | write!(out, "could not find metadata in {}.\n", path.display()) |
|
0 commit comments