Skip to content

Commit bcdfb0b

Browse files
committed
Auto merge of rust-lang#115693 - Zoxc:early-dep-graph-load, r=<try>
Load the dep graph before parsing This changes the dep graph to start loading before parsing. We don't have access to the crate name defined in the source code at this point, so if it's not specified on the command line, incremental compilation will fallback to the file path as a crate identifier. r? `@oli-obk`
2 parents 6cc1898 + 360ee87 commit bcdfb0b

File tree

2 files changed

+71
-43
lines changed

2 files changed

+71
-43
lines changed

compiler/rustc_incremental/src/persist/fs.rs

+35-9
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,18 @@
105105
106106
use crate::errors;
107107
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
108+
use rustc_data_structures::stable_hasher::{Hash64, StableHasher};
108109
use rustc_data_structures::svh::Svh;
109110
use rustc_data_structures::unord::{UnordMap, UnordSet};
110111
use rustc_data_structures::{base_n, flock};
111112
use rustc_errors::ErrorGuaranteed;
112113
use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
114+
use rustc_session::config::{CrateType, Input};
113115
use rustc_session::{Session, StableCrateId};
114-
use rustc_span::Symbol;
116+
use rustc_span::symbol;
115117

116118
use std::fs as std_fs;
119+
use std::hash::Hash;
117120
use std::io::{self, ErrorKind};
118121
use std::path::{Path, PathBuf};
119122
use std::time::{Duration, SystemTime, UNIX_EPOCH};
@@ -202,11 +205,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
202205
/// The garbage collection will take care of it.
203206
///
204207
/// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
205-
pub fn prepare_session_directory(
206-
sess: &Session,
207-
crate_name: Symbol,
208-
stable_crate_id: StableCrateId,
209-
) -> Result<(), ErrorGuaranteed> {
208+
pub fn prepare_session_directory(sess: &Session) -> Result<(), ErrorGuaranteed> {
210209
if sess.opts.incremental.is_none() {
211210
return Ok(());
212211
}
@@ -216,7 +215,7 @@ pub fn prepare_session_directory(
216215
debug!("prepare_session_directory");
217216

218217
// {incr-comp-dir}/{crate-name-and-disambiguator}
219-
let crate_dir = crate_path(sess, crate_name, stable_crate_id);
218+
let crate_dir = crate_path(sess);
220219
debug!("crate-dir: {}", crate_dir.display());
221220
create_dir(sess, &crate_dir, "crate")?;
222221

@@ -601,12 +600,39 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, &'static str> {
601600
Ok(UNIX_EPOCH + duration)
602601
}
603602

604-
fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf {
603+
fn crate_path(sess: &Session) -> PathBuf {
604+
// Use the crate name from the command line if available and valid
605+
let crate_name = sess.opts.crate_name.as_ref().and_then(|name| {
606+
name.as_str().chars().all(|c| c.is_alphanumeric() || c == '_').then_some(&name[..])
607+
});
608+
609+
// Create a hash for metadata and the rust version
610+
let metadata_and_version = StableCrateId::new(
611+
symbol::kw::Empty,
612+
// JUSTIFICATION: before wrapper fn is available
613+
#[allow(rustc::bad_opt_access)]
614+
sess.opts.crate_types.contains(&CrateType::Executable),
615+
sess.opts.cg.metadata.clone(),
616+
sess.cfg_version,
617+
);
618+
619+
// Find a file path to differentiate crates if crate name is missing
620+
let canonical_file_path = crate_name.is_none().then(|| match &sess.io.input {
621+
Input::File(file) => try_canonicalize(file).ok(),
622+
Input::Str { .. } => None,
623+
});
624+
625+
let mut hasher = StableHasher::new();
626+
crate_name.hash(&mut hasher);
627+
metadata_and_version.hash(&mut hasher);
628+
canonical_file_path.hash(&mut hasher);
629+
let stable_crate_id: Hash64 = hasher.finish();
630+
605631
let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
606632

607633
let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE);
608634

609-
let crate_name = format!("{crate_name}-{stable_crate_id}");
635+
let crate_name = format!("{}-{stable_crate_id}", crate_name.unwrap_or("unknown.crate"));
610636
incr_dir.join(crate_name)
611637
}
612638

compiler/rustc_interface/src/queries.rs

+36-34
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc_session::config::{self, CrateType, OutputFilenames, OutputType};
2121
use rustc_session::cstore::Untracked;
2222
use rustc_session::{output::find_crate_name, Session};
2323
use rustc_span::symbol::sym;
24-
use rustc_span::Symbol;
2524
use std::any::Any;
2625
use std::cell::{RefCell, RefMut};
2726
use std::sync::Arc;
@@ -85,6 +84,7 @@ pub struct Queries<'tcx> {
8584
arena: WorkerLocal<Arena<'tcx>>,
8685
hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>,
8786

87+
dep_graph_future: Query<Option<DepGraphFuture>>,
8888
parse: Query<ast::Crate>,
8989
pre_configure: Query<(ast::Crate, ast::AttrVec)>,
9090
// This just points to what's in `gcx_cell`.
@@ -98,6 +98,7 @@ impl<'tcx> Queries<'tcx> {
9898
gcx_cell: OnceLock::new(),
9999
arena: WorkerLocal::new(|_| Arena::default()),
100100
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
101+
dep_graph_future: Default::default(),
101102
parse: Default::default(),
102103
pre_configure: Default::default(),
103104
gcx: Default::default(),
@@ -112,8 +113,13 @@ impl<'tcx> Queries<'tcx> {
112113
}
113114

114115
pub fn parse(&self) -> Result<QueryResult<'_, ast::Crate>> {
115-
self.parse
116-
.compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit()))
116+
self.parse.compute(|| {
117+
// Compute the dependency graph (in the background). We want to do this as early as
118+
// possible, to give the DepGraph maximum time to load before `dep_graph` is called.
119+
self.dep_graph_future()?;
120+
121+
passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())
122+
})
117123
}
118124

119125
pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> {
@@ -133,41 +139,41 @@ impl<'tcx> Queries<'tcx> {
133139
})
134140
}
135141

136-
fn dep_graph_future(
137-
&self,
138-
crate_name: Symbol,
139-
stable_crate_id: StableCrateId,
140-
) -> Result<Option<DepGraphFuture>> {
141-
let sess = self.session();
142-
143-
// `load_dep_graph` can only be called after `prepare_session_directory`.
144-
rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?;
145-
let res = sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess));
146-
147-
if sess.opts.incremental.is_some() {
148-
sess.time("incr_comp_garbage_collect_session_directories", || {
149-
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
150-
warn!(
151-
"Error while trying to garbage collect incremental \
152-
compilation cache directory: {}",
153-
e
154-
);
155-
}
156-
});
157-
}
142+
fn dep_graph_future(&self) -> Result<QueryResult<'_, Option<DepGraphFuture>>> {
143+
self.dep_graph_future.compute(|| {
144+
let sess = self.session();
145+
146+
// `load_dep_graph` can only be called after `prepare_session_directory`.
147+
rustc_incremental::prepare_session_directory(sess)?;
148+
let res = sess.opts.build_dep_graph().then(|| rustc_incremental::load_dep_graph(sess));
149+
150+
if sess.opts.incremental.is_some() {
151+
sess.time("incr_comp_garbage_collect_session_directories", || {
152+
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
153+
warn!(
154+
"Error while trying to garbage collect incremental \
155+
compilation cache directory: {}",
156+
e
157+
);
158+
}
159+
});
160+
}
158161

159-
Ok(res)
162+
Ok(res)
163+
})
160164
}
161165

162-
fn dep_graph(&self, dep_graph_future: Option<DepGraphFuture>) -> DepGraph {
163-
dep_graph_future
166+
fn dep_graph(&self) -> Result<DepGraph> {
167+
Ok(self
168+
.dep_graph_future()?
169+
.steal()
164170
.and_then(|future| {
165171
let sess = self.session();
166172
let (prev_graph, prev_work_products) =
167173
sess.time("blocked_on_dep_graph_loading", || future.open().open(sess));
168174
rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products)
169175
})
170-
.unwrap_or_else(DepGraph::new_disabled)
176+
.unwrap_or_else(DepGraph::new_disabled))
171177
}
172178

173179
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
@@ -185,10 +191,6 @@ impl<'tcx> Queries<'tcx> {
185191
sess.cfg_version,
186192
);
187193

188-
// Compute the dependency graph (in the background). We want to do this as early as
189-
// possible, to give the DepGraph maximum time to load before `dep_graph` is called.
190-
let dep_graph_future = self.dep_graph_future(crate_name, stable_crate_id)?;
191-
192194
let lint_store = Lrc::new(passes::create_lint_store(
193195
sess,
194196
&*self.codegen_backend().metadata_loader(),
@@ -210,7 +212,7 @@ impl<'tcx> Queries<'tcx> {
210212
crate_types,
211213
stable_crate_id,
212214
lint_store,
213-
self.dep_graph(dep_graph_future),
215+
self.dep_graph()?,
214216
untracked,
215217
&self.gcx_cell,
216218
&self.arena,

0 commit comments

Comments
 (0)