incr.comp.: Introduce the concept of anonymous DepNodes.

This commit is contained in:
Michael Woerister 2017-06-23 16:37:12 +02:00
parent 089860b603
commit 0363a23c35
3 changed files with 197 additions and 87 deletions

View File

@ -79,9 +79,14 @@ macro_rules! erase {
($x:tt) => ({})
}
macro_rules! anon_attr_to_bool {
(anon) => (true)
}
macro_rules! define_dep_nodes {
(<$tcx:tt>
$(
[$($anon:ident)*]
$variant:ident $(( $($tuple_arg:tt),* ))*
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
,)*
@ -117,6 +122,19 @@ macro_rules! define_dep_nodes {
}
}
#[allow(unreachable_code)]
#[inline]
pub fn is_anon<$tcx>(&self) -> bool {
match *self {
$(
DepKind :: $variant => {
$(return anon_attr_to_bool!($anon);)*
false
}
)*
}
}
#[allow(unreachable_code)]
#[inline]
pub fn has_params(&self) -> bool {
@ -356,100 +374,101 @@ define_dep_nodes!( <'tcx>
// suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain
// access to the krate, but you must remember to add suitable
// edges yourself for the individual items that you read.
Krate,
[] Krate,
// Represents the HIR node with the given node-id
Hir(DefId),
[] Hir(DefId),
// Represents the body of a function or method. The def-id is that of the
// function/method.
HirBody(DefId),
[] HirBody(DefId),
// Represents the metadata for a given HIR node, typically found
// in an extern crate.
MetaData(DefId),
[] MetaData(DefId),
// Represents some artifact that we save to disk. Note that these
// do not have a def-id as part of their identifier.
WorkProduct(WorkProductId),
[] WorkProduct(WorkProductId),
// Represents different phases in the compiler.
RegionMaps(DefId),
Coherence,
Resolve,
CoherenceCheckTrait(DefId),
PrivacyAccessLevels(CrateNum),
[] RegionMaps(DefId),
[] Coherence,
[] Resolve,
[] CoherenceCheckTrait(DefId),
[] PrivacyAccessLevels(CrateNum),
// Represents the MIR for a fn; also used as the task node for
// things read/modify that MIR.
MirConstQualif(DefId),
MirConst(DefId),
MirValidated(DefId),
MirOptimized(DefId),
MirShim { instance_def: InstanceDef<'tcx> },
[] MirConstQualif(DefId),
[] MirConst(DefId),
[] MirValidated(DefId),
[] MirOptimized(DefId),
[] MirShim { instance_def: InstanceDef<'tcx> },
BorrowCheckKrate,
BorrowCheck(DefId),
RvalueCheck(DefId),
Reachability,
MirKeys,
TransWriteMetadata,
CrateVariances,
[] BorrowCheckKrate,
[] BorrowCheck(DefId),
[] RvalueCheck(DefId),
[] Reachability,
[] MirKeys,
[] TransWriteMetadata,
[] CrateVariances,
// Nodes representing bits of computed IR in the tcx. Each shared
// table in the tcx (or elsewhere) maps to one of these
// nodes.
AssociatedItems(DefId),
TypeOfItem(DefId),
GenericsOfItem(DefId),
PredicatesOfItem(DefId),
SuperPredicatesOfItem(DefId),
TraitDefOfItem(DefId),
AdtDefOfItem(DefId),
IsDefaultImpl(DefId),
ImplTraitRef(DefId),
ImplPolarity(DefId),
ClosureKind(DefId),
FnSignature(DefId),
CoerceUnsizedInfo(DefId),
[] AssociatedItems(DefId),
[] TypeOfItem(DefId),
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
[] SuperPredicatesOfItem(DefId),
[] TraitDefOfItem(DefId),
[] AdtDefOfItem(DefId),
[] IsDefaultImpl(DefId),
[] ImplTraitRef(DefId),
[] ImplPolarity(DefId),
[] ClosureKind(DefId),
[] FnSignature(DefId),
[] CoerceUnsizedInfo(DefId),
ItemVarianceConstraints(DefId),
ItemVariances(DefId),
IsConstFn(DefId),
IsForeignItem(DefId),
TypeParamPredicates { item_id: DefId, param_id: DefId },
SizedConstraint(DefId),
DtorckConstraint(DefId),
AdtDestructor(DefId),
AssociatedItemDefIds(DefId),
InherentImpls(DefId),
TypeckBodiesKrate,
TypeckTables(DefId),
HasTypeckTables(DefId),
ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> },
SymbolName(DefId),
InstanceSymbolName { instance: Instance<'tcx> },
SpecializationGraph(DefId),
ObjectSafety(DefId),
IsCopy(DefId),
IsSized(DefId),
IsFreeze(DefId),
NeedsDrop(DefId),
Layout(DefId),
[] ItemVarianceConstraints(DefId),
[] ItemVariances(DefId),
[] IsConstFn(DefId),
[] IsForeignItem(DefId),
[] TypeParamPredicates { item_id: DefId, param_id: DefId },
[] SizedConstraint(DefId),
[] DtorckConstraint(DefId),
[] AdtDestructor(DefId),
[] AssociatedItemDefIds(DefId),
[] InherentImpls(DefId),
[] TypeckBodiesKrate,
[] TypeckTables(DefId),
[] HasTypeckTables(DefId),
[] ConstEval { def_id: DefId, substs: &'tcx Substs<'tcx> },
[] SymbolName(DefId),
[] InstanceSymbolName { instance: Instance<'tcx> },
[] SpecializationGraph(DefId),
[] ObjectSafety(DefId),
[anon] IsCopy(DefId),
[anon] IsSized(DefId),
[anon] IsFreeze(DefId),
[anon] NeedsDrop(DefId),
[anon] Layout(DefId),
// The set of impls for a given trait.
TraitImpls(DefId),
RelevantTraitImpls(DefId, SimplifiedType),
[] TraitImpls(DefId),
[] RelevantTraitImpls(DefId, SimplifiedType),
AllLocalTraitImpls,
[] AllLocalTraitImpls,
// Nodes representing caches. To properly handle a true cache, we
// don't use a DepTrackingMap, but rather we push a task node.
// Otherwise the write into the map would be incorrectly
// attributed to the first task that happened to fill the cache,
// which would yield an overly conservative dep-graph.
TraitItems(DefId),
ReprHints(DefId),
[] TraitItems(DefId),
[] ReprHints(DefId),
// Trait selection cache is a little funny. Given a trait
// reference like `Foo: SomeTrait<Bar>`, there could be
@ -476,35 +495,45 @@ define_dep_nodes!( <'tcx>
// imprecision in our dep-graph tracking. The important thing is
// that for any given trait-ref, we always map to the **same**
// trait-select node.
TraitSelect { trait_def_id: DefId, input_def_id: DefId },
[] TraitSelect { trait_def_id: DefId, input_def_id: DefId },
// For proj. cache, we just keep a list of all def-ids, since it is
// not a hotspot.
ProjectionCache { def_ids: DefIdList },
[] ProjectionCache { def_ids: DefIdList },
ParamEnv(DefId),
DescribeDef(DefId),
DefSpan(DefId),
Stability(DefId),
Deprecation(DefId),
ItemBodyNestedBodies(DefId),
ConstIsRvaluePromotableToStatic(DefId),
ImplParent(DefId),
TraitOfItem(DefId),
IsExportedSymbol(DefId),
IsMirAvailable(DefId),
ItemAttrs(DefId),
FnArgNames(DefId),
DylibDepFormats(DefId),
IsAllocator(DefId),
IsPanicRuntime(DefId),
ExternCrate(DefId),
[] ParamEnv(DefId),
[] DescribeDef(DefId),
[] DefSpan(DefId),
[] Stability(DefId),
[] Deprecation(DefId),
[] ItemBodyNestedBodies(DefId),
[] ConstIsRvaluePromotableToStatic(DefId),
[] ImplParent(DefId),
[] TraitOfItem(DefId),
[] IsExportedSymbol(DefId),
[] IsMirAvailable(DefId),
[] ItemAttrs(DefId),
[] FnArgNames(DefId),
[] DylibDepFormats(DefId),
[] IsAllocator(DefId),
[] IsPanicRuntime(DefId),
[] ExternCrate(DefId),
);
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> {
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
const CAN_RECONSTRUCT_QUERY_KEY: bool;
fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint;
fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String;
/// This method turns the parameters of a DepNodeConstructor into an opaque
/// Fingerprint to be used in DepNode.
/// Not all DepNodeParams support being turned into a Fingerprint (they
/// don't need to if the corresponding DepNode is anonymous).
fn to_fingerprint(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint {
panic!("Not implemented. Accidentally called on anonymous node?")
}
fn to_debug_str(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> String {
format!("{:?}", self)
}
}
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T

View File

@ -8,9 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ich::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::StableHasher;
use std::env;
use super::{DepGraphQuery, DepNode};
use std::hash::Hash;
use std::mem;
use super::{DepGraphQuery, DepKind, DepNode};
use super::debug::EdgeFilter;
pub struct DepGraphEdges {
@ -44,6 +48,10 @@ enum OpenTask {
reads: Vec<DepNode>,
read_set: FxHashSet<DepNode>,
},
Anon {
reads: Vec<DepNode>,
read_set: FxHashSet<DepNode>,
},
Ignore,
}
@ -114,6 +122,56 @@ impl DepGraphEdges {
}
}
pub fn push_anon_task(&mut self) {
self.task_stack.push(OpenTask::Anon {
reads: Vec::new(),
read_set: FxHashSet(),
});
}
pub fn pop_anon_task(&mut self, kind: DepKind) -> DepNode {
let popped_node = self.task_stack.pop().unwrap();
if let OpenTask::Anon {
read_set: _,
reads
} = popped_node {
let mut fingerprint = Fingerprint::zero();
let mut hasher = StableHasher::new();
for read in reads.iter() {
mem::discriminant(&read.kind).hash(&mut hasher);
// Fingerprint::combine() is faster than sending Fingerprint
// through the StableHasher (at least as long as StableHasher
// is so slow).
fingerprint = fingerprint.combine(read.hash);
}
fingerprint = fingerprint.combine(hasher.finish());
let target_dep_node = DepNode {
kind,
hash: fingerprint,
};
if self.indices.contains_key(&target_dep_node) {
return target_dep_node;
}
let target_id = self.get_or_create_node(target_dep_node);
for read in reads.into_iter() {
let source_id = self.get_or_create_node(read);
self.edges.insert((source_id, target_id));
}
target_dep_node
} else {
bug!("pop_anon_task() - Expected anonymous task to be popped")
}
}
/// Indicates that the current task `C` reads `v` by adding an
/// edge from `v` to `C`. If there is no current task, has no
/// effect. Note that *reading* from tracked state is harmless if
@ -138,6 +196,14 @@ impl DepGraphEdges {
}
}
}
Some(&mut OpenTask::Anon {
ref mut reads,
ref mut read_set,
}) => {
if read_set.insert(source) {
reads.push(source);
}
}
Some(&mut OpenTask::Ignore) | None => {
// ignore
}

View File

@ -13,7 +13,7 @@ use session::config::OutputType;
use std::cell::{Ref, RefCell};
use std::rc::Rc;
use super::dep_node::{DepNode, WorkProductId};
use super::dep_node::{DepNode, DepKind, WorkProductId};
use super::query::DepGraphQuery;
use super::raii;
use super::safe::DepGraphSafe;
@ -115,6 +115,21 @@ impl DepGraph {
task(cx, arg)
}
/// Execute something within an "anonymous" task, that is, a task the
/// DepNode of which is determined by the list of inputs it read from.
pub fn with_anon_task<OP,R>(&self, dep_kind: DepKind, op: OP) -> (R, DepNode)
where OP: FnOnce() -> R
{
if let Some(ref data) = self.data {
data.edges.borrow_mut().push_anon_task();
let result = op();
let dep_node = data.edges.borrow_mut().pop_anon_task(dep_kind);
(result, dep_node)
} else {
(op(), DepNode::new_no_params(DepKind::Krate))
}
}
#[inline]
pub fn read(&self, v: DepNode) {
if let Some(ref data) = self.data {