Skip to content

Commit 172c047

Browse files
authored
Merge pull request #28515 from DougGregor/fast-dependency-scanning
Fast dependency scanning for Swift
2 parents c093de1 + 5351d54 commit 172c047

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2014
-17
lines changed

include/swift/AST/ASTContext.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ namespace swift {
7878
class LazyContextData;
7979
class LazyIterableDeclContextData;
8080
class LazyMemberLoader;
81+
class ModuleDependencies;
8182
class PatternBindingDecl;
8283
class PatternBindingInitializer;
8384
class SourceFile;
@@ -91,6 +92,7 @@ namespace swift {
9192
class Identifier;
9293
class InheritedNameSet;
9394
class ModuleDecl;
95+
class ModuleDependenciesCache;
9496
class ModuleLoader;
9597
class NominalTypeDecl;
9698
class NormalProtocolConformance;
@@ -710,6 +712,15 @@ class ASTContext final {
710712
void addModuleLoader(std::unique_ptr<ModuleLoader> loader,
711713
bool isClang = false, bool isDWARF = false);
712714

715+
/// Retrieve the module dependencies for the module with the given name.
716+
///
717+
/// \param isUnderlyingClangModule When true, only look for a Clang module
718+
/// with the given name, ignoring any Swift modules.
719+
Optional<ModuleDependencies> getModuleDependencies(
720+
StringRef moduleName,
721+
bool isUnderlyingClangModule,
722+
ModuleDependenciesCache &cache);
723+
713724
/// Load extensions to the given nominal type from the external
714725
/// module loaders.
715726
///
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
//===--- ModuleDependencies.h - Module Dependencies -------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines data structures for capturing all of the source files
14+
// and modules on which a given module depends, forming a graph of all of the
15+
// modules that need to be present for a given module to be built.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
#ifndef SWIFT_AST_MODULE_DEPENDENCIES_H
19+
#define SWIFT_AST_MODULE_DEPENDENCIES_H
20+
21+
#include "swift/Basic/LLVM.h"
22+
#include "llvm/ADT/ArrayRef.h"
23+
#include "llvm/ADT/DenseMap.h"
24+
#include "llvm/ADT/Optional.h"
25+
#include "llvm/ADT/StringSet.h"
26+
#include <string>
27+
#include <vector>
28+
29+
namespace swift {
30+
31+
class ClangModuleDependenciesCacheImpl;
32+
class SourceFile;
33+
34+
/// Which kind of module dependencies we are looking for.
35+
enum class ModuleDependenciesKind : int8_t {
36+
Swift,
37+
Clang,
38+
};
39+
40+
/// Base class for the variant storage of ModuleDependencies.
41+
///
42+
/// This class is mostly an implementation detail for \c ModuleDependencies.
43+
class ModuleDependenciesStorageBase {
44+
public:
45+
const bool isSwiftModule;
46+
47+
ModuleDependenciesStorageBase(bool isSwiftModule,
48+
const std::string &compiledModulePath)
49+
: isSwiftModule(isSwiftModule),
50+
compiledModulePath(compiledModulePath) { }
51+
52+
virtual ModuleDependenciesStorageBase *clone() const = 0;
53+
54+
virtual ~ModuleDependenciesStorageBase();
55+
56+
/// The path to the compiled module file.
57+
const std::string compiledModulePath;
58+
59+
/// The set of modules on which this module depends.
60+
std::vector<std::string> moduleDependencies;
61+
};
62+
63+
/// Describes the dependencies of a Swift module.
64+
///
65+
/// This class is mostly an implementation detail for \c ModuleDependencies.
66+
class SwiftModuleDependenciesStorage : public ModuleDependenciesStorageBase {
67+
public:
68+
/// The Swift interface file, if it can be used to generate the module file.
69+
const Optional<std::string> swiftInterfaceFile;
70+
71+
/// Bridging header file, if there is one.
72+
Optional<std::string> bridgingHeaderFile;
73+
74+
/// Swift source files that are part of the Swift module, when known.
75+
std::vector<std::string> sourceFiles;
76+
77+
/// Source files on which the bridging header depends.
78+
std::vector<std::string> bridgingSourceFiles;
79+
80+
/// (Clang) modules on which the bridging header depends.
81+
std::vector<std::string> bridgingModuleDependencies;
82+
83+
SwiftModuleDependenciesStorage(
84+
const std::string &compiledModulePath,
85+
const Optional<std::string> &swiftInterfaceFile
86+
) : ModuleDependenciesStorageBase(/*isSwiftModule=*/true, compiledModulePath),
87+
swiftInterfaceFile(swiftInterfaceFile) { }
88+
89+
ModuleDependenciesStorageBase *clone() const override {
90+
return new SwiftModuleDependenciesStorage(*this);
91+
}
92+
93+
static bool classof(const ModuleDependenciesStorageBase *base) {
94+
return base->isSwiftModule;
95+
}
96+
};
97+
98+
/// Describes the dependencies of a Clang module.
99+
///
100+
/// This class is mostly an implementation detail for \c ModuleDependencies.
101+
class ClangModuleDependenciesStorage : public ModuleDependenciesStorageBase {
102+
public:
103+
/// The module map file used to generate the Clang module.
104+
const std::string moduleMapFile;
105+
106+
/// The context hash describing the configuration options for this module.
107+
const std::string contextHash;
108+
109+
/// Partial (Clang) command line that can be used to build this module.
110+
const std::vector<std::string> nonPathCommandLine;
111+
112+
/// The file dependencies
113+
const std::vector<std::string> fileDependencies;
114+
115+
ClangModuleDependenciesStorage(
116+
const std::string &compiledModulePath,
117+
const std::string &moduleMapFile,
118+
const std::string &contextHash,
119+
const std::vector<std::string> &nonPathCommandLine,
120+
const std::vector<std::string> &fileDependencies
121+
) : ModuleDependenciesStorageBase(/*isSwiftModule=*/false,
122+
compiledModulePath),
123+
moduleMapFile(moduleMapFile),
124+
contextHash(contextHash),
125+
nonPathCommandLine(nonPathCommandLine),
126+
fileDependencies(fileDependencies) { }
127+
128+
ModuleDependenciesStorageBase *clone() const override {
129+
return new ClangModuleDependenciesStorage(*this);
130+
}
131+
132+
static bool classof(const ModuleDependenciesStorageBase *base) {
133+
return !base->isSwiftModule;
134+
}
135+
};
136+
137+
/// Describes the dependencies of a given module.
138+
///
139+
/// The dependencies of a module include all of the source files that go
140+
/// into that module, as well as any modules that are directly imported
141+
/// into the module.
142+
class ModuleDependencies {
143+
private:
144+
std::unique_ptr<ModuleDependenciesStorageBase> storage;
145+
146+
ModuleDependencies(std::unique_ptr<ModuleDependenciesStorageBase> &&storage)
147+
: storage(std::move(storage)) { }
148+
149+
public:
150+
ModuleDependencies(const ModuleDependencies &other)
151+
: storage(other.storage->clone()) { }
152+
ModuleDependencies(ModuleDependencies &&other) = default;
153+
154+
ModuleDependencies &operator=(const ModuleDependencies &other) {
155+
storage.reset(other.storage->clone());
156+
return *this;
157+
}
158+
159+
ModuleDependencies &operator=(ModuleDependencies &&other) = default;
160+
161+
/// Describe the module dependencies for a Swift module that can be
162+
/// built from a Swift interface file (\c .swiftinterface).
163+
static ModuleDependencies forSwiftInterface(
164+
const std::string &compiledModulePath,
165+
const std::string &swiftInterfaceFile) {
166+
return ModuleDependencies(
167+
std::make_unique<SwiftModuleDependenciesStorage>(
168+
compiledModulePath, swiftInterfaceFile));
169+
}
170+
171+
/// Describe the module dependencies for a serialized or parsed Swift module.
172+
static ModuleDependencies forSwiftModule(
173+
const std::string &compiledModulePath) {
174+
return ModuleDependencies(
175+
std::make_unique<SwiftModuleDependenciesStorage>(
176+
compiledModulePath, None));
177+
}
178+
179+
/// Describe the module dependencies for a Clang module that can be
180+
/// built from a module map and headers.
181+
static ModuleDependencies forClangModule(
182+
const std::string &compiledModulePath,
183+
const std::string &moduleMapFile,
184+
const std::string &contextHash,
185+
const std::vector<std::string> &nonPathCommandLine,
186+
const std::vector<std::string> &fileDependencies) {
187+
return ModuleDependencies(
188+
std::make_unique<ClangModuleDependenciesStorage>(
189+
compiledModulePath, moduleMapFile, contextHash, nonPathCommandLine,
190+
fileDependencies));
191+
}
192+
193+
/// Retrieve the path to the compiled module.
194+
const std::string getCompiledModulePath() const {
195+
return storage->compiledModulePath;
196+
}
197+
198+
/// Retrieve the module-level dependencies.
199+
ArrayRef<std::string> getModuleDependencies() const {
200+
return storage->moduleDependencies;
201+
}
202+
203+
/// Whether the dependencies are for a Swift module.
204+
bool isSwiftModule() const;
205+
206+
ModuleDependenciesKind getKind() const {
207+
return isSwiftModule() ? ModuleDependenciesKind::Swift
208+
: ModuleDependenciesKind::Clang;
209+
}
210+
/// Retrieve the dependencies for a Swift module.
211+
const SwiftModuleDependenciesStorage *getAsSwiftModule() const;
212+
213+
/// Retrieve the dependencies for a Clang module.
214+
const ClangModuleDependenciesStorage *getAsClangModule() const;
215+
216+
/// Add a dependency on the given module, if it was not already in the set.
217+
void addModuleDependency(StringRef module,
218+
llvm::StringSet<> &alreadyAddedModules);
219+
220+
/// Add all of the module dependencies for the imports in the given source
221+
/// file to the set of module dependencies.
222+
void addModuleDependencies(const SourceFile &sf,
223+
llvm::StringSet<> &alreadyAddedModules);
224+
225+
/// Get the bridging header.
226+
Optional<std::string> getBridgingHeader() const;
227+
228+
/// Add a bridging header to a Swift module's dependencies.
229+
void addBridgingHeader(StringRef bridgingHeader);
230+
231+
/// Add source files that the bridging header depends on.
232+
void addBridgingSourceFile(StringRef bridgingSourceFile);
233+
234+
/// Add (Clang) module on which the bridging header depends.
235+
void addBridgingModuleDependency(StringRef module,
236+
llvm::StringSet<> &alreadyAddedModules);
237+
};
238+
239+
using ModuleDependencyID = std::pair<std::string, ModuleDependenciesKind>;
240+
241+
/// A cache describing the set of module dependencies that has been queried
242+
/// thus far.
243+
class ModuleDependenciesCache {
244+
/// All cached module dependencies, in the order in which they were
245+
/// encountered.
246+
std::vector<ModuleDependencyID> AllModules;
247+
248+
/// Dependencies for Swift modules that have already been computed.
249+
llvm::StringMap<ModuleDependencies> SwiftModuleDependencies;
250+
251+
/// Dependencies for Clang modules that have already been computed.
252+
llvm::StringMap<ModuleDependencies> ClangModuleDependencies;
253+
254+
/// Additional information needed for Clang dependency scanning.
255+
ClangModuleDependenciesCacheImpl *clangImpl = nullptr;
256+
257+
/// Function that will delete \c clangImpl properly.
258+
void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *) = nullptr;
259+
260+
/// Free up the storage associated with the Clang implementation.
261+
void destroyClangImpl() {
262+
if (this->clangImplDeleter)
263+
this->clangImplDeleter(this->clangImpl);
264+
}
265+
266+
/// Retrieve the dependencies map that corresponds to the given dependency
267+
/// kind.
268+
llvm::StringMap<ModuleDependencies> &getDependenciesMap(
269+
ModuleDependenciesKind kind);
270+
const llvm::StringMap<ModuleDependencies> &getDependenciesMap(
271+
ModuleDependenciesKind kind) const;
272+
273+
public:
274+
ModuleDependenciesCache() { }
275+
276+
ModuleDependenciesCache(const ModuleDependenciesCache &) = delete;
277+
ModuleDependenciesCache &operator=(const ModuleDependenciesCache &) = delete;
278+
279+
~ModuleDependenciesCache() {
280+
destroyClangImpl();
281+
}
282+
283+
/// Set the Clang-specific implementation data.
284+
void setClangImpl(
285+
ClangModuleDependenciesCacheImpl *clangImpl,
286+
void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *)) {
287+
destroyClangImpl();
288+
289+
this->clangImpl = clangImpl;
290+
this->clangImplDeleter = clangImplDeleter;
291+
}
292+
293+
/// Retrieve the Clang-specific implementation data;
294+
ClangModuleDependenciesCacheImpl *getClangImpl() const {
295+
return clangImpl;
296+
}
297+
298+
/// Whether we have cached dependency information for the given module.
299+
bool hasDependencies(StringRef moduleName,
300+
Optional<ModuleDependenciesKind> kind) const;
301+
302+
/// Look for module dependencies for a module with the given name.
303+
///
304+
/// \returns the cached result, or \c None if there is no cached entry.
305+
Optional<ModuleDependencies> findDependencies(
306+
StringRef moduleName,
307+
Optional<ModuleDependenciesKind> kind) const;
308+
309+
/// Record dependencies for the given module.
310+
void recordDependencies(StringRef moduleName,
311+
ModuleDependencies dependencies,
312+
ModuleDependenciesKind kind);
313+
314+
/// Update stored dependencies for the given module.
315+
void updateDependencies(ModuleDependencyID moduleID,
316+
ModuleDependencies dependencies);
317+
318+
/// Reference the list of all module dependencies.
319+
const std::vector<ModuleDependencyID> &getAllModules() const {
320+
return AllModules;
321+
}
322+
};
323+
324+
}
325+
326+
#endif /* SWIFT_AST_MODULE_DEPENDENCIES_H */

include/swift/AST/ModuleLoader.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/Basic/SourceLoc.h"
2424
#include "llvm/ADT/SetVector.h"
2525
#include "llvm/ADT/SmallSet.h"
26+
#include "llvm/ADT/StringSet.h"
2627
#include "llvm/ADT/TinyPtrVector.h"
2728

2829
namespace llvm {
@@ -41,7 +42,10 @@ class ClangImporterOptions;
4142
class ClassDecl;
4243
class FileUnit;
4344
class ModuleDecl;
45+
class ModuleDependencies;
46+
class ModuleDependenciesCache;
4447
class NominalTypeDecl;
48+
class SourceFile;
4549
class TypeDecl;
4650

4751
enum class KnownProtocolKind : uint8_t;
@@ -177,6 +181,12 @@ class ModuleLoader {
177181
/// Discover overlays declared alongside this file and add infomation about
178182
/// them to it.
179183
void findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module, FileUnit *file);
184+
185+
/// Retrieve the dependencies for the given, named module, or \c None
186+
/// if no such module exists.
187+
virtual Optional<ModuleDependencies> getModuleDependencies(
188+
StringRef moduleName,
189+
ModuleDependenciesCache &cache) = 0;
180190
};
181191

182192
} // namespace swift

0 commit comments

Comments
 (0)