mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Refine Naive Dependency Collection Algorithm
Split off the notion of "recording" dependencies from the notion of "collecting" dependencies. This corrects an oversight in the previous design where dependency replay and recording were actually not "free" in WMO where we actually never track dependencies. This architecture also lays the groundwork for the removal of the referenced name trackers. The algorithm builds upon the infrastructure for dependency sources and sinks laid down during the cut over to request-based dependency tracking in #30723. The idea of the naive algorithm is this: For a chain of requests A -> B* -> C -> D* -> ... -> L where L is a lookup request and all starred requests are cached, once L writes into the dependency collector, the active stack is walked and at each cache-point the results of dependency collection are associated with the request itself (in this example, B* and D* have all the names L found associated with them). Subsequent evaluations of these cached requests (B* and D* et al) will then *replay* the previous lookup results from L into the active referenced name tracker. One complication is, suppose the evaluation of a cached request involves multiple downstream name lookups. More concretely, suppose we have the following request trace: A* -> B -> L | -> C -> L | -> D -> L | -> ... Then A* must see the union of the results of each L. If this reminds anyone of a union-find, that is no accident! A persistent union-find a la Conchon and Filliatre is probably in order to help bring down peak heap usage...
This commit is contained in:
@@ -225,7 +225,7 @@ class Evaluator {
|
|||||||
/// so all clients must cope with cycles.
|
/// so all clients must cope with cycles.
|
||||||
llvm::DenseMap<AnyRequest, std::vector<AnyRequest>> dependencies;
|
llvm::DenseMap<AnyRequest, std::vector<AnyRequest>> dependencies;
|
||||||
|
|
||||||
evaluator::DependencyCollector collector;
|
evaluator::DependencyRecorder recorder;
|
||||||
|
|
||||||
/// Retrieve the request function for the given zone and request IDs.
|
/// Retrieve the request function for the given zone and request IDs.
|
||||||
AbstractRequestFunction *getAbstractRequestFunction(uint8_t zoneID,
|
AbstractRequestFunction *getAbstractRequestFunction(uint8_t zoneID,
|
||||||
@@ -268,7 +268,7 @@ public:
|
|||||||
typename std::enable_if<Request::isEverCached>::type * = nullptr>
|
typename std::enable_if<Request::isEverCached>::type * = nullptr>
|
||||||
llvm::Expected<typename Request::OutputType>
|
llvm::Expected<typename Request::OutputType>
|
||||||
operator()(const Request &request) {
|
operator()(const Request &request) {
|
||||||
evaluator::DependencyCollector::StackRAII<Request> incDeps{collector,
|
evaluator::DependencyRecorder::StackRAII<Request> incDeps{recorder,
|
||||||
request};
|
request};
|
||||||
// The request can be cached, but check a predicate to determine
|
// The request can be cached, but check a predicate to determine
|
||||||
// whether this particular instance is cached. This allows more
|
// whether this particular instance is cached. This allows more
|
||||||
@@ -285,7 +285,7 @@ public:
|
|||||||
typename std::enable_if<!Request::isEverCached>::type * = nullptr>
|
typename std::enable_if<!Request::isEverCached>::type * = nullptr>
|
||||||
llvm::Expected<typename Request::OutputType>
|
llvm::Expected<typename Request::OutputType>
|
||||||
operator()(const Request &request) {
|
operator()(const Request &request) {
|
||||||
evaluator::DependencyCollector::StackRAII<Request> incDeps{collector,
|
evaluator::DependencyRecorder::StackRAII<Request> incDeps{recorder,
|
||||||
request};
|
request};
|
||||||
return getResultUncached(request);
|
return getResultUncached(request);
|
||||||
}
|
}
|
||||||
@@ -436,7 +436,7 @@ private:
|
|||||||
!Request::isDependencySink>::type * = nullptr>
|
!Request::isDependencySink>::type * = nullptr>
|
||||||
void reportEvaluatedResult(const Request &r,
|
void reportEvaluatedResult(const Request &r,
|
||||||
const typename Request::OutputType &o) {
|
const typename Request::OutputType &o) {
|
||||||
collector.replay(ActiveRequest(r));
|
recorder.replay(ActiveRequest(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report the result of evaluating a request that is a dependency sink.
|
// Report the result of evaluating a request that is a dependency sink.
|
||||||
@@ -444,7 +444,7 @@ private:
|
|||||||
typename std::enable_if<Request::isDependencySink>::type * = nullptr>
|
typename std::enable_if<Request::isDependencySink>::type * = nullptr>
|
||||||
void reportEvaluatedResult(const Request &r,
|
void reportEvaluatedResult(const Request &r,
|
||||||
const typename Request::OutputType &o) {
|
const typename Request::OutputType &o) {
|
||||||
return collector.record(activeRequests, [&r, &o](auto &c) {
|
return recorder.record(activeRequests, [&r, &o](auto &c) {
|
||||||
return r.writeDependencySink(c, o);
|
return r.writeDependencySink(c, o);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,13 +107,9 @@ inline DependencyScope getScopeForAccessLevel(AccessLevel l) {
|
|||||||
// of individual contexts.
|
// of individual contexts.
|
||||||
using DependencySource = llvm::PointerIntPair<SourceFile *, 1, DependencyScope>;
|
using DependencySource = llvm::PointerIntPair<SourceFile *, 1, DependencyScope>;
|
||||||
|
|
||||||
/// A \c DependencyCollector is an aggregator of named references discovered in a
|
struct DependencyRecorder;
|
||||||
/// particular \c DependencyScope during the course of request evaluation.
|
|
||||||
struct DependencyCollector {
|
|
||||||
private:
|
|
||||||
/// A stack of dependency sources in the order they were evaluated.
|
|
||||||
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;
|
|
||||||
|
|
||||||
|
struct DependencyCollector {
|
||||||
struct Reference {
|
struct Reference {
|
||||||
public:
|
public:
|
||||||
enum class Kind {
|
enum class Kind {
|
||||||
@@ -178,36 +174,11 @@ private:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
DependencyRecorder &parent;
|
||||||
enum class Mode {
|
|
||||||
// Enables the current "status quo" behavior of the dependency collector.
|
|
||||||
//
|
|
||||||
// By default, the dependency collector moves to register dependencies in
|
|
||||||
// the referenced name trackers at the top of the active dependency stack.
|
|
||||||
StatusQuo,
|
|
||||||
// Enables an experimental mode to only register private dependencies.
|
|
||||||
//
|
|
||||||
// This mode restricts the dependency collector to ignore changes of
|
|
||||||
// scope. This has practical effect of charging all unqualified lookups to
|
|
||||||
// the primary file being acted upon instead of to the destination file.
|
|
||||||
ExperimentalPrivateDependencies,
|
|
||||||
};
|
|
||||||
Mode mode;
|
|
||||||
llvm::DenseMap<AnyRequest, llvm::DenseSet<Reference, Reference::Info>>
|
|
||||||
requestReferences;
|
|
||||||
llvm::DenseSet<Reference, Reference::Info> scratch;
|
llvm::DenseSet<Reference, Reference::Info> scratch;
|
||||||
bool isRecording;
|
|
||||||
|
|
||||||
explicit DependencyCollector(Mode mode)
|
|
||||||
: mode{mode}, requestReferences{}, scratch{}, isRecording{false} {};
|
|
||||||
|
|
||||||
private:
|
|
||||||
void realizeOrRecord(const Reference &ref);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void replay(const swift::ActiveRequest &req);
|
explicit DependencyCollector(DependencyRecorder &parent) : parent(parent) {}
|
||||||
void record(const llvm::SetVector<swift::ActiveRequest> &stack,
|
|
||||||
llvm::function_ref<void(DependencyCollector &)> rec);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Registers a named reference from the current dependency scope to a member
|
/// Registers a named reference from the current dependency scope to a member
|
||||||
@@ -246,6 +217,50 @@ public:
|
|||||||
/// a name that is found by \c AnyObject lookup.
|
/// a name that is found by \c AnyObject lookup.
|
||||||
void addDynamicLookupName(DeclBaseName name);
|
void addDynamicLookupName(DeclBaseName name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const DependencyRecorder &getRecorder() const { return parent; }
|
||||||
|
bool empty() const { return scratch.empty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A \c DependencyCollector is an aggregator of named references discovered in a
|
||||||
|
/// particular \c DependencyScope during the course of request evaluation.
|
||||||
|
struct DependencyRecorder {
|
||||||
|
friend DependencyCollector;
|
||||||
|
private:
|
||||||
|
/// A stack of dependency sources in the order they were evaluated.
|
||||||
|
llvm::SmallVector<evaluator::DependencySource, 8> dependencySources;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Mode {
|
||||||
|
// Enables the current "status quo" behavior of the dependency collector.
|
||||||
|
//
|
||||||
|
// By default, the dependency collector moves to register dependencies in
|
||||||
|
// the referenced name trackers at the top of the active dependency stack.
|
||||||
|
StatusQuo,
|
||||||
|
// Enables an experimental mode to only register private dependencies.
|
||||||
|
//
|
||||||
|
// This mode restricts the dependency collector to ignore changes of
|
||||||
|
// scope. This has practical effect of charging all unqualified lookups to
|
||||||
|
// the primary file being acted upon instead of to the destination file.
|
||||||
|
ExperimentalPrivateDependencies,
|
||||||
|
};
|
||||||
|
Mode mode;
|
||||||
|
llvm::DenseMap<AnyRequest, llvm::DenseSet<DependencyCollector::Reference,
|
||||||
|
DependencyCollector::Reference::Info>>
|
||||||
|
requestReferences;
|
||||||
|
bool isRecording;
|
||||||
|
|
||||||
|
explicit DependencyRecorder(Mode mode)
|
||||||
|
: mode{mode}, requestReferences{}, isRecording{false} {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void realize(const DependencyCollector::Reference &ref);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void replay(const swift::ActiveRequest &req);
|
||||||
|
void record(const llvm::SetVector<swift::ActiveRequest> &stack,
|
||||||
|
llvm::function_ref<void(DependencyCollector &)> rec);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Returns the scope of the current active scope.
|
/// Returns the scope of the current active scope.
|
||||||
///
|
///
|
||||||
@@ -275,14 +290,14 @@ public:
|
|||||||
/// dependency source stack. It is specialized to be zero-cost for
|
/// dependency source stack. It is specialized to be zero-cost for
|
||||||
/// requests that are not dependency sources.
|
/// requests that are not dependency sources.
|
||||||
template <typename Request, typename = detail::void_t<>> struct StackRAII {
|
template <typename Request, typename = detail::void_t<>> struct StackRAII {
|
||||||
StackRAII(DependencyCollector &DC, const Request &Req) {}
|
StackRAII(DependencyRecorder &DR, const Request &Req) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Request>
|
template <typename Request>
|
||||||
struct StackRAII<Request,
|
struct StackRAII<Request,
|
||||||
typename std::enable_if<Request::isDependencySource>::type> {
|
typename std::enable_if<Request::isDependencySource>::type> {
|
||||||
NullablePtr<DependencyCollector> Coll;
|
NullablePtr<DependencyRecorder> Coll;
|
||||||
StackRAII(DependencyCollector &coll, const Request &Req) {
|
StackRAII(DependencyRecorder &coll, const Request &Req) {
|
||||||
auto Source = Req.readDependencySource(coll);
|
auto Source = Req.readDependencySource(coll);
|
||||||
// If there is no source to introduce, bail. This can occur if
|
// If there is no source to introduce, bail. This can occur if
|
||||||
// a request originates in the context of a module.
|
// a request originates in the context of a module.
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies.
|
// Incremental dependencies.
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IRGenWholeModuleRequest
|
class IRGenWholeModuleRequest
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies
|
// Incremental dependencies
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &e) const;
|
readDependencySource(const evaluator::DependencyRecorder &e) const;
|
||||||
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
||||||
ArrayRef<ProtocolDecl *> result) const;
|
ArrayRef<ProtocolDecl *> result) const;
|
||||||
};
|
};
|
||||||
@@ -330,7 +330,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies.
|
// Incremental dependencies.
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GenericParamListRequest :
|
class GenericParamListRequest :
|
||||||
@@ -434,7 +434,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies
|
// Incremental dependencies
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
||||||
LookupResult res) const;
|
LookupResult res) const;
|
||||||
};
|
};
|
||||||
@@ -506,7 +506,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies
|
// Incremental dependencies
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
||||||
QualifiedLookupResult lookupResult) const;
|
QualifiedLookupResult lookupResult) const;
|
||||||
};
|
};
|
||||||
@@ -533,7 +533,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies.
|
// Incremental dependencies.
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The input type for a direct lookup request.
|
/// The input type for a direct lookup request.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
void simple_display(llvm::raw_ostream &out,
|
void simple_display(llvm::raw_ostream &out,
|
||||||
@@ -125,7 +125,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The zone number for the parser.
|
/// The zone number for the parser.
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies.
|
// Incremental dependencies.
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parses a .sil file into a SILModule.
|
/// Parses a .sil file into a SILModule.
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ SourceLoc extractNearestSourceLoc(const std::tuple<First, Rest...> &value) {
|
|||||||
/// the 3 caching kinds defined above.
|
/// the 3 caching kinds defined above.
|
||||||
/// \code
|
/// \code
|
||||||
/// evaluator::DependencySource
|
/// evaluator::DependencySource
|
||||||
/// readDependencySource(const evaluator::DependencyCollector &) const;
|
/// readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
///
|
||||||
/// Requests that define dependency sinks should instead override
|
/// Requests that define dependency sinks should instead override
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies
|
// Incremental dependencies
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &e) const;
|
readDependencySource(const evaluator::DependencyRecorder &e) const;
|
||||||
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
||||||
Type t) const;
|
Type t) const;
|
||||||
};
|
};
|
||||||
@@ -893,7 +893,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies.
|
// Incremental dependencies.
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Request to obtain a list of stored properties in a nominal type.
|
/// Request to obtain a list of stored properties in a nominal type.
|
||||||
@@ -2034,7 +2034,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies.
|
// Incremental dependencies.
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &) const;
|
readDependencySource(const evaluator::DependencyRecorder &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Computes whether the specified type or a super-class/super-protocol has the
|
/// Computes whether the specified type or a super-class/super-protocol has the
|
||||||
@@ -2277,7 +2277,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
// Incremental dependencies
|
// Incremental dependencies
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &eval) const;
|
readDependencySource(const evaluator::DependencyRecorder &eval) const;
|
||||||
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
||||||
ProtocolConformanceLookupResult r) const;
|
ProtocolConformanceLookupResult r) const;
|
||||||
};
|
};
|
||||||
@@ -2305,7 +2305,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
readDependencySource(const evaluator::DependencyCollector &eval) const;
|
readDependencySource(const evaluator::DependencyRecorder &eval) const;
|
||||||
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
void writeDependencySink(evaluator::DependencyCollector &tracker,
|
||||||
evaluator::SideEffect) const;
|
evaluator::SideEffect) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,12 +61,13 @@ void Evaluator::registerRequestFunctions(
|
|||||||
requestFunctionsByZone.push_back({zoneID, functions});
|
requestFunctionsByZone.push_back({zoneID, functions});
|
||||||
}
|
}
|
||||||
|
|
||||||
static evaluator::DependencyCollector::Mode
|
static evaluator::DependencyRecorder::Mode
|
||||||
computeDependencyModeFromFlags(bool enableExperimentalPrivateDeps) {
|
computeDependencyModeFromFlags(bool enableExperimentalPrivateDeps) {
|
||||||
using Mode = evaluator::DependencyCollector::Mode;
|
using Mode = evaluator::DependencyRecorder::Mode;
|
||||||
if (enableExperimentalPrivateDeps) {
|
if (enableExperimentalPrivateDeps) {
|
||||||
return Mode::ExperimentalPrivateDependencies;
|
return Mode::ExperimentalPrivateDependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Mode::StatusQuo;
|
return Mode::StatusQuo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,8 +76,7 @@ Evaluator::Evaluator(DiagnosticEngine &diags, bool debugDumpCycles,
|
|||||||
bool enableExperimentalPrivateDeps)
|
bool enableExperimentalPrivateDeps)
|
||||||
: diags(diags), debugDumpCycles(debugDumpCycles),
|
: diags(diags), debugDumpCycles(debugDumpCycles),
|
||||||
buildDependencyGraph(buildDependencyGraph),
|
buildDependencyGraph(buildDependencyGraph),
|
||||||
collector{computeDependencyModeFromFlags(enableExperimentalPrivateDeps)} {
|
recorder{computeDependencyModeFromFlags(enableExperimentalPrivateDeps)} {}
|
||||||
}
|
|
||||||
|
|
||||||
void Evaluator::emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath) {
|
void Evaluator::emitRequestEvaluatorGraphViz(llvm::StringRef graphVizPath) {
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
@@ -379,32 +379,27 @@ void Evaluator::dumpDependenciesGraphviz() const {
|
|||||||
printDependenciesGraphviz(llvm::dbgs());
|
printDependenciesGraphviz(llvm::dbgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluator::DependencyCollector::realizeOrRecord(const Reference &ref) {
|
void evaluator::DependencyRecorder::realize(
|
||||||
if (isRecording) {
|
const DependencyCollector::Reference &ref) {
|
||||||
scratch.insert(std::move(ref));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *tracker = getActiveDependencyTracker();
|
auto *tracker = getActiveDependencyTracker();
|
||||||
if (!tracker) {
|
assert(tracker && "cannot realize dependency without name tracker!");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
using Kind = evaluator::DependencyCollector::Reference::Kind;
|
||||||
switch (ref.kind) {
|
switch (ref.kind) {
|
||||||
case Reference::Kind::Empty:
|
case Kind::Empty:
|
||||||
case Reference::Kind::Tombstone:
|
case Kind::Tombstone:
|
||||||
llvm_unreachable("cannot record empty dependency");
|
llvm_unreachable("cannot record empty dependency");
|
||||||
case Reference::Kind::UsedMember:
|
case Kind::UsedMember:
|
||||||
tracker->addUsedMember({ref.subject, ref.name}, isActiveSourceCascading());
|
tracker->addUsedMember({ref.subject, ref.name}, isActiveSourceCascading());
|
||||||
break;
|
break;
|
||||||
case Reference::Kind::PotentialMember:
|
case Kind::PotentialMember:
|
||||||
tracker->addUsedMember({ref.subject, Identifier()},
|
tracker->addUsedMember({ref.subject, Identifier()},
|
||||||
isActiveSourceCascading());
|
isActiveSourceCascading());
|
||||||
break;
|
break;
|
||||||
case Reference::Kind::TopLevel:
|
case Kind::TopLevel:
|
||||||
tracker->addTopLevelName(ref.name, isActiveSourceCascading());
|
tracker->addTopLevelName(ref.name, isActiveSourceCascading());
|
||||||
break;
|
break;
|
||||||
case Reference::Kind::Dynamic:
|
case Kind::Dynamic:
|
||||||
tracker->addDynamicLookupName(ref.name, isActiveSourceCascading());
|
tracker->addDynamicLookupName(ref.name, isActiveSourceCascading());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -412,33 +407,55 @@ void evaluator::DependencyCollector::realizeOrRecord(const Reference &ref) {
|
|||||||
|
|
||||||
void evaluator::DependencyCollector::addUsedMember(NominalTypeDecl *subject,
|
void evaluator::DependencyCollector::addUsedMember(NominalTypeDecl *subject,
|
||||||
DeclBaseName name) {
|
DeclBaseName name) {
|
||||||
return realizeOrRecord(Reference::usedMember(subject, name));
|
if (parent.mode ==
|
||||||
|
DependencyRecorder::Mode::ExperimentalPrivateDependencies) {
|
||||||
|
scratch.insert(Reference::usedMember(subject, name));
|
||||||
|
}
|
||||||
|
return parent.realize(Reference::usedMember(subject, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluator::DependencyCollector::addPotentialMember(
|
void evaluator::DependencyCollector::addPotentialMember(
|
||||||
NominalTypeDecl *subject) {
|
NominalTypeDecl *subject) {
|
||||||
return realizeOrRecord(Reference::potentialMember(subject));
|
if (parent.mode ==
|
||||||
|
DependencyRecorder::Mode::ExperimentalPrivateDependencies) {
|
||||||
|
scratch.insert(Reference::potentialMember(subject));
|
||||||
|
}
|
||||||
|
return parent.realize(Reference::potentialMember(subject));
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluator::DependencyCollector::addTopLevelName(DeclBaseName name) {
|
void evaluator::DependencyCollector::addTopLevelName(DeclBaseName name) {
|
||||||
return realizeOrRecord(Reference::topLevel(name));
|
if (parent.mode ==
|
||||||
|
DependencyRecorder::Mode::ExperimentalPrivateDependencies) {
|
||||||
|
scratch.insert(Reference::topLevel(name));
|
||||||
|
}
|
||||||
|
return parent.realize(Reference::topLevel(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluator::DependencyCollector::addDynamicLookupName(DeclBaseName name) {
|
void evaluator::DependencyCollector::addDynamicLookupName(DeclBaseName name) {
|
||||||
return realizeOrRecord(Reference::dynamic(name));
|
if (parent.mode ==
|
||||||
|
DependencyRecorder::Mode::ExperimentalPrivateDependencies) {
|
||||||
|
scratch.insert(Reference::dynamic(name));
|
||||||
|
}
|
||||||
|
return parent.realize(Reference::dynamic(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluator::DependencyCollector::record(
|
void evaluator::DependencyRecorder::record(
|
||||||
const llvm::SetVector<swift::ActiveRequest> &stack,
|
const llvm::SetVector<swift::ActiveRequest> &stack,
|
||||||
llvm::function_ref<void(DependencyCollector &)> rec) {
|
llvm::function_ref<void(DependencyCollector &)> rec) {
|
||||||
assert(!isRecording && "Probably not a good idea to allow nested recording");
|
assert(!isRecording && "Probably not a good idea to allow nested recording");
|
||||||
if (mode == Mode::StatusQuo) {
|
if (!getActiveDependencyTracker()) {
|
||||||
return rec(*this);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::SaveAndRestore<bool> restore(isRecording, true);
|
llvm::SaveAndRestore<bool> restore(isRecording, true);
|
||||||
scratch = {};
|
|
||||||
rec(*this);
|
DependencyCollector collector{*this};
|
||||||
|
rec(collector);
|
||||||
|
if (collector.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mode != Mode::StatusQuo);
|
||||||
for (const auto &request : stack) {
|
for (const auto &request : stack) {
|
||||||
if (!request.isCached()) {
|
if (!request.isCached()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -446,26 +463,31 @@ void evaluator::DependencyCollector::record(
|
|||||||
|
|
||||||
auto entry = requestReferences.find_as(request);
|
auto entry = requestReferences.find_as(request);
|
||||||
if (entry == requestReferences.end()) {
|
if (entry == requestReferences.end()) {
|
||||||
requestReferences.insert({AnyRequest(request), scratch});
|
requestReferences.insert({AnyRequest(request), collector.scratch});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->second.insert(scratch.begin(), scratch.end());
|
entry->second.insert(collector.scratch.begin(), collector.scratch.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluator::DependencyCollector::replay(const swift::ActiveRequest &req) {
|
void evaluator::DependencyRecorder::replay(const swift::ActiveRequest &req) {
|
||||||
if (mode == Mode::StatusQuo) {
|
assert(!isRecording && "Probably not a good idea to allow nested recording");
|
||||||
|
|
||||||
|
if (mode == Mode::StatusQuo || !getActiveDependencyTracker()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.isCached()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!isRecording && "Probably not a good idea to allow nested recording");
|
|
||||||
auto entry = requestReferences.find_as(req);
|
auto entry = requestReferences.find_as(req);
|
||||||
if (entry == requestReferences.end()) {
|
if (entry == requestReferences.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &ref : entry->second) {
|
for (const auto &ref : entry->second) {
|
||||||
realizeOrRecord(ref);
|
realize(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ void InheritedProtocolsRequest::cacheResult(ArrayRef<ProtocolDecl *> PDs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource InheritedProtocolsRequest::readDependencySource(
|
evaluator::DependencySource InheritedProtocolsRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
auto *PD = std::get<0>(getStorage());
|
auto *PD = std::get<0>(getStorage());
|
||||||
// Ignore context changes for protocols outside our module. This
|
// Ignore context changes for protocols outside our module. This
|
||||||
// prevents transitive cascading edges when e.g. our private
|
// prevents transitive cascading edges when e.g. our private
|
||||||
@@ -184,7 +184,7 @@ void ExtendedNominalRequest::writeDependencySink(
|
|||||||
auto *SF = std::get<0>(getStorage())->getParentSourceFile();
|
auto *SF = std::get<0>(getStorage())->getParentSourceFile();
|
||||||
if (!SF)
|
if (!SF)
|
||||||
return;
|
return;
|
||||||
if (SF != tracker.getActiveDependencySourceOrNull())
|
if (SF != tracker.getRecorder().getActiveDependencySourceOrNull())
|
||||||
return;
|
return;
|
||||||
tracker.addPotentialMember(value);
|
tracker.addPotentialMember(value);
|
||||||
}
|
}
|
||||||
@@ -208,7 +208,7 @@ void GetDestructorRequest::cacheResult(DestructorDecl *value) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource GetDestructorRequest::readDependencySource(
|
evaluator::DependencySource GetDestructorRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &eval) const {
|
const evaluator::DependencyRecorder &eval) const {
|
||||||
// Looking up the deinitializer currently always occurs in a private
|
// Looking up the deinitializer currently always occurs in a private
|
||||||
// scope because it is impossible to reference 'deinit' in user code, and a
|
// scope because it is impossible to reference 'deinit' in user code, and a
|
||||||
// valid 'deinit' declaration cannot occur outside of the
|
// valid 'deinit' declaration cannot occur outside of the
|
||||||
@@ -338,7 +338,7 @@ swift::extractNearestSourceLoc(const LookupConformanceDescriptor &desc) {
|
|||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
evaluator::DependencySource ModuleQualifiedLookupRequest::readDependencySource(
|
evaluator::DependencySource ModuleQualifiedLookupRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &eval) const {
|
const evaluator::DependencyRecorder &eval) const {
|
||||||
auto *DC = std::get<0>(getStorage());
|
auto *DC = std::get<0>(getStorage());
|
||||||
auto options = std::get<3>(getStorage());
|
auto options = std::get<3>(getStorage());
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ void LookupConformanceInModuleRequest::writeDependencySink(
|
|||||||
if (!Adoptee)
|
if (!Adoptee)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto *source = reqTracker.getActiveDependencySourceOrNull();
|
auto *source = reqTracker.getRecorder().getActiveDependencySourceOrNull();
|
||||||
if (!source)
|
if (!source)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -402,7 +402,7 @@ void LookupConformanceInModuleRequest::writeDependencySink(
|
|||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
evaluator::DependencySource UnqualifiedLookupRequest::readDependencySource(
|
evaluator::DependencySource UnqualifiedLookupRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &) const {
|
const evaluator::DependencyRecorder &) const {
|
||||||
auto &desc = std::get<0>(getStorage());
|
auto &desc = std::get<0>(getStorage());
|
||||||
// FIXME(Evaluator Incremental Dependencies): This maintains compatibility
|
// FIXME(Evaluator Incremental Dependencies): This maintains compatibility
|
||||||
// with the existing scheme, but the existing scheme is totally ad-hoc. We
|
// with the existing scheme, but the existing scheme is totally ad-hoc. We
|
||||||
@@ -426,7 +426,7 @@ void UnqualifiedLookupRequest::writeDependencySink(
|
|||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
evaluator::DependencySource QualifiedLookupRequest::readDependencySource(
|
evaluator::DependencySource QualifiedLookupRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &) const {
|
const evaluator::DependencyRecorder &) const {
|
||||||
auto *dc = std::get<0>(getStorage());
|
auto *dc = std::get<0>(getStorage());
|
||||||
auto opts = std::get<3>(getStorage());
|
auto opts = std::get<3>(getStorage());
|
||||||
// FIXME(Evaluator Incremental Dependencies): This is an artifact of the
|
// FIXME(Evaluator Incremental Dependencies): This is an artifact of the
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ void SuperclassTypeRequest::cacheResult(Type value) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource SuperclassTypeRequest::readDependencySource(
|
evaluator::DependencySource SuperclassTypeRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
const auto access = std::get<0>(getStorage())->getFormalAccess();
|
const auto access = std::get<0>(getStorage())->getFormalAccess();
|
||||||
return {
|
return {
|
||||||
e.getActiveDependencySourceOrNull(),
|
e.getActiveDependencySourceOrNull(),
|
||||||
@@ -1349,7 +1349,7 @@ void CheckRedeclarationRequest::cacheResult(evaluator::SideEffect) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource CheckRedeclarationRequest::readDependencySource(
|
evaluator::DependencySource CheckRedeclarationRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &eval) const {
|
const evaluator::DependencyRecorder &eval) const {
|
||||||
auto *current = std::get<0>(getStorage());
|
auto *current = std::get<0>(getStorage());
|
||||||
auto *currentDC = current->getDeclContext();
|
auto *currentDC = current->getDeclContext();
|
||||||
return {
|
return {
|
||||||
@@ -1384,7 +1384,7 @@ void CheckRedeclarationRequest::writeDependencySink(
|
|||||||
|
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
LookupAllConformancesInContextRequest::readDependencySource(
|
LookupAllConformancesInContextRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &collector) const {
|
const evaluator::DependencyRecorder &collector) const {
|
||||||
const auto *nominal = std::get<0>(getStorage())
|
const auto *nominal = std::get<0>(getStorage())
|
||||||
->getAsGenericContext()
|
->getAsGenericContext()
|
||||||
->getSelfNominalTypeDecl();
|
->getSelfNominalTypeDecl();
|
||||||
@@ -1427,7 +1427,7 @@ void ResolveTypeEraserTypeRequest::cacheResult(Type value) const {
|
|||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
evaluator::DependencySource TypeCheckSourceFileRequest::readDependencySource(
|
evaluator::DependencySource TypeCheckSourceFileRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
return {std::get<0>(getStorage()), evaluator::DependencyScope::Cascading};
|
return {std::get<0>(getStorage()), evaluator::DependencyScope::Cascading};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1460,7 +1460,7 @@ void TypeCheckSourceFileRequest::cacheResult(evaluator::SideEffect) const {
|
|||||||
|
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
TypeCheckFunctionBodyUntilRequest::readDependencySource(
|
TypeCheckFunctionBodyUntilRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
// We're going under a function body scope, unconditionally flip the scope
|
// We're going under a function body scope, unconditionally flip the scope
|
||||||
// to private.
|
// to private.
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ SourceLoc swift::extractNearestSourceLoc(const IRGenDescriptor &desc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource IRGenSourceFileRequest::readDependencySource(
|
evaluator::DependencySource IRGenSourceFileRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
auto &desc = std::get<0>(getStorage());
|
auto &desc = std::get<0>(getStorage());
|
||||||
return {
|
return {
|
||||||
desc.Ctx.dyn_cast<SourceFile *>(),
|
desc.Ctx.dyn_cast<SourceFile *>(),
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ ArrayRef<Decl *> ParseSourceFileRequest::evaluate(Evaluator &evaluator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource ParseSourceFileRequest::readDependencySource(
|
evaluator::DependencySource ParseSourceFileRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
return {std::get<0>(getStorage()), evaluator::DependencyScope::Cascading};
|
return {std::get<0>(getStorage()), evaluator::DependencyScope::Cascading};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ void swift::simple_display(llvm::raw_ostream &out,
|
|||||||
|
|
||||||
evaluator::DependencySource
|
evaluator::DependencySource
|
||||||
CodeCompletionSecondPassRequest::readDependencySource(
|
CodeCompletionSecondPassRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
return {std::get<0>(getStorage()), e.getActiveSourceScope()};
|
return {std::get<0>(getStorage()), e.getActiveSourceScope()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ SourceLoc swift::extractNearestSourceLoc(const SILGenDescriptor &desc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluator::DependencySource SILGenerationRequest::readDependencySource(
|
evaluator::DependencySource SILGenerationRequest::readDependencySource(
|
||||||
const evaluator::DependencyCollector &e) const {
|
const evaluator::DependencyRecorder &e) const {
|
||||||
auto &desc = std::get<0>(getStorage());
|
auto &desc = std::get<0>(getStorage());
|
||||||
|
|
||||||
// We don't track dependencies in whole-module mode.
|
// We don't track dependencies in whole-module mode.
|
||||||
|
|||||||
Reference in New Issue
Block a user