1 use rustc_data_structures::fx::FxHashMap;
2 use rustc_data_structures::sync::join;
3 use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
4 use rustc_middle::ty::TyCtxt;
5 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
6 use rustc_serialize::Encodable as RustcEncodable;
7 use rustc_session::Session;
11 use super::dirty_clean;
12 use super::file_format;
14 use super::work_product;
16 /// Save and dump the DepGraph.
18 /// No query must be invoked after this function.
19 pub fn save_dep_graph(tcx: TyCtxt<'_>) {
20 debug!("save_dep_graph()");
21 tcx.dep_graph.with_ignore(|| {
23 if sess.opts.incremental.is_none() {
26 // This is going to be deleted in finalize_session_directory, so let's not create it
27 if sess.has_errors_or_delayed_span_bugs() {
31 let query_cache_path = query_cache_path(sess);
32 let dep_graph_path = dep_graph_path(sess);
33 let staging_dep_graph_path = staging_dep_graph_path(sess);
35 sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx));
36 sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
38 if sess.opts.debugging_opts.incremental_info {
39 tcx.dep_graph.print_incremental_info()
44 sess.time("incr_comp_persist_result_cache", || {
45 // Drop the memory map so that we can remove the file and write to it.
46 if let Some(odc) = &tcx.on_disk_cache {
47 odc.drop_serialized_data(tcx);
50 file_format::save_in(sess, query_cache_path, "query cache", |e| {
51 encode_query_cache(tcx, e)
56 sess.time("incr_comp_persist_dep_graph", || {
57 if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
59 "failed to write dependency graph to `{}`: {}",
60 staging_dep_graph_path.display(),
64 if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
66 "failed to move dependency graph from `{}` to `{}`: {}",
67 staging_dep_graph_path.display(),
68 dep_graph_path.display(),
78 pub fn save_work_product_index(
81 new_work_products: FxHashMap<WorkProductId, WorkProduct>,
83 if sess.opts.incremental.is_none() {
86 // This is going to be deleted in finalize_session_directory, so let's not create it
87 if sess.has_errors_or_delayed_span_bugs() {
91 debug!("save_work_product_index()");
92 dep_graph.assert_ignored();
93 let path = work_products_path(sess);
94 file_format::save_in(sess, path, "work product index", |e| {
95 encode_work_product_index(&new_work_products, e)
98 // We also need to clean out old work-products, as not all of them are
99 // deleted during invalidation. Some object files don't change their
100 // content, they are just not needed anymore.
101 let previous_work_products = dep_graph.previous_work_products();
102 for (id, wp) in previous_work_products.iter() {
103 if !new_work_products.contains_key(id) {
104 work_product::delete_workproduct_files(sess, wp);
106 wp.saved_file.as_ref().map_or(true, |file_name| {
107 !in_incr_comp_dir_sess(sess, &file_name).exists()
113 // Check that we did not delete one of the current work-products:
117 .flat_map(|(_, wp)| wp.saved_file.iter())
118 .map(|name| in_incr_comp_dir_sess(sess, name))
119 .all(|path| path.exists())
123 fn encode_work_product_index(
124 work_products: &FxHashMap<WorkProductId, WorkProduct>,
125 encoder: &mut FileEncoder,
126 ) -> FileEncodeResult {
127 let serialized_products: Vec<_> = work_products
129 .map(|(id, work_product)| SerializedWorkProduct {
131 work_product: work_product.clone(),
135 serialized_products.encode(encoder)
138 fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
139 tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
142 pub fn build_dep_graph(
144 prev_graph: SerializedDepGraph,
145 prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
146 ) -> Option<DepGraph> {
147 if sess.opts.incremental.is_none() {
148 // No incremental compilation.
152 // Stream the dep-graph to an alternate file, to avoid overwriting anything in case of errors.
153 let path_buf = staging_dep_graph_path(sess);
155 let mut encoder = match FileEncoder::new(&path_buf) {
156 Ok(encoder) => encoder,
159 "failed to create dependency graph at `{}`: {}",
167 if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) {
169 "failed to write dependency graph header to `{}`: {}",
176 // First encode the commandline arguments hash
177 if let Err(err) = sess.opts.dep_tracking_hash(false).encode(&mut encoder) {
179 "failed to write dependency graph hash `{}`: {}",
191 sess.opts.debugging_opts.query_dep_graph,
192 sess.opts.debugging_opts.incremental_info,