|
18 | 18 | #ifndef SWIFT_AST_EVALUATOR_DEPENDENCIES_H
|
19 | 19 | #define SWIFT_AST_EVALUATOR_DEPENDENCIES_H
|
20 | 20 |
|
| 21 | +#include "swift/AST/AnyRequest.h" |
21 | 22 | #include "swift/AST/AttrKind.h"
|
22 | 23 | #include "swift/AST/SourceFile.h"
|
23 | 24 | #include "llvm/ADT/PointerIntPair.h"
|
@@ -106,30 +107,78 @@ inline DependencyScope getScopeForAccessLevel(AccessLevel l) {
|
106 | 107 | // of individual contexts.
|
107 | 108 | using DependencySource = llvm::PointerIntPair<SourceFile *, 1, DependencyScope>;
|
108 | 109 |
|
109 |
| -/// A \c DependencyCollector is an aggregator of named references discovered in a |
110 |
| -/// particular \c DependencyScope during the course of request evaluation. |
| 110 | +struct DependencyRecorder; |
| 111 | + |
111 | 112 | struct DependencyCollector {
|
112 |
| -private: |
113 |
| - /// A stack of dependency sources in the order they were evaluated. |
114 |
| - llvm::SmallVector<evaluator::DependencySource, 8> dependencySources; |
| 113 | + struct Reference { |
| 114 | + public: |
| 115 | + enum class Kind { |
| 116 | + Empty, |
| 117 | + Tombstone, |
| 118 | + UsedMember, |
| 119 | + PotentialMember, |
| 120 | + TopLevel, |
| 121 | + Dynamic, |
| 122 | + } kind; |
115 | 123 |
|
116 |
| -public: |
117 |
| - enum class Mode { |
118 |
| - // Enables the current "status quo" behavior of the dependency collector. |
119 |
| - // |
120 |
| - // By default, the dependency collector moves to register dependencies in |
121 |
| - // the referenced name trackers at the top of the active dependency stack. |
122 |
| - StatusQuo, |
123 |
| - // Enables an experimental mode to only register private dependencies. |
124 |
| - // |
125 |
| - // This mode restricts the dependency collector to ignore changes of |
126 |
| - // scope. This has practical effect of charging all unqualified lookups to |
127 |
| - // the primary file being acted upon instead of to the destination file. |
128 |
| - ExperimentalPrivateDependencies, |
| 124 | + NominalTypeDecl *subject; |
| 125 | + DeclBaseName name; |
| 126 | + |
| 127 | + private: |
| 128 | + Reference(Kind kind, NominalTypeDecl *subject, DeclBaseName name) |
| 129 | + : kind(kind), subject(subject), name(name) {} |
| 130 | + |
| 131 | + public: |
| 132 | + static Reference empty() { |
| 133 | + return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey(), |
| 134 | + llvm::DenseMapInfo<DeclBaseName>::getEmptyKey()}; |
| 135 | + } |
| 136 | + |
| 137 | + static Reference tombstone() { |
| 138 | + return {Kind::Empty, |
| 139 | + llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey(), |
| 140 | + llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey()}; |
| 141 | + } |
| 142 | + |
| 143 | + public: |
| 144 | + static Reference usedMember(NominalTypeDecl *subject, DeclBaseName name) { |
| 145 | + return {Kind::UsedMember, subject, name}; |
| 146 | + } |
| 147 | + |
| 148 | + static Reference potentialMember(NominalTypeDecl *subject) { |
| 149 | + return {Kind::PotentialMember, subject, DeclBaseName()}; |
| 150 | + } |
| 151 | + |
| 152 | + static Reference topLevel(DeclBaseName name) { |
| 153 | + return {Kind::TopLevel, nullptr, name}; |
| 154 | + } |
| 155 | + |
| 156 | + static Reference dynamic(DeclBaseName name) { |
| 157 | + return {Kind::Dynamic, nullptr, name}; |
| 158 | + } |
| 159 | + |
| 160 | + public: |
| 161 | + struct Info { |
| 162 | + static inline Reference getEmptyKey() { return Reference::empty(); } |
| 163 | + static inline Reference getTombstoneKey() { |
| 164 | + return Reference::tombstone(); |
| 165 | + } |
| 166 | + static inline unsigned getHashValue(const Reference &Val) { |
| 167 | + return llvm::hash_combine(Val.kind, Val.subject, |
| 168 | + Val.name.getAsOpaquePointer()); |
| 169 | + } |
| 170 | + static bool isEqual(const Reference &LHS, const Reference &RHS) { |
| 171 | + return LHS.kind == RHS.kind && LHS.subject == RHS.subject && |
| 172 | + LHS.name == RHS.name; |
| 173 | + } |
| 174 | + }; |
129 | 175 | };
|
130 |
| - Mode mode; |
131 | 176 |
|
132 |
| - explicit DependencyCollector(Mode mode) : mode{mode} {}; |
| 177 | + DependencyRecorder &parent; |
| 178 | + llvm::DenseSet<Reference, Reference::Info> scratch; |
| 179 | + |
| 180 | +public: |
| 181 | + explicit DependencyCollector(DependencyRecorder &parent) : parent(parent) {} |
133 | 182 |
|
134 | 183 | public:
|
135 | 184 | /// Registers a named reference from the current dependency scope to a member
|
@@ -168,6 +217,50 @@ struct DependencyCollector {
|
168 | 217 | /// a name that is found by \c AnyObject lookup.
|
169 | 218 | void addDynamicLookupName(DeclBaseName name);
|
170 | 219 |
|
| 220 | +public: |
| 221 | + const DependencyRecorder &getRecorder() const { return parent; } |
| 222 | + bool empty() const { return scratch.empty(); } |
| 223 | +}; |
| 224 | + |
| 225 | +/// A \c DependencyCollector is an aggregator of named references discovered in a |
| 226 | +/// particular \c DependencyScope during the course of request evaluation. |
| 227 | +struct DependencyRecorder { |
| 228 | + friend DependencyCollector; |
| 229 | +private: |
| 230 | + /// A stack of dependency sources in the order they were evaluated. |
| 231 | + llvm::SmallVector<evaluator::DependencySource, 8> dependencySources; |
| 232 | + |
| 233 | +public: |
| 234 | + enum class Mode { |
| 235 | + // Enables the current "status quo" behavior of the dependency collector. |
| 236 | + // |
| 237 | + // By default, the dependency collector moves to register dependencies in |
| 238 | + // the referenced name trackers at the top of the active dependency stack. |
| 239 | + StatusQuo, |
| 240 | + // Enables an experimental mode to only register private dependencies. |
| 241 | + // |
| 242 | + // This mode restricts the dependency collector to ignore changes of |
| 243 | + // scope. This has practical effect of charging all unqualified lookups to |
| 244 | + // the primary file being acted upon instead of to the destination file. |
| 245 | + ExperimentalPrivateDependencies, |
| 246 | + }; |
| 247 | + Mode mode; |
| 248 | + llvm::DenseMap<AnyRequest, llvm::DenseSet<DependencyCollector::Reference, |
| 249 | + DependencyCollector::Reference::Info>> |
| 250 | + requestReferences; |
| 251 | + bool isRecording; |
| 252 | + |
| 253 | + explicit DependencyRecorder(Mode mode) |
| 254 | + : mode{mode}, requestReferences{}, isRecording{false} {}; |
| 255 | + |
| 256 | +private: |
| 257 | + void realize(const DependencyCollector::Reference &ref); |
| 258 | + |
| 259 | +public: |
| 260 | + void replay(const swift::ActiveRequest &req); |
| 261 | + void record(const llvm::SetVector<swift::ActiveRequest> &stack, |
| 262 | + llvm::function_ref<void(DependencyCollector &)> rec); |
| 263 | + |
171 | 264 | public:
|
172 | 265 | /// Returns the scope of the current active scope.
|
173 | 266 | ///
|
@@ -197,14 +290,14 @@ struct DependencyCollector {
|
197 | 290 | /// dependency source stack. It is specialized to be zero-cost for
|
198 | 291 | /// requests that are not dependency sources.
|
199 | 292 | template <typename Request, typename = detail::void_t<>> struct StackRAII {
|
200 |
| - StackRAII(DependencyCollector &DC, const Request &Req) {} |
| 293 | + StackRAII(DependencyRecorder &DR, const Request &Req) {} |
201 | 294 | };
|
202 | 295 |
|
203 | 296 | template <typename Request>
|
204 | 297 | struct StackRAII<Request,
|
205 | 298 | typename std::enable_if<Request::isDependencySource>::type> {
|
206 |
| - NullablePtr<DependencyCollector> Coll; |
207 |
| - StackRAII(DependencyCollector &coll, const Request &Req) { |
| 299 | + NullablePtr<DependencyRecorder> Coll; |
| 300 | + StackRAII(DependencyRecorder &coll, const Request &Req) { |
208 | 301 | auto Source = Req.readDependencySource(coll);
|
209 | 302 | // If there is no source to introduce, bail. This can occur if
|
210 | 303 | // a request originates in the context of a module.
|
|
0 commit comments