Skip to content

Commit d44943a

Browse files
committed
[ModuleInterface] Include and dedupe (transitive) FILE_DEPENDENCY records from dependencies.
1 parent b07425a commit d44943a

File tree

4 files changed

+96
-64
lines changed

4 files changed

+96
-64
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ ERROR(error_extracting_flags_from_parseable_interface,none,
270270
ERROR(missing_dependency_of_parseable_module_interface,none,
271271
"missing dependency '%0' of parseable module interface '%1': %2",
272272
(StringRef, StringRef, StringRef))
273+
ERROR(error_extracting_dependencies_from_cached_module,none,
274+
"error extracting dependencies from cached module '%0'",
275+
(StringRef))
273276

274277
#ifndef DIAG_NO_UNDEF
275278
# if defined(DIAG)

include/swift/Serialization/SerializationOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace swift {
3838
struct FileDependency {
3939
uint64_t Size;
4040
uint64_t Hash;
41-
StringRef Path;
41+
std::string Path;
4242
};
4343
ArrayRef<FileDependency> Dependencies;
4444

lib/Frontend/ParseableInterfaceSupport.cpp

Lines changed: 91 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "clang/Lex/Preprocessor.h"
2828
#include "clang/Lex/HeaderSearch.h"
2929
#include "llvm/ADT/Hashing.h"
30+
#include "llvm/ADT/StringSet.h"
3031
#include "llvm/Support/xxhash.h"
3132
#include "llvm/Support/Debug.h"
3233
#include "llvm/Support/CommandLine.h"
@@ -36,6 +37,7 @@
3637
#include "llvm/Support/StringSaver.h"
3738

3839
using namespace swift;
40+
using FileDependency = SerializationOptions::FileDependency;
3941

4042
#define SWIFT_TOOLS_VERSION_KEY "swift-tools-version"
4143
#define SWIFT_MODULE_FLAGS_KEY "swift-module-flags"
@@ -74,20 +76,19 @@ extractSwiftInterfaceVersionAndArgs(DiagnosticEngine &Diags,
7476
return false;
7577
}
7678

77-
static bool
78-
getHashOfFile(clang::vfs::FileSystem &FS,
79-
StringRef Path, uint64_t &HashOut,
80-
DiagnosticEngine &Diags) {
81-
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf =
82-
FS.getBufferForFile(Path, /*FileSize=*/-1,
83-
/*RequiresNullTerminator=*/false);
84-
if (!Buf) {
85-
Diags.diagnose(SourceLoc(), diag::cannot_open_file, Path,
86-
Buf.getError().message());
87-
return true;
79+
static std::unique_ptr<llvm::MemoryBuffer>
80+
getBufferOfDependency(clang::vfs::FileSystem &FS,
81+
StringRef ModulePath, StringRef DepPath,
82+
DiagnosticEngine &Diags) {
83+
auto DepBuf = FS.getBufferForFile(DepPath, /*FileSize=*/-1,
84+
/*RequiresNullTerminator=*/false);
85+
if (!DepBuf) {
86+
Diags.diagnose(SourceLoc(),
87+
diag::missing_dependency_of_parseable_module_interface,
88+
DepPath, ModulePath, DepBuf.getError().message());
89+
return nullptr;
8890
}
89-
HashOut = xxHash64(Buf.get()->getBuffer());
90-
return false;
91+
return std::move(DepBuf.get());
9192
}
9293

9394
/// Construct a cache key for the .swiftmodule being generated. There is a
@@ -174,19 +175,12 @@ swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
174175
StringRef OutPath,
175176
DiagnosticEngine &Diags) {
176177

177-
if (!FS.exists(OutPath))
178-
return false;
179-
180-
auto OutStatus = FS.status(OutPath);
181-
if (!OutStatus)
182-
return false;
183-
184178
auto OutBuf = FS.getBufferForFile(OutPath);
185179
if (!OutBuf)
186180
return false;
187181

188182
LLVM_DEBUG(llvm::dbgs() << "Validating deps of " << OutPath << "\n");
189-
SmallVector<SerializationOptions::FileDependency, 16> AllDeps;
183+
SmallVector<FileDependency, 16> AllDeps;
190184
auto VI = serialization::validateSerializedAST(
191185
OutBuf.get()->getBuffer(),
192186
/*ExtendedValidationInfo=*/nullptr, &AllDeps);
@@ -195,34 +189,83 @@ swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
195189
return false;
196190

197191
for (auto In : AllDeps) {
198-
uint64_t Hash = 0;
199-
auto InStatus = FS.status(In.Path);
200-
if (!InStatus ||
201-
(InStatus.get().getSize() != In.Size) ||
202-
getHashOfFile(FS, In.Path, Hash, Diags) ||
203-
(Hash != In.Hash)) {
192+
auto DepBuf = getBufferOfDependency(FS, OutPath, In.Path, Diags);
193+
if (!DepBuf ||
194+
DepBuf->getBufferSize() != In.Size ||
195+
xxHash64(DepBuf->getBuffer()) != In.Hash) {
204196
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path
205197
<< " is directly out of date\n");
206198
return false;
207199
}
208-
// Recursively check freshness of any .swiftmodules in the module cache.
209-
auto Ext = llvm::sys::path::extension(In.Path);
200+
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path << " is up to date\n");
201+
}
202+
return true;
203+
}
204+
205+
/// Populate the provided \p Deps with \c FileDependency entries including:
206+
///
207+
/// - \p InPath - The .swiftinterface input file
208+
///
209+
/// - All the dependencies mentioned by \p SubInstance's DependencyTracker,
210+
/// that were read while compiling the module.
211+
///
212+
/// - For any file in the latter set that is itself a .swiftmodule
213+
/// living in \p ModuleCachePath, all of _its_ dependencies, copied
214+
/// out to avoid having to do recursive scanning when rechecking this
215+
/// dependency in the future.
216+
static bool
217+
collectDepsForSerialization(clang::vfs::FileSystem &FS,
218+
CompilerInstance &SubInstance,
219+
StringRef InPath, StringRef ModuleCachePath,
220+
SmallVectorImpl<FileDependency> &Deps,
221+
DiagnosticEngine &Diags) {
222+
auto DTDeps = SubInstance.getDependencyTracker()->getDependencies();
223+
SmallVector<StringRef, 16> InitialDepNames(DTDeps.begin(), DTDeps.end());
224+
InitialDepNames.push_back(InPath);
225+
llvm::StringSet<> AllDepNames;
226+
for (auto const &DepName : InitialDepNames) {
227+
AllDepNames.insert(DepName);
228+
auto DepBuf = getBufferOfDependency(FS, InPath, DepName, Diags);
229+
if (!DepBuf) {
230+
return true;
231+
}
232+
uint64_t Size = DepBuf->getBufferSize();
233+
uint64_t Hash = xxHash64(DepBuf->getBuffer());
234+
Deps.push_back(FileDependency{Size, Hash, DepName});
235+
236+
// If Dep is itself a .swiftmodule in the cache dir, pull out its deps
237+
// and include them in our own, so we have a single-file view of
238+
// transitive deps: removes redundancies, and avoids opening and reading
239+
// multiple swiftmodules during future loads.
240+
auto Ext = llvm::sys::path::extension(DepName);
210241
auto Ty = file_types::lookupTypeForExtension(Ext);
211242
if (Ty == file_types::TY_SwiftModuleFile &&
212-
In.Path.startswith(ModuleCachePath) &&
213-
!swiftModuleIsUpToDate(FS, ModuleCachePath, In.Path, Diags)) {
214-
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path
215-
<< " is indirectly out of date\n");
216-
return false;
243+
DepName.startswith(ModuleCachePath)) {
244+
SmallVector<FileDependency, 16> SubDeps;
245+
auto VI = serialization::validateSerializedAST(
246+
DepBuf->getBuffer(),
247+
/*ExtendedValidationInfo=*/nullptr, &SubDeps);
248+
if (VI.status != serialization::Status::Valid) {
249+
Diags.diagnose(SourceLoc(),
250+
diag::error_extracting_dependencies_from_cached_module,
251+
DepName);
252+
return true;
253+
}
254+
for (auto const &SubDep : SubDeps) {
255+
if (AllDepNames.count(SubDep.Path) == 0) {
256+
AllDepNames.insert(SubDep.Path);
257+
Deps.push_back(SubDep);
258+
}
259+
}
217260
}
218-
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path << " is up to date\n");
219261
}
220-
return true;
262+
return false;
221263
}
222264

223265
static bool buildSwiftModuleFromSwiftInterface(
224266
clang::vfs::FileSystem &FS, DiagnosticEngine &Diags,
225-
CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath) {
267+
CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath,
268+
StringRef ModuleCachePath) {
226269
bool SubError = false;
227270
bool RunSuccess = llvm::CrashRecoveryContext().RunSafelyOnThread([&] {
228271

@@ -279,34 +322,19 @@ static bool buildSwiftModuleFromSwiftInterface(
279322
}
280323

281324
LLVM_DEBUG(llvm::dbgs() << "Serializing " << OutPath << "\n");
282-
SerializationOptions serializationOpts;
325+
SerializationOptions SerializationOpts;
283326
std::string OutPathStr = OutPath;
284-
serializationOpts.OutputPath = OutPathStr.c_str();
285-
serializationOpts.SerializeAllSIL = true;
286-
auto DTDeps = SubInstance.getDependencyTracker()->getDependencies();
287-
SmallVector<std::string, 16> DepNames(DTDeps.begin(), DTDeps.end());
288-
DepNames.push_back(InPath);
289-
SmallVector<SerializationOptions::FileDependency, 16> Deps;
290-
for (auto const &Dep : DepNames) {
291-
auto DepStatus = FS.status(Dep);
292-
if (!DepStatus) {
293-
Diags.diagnose(SourceLoc(),
294-
diag::missing_dependency_of_parseable_module_interface,
295-
Dep, InPath, DepStatus.getError().message());
296-
SubError = true;
297-
return;
298-
}
299-
uint64_t Hash = 0;
300-
if (getHashOfFile(FS, Dep, Hash, Diags)) {
301-
SubError = true;
302-
return;
303-
}
304-
Deps.push_back(SerializationOptions::FileDependency{
305-
DepStatus.get().getSize(), Hash, Dep});
327+
SerializationOpts.OutputPath = OutPathStr.c_str();
328+
SerializationOpts.SerializeAllSIL = true;
329+
SmallVector<FileDependency, 16> Deps;
330+
if (collectDepsForSerialization(FS, SubInstance, InPath, ModuleCachePath,
331+
Deps, Diags)) {
332+
SubError = true;
333+
return;
306334
}
307-
serializationOpts.Dependencies = Deps;
335+
SerializationOpts.Dependencies = Deps;
308336
SILMod->setSerializeSILAction([&]() {
309-
serialize(Mod, serializationOpts, SILMod.get());
337+
serialize(Mod, SerializationOpts, SILMod.get());
310338
});
311339
SILMod->serialize();
312340
SubError = Diags.hadAnyError();
@@ -343,7 +371,7 @@ std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
343371
// Evaluate if we need to run this sub-invocation, and if so run it.
344372
if (!swiftModuleIsUpToDate(FS, CacheDir, OutPath, Diags)) {
345373
if (buildSwiftModuleFromSwiftInterface(FS, Diags, SubInvocation, InPath,
346-
OutPath))
374+
OutPath, CacheDir))
347375
return std::make_error_code(std::errc::invalid_argument);
348376
}
349377

test/ParseableInterface/ModuleCache/module-cache-init.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
// CHECK-OTHERMODULE: {{FILE_DEPENDENCY.*Swift.swiftmodule'}}
4242
// CHECK-OTHERMODULE: {{FILE_DEPENDENCY.*SwiftOnoneSupport.swiftmodule'}}
4343
// CHECK-OTHERMODULE: {{FILE_DEPENDENCY.*LeafModule-.*.swiftmodule'}}
44+
// CHECK-OTHERMODULE: {{FILE_DEPENDENCY.*LeafModule.swiftinterface'}}
4445
// CHECK-OTHERMODULE: {{FILE_DEPENDENCY.*OtherModule.swiftinterface'}}
4546
// CHECK-OTHERMODULE: FUNC_DECL
4647

0 commit comments

Comments
 (0)