Skip to content

Commit 01fb476

Browse files
committed
---
yaml --- r: 346727 b: refs/heads/master c: 34d9c2e h: refs/heads/master i: 346725: cbab822 346723: 932c6bc 346719: c1025fd
1 parent 649f984 commit 01fb476

File tree

7 files changed

+84
-29
lines changed

7 files changed

+84
-29
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 64002eccd4847c1aed961364970c914e94ad2fef
2+
refs/heads/master: 34d9c2e1782ed87752fdb896208b4217c6f0c412
33
refs/heads/master-next: 203b3026584ecad859eb328b2e12490099409cd5
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea

trunk/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-
uint64_t Hash;
40+
uint64_t ModificationTime;
4141
std::string Path;
4242
};
4343
ArrayRef<FileDependency> Dependencies;

trunk/lib/Frontend/ParseableInterfaceSupport.cpp

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ getBufferOfDependency(llvm::vfs::FileSystem &FS,
9797
return std::move(DepBuf.get());
9898
}
9999

100+
static Optional<clang::vfs::Status>
101+
getStatusOfDependency(clang::vfs::FileSystem &FS,
102+
StringRef ModulePath, StringRef DepPath,
103+
DiagnosticEngine &Diags, SourceLoc DiagLoc) {
104+
auto Status = FS.status(DepPath);
105+
if (!Status) {
106+
Diags.diagnose(DiagLoc,
107+
diag::missing_dependency_of_parseable_module_interface,
108+
DepPath, ModulePath, Status.getError().message());
109+
return None;
110+
}
111+
return Status.get();
112+
}
113+
100114
/// Construct a cache key for the .swiftmodule being generated. There is a
101115
/// balance to be struck here between things that go in the cache key and
102116
/// things that go in the "up to date" check of the cache entry. We want to
@@ -111,20 +125,23 @@ static std::string getCacheHash(ASTContext &Ctx,
111125
const CompilerInvocation &SubInvocation,
112126
StringRef InPath) {
113127
// Start with the compiler version (which will be either tag names or revs).
114-
std::string vers = swift::version::getSwiftFullVersion(
115-
Ctx.LangOpts.EffectiveLanguageVersion);
116-
llvm::hash_code H = llvm::hash_value(vers);
128+
// Explicitly don't pass in the "effective" language version -- this would
129+
// mean modules built in different -swift-version modes would rebuild their
130+
// dependencies.
131+
llvm::hash_code H = hash_value(swift::version::getSwiftFullVersion());
117132

118133
// Simplest representation of input "identity" (not content) is just a
119134
// pathname, and probably all we can get from the VFS in this regard anyways.
120-
H = llvm::hash_combine(H, InPath);
135+
H = hash_combine(H, InPath);
136+
137+
// Include the target CPU. In practice, .swiftinterface files will be in
138+
// architecture-specific subdirectories and would have target-specific pieces
139+
// #if'd out. However, it doesn't hurt to include it, and it guards against
140+
// mistakenly reusing cached modules across targets.
141+
H = hash_combine(H, SubInvocation.getTargetTriple());
121142

122-
// ClangImporterOpts does include the target CPU, which is redundant: we
123-
// already have separate .swiftinterface files per target due to expanding
124-
// preprocessing directives, but further specializing the cache key to that
125-
// target is harmless and will not make any extra cache entries, so allow it.
126-
H = llvm::hash_combine(
127-
H, SubInvocation.getClangImporterOptions().getPCHHashComponents());
143+
// The SDK path is going to affect how this module is imported, so include it.
144+
H = hash_combine(H, SubInvocation.getSDKPath());
128145

129146
return llvm::APInt(64, H).toString(36, /*Signed=*/false);
130147
}
@@ -195,6 +212,17 @@ void ParseableInterfaceModuleLoader::configureSubInvocationInputsAndOutputs(
195212
SubFEOpts.InputsAndOutputs.setMainAndSupplementaryOutputs({MainOut}, {SOPs});
196213
}
197214

215+
// Checks that a dependency read from the cached module is up to date compared
216+
// to the interface file it represents.
217+
static bool dependencyIsUpToDate(clang::vfs::FileSystem &FS, FileDependency In,
218+
StringRef ModulePath, DiagnosticEngine &Diags,
219+
SourceLoc DiagLoc) {
220+
auto Status = getStatusOfDependency(FS, ModulePath, In.Path, Diags, DiagLoc);
221+
if (!Status) return false;
222+
uint64_t mtime = Status->getLastModificationTime().time_since_epoch().count();
223+
return Status->getSize() == In.Size && mtime == In.ModificationTime;
224+
}
225+
198226
// Check that the output .swiftmodule file is at least as new as all the
199227
// dependencies it read when it was built last time.
200228
static bool
@@ -223,11 +251,7 @@ swiftModuleIsUpToDate(llvm::vfs::FileSystem &FS,
223251
for (auto In : AllDeps) {
224252
if (OuterTracker)
225253
OuterTracker->addDependency(In.Path, /*IsSystem=*/false);
226-
auto DepBuf = getBufferOfDependency(FS, OutPath, In.Path, Diags,
227-
ModuleID.second);
228-
if (!DepBuf ||
229-
DepBuf->getBufferSize() != In.Size ||
230-
xxHash64(DepBuf->getBuffer()) != In.Hash) {
254+
if (!dependencyIsUpToDate(FS, In, OutPath, Diags, ModuleID.second)) {
231255
LLVM_DEBUG(llvm::dbgs() << "Dep " << In.Path
232256
<< " is directly out of date\n");
233257
return false;
@@ -263,13 +287,15 @@ collectDepsForSerialization(llvm::vfs::FileSystem &FS,
263287
if (AllDepNames.insert(DepName).second && OuterTracker) {
264288
OuterTracker->addDependency(DepName, /*IsSystem=*/false);
265289
}
290+
auto Status = getStatusOfDependency(FS, InPath, DepName, Diags, DiagLoc);
291+
if (!Status)
292+
return true;
266293
auto DepBuf = getBufferOfDependency(FS, InPath, DepName, Diags, DiagLoc);
267-
if (!DepBuf) {
294+
if (!DepBuf)
268295
return true;
269-
}
270-
uint64_t Size = DepBuf->getBufferSize();
271-
uint64_t Hash = xxHash64(DepBuf->getBuffer());
272-
Deps.push_back(FileDependency{Size, Hash, DepName});
296+
uint64_t mtime =
297+
Status->getLastModificationTime().time_since_epoch().count();
298+
Deps.push_back(FileDependency{Status->getSize(), mtime, DepName});
273299

274300
if (ModuleCachePath.empty())
275301
continue;

trunk/lib/Serialization/Serialization.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,9 @@ void Serializer::writeInputBlock(const SerializationOptions &options) {
10581058
}
10591059

10601060
for (auto const &dep : options.Dependencies) {
1061-
FileDependency.emit(ScratchRecord, dep.Size, dep.Hash, dep.Path);
1061+
FileDependency.emit(ScratchRecord, dep.Size,
1062+
dep.ModificationTime,
1063+
dep.Path);
10621064
}
10631065

10641066
SmallVector<ModuleDecl::ImportedModule, 8> allImports;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
//
3+
// Test will build a module TestModule that depends on OtherModule and LeafModule (built from other.swift and leaf.swift).
4+
//
5+
// RUN: echo 'public func LeafFunc() -> Int { return 10; }' >%t/leaf.swift
6+
//
7+
// RUN: echo 'import LeafModule' >%t/other.swift
8+
// RUN: echo 'public func OtherFunc() -> Int { return LeafFunc(); }' >>%t/other.swift
9+
//
10+
// Phase 1: build LeafModule into a .swiftinterface file with -swift-version 4:
11+
//
12+
// RUN: %target-swift-frontend -swift-version 4 -I %t -module-cache-path %t/modulecache -emit-parseable-module-interface-path %t/LeafModule.swiftinterface -module-name LeafModule %t/leaf.swift -typecheck
13+
//
14+
// Phase 2: build OtherModule into a .swiftinterface file with -swift-version 4.2:
15+
//
16+
// RUN: %target-swift-frontend -swift-version 4.2 -I %t -module-cache-path %t/modulecache -emit-parseable-module-interface-path %t/OtherModule.swiftinterface -module-name OtherModule %t/other.swift -enable-parseable-module-interface -typecheck
17+
//
18+
// Phase 3: build TestModule in -swift-version 5 and import both of these:
19+
//
20+
// RUN: %target-swift-frontend -swift-version 5 -I %t -module-cache-path %t/modulecache -module-name TestModule %s -enable-parseable-module-interface -typecheck
21+
//
22+
// Phase 4: make sure we only compiled LeafModule and OtherModule one time:
23+
//
24+
// RUN: NUM_LEAF_MODULES=$(find %t/modulecache -type f -name 'LeafModule-*.swiftmodule' | wc -l)
25+
// RUN: NUM_OTHER_MODULES=$(find %t/modulecache -type f -name 'OtherModule-*.swiftmodule' | wc -l)
26+
// RUN: if [ ! $NUM_LEAF_MODULES -eq 1 ]; then echo "Should only be 1 LeafModule, found $NUM_LEAF_MODULES"; exit 1; fi
27+
// RUN: if [ ! $NUM_OTHER_MODULES -eq 1 ]; then echo "Should only be 1 OtherModule, found $NUM_OTHER_MODULES"; exit 1; fi
28+
import LeafModule
29+
import OtherModule
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@
2727
// RUN: %{python} %S/Inputs/make-old.py %t/modulecache/OtherModule-*.swiftmodule
2828
//
2929
//
30-
// Actual test: Change a byte in OtherModule.swiftinterface, check we only rebuild its cached module.
30+
// Actual test: Change the mtime of OtherModule.swiftinterface, check we only rebuild its cached module.
3131
//
3232
// RUN: %{python} %S/Inputs/check-is-old.py %t/OtherModule.swiftinterface %t/LeafModule.swiftinterface
3333
// RUN: %{python} %S/Inputs/check-is-old.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule
34-
// RUN: sed -e 's/OtherFunc2/OtterFunc2/' -i.prev %t/OtherModule.swiftinterface
35-
// RUN: %{python} %S/Inputs/make-old.py %t/OtherModule.swiftinterface
34+
// RUN: touch %t/OtherModule.swiftinterface
3635
// RUN: rm %t/TestModule.swiftmodule
3736
// 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
3837
// RUN: %{python} %S/Inputs/check-is-new.py %t/modulecache/OtherModule-*.swiftmodule

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@
2727
// RUN: %{python} %S/Inputs/make-old.py %t/modulecache/OtherModule-*.swiftmodule
2828
//
2929
//
30-
// Actual test: Change a byte in LeafModule.swiftinterface, check both cached modules get rebuilt.
30+
// Actual test: Change the mtime of LeafModule.swiftinterface, check both cached modules get rebuilt.
3131
//
3232
// RUN: %{python} %S/Inputs/check-is-old.py %t/OtherModule.swiftinterface %t/LeafModule.swiftinterface
3333
// RUN: %{python} %S/Inputs/check-is-old.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule
34-
// RUN: sed -e 's/LeafFunc2/LoafFunc2/' -i.prev %t/LeafModule.swiftinterface
35-
// RUN: %{python} %S/Inputs/make-old.py %t/LeafModule.swiftinterface
34+
// RUN: touch %t/LeafModule.swiftinterface
3635
// RUN: rm %t/TestModule.swiftmodule
3736
// 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
3837
// RUN: %{python} %S/Inputs/check-is-new.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule

0 commit comments

Comments
 (0)