27
27
#include " clang/Lex/Preprocessor.h"
28
28
#include " clang/Lex/HeaderSearch.h"
29
29
#include " llvm/ADT/Hashing.h"
30
+ #include " llvm/ADT/StringSet.h"
30
31
#include " llvm/Support/xxhash.h"
31
32
#include " llvm/Support/Debug.h"
32
33
#include " llvm/Support/CommandLine.h"
36
37
#include " llvm/Support/StringSaver.h"
37
38
38
39
using namespace swift ;
40
+ using FileDependency = SerializationOptions::FileDependency;
39
41
40
42
#define SWIFT_TOOLS_VERSION_KEY " swift-tools-version"
41
43
#define SWIFT_MODULE_FLAGS_KEY " swift-module-flags"
@@ -74,20 +76,19 @@ extractSwiftInterfaceVersionAndArgs(DiagnosticEngine &Diags,
74
76
return false ;
75
77
}
76
78
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 ;
88
90
}
89
- HashOut = xxHash64 (Buf.get ()->getBuffer ());
90
- return false ;
91
+ return std::move (DepBuf.get ());
91
92
}
92
93
93
94
// / Construct a cache key for the .swiftmodule being generated. There is a
@@ -174,19 +175,12 @@ swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
174
175
StringRef OutPath,
175
176
DiagnosticEngine &Diags) {
176
177
177
- if (!FS.exists (OutPath))
178
- return false ;
179
-
180
- auto OutStatus = FS.status (OutPath);
181
- if (!OutStatus)
182
- return false ;
183
-
184
178
auto OutBuf = FS.getBufferForFile (OutPath);
185
179
if (!OutBuf)
186
180
return false ;
187
181
188
182
LLVM_DEBUG (llvm::dbgs () << " Validating deps of " << OutPath << " \n " );
189
- SmallVector<SerializationOptions:: FileDependency, 16 > AllDeps;
183
+ SmallVector<FileDependency, 16 > AllDeps;
190
184
auto VI = serialization::validateSerializedAST (
191
185
OutBuf.get ()->getBuffer (),
192
186
/* ExtendedValidationInfo=*/ nullptr , &AllDeps);
@@ -195,34 +189,83 @@ swiftModuleIsUpToDate(clang::vfs::FileSystem &FS,
195
189
return false ;
196
190
197
191
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 ) {
204
196
LLVM_DEBUG (llvm::dbgs () << " Dep " << In.Path
205
197
<< " is directly out of date\n " );
206
198
return false ;
207
199
}
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);
210
241
auto Ty = file_types::lookupTypeForExtension (Ext);
211
242
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
+ }
217
260
}
218
- LLVM_DEBUG (llvm::dbgs () << " Dep " << In.Path << " is up to date\n " );
219
261
}
220
- return true ;
262
+ return false ;
221
263
}
222
264
223
265
static bool buildSwiftModuleFromSwiftInterface (
224
266
clang::vfs::FileSystem &FS, DiagnosticEngine &Diags,
225
- CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath) {
267
+ CompilerInvocation &SubInvocation, StringRef InPath, StringRef OutPath,
268
+ StringRef ModuleCachePath) {
226
269
bool SubError = false ;
227
270
bool RunSuccess = llvm::CrashRecoveryContext ().RunSafelyOnThread ([&] {
228
271
@@ -279,34 +322,19 @@ static bool buildSwiftModuleFromSwiftInterface(
279
322
}
280
323
281
324
LLVM_DEBUG (llvm::dbgs () << " Serializing " << OutPath << " \n " );
282
- SerializationOptions serializationOpts ;
325
+ SerializationOptions SerializationOpts ;
283
326
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 ;
306
334
}
307
- serializationOpts .Dependencies = Deps;
335
+ SerializationOpts .Dependencies = Deps;
308
336
SILMod->setSerializeSILAction ([&]() {
309
- serialize (Mod, serializationOpts , SILMod.get ());
337
+ serialize (Mod, SerializationOpts , SILMod.get ());
310
338
});
311
339
SILMod->serialize ();
312
340
SubError = Diags.hadAnyError ();
@@ -343,7 +371,7 @@ std::error_code ParseableInterfaceModuleLoader::openModuleFiles(
343
371
// Evaluate if we need to run this sub-invocation, and if so run it.
344
372
if (!swiftModuleIsUpToDate (FS, CacheDir, OutPath, Diags)) {
345
373
if (buildSwiftModuleFromSwiftInterface (FS, Diags, SubInvocation, InPath,
346
- OutPath))
374
+ OutPath, CacheDir ))
347
375
return std::make_error_code (std::errc::invalid_argument);
348
376
}
349
377
0 commit comments