This commit is contained in:
David Ungar
2019-01-28 15:56:18 -08:00
parent fc4b7963ee
commit 14ba2a1b60
7 changed files with 142 additions and 119 deletions

View File

@@ -459,12 +459,14 @@ public:
} }
bool operator!=(const DependencyKey &rhs) const { return !(*this == rhs); } bool operator!=(const DependencyKey &rhs) const { return !(*this == rhs); }
/// Return true if this key can be recorded as a use of def. /// Return true if this key can be recorded as a use of def.
/// If everything is the same except for aspect, it's tricky: /// If everything is the same except for aspect, it's tricky:
/// The implementation does not depend on the interface; it's the other way around. /// The implementation does not depend on the interface; it's the other way
/// around.
bool canDependUpon(const DependencyKey &def) const { bool canDependUpon(const DependencyKey &def) const {
if (getKind() != def.getKind() || getContext() != def.getContext() || getName() != def.getName()) if (getKind() != def.getKind() || getContext() != def.getContext() ||
getName() != def.getName())
return true; return true;
if (getAspect() == def.getAspect()) if (getAspect() == def.getAspect())
return false; return false;
@@ -664,7 +666,8 @@ public:
bool operator==(const SourceFileDepGraphNode &other) const { bool operator==(const SourceFileDepGraphNode &other) const {
return DepGraphNode::operator==(other) && return DepGraphNode::operator==(other) &&
sequenceNumber == other.sequenceNumber && sequenceNumber == other.sequenceNumber &&
defsIDependUpon == other.defsIDependUpon && isProvides == other.isProvides; defsIDependUpon == other.defsIDependUpon &&
isProvides == other.isProvides;
} }
size_t getSequenceNumber() const { return sequenceNumber; } size_t getSequenceNumber() const { return sequenceNumber; }
@@ -755,8 +758,9 @@ public:
const SourceFileDepGraphNode *use)> const SourceFileDepGraphNode *use)>
fn) const; fn) const;
void forEachDefDependedUponBy(const SourceFileDepGraphNode *n, void forEachDefDependedUponBy(
function_ref<void(SourceFileDepGraphNode *)> fn) const { const SourceFileDepGraphNode *n,
function_ref<void(SourceFileDepGraphNode *)> fn) const {
n->forEachDefIDependUpon([&](size_t useIndex) { fn(getNode(useIndex)); }); n->forEachDefIDependUpon([&](size_t useIndex) { fn(getNode(useIndex)); });
} }
@@ -773,7 +777,8 @@ public:
/// \p Use is the Node that must be rebuilt when \p def changes. /// \p Use is the Node that must be rebuilt when \p def changes.
/// Record that fact in the graph. /// Record that fact in the graph.
void addArc(SourceFileDepGraphNode *def, SourceFileDepGraphNode *use) { void addArc(SourceFileDepGraphNode *def, SourceFileDepGraphNode *use) {
getNode(use->getSequenceNumber())->addDefIDependUpon(def->getSequenceNumber()); getNode(use->getSequenceNumber())
->addDefIDependUpon(def->getSequenceNumber());
} }
/// Read a swiftdeps file at \p path and return a SourceFileDepGraph if /// Read a swiftdeps file at \p path and return a SourceFileDepGraph if

View File

@@ -161,10 +161,11 @@ protected:
const void *node, MarkTracerImpl *tracer = nullptr); const void *node, MarkTracerImpl *tracer = nullptr);
bool markIntransitive(const void *node) { bool markIntransitive(const void *node) {
assert(Provides.count(node) && "node is not in the graph"); assert(Provides.count(node) && "node is not in the graph");
// const driver::Job *HERE = (const driver::Job*)node; // const driver::Job *HERE = (const driver::Job*)node;
// StringRef HERE1 = llvm::sys::path::filename(HERE->getOutput().getBaseInput(0)); // StringRef HERE1 =
// if (HERE1 == "Calendars.swift") // llvm::sys::path::filename(HERE->getOutput().getBaseInput(0)); if
// llvm::errs() << "HERE10\n"; // (HERE1 == "Calendars.swift")
// llvm::errs() << "HERE10\n";
return Marked.insert(node).second; return Marked.insert(node).second;
} }

View File

@@ -150,7 +150,7 @@ class ModuleDepGraph {
/// source file.) /// source file.)
/// Tracks def-use relationships by DependencyKey. /// Tracks def-use relationships by DependencyKey.
std::unordered_map<DependencyKey, std::unordered_set<ModuleDepGraphNode*>> std::unordered_map<DependencyKey, std::unordered_set<ModuleDepGraphNode *>>
usesByDef; usesByDef;
// Supports requests from the driver to getExternalDependencies. // Supports requests from the driver to getExternalDependencies.
@@ -192,7 +192,8 @@ class ModuleDepGraph {
Optional<std::vector<const ModuleDepGraphNode *>> currentPathIfTracing; Optional<std::vector<const ModuleDepGraphNode *>> currentPathIfTracing;
/// If tracing dependencies, record the node sequence /// If tracing dependencies, record the node sequence
std::unordered_multimap<const driver::Job*, std::vector<const ModuleDepGraphNode *>> std::unordered_multimap<const driver::Job *,
std::vector<const ModuleDepGraphNode *>>
dependencyPathsToJobs; dependencyPathsToJobs;
/// For helping with performance tuning, may be null: /// For helping with performance tuning, may be null:
@@ -289,13 +290,16 @@ public:
/// Interface to status quo code in the driver. /// Interface to status quo code in the driver.
bool isMarked(const driver::Job *) const; bool isMarked(const driver::Job *) const;
/// Given a "cascading" job, that is a job whose dependents must be recompiled when this job is recompiled, /// Given a "cascading" job, that is a job whose dependents must be recompiled
/// Compute two sets of jobs: /// when this job is recompiled, Compute two sets of jobs:
/// 1. Return value (via visited) is the set of jobs needing recompilation after this one, and /// 1. Return value (via visited) is the set of jobs needing recompilation
/// 2. Jobs not previously known to need dependencies reexamined after they are recompiled. /// after this one, and
/// Such jobs are added to the \ref cascadingJobs set, and accessed via \ref isMarked. /// 2. Jobs not previously known to need dependencies reexamined after they
void markTransitive(SmallVectorImpl<const driver::Job *> &consequentJobsToRecompile, /// are recompiled. Such jobs are added to the \ref cascadingJobs set, and
const driver::Job *jobToBeRecompiled, const void *ignored = nullptr); /// accessed via \ref isMarked.
void markTransitive(
SmallVectorImpl<const driver::Job *> &consequentJobsToRecompile,
const driver::Job *jobToBeRecompiled, const void *ignored = nullptr);
/// "Mark" this node only. /// "Mark" this node only.
bool markIntransitive(const driver::Job *); bool markIntransitive(const driver::Job *);
@@ -349,7 +353,7 @@ private:
void verifyCanFindEachJob() const; void verifyCanFindEachJob() const;
void verifyEachJobInGraphIsTracked() const; void verifyEachJobInGraphIsTracked() const;
static bool mapCorruption(const char *msg) { llvm_unreachable(msg); } static bool mapCorruption(const char *msg) { llvm_unreachable(msg); }
/// Use the known swiftDeps to find a directory for /// Use the known swiftDeps to find a directory for
@@ -366,44 +370,44 @@ private:
/// Integrate a SourceFileDepGraph into the receiver. /// Integrate a SourceFileDepGraph into the receiver.
/// Integration happens when the driver needs to read SourceFileDepGraph. /// Integration happens when the driver needs to read SourceFileDepGraph.
DependencyGraphImpl::LoadResult integrate(const SourceFileDepGraph &); DependencyGraphImpl::LoadResult integrate(const SourceFileDepGraph &);
enum class LocationOfPreexistingNode { enum class LocationOfPreexistingNode { nowhere, here, elsewhere };
nowhere, here, elsewhere
}; typedef Optional<std::pair<LocationOfPreexistingNode, ModuleDepGraphNode *>>
PreexistingNodeIfAny;
typedef Optional<std::pair<LocationOfPreexistingNode, ModuleDepGraphNode *>> PreexistingNodeIfAny;
/// Find the preexisting node here that best matches the integrand. /// Find the preexisting node here that best matches the integrand.
PreexistingNodeIfAny PreexistingNodeIfAny
findPreexistingMatch(StringRef swiftDepsOfCompilationToBeIntegrated, findPreexistingMatch(StringRef swiftDepsOfCompilationToBeIntegrated,
const SourceFileDepGraphNode *integrand); const SourceFileDepGraphNode *integrand);
/// Integrate the \p integrand into the receiver. /// Integrate the \p integrand into the receiver.
/// Return a bool indicating if this node represents a change that must be /// Return a bool indicating if this node represents a change that must be
/// propagated. /// propagated.
bool integrateSourceFileDepGraphNode( bool
const SourceFileDepGraph &g, integrateSourceFileDepGraphNode(const SourceFileDepGraph &g,
const SourceFileDepGraphNode *integrand, const SourceFileDepGraphNode *integrand,
const PreexistingNodeIfAny preexistingMatch); const PreexistingNodeIfAny preexistingMatch);
/// Integrate the \p integrand, a node that represents a Decl in the swiftDeps /// Integrate the \p integrand, a node that represents a Decl in the swiftDeps
/// file being integrated. \p preexistingNodeInPlace holds the node /// file being integrated. \p preexistingNodeInPlace holds the node
/// representing the same Decl that already exists, if there is one. \p /// representing the same Decl that already exists, if there is one. \p
/// prexisintExpat holds a node with the same key that already exists, but was /// prexisintExpat holds a node with the same key that already exists, but was
/// not known to reside in any swiftDeps file. Return a bool indicating if this node represents a change that must be /// not known to reside in any swiftDeps file. Return a bool indicating if
/// propagated, and the integrated ModuleDepGraphNode. /// this node represents a change that must be propagated, and the integrated
std::pair<bool, ModuleDepGraphNode*> integrateSourceFileDeclNode( /// ModuleDepGraphNode.
const SourceFileDepGraphNode *integrand, std::pair<bool, ModuleDepGraphNode *>
StringRef swiftDepsOfSourceFileGraph, integrateSourceFileDeclNode(const SourceFileDepGraphNode *integrand,
const PreexistingNodeIfAny preexistingMatch); StringRef swiftDepsOfSourceFileGraph,
const PreexistingNodeIfAny preexistingMatch);
/// Create a brand-new ModuleDepGraphNode to integrate \p integrand. /// Create a brand-new ModuleDepGraphNode to integrate \p integrand.
ModuleDepGraphNode * ModuleDepGraphNode *
integrateByCreatingANewNode(const SourceFileDepGraphNode *integrand, integrateByCreatingANewNode(const SourceFileDepGraphNode *integrand,
Optional<std::string> swiftDepsForNewNode); Optional<std::string> swiftDepsForNewNode);
/// After importing a provides node from the frontend, record its dependencies. /// After importing a provides node from the frontend, record its
/// dependencies.
void recordWhatUseDependsUpon(const SourceFileDepGraph &g, void recordWhatUseDependsUpon(const SourceFileDepGraph &g,
const SourceFileDepGraphNode *sourceFileUseNode, const SourceFileDepGraphNode *sourceFileUseNode,
ModuleDepGraphNode *moduleUseNode); ModuleDepGraphNode *moduleUseNode);
@@ -415,24 +419,25 @@ private:
/// Given a definition node, and a list of already found dependents, /// Given a definition node, and a list of already found dependents,
/// recursively add transitive closure of dependents of the definition /// recursively add transitive closure of dependents of the definition
/// into the already found dependents. /// into the already found dependents.
/// Also record any dependents that "cascade", i.e. whose dependencies must be recomputed after recompilation so that its dependents can be recompiled. /// Also record any dependents that "cascade", i.e. whose dependencies must be
/// recomputed after recompilation so that its dependents can be recompiled.
void findDependentNodesAndRecordCascadingOnes( void findDependentNodesAndRecordCascadingOnes(
std::unordered_set<const ModuleDepGraphNode *> &foundDependents, std::unordered_set<const ModuleDepGraphNode *> &foundDependents,
const ModuleDepGraphNode *definition); const ModuleDepGraphNode *definition);
void computeUniqueJobsFromNodes( void computeUniqueJobsFromNodes(
SmallVectorImpl<const driver::Job *> &uniqueJobs, SmallVectorImpl<const driver::Job *> &uniqueJobs,
const std::unordered_set<const ModuleDepGraphNode *> &nodes); const std::unordered_set<const ModuleDepGraphNode *> &nodes);
/// Record a visit to this node for later dependency printing /// Record a visit to this node for later dependency printing
size_t traceArrival(const ModuleDepGraphNode *visitedNode); size_t traceArrival(const ModuleDepGraphNode *visitedNode);
/// Record end of visit to this node. /// Record end of visit to this node.
void traceDeparture(size_t pathLengthAfterArrival); void traceDeparture(size_t pathLengthAfterArrival);
/// For printing why a Job was compiled, record how it was found.
void recordDependencyPathToJob(const std::vector<const ModuleDepGraphNode *> &pathToJob, const driver::Job* dependentJob);
/// For printing why a Job was compiled, record how it was found.
void recordDependencyPathToJob(
const std::vector<const ModuleDepGraphNode *> &pathToJob,
const driver::Job *dependentJob);
/// Return true if job did not cascade before /// Return true if job did not cascade before
bool rememberThatJobCascades(StringRef swiftDeps) { bool rememberThatJobCascades(StringRef swiftDeps) {

View File

@@ -69,7 +69,7 @@ void SourceFileDepGraph::forEachArc(
const SourceFileDepGraphNode *use)> const SourceFileDepGraphNode *use)>
fn) const { fn) const {
forEachNode([&](const SourceFileDepGraphNode *useNode) { forEachNode([&](const SourceFileDepGraphNode *useNode) {
forEachDefDependedUponBy(useNode, [&](SourceFileDepGraphNode* defNode) { forEachDefDependedUponBy(useNode, [&](SourceFileDepGraphNode *defNode) {
fn(defNode, useNode); fn(defNode, useNode);
}); });
}); });
@@ -306,7 +306,8 @@ void MappingContextTraits<SourceFileDepGraphNode, SourceFileDepGraph>::mapping(
IO &io, SourceFileDepGraphNode &node, SourceFileDepGraph &g) { IO &io, SourceFileDepGraphNode &node, SourceFileDepGraph &g) {
MappingTraits<DepGraphNode>::mapping(io, node); MappingTraits<DepGraphNode>::mapping(io, node);
io.mapRequired("sequenceNumber", node.sequenceNumber); io.mapRequired("sequenceNumber", node.sequenceNumber);
std::vector<size_t> defsIDependUponVec(node.defsIDependUpon.begin(), node.defsIDependUpon.end()); std::vector<size_t> defsIDependUponVec(node.defsIDependUpon.begin(),
node.defsIDependUpon.end());
io.mapRequired("defsIDependUpon", defsIDependUponVec); io.mapRequired("defsIDependUpon", defsIDependUponVec);
io.mapRequired("isProvides", node.isProvides); io.mapRequired("isProvides", node.isProvides);
if (!io.outputting()) { if (!io.outputting()) {

View File

@@ -413,8 +413,7 @@ namespace driver {
int ReturnCode, int ReturnCode,
SmallVector<const Job *, N> &Dependents, SmallVector<const Job *, N> &Dependents,
DependencyGraphT &DepGraph) { DependencyGraphT &DepGraph) {
const CommandOutput &Output = FinishedCmd->getOutput(); const CommandOutput &Output = FinishedCmd->getOutput();
StringRef DependenciesFile = StringRef DependenciesFile =
Output.getAdditionalOutputForType(file_types::TY_SwiftDeps); Output.getAdditionalOutputForType(file_types::TY_SwiftDeps);
@@ -439,10 +438,11 @@ namespace driver {
// things that do not need to be marked. Unecessary compilation would // things that do not need to be marked. Unecessary compilation would
// result if that were the case. // result if that were the case.
bool wasCascading = DepGraph.isMarked(FinishedCmd); bool wasCascading = DepGraph.isMarked(FinishedCmd);
if (wasCascading && Comp.getShowIncrementalBuildDecisions()) if (wasCascading && Comp.getShowIncrementalBuildDecisions())
llvm::outs() << "HERE cascading: " << LogJob(FinishedCmd) << "\n"; llvm::outs() << "HERE cascading: " << LogJob(FinishedCmd) << "\n";
const driver::Job *HERE = (const driver::Job*)FinishedCmd; const driver::Job *HERE = (const driver::Job *)FinishedCmd;
StringRef HERE1 = llvm::sys::path::filename(HERE->getOutput().getBaseInput(0)); StringRef HERE1 =
llvm::sys::path::filename(HERE->getOutput().getBaseInput(0));
if (HERE1 == "Calendars.swift") if (HERE1 == "Calendars.swift")
llvm::errs() << "HERE10\n"; llvm::errs() << "HERE10\n";

View File

@@ -311,28 +311,29 @@ void DependencyGraphImpl::markExternal(SmallVectorImpl<const void *> &visited,
} }
} }
//HERE // HERE
#include "swift/Driver/Job.h" #include "swift/Driver/Job.h"
#include "llvm/Support/Path.h"
#include "llvm/Option/Arg.h" #include "llvm/Option/Arg.h"
#include "llvm/Support/Path.h"
void void
DependencyGraphImpl::markTransitive(SmallVectorImpl<const void *> &visited, DependencyGraphImpl::markTransitive(SmallVectorImpl<const void *> &visited,
const void *node, MarkTracerImpl *tracer) { const void *node, MarkTracerImpl *tracer) {
const driver::Job *HERE = (const driver::Job*)node; const driver::Job *HERE = (const driver::Job *)node;
StringRef HERE1 = llvm::sys::path::filename(HERE->getOutput().getBaseInput(0)); StringRef HERE1 =
llvm::sys::path::filename(HERE->getOutput().getBaseInput(0));
if (HERE1 == "Calendars.swift") if (HERE1 == "Calendars.swift")
llvm::errs() << "HERE2\n"; llvm::errs() << "HERE2\n";
const driver::InputAction *IA = dyn_cast<driver::InputAction>(HERE->getSource().getInputs().front()); const driver::InputAction *IA =
dyn_cast<driver::InputAction>(HERE->getSource().getInputs().front());
auto HERE2 = llvm::sys::path::filename(IA->getInputArg().getValue()); auto HERE2 = llvm::sys::path::filename(IA->getInputArg().getValue());
if (HERE2 == "Calendars.swift") if (HERE2 == "Calendars.swift")
llvm::errs() << "HERE3\n"; llvm::errs() << "HERE3\n";
// StringRef HERE3 = HERE->getInputs().front()->getOutput().getPrimaryOutputFilenames().front(); // StringRef HERE3 =
// if (HERE3 == "Calendars.swift") // HERE->getInputs().front()->getOutput().getPrimaryOutputFilenames().front();
// llvm::errs() << "HERE3\n"; // if (HERE3 == "Calendars.swift")
// llvm::errs() << "HERE3\n";
assert(Provides.count(node) && "node is not in the graph"); assert(Provides.count(node) && "node is not in the graph");
llvm::SpecificBumpPtrAllocator<MarkTracerImpl::Entry> scratchAlloc; llvm::SpecificBumpPtrAllocator<MarkTracerImpl::Entry> scratchAlloc;

View File

@@ -79,23 +79,26 @@ bool ModuleDepGraph::isMarked(const Job *cmd) const {
return cascadingJobs.count(getSwiftDeps(cmd)); return cascadingJobs.count(getSwiftDeps(cmd));
} }
void ModuleDepGraph::markTransitive(SmallVectorImpl<const Job *> &consequentJobsToRecompile, void ModuleDepGraph::markTransitive(
const Job *jobToBeRecompiled, const void *ignored) { SmallVectorImpl<const Job *> &consequentJobsToRecompile,
const Job *jobToBeRecompiled, const void *ignored) {
FrontendStatsTracer tracer(stats, "experimental-dependencies-markTransitive"); FrontendStatsTracer tracer(stats, "experimental-dependencies-markTransitive");
std::unordered_set<const ModuleDepGraphNode *> dependentNodes; std::unordered_set<const ModuleDepGraphNode *> dependentNodes;
const StringRef swiftDepsToBeRecompiled = getSwiftDeps(jobToBeRecompiled); const StringRef swiftDepsToBeRecompiled = getSwiftDeps(jobToBeRecompiled);
// Do the traversal. // Do the traversal.
for (auto &fileAndNode : nodeMap[swiftDepsToBeRecompiled]) { for (auto &fileAndNode : nodeMap[swiftDepsToBeRecompiled]) {
assert(isCurrentPathForTracingEmpty()); assert(isCurrentPathForTracingEmpty());
findDependentNodesAndRecordCascadingOnes(dependentNodes, fileAndNode.second); findDependentNodesAndRecordCascadingOnes(dependentNodes,
fileAndNode.second);
} }
computeUniqueJobsFromNodes(consequentJobsToRecompile, dependentNodes); computeUniqueJobsFromNodes(consequentJobsToRecompile, dependentNodes);
} }
void ModuleDepGraph::computeUniqueJobsFromNodes(SmallVectorImpl<const Job *> &jobs, void ModuleDepGraph::computeUniqueJobsFromNodes(
const std::unordered_set<const ModuleDepGraphNode *> &nodes) { SmallVectorImpl<const Job *> &jobs,
const std::unordered_set<const ModuleDepGraphNode *> &nodes) {
std::unordered_set<std::string> swiftDepsOfNodes; std::unordered_set<std::string> swiftDepsOfNodes;
for (const ModuleDepGraphNode *n : nodes) { for (const ModuleDepGraphNode *n : nodes) {
if (!n->getSwiftDeps().hasValue()) if (!n->getSwiftDeps().hasValue())
@@ -109,7 +112,6 @@ void ModuleDepGraph::computeUniqueJobsFromNodes(SmallVectorImpl<const Job *> &jo
} }
} }
bool ModuleDepGraph::markIntransitive(const Job *node) { bool ModuleDepGraph::markIntransitive(const Job *node) {
return rememberThatJobCascades(getSwiftDeps(node)); return rememberThatJobCascades(getSwiftDeps(node));
} }
@@ -162,11 +164,11 @@ LoadResult ModuleDepGraph::integrate(const SourceFileDepGraph &g) {
g.forEachNode([&](const SourceFileDepGraphNode *integrand) { g.forEachNode([&](const SourceFileDepGraphNode *integrand) {
const auto &key = integrand->getKey(); const auto &key = integrand->getKey();
auto preexistingMatch = findPreexistingMatch(swiftDeps, integrand); auto preexistingMatch = findPreexistingMatch(swiftDeps, integrand);
if (preexistingMatch.hasValue() && preexistingMatch.getValue().first == LocationOfPreexistingNode::here) if (preexistingMatch.hasValue() &&
preexistingMatch.getValue().first == LocationOfPreexistingNode::here)
disappearedNodes.erase(key); // Node was and still is. Do not erase it. disappearedNodes.erase(key); // Node was and still is. Do not erase it.
const bool changed = integrateSourceFileDepGraphNode(g, const bool changed =
integrand, integrateSourceFileDepGraphNode(g, integrand, preexistingMatch);
preexistingMatch);
if (changed) if (changed)
changedNodes.insert(key); changedNodes.insert(key);
}); });
@@ -182,71 +184,75 @@ LoadResult ModuleDepGraph::integrate(const SourceFileDepGraph &g) {
: LoadResult::AffectsDownstream; : LoadResult::AffectsDownstream;
} }
ModuleDepGraph::PreexistingNodeIfAny ModuleDepGraph::PreexistingNodeIfAny ModuleDepGraph::findPreexistingMatch(
ModuleDepGraph::findPreexistingMatch( StringRef swiftDepsOfCompilationToBeIntegrated,
StringRef swiftDepsOfCompilationToBeIntegrated, const SourceFileDepGraphNode *integrand) {
const SourceFileDepGraphNode *integrand) {
const auto &matches = nodeMap[integrand->getKey()]; const auto &matches = nodeMap[integrand->getKey()];
const auto &expatsIter = matches.find(""); const auto &expatsIter = matches.find("");
if (expatsIter != matches.end()) { if (expatsIter != matches.end()) {
assert(matches.size() == 1 && "If an expat exists, then must not be any matches in other files"); assert(matches.size() == 1 &&
return std::make_pair(LocationOfPreexistingNode::nowhere, expatsIter->second); "If an expat exists, then must not be any matches in other files");
return std::make_pair(LocationOfPreexistingNode::nowhere,
expatsIter->second);
} }
if (integrand->getIsProvides()) { if (integrand->getIsProvides()) {
const auto &preexistingNodeInPlaceIter = matches.find(swiftDepsOfCompilationToBeIntegrated); const auto &preexistingNodeInPlaceIter =
matches.find(swiftDepsOfCompilationToBeIntegrated);
if (preexistingNodeInPlaceIter != matches.end()) if (preexistingNodeInPlaceIter != matches.end())
return std::make_pair(LocationOfPreexistingNode::here, preexistingNodeInPlaceIter->second); return std::make_pair(LocationOfPreexistingNode::here,
preexistingNodeInPlaceIter->second);
} }
if (!matches.empty()) if (!matches.empty())
return std::make_pair(LocationOfPreexistingNode::elsewhere, matches.begin()->second); return std::make_pair(LocationOfPreexistingNode::elsewhere,
matches.begin()->second);
return None; return None;
} }
bool ModuleDepGraph::integrateSourceFileDepGraphNode( bool ModuleDepGraph::integrateSourceFileDepGraphNode(
const SourceFileDepGraph &g, const SourceFileDepGraph &g, const SourceFileDepGraphNode *integrand,
const SourceFileDepGraphNode *integrand,
const PreexistingNodeIfAny preexistingMatch) { const PreexistingNodeIfAny preexistingMatch) {
// Track externalDependencies so Compilation can check them. // Track externalDependencies so Compilation can check them.
if (integrand->getKey().getKind() == NodeKind::externalDepend) if (integrand->getKey().getKind() == NodeKind::externalDepend)
return externalDependencies.insert(integrand->getKey().getName()).second; return externalDependencies.insert(integrand->getKey().getName()).second;
if (integrand->isDepends()) if (integrand->isDepends())
return false; // dependency will be handled by the use node return false; // dependency will be handled by the use node
StringRef swiftDepsOfSourceFileGraph = g.getSwiftDepsFromSourceFileProvide(); StringRef swiftDepsOfSourceFileGraph = g.getSwiftDepsFromSourceFileProvide();
auto changedAndUseNode = integrateSourceFileDeclNode(integrand, swiftDepsOfSourceFileGraph, auto changedAndUseNode = integrateSourceFileDeclNode(
preexistingMatch); integrand, swiftDepsOfSourceFileGraph, preexistingMatch);
recordWhatUseDependsUpon(g, integrand, changedAndUseNode.second); recordWhatUseDependsUpon(g, integrand, changedAndUseNode.second);
return changedAndUseNode.first; return changedAndUseNode.first;
} }
std::pair<bool, ModuleDepGraphNode *>
std::pair<bool, ModuleDepGraphNode*> ModuleDepGraph::integrateSourceFileDeclNode( ModuleDepGraph::integrateSourceFileDeclNode(
const SourceFileDepGraphNode *integrand, const SourceFileDepGraphNode *integrand,
StringRef swiftDepsOfSourceFileGraph, StringRef swiftDepsOfSourceFileGraph,
const PreexistingNodeIfAny preexistingMatch) { const PreexistingNodeIfAny preexistingMatch) {
if (!preexistingMatch.hasValue()) { if (!preexistingMatch.hasValue()) {
auto *newNode = integrateByCreatingANewNode(integrand, swiftDepsOfSourceFileGraph.str()); auto *newNode = integrateByCreatingANewNode(
integrand, swiftDepsOfSourceFileGraph.str());
return std::make_pair(true, newNode); // New node return std::make_pair(true, newNode); // New node
} }
const auto where = preexistingMatch.getValue().first; const auto where = preexistingMatch.getValue().first;
auto *match = preexistingMatch.getValue().second; auto *match = preexistingMatch.getValue().second;
switch (where) { switch (where) {
case LocationOfPreexistingNode::here: case LocationOfPreexistingNode::here:
return std::make_pair(match->integrateFingerprintFrom(integrand), match); return std::make_pair(match->integrateFingerprintFrom(integrand), match);
case LocationOfPreexistingNode::nowhere:
// Some other file depended on this, but didn't know where it was.
moveNodeToDifferentFile(match, swiftDepsOfSourceFileGraph.str());
match->integrateFingerprintFrom(integrand);
return std::make_pair(true, match); // New Decl, assume changed
case LocationOfPreexistingNode::elsewhere: case LocationOfPreexistingNode::nowhere:
auto *newNode = integrateByCreatingANewNode(integrand, swiftDepsOfSourceFileGraph.str()); // Some other file depended on this, but didn't know where it was.
return std::make_pair(true, newNode); // New node; moveNodeToDifferentFile(match, swiftDepsOfSourceFileGraph.str());
match->integrateFingerprintFrom(integrand);
return std::make_pair(true, match); // New Decl, assume changed
case LocationOfPreexistingNode::elsewhere:
auto *newNode = integrateByCreatingANewNode(
integrand, swiftDepsOfSourceFileGraph.str());
return std::make_pair(true, newNode); // New node;
} }
llvm_unreachable("impossible"); llvm_unreachable("impossible");
} }
@@ -261,13 +267,14 @@ ModuleDepGraphNode *ModuleDepGraph::integrateByCreatingANewNode(
return newNode; return newNode;
} }
void ModuleDepGraph::recordWhatUseDependsUpon(const SourceFileDepGraph &g, void ModuleDepGraph::recordWhatUseDependsUpon(
const SourceFileDepGraphNode *sourceFileUseNode, const SourceFileDepGraph &g,
ModuleDepGraphNode *moduleUseNode) { const SourceFileDepGraphNode *sourceFileUseNode,
ModuleDepGraphNode *moduleUseNode) {
g.forEachDefDependedUponBy(sourceFileUseNode, g.forEachDefDependedUponBy(sourceFileUseNode,
[&](const SourceFileDepGraphNode *def) { [&](const SourceFileDepGraphNode *def) {
usesByDef[def->getKey()].insert(moduleUseNode); usesByDef[def->getKey()].insert(moduleUseNode);
}); });
} }
void ModuleDepGraph::removeNode(ModuleDepGraphNode *n) { void ModuleDepGraph::removeNode(ModuleDepGraphNode *n) {
@@ -309,7 +316,7 @@ void ModuleDepGraph::forEachArc(
for (const auto &defUse : usesByDef) for (const auto &defUse : usesByDef)
forEachMatchingNode(defUse.first, [&](const ModuleDepGraphNode *defNode) { forEachMatchingNode(defUse.first, [&](const ModuleDepGraphNode *defNode) {
for (const auto &useNode : defUse.second) for (const auto &useNode : defUse.second)
fn(defNode, useNode); fn(defNode, useNode);
}); });
} }
@@ -354,20 +361,23 @@ size_t ModuleDepGraph::traceArrival(const ModuleDepGraphNode *visitedNode) {
return 0; return 0;
auto &currentPath = currentPathIfTracing.getValue(); auto &currentPath = currentPathIfTracing.getValue();
recordDependencyPathToJob(currentPath, getJob(visitedNode->getSwiftDeps())); recordDependencyPathToJob(currentPath, getJob(visitedNode->getSwiftDeps()));
currentPath.push_back(visitedNode); currentPath.push_back(visitedNode);
return currentPath.size(); return currentPath.size();
} }
void ModuleDepGraph::recordDependencyPathToJob(const std::vector<const ModuleDepGraphNode *> &pathToJob, const driver::Job* dependentJob) { void ModuleDepGraph::recordDependencyPathToJob(
dependencyPathsToJobs.insert( std::make_pair(dependentJob, pathToJob) ); const std::vector<const ModuleDepGraphNode *> &pathToJob,
const driver::Job *dependentJob) {
dependencyPathsToJobs.insert(std::make_pair(dependentJob, pathToJob));
} }
void ModuleDepGraph::traceDeparture(size_t pathLengthAfterArrival) { void ModuleDepGraph::traceDeparture(size_t pathLengthAfterArrival) {
if (!currentPathIfTracing) if (!currentPathIfTracing)
return; return;
auto &currentPath = currentPathIfTracing.getValue(); auto &currentPath = currentPathIfTracing.getValue();
assert(pathLengthAfterArrival == currentPath.size() && "Path must be maintained throughout recursive visits."); assert(pathLengthAfterArrival == currentPath.size() &&
"Path must be maintained throughout recursive visits.");
currentPath.pop_back(); currentPath.pop_back();
} }