@@ -16,6 +16,7 @@ use rustc_hir as hir;
1616use rustc_hir:: def_id:: { CRATE_DEF_ID , CRATE_DEF_INDEX , LOCAL_CRATE , LocalDefId , LocalDefIdSet } ;
1717use rustc_hir:: definitions:: DefPathData ;
1818use rustc_hir_pretty:: id_to_string;
19+ use rustc_middle:: dep_graph:: WorkProductId ;
1920use rustc_middle:: middle:: dependency_format:: Linkage ;
2021use rustc_middle:: middle:: exported_symbols:: metadata_symbol_name;
2122use rustc_middle:: mir:: interpret;
@@ -2307,6 +2308,8 @@ pub struct EncodedMetadata {
23072308 // This is an optional stub metadata containing only the crate header.
23082309 // The header should be very small, so we load it directly into memory.
23092310 stub_metadata : Option < Vec < u8 > > ,
2311+ // The path containing the metadata, to record as work product.
2312+ path : Option < Box < Path > > ,
23102313 // We need to carry MaybeTempDir to avoid deleting the temporary
23112314 // directory while accessing the Mmap.
23122315 _temp_dir : Option < MaybeTempDir > ,
@@ -2322,14 +2325,24 @@ impl EncodedMetadata {
23222325 let file = std:: fs:: File :: open ( & path) ?;
23232326 let file_metadata = file. metadata ( ) ?;
23242327 if file_metadata. len ( ) == 0 {
2325- return Ok ( Self { full_metadata : None , stub_metadata : None , _temp_dir : None } ) ;
2328+ return Ok ( Self {
2329+ full_metadata : None ,
2330+ stub_metadata : None ,
2331+ path : None ,
2332+ _temp_dir : None ,
2333+ } ) ;
23262334 }
23272335 let full_mmap = unsafe { Some ( Mmap :: map ( file) ?) } ;
23282336
23292337 let stub =
23302338 if let Some ( stub_path) = stub_path { Some ( std:: fs:: read ( stub_path) ?) } else { None } ;
23312339
2332- Ok ( Self { full_metadata : full_mmap, stub_metadata : stub, _temp_dir : temp_dir } )
2340+ Ok ( Self {
2341+ full_metadata : full_mmap,
2342+ stub_metadata : stub,
2343+ path : Some ( path. into ( ) ) ,
2344+ _temp_dir : temp_dir,
2345+ } )
23332346 }
23342347
23352348 #[ inline]
@@ -2341,6 +2354,11 @@ impl EncodedMetadata {
23412354 pub fn stub_or_full ( & self ) -> & [ u8 ] {
23422355 self . stub_metadata . as_deref ( ) . unwrap_or ( self . full ( ) )
23432356 }
2357+
2358+ #[ inline]
2359+ pub fn path ( & self ) -> Option < & Path > {
2360+ self . path . as_deref ( )
2361+ }
23442362}
23452363
23462364impl < S : Encoder > Encodable < S > for EncodedMetadata {
@@ -2365,17 +2383,53 @@ impl<D: Decoder> Decodable<D> for EncodedMetadata {
23652383 None
23662384 } ;
23672385
2368- Self { full_metadata, stub_metadata : stub, _temp_dir : None }
2386+ Self { full_metadata, stub_metadata : stub, path : None , _temp_dir : None }
23692387 }
23702388}
23712389
2390+ #[ instrument( level = "trace" , skip( tcx) ) ]
23722391pub fn encode_metadata ( tcx : TyCtxt < ' _ > , path : & Path , ref_path : Option < & Path > ) {
2373- let _prof_timer = tcx. prof . verbose_generic_activity ( "generate_crate_metadata" ) ;
2374-
23752392 // Since encoding metadata is not in a query, and nothing is cached,
23762393 // there's no need to do dep-graph tracking for any of it.
23772394 tcx. dep_graph . assert_ignored ( ) ;
23782395
2396+ // Generate the metadata stub manually, as that is a small file compared to full metadata.
2397+ if let Some ( ref_path) = ref_path {
2398+ let _prof_timer = tcx. prof . verbose_generic_activity ( "generate_crate_metadata_stub" ) ;
2399+
2400+ with_encode_metadata_header ( tcx, ref_path, |ecx| {
2401+ let header: LazyValue < CrateHeader > = ecx. lazy ( CrateHeader {
2402+ name : tcx. crate_name ( LOCAL_CRATE ) ,
2403+ triple : tcx. sess . opts . target_triple . clone ( ) ,
2404+ hash : tcx. crate_hash ( LOCAL_CRATE ) ,
2405+ is_proc_macro_crate : false ,
2406+ is_stub : true ,
2407+ } ) ;
2408+ header. position . get ( )
2409+ } )
2410+ }
2411+
2412+ let _prof_timer = tcx. prof . verbose_generic_activity ( "generate_crate_metadata" ) ;
2413+
2414+ let dep_node = tcx. metadata_dep_node ( ) ;
2415+
2416+ // If the metadata dep-node is green, try to reuse the saved work product.
2417+ if tcx. dep_graph . is_fully_enabled ( )
2418+ && let work_product_id = WorkProductId :: from_cgu_name ( "metadata" )
2419+ && let Some ( work_product) = tcx. dep_graph . previous_work_product ( & work_product_id)
2420+ && tcx. try_mark_green ( & dep_node)
2421+ {
2422+ let saved_path = & work_product. saved_files [ "rmeta" ] ;
2423+ let incr_comp_session_dir = tcx. sess . incr_comp_session_dir_opt ( ) . unwrap ( ) ;
2424+ let source_file = rustc_incremental:: in_incr_comp_dir ( & incr_comp_session_dir, saved_path) ;
2425+ debug ! ( "copying preexisting metadata from {source_file:?} to {path:?}" ) ;
2426+ match rustc_fs_util:: link_or_copy ( & source_file, path) {
2427+ Ok ( _) => { }
2428+ Err ( err) => tcx. dcx ( ) . emit_fatal ( FailCreateFileEncoder { err } ) ,
2429+ } ;
2430+ return ;
2431+ } ;
2432+
23792433 if tcx. sess . threads ( ) != 1 {
23802434 // Prefetch some queries used by metadata encoding.
23812435 // This is not necessary for correctness, but is only done for performance reasons.
@@ -2389,35 +2443,32 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path, ref_path: Option<&Path>) {
23892443 ) ;
23902444 }
23912445
2392- with_encode_metadata_header ( tcx, path, |ecx| {
2393- // Encode all the entries and extra information in the crate,
2394- // culminating in the `CrateRoot` which points to all of it.
2395- let root = ecx. encode_crate_root ( ) ;
2396-
2397- // Flush buffer to ensure backing file has the correct size.
2398- ecx. opaque . flush ( ) ;
2399- // Record metadata size for self-profiling
2400- tcx. prof . artifact_size (
2401- "crate_metadata" ,
2402- "crate_metadata" ,
2403- ecx. opaque . file ( ) . metadata ( ) . unwrap ( ) . len ( ) ,
2404- ) ;
2405-
2406- root. position . get ( )
2407- } ) ;
2446+ // Perform metadata encoding inside a task, so the dep-graph can check if any encoded
2447+ // information changes, and maybe reuse the work product.
2448+ tcx. dep_graph . with_task (
2449+ dep_node,
2450+ tcx,
2451+ path,
2452+ |tcx, path| {
2453+ with_encode_metadata_header ( tcx, path, |ecx| {
2454+ // Encode all the entries and extra information in the crate,
2455+ // culminating in the `CrateRoot` which points to all of it.
2456+ let root = ecx. encode_crate_root ( ) ;
2457+
2458+ // Flush buffer to ensure backing file has the correct size.
2459+ ecx. opaque . flush ( ) ;
2460+ // Record metadata size for self-profiling
2461+ tcx. prof . artifact_size (
2462+ "crate_metadata" ,
2463+ "crate_metadata" ,
2464+ ecx. opaque . file ( ) . metadata ( ) . unwrap ( ) . len ( ) ,
2465+ ) ;
24082466
2409- if let Some ( ref_path) = ref_path {
2410- with_encode_metadata_header ( tcx, ref_path, |ecx| {
2411- let header: LazyValue < CrateHeader > = ecx. lazy ( CrateHeader {
2412- name : tcx. crate_name ( LOCAL_CRATE ) ,
2413- triple : tcx. sess . opts . target_triple . clone ( ) ,
2414- hash : tcx. crate_hash ( LOCAL_CRATE ) ,
2415- is_proc_macro_crate : false ,
2416- is_stub : true ,
2417- } ) ;
2418- header. position . get ( )
2419- } ) ;
2420- }
2467+ root. position . get ( )
2468+ } )
2469+ } ,
2470+ None ,
2471+ ) ;
24212472}
24222473
24232474fn with_encode_metadata_header (
0 commit comments