1use std::fs;
23use rustc_data_structures::sync::par_join;
4use rustc_middle::dep_graph::{DepGraph, WorkProductMap};
5use rustc_middle::query::on_disk_cache;
6use rustc_middle::ty::TyCtxt;
7use rustc_serialize::Encodableas RustcEncodable;
8use rustc_serialize::opaque::FileEncoder;
9use rustc_session::{IncrCompSession, Session};
10use tracing::debug;
1112use super::data::*;
13use super::fs::*;
14use super::{clean, file_format, work_product};
15use crate::assert_dep_graph::assert_dep_graph;
16use crate::diagnostics;
1718/// Saves and writes the [`DepGraph`] to the file system.
19///
20/// This function saves both the dep-graph and the query result cache,
21/// and drops the result cache.
22///
23/// This function should only run after all queries have completed.
24/// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
25pub(crate) fn save_dep_graph(tcx: TyCtxt<'_>) {
26{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/save.rs:26",
"rustc_incremental::persist::save", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/save.rs"),
::tracing_core::__macro_support::Option::Some(26u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::save"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("save_dep_graph()")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("save_dep_graph()");
27tcx.dep_graph.with_ignore(|| {
28let sess = tcx.sess;
29if sess.opts.incremental.is_none() {
30return;
31 }
32// This is going to be deleted in finalize_session_directory, so let's not create it.
33if sess.dcx().has_errors_or_delayed_bugs().is_some() {
34return;
35 }
3637let incr_comp_session = tcx.incr_comp_session.unwrap();
38let query_cache_path = query_cache_path(incr_comp_session);
39let dep_graph_path = dep_graph_path(incr_comp_session);
40let staging_dep_graph_path = staging_dep_graph_path(incr_comp_session);
4142sess.time("assert_dep_graph", || assert_dep_graph(tcx));
43sess.time("check_clean", || clean::check_clean_annotations(tcx));
4445par_join(
46move || {
47sess.time("incr_comp_persist_dep_graph", || {
48if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
49sess.dcx().emit_err(diagnostics::MoveDepGraph {
50 from: &staging_dep_graph_path,
51 to: &dep_graph_path,
52err,
53 });
54 }
55 });
56 },
57move || {
58// We execute this after `incr_comp_persist_dep_graph` for the serial compiler
59 // to catch any potential query execution writing to the dep graph.
60sess.time("incr_comp_persist_result_cache", || {
61// The on-disk cache struct is always present in incremental mode,
62 // even if there was no previous session.
63let on_disk_cache = tcx.query_system.on_disk_cache.as_ref().unwrap();
6465// For every green dep node that has a disk-cached value from the
66 // previous session, make sure the value is loaded into the memory
67 // cache, so that it will be serialized as part of this session.
68 //
69 // This reads data from the previous session, so it needs to happen
70 // before dropping the mmap.
71 //
72 // FIXME(Zalathar): This step is intended to be cheap, but still does
73 // quite a lot of work, especially in builds with few or no changes.
74 // Can we be smarter about how we identify values that need promotion?
75 // Can we promote values without decoding them into the memory cache?
76tcx.dep_graph.exec_cache_promotions(tcx);
7778// Drop the memory map so that we can remove the file and write to it.
79on_disk_cache.close_serialized_data_mmap();
8081 file_format::save_in(sess, query_cache_path, "query cache", |encoder| {
82tcx.sess.time("incr_comp_serialize_result_cache", || {
83 on_disk_cache::OnDiskCache::serialize(tcx, encoder)
84 })
85 });
86 });
87 },
88 );
89 })
90}
9192/// Saves the work product index.
93pub fn save_work_product_index(
94 sess: &Session,
95 incr_comp_session: Option<&IncrCompSession>,
96 dep_graph: &DepGraph,
97 new_work_products: WorkProductMap,
98) {
99if sess.opts.incremental.is_none() {
100return;
101 }
102// This is going to be deleted in finalize_session_directory, so let's not create it
103if sess.dcx().has_errors().is_some() {
104return;
105 }
106107{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/save.rs:107",
"rustc_incremental::persist::save", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/save.rs"),
::tracing_core::__macro_support::Option::Some(107u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::save"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("save_work_product_index()")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("save_work_product_index()");
108dep_graph.assert_ignored();
109let path = work_products_path(incr_comp_session.unwrap());
110 file_format::save_in(sess, path, "work product index", |mut e| {
111encode_work_product_index(&new_work_products, &mut e);
112e.finish()
113 });
114115// We also need to clean out old work-products, as not all of them are
116 // deleted during invalidation. Some object files don't change their
117 // content, they are just not needed anymore.
118let previous_work_products = dep_graph.previous_work_products();
119for (id, wp) in previous_work_products.to_sorted_stable_ord() {
120if !new_work_products.contains_key(id) {
121 work_product::delete_workproduct_files(sess, incr_comp_session.unwrap(), wp);
122if true {
if !!wp.saved_files.items().all(|(_, path)|
in_incr_comp_dir_sess(incr_comp_session.unwrap(),
path).exists()) {
::core::panicking::panic("assertion failed: !wp.saved_files.items().all(|(_, path)|\n in_incr_comp_dir_sess(incr_comp_session.unwrap(), path).exists())")
};
};debug_assert!(
123 !wp.saved_files.items().all(|(_, path)| in_incr_comp_dir_sess(
124 incr_comp_session.unwrap(),
125 path
126 )
127 .exists())
128 );
129 }
130 }
131132// Check that we did not delete one of the current work-products:
133if true {
if !{
new_work_products.items().all(|(_, wp)|
{
wp.saved_files.items().all(|(_, path)|
in_incr_comp_dir_sess(incr_comp_session.unwrap(),
path).exists())
})
} {
::core::panicking::panic("assertion failed: {\n new_work_products.items().all(|(_, wp)|\n {\n wp.saved_files.items().all(|(_, path)|\n in_incr_comp_dir_sess(incr_comp_session.unwrap(),\n path).exists())\n })\n}")
};
};debug_assert!({
134 new_work_products.items().all(|(_, wp)| {
135 wp.saved_files
136 .items()
137 .all(|(_, path)| in_incr_comp_dir_sess(incr_comp_session.unwrap(), path).exists())
138 })
139 });
140}
141142fn encode_work_product_index(work_products: &WorkProductMap, encoder: &mut FileEncoder<'_>) {
143let serialized_products: Vec<_> = work_products144 .to_sorted_stable_ord()
145 .into_iter()
146 .map(|(id, work_product)| SerializedWorkProduct {
147 id: *id,
148 work_product: work_product.clone(),
149 })
150 .collect();
151152serialized_products.encode(encoder)
153}