about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src/back
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-02-20 11:32:40 +0000
committerbors <bors@rust-lang.org>2022-02-20 11:32:40 +0000
commit3b186511f62b0ce20e72ede0e8e13f8787155f02 (patch)
tree43beb306dece88a6b76b50d7b35c5ae518687bd0 /compiler/rustc_codegen_ssa/src/back
parent6d7aa4763fe7f737d6add4261b9e050b36701089 (diff)
parent932559cc21a2f0746012645f130956b81480cd86 (diff)
downloadrust-3b186511f62b0ce20e72ede0e8e13f8787155f02.tar.gz
rust-3b186511f62b0ce20e72ede0e8e13f8787155f02.zip
Auto merge of #93816 - bjorn3:rlib_metadata_first, r=nagisa
Put crate metadata first in the rlib

This should make metadata lookup faster

Fixes https://github.com/rust-lang/rust/issues/93806
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs97
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs11
2 files changed, 68 insertions, 40 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 5a07b23f3f9..587453fd8e8 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -23,7 +23,7 @@ use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Ta
 use super::archive::{find_library, ArchiveBuilder};
 use super::command::Command;
 use super::linker::{self, Linker};
-use super::metadata::create_rmeta_file;
+use super::metadata::{create_rmeta_file, MetadataPosition};
 use super::rpath::{self, RPathConfig};
 use crate::{
     looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
@@ -267,6 +267,28 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
 
     let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
 
+    let trailing_metadata = match flavor {
+        RlibFlavor::Normal => {
+            let (metadata, metadata_position) =
+                create_rmeta_file(sess, codegen_results.metadata.raw_data());
+            let metadata = emit_metadata(sess, &metadata, tmpdir);
+            match metadata_position {
+                MetadataPosition::First => {
+                    // Most of the time metadata in rlib files is wrapped in a "dummy" object
+                    // file for the target platform so the rlib can be processed entirely by
+                    // normal linkers for the platform. Sometimes this is not possible however.
+                    // If it is possible however, placing the metadata object first improves
+                    // performance of getting metadata from rlibs.
+                    ab.add_file(&metadata);
+                    None
+                }
+                MetadataPosition::Last => Some(metadata),
+            }
+        }
+
+        RlibFlavor::StaticlibBase => None,
+    };
+
     for m in &codegen_results.modules {
         if let Some(obj) = m.object.as_ref() {
             ab.add_file(obj);
@@ -277,6 +299,16 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
         }
     }
 
+    match flavor {
+        RlibFlavor::Normal => {}
+        RlibFlavor::StaticlibBase => {
+            let obj = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref());
+            if let Some(obj) = obj {
+                ab.add_file(obj);
+            }
+        }
+    }
+
     // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
     // we may not be configured to actually include a static library if we're
     // adding it here. That's because later when we consume this rlib we'll
@@ -334,42 +366,33 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
         ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
     }
 
-    // Note that it is important that we add all of our non-object "magical
-    // files" *after* all of the object files in the archive. The reason for
-    // this is as follows:
-    //
-    // * When performing LTO, this archive will be modified to remove
-    //   objects from above. The reason for this is described below.
-    //
-    // * When the system linker looks at an archive, it will attempt to
-    //   determine the architecture of the archive in order to see whether its
-    //   linkable.
-    //
-    //   The algorithm for this detection is: iterate over the files in the
-    //   archive. Skip magical SYMDEF names. Interpret the first file as an
-    //   object file. Read architecture from the object file.
-    //
-    // * As one can probably see, if "metadata" and "foo.bc" were placed
-    //   before all of the objects, then the architecture of this archive would
-    //   not be correctly inferred once 'foo.o' is removed.
-    //
-    // Basically, all this means is that this code should not move above the
-    // code above.
-    match flavor {
-        RlibFlavor::Normal => {
-            // metadata in rlib files is wrapped in a "dummy" object file for
-            // the target platform so the rlib can be processed entirely by
-            // normal linkers for the platform.
-            let metadata = create_rmeta_file(sess, codegen_results.metadata.raw_data());
-            ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
-        }
-
-        RlibFlavor::StaticlibBase => {
-            let obj = codegen_results.allocator_module.as_ref().and_then(|m| m.object.as_ref());
-            if let Some(obj) = obj {
-                ab.add_file(obj);
-            }
-        }
+    if let Some(trailing_metadata) = trailing_metadata {
+        // Note that it is important that we add all of our non-object "magical
+        // files" *after* all of the object files in the archive. The reason for
+        // this is as follows:
+        //
+        // * When performing LTO, this archive will be modified to remove
+        //   objects from above. The reason for this is described below.
+        //
+        // * When the system linker looks at an archive, it will attempt to
+        //   determine the architecture of the archive in order to see whether its
+        //   linkable.
+        //
+        //   The algorithm for this detection is: iterate over the files in the
+        //   archive. Skip magical SYMDEF names. Interpret the first file as an
+        //   object file. Read architecture from the object file.
+        //
+        // * As one can probably see, if "metadata" and "foo.bc" were placed
+        //   before all of the objects, then the architecture of this archive would
+        //   not be correctly inferred once 'foo.o' is removed.
+        //
+        // * Most of the time metadata in rlib files is wrapped in a "dummy" object
+        //   file for the target platform so the rlib can be processed entirely by
+        //   normal linkers for the platform. Sometimes this is not possible however.
+        //
+        // Basically, all this means is that this code should not move above the
+        // code above.
+        ab.add_file(&trailing_metadata);
     }
 
     return Ok(ab);
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 39d39ad1365..c52269805c4 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -166,6 +166,11 @@ fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
     Some(file)
 }
 
+pub enum MetadataPosition {
+    First,
+    Last,
+}
+
 // For rlibs we "pack" rustc metadata into a dummy object file. When rustc
 // creates a dylib crate type it will pass `--whole-archive` (or the
 // platform equivalent) to include all object files from an rlib into the
@@ -198,7 +203,7 @@ fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
 // * ELF - All other targets are similar to Windows in that there's a
 //   `SHF_EXCLUDE` flag we can set on sections in an object file to get
 //   automatically removed from the final output.
-pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
+pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> (Vec<u8>, MetadataPosition) {
     let Some(mut file) = create_object_file(sess) else {
         // This is used to handle all "other" targets. This includes targets
         // in two categories:
@@ -216,7 +221,7 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
         // WebAssembly and for targets not supported by the `object` crate
         // yet it means that work will need to be done in the `object` crate
         // to add a case above.
-        return metadata.to_vec();
+        return (metadata.to_vec(), MetadataPosition::Last);
     };
     let section = file.add_section(
         file.segment_name(StandardSegment::Debug).to_vec(),
@@ -235,7 +240,7 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
         _ => {}
     };
     file.append_section_data(section, metadata, 1);
-    file.write().unwrap()
+    (file.write().unwrap(), MetadataPosition::First)
 }
 
 // Historical note: