@@ -701,6 +701,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
701701 triple: tcx. sess. opts. target_triple. clone( ) ,
702702 hash: tcx. crate_hash( LOCAL_CRATE ) ,
703703 is_proc_macro_crate: proc_macro_data. is_some( ) ,
704+ is_stub: false ,
704705 } ,
705706 extra_filename: tcx. sess. opts. cg. extra_filename. clone( ) ,
706707 stable_crate_id: tcx. def_path_hash( LOCAL_CRATE . as_def_id( ) ) . stable_crate_id( ) ,
@@ -2231,54 +2232,75 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
22312232// generated regardless of trailing bytes that end up in it.
22322233
22332234pub struct EncodedMetadata {
2234- // The declaration order matters because `mmap` should be dropped before `_temp_dir`.
2235- mmap : Option < Mmap > ,
2235+ // The declaration order matters because `full_metadata` should be dropped
2236+ // before `_temp_dir`.
2237+ full_metadata : Option < Mmap > ,
2238+ // This is an optional stub metadata containing only the crate header.
2239+ // The header should be very small, so we load it directly into memory.
2240+ stub_metadata : Option < Vec < u8 > > ,
22362241 // We need to carry MaybeTempDir to avoid deleting the temporary
22372242 // directory while accessing the Mmap.
22382243 _temp_dir : Option < MaybeTempDir > ,
22392244}
22402245
22412246impl EncodedMetadata {
22422247 #[ inline]
2243- pub fn from_path ( path : PathBuf , temp_dir : Option < MaybeTempDir > ) -> std:: io:: Result < Self > {
2248+ pub fn from_path (
2249+ path : PathBuf ,
2250+ stub_path : Option < PathBuf > ,
2251+ temp_dir : Option < MaybeTempDir > ,
2252+ ) -> std:: io:: Result < Self > {
22442253 let file = std:: fs:: File :: open ( & path) ?;
22452254 let file_metadata = file. metadata ( ) ?;
22462255 if file_metadata. len ( ) == 0 {
2247- return Ok ( Self { mmap : None , _temp_dir : None } ) ;
2256+ return Ok ( Self { full_metadata : None , stub_metadata : None , _temp_dir : None } ) ;
22482257 }
2249- let mmap = unsafe { Some ( Mmap :: map ( file) ?) } ;
2250- Ok ( Self { mmap, _temp_dir : temp_dir } )
2258+ let full_mmap = unsafe { Some ( Mmap :: map ( file) ?) } ;
2259+
2260+ let stub =
2261+ if let Some ( stub_path) = stub_path { Some ( std:: fs:: read ( stub_path) ?) } else { None } ;
2262+
2263+ Ok ( Self { full_metadata : full_mmap, stub_metadata : stub, _temp_dir : temp_dir } )
2264+ }
2265+
2266+ #[ inline]
2267+ pub fn full ( & self ) -> & [ u8 ] {
2268+ & self . full_metadata . as_deref ( ) . unwrap_or_default ( )
22512269 }
22522270
22532271 #[ inline]
2254- pub fn raw_data ( & self ) -> & [ u8 ] {
2255- self . mmap . as_deref ( ) . unwrap_or_default ( )
2272+ pub fn stub_or_full ( & self ) -> & [ u8 ] {
2273+ self . stub_metadata . as_deref ( ) . unwrap_or ( self . full ( ) )
22562274 }
22572275}
22582276
22592277impl < S : Encoder > Encodable < S > for EncodedMetadata {
22602278 fn encode ( & self , s : & mut S ) {
2261- let slice = self . raw_data ( ) ;
2279+ self . stub_metadata . encode ( s) ;
2280+
2281+ let slice = self . full ( ) ;
22622282 slice. encode ( s)
22632283 }
22642284}
22652285
22662286impl < D : Decoder > Decodable < D > for EncodedMetadata {
22672287 fn decode ( d : & mut D ) -> Self {
2288+ let stub = <Option < Vec < u8 > > >:: decode ( d) ;
2289+
22682290 let len = d. read_usize ( ) ;
2269- let mmap = if len > 0 {
2291+ let full_metadata = if len > 0 {
22702292 let mut mmap = MmapMut :: map_anon ( len) . unwrap ( ) ;
22712293 mmap. copy_from_slice ( d. read_raw_bytes ( len) ) ;
22722294 Some ( mmap. make_read_only ( ) . unwrap ( ) )
22732295 } else {
22742296 None
22752297 } ;
22762298
2277- Self { mmap , _temp_dir : None }
2299+ Self { full_metadata , stub_metadata : stub , _temp_dir : None }
22782300 }
22792301}
22802302
2281- pub fn encode_metadata ( tcx : TyCtxt < ' _ > , path : & Path ) {
2303+ pub fn encode_metadata ( tcx : TyCtxt < ' _ > , path : & Path , ref_path : Option < & Path > ) {
22822304 let _prof_timer = tcx. prof . verbose_generic_activity ( "generate_crate_metadata" ) ;
22832305
22842306 // Since encoding metadata is not in a query, and nothing is cached,
@@ -2292,6 +2314,42 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
22922314 join ( || prefetch_mir ( tcx) , || tcx. exported_symbols ( LOCAL_CRATE ) ) ;
22932315 }
22942316
2317+ with_encode_metadata_header ( tcx, path, |ecx| {
2318+ // Encode all the entries and extra information in the crate,
2319+ // culminating in the `CrateRoot` which points to all of it.
2320+ let root = ecx. encode_crate_root ( ) ;
2321+
2322+ // Flush buffer to ensure backing file has the correct size.
2323+ ecx. opaque . flush ( ) ;
2324+ // Record metadata size for self-profiling
2325+ tcx. prof . artifact_size (
2326+ "crate_metadata" ,
2327+ "crate_metadata" ,
2328+ ecx. opaque . file ( ) . metadata ( ) . unwrap ( ) . len ( ) ,
2329+ ) ;
2330+
2331+ root. position . get ( )
2332+ } ) ;
2333+
2334+ if let Some ( ref_path) = ref_path {
2335+ with_encode_metadata_header ( tcx, ref_path, |ecx| {
2336+ let header: LazyValue < CrateHeader > = ecx. lazy ( CrateHeader {
2337+ name : tcx. crate_name ( LOCAL_CRATE ) ,
2338+ triple : tcx. sess . opts . target_triple . clone ( ) ,
2339+ hash : tcx. crate_hash ( LOCAL_CRATE ) ,
2340+ is_proc_macro_crate : false ,
2341+ is_stub : true ,
2342+ } ) ;
2343+ header. position . get ( )
2344+ } ) ;
2345+ }
2346+ }
2347+
2348+ fn with_encode_metadata_header (
2349+ tcx : TyCtxt < ' _ > ,
2350+ path : & Path ,
2351+ f : impl FnOnce ( & mut EncodeContext < ' _ , ' _ > ) -> usize ,
2352+ ) {
22952353 let mut encoder = opaque:: FileEncoder :: new ( path)
22962354 . unwrap_or_else ( |err| tcx. dcx ( ) . emit_fatal ( FailCreateFileEncoder { err } ) ) ;
22972355 encoder. emit_raw_bytes ( METADATA_HEADER ) ;
@@ -2326,9 +2384,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
23262384 // Encode the rustc version string in a predictable location.
23272385 rustc_version ( tcx. sess . cfg_version ) . encode ( & mut ecx) ;
23282386
2329- // Encode all the entries and extra information in the crate,
2330- // culminating in the `CrateRoot` which points to all of it.
2331- let root = ecx. encode_crate_root ( ) ;
2387+ let root_position = f ( & mut ecx) ;
23322388
23332389 // Make sure we report any errors from writing to the file.
23342390 // If we forget this, compilation can succeed with an incomplete rmeta file,
@@ -2338,12 +2394,9 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
23382394 }
23392395
23402396 let file = ecx. opaque . file ( ) ;
2341- if let Err ( err) = encode_root_position ( file, root . position . get ( ) ) {
2397+ if let Err ( err) = encode_root_position ( file, root_position ) {
23422398 tcx. dcx ( ) . emit_fatal ( FailWriteFile { path : ecx. opaque . path ( ) , err } ) ;
23432399 }
2344-
2345- // Record metadata size for self-profiling
2346- tcx. prof . artifact_size ( "crate_metadata" , "crate_metadata" , file. metadata ( ) . unwrap ( ) . len ( ) ) ;
23472400}
23482401
23492402fn encode_root_position ( mut file : & File , pos : usize ) -> Result < ( ) , std:: io:: Error > {
0 commit comments