Skip to content

Commit b07425a

Browse files
committed
[ModuleInterface] Switch from mtime to xxhash in FILE_DEPENDENCY records.
1 parent 37a2eb5 commit b07425a

File tree

7 files changed

+49
-24
lines changed

7 files changed

+49
-24
lines changed

include/swift/Serialization/ModuleFormat.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 466; // Last change: add isAutoClosure flag to param
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 467; // Last change: switch FILE_DEPENDENCY records to hashes.
5656

5757
using DeclIDField = BCFixed<31>;
5858

@@ -108,6 +108,7 @@ using CharOffsetField = BitOffsetField;
108108

109109
using FileSizeField = BCVBR<16>;
110110
using FileModTimeField = BCVBR<16>;
111+
using FileHashField = BCVBR<16>;
111112

112113
// These IDs must \em not be renumbered or reordered without incrementing
113114
// the module version.
@@ -652,7 +653,7 @@ namespace input_block {
652653
IMPORTED_HEADER,
653654
BCFixed<1>, // exported?
654655
FileSizeField, // file size (for validation)
655-
FileModTimeField, // file mtime (for validation)
656+
FileHashField, // file hash (for validation)
656657
BCBlob // file path
657658
>;
658659

include/swift/Serialization/SerializationOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace swift {
3737

3838
struct FileDependency {
3939
uint64_t Size;
40-
llvm::sys::TimePoint<> LastModTime;
40+
uint64_t Hash;
4141
StringRef Path;
4242
};
4343
ArrayRef<FileDependency> Dependencies;

lib/Frontend/ParseableInterfaceSupport.cpp

Lines changed: 33 additions & 9 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/Support/xxhash.h"
3031
#include "llvm/Support/Debug.h"
3132
#include "llvm/Support/CommandLine.h"
3233
#include "llvm/Support/CrashRecoveryContext.h"
@@ -73,6 +74,22 @@ extractSwiftInterfaceVersionAndArgs(DiagnosticEngine &Diags,
7374
return false;
7475
}
7576

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;
88+
}
89+
HashOut = xxHash64(Buf.get()->getBuffer());
90+
return false;
91+
}
92+
7693
/// Construct a cache key for the .swiftmodule being generated. There is a
7794
/// balance to be struck here between things that go in the cache key and
7895
/// things that go in the "up to date" check of the cache entry. We want to
@@ -83,9 +100,9 @@ extractSwiftInterfaceVersionAndArgs(DiagnosticEngine &Diags,
83100
/// -- rather than making a new one and potentially filling up the cache
84101
/// with dead entries -- when other factors change, such as the contents of
85102
/// the .swiftinterface input or its dependencies.
86-
std::string getCacheHash(ASTContext &Ctx,
87-
CompilerInvocation &SubInvocation,
88-
StringRef InPath) {
103+
static std::string getCacheHash(ASTContext &Ctx,
104+
CompilerInvocation &SubInvocation,
105+
StringRef InPath) {
89106
// Start with the compiler version (which will be either tag names or revs).
90107
std::string vers = swift::version::getSwiftFullVersion(
91108
Ctx.LangOpts.EffectiveLanguageVersion);
@@ -154,7 +171,8 @@ ParseableInterfaceModuleLoader::configureSubInvocationAndOutputPaths(
154171
static bool
155172
swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
156173
StringRef ModuleCachePath,
157-
StringRef OutPath) {
174+
StringRef OutPath,
175+
DiagnosticEngine &Diags) {
158176

159177
if (!FS.exists(OutPath))
160178
return false;
@@ -177,10 +195,12 @@ swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
177195
return false;
178196

179197
for (auto In : AllDeps) {
198+
uint64_t Hash = 0;
180199
auto InStatus = FS.status(In.Path);
181200
if (!InStatus ||
182201
(InStatus.get().getSize() != In.Size) ||
183-
(InStatus.get().getLastModificationTime() != In.LastModTime)) {
202+
getHashOfFile(FS, In.Path, Hash, Diags) ||
203+
(Hash != In.Hash)) {
184204
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path
185205
<< " is directly out of date\n");
186206
return false;
@@ -190,7 +210,7 @@ swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
190210
auto Ty = file_types::lookupTypeForExtension(Ext);
191211
if (Ty == file_types::TY_SwiftModuleFile &&
192212
In.Path.startswith(ModuleCachePath) &&
193-
!swiftModuleIsUpToDate(FS, ModuleCachePath, In.Path)) {
213+
!swiftModuleIsUpToDate(FS, ModuleCachePath, In.Path, Diags)) {
194214
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path
195215
<< " is indirectly out of date\n");
196216
return false;
@@ -276,9 +296,13 @@ static bool buildSwiftModuleFromSwiftInterface(
276296
SubError = true;
277297
return;
278298
}
299+
uint64_t Hash = 0;
300+
if (getHashOfFile(FS, Dep, Hash, Diags)) {
301+
SubError = true;
302+
return;
303+
}
279304
Deps.push_back(SerializationOptions::FileDependency{
280-
DepStatus.get().getSize(), DepStatus.get().getLastModificationTime(),
281-
Dep});
305+
DepStatus.get().getSize(), Hash, Dep});
282306
}
283307
serializationOpts.Dependencies = Deps;
284308
SILMod->setSerializeSILAction([&]() {
@@ -317,7 +341,7 @@ std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
317341
configureSubInvocationAndOutputPaths(SubInvocation, InPath, OutPath);
318342

319343
// Evaluate if we need to run this sub-invocation, and if so run it.
320-
if (!swiftModuleIsUpToDate(FS, CacheDir, OutPath)) {
344+
if (!swiftModuleIsUpToDate(FS, CacheDir, OutPath, Diags)) {
321345
if (buildSwiftModuleFromSwiftInterface(FS, Diags, SubInvocation, InPath,
322346
OutPath))
323347
return std::make_error_code(std::errc::invalid_argument);

lib/Serialization/ModuleFile.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ static bool validateInputBlock(
254254
switch (kind) {
255255
case input_block::FILE_DEPENDENCY:
256256
dependencies.push_back(SerializationOptions::FileDependency{
257-
scratch[0], llvm::sys::toTimePoint(scratch[1]), blobData});
257+
scratch[0], scratch[1], blobData});
258258
break;
259259
default:
260260
// Unknown metadata record, possibly for use by a future version of the

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,9 +1053,7 @@ void Serializer::writeInputBlock(const SerializationOptions &options) {
10531053
}
10541054

10551055
for (auto const &dep : options.Dependencies) {
1056-
FileDependency.emit(ScratchRecord, dep.Size,
1057-
llvm::sys::toTimeT(dep.LastModTime),
1058-
dep.Path);
1056+
FileDependency.emit(ScratchRecord, dep.Size, dep.Hash, dep.Path);
10591057
}
10601058

10611059
SmallVector<ModuleDecl::ImportedModule, 8> allImports;
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Setup builds a module TestModule that depends on OtherModule and LeafModule (built from other.swift and leaf.swift).
55
// During setup, input and intermediate mtimes are all set to a constant 'old' time (long in the past).
66
//
7-
// We then modify OtherModule.swiftinterface, and check only OtherModule-*.swiftmodule has a new mtime, LeafModule is unchanged.
7+
// We then modify OtherModule.swiftinterface's content (but not size), and check only OtherModule-*.swiftmodule has a new mtime, LeafModule is unchanged.
88
//
99
//
1010
// Setup phase 1: Write input files.
@@ -13,6 +13,7 @@
1313
//
1414
// RUN: echo 'import LeafModule' >%t/other.swift
1515
// RUN: echo 'public func OtherFunc() -> Int { return LeafFunc(); }' >>%t/other.swift
16+
// RUN: echo 'public func OtherFunc2() -> Int { return LeafFunc(); }' >>%t/other.swift
1617
//
1718
//
1819
// Setup phase 2: build modules, pushing timestamps of inputs and intermediates into the past as we go.
@@ -26,12 +27,12 @@
2627
// RUN: %S/Inputs/make-old.py %t/modulecache/OtherModule-*.swiftmodule
2728
//
2829
//
29-
// Actual test: make OtherModule.swiftinterface newer, check we only rebuild its cached module.
30+
// Actual test: Change a byte in OtherModule.swiftinterface, check we only rebuild its cached module.
3031
//
3132
// RUN: %S/Inputs/check-is-old.py %t/OtherModule.swiftinterface %t/LeafModule.swiftinterface
3233
// RUN: %S/Inputs/check-is-old.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule
33-
// RUN: touch %t/OtherModule.swiftinterface
34-
// RUN: %S/Inputs/check-is-new.py %t/OtherModule.swiftinterface
34+
// RUN: sed -e 's/OtherFunc2/OtterFunc2/' -i.prev %t/OtherModule.swiftinterface
35+
// RUN: %S/Inputs/make-old.py %t/OtherModule.swiftinterface
3536
// RUN: rm %t/TestModule.swiftmodule
3637
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -enable-parseable-module-interface -emit-module -o %t/TestModule.swiftmodule -module-name TestModule %s
3738
// RUN: %S/Inputs/check-is-new.py %t/modulecache/OtherModule-*.swiftmodule

test/ParseableInterface/ModuleCache/module-cache-leaf-mtime-change-rebuilds-all.swift renamed to test/ParseableInterface/ModuleCache/module-cache-leaf-hash-change-rebuilds-all.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
// Setup builds a module TestModule that depends on OtherModule and LeafModule (built from other.swift and leaf.swift).
55
// During setup, input and intermediate mtimes are all set to a constant 'old' time (long in the past).
66
//
7-
// We then modify LeafModule.swiftinterface, and check both cached modules have new mtimes.
7+
// We then modify LeafModule.swiftinterface's content (but not size), and check both cached modules have new mtimes.
88
//
99
//
1010
// Setup phase 1: Write input files.
1111
//
1212
// RUN: echo 'public func LeafFunc() -> Int { return 10; }' >%t/leaf.swift
13+
// RUN: echo 'public func LeafFunc2() -> Int { return 11; }' >>%t/leaf.swift
1314
//
1415
// RUN: echo 'import LeafModule' >%t/other.swift
1516
// RUN: echo 'public func OtherFunc() -> Int { return LeafFunc(); }' >>%t/other.swift
@@ -26,12 +27,12 @@
2627
// RUN: %S/Inputs/make-old.py %t/modulecache/OtherModule-*.swiftmodule
2728
//
2829
//
29-
// Actual test: make LeafModule.swiftinterface newer, check both cached modules get rebuilt.
30+
// Actual test: Change a byte in LeafModule.swiftinterface, check both cached modules get rebuilt.
3031
//
3132
// RUN: %S/Inputs/check-is-old.py %t/OtherModule.swiftinterface %t/LeafModule.swiftinterface
3233
// RUN: %S/Inputs/check-is-old.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule
33-
// RUN: touch %t/LeafModule.swiftinterface
34-
// RUN: %S/Inputs/check-is-new.py %t/LeafModule.swiftinterface
34+
// RUN: sed -e 's/LeafFunc2/LoafFunc2/' -i.prev %t/LeafModule.swiftinterface
35+
// RUN: %S/Inputs/make-old.py %t/LeafModule.swiftinterface
3536
// RUN: rm %t/TestModule.swiftmodule
3637
// RUN: %target-swift-frontend -I %t -module-cache-path %t/modulecache -enable-parseable-module-interface -emit-module -o %t/TestModule.swiftmodule -module-name TestModule %s
3738
// RUN: %S/Inputs/check-is-new.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule

0 commit comments

Comments
 (0)