Skip to content

Commit 4e5256e

Browse files
committed
add with_hash_task to generate DepNode deterministically
1 parent 1429899 commit 4e5256e

File tree

3 files changed

+73
-22
lines changed

3 files changed

+73
-22
lines changed

compiler/rustc_query_system/src/cache.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::dep_graph::{DepContext, DepNodeIndex};
44

55
use rustc_data_structures::fx::FxHashMap;
6-
use rustc_data_structures::sync::Lock;
6+
use rustc_data_structures::sync::{HashMapExt, Lock};
77

88
use std::hash::Hash;
99

@@ -35,6 +35,12 @@ impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
3535
}
3636
}
3737

38+
impl<Key: Eq + Hash, Value: Clone + Eq> Cache<Key, Value> {
39+
pub fn insert_same(&self, key: Key, dep_node: DepNodeIndex, value: Value) {
40+
self.hashmap.borrow_mut().insert_same(key, WithDepNode::new(dep_node, value));
41+
}
42+
}
43+
3844
#[derive(Clone, Eq, PartialEq)]
3945
pub struct WithDepNode<T> {
4046
dep_node: DepNodeIndex,

compiler/rustc_query_system/src/dep_graph/graph.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -377,24 +377,48 @@ impl<K: DepKind> DepGraph<K> {
377377

378378
/// Executes something within an "anonymous" task, that is, a task the
379379
/// `DepNode` of which is determined by the list of inputs it read from.
380-
pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
381-
&self,
380+
#[inline]
381+
pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>( &self,
382382
cx: Tcx,
383383
dep_kind: K,
384384
op: OP,
385385
) -> (R, DepNodeIndex)
386386
where
387387
OP: FnOnce() -> R,
388+
{
389+
self.with_hash_task(cx, dep_kind, op, |task_deps| {
390+
// The dep node indices are hashed here instead of hashing the dep nodes of the
391+
// dependencies. These indices may refer to different nodes per session, but this isn't
392+
// a problem here because we that ensure the final dep node hash is per session only by
393+
// combining it with the per session random number `anon_id_seed`. This hash only need
394+
// to map the dependencies to a single value on a per session basis.
395+
let mut hasher = StableHasher::new();
396+
task_deps.reads.hash(&mut hasher);
397+
hasher.finish()
398+
})
399+
}
400+
401+
/// Executes something within an "anonymous" task. The `hash` is used for
402+
/// generating the `DepNode`.
403+
pub fn with_hash_task<Ctxt: DepContext<DepKind = K>, OP, R, H>(
404+
&self,
405+
cx: Ctxt,
406+
dep_kind: K,
407+
op: OP,
408+
hash: H,
409+
) -> (R, DepNodeIndex)
410+
where
411+
OP: FnOnce() -> R,
412+
H: FnOnce(&TaskDeps<K>) -> Fingerprint,
388413
{
389414
debug_assert!(!cx.is_eval_always(dep_kind));
390415

391416
if let Some(ref data) = self.data {
392417
let task_deps = Lock::new(TaskDeps::default());
393418
let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op);
394419
let task_deps = task_deps.into_inner();
395-
let task_deps = task_deps.reads;
396420

397-
let dep_node_index = match task_deps.len() {
421+
let dep_node_index = match task_deps.reads.len() {
398422
0 => {
399423
// Because the dep-node id of anon nodes is computed from the sets of its
400424
// dependencies we already know what the ID of this dependency-less node is
@@ -405,29 +429,23 @@ impl<K: DepKind> DepGraph<K> {
405429
}
406430
1 => {
407431
// When there is only one dependency, don't bother creating a node.
408-
task_deps[0]
432+
task_deps.reads[0]
409433
}
410434
_ => {
411-
// The dep node indices are hashed here instead of hashing the dep nodes of the
412-
// dependencies. These indices may refer to different nodes per session, but this isn't
413-
// a problem here because we that ensure the final dep node hash is per session only by
414-
// combining it with the per session random number `anon_id_seed`. This hash only need
415-
// to map the dependencies to a single value on a per session basis.
416-
let mut hasher = StableHasher::new();
417-
task_deps.hash(&mut hasher);
435+
let hash_result = hash(&task_deps);
418436

419437
let target_dep_node = DepNode {
420438
kind: dep_kind,
421439
// Fingerprint::combine() is faster than sending Fingerprint
422440
// through the StableHasher (at least as long as StableHasher
423441
// is so slow).
424-
hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
442+
hash: data.current.anon_id_seed.combine(hash_result).into(),
425443
};
426444

427445
data.current.intern_new_node(
428446
cx.profiler(),
429447
target_dep_node,
430-
task_deps,
448+
task_deps.reads,
431449
Fingerprint::ZERO,
432450
)
433451
}

compiler/rustc_trait_selection/src/traits/select/mod.rs

+34-7
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRe
4949
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
5050
use rustc_span::symbol::sym;
5151

52+
use rustc_data_structures::fingerprint::Fingerprint;
53+
use rustc_data_structures::stable_hasher::StableHasher;
5254
use std::cell::{Cell, RefCell};
5355
use std::cmp;
5456
use std::fmt::{self, Display};
57+
use std::hash::Hash;
5558
use std::iter;
5659

5760
pub use rustc_middle::traits::select::*;
5861
use rustc_middle::ty::print::with_no_trimmed_paths;
62+
use rustc_query_system::dep_graph::TaskDeps;
5963

6064
mod candidate_assembly;
6165
mod confirmation;
@@ -1017,7 +1021,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10171021
return Ok(cycle_result);
10181022
}
10191023

1020-
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
1024+
let (result, dep_node) = if cfg!(parallel_compiler) {
1025+
self.in_task_with_hash(
1026+
|this| this.evaluate_stack(&stack),
1027+
|_| {
1028+
let mut hasher = StableHasher::new();
1029+
(param_env, fresh_trait_pred).hash(&mut hasher);
1030+
hasher.finish()
1031+
},
1032+
)
1033+
} else {
1034+
self.in_task(|this| this.evaluate_stack(&stack))
1035+
};
1036+
10211037
let result = result?;
10221038

10231039
if !result.must_apply_modulo_regions() {
@@ -1263,17 +1279,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12631279
if self.can_use_global_caches(param_env) {
12641280
if !trait_pred.needs_infer() {
12651281
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
1266-
// This may overwrite the cache with the same value
1267-
// FIXME: Due to #50507 this overwrites the different values
1268-
// This should be changed to use HashMapExt::insert_same
1269-
// when that is fixed
1270-
self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result);
1282+
self.tcx().evaluation_cache.insert_same((param_env, trait_pred), dep_node, result);
12711283
return;
12721284
}
12731285
}
12741286

12751287
debug!(?trait_pred, ?result, "insert_evaluation_cache");
1276-
self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
1288+
self.infcx.evaluation_cache.insert_same((param_env, trait_pred), dep_node, result);
12771289
}
12781290

12791291
/// For various reasons, it's possible for a subobligation
@@ -1344,6 +1356,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13441356
(result, dep_node)
13451357
}
13461358

1359+
fn in_task_with_hash<OP, R, H>(&mut self, op: OP, hash: H) -> (R, DepNodeIndex)
1360+
where
1361+
OP: FnOnce(&mut Self) -> R,
1362+
H: FnOnce(&TaskDeps<DepKind>) -> Fingerprint,
1363+
{
1364+
let (result, dep_node) = self.tcx().dep_graph.with_hash_task(
1365+
self.tcx(),
1366+
DepKind::TraitSelect,
1367+
|| op(self),
1368+
hash,
1369+
);
1370+
self.tcx().dep_graph.read_index(dep_node);
1371+
(result, dep_node)
1372+
}
1373+
13471374
/// filter_impls filters constant trait obligations and candidates that have a positive impl
13481375
/// for a negative goal and a negative impl for a positive goal
13491376
#[instrument(level = "debug", skip(self, candidates))]

0 commit comments

Comments
 (0)