14
14
#include " clang/Serialization/ASTReader.h"
15
15
#include " clang/Serialization/InMemoryModuleCache.h"
16
16
#include " llvm/ADT/ScopeExit.h"
17
+ #include < queue>
17
18
18
19
namespace clang {
19
20
namespace clangd {
@@ -125,6 +126,11 @@ struct ModuleFile {
125
126
llvm::sys::fs::remove (ModuleFilePath);
126
127
}
127
128
129
+ StringRef getModuleName () const { return ModuleName; }
130
+
131
+ StringRef getModuleFilePath () const { return ModuleFilePath; }
132
+
133
+ private:
128
134
std::string ModuleName;
129
135
std::string ModuleFilePath;
130
136
};
@@ -213,7 +219,8 @@ class ReusablePrerequisiteModules : public PrerequisiteModules {
213
219
// Appending all built module files.
214
220
for (auto &RequiredModule : RequiredModules)
215
221
Options.PrebuiltModuleFiles .insert_or_assign (
216
- RequiredModule->ModuleName , RequiredModule->ModuleFilePath );
222
+ RequiredModule->getModuleName ().str (),
223
+ RequiredModule->getModuleFilePath ().str ());
217
224
}
218
225
219
226
bool canReuse (const CompilerInvocation &CI,
@@ -224,12 +231,12 @@ class ReusablePrerequisiteModules : public PrerequisiteModules {
224
231
}
225
232
226
233
void addModuleFile (std::shared_ptr<ModuleFile> BMI) {
227
- BuiltModuleNames.insert (BMI->ModuleName );
234
+ BuiltModuleNames.insert (BMI->getModuleName () );
228
235
RequiredModules.emplace_back (std::move (BMI));
229
236
}
230
237
231
238
private:
232
- mutable llvm::SmallVector<std::shared_ptr<ModuleFile>, 8 > RequiredModules;
239
+ llvm::SmallVector<std::shared_ptr<ModuleFile>, 8 > RequiredModules;
233
240
// A helper class to speedup the query if a module is built.
234
241
llvm::StringSet<> BuiltModuleNames;
235
242
};
@@ -298,12 +305,11 @@ bool ReusablePrerequisiteModules::canReuse(
298
305
299
306
SmallVector<StringRef> BMIPaths;
300
307
for (auto &MF : RequiredModules)
301
- BMIPaths.push_back (MF->ModuleFilePath );
308
+ BMIPaths.push_back (MF->getModuleFilePath () );
302
309
return IsModuleFilesUpToDate (BMIPaths, *this , VFS);
303
310
}
304
- } // namespace
305
311
306
- class ModulesBuilder :: ModuleFileCache {
312
+ class ModuleFileCache {
307
313
public:
308
314
ModuleFileCache (const GlobalCompilationDatabase &CDB) : CDB(CDB) {}
309
315
@@ -313,68 +319,107 @@ class ModulesBuilder::ModuleFileCache {
313
319
ReusablePrerequisiteModules &RequiredModules);
314
320
const GlobalCompilationDatabase &getCDB () const { return CDB; }
315
321
316
- private:
317
322
std::shared_ptr<ModuleFile>
318
323
getValidModuleFile (StringRef ModuleName, ProjectModules &MDB,
319
324
const ThreadsafeFS &TFS,
320
325
PrerequisiteModules &BuiltModuleFiles);
321
326
322
- // / This should only be called by getValidModuleFile. This is unlocked version
323
- // / of getValidModuleFile. The function is extracted to avoid dead locks when
324
- // / recursing.
325
- std::shared_ptr<ModuleFile>
326
- isValidModuleFileUnlocked (StringRef ModuleName, ProjectModules &MDB,
327
- const ThreadsafeFS &TFS,
328
- PrerequisiteModules &BuiltModuleFiles);
327
+ void add (StringRef ModuleName, std::shared_ptr<ModuleFile> ModuleFile) {
328
+ std::lock_guard<std::mutex> _ (ModuleFilesMutex);
329
+
330
+ ModuleFiles.insert_or_assign (ModuleName, ModuleFile);
331
+ }
329
332
333
+ private:
330
334
const GlobalCompilationDatabase &CDB;
331
335
332
336
llvm::StringMap<std::shared_ptr<ModuleFile>> ModuleFiles;
333
337
// Mutex to guard accesses to ModuleFiles.
334
338
std::mutex ModuleFilesMutex;
335
339
};
336
340
341
+ // / Collect the directly and indirectly required module names for \param
342
+ // / ModuleName. The \param ModuleName is guaranteed to be the first element in
343
+ // / \param ModuleNames.
344
+ void getAllRequiredModules (ProjectModules &MDB, StringRef ModuleName,
345
+ llvm::SmallVector<StringRef> &ModuleNames) {
346
+ std::queue<StringRef> Worklist;
347
+ llvm::StringSet<> ModuleNamesSet;
348
+ Worklist.push (ModuleName);
349
+
350
+ while (!Worklist.empty ()) {
351
+ StringRef CurrentModule = Worklist.front ();
352
+ Worklist.pop ();
353
+
354
+ if (!ModuleNamesSet.insert (CurrentModule).second )
355
+ continue ;
356
+
357
+ ModuleNames.push_back (CurrentModule);
358
+
359
+ for (StringRef RequiredModuleName :
360
+ MDB.getRequiredModules (MDB.getSourceForModuleName (CurrentModule)))
361
+ if (!ModuleNamesSet.contains (RequiredModuleName))
362
+ Worklist.push (RequiredModuleName);
363
+ }
364
+ }
365
+
337
366
std::shared_ptr<ModuleFile>
338
- ModulesBuilder::ModuleFileCache::isValidModuleFileUnlocked (
339
- StringRef ModuleName, ProjectModules &MDB, const ThreadsafeFS &TFS,
340
- PrerequisiteModules &BuiltModuleFiles) {
341
- auto Iter = ModuleFiles.find (ModuleName);
342
- if (Iter != ModuleFiles.end ()) {
343
- if (!IsModuleFileUpToDate (Iter->second ->ModuleFilePath , BuiltModuleFiles,
344
- TFS.view (std::nullopt))) {
345
- log (" Found not-up-date module file {0} for module {1} in cache" ,
346
- Iter->second ->ModuleFilePath , ModuleName);
347
- ModuleFiles.erase (Iter);
348
- return nullptr ;
349
- }
367
+ ModuleFileCache::getValidModuleFile (StringRef ModuleName, ProjectModules &MDB,
368
+ const ThreadsafeFS &TFS,
369
+ PrerequisiteModules &BuiltModuleFiles) {
370
+ {
371
+ std::lock_guard<std::mutex> _ (ModuleFilesMutex);
350
372
351
- if (llvm::any_of (
352
- MDB.getRequiredModules (MDB.getSourceForModuleName (ModuleName)),
353
- [&MDB, &TFS, &BuiltModuleFiles, this ](auto &&RequiredModuleName) {
354
- return !isValidModuleFileUnlocked (RequiredModuleName, MDB, TFS,
355
- BuiltModuleFiles);
356
- })) {
357
- ModuleFiles.erase (Iter);
373
+ if (ModuleFiles.find (ModuleName) == ModuleFiles.end ())
358
374
return nullptr ;
359
- }
375
+ }
376
+
377
+ llvm::SmallVector<StringRef> ModuleNames;
378
+ getAllRequiredModules (MDB, ModuleName, ModuleNames);
379
+
380
+ llvm::SmallVector<std::shared_ptr<ModuleFile>> RequiredModuleFiles;
381
+
382
+ {
383
+ std::lock_guard<std::mutex> _ (ModuleFilesMutex);
384
+
385
+ for (StringRef ModuleName : ModuleNames) {
386
+ auto Iter = ModuleFiles.find (ModuleName);
387
+ if (Iter == ModuleFiles.end ())
388
+ return nullptr ;
360
389
361
- return Iter->second ;
390
+ RequiredModuleFiles.push_back (Iter->second );
391
+ }
362
392
}
363
393
364
- log (" Don't find {0} in cache" , ModuleName);
394
+ if (RequiredModuleFiles.empty ())
395
+ return nullptr ;
396
+
397
+ if (llvm::all_of (RequiredModuleFiles, [&](auto MF) {
398
+ return IsModuleFileUpToDate (MF->getModuleFilePath (), BuiltModuleFiles,
399
+ TFS.view (std::nullopt));
400
+ }))
401
+ return RequiredModuleFiles[0 ];
365
402
366
403
return nullptr ;
367
404
}
405
+ } // namespace
368
406
369
- std::shared_ptr<ModuleFile> ModulesBuilder::ModuleFileCache::getValidModuleFile (
370
- StringRef ModuleName, ProjectModules &MDB, const ThreadsafeFS &TFS,
371
- PrerequisiteModules &BuiltModuleFiles) {
372
- std::lock_guard<std::mutex> _ (ModuleFilesMutex);
407
+ class ModulesBuilder ::ModulesBuilderImpl {
408
+ public:
409
+ ModulesBuilderImpl (const GlobalCompilationDatabase &CDB) : Cache(CDB) {}
373
410
374
- return isValidModuleFileUnlocked (ModuleName, MDB, TFS, BuiltModuleFiles);
375
- }
411
+ const GlobalCompilationDatabase &getCDB () const { return Cache.getCDB (); }
376
412
377
- llvm::Error ModulesBuilder::ModuleFileCache::getOrBuildModuleFile (
413
+ llvm::Error
414
+ getOrBuildModuleFile (StringRef ModuleName, const ThreadsafeFS &TFS,
415
+ ProjectModules &MDB,
416
+ ReusablePrerequisiteModules &BuiltModuleFiles);
417
+
418
+ private:
419
+ ModuleFileCache Cache;
420
+ };
421
+
422
+ llvm::Error ModulesBuilder::ModulesBuilderImpl::getOrBuildModuleFile (
378
423
StringRef ModuleName, const ThreadsafeFS &TFS, ProjectModules &MDB,
379
424
ReusablePrerequisiteModules &BuiltModuleFiles) {
380
425
if (BuiltModuleFiles.isModuleUnitBuilt (ModuleName))
@@ -399,8 +444,8 @@ llvm::Error ModulesBuilder::ModuleFileCache::getOrBuildModuleFile(
399
444
llvm::formatv (" Failed to build module {0}" , RequiredModuleName));
400
445
401
446
if (std::shared_ptr<ModuleFile> Cached =
402
- getValidModuleFile (ModuleName, MDB, TFS, BuiltModuleFiles)) {
403
- log (" Reusing module {0} from {1}" , ModuleName, Cached->ModuleFilePath );
447
+ Cache. getValidModuleFile (ModuleName, MDB, TFS, BuiltModuleFiles)) {
448
+ log (" Reusing module {0} from {1}" , ModuleName, Cached->getModuleFilePath () );
404
449
BuiltModuleFiles.addModuleFile (Cached);
405
450
return llvm::Error::success ();
406
451
}
@@ -411,25 +456,23 @@ llvm::Error ModulesBuilder::ModuleFileCache::getOrBuildModuleFile(
411
456
getUniqueModuleFilesPath (ModuleUnitFileName);
412
457
413
458
llvm::Expected<ModuleFile> MF =
414
- buildModuleFile (ModuleName, ModuleUnitFileName, CDB , TFS,
459
+ buildModuleFile (ModuleName, ModuleUnitFileName, getCDB () , TFS,
415
460
ModuleFilesPrefix, BuiltModuleFiles);
416
461
if (llvm::Error Err = MF.takeError ())
417
462
return Err;
418
463
419
- log (" Built module {0} to {1}" , ModuleName, MF->ModuleFilePath );
420
-
421
- std::lock_guard<std::mutex> __ (ModuleFilesMutex);
464
+ log (" Built module {0} to {1}" , ModuleName, MF->getModuleFilePath ());
422
465
auto BuiltModuleFile = std::make_shared<ModuleFile>(std::move (*MF));
423
- ModuleFiles. insert_or_assign (ModuleName, BuiltModuleFile);
466
+ Cache. add (ModuleName, BuiltModuleFile);
424
467
BuiltModuleFiles.addModuleFile (std::move (BuiltModuleFile));
425
468
426
469
return llvm::Error::success ();
427
470
}
471
+
428
472
std::unique_ptr<PrerequisiteModules>
429
473
ModulesBuilder::buildPrerequisiteModulesFor (PathRef File,
430
474
const ThreadsafeFS &TFS) {
431
- std::unique_ptr<ProjectModules> MDB =
432
- MFCache->getCDB ().getProjectModules (File);
475
+ std::unique_ptr<ProjectModules> MDB = Impl->getCDB ().getProjectModules (File);
433
476
if (!MDB) {
434
477
elog (" Failed to get Project Modules information for {0}" , File);
435
478
return std::make_unique<FailedPrerequisiteModules>();
@@ -448,7 +491,7 @@ ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
448
491
449
492
for (llvm::StringRef RequiredModuleName : RequiredModuleNames) {
450
493
// Return early if there is any error.
451
- if (llvm::Error Err = MFCache ->getOrBuildModuleFile (
494
+ if (llvm::Error Err = Impl ->getOrBuildModuleFile (
452
495
RequiredModuleName, TFS, *MDB.get (), *RequiredModules.get ())) {
453
496
elog (" Failed to build module {0}; due to {1}" , RequiredModuleName,
454
497
toString (std::move (Err)));
@@ -462,7 +505,7 @@ ModulesBuilder::buildPrerequisiteModulesFor(PathRef File,
462
505
}
463
506
464
507
ModulesBuilder::ModulesBuilder (const GlobalCompilationDatabase &CDB) {
465
- MFCache = std::make_unique<ModuleFileCache >(CDB);
508
+ Impl = std::make_unique<ModulesBuilderImpl >(CDB);
466
509
}
467
510
468
511
ModulesBuilder::~ModulesBuilder () {}
0 commit comments