19a199699SDimitry Andric //===- ModuleManager.cpp - Module Manager ---------------------------------===//
26122f3e6SDimitry Andric //
36122f3e6SDimitry Andric // The LLVM Compiler Infrastructure
46122f3e6SDimitry Andric //
56122f3e6SDimitry Andric // This file is distributed under the University of Illinois Open Source
66122f3e6SDimitry Andric // License. See LICENSE.TXT for details.
76122f3e6SDimitry Andric //
86122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
96122f3e6SDimitry Andric //
106122f3e6SDimitry Andric // This file defines the ModuleManager class, which manages a set of loaded
116122f3e6SDimitry Andric // modules for the ASTReader.
126122f3e6SDimitry Andric //
136122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
149a199699SDimitry Andric
1544290647SDimitry Andric #include "clang/Serialization/ModuleManager.h"
169a199699SDimitry Andric #include "clang/Basic/FileManager.h"
179a199699SDimitry Andric #include "clang/Basic/LLVM.h"
1820e90f04SDimitry Andric #include "clang/Basic/MemoryBufferCache.h"
1959d1ed5bSDimitry Andric #include "clang/Lex/HeaderSearch.h"
20139f7f9bSDimitry Andric #include "clang/Lex/ModuleMap.h"
21139f7f9bSDimitry Andric #include "clang/Serialization/GlobalModuleIndex.h"
229a199699SDimitry Andric #include "clang/Serialization/Module.h"
23*b5893f02SDimitry Andric #include "clang/Serialization/PCHContainerOperations.h"
249a199699SDimitry Andric #include "llvm/ADT/STLExtras.h"
259a199699SDimitry Andric #include "llvm/ADT/SetVector.h"
269a199699SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
279a199699SDimitry Andric #include "llvm/ADT/SmallVector.h"
289a199699SDimitry Andric #include "llvm/ADT/StringRef.h"
299a199699SDimitry Andric #include "llvm/ADT/iterator.h"
309a199699SDimitry Andric #include "llvm/Support/Chrono.h"
319a199699SDimitry Andric #include "llvm/Support/DOTGraphTraits.h"
329a199699SDimitry Andric #include "llvm/Support/ErrorOr.h"
336122f3e6SDimitry Andric #include "llvm/Support/GraphWriter.h"
349a199699SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
35*b5893f02SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
369a199699SDimitry Andric #include <algorithm>
379a199699SDimitry Andric #include <cassert>
389a199699SDimitry Andric #include <memory>
399a199699SDimitry Andric #include <string>
409a199699SDimitry Andric #include <system_error>
416122f3e6SDimitry Andric
426122f3e6SDimitry Andric using namespace clang;
436122f3e6SDimitry Andric using namespace serialization;
446122f3e6SDimitry Andric
lookupByFileName(StringRef Name) const459a199699SDimitry Andric ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
46139f7f9bSDimitry Andric const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
47139f7f9bSDimitry Andric /*cacheFailure=*/false);
48139f7f9bSDimitry Andric if (Entry)
49139f7f9bSDimitry Andric return lookup(Entry);
50139f7f9bSDimitry Andric
5159d1ed5bSDimitry Andric return nullptr;
52139f7f9bSDimitry Andric }
53139f7f9bSDimitry Andric
lookupByModuleName(StringRef Name) const549a199699SDimitry Andric ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
559a199699SDimitry Andric if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
569a199699SDimitry Andric if (const FileEntry *File = Mod->getASTFile())
579a199699SDimitry Andric return lookup(File);
589a199699SDimitry Andric
599a199699SDimitry Andric return nullptr;
609a199699SDimitry Andric }
619a199699SDimitry Andric
lookup(const FileEntry * File) const6220e90f04SDimitry Andric ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
6320e90f04SDimitry Andric auto Known = Modules.find(File);
64139f7f9bSDimitry Andric if (Known == Modules.end())
6559d1ed5bSDimitry Andric return nullptr;
66139f7f9bSDimitry Andric
67139f7f9bSDimitry Andric return Known->second;
686122f3e6SDimitry Andric }
696122f3e6SDimitry Andric
7039d628a0SDimitry Andric std::unique_ptr<llvm::MemoryBuffer>
lookupBuffer(StringRef Name)7139d628a0SDimitry Andric ModuleManager::lookupBuffer(StringRef Name) {
72139f7f9bSDimitry Andric const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
73139f7f9bSDimitry Andric /*cacheFailure=*/false);
7439d628a0SDimitry Andric return std::move(InMemoryBuffers[Entry]);
756122f3e6SDimitry Andric }
766122f3e6SDimitry Andric
checkSignature(ASTFileSignature Signature,ASTFileSignature ExpectedSignature,std::string & ErrorStr)7720e90f04SDimitry Andric static bool checkSignature(ASTFileSignature Signature,
7820e90f04SDimitry Andric ASTFileSignature ExpectedSignature,
7920e90f04SDimitry Andric std::string &ErrorStr) {
8020e90f04SDimitry Andric if (!ExpectedSignature || Signature == ExpectedSignature)
8120e90f04SDimitry Andric return false;
8220e90f04SDimitry Andric
8320e90f04SDimitry Andric ErrorStr =
8420e90f04SDimitry Andric Signature ? "signature mismatch" : "could not read module signature";
8520e90f04SDimitry Andric return true;
8620e90f04SDimitry Andric }
8720e90f04SDimitry Andric
updateModuleImports(ModuleFile & MF,ModuleFile * ImportedBy,SourceLocation ImportLoc)8820e90f04SDimitry Andric static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
8920e90f04SDimitry Andric SourceLocation ImportLoc) {
9020e90f04SDimitry Andric if (ImportedBy) {
9120e90f04SDimitry Andric MF.ImportedBy.insert(ImportedBy);
9220e90f04SDimitry Andric ImportedBy->Imports.insert(&MF);
9320e90f04SDimitry Andric } else {
9420e90f04SDimitry Andric if (!MF.DirectlyImported)
9520e90f04SDimitry Andric MF.ImportLoc = ImportLoc;
9620e90f04SDimitry Andric
9720e90f04SDimitry Andric MF.DirectlyImported = true;
9820e90f04SDimitry Andric }
9920e90f04SDimitry Andric }
10020e90f04SDimitry Andric
101139f7f9bSDimitry 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)1026122f3e6SDimitry Andric ModuleManager::addModule(StringRef FileName, ModuleKind Type,
103139f7f9bSDimitry Andric SourceLocation ImportLoc, ModuleFile *ImportedBy,
104139f7f9bSDimitry Andric unsigned Generation,
105139f7f9bSDimitry Andric off_t ExpectedSize, time_t ExpectedModTime,
10639d628a0SDimitry Andric ASTFileSignature ExpectedSignature,
10733956c43SDimitry Andric ASTFileSignatureReader ReadSignature,
108139f7f9bSDimitry Andric ModuleFile *&Module,
109dff0c46cSDimitry Andric std::string &ErrorStr) {
11059d1ed5bSDimitry Andric Module = nullptr;
111139f7f9bSDimitry Andric
112139f7f9bSDimitry Andric // Look for the file entry. This only fails if the expected size or
113139f7f9bSDimitry Andric // modification time differ.
114139f7f9bSDimitry Andric const FileEntry *Entry;
11544290647SDimitry Andric if (Type == MK_ExplicitModule || Type == MK_PrebuiltModule) {
11639d628a0SDimitry Andric // If we're not expecting to pull this file out of the module cache, it
11739d628a0SDimitry Andric // might have a different mtime due to being moved across filesystems in
11839d628a0SDimitry Andric // a distributed build. The size must still match, though. (As must the
11939d628a0SDimitry Andric // contents, but we can't check that.)
12039d628a0SDimitry Andric ExpectedModTime = 0;
12139d628a0SDimitry Andric }
122f785676fSDimitry Andric if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
123f785676fSDimitry Andric ErrorStr = "module file out of date";
124139f7f9bSDimitry Andric return OutOfDate;
125f785676fSDimitry Andric }
126139f7f9bSDimitry Andric
1276122f3e6SDimitry Andric if (!Entry && FileName != "-") {
128f785676fSDimitry Andric ErrorStr = "module file not found";
129139f7f9bSDimitry Andric return Missing;
1306122f3e6SDimitry Andric }
1316122f3e6SDimitry Andric
1326122f3e6SDimitry Andric // Check whether we already loaded this module, before
13320e90f04SDimitry Andric if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
13420e90f04SDimitry Andric // Check the stored signature.
13520e90f04SDimitry Andric if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
13620e90f04SDimitry Andric return OutOfDate;
1376122f3e6SDimitry Andric
13820e90f04SDimitry Andric Module = ModuleEntry;
13920e90f04SDimitry Andric updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
14020e90f04SDimitry Andric return AlreadyLoaded;
14120e90f04SDimitry Andric }
14220e90f04SDimitry Andric
14320e90f04SDimitry Andric // Allocate a new module.
14420e90f04SDimitry Andric auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation);
14520e90f04SDimitry Andric NewModule->Index = Chain.size();
14620e90f04SDimitry Andric NewModule->FileName = FileName.str();
14720e90f04SDimitry Andric NewModule->File = Entry;
14820e90f04SDimitry Andric NewModule->ImportLoc = ImportLoc;
14920e90f04SDimitry Andric NewModule->InputFilesValidationTimestamp = 0;
15020e90f04SDimitry Andric
15120e90f04SDimitry Andric if (NewModule->Kind == MK_ImplicitModule) {
15220e90f04SDimitry Andric std::string TimestampFilename = NewModule->getTimestampFilename();
153*b5893f02SDimitry Andric llvm::vfs::Status Status;
15459d1ed5bSDimitry Andric // A cached stat value would be fine as well.
15559d1ed5bSDimitry Andric if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
15620e90f04SDimitry Andric NewModule->InputFilesValidationTimestamp =
15744290647SDimitry Andric llvm::sys::toTimeT(Status.getLastModificationTime());
15859d1ed5bSDimitry Andric }
15959d1ed5bSDimitry Andric
1606122f3e6SDimitry Andric // Load the contents of the module
16139d628a0SDimitry Andric if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
1626122f3e6SDimitry Andric // The buffer was already provided for us.
16320e90f04SDimitry Andric NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(Buffer));
164*b5893f02SDimitry Andric // Since the cached buffer is reused, it is safe to close the file
165*b5893f02SDimitry Andric // descriptor that was opened while stat()ing the PCM in
166*b5893f02SDimitry Andric // lookupModuleFile() above, it won't be needed any longer.
167*b5893f02SDimitry Andric Entry->closeFile();
16820e90f04SDimitry Andric } else if (llvm::MemoryBuffer *Buffer = PCMCache->lookupBuffer(FileName)) {
16920e90f04SDimitry Andric NewModule->Buffer = Buffer;
170*b5893f02SDimitry Andric // As above, the file descriptor is no longer needed.
171*b5893f02SDimitry Andric Entry->closeFile();
1726122f3e6SDimitry Andric } else {
1736122f3e6SDimitry Andric // Open the AST file.
17420e90f04SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
1756122f3e6SDimitry Andric if (FileName == "-") {
17639d628a0SDimitry Andric Buf = llvm::MemoryBuffer::getSTDIN();
17759d1ed5bSDimitry Andric } else {
178*b5893f02SDimitry Andric // Get a buffer of the file and close the file descriptor when done.
17920e90f04SDimitry Andric Buf = FileMgr.getBufferForFile(NewModule->File,
18039d628a0SDimitry Andric /*IsVolatile=*/false,
181*b5893f02SDimitry Andric /*ShouldClose=*/true);
18259d1ed5bSDimitry Andric }
1836122f3e6SDimitry Andric
18439d628a0SDimitry Andric if (!Buf) {
18539d628a0SDimitry Andric ErrorStr = Buf.getError().message();
186139f7f9bSDimitry Andric return Missing;
1876122f3e6SDimitry Andric }
1886122f3e6SDimitry Andric
18920e90f04SDimitry Andric NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf));
19039d628a0SDimitry Andric }
19139d628a0SDimitry Andric
1928f0fd8f6SDimitry Andric // Initialize the stream.
19320e90f04SDimitry Andric NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
1946122f3e6SDimitry Andric
19520e90f04SDimitry Andric // Read the signature eagerly now so that we can check it. Avoid calling
19620e90f04SDimitry Andric // ReadSignature unless there's something to check though.
19720e90f04SDimitry Andric if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
19820e90f04SDimitry Andric ExpectedSignature, ErrorStr)) {
19920e90f04SDimitry Andric // Try to remove the buffer. If it can't be removed, then it was already
20020e90f04SDimitry Andric // validated by this process.
20120e90f04SDimitry Andric if (!PCMCache->tryToRemoveBuffer(NewModule->FileName))
20220e90f04SDimitry Andric FileMgr.invalidateCache(NewModule->File);
20339d628a0SDimitry Andric return OutOfDate;
20439d628a0SDimitry Andric }
20539d628a0SDimitry Andric
20620e90f04SDimitry Andric // We're keeping this module. Store it everywhere.
20720e90f04SDimitry Andric Module = Modules[Entry] = NewModule.get();
208139f7f9bSDimitry Andric
20920e90f04SDimitry Andric updateModuleImports(*NewModule, ImportedBy, ImportLoc);
2106122f3e6SDimitry Andric
21120e90f04SDimitry Andric if (!NewModule->isModule())
21220e90f04SDimitry Andric PCHChain.push_back(NewModule.get());
21344290647SDimitry Andric if (!ImportedBy)
21420e90f04SDimitry Andric Roots.push_back(NewModule.get());
21544290647SDimitry Andric
21620e90f04SDimitry Andric Chain.push_back(std::move(NewModule));
21744290647SDimitry Andric return NewlyLoaded;
2186122f3e6SDimitry Andric }
2196122f3e6SDimitry Andric
removeModules(ModuleIterator First,llvm::SmallPtrSetImpl<ModuleFile * > & LoadedSuccessfully,ModuleMap * modMap)22059d1ed5bSDimitry Andric void ModuleManager::removeModules(
22120e90f04SDimitry Andric ModuleIterator First,
22259d1ed5bSDimitry Andric llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
223139f7f9bSDimitry Andric ModuleMap *modMap) {
22420e90f04SDimitry Andric auto Last = end();
22520e90f04SDimitry Andric if (First == Last)
2263861d79fSDimitry Andric return;
2273861d79fSDimitry Andric
2280623d748SDimitry Andric // Explicitly clear VisitOrder since we might not notice it is stale.
2290623d748SDimitry Andric VisitOrder.clear();
2300623d748SDimitry Andric
2313861d79fSDimitry Andric // Collect the set of module file pointers that we'll be removing.
23220e90f04SDimitry Andric llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
23320e90f04SDimitry Andric (llvm::pointer_iterator<ModuleIterator>(First)),
23420e90f04SDimitry Andric (llvm::pointer_iterator<ModuleIterator>(Last)));
2353861d79fSDimitry Andric
23633956c43SDimitry Andric auto IsVictim = [&](ModuleFile *MF) {
23733956c43SDimitry Andric return victimSet.count(MF);
23833956c43SDimitry Andric };
2393861d79fSDimitry Andric // Remove any references to the now-destroyed modules.
24020e90f04SDimitry Andric for (auto I = begin(); I != First; ++I) {
24120e90f04SDimitry Andric I->Imports.remove_if(IsVictim);
24220e90f04SDimitry Andric I->ImportedBy.remove_if(IsVictim);
2433861d79fSDimitry Andric }
24433956c43SDimitry Andric Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
24533956c43SDimitry Andric Roots.end());
2463861d79fSDimitry Andric
2470623d748SDimitry Andric // Remove the modules from the PCH chain.
24820e90f04SDimitry Andric for (auto I = First; I != Last; ++I) {
24920e90f04SDimitry Andric if (!I->isModule()) {
25020e90f04SDimitry Andric PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), &*I),
2510623d748SDimitry Andric PCHChain.end());
2520623d748SDimitry Andric break;
2530623d748SDimitry Andric }
2540623d748SDimitry Andric }
2550623d748SDimitry Andric
2563861d79fSDimitry Andric // Delete the modules and erase them from the various structures.
25720e90f04SDimitry Andric for (ModuleIterator victim = First; victim != Last; ++victim) {
25820e90f04SDimitry Andric Modules.erase(victim->File);
259139f7f9bSDimitry Andric
260139f7f9bSDimitry Andric if (modMap) {
26120e90f04SDimitry Andric StringRef ModuleName = victim->ModuleName;
262139f7f9bSDimitry Andric if (Module *mod = modMap->findModule(ModuleName)) {
26359d1ed5bSDimitry Andric mod->setASTFile(nullptr);
264139f7f9bSDimitry Andric }
265139f7f9bSDimitry Andric }
26659d1ed5bSDimitry Andric
26759d1ed5bSDimitry Andric // Files that didn't make it through ReadASTCore successfully will be
26859d1ed5bSDimitry Andric // rebuilt (or there was an error). Invalidate them so that we can load the
26959d1ed5bSDimitry Andric // new files that will be renamed over the old ones.
27020e90f04SDimitry Andric //
27120e90f04SDimitry Andric // The PCMCache tracks whether the module was successfully loaded in another
27220e90f04SDimitry Andric // thread/context; in that case, it won't need to be rebuilt (and we can't
27320e90f04SDimitry Andric // safely invalidate it anyway).
27420e90f04SDimitry Andric if (LoadedSuccessfully.count(&*victim) == 0 &&
27520e90f04SDimitry Andric !PCMCache->tryToRemoveBuffer(victim->FileName))
27620e90f04SDimitry Andric FileMgr.invalidateCache(victim->File);
2773861d79fSDimitry Andric }
2783861d79fSDimitry Andric
27920e90f04SDimitry Andric // Delete the modules.
28020e90f04SDimitry Andric Chain.erase(Chain.begin() + (First - begin()), Chain.end());
2813861d79fSDimitry Andric }
2823861d79fSDimitry Andric
28339d628a0SDimitry Andric void
addInMemoryBuffer(StringRef FileName,std::unique_ptr<llvm::MemoryBuffer> Buffer)28439d628a0SDimitry Andric ModuleManager::addInMemoryBuffer(StringRef FileName,
28539d628a0SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> Buffer) {
28639d628a0SDimitry Andric const FileEntry *Entry =
28739d628a0SDimitry Andric FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0);
28839d628a0SDimitry Andric InMemoryBuffers[Entry] = std::move(Buffer);
2896122f3e6SDimitry Andric }
2906122f3e6SDimitry Andric
allocateVisitState()291139f7f9bSDimitry Andric ModuleManager::VisitState *ModuleManager::allocateVisitState() {
292139f7f9bSDimitry Andric // Fast path: if we have a cached state, use it.
293139f7f9bSDimitry Andric if (FirstVisitState) {
294139f7f9bSDimitry Andric VisitState *Result = FirstVisitState;
295139f7f9bSDimitry Andric FirstVisitState = FirstVisitState->NextState;
29659d1ed5bSDimitry Andric Result->NextState = nullptr;
297139f7f9bSDimitry Andric return Result;
298139f7f9bSDimitry Andric }
299139f7f9bSDimitry Andric
300139f7f9bSDimitry Andric // Allocate and return a new state.
301139f7f9bSDimitry Andric return new VisitState(size());
302139f7f9bSDimitry Andric }
303139f7f9bSDimitry Andric
returnVisitState(VisitState * State)304139f7f9bSDimitry Andric void ModuleManager::returnVisitState(VisitState *State) {
30559d1ed5bSDimitry Andric assert(State->NextState == nullptr && "Visited state is in list?");
306139f7f9bSDimitry Andric State->NextState = FirstVisitState;
307139f7f9bSDimitry Andric FirstVisitState = State;
308139f7f9bSDimitry Andric }
309139f7f9bSDimitry Andric
setGlobalIndex(GlobalModuleIndex * Index)310139f7f9bSDimitry Andric void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
311139f7f9bSDimitry Andric GlobalIndex = Index;
312139f7f9bSDimitry Andric if (!GlobalIndex) {
313139f7f9bSDimitry Andric ModulesInCommonWithGlobalIndex.clear();
314139f7f9bSDimitry Andric return;
315139f7f9bSDimitry Andric }
316139f7f9bSDimitry Andric
317139f7f9bSDimitry Andric // Notify the global module index about all of the modules we've already
318139f7f9bSDimitry Andric // loaded.
31920e90f04SDimitry Andric for (ModuleFile &M : *this)
32020e90f04SDimitry Andric if (!GlobalIndex->loadedModuleFile(&M))
32120e90f04SDimitry Andric ModulesInCommonWithGlobalIndex.push_back(&M);
322139f7f9bSDimitry Andric }
323139f7f9bSDimitry Andric
moduleFileAccepted(ModuleFile * MF)324139f7f9bSDimitry Andric void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
325139f7f9bSDimitry Andric if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
326139f7f9bSDimitry Andric return;
327139f7f9bSDimitry Andric
328139f7f9bSDimitry Andric ModulesInCommonWithGlobalIndex.push_back(MF);
329139f7f9bSDimitry Andric }
330139f7f9bSDimitry Andric
ModuleManager(FileManager & FileMgr,MemoryBufferCache & PCMCache,const PCHContainerReader & PCHContainerRdr,const HeaderSearch & HeaderSearchInfo)33120e90f04SDimitry Andric ModuleManager::ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache,
3329a199699SDimitry Andric const PCHContainerReader &PCHContainerRdr,
3339a199699SDimitry Andric const HeaderSearch& HeaderSearchInfo)
33420e90f04SDimitry Andric : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr),
3359a199699SDimitry Andric HeaderSearchInfo(HeaderSearchInfo) {}
3366122f3e6SDimitry Andric
~ModuleManager()33720e90f04SDimitry Andric ModuleManager::~ModuleManager() { delete FirstVisitState; }
3386122f3e6SDimitry Andric
visit(llvm::function_ref<bool (ModuleFile & M)> Visitor,llvm::SmallPtrSetImpl<ModuleFile * > * ModuleFilesHit)3390623d748SDimitry Andric void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
34039d628a0SDimitry Andric llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
341139f7f9bSDimitry Andric // If the visitation order vector is the wrong size, recompute the order.
342139f7f9bSDimitry Andric if (VisitOrder.size() != Chain.size()) {
3436122f3e6SDimitry Andric unsigned N = size();
344139f7f9bSDimitry Andric VisitOrder.clear();
345139f7f9bSDimitry Andric VisitOrder.reserve(N);
3466122f3e6SDimitry Andric
3476122f3e6SDimitry Andric // Record the number of incoming edges for each module. When we
3486122f3e6SDimitry Andric // encounter a module with no incoming edges, push it into the queue
3496122f3e6SDimitry Andric // to seed the queue.
350dff0c46cSDimitry Andric SmallVector<ModuleFile *, 4> Queue;
3516122f3e6SDimitry Andric Queue.reserve(N);
352139f7f9bSDimitry Andric llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
3530623d748SDimitry Andric UnusedIncomingEdges.resize(size());
35420e90f04SDimitry Andric for (ModuleFile &M : llvm::reverse(*this)) {
35520e90f04SDimitry Andric unsigned Size = M.ImportedBy.size();
35620e90f04SDimitry Andric UnusedIncomingEdges[M.Index] = Size;
3570623d748SDimitry Andric if (!Size)
35820e90f04SDimitry Andric Queue.push_back(&M);
3596122f3e6SDimitry Andric }
3606122f3e6SDimitry Andric
361139f7f9bSDimitry Andric // Traverse the graph, making sure to visit a module before visiting any
362139f7f9bSDimitry Andric // of its dependencies.
3630623d748SDimitry Andric while (!Queue.empty()) {
3640623d748SDimitry Andric ModuleFile *CurrentModule = Queue.pop_back_val();
365139f7f9bSDimitry Andric VisitOrder.push_back(CurrentModule);
3666122f3e6SDimitry Andric
367139f7f9bSDimitry Andric // For any module that this module depends on, push it on the
368139f7f9bSDimitry Andric // stack (if it hasn't already been marked as visited).
3690623d748SDimitry Andric for (auto M = CurrentModule->Imports.rbegin(),
3700623d748SDimitry Andric MEnd = CurrentModule->Imports.rend();
371139f7f9bSDimitry Andric M != MEnd; ++M) {
372139f7f9bSDimitry Andric // Remove our current module as an impediment to visiting the
373139f7f9bSDimitry Andric // module we depend on. If we were the last unvisited module
374139f7f9bSDimitry Andric // that depends on this particular module, push it into the
375139f7f9bSDimitry Andric // queue to be visited.
376139f7f9bSDimitry Andric unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
377139f7f9bSDimitry Andric if (NumUnusedEdges && (--NumUnusedEdges == 0))
378139f7f9bSDimitry Andric Queue.push_back(*M);
379139f7f9bSDimitry Andric }
380139f7f9bSDimitry Andric }
381139f7f9bSDimitry Andric
382139f7f9bSDimitry Andric assert(VisitOrder.size() == N && "Visitation order is wrong?");
383139f7f9bSDimitry Andric
384139f7f9bSDimitry Andric delete FirstVisitState;
38559d1ed5bSDimitry Andric FirstVisitState = nullptr;
386139f7f9bSDimitry Andric }
387139f7f9bSDimitry Andric
388139f7f9bSDimitry Andric VisitState *State = allocateVisitState();
389139f7f9bSDimitry Andric unsigned VisitNumber = State->NextVisitNumber++;
390139f7f9bSDimitry Andric
391139f7f9bSDimitry Andric // If the caller has provided us with a hit-set that came from the global
392139f7f9bSDimitry Andric // module index, mark every module file in common with the global module
393139f7f9bSDimitry Andric // index that is *not* in that set as 'visited'.
394139f7f9bSDimitry Andric if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
395139f7f9bSDimitry Andric for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
396139f7f9bSDimitry Andric {
397139f7f9bSDimitry Andric ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
398139f7f9bSDimitry Andric if (!ModuleFilesHit->count(M))
399139f7f9bSDimitry Andric State->VisitNumber[M->Index] = VisitNumber;
400139f7f9bSDimitry Andric }
401139f7f9bSDimitry Andric }
402139f7f9bSDimitry Andric
403139f7f9bSDimitry Andric for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
404139f7f9bSDimitry Andric ModuleFile *CurrentModule = VisitOrder[I];
405139f7f9bSDimitry Andric // Should we skip this module file?
406139f7f9bSDimitry Andric if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
4076122f3e6SDimitry Andric continue;
4086122f3e6SDimitry Andric
409139f7f9bSDimitry Andric // Visit the module.
410139f7f9bSDimitry Andric assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
411139f7f9bSDimitry Andric State->VisitNumber[CurrentModule->Index] = VisitNumber;
4120623d748SDimitry Andric if (!Visitor(*CurrentModule))
413139f7f9bSDimitry Andric continue;
414139f7f9bSDimitry Andric
4156122f3e6SDimitry Andric // The visitor has requested that cut off visitation of any
4166122f3e6SDimitry Andric // module that the current module depends on. To indicate this
417139f7f9bSDimitry Andric // behavior, we mark all of the reachable modules as having been visited.
418139f7f9bSDimitry Andric ModuleFile *NextModule = CurrentModule;
419139f7f9bSDimitry Andric do {
4206122f3e6SDimitry Andric // For any module that this module depends on, push it on the
4216122f3e6SDimitry Andric // stack (if it hasn't already been marked as visited).
422dff0c46cSDimitry Andric for (llvm::SetVector<ModuleFile *>::iterator
4236122f3e6SDimitry Andric M = NextModule->Imports.begin(),
4246122f3e6SDimitry Andric MEnd = NextModule->Imports.end();
4256122f3e6SDimitry Andric M != MEnd; ++M) {
426139f7f9bSDimitry Andric if (State->VisitNumber[(*M)->Index] != VisitNumber) {
427139f7f9bSDimitry Andric State->Stack.push_back(*M);
428139f7f9bSDimitry Andric State->VisitNumber[(*M)->Index] = VisitNumber;
4296122f3e6SDimitry Andric }
4306122f3e6SDimitry Andric }
4316122f3e6SDimitry Andric
432139f7f9bSDimitry Andric if (State->Stack.empty())
433139f7f9bSDimitry Andric break;
4346122f3e6SDimitry Andric
435139f7f9bSDimitry Andric // Pop the next module off the stack.
436f785676fSDimitry Andric NextModule = State->Stack.pop_back_val();
437139f7f9bSDimitry Andric } while (true);
4386122f3e6SDimitry Andric }
439139f7f9bSDimitry Andric
440139f7f9bSDimitry Andric returnVisitState(State);
4416122f3e6SDimitry Andric }
4426122f3e6SDimitry Andric
lookupModuleFile(StringRef FileName,off_t ExpectedSize,time_t ExpectedModTime,const FileEntry * & File)443139f7f9bSDimitry Andric bool ModuleManager::lookupModuleFile(StringRef FileName,
444139f7f9bSDimitry Andric off_t ExpectedSize,
445139f7f9bSDimitry Andric time_t ExpectedModTime,
446139f7f9bSDimitry Andric const FileEntry *&File) {
44744290647SDimitry Andric if (FileName == "-") {
44844290647SDimitry Andric File = nullptr;
44944290647SDimitry Andric return false;
45044290647SDimitry Andric }
45144290647SDimitry Andric
45259d1ed5bSDimitry Andric // Open the file immediately to ensure there is no race between stat'ing and
45359d1ed5bSDimitry Andric // opening the file.
45459d1ed5bSDimitry Andric File = FileMgr.getFile(FileName, /*openFile=*/true, /*cacheFailure=*/false);
45544290647SDimitry Andric if (!File)
456139f7f9bSDimitry Andric return false;
457139f7f9bSDimitry Andric
458139f7f9bSDimitry Andric if ((ExpectedSize && ExpectedSize != File->getSize()) ||
45959d1ed5bSDimitry Andric (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
46059d1ed5bSDimitry Andric // Do not destroy File, as it may be referenced. If we need to rebuild it,
46159d1ed5bSDimitry Andric // it will be destroyed by removeModules.
462139f7f9bSDimitry Andric return true;
463139f7f9bSDimitry Andric
464139f7f9bSDimitry Andric return false;
465139f7f9bSDimitry Andric }
466139f7f9bSDimitry Andric
4676122f3e6SDimitry Andric #ifndef NDEBUG
4686122f3e6SDimitry Andric namespace llvm {
4699a199699SDimitry Andric
4706122f3e6SDimitry Andric template<>
4716122f3e6SDimitry Andric struct GraphTraits<ModuleManager> {
4729a199699SDimitry Andric using NodeRef = ModuleFile *;
4739a199699SDimitry Andric using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
4749a199699SDimitry Andric using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
4756122f3e6SDimitry Andric
child_beginllvm::GraphTraits47644290647SDimitry Andric static ChildIteratorType child_begin(NodeRef Node) {
4776122f3e6SDimitry Andric return Node->Imports.begin();
4786122f3e6SDimitry Andric }
4796122f3e6SDimitry Andric
child_endllvm::GraphTraits48044290647SDimitry Andric static ChildIteratorType child_end(NodeRef Node) {
4816122f3e6SDimitry Andric return Node->Imports.end();
4826122f3e6SDimitry Andric }
4836122f3e6SDimitry Andric
nodes_beginllvm::GraphTraits4846122f3e6SDimitry Andric static nodes_iterator nodes_begin(const ModuleManager &Manager) {
48520e90f04SDimitry Andric return nodes_iterator(Manager.begin());
4866122f3e6SDimitry Andric }
4876122f3e6SDimitry Andric
nodes_endllvm::GraphTraits4886122f3e6SDimitry Andric static nodes_iterator nodes_end(const ModuleManager &Manager) {
48920e90f04SDimitry Andric return nodes_iterator(Manager.end());
4906122f3e6SDimitry Andric }
4916122f3e6SDimitry Andric };
4926122f3e6SDimitry Andric
4936122f3e6SDimitry Andric template<>
4946122f3e6SDimitry Andric struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits4956122f3e6SDimitry Andric explicit DOTGraphTraits(bool IsSimple = false)
4966122f3e6SDimitry Andric : DefaultDOTGraphTraits(IsSimple) {}
4976122f3e6SDimitry Andric
renderGraphFromBottomUpllvm::DOTGraphTraits4989a199699SDimitry Andric static bool renderGraphFromBottomUp() { return true; }
4996122f3e6SDimitry Andric
getNodeLabelllvm::DOTGraphTraits500dff0c46cSDimitry Andric std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
50159d1ed5bSDimitry Andric return M->ModuleName;
5026122f3e6SDimitry Andric }
5036122f3e6SDimitry Andric };
5049a199699SDimitry Andric
5059a199699SDimitry Andric } // namespace llvm
5066122f3e6SDimitry Andric
viewGraph()5076122f3e6SDimitry Andric void ModuleManager::viewGraph() {
5086122f3e6SDimitry Andric llvm::ViewGraph(*this, "Modules");
5096122f3e6SDimitry Andric }
5106122f3e6SDimitry Andric #endif
511