Skip to content

Commit 0363a23

Browse files
incr.comp.: Introduce the concept of anonymous DepNodes.
1 parent 089860b commit 0363a23

File tree

3 files changed

+200
-90
lines changed

3 files changed

+200
-90
lines changed

src/librustc/dep_graph/dep_node.rs

+117-88
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,14 @@ macro_rules! erase {
7979
($x:tt) => ({})
8080
}
8181

82+
macro_rules! anon_attr_to_bool {
83+
(anon) => (true)
84+
}
85+
8286
macro_rules! define_dep_nodes {
8387
(<$tcx:tt>
8488
$(
89+
[$($anon:ident)*]
8590
$variant:ident $(( $($tuple_arg:tt),* ))*
8691
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
8792
,)*
@@ -117,6 +122,19 @@ macro_rules! define_dep_nodes {
117122
}
118123
}
119124

125+
#[allow(unreachable_code)]
126+
#[inline]
127+
pub fn is_anon<$tcx>(&self) -> bool {
128+
match *self {
129+
$(
130+
DepKind :: $variant => {
131+
$(return anon_attr_to_bool!($anon);)*
132+
false
133+
}
134+
)*
135+
}
136+
}
137+
120138
#[allow(unreachable_code)]
121139
#[inline]
122140
pub fn has_params(&self) -> bool {
@@ -356,100 +374,101 @@ define_dep_nodes!( <'tcx>
356374
// suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
357375
// access to the krate, but you must remember to add suitable
358376
// edges yourself for the individual items that you read.
359-
Krate,
377+
[] Krate,
360378

361379
// Represents the HIR node with the given node-id
362-
Hir(DefId),
380+
[] Hir(DefId),
363381

364382
// Represents the body of a function or method. The def-id is that of the
365383
// function/method.
366-
HirBody(DefId),
384+
[] HirBody(DefId),
367385

368386
// Represents the metadata for a given HIR node, typically found
369387
// in an extern crate.
370-
MetaData(DefId),
388+
[] MetaData(DefId),
371389

372390
// Represents some artifact that we save to disk. Note that these
373391
// do not have a def-id as part of their identifier.
374-
WorkProduct(WorkProductId),
392+
[] WorkProduct(WorkProductId),
375393

376394
// Represents different phases in the compiler.
377-
RegionMaps(DefId),
378-
Coherence,
379-
Resolve,
380-
CoherenceCheckTrait(DefId),
381-
PrivacyAccessLevels(CrateNum),
395+
[] RegionMaps(DefId),
396+
[] Coherence,
397+
[] Resolve,
398+
[] CoherenceCheckTrait(DefId),
399+
[] PrivacyAccessLevels(CrateNum),
382400

383401
// Represents the MIR for a fn; also used as the task node for
384402
// things read/modify that MIR.
385-
MirConstQualif(DefId),
386-
MirConst(DefId),
387-
MirValidated(DefId),
388-
MirOptimized(DefId),
389-
MirShim { instance_def: InstanceDef<'tcx> },
390-
391-
BorrowCheckKrate,
392-
BorrowCheck(DefId),
393-
RvalueCheck(DefId),
394-
Reachability,
395-
MirKeys,
396-
TransWriteMetadata,
397-
CrateVariances,
403+
[] MirConstQualif(DefId),
404+
[] MirConst(DefId),
405+
[] MirValidated(DefId),
406+
[] MirOptimized(DefId),
407+
[] MirShim { instance_def: InstanceDef<'tcx> },
408+
409+
[] BorrowCheckKrate,
410+
[] BorrowCheck(DefId),
411+
[] RvalueCheck(DefId),
412+
[] Reachability,
413+
[] MirKeys,
414+
[] TransWriteMetadata,
415+
[] CrateVariances,
398416

399417
// Nodes representing bits of computed IR in the tcx. Each shared
400418
// table in the tcx (or elsewhere) maps to one of these
401419
// nodes.
402-
AssociatedItems(DefId),
403-
TypeOfItem(DefId),
404-
GenericsOfItem(DefId),
405-
PredicatesOfItem(DefId),
406-
SuperPredicatesOfItem(DefId),
407-
TraitDefOfItem(DefId),
408-
AdtDefOfItem(DefId),
409-
IsDefaultImpl(DefId),
410-
ImplTraitRef(DefId),
411-
ImplPolarity(DefId),
412-
ClosureKind(DefId),
413-
FnSignature(DefId),
414-
CoerceUnsizedInfo(DefId),
415-
416-
ItemVarianceConstraints(DefId),
417-
ItemVariances(DefId),
418-
IsConstFn(DefId),
419-
IsForeignItem(DefId),
420-
TypeParamPredicates { item_id: DefId, param_id: DefId },
421-
SizedConstraint(DefId),
422-
DtorckConstraint(DefId),
423-
AdtDestructor(DefId),
424-
AssociatedItemDefIds(DefId),
425-
InherentImpls(DefId),
426-
TypeckBodiesKrate,
427-
TypeckTables(DefId),
428-
HasTypeckTables(DefId),
429-
ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> },
430-
SymbolName(DefId),
431-
InstanceSymbolName { instance: Instance<'tcx> },
432-
SpecializationGraph(DefId),
433-
ObjectSafety(DefId),
434-
IsCopy(DefId),
435-
IsSized(DefId),
436-
IsFreeze(DefId),
437-
NeedsDrop(DefId),
438-
Layout(DefId),
420+
[] AssociatedItems(DefId),
421+
[] TypeOfItem(DefId),
422+
[] GenericsOfItem(DefId),
423+
[] PredicatesOfItem(DefId),
424+
[] SuperPredicatesOfItem(DefId),
425+
[] TraitDefOfItem(DefId),
426+
[] AdtDefOfItem(DefId),
427+
[] IsDefaultImpl(DefId),
428+
[] ImplTraitRef(DefId),
429+
[] ImplPolarity(DefId),
430+
[] ClosureKind(DefId),
431+
[] FnSignature(DefId),
432+
[] CoerceUnsizedInfo(DefId),
433+
434+
[] ItemVarianceConstraints(DefId),
435+
[] ItemVariances(DefId),
436+
[] IsConstFn(DefId),
437+
[] IsForeignItem(DefId),
438+
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
439+
[] SizedConstraint(DefId),
440+
[] DtorckConstraint(DefId),
441+
[] AdtDestructor(DefId),
442+
[] AssociatedItemDefIds(DefId),
443+
[] InherentImpls(DefId),
444+
[] TypeckBodiesKrate,
445+
[] TypeckTables(DefId),
446+
[] HasTypeckTables(DefId),
447+
[] ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> },
448+
[] SymbolName(DefId),
449+
[] InstanceSymbolName { instance: Instance<'tcx> },
450+
[] SpecializationGraph(DefId),
451+
[] ObjectSafety(DefId),
452+
453+
[anon] IsCopy(DefId),
454+
[anon] IsSized(DefId),
455+
[anon] IsFreeze(DefId),
456+
[anon] NeedsDrop(DefId),
457+
[anon] Layout(DefId),
439458

440459
// The set of impls for a given trait.
441-
TraitImpls(DefId),
442-
RelevantTraitImpls(DefId, SimplifiedType),
460+
[] TraitImpls(DefId),
461+
[] RelevantTraitImpls(DefId, SimplifiedType),
443462

444-
AllLocalTraitImpls,
463+
[] AllLocalTraitImpls,
445464

446465
// Nodes representing caches. To properly handle a true cache, we
447466
// don't use a DepTrackingMap, but rather we push a task node.
448467
// Otherwise the write into the map would be incorrectly
449468
// attributed to the first task that happened to fill the cache,
450469
// which would yield an overly conservative dep-graph.
451-
TraitItems(DefId),
452-
ReprHints(DefId),
470+
[] TraitItems(DefId),
471+
[] ReprHints(DefId),
453472

454473
// Trait selection cache is a little funny. Given a trait
455474
// reference like `Foo: SomeTrait<Bar>`, there could be
@@ -476,35 +495,45 @@ define_dep_nodes!( <'tcx>
476495
// imprecision in our dep-graph tracking. The important thing is
477496
// that for any given trait-ref, we always map to the **same**
478497
// trait-select node.
479-
TraitSelect { trait_def_id: DefId, input_def_id: DefId },
498+
[] TraitSelect { trait_def_id: DefId, input_def_id: DefId },
480499

481500
// For proj. cache, we just keep a list of all def-ids, since it is
482501
// not a hotspot.
483-
ProjectionCache { def_ids: DefIdList },
484-
485-
ParamEnv(DefId),
486-
DescribeDef(DefId),
487-
DefSpan(DefId),
488-
Stability(DefId),
489-
Deprecation(DefId),
490-
ItemBodyNestedBodies(DefId),
491-
ConstIsRvaluePromotableToStatic(DefId),
492-
ImplParent(DefId),
493-
TraitOfItem(DefId),
494-
IsExportedSymbol(DefId),
495-
IsMirAvailable(DefId),
496-
ItemAttrs(DefId),
497-
FnArgNames(DefId),
498-
DylibDepFormats(DefId),
499-
IsAllocator(DefId),
500-
IsPanicRuntime(DefId),
501-
ExternCrate(DefId),
502+
[] ProjectionCache { def_ids: DefIdList },
503+
504+
[] ParamEnv(DefId),
505+
[] DescribeDef(DefId),
506+
[] DefSpan(DefId),
507+
[] Stability(DefId),
508+
[] Deprecation(DefId),
509+
[] ItemBodyNestedBodies(DefId),
510+
[] ConstIsRvaluePromotableToStatic(DefId),
511+
[] ImplParent(DefId),
512+
[] TraitOfItem(DefId),
513+
[] IsExportedSymbol(DefId),
514+
[] IsMirAvailable(DefId),
515+
[] ItemAttrs(DefId),
516+
[] FnArgNames(DefId),
517+
[] DylibDepFormats(DefId),
518+
[] IsAllocator(DefId),
519+
[] IsPanicRuntime(DefId),
520+
[] ExternCrate(DefId),
502521
);
503522

504-
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
523+
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
505524
const CAN_RECONSTRUCT_QUERY_KEY: bool;
506-
fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint;
507-
fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String;
525+
526+
/// This method turns the parameters of a DepNodeConstructor into an opaque
527+
/// Fingerprint to be used in DepNode.
528+
/// Not all DepNodeParams support being turned into a Fingerprint (they
529+
/// don't need to if the corresponding DepNode is anonymous).
530+
fn to_fingerprint(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint {
531+
panic!("Not implemented. Accidentally called on anonymous node?")
532+
}
533+
534+
fn to_debug_str(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> String {
535+
format!("{:?}", self)
536+
}
508537
}
509538

510539
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T

src/librustc/dep_graph/edges.rs

+67-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use ich::Fingerprint;
1112
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13+
use rustc_data_structures::stable_hasher::StableHasher;
1214
use std::env;
13-
use super::{DepGraphQuery, DepNode};
15+
use std::hash::Hash;
16+
use std::mem;
17+
use super::{DepGraphQuery, DepKind, DepNode};
1418
use super::debug::EdgeFilter;
1519

1620
pub struct DepGraphEdges {
@@ -44,6 +48,10 @@ enum OpenTask {
4448
reads: Vec<DepNode>,
4549
read_set: FxHashSet<DepNode>,
4650
},
51+
Anon {
52+
reads: Vec<DepNode>,
53+
read_set: FxHashSet<DepNode>,
54+
},
4755
Ignore,
4856
}
4957

@@ -114,6 +122,56 @@ impl DepGraphEdges {
114122
}
115123
}
116124

125+
pub fn push_anon_task(&mut self) {
126+
self.task_stack.push(OpenTask::Anon {
127+
reads: Vec::new(),
128+
read_set: FxHashSet(),
129+
});
130+
}
131+
132+
pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNode {
133+
let popped_node = self.task_stack.pop().unwrap();
134+
135+
if let OpenTask::Anon {
136+
read_set: _,
137+
reads
138+
} = popped_node {
139+
let mut fingerprint = Fingerprint::zero();
140+
let mut hasher = StableHasher::new();
141+
142+
for read in reads.iter() {
143+
mem::discriminant(&read.kind).hash(&mut hasher);
144+
145+
// Fingerprint::combine() is faster than sending Fingerprint
146+
// through the StableHasher (at least as long as StableHasher
147+
// is so slow).
148+
fingerprint = fingerprint.combine(read.hash);
149+
}
150+
151+
fingerprint = fingerprint.combine(hasher.finish());
152+
153+
let target_dep_node = DepNode {
154+
kind,
155+
hash: fingerprint,
156+
};
157+
158+
if self.indices.contains_key(&target_dep_node) {
159+
return target_dep_node;
160+
}
161+
162+
let target_id = self.get_or_create_node(target_dep_node);
163+
164+
for read in reads.into_iter() {
165+
let source_id = self.get_or_create_node(read);
166+
self.edges.insert((source_id, target_id));
167+
}
168+
169+
target_dep_node
170+
} else {
171+
bug!("pop_anon_task() - Expected anonymous task to be popped")
172+
}
173+
}
174+
117175
/// Indicates that the current task `C` reads `v` by adding an
118176
/// edge from `v` to `C`. If there is no current task, has no
119177
/// effect. Note that *reading* from tracked state is harmless if
@@ -138,6 +196,14 @@ impl DepGraphEdges {
138196
}
139197
}
140198
}
199+
Some(&mut OpenTask::Anon {
200+
ref mut reads,
201+
ref mut read_set,
202+
}) => {
203+
if read_set.insert(source) {
204+
reads.push(source);
205+
}
206+
}
141207
Some(&mut OpenTask::Ignore) | None => {
142208
// ignore
143209
}

src/librustc/dep_graph/graph.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use session::config::OutputType;
1313
use std::cell::{Ref, RefCell};
1414
use std::rc::Rc;
1515

16-
use super::dep_node::{DepNode, WorkProductId};
16+
use super::dep_node::{DepNode, DepKind, WorkProductId};
1717
use super::query::DepGraphQuery;
1818
use super::raii;
1919
use super::safe::DepGraphSafe;
@@ -115,6 +115,21 @@ impl DepGraph {
115115
task(cx, arg)
116116
}
117117

118+
/// Execute something within an "anonymous" task, that is, a task the
119+
/// DepNode of which is determined by the list of inputs it read from.
120+
pub fn with_anon_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNode)
121+
where OP: FnOnce() -> R
122+
{
123+
if let Some(ref data) = self.data {
124+
data.edges.borrow_mut().push_anon_task();
125+
let result = op();
126+
let dep_node = data.edges.borrow_mut().pop_anon_task(dep_kind);
127+
(result, dep_node)
128+
} else {
129+
(op(), DepNode::new_no_params(DepKind::Krate))
130+
}
131+
}
132+
118133
#[inline]
119134
pub fn read(&self, v: DepNode) {
120135
if let Some(ref data) = self.data {

0 commit comments

Comments
 (0)