1461a67faSDimitry Andric //===- ModuleManager.cpp - Module Manager ---------------------------------===//
236981b17SDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
636981b17SDimitry Andric //
736981b17SDimitry Andric //===----------------------------------------------------------------------===//
836981b17SDimitry Andric //
936981b17SDimitry Andric // This file defines the ModuleManager class, which manages a set of loaded
1036981b17SDimitry Andric // modules for the ASTReader.
1136981b17SDimitry Andric //
1236981b17SDimitry Andric //===----------------------------------------------------------------------===//
13461a67faSDimitry Andric
14bab175ecSDimitry Andric #include "clang/Serialization/ModuleManager.h"
15461a67faSDimitry Andric #include "clang/Basic/FileManager.h"
16461a67faSDimitry Andric #include "clang/Basic/LLVM.h"
179f4dbff6SDimitry Andric #include "clang/Lex/HeaderSearch.h"
18809500fcSDimitry Andric #include "clang/Lex/ModuleMap.h"
19809500fcSDimitry Andric #include "clang/Serialization/GlobalModuleIndex.h"
2022989816SDimitry Andric #include "clang/Serialization/InMemoryModuleCache.h"
21706b4fc4SDimitry Andric #include "clang/Serialization/ModuleFile.h"
22676fbe81SDimitry Andric #include "clang/Serialization/PCHContainerOperations.h"
23461a67faSDimitry Andric #include "llvm/ADT/STLExtras.h"
24461a67faSDimitry Andric #include "llvm/ADT/SetVector.h"
25461a67faSDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
26461a67faSDimitry Andric #include "llvm/ADT/SmallVector.h"
27461a67faSDimitry Andric #include "llvm/ADT/StringRef.h"
28461a67faSDimitry Andric #include "llvm/ADT/iterator.h"
29461a67faSDimitry Andric #include "llvm/Support/Chrono.h"
30461a67faSDimitry Andric #include "llvm/Support/DOTGraphTraits.h"
31461a67faSDimitry Andric #include "llvm/Support/ErrorOr.h"
3236981b17SDimitry Andric #include "llvm/Support/GraphWriter.h"
33461a67faSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
34676fbe81SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
35461a67faSDimitry Andric #include <algorithm>
36461a67faSDimitry Andric #include <cassert>
37461a67faSDimitry Andric #include <memory>
38461a67faSDimitry Andric #include <string>
39461a67faSDimitry Andric #include <system_error>
4036981b17SDimitry Andric
4136981b17SDimitry Andric using namespace clang;
4236981b17SDimitry Andric using namespace serialization;
4336981b17SDimitry Andric
lookupByFileName(StringRef Name) const44461a67faSDimitry Andric ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
45519fc96cSDimitry Andric auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
4622989816SDimitry Andric /*CacheFailure=*/false);
47809500fcSDimitry Andric if (Entry)
48519fc96cSDimitry Andric return lookup(*Entry);
49809500fcSDimitry Andric
509f4dbff6SDimitry Andric return nullptr;
51809500fcSDimitry Andric }
52809500fcSDimitry Andric
lookupByModuleName(StringRef Name) const53461a67faSDimitry Andric ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
54461a67faSDimitry Andric if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
55b1c73532SDimitry Andric if (OptionalFileEntryRef File = Mod->getASTFile())
56b1c73532SDimitry Andric return lookup(*File);
57461a67faSDimitry Andric
58461a67faSDimitry Andric return nullptr;
59461a67faSDimitry Andric }
60461a67faSDimitry Andric
lookup(const FileEntry * File) const617442d6faSDimitry Andric ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
627fa27ce4SDimitry Andric return Modules.lookup(File);
6336981b17SDimitry Andric }
6436981b17SDimitry Andric
6506d4ba38SDimitry Andric std::unique_ptr<llvm::MemoryBuffer>
lookupBuffer(StringRef Name)6606d4ba38SDimitry Andric ModuleManager::lookupBuffer(StringRef Name) {
67519fc96cSDimitry Andric auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
6822989816SDimitry Andric /*CacheFailure=*/false);
69519fc96cSDimitry Andric if (!Entry)
70519fc96cSDimitry Andric return nullptr;
71519fc96cSDimitry Andric return std::move(InMemoryBuffers[*Entry]);
7236981b17SDimitry Andric }
7336981b17SDimitry Andric
checkSignature(ASTFileSignature Signature,ASTFileSignature ExpectedSignature,std::string & ErrorStr)747442d6faSDimitry Andric static bool checkSignature(ASTFileSignature Signature,
757442d6faSDimitry Andric ASTFileSignature ExpectedSignature,
767442d6faSDimitry Andric std::string &ErrorStr) {
777442d6faSDimitry Andric if (!ExpectedSignature || Signature == ExpectedSignature)
787442d6faSDimitry Andric return false;
797442d6faSDimitry Andric
807442d6faSDimitry Andric ErrorStr =
817442d6faSDimitry Andric Signature ? "signature mismatch" : "could not read module signature";
827442d6faSDimitry Andric return true;
837442d6faSDimitry Andric }
847442d6faSDimitry Andric
updateModuleImports(ModuleFile & MF,ModuleFile * ImportedBy,SourceLocation ImportLoc)857442d6faSDimitry Andric static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
867442d6faSDimitry Andric SourceLocation ImportLoc) {
877442d6faSDimitry Andric if (ImportedBy) {
887442d6faSDimitry Andric MF.ImportedBy.insert(ImportedBy);
897442d6faSDimitry Andric ImportedBy->Imports.insert(&MF);
907442d6faSDimitry Andric } else {
917442d6faSDimitry Andric if (!MF.DirectlyImported)
927442d6faSDimitry Andric MF.ImportLoc = ImportLoc;
937442d6faSDimitry Andric
947442d6faSDimitry Andric MF.DirectlyImported = true;
957442d6faSDimitry Andric }
967442d6faSDimitry Andric }
977442d6faSDimitry Andric
98809500fcSDimitry Andric ModuleManager::AddModuleResult
addModule(StringRef FileName,ModuleKind Type,SourceLocation ImportLoc,ModuleFile * ImportedBy,unsigned Generation,off_t ExpectedSize,time_t ExpectedModTime,ASTFileSignature ExpectedSignature,ASTFileSignatureReader ReadSignature,ModuleFile * & Module,std::string & ErrorStr)9936981b17SDimitry Andric ModuleManager::addModule(StringRef FileName, ModuleKind Type,
100809500fcSDimitry Andric SourceLocation ImportLoc, ModuleFile *ImportedBy,
101809500fcSDimitry Andric unsigned Generation,
102809500fcSDimitry Andric off_t ExpectedSize, time_t ExpectedModTime,
10306d4ba38SDimitry Andric ASTFileSignature ExpectedSignature,
1045e20cdd8SDimitry Andric ASTFileSignatureReader ReadSignature,
105809500fcSDimitry Andric ModuleFile *&Module,
106dbe13110SDimitry Andric std::string &ErrorStr) {
1079f4dbff6SDimitry Andric Module = nullptr;
108809500fcSDimitry Andric
109809500fcSDimitry Andric // Look for the file entry. This only fails if the expected size or
110809500fcSDimitry Andric // modification time differ.
111b1c73532SDimitry Andric OptionalFileEntryRef Entry;
112bab175ecSDimitry Andric if (Type == MK_ExplicitModule || Type == MK_PrebuiltModule) {
11306d4ba38SDimitry Andric // If we're not expecting to pull this file out of the module cache, it
11406d4ba38SDimitry Andric // might have a different mtime due to being moved across filesystems in
11506d4ba38SDimitry Andric // a distributed build. The size must still match, though. (As must the
11606d4ba38SDimitry Andric // contents, but we can't check that.)
11706d4ba38SDimitry Andric ExpectedModTime = 0;
11806d4ba38SDimitry Andric }
11922989816SDimitry Andric // Note: ExpectedSize and ExpectedModTime will be 0 for MK_ImplicitModule
12022989816SDimitry Andric // when using an ASTFileSignature.
121bfef3995SDimitry Andric if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
122bfef3995SDimitry Andric ErrorStr = "module file out of date";
123809500fcSDimitry Andric return OutOfDate;
124bfef3995SDimitry Andric }
125809500fcSDimitry Andric
126b1c73532SDimitry Andric if (!Entry) {
127bfef3995SDimitry Andric ErrorStr = "module file not found";
128809500fcSDimitry Andric return Missing;
12936981b17SDimitry Andric }
13036981b17SDimitry Andric
131b60736ecSDimitry Andric // The ModuleManager's use of FileEntry nodes as the keys for its map of
132b60736ecSDimitry Andric // loaded modules is less than ideal. Uniqueness for FileEntry nodes is
133b60736ecSDimitry Andric // maintained by FileManager, which in turn uses inode numbers on hosts
134b60736ecSDimitry Andric // that support that. When coupled with the module cache's proclivity for
135b60736ecSDimitry Andric // turning over and deleting stale PCMs, this means entries for different
136b60736ecSDimitry Andric // module files can wind up reusing the same underlying inode. When this
137b60736ecSDimitry Andric // happens, subsequent accesses to the Modules map will disagree on the
138b60736ecSDimitry Andric // ModuleFile associated with a given file. In general, it is not sufficient
139b60736ecSDimitry Andric // to resolve this conundrum with a type like FileEntryRef that stores the
140b60736ecSDimitry Andric // name of the FileEntry node on first access because of path canonicalization
141b60736ecSDimitry Andric // issues. However, the paths constructed for implicit module builds are
142b60736ecSDimitry Andric // fully under Clang's control. We *can*, therefore, rely on their structure
143b60736ecSDimitry Andric // being consistent across operating systems and across subsequent accesses
144b60736ecSDimitry Andric // to the Modules map.
145b60736ecSDimitry Andric auto implicitModuleNamesMatch = [](ModuleKind Kind, const ModuleFile *MF,
146b1c73532SDimitry Andric FileEntryRef Entry) -> bool {
147b60736ecSDimitry Andric if (Kind != MK_ImplicitModule)
148b60736ecSDimitry Andric return true;
149b1c73532SDimitry Andric return Entry.getName() == MF->FileName;
150b60736ecSDimitry Andric };
151b60736ecSDimitry Andric
15236981b17SDimitry Andric // Check whether we already loaded this module, before
153b1c73532SDimitry Andric if (ModuleFile *ModuleEntry = Modules.lookup(*Entry)) {
154b1c73532SDimitry Andric if (implicitModuleNamesMatch(Type, ModuleEntry, *Entry)) {
1557442d6faSDimitry Andric // Check the stored signature.
1567442d6faSDimitry Andric if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
1577442d6faSDimitry Andric return OutOfDate;
15836981b17SDimitry Andric
1597442d6faSDimitry Andric Module = ModuleEntry;
1607442d6faSDimitry Andric updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
1617442d6faSDimitry Andric return AlreadyLoaded;
1627442d6faSDimitry Andric }
163b60736ecSDimitry Andric }
1647442d6faSDimitry Andric
1657442d6faSDimitry Andric // Allocate a new module.
166b1c73532SDimitry Andric auto NewModule = std::make_unique<ModuleFile>(Type, *Entry, Generation);
1677442d6faSDimitry Andric NewModule->Index = Chain.size();
1687442d6faSDimitry Andric NewModule->FileName = FileName.str();
1697442d6faSDimitry Andric NewModule->ImportLoc = ImportLoc;
1707442d6faSDimitry Andric NewModule->InputFilesValidationTimestamp = 0;
1717442d6faSDimitry Andric
1727442d6faSDimitry Andric if (NewModule->Kind == MK_ImplicitModule) {
1737442d6faSDimitry Andric std::string TimestampFilename = NewModule->getTimestampFilename();
174676fbe81SDimitry Andric llvm::vfs::Status Status;
1759f4dbff6SDimitry Andric // A cached stat value would be fine as well.
1769f4dbff6SDimitry Andric if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
1777442d6faSDimitry Andric NewModule->InputFilesValidationTimestamp =
178bab175ecSDimitry Andric llvm::sys::toTimeT(Status.getLastModificationTime());
1799f4dbff6SDimitry Andric }
1809f4dbff6SDimitry Andric
18136981b17SDimitry Andric // Load the contents of the module
18206d4ba38SDimitry Andric if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
18336981b17SDimitry Andric // The buffer was already provided for us.
18422989816SDimitry Andric NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer));
185676fbe81SDimitry Andric // Since the cached buffer is reused, it is safe to close the file
186676fbe81SDimitry Andric // descriptor that was opened while stat()ing the PCM in
187676fbe81SDimitry Andric // lookupModuleFile() above, it won't be needed any longer.
188676fbe81SDimitry Andric Entry->closeFile();
18922989816SDimitry Andric } else if (llvm::MemoryBuffer *Buffer =
19022989816SDimitry Andric getModuleCache().lookupPCM(FileName)) {
1917442d6faSDimitry Andric NewModule->Buffer = Buffer;
192676fbe81SDimitry Andric // As above, the file descriptor is no longer needed.
193676fbe81SDimitry Andric Entry->closeFile();
19422989816SDimitry Andric } else if (getModuleCache().shouldBuildPCM(FileName)) {
19522989816SDimitry Andric // Report that the module is out of date, since we tried (and failed) to
19622989816SDimitry Andric // import it earlier.
19722989816SDimitry Andric Entry->closeFile();
19822989816SDimitry Andric return OutOfDate;
19936981b17SDimitry Andric } else {
200676fbe81SDimitry Andric // Get a buffer of the file and close the file descriptor when done.
201cfca06d7SDimitry Andric // The file is volatile because in a parallel build we expect multiple
202cfca06d7SDimitry Andric // compiler processes to use the same module file rebuilding it if needed.
203cfca06d7SDimitry Andric //
204cfca06d7SDimitry Andric // RequiresNullTerminator is false because module files don't need it, and
205cfca06d7SDimitry Andric // this allows the file to still be mmapped.
206b1c73532SDimitry Andric auto Buf = FileMgr.getBufferForFile(NewModule->File,
207cfca06d7SDimitry Andric /*IsVolatile=*/true,
208cfca06d7SDimitry Andric /*RequiresNullTerminator=*/false);
20936981b17SDimitry Andric
21006d4ba38SDimitry Andric if (!Buf) {
21106d4ba38SDimitry Andric ErrorStr = Buf.getError().message();
212809500fcSDimitry Andric return Missing;
21336981b17SDimitry Andric }
21436981b17SDimitry Andric
21522989816SDimitry Andric NewModule->Buffer = &getModuleCache().addPCM(FileName, std::move(*Buf));
21606d4ba38SDimitry Andric }
21706d4ba38SDimitry Andric
2182e645aa5SDimitry Andric // Initialize the stream.
2197442d6faSDimitry Andric NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
22036981b17SDimitry Andric
2217442d6faSDimitry Andric // Read the signature eagerly now so that we can check it. Avoid calling
2227442d6faSDimitry Andric // ReadSignature unless there's something to check though.
2237442d6faSDimitry Andric if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
224519fc96cSDimitry Andric ExpectedSignature, ErrorStr))
22506d4ba38SDimitry Andric return OutOfDate;
22606d4ba38SDimitry Andric
2277442d6faSDimitry Andric // We're keeping this module. Store it everywhere.
228b1c73532SDimitry Andric Module = Modules[*Entry] = NewModule.get();
229809500fcSDimitry Andric
2307442d6faSDimitry Andric updateModuleImports(*NewModule, ImportedBy, ImportLoc);
23136981b17SDimitry Andric
2327442d6faSDimitry Andric if (!NewModule->isModule())
2337442d6faSDimitry Andric PCHChain.push_back(NewModule.get());
234bab175ecSDimitry Andric if (!ImportedBy)
2357442d6faSDimitry Andric Roots.push_back(NewModule.get());
236bab175ecSDimitry Andric
2377442d6faSDimitry Andric Chain.push_back(std::move(NewModule));
238bab175ecSDimitry Andric return NewlyLoaded;
23936981b17SDimitry Andric }
24036981b17SDimitry Andric
removeModules(ModuleIterator First)241e3b55780SDimitry Andric void ModuleManager::removeModules(ModuleIterator First) {
2427442d6faSDimitry Andric auto Last = end();
2437442d6faSDimitry Andric if (First == Last)
24413cc256eSDimitry Andric return;
24513cc256eSDimitry Andric
24645b53394SDimitry Andric // Explicitly clear VisitOrder since we might not notice it is stale.
24745b53394SDimitry Andric VisitOrder.clear();
24845b53394SDimitry Andric
24913cc256eSDimitry Andric // Collect the set of module file pointers that we'll be removing.
2507442d6faSDimitry Andric llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
2517442d6faSDimitry Andric (llvm::pointer_iterator<ModuleIterator>(First)),
2527442d6faSDimitry Andric (llvm::pointer_iterator<ModuleIterator>(Last)));
25313cc256eSDimitry Andric
2545e20cdd8SDimitry Andric auto IsVictim = [&](ModuleFile *MF) {
2555e20cdd8SDimitry Andric return victimSet.count(MF);
2565e20cdd8SDimitry Andric };
25713cc256eSDimitry Andric // Remove any references to the now-destroyed modules.
2587442d6faSDimitry Andric for (auto I = begin(); I != First; ++I) {
2597442d6faSDimitry Andric I->Imports.remove_if(IsVictim);
2607442d6faSDimitry Andric I->ImportedBy.remove_if(IsVictim);
26113cc256eSDimitry Andric }
262c0981da4SDimitry Andric llvm::erase_if(Roots, IsVictim);
26313cc256eSDimitry Andric
26445b53394SDimitry Andric // Remove the modules from the PCH chain.
2657442d6faSDimitry Andric for (auto I = First; I != Last; ++I) {
2667442d6faSDimitry Andric if (!I->isModule()) {
26722989816SDimitry Andric PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
26845b53394SDimitry Andric break;
26945b53394SDimitry Andric }
27045b53394SDimitry Andric }
27145b53394SDimitry Andric
272e3b55780SDimitry Andric // Delete the modules.
273e3b55780SDimitry Andric for (ModuleIterator victim = First; victim != Last; ++victim)
2747442d6faSDimitry Andric Modules.erase(victim->File);
275809500fcSDimitry Andric
2767442d6faSDimitry Andric Chain.erase(Chain.begin() + (First - begin()), Chain.end());
27713cc256eSDimitry Andric }
27813cc256eSDimitry Andric
27906d4ba38SDimitry Andric void
addInMemoryBuffer(StringRef FileName,std::unique_ptr<llvm::MemoryBuffer> Buffer)28006d4ba38SDimitry Andric ModuleManager::addInMemoryBuffer(StringRef FileName,
28106d4ba38SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer) {
28206d4ba38SDimitry Andric const FileEntry *Entry =
28306d4ba38SDimitry Andric FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0);
28406d4ba38SDimitry Andric InMemoryBuffers[Entry] = std::move(Buffer);
28536981b17SDimitry Andric }
28636981b17SDimitry Andric
allocateVisitState()2876f8fc217SDimitry Andric std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
288809500fcSDimitry Andric // Fast path: if we have a cached state, use it.
289809500fcSDimitry Andric if (FirstVisitState) {
2906f8fc217SDimitry Andric auto Result = std::move(FirstVisitState);
2916f8fc217SDimitry Andric FirstVisitState = std::move(Result->NextState);
292809500fcSDimitry Andric return Result;
293809500fcSDimitry Andric }
294809500fcSDimitry Andric
295809500fcSDimitry Andric // Allocate and return a new state.
2966f8fc217SDimitry Andric return std::make_unique<VisitState>(size());
297809500fcSDimitry Andric }
298809500fcSDimitry Andric
returnVisitState(std::unique_ptr<VisitState> State)2996f8fc217SDimitry Andric void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
3009f4dbff6SDimitry Andric assert(State->NextState == nullptr && "Visited state is in list?");
3016f8fc217SDimitry Andric State->NextState = std::move(FirstVisitState);
3026f8fc217SDimitry Andric FirstVisitState = std::move(State);
303809500fcSDimitry Andric }
304809500fcSDimitry Andric
setGlobalIndex(GlobalModuleIndex * Index)305809500fcSDimitry Andric void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
306809500fcSDimitry Andric GlobalIndex = Index;
307809500fcSDimitry Andric if (!GlobalIndex) {
308809500fcSDimitry Andric ModulesInCommonWithGlobalIndex.clear();
309809500fcSDimitry Andric return;
310809500fcSDimitry Andric }
311809500fcSDimitry Andric
312809500fcSDimitry Andric // Notify the global module index about all of the modules we've already
313809500fcSDimitry Andric // loaded.
3147442d6faSDimitry Andric for (ModuleFile &M : *this)
3157442d6faSDimitry Andric if (!GlobalIndex->loadedModuleFile(&M))
3167442d6faSDimitry Andric ModulesInCommonWithGlobalIndex.push_back(&M);
317809500fcSDimitry Andric }
318809500fcSDimitry Andric
moduleFileAccepted(ModuleFile * MF)319809500fcSDimitry Andric void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
320809500fcSDimitry Andric if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
321809500fcSDimitry Andric return;
322809500fcSDimitry Andric
323809500fcSDimitry Andric ModulesInCommonWithGlobalIndex.push_back(MF);
324809500fcSDimitry Andric }
325809500fcSDimitry Andric
ModuleManager(FileManager & FileMgr,InMemoryModuleCache & ModuleCache,const PCHContainerReader & PCHContainerRdr,const HeaderSearch & HeaderSearchInfo)32622989816SDimitry Andric ModuleManager::ModuleManager(FileManager &FileMgr,
32722989816SDimitry Andric InMemoryModuleCache &ModuleCache,
328461a67faSDimitry Andric const PCHContainerReader &PCHContainerRdr,
329461a67faSDimitry Andric const HeaderSearch &HeaderSearchInfo)
33022989816SDimitry Andric : FileMgr(FileMgr), ModuleCache(&ModuleCache),
33122989816SDimitry Andric PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}
33236981b17SDimitry Andric
visit(llvm::function_ref<bool (ModuleFile & M)> Visitor,llvm::SmallPtrSetImpl<ModuleFile * > * ModuleFilesHit)33345b53394SDimitry Andric void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
33406d4ba38SDimitry Andric llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
335809500fcSDimitry Andric // If the visitation order vector is the wrong size, recompute the order.
336809500fcSDimitry Andric if (VisitOrder.size() != Chain.size()) {
33736981b17SDimitry Andric unsigned N = size();
338809500fcSDimitry Andric VisitOrder.clear();
339809500fcSDimitry Andric VisitOrder.reserve(N);
34036981b17SDimitry Andric
34136981b17SDimitry Andric // Record the number of incoming edges for each module. When we
34236981b17SDimitry Andric // encounter a module with no incoming edges, push it into the queue
34336981b17SDimitry Andric // to seed the queue.
344dbe13110SDimitry Andric SmallVector<ModuleFile *, 4> Queue;
34536981b17SDimitry Andric Queue.reserve(N);
346809500fcSDimitry Andric llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
34745b53394SDimitry Andric UnusedIncomingEdges.resize(size());
3487442d6faSDimitry Andric for (ModuleFile &M : llvm::reverse(*this)) {
3497442d6faSDimitry Andric unsigned Size = M.ImportedBy.size();
3507442d6faSDimitry Andric UnusedIncomingEdges[M.Index] = Size;
35145b53394SDimitry Andric if (!Size)
3527442d6faSDimitry Andric Queue.push_back(&M);
35336981b17SDimitry Andric }
35436981b17SDimitry Andric
355809500fcSDimitry Andric // Traverse the graph, making sure to visit a module before visiting any
356809500fcSDimitry Andric // of its dependencies.
35745b53394SDimitry Andric while (!Queue.empty()) {
35845b53394SDimitry Andric ModuleFile *CurrentModule = Queue.pop_back_val();
359809500fcSDimitry Andric VisitOrder.push_back(CurrentModule);
36036981b17SDimitry Andric
361809500fcSDimitry Andric // For any module that this module depends on, push it on the
362809500fcSDimitry Andric // stack (if it hasn't already been marked as visited).
363c0981da4SDimitry Andric for (ModuleFile *M : llvm::reverse(CurrentModule->Imports)) {
364809500fcSDimitry Andric // Remove our current module as an impediment to visiting the
365809500fcSDimitry Andric // module we depend on. If we were the last unvisited module
366809500fcSDimitry Andric // that depends on this particular module, push it into the
367809500fcSDimitry Andric // queue to be visited.
368c0981da4SDimitry Andric unsigned &NumUnusedEdges = UnusedIncomingEdges[M->Index];
369809500fcSDimitry Andric if (NumUnusedEdges && (--NumUnusedEdges == 0))
370c0981da4SDimitry Andric Queue.push_back(M);
371809500fcSDimitry Andric }
372809500fcSDimitry Andric }
373809500fcSDimitry Andric
374809500fcSDimitry Andric assert(VisitOrder.size() == N && "Visitation order is wrong?");
375809500fcSDimitry Andric
3769f4dbff6SDimitry Andric FirstVisitState = nullptr;
377809500fcSDimitry Andric }
378809500fcSDimitry Andric
3796f8fc217SDimitry Andric auto State = allocateVisitState();
380809500fcSDimitry Andric unsigned VisitNumber = State->NextVisitNumber++;
381809500fcSDimitry Andric
382809500fcSDimitry Andric // If the caller has provided us with a hit-set that came from the global
383809500fcSDimitry Andric // module index, mark every module file in common with the global module
384809500fcSDimitry Andric // index that is *not* in that set as 'visited'.
385809500fcSDimitry Andric if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
386809500fcSDimitry Andric for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
387809500fcSDimitry Andric {
388809500fcSDimitry Andric ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
389809500fcSDimitry Andric if (!ModuleFilesHit->count(M))
390809500fcSDimitry Andric State->VisitNumber[M->Index] = VisitNumber;
391809500fcSDimitry Andric }
392809500fcSDimitry Andric }
393809500fcSDimitry Andric
394809500fcSDimitry Andric for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
395809500fcSDimitry Andric ModuleFile *CurrentModule = VisitOrder[I];
396809500fcSDimitry Andric // Should we skip this module file?
397809500fcSDimitry Andric if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
39836981b17SDimitry Andric continue;
39936981b17SDimitry Andric
400809500fcSDimitry Andric // Visit the module.
401809500fcSDimitry Andric assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
402809500fcSDimitry Andric State->VisitNumber[CurrentModule->Index] = VisitNumber;
40345b53394SDimitry Andric if (!Visitor(*CurrentModule))
404809500fcSDimitry Andric continue;
405809500fcSDimitry Andric
40636981b17SDimitry Andric // The visitor has requested that cut off visitation of any
40736981b17SDimitry Andric // module that the current module depends on. To indicate this
408809500fcSDimitry Andric // behavior, we mark all of the reachable modules as having been visited.
409809500fcSDimitry Andric ModuleFile *NextModule = CurrentModule;
410809500fcSDimitry Andric do {
41136981b17SDimitry Andric // For any module that this module depends on, push it on the
41236981b17SDimitry Andric // stack (if it hasn't already been marked as visited).
413dbe13110SDimitry Andric for (llvm::SetVector<ModuleFile *>::iterator
41436981b17SDimitry Andric M = NextModule->Imports.begin(),
41536981b17SDimitry Andric MEnd = NextModule->Imports.end();
41636981b17SDimitry Andric M != MEnd; ++M) {
417809500fcSDimitry Andric if (State->VisitNumber[(*M)->Index] != VisitNumber) {
418809500fcSDimitry Andric State->Stack.push_back(*M);
419809500fcSDimitry Andric State->VisitNumber[(*M)->Index] = VisitNumber;
42036981b17SDimitry Andric }
42136981b17SDimitry Andric }
42236981b17SDimitry Andric
423809500fcSDimitry Andric if (State->Stack.empty())
424809500fcSDimitry Andric break;
42536981b17SDimitry Andric
426809500fcSDimitry Andric // Pop the next module off the stack.
427bfef3995SDimitry Andric NextModule = State->Stack.pop_back_val();
428809500fcSDimitry Andric } while (true);
42936981b17SDimitry Andric }
430809500fcSDimitry Andric
4316f8fc217SDimitry Andric returnVisitState(std::move(State));
43236981b17SDimitry Andric }
43336981b17SDimitry Andric
lookupModuleFile(StringRef FileName,off_t ExpectedSize,time_t ExpectedModTime,OptionalFileEntryRef & File)434b60736ecSDimitry Andric bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize,
435809500fcSDimitry Andric time_t ExpectedModTime,
436e3b55780SDimitry Andric OptionalFileEntryRef &File) {
437b1c73532SDimitry Andric if (FileName == "-") {
438b1c73532SDimitry Andric File = expectedToOptional(FileMgr.getSTDIN());
439bab175ecSDimitry Andric return false;
440b1c73532SDimitry Andric }
441bab175ecSDimitry Andric
4429f4dbff6SDimitry Andric // Open the file immediately to ensure there is no race between stat'ing and
4439f4dbff6SDimitry Andric // opening the file.
444b1c73532SDimitry Andric File = FileMgr.getOptionalFileRef(FileName, /*OpenFile=*/true,
445b1c73532SDimitry Andric /*CacheFailure=*/false);
446b60736ecSDimitry Andric
447b1c73532SDimitry Andric if (File &&
448b1c73532SDimitry Andric ((ExpectedSize && ExpectedSize != File->getSize()) ||
449b1c73532SDimitry Andric (ExpectedModTime && ExpectedModTime != File->getModificationTime())))
4509f4dbff6SDimitry Andric // Do not destroy File, as it may be referenced. If we need to rebuild it,
4519f4dbff6SDimitry Andric // it will be destroyed by removeModules.
452809500fcSDimitry Andric return true;
453809500fcSDimitry Andric
454809500fcSDimitry Andric return false;
455809500fcSDimitry Andric }
456809500fcSDimitry Andric
45736981b17SDimitry Andric #ifndef NDEBUG
45836981b17SDimitry Andric namespace llvm {
459461a67faSDimitry Andric
46036981b17SDimitry Andric template<>
46136981b17SDimitry Andric struct GraphTraits<ModuleManager> {
462461a67faSDimitry Andric using NodeRef = ModuleFile *;
463461a67faSDimitry Andric using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
464461a67faSDimitry Andric using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
46536981b17SDimitry Andric
child_beginllvm::GraphTraits466bab175ecSDimitry Andric static ChildIteratorType child_begin(NodeRef Node) {
46736981b17SDimitry Andric return Node->Imports.begin();
46836981b17SDimitry Andric }
46936981b17SDimitry Andric
child_endllvm::GraphTraits470bab175ecSDimitry Andric static ChildIteratorType child_end(NodeRef Node) {
47136981b17SDimitry Andric return Node->Imports.end();
47236981b17SDimitry Andric }
47336981b17SDimitry Andric
nodes_beginllvm::GraphTraits47436981b17SDimitry Andric static nodes_iterator nodes_begin(const ModuleManager &Manager) {
4757442d6faSDimitry Andric return nodes_iterator(Manager.begin());
47636981b17SDimitry Andric }
47736981b17SDimitry Andric
nodes_endllvm::GraphTraits47836981b17SDimitry Andric static nodes_iterator nodes_end(const ModuleManager &Manager) {
4797442d6faSDimitry Andric return nodes_iterator(Manager.end());
48036981b17SDimitry Andric }
48136981b17SDimitry Andric };
48236981b17SDimitry Andric
48336981b17SDimitry Andric template<>
48436981b17SDimitry Andric struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits48536981b17SDimitry Andric explicit DOTGraphTraits(bool IsSimple = false)
48636981b17SDimitry Andric : DefaultDOTGraphTraits(IsSimple) {}
48736981b17SDimitry Andric
renderGraphFromBottomUpllvm::DOTGraphTraits488461a67faSDimitry Andric static bool renderGraphFromBottomUp() { return true; }
48936981b17SDimitry Andric
getNodeLabelllvm::DOTGraphTraits490dbe13110SDimitry Andric std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
4919f4dbff6SDimitry Andric return M->ModuleName;
49236981b17SDimitry Andric }
49336981b17SDimitry Andric };
494461a67faSDimitry Andric
495461a67faSDimitry Andric } // namespace llvm
49636981b17SDimitry Andric
viewGraph()49736981b17SDimitry Andric void ModuleManager::viewGraph() {
49836981b17SDimitry Andric llvm::ViewGraph(*this, "Modules");
49936981b17SDimitry Andric }
50036981b17SDimitry Andric #endif
501