@@ -16,6 +16,7 @@ use rustc_hir as hir;
16
16
use rustc_hir:: def_id:: { CRATE_DEF_ID , CRATE_DEF_INDEX , LOCAL_CRATE , LocalDefId , LocalDefIdSet } ;
17
17
use rustc_hir:: definitions:: DefPathData ;
18
18
use rustc_hir_pretty:: id_to_string;
19
+ use rustc_middle:: dep_graph:: WorkProductId ;
19
20
use rustc_middle:: middle:: dependency_format:: Linkage ;
20
21
use rustc_middle:: middle:: exported_symbols:: metadata_symbol_name;
21
22
use rustc_middle:: mir:: interpret;
@@ -2307,6 +2308,8 @@ pub struct EncodedMetadata {
2307
2308
// This is an optional stub metadata containing only the crate header.
2308
2309
// The header should be very small, so we load it directly into memory.
2309
2310
stub_metadata : Option < Vec < u8 > > ,
2311
+ // The path containing the metadata, to record as work product.
2312
+ path : Option < Box < Path > > ,
2310
2313
// We need to carry MaybeTempDir to avoid deleting the temporary
2311
2314
// directory while accessing the Mmap.
2312
2315
_temp_dir : Option < MaybeTempDir > ,
@@ -2322,14 +2325,24 @@ impl EncodedMetadata {
2322
2325
let file = std:: fs:: File :: open ( & path) ?;
2323
2326
let file_metadata = file. metadata ( ) ?;
2324
2327
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
+ } ) ;
2326
2334
}
2327
2335
let full_mmap = unsafe { Some ( Mmap :: map ( file) ?) } ;
2328
2336
2329
2337
let stub =
2330
2338
if let Some ( stub_path) = stub_path { Some ( std:: fs:: read ( stub_path) ?) } else { None } ;
2331
2339
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
+ } )
2333
2346
}
2334
2347
2335
2348
#[ inline]
@@ -2341,6 +2354,11 @@ impl EncodedMetadata {
2341
2354
pub fn stub_or_full ( & self ) -> & [ u8 ] {
2342
2355
self . stub_metadata . as_deref ( ) . unwrap_or ( self . full ( ) )
2343
2356
}
2357
+
2358
+ #[ inline]
2359
+ pub fn path ( & self ) -> Option < & Path > {
2360
+ self . path . as_deref ( )
2361
+ }
2344
2362
}
2345
2363
2346
2364
impl < S : Encoder > Encodable < S > for EncodedMetadata {
@@ -2365,17 +2383,53 @@ impl<D: Decoder> Decodable<D> for EncodedMetadata {
2365
2383
None
2366
2384
} ;
2367
2385
2368
- Self { full_metadata, stub_metadata : stub, _temp_dir : None }
2386
+ Self { full_metadata, stub_metadata : stub, path : None , _temp_dir : None }
2369
2387
}
2370
2388
}
2371
2389
2390
+ #[ instrument( level = "trace" , skip( tcx) ) ]
2372
2391
pub fn encode_metadata ( tcx : TyCtxt < ' _ > , path : & Path , ref_path : Option < & Path > ) {
2373
- let _prof_timer = tcx. prof . verbose_generic_activity ( "generate_crate_metadata" ) ;
2374
-
2375
2392
// Since encoding metadata is not in a query, and nothing is cached,
2376
2393
// there's no need to do dep-graph tracking for any of it.
2377
2394
tcx. dep_graph . assert_ignored ( ) ;
2378
2395
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
+
2379
2433
if tcx. sess . threads ( ) != 1 {
2380
2434
// Prefetch some queries used by metadata encoding.
2381
2435
// 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>) {
2389
2443
) ;
2390
2444
}
2391
2445
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
+ ) ;
2408
2466
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
+ ) ;
2421
2472
}
2422
2473
2423
2474
fn with_encode_metadata_header (
0 commit comments