17330f729Sjoerg //===- ModuleManager.cpp - Module Manager ---------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file defines the ModuleManager class, which manages a set of loaded
107330f729Sjoerg // modules for the ASTReader.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "clang/Serialization/ModuleManager.h"
157330f729Sjoerg #include "clang/Basic/FileManager.h"
167330f729Sjoerg #include "clang/Basic/LLVM.h"
177330f729Sjoerg #include "clang/Lex/HeaderSearch.h"
187330f729Sjoerg #include "clang/Lex/ModuleMap.h"
197330f729Sjoerg #include "clang/Serialization/GlobalModuleIndex.h"
207330f729Sjoerg #include "clang/Serialization/InMemoryModuleCache.h"
21*e038c9c4Sjoerg #include "clang/Serialization/ModuleFile.h"
227330f729Sjoerg #include "clang/Serialization/PCHContainerOperations.h"
237330f729Sjoerg #include "llvm/ADT/STLExtras.h"
247330f729Sjoerg #include "llvm/ADT/SetVector.h"
257330f729Sjoerg #include "llvm/ADT/SmallPtrSet.h"
267330f729Sjoerg #include "llvm/ADT/SmallVector.h"
277330f729Sjoerg #include "llvm/ADT/StringRef.h"
287330f729Sjoerg #include "llvm/ADT/iterator.h"
297330f729Sjoerg #include "llvm/Support/Chrono.h"
307330f729Sjoerg #include "llvm/Support/DOTGraphTraits.h"
317330f729Sjoerg #include "llvm/Support/ErrorOr.h"
327330f729Sjoerg #include "llvm/Support/GraphWriter.h"
337330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
347330f729Sjoerg #include "llvm/Support/VirtualFileSystem.h"
357330f729Sjoerg #include <algorithm>
367330f729Sjoerg #include <cassert>
377330f729Sjoerg #include <memory>
387330f729Sjoerg #include <string>
397330f729Sjoerg #include <system_error>
407330f729Sjoerg
417330f729Sjoerg using namespace clang;
427330f729Sjoerg using namespace serialization;
437330f729Sjoerg
lookupByFileName(StringRef Name) const447330f729Sjoerg ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
457330f729Sjoerg auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
467330f729Sjoerg /*CacheFailure=*/false);
477330f729Sjoerg if (Entry)
487330f729Sjoerg return lookup(*Entry);
497330f729Sjoerg
507330f729Sjoerg return nullptr;
517330f729Sjoerg }
527330f729Sjoerg
lookupByModuleName(StringRef Name) const537330f729Sjoerg ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
547330f729Sjoerg if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
557330f729Sjoerg if (const FileEntry *File = Mod->getASTFile())
567330f729Sjoerg return lookup(File);
577330f729Sjoerg
587330f729Sjoerg return nullptr;
597330f729Sjoerg }
607330f729Sjoerg
lookup(const FileEntry * File) const617330f729Sjoerg ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
627330f729Sjoerg auto Known = Modules.find(File);
637330f729Sjoerg if (Known == Modules.end())
647330f729Sjoerg return nullptr;
657330f729Sjoerg
667330f729Sjoerg return Known->second;
677330f729Sjoerg }
687330f729Sjoerg
697330f729Sjoerg std::unique_ptr<llvm::MemoryBuffer>
lookupBuffer(StringRef Name)707330f729Sjoerg ModuleManager::lookupBuffer(StringRef Name) {
717330f729Sjoerg auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
727330f729Sjoerg /*CacheFailure=*/false);
737330f729Sjoerg if (!Entry)
747330f729Sjoerg return nullptr;
757330f729Sjoerg return std::move(InMemoryBuffers[*Entry]);
767330f729Sjoerg }
777330f729Sjoerg
checkSignature(ASTFileSignature Signature,ASTFileSignature ExpectedSignature,std::string & ErrorStr)787330f729Sjoerg static bool checkSignature(ASTFileSignature Signature,
797330f729Sjoerg ASTFileSignature ExpectedSignature,
807330f729Sjoerg std::string &ErrorStr) {
817330f729Sjoerg if (!ExpectedSignature || Signature == ExpectedSignature)
827330f729Sjoerg return false;
837330f729Sjoerg
847330f729Sjoerg ErrorStr =
857330f729Sjoerg Signature ? "signature mismatch" : "could not read module signature";
867330f729Sjoerg return true;
877330f729Sjoerg }
887330f729Sjoerg
updateModuleImports(ModuleFile & MF,ModuleFile * ImportedBy,SourceLocation ImportLoc)897330f729Sjoerg static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
907330f729Sjoerg SourceLocation ImportLoc) {
917330f729Sjoerg if (ImportedBy) {
927330f729Sjoerg MF.ImportedBy.insert(ImportedBy);
937330f729Sjoerg ImportedBy->Imports.insert(&MF);
947330f729Sjoerg } else {
957330f729Sjoerg if (!MF.DirectlyImported)
967330f729Sjoerg MF.ImportLoc = ImportLoc;
977330f729Sjoerg
987330f729Sjoerg MF.DirectlyImported = true;
997330f729Sjoerg }
1007330f729Sjoerg }
1017330f729Sjoerg
1027330f729Sjoerg 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)1037330f729Sjoerg ModuleManager::addModule(StringRef FileName, ModuleKind Type,
1047330f729Sjoerg SourceLocation ImportLoc, ModuleFile *ImportedBy,
1057330f729Sjoerg unsigned Generation,
1067330f729Sjoerg off_t ExpectedSize, time_t ExpectedModTime,
1077330f729Sjoerg ASTFileSignature ExpectedSignature,
1087330f729Sjoerg ASTFileSignatureReader ReadSignature,
1097330f729Sjoerg ModuleFile *&Module,
1107330f729Sjoerg std::string &ErrorStr) {
1117330f729Sjoerg Module = nullptr;
1127330f729Sjoerg
1137330f729Sjoerg // Look for the file entry. This only fails if the expected size or
1147330f729Sjoerg // modification time differ.
115*e038c9c4Sjoerg OptionalFileEntryRefDegradesToFileEntryPtr Entry;
1167330f729Sjoerg if (Type == MK_ExplicitModule || Type == MK_PrebuiltModule) {
1177330f729Sjoerg // If we're not expecting to pull this file out of the module cache, it
1187330f729Sjoerg // might have a different mtime due to being moved across filesystems in
1197330f729Sjoerg // a distributed build. The size must still match, though. (As must the
1207330f729Sjoerg // contents, but we can't check that.)
1217330f729Sjoerg ExpectedModTime = 0;
1227330f729Sjoerg }
1237330f729Sjoerg // Note: ExpectedSize and ExpectedModTime will be 0 for MK_ImplicitModule
1247330f729Sjoerg // when using an ASTFileSignature.
1257330f729Sjoerg if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
1267330f729Sjoerg ErrorStr = "module file out of date";
1277330f729Sjoerg return OutOfDate;
1287330f729Sjoerg }
1297330f729Sjoerg
1307330f729Sjoerg if (!Entry && FileName != "-") {
1317330f729Sjoerg ErrorStr = "module file not found";
1327330f729Sjoerg return Missing;
1337330f729Sjoerg }
1347330f729Sjoerg
135*e038c9c4Sjoerg // The ModuleManager's use of FileEntry nodes as the keys for its map of
136*e038c9c4Sjoerg // loaded modules is less than ideal. Uniqueness for FileEntry nodes is
137*e038c9c4Sjoerg // maintained by FileManager, which in turn uses inode numbers on hosts
138*e038c9c4Sjoerg // that support that. When coupled with the module cache's proclivity for
139*e038c9c4Sjoerg // turning over and deleting stale PCMs, this means entries for different
140*e038c9c4Sjoerg // module files can wind up reusing the same underlying inode. When this
141*e038c9c4Sjoerg // happens, subsequent accesses to the Modules map will disagree on the
142*e038c9c4Sjoerg // ModuleFile associated with a given file. In general, it is not sufficient
143*e038c9c4Sjoerg // to resolve this conundrum with a type like FileEntryRef that stores the
144*e038c9c4Sjoerg // name of the FileEntry node on first access because of path canonicalization
145*e038c9c4Sjoerg // issues. However, the paths constructed for implicit module builds are
146*e038c9c4Sjoerg // fully under Clang's control. We *can*, therefore, rely on their structure
147*e038c9c4Sjoerg // being consistent across operating systems and across subsequent accesses
148*e038c9c4Sjoerg // to the Modules map.
149*e038c9c4Sjoerg auto implicitModuleNamesMatch = [](ModuleKind Kind, const ModuleFile *MF,
150*e038c9c4Sjoerg const FileEntry *Entry) -> bool {
151*e038c9c4Sjoerg if (Kind != MK_ImplicitModule)
152*e038c9c4Sjoerg return true;
153*e038c9c4Sjoerg return Entry->getName() == MF->FileName;
154*e038c9c4Sjoerg };
155*e038c9c4Sjoerg
1567330f729Sjoerg // Check whether we already loaded this module, before
1577330f729Sjoerg if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
158*e038c9c4Sjoerg if (implicitModuleNamesMatch(Type, ModuleEntry, Entry)) {
1597330f729Sjoerg // Check the stored signature.
1607330f729Sjoerg if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
1617330f729Sjoerg return OutOfDate;
1627330f729Sjoerg
1637330f729Sjoerg Module = ModuleEntry;
1647330f729Sjoerg updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
1657330f729Sjoerg return AlreadyLoaded;
1667330f729Sjoerg }
167*e038c9c4Sjoerg }
1687330f729Sjoerg
1697330f729Sjoerg // Allocate a new module.
1707330f729Sjoerg auto NewModule = std::make_unique<ModuleFile>(Type, Generation);
1717330f729Sjoerg NewModule->Index = Chain.size();
1727330f729Sjoerg NewModule->FileName = FileName.str();
1737330f729Sjoerg NewModule->File = Entry;
1747330f729Sjoerg NewModule->ImportLoc = ImportLoc;
1757330f729Sjoerg NewModule->InputFilesValidationTimestamp = 0;
1767330f729Sjoerg
1777330f729Sjoerg if (NewModule->Kind == MK_ImplicitModule) {
1787330f729Sjoerg std::string TimestampFilename = NewModule->getTimestampFilename();
1797330f729Sjoerg llvm::vfs::Status Status;
1807330f729Sjoerg // A cached stat value would be fine as well.
1817330f729Sjoerg if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
1827330f729Sjoerg NewModule->InputFilesValidationTimestamp =
1837330f729Sjoerg llvm::sys::toTimeT(Status.getLastModificationTime());
1847330f729Sjoerg }
1857330f729Sjoerg
1867330f729Sjoerg // Load the contents of the module
1877330f729Sjoerg if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
1887330f729Sjoerg // The buffer was already provided for us.
1897330f729Sjoerg NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer));
1907330f729Sjoerg // Since the cached buffer is reused, it is safe to close the file
1917330f729Sjoerg // descriptor that was opened while stat()ing the PCM in
1927330f729Sjoerg // lookupModuleFile() above, it won't be needed any longer.
1937330f729Sjoerg Entry->closeFile();
1947330f729Sjoerg } else if (llvm::MemoryBuffer *Buffer =
1957330f729Sjoerg getModuleCache().lookupPCM(FileName)) {
1967330f729Sjoerg NewModule->Buffer = Buffer;
1977330f729Sjoerg // As above, the file descriptor is no longer needed.
1987330f729Sjoerg Entry->closeFile();
1997330f729Sjoerg } else if (getModuleCache().shouldBuildPCM(FileName)) {
2007330f729Sjoerg // Report that the module is out of date, since we tried (and failed) to
2017330f729Sjoerg // import it earlier.
2027330f729Sjoerg Entry->closeFile();
2037330f729Sjoerg return OutOfDate;
2047330f729Sjoerg } else {
2057330f729Sjoerg // Open the AST file.
2067330f729Sjoerg llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
2077330f729Sjoerg if (FileName == "-") {
2087330f729Sjoerg Buf = llvm::MemoryBuffer::getSTDIN();
2097330f729Sjoerg } else {
2107330f729Sjoerg // Get a buffer of the file and close the file descriptor when done.
211*e038c9c4Sjoerg // The file is volatile because in a parallel build we expect multiple
212*e038c9c4Sjoerg // compiler processes to use the same module file rebuilding it if needed.
213*e038c9c4Sjoerg //
214*e038c9c4Sjoerg // RequiresNullTerminator is false because module files don't need it, and
215*e038c9c4Sjoerg // this allows the file to still be mmapped.
216*e038c9c4Sjoerg Buf = FileMgr.getBufferForFile(NewModule->File,
217*e038c9c4Sjoerg /*IsVolatile=*/true,
218*e038c9c4Sjoerg /*RequiresNullTerminator=*/false);
2197330f729Sjoerg }
2207330f729Sjoerg
2217330f729Sjoerg if (!Buf) {
2227330f729Sjoerg ErrorStr = Buf.getError().message();
2237330f729Sjoerg return Missing;
2247330f729Sjoerg }
2257330f729Sjoerg
2267330f729Sjoerg NewModule->Buffer = &getModuleCache().addPCM(FileName, std::move(*Buf));
2277330f729Sjoerg }
2287330f729Sjoerg
2297330f729Sjoerg // Initialize the stream.
2307330f729Sjoerg NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
2317330f729Sjoerg
2327330f729Sjoerg // Read the signature eagerly now so that we can check it. Avoid calling
2337330f729Sjoerg // ReadSignature unless there's something to check though.
2347330f729Sjoerg if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
2357330f729Sjoerg ExpectedSignature, ErrorStr))
2367330f729Sjoerg return OutOfDate;
2377330f729Sjoerg
2387330f729Sjoerg // We're keeping this module. Store it everywhere.
2397330f729Sjoerg Module = Modules[Entry] = NewModule.get();
2407330f729Sjoerg
2417330f729Sjoerg updateModuleImports(*NewModule, ImportedBy, ImportLoc);
2427330f729Sjoerg
2437330f729Sjoerg if (!NewModule->isModule())
2447330f729Sjoerg PCHChain.push_back(NewModule.get());
2457330f729Sjoerg if (!ImportedBy)
2467330f729Sjoerg Roots.push_back(NewModule.get());
2477330f729Sjoerg
2487330f729Sjoerg Chain.push_back(std::move(NewModule));
2497330f729Sjoerg return NewlyLoaded;
2507330f729Sjoerg }
2517330f729Sjoerg
removeModules(ModuleIterator First,ModuleMap * modMap)252*e038c9c4Sjoerg void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) {
2537330f729Sjoerg auto Last = end();
2547330f729Sjoerg if (First == Last)
2557330f729Sjoerg return;
2567330f729Sjoerg
2577330f729Sjoerg // Explicitly clear VisitOrder since we might not notice it is stale.
2587330f729Sjoerg VisitOrder.clear();
2597330f729Sjoerg
2607330f729Sjoerg // Collect the set of module file pointers that we'll be removing.
2617330f729Sjoerg llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
2627330f729Sjoerg (llvm::pointer_iterator<ModuleIterator>(First)),
2637330f729Sjoerg (llvm::pointer_iterator<ModuleIterator>(Last)));
2647330f729Sjoerg
2657330f729Sjoerg auto IsVictim = [&](ModuleFile *MF) {
2667330f729Sjoerg return victimSet.count(MF);
2677330f729Sjoerg };
2687330f729Sjoerg // Remove any references to the now-destroyed modules.
2697330f729Sjoerg for (auto I = begin(); I != First; ++I) {
2707330f729Sjoerg I->Imports.remove_if(IsVictim);
2717330f729Sjoerg I->ImportedBy.remove_if(IsVictim);
2727330f729Sjoerg }
2737330f729Sjoerg Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
2747330f729Sjoerg Roots.end());
2757330f729Sjoerg
2767330f729Sjoerg // Remove the modules from the PCH chain.
2777330f729Sjoerg for (auto I = First; I != Last; ++I) {
2787330f729Sjoerg if (!I->isModule()) {
2797330f729Sjoerg PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
2807330f729Sjoerg break;
2817330f729Sjoerg }
2827330f729Sjoerg }
2837330f729Sjoerg
2847330f729Sjoerg // Delete the modules and erase them from the various structures.
2857330f729Sjoerg for (ModuleIterator victim = First; victim != Last; ++victim) {
2867330f729Sjoerg Modules.erase(victim->File);
2877330f729Sjoerg
2887330f729Sjoerg if (modMap) {
2897330f729Sjoerg StringRef ModuleName = victim->ModuleName;
2907330f729Sjoerg if (Module *mod = modMap->findModule(ModuleName)) {
291*e038c9c4Sjoerg mod->setASTFile(None);
2927330f729Sjoerg }
2937330f729Sjoerg }
2947330f729Sjoerg }
2957330f729Sjoerg
2967330f729Sjoerg // Delete the modules.
2977330f729Sjoerg Chain.erase(Chain.begin() + (First - begin()), Chain.end());
2987330f729Sjoerg }
2997330f729Sjoerg
3007330f729Sjoerg void
addInMemoryBuffer(StringRef FileName,std::unique_ptr<llvm::MemoryBuffer> Buffer)3017330f729Sjoerg ModuleManager::addInMemoryBuffer(StringRef FileName,
3027330f729Sjoerg std::unique_ptr<llvm::MemoryBuffer> Buffer) {
3037330f729Sjoerg const FileEntry *Entry =
3047330f729Sjoerg FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0);
3057330f729Sjoerg InMemoryBuffers[Entry] = std::move(Buffer);
3067330f729Sjoerg }
3077330f729Sjoerg
allocateVisitState()3087330f729Sjoerg ModuleManager::VisitState *ModuleManager::allocateVisitState() {
3097330f729Sjoerg // Fast path: if we have a cached state, use it.
3107330f729Sjoerg if (FirstVisitState) {
3117330f729Sjoerg VisitState *Result = FirstVisitState;
3127330f729Sjoerg FirstVisitState = FirstVisitState->NextState;
3137330f729Sjoerg Result->NextState = nullptr;
3147330f729Sjoerg return Result;
3157330f729Sjoerg }
3167330f729Sjoerg
3177330f729Sjoerg // Allocate and return a new state.
3187330f729Sjoerg return new VisitState(size());
3197330f729Sjoerg }
3207330f729Sjoerg
returnVisitState(VisitState * State)3217330f729Sjoerg void ModuleManager::returnVisitState(VisitState *State) {
3227330f729Sjoerg assert(State->NextState == nullptr && "Visited state is in list?");
3237330f729Sjoerg State->NextState = FirstVisitState;
3247330f729Sjoerg FirstVisitState = State;
3257330f729Sjoerg }
3267330f729Sjoerg
setGlobalIndex(GlobalModuleIndex * Index)3277330f729Sjoerg void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
3287330f729Sjoerg GlobalIndex = Index;
3297330f729Sjoerg if (!GlobalIndex) {
3307330f729Sjoerg ModulesInCommonWithGlobalIndex.clear();
3317330f729Sjoerg return;
3327330f729Sjoerg }
3337330f729Sjoerg
3347330f729Sjoerg // Notify the global module index about all of the modules we've already
3357330f729Sjoerg // loaded.
3367330f729Sjoerg for (ModuleFile &M : *this)
3377330f729Sjoerg if (!GlobalIndex->loadedModuleFile(&M))
3387330f729Sjoerg ModulesInCommonWithGlobalIndex.push_back(&M);
3397330f729Sjoerg }
3407330f729Sjoerg
moduleFileAccepted(ModuleFile * MF)3417330f729Sjoerg void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
3427330f729Sjoerg if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
3437330f729Sjoerg return;
3447330f729Sjoerg
3457330f729Sjoerg ModulesInCommonWithGlobalIndex.push_back(MF);
3467330f729Sjoerg }
3477330f729Sjoerg
ModuleManager(FileManager & FileMgr,InMemoryModuleCache & ModuleCache,const PCHContainerReader & PCHContainerRdr,const HeaderSearch & HeaderSearchInfo)3487330f729Sjoerg ModuleManager::ModuleManager(FileManager &FileMgr,
3497330f729Sjoerg InMemoryModuleCache &ModuleCache,
3507330f729Sjoerg const PCHContainerReader &PCHContainerRdr,
3517330f729Sjoerg const HeaderSearch &HeaderSearchInfo)
3527330f729Sjoerg : FileMgr(FileMgr), ModuleCache(&ModuleCache),
3537330f729Sjoerg PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}
3547330f729Sjoerg
~ModuleManager()3557330f729Sjoerg ModuleManager::~ModuleManager() { delete FirstVisitState; }
3567330f729Sjoerg
visit(llvm::function_ref<bool (ModuleFile & M)> Visitor,llvm::SmallPtrSetImpl<ModuleFile * > * ModuleFilesHit)3577330f729Sjoerg void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
3587330f729Sjoerg llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
3597330f729Sjoerg // If the visitation order vector is the wrong size, recompute the order.
3607330f729Sjoerg if (VisitOrder.size() != Chain.size()) {
3617330f729Sjoerg unsigned N = size();
3627330f729Sjoerg VisitOrder.clear();
3637330f729Sjoerg VisitOrder.reserve(N);
3647330f729Sjoerg
3657330f729Sjoerg // Record the number of incoming edges for each module. When we
3667330f729Sjoerg // encounter a module with no incoming edges, push it into the queue
3677330f729Sjoerg // to seed the queue.
3687330f729Sjoerg SmallVector<ModuleFile *, 4> Queue;
3697330f729Sjoerg Queue.reserve(N);
3707330f729Sjoerg llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
3717330f729Sjoerg UnusedIncomingEdges.resize(size());
3727330f729Sjoerg for (ModuleFile &M : llvm::reverse(*this)) {
3737330f729Sjoerg unsigned Size = M.ImportedBy.size();
3747330f729Sjoerg UnusedIncomingEdges[M.Index] = Size;
3757330f729Sjoerg if (!Size)
3767330f729Sjoerg Queue.push_back(&M);
3777330f729Sjoerg }
3787330f729Sjoerg
3797330f729Sjoerg // Traverse the graph, making sure to visit a module before visiting any
3807330f729Sjoerg // of its dependencies.
3817330f729Sjoerg while (!Queue.empty()) {
3827330f729Sjoerg ModuleFile *CurrentModule = Queue.pop_back_val();
3837330f729Sjoerg VisitOrder.push_back(CurrentModule);
3847330f729Sjoerg
3857330f729Sjoerg // For any module that this module depends on, push it on the
3867330f729Sjoerg // stack (if it hasn't already been marked as visited).
3877330f729Sjoerg for (auto M = CurrentModule->Imports.rbegin(),
3887330f729Sjoerg MEnd = CurrentModule->Imports.rend();
3897330f729Sjoerg M != MEnd; ++M) {
3907330f729Sjoerg // Remove our current module as an impediment to visiting the
3917330f729Sjoerg // module we depend on. If we were the last unvisited module
3927330f729Sjoerg // that depends on this particular module, push it into the
3937330f729Sjoerg // queue to be visited.
3947330f729Sjoerg unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
3957330f729Sjoerg if (NumUnusedEdges && (--NumUnusedEdges == 0))
3967330f729Sjoerg Queue.push_back(*M);
3977330f729Sjoerg }
3987330f729Sjoerg }
3997330f729Sjoerg
4007330f729Sjoerg assert(VisitOrder.size() == N && "Visitation order is wrong?");
4017330f729Sjoerg
4027330f729Sjoerg delete FirstVisitState;
4037330f729Sjoerg FirstVisitState = nullptr;
4047330f729Sjoerg }
4057330f729Sjoerg
4067330f729Sjoerg VisitState *State = allocateVisitState();
4077330f729Sjoerg unsigned VisitNumber = State->NextVisitNumber++;
4087330f729Sjoerg
4097330f729Sjoerg // If the caller has provided us with a hit-set that came from the global
4107330f729Sjoerg // module index, mark every module file in common with the global module
4117330f729Sjoerg // index that is *not* in that set as 'visited'.
4127330f729Sjoerg if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
4137330f729Sjoerg for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
4147330f729Sjoerg {
4157330f729Sjoerg ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
4167330f729Sjoerg if (!ModuleFilesHit->count(M))
4177330f729Sjoerg State->VisitNumber[M->Index] = VisitNumber;
4187330f729Sjoerg }
4197330f729Sjoerg }
4207330f729Sjoerg
4217330f729Sjoerg for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
4227330f729Sjoerg ModuleFile *CurrentModule = VisitOrder[I];
4237330f729Sjoerg // Should we skip this module file?
4247330f729Sjoerg if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
4257330f729Sjoerg continue;
4267330f729Sjoerg
4277330f729Sjoerg // Visit the module.
4287330f729Sjoerg assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
4297330f729Sjoerg State->VisitNumber[CurrentModule->Index] = VisitNumber;
4307330f729Sjoerg if (!Visitor(*CurrentModule))
4317330f729Sjoerg continue;
4327330f729Sjoerg
4337330f729Sjoerg // The visitor has requested that cut off visitation of any
4347330f729Sjoerg // module that the current module depends on. To indicate this
4357330f729Sjoerg // behavior, we mark all of the reachable modules as having been visited.
4367330f729Sjoerg ModuleFile *NextModule = CurrentModule;
4377330f729Sjoerg do {
4387330f729Sjoerg // For any module that this module depends on, push it on the
4397330f729Sjoerg // stack (if it hasn't already been marked as visited).
4407330f729Sjoerg for (llvm::SetVector<ModuleFile *>::iterator
4417330f729Sjoerg M = NextModule->Imports.begin(),
4427330f729Sjoerg MEnd = NextModule->Imports.end();
4437330f729Sjoerg M != MEnd; ++M) {
4447330f729Sjoerg if (State->VisitNumber[(*M)->Index] != VisitNumber) {
4457330f729Sjoerg State->Stack.push_back(*M);
4467330f729Sjoerg State->VisitNumber[(*M)->Index] = VisitNumber;
4477330f729Sjoerg }
4487330f729Sjoerg }
4497330f729Sjoerg
4507330f729Sjoerg if (State->Stack.empty())
4517330f729Sjoerg break;
4527330f729Sjoerg
4537330f729Sjoerg // Pop the next module off the stack.
4547330f729Sjoerg NextModule = State->Stack.pop_back_val();
4557330f729Sjoerg } while (true);
4567330f729Sjoerg }
4577330f729Sjoerg
4587330f729Sjoerg returnVisitState(State);
4597330f729Sjoerg }
4607330f729Sjoerg
lookupModuleFile(StringRef FileName,off_t ExpectedSize,time_t ExpectedModTime,Optional<FileEntryRef> & File)461*e038c9c4Sjoerg bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize,
4627330f729Sjoerg time_t ExpectedModTime,
463*e038c9c4Sjoerg Optional<FileEntryRef> &File) {
464*e038c9c4Sjoerg File = None;
465*e038c9c4Sjoerg if (FileName == "-")
4667330f729Sjoerg return false;
4677330f729Sjoerg
4687330f729Sjoerg // Open the file immediately to ensure there is no race between stat'ing and
4697330f729Sjoerg // opening the file.
470*e038c9c4Sjoerg Optional<FileEntryRef> FileOrErr =
471*e038c9c4Sjoerg expectedToOptional(FileMgr.getFileRef(FileName, /*OpenFile=*/true,
472*e038c9c4Sjoerg /*CacheFailure=*/false));
473*e038c9c4Sjoerg if (!FileOrErr)
4747330f729Sjoerg return false;
475*e038c9c4Sjoerg
4767330f729Sjoerg File = *FileOrErr;
4777330f729Sjoerg
4787330f729Sjoerg if ((ExpectedSize && ExpectedSize != File->getSize()) ||
4797330f729Sjoerg (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
4807330f729Sjoerg // Do not destroy File, as it may be referenced. If we need to rebuild it,
4817330f729Sjoerg // it will be destroyed by removeModules.
4827330f729Sjoerg return true;
4837330f729Sjoerg
4847330f729Sjoerg return false;
4857330f729Sjoerg }
4867330f729Sjoerg
4877330f729Sjoerg #ifndef NDEBUG
4887330f729Sjoerg namespace llvm {
4897330f729Sjoerg
4907330f729Sjoerg template<>
4917330f729Sjoerg struct GraphTraits<ModuleManager> {
4927330f729Sjoerg using NodeRef = ModuleFile *;
4937330f729Sjoerg using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
4947330f729Sjoerg using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
4957330f729Sjoerg
child_beginllvm::GraphTraits4967330f729Sjoerg static ChildIteratorType child_begin(NodeRef Node) {
4977330f729Sjoerg return Node->Imports.begin();
4987330f729Sjoerg }
4997330f729Sjoerg
child_endllvm::GraphTraits5007330f729Sjoerg static ChildIteratorType child_end(NodeRef Node) {
5017330f729Sjoerg return Node->Imports.end();
5027330f729Sjoerg }
5037330f729Sjoerg
nodes_beginllvm::GraphTraits5047330f729Sjoerg static nodes_iterator nodes_begin(const ModuleManager &Manager) {
5057330f729Sjoerg return nodes_iterator(Manager.begin());
5067330f729Sjoerg }
5077330f729Sjoerg
nodes_endllvm::GraphTraits5087330f729Sjoerg static nodes_iterator nodes_end(const ModuleManager &Manager) {
5097330f729Sjoerg return nodes_iterator(Manager.end());
5107330f729Sjoerg }
5117330f729Sjoerg };
5127330f729Sjoerg
5137330f729Sjoerg template<>
5147330f729Sjoerg struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits5157330f729Sjoerg explicit DOTGraphTraits(bool IsSimple = false)
5167330f729Sjoerg : DefaultDOTGraphTraits(IsSimple) {}
5177330f729Sjoerg
renderGraphFromBottomUpllvm::DOTGraphTraits5187330f729Sjoerg static bool renderGraphFromBottomUp() { return true; }
5197330f729Sjoerg
getNodeLabelllvm::DOTGraphTraits5207330f729Sjoerg std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
5217330f729Sjoerg return M->ModuleName;
5227330f729Sjoerg }
5237330f729Sjoerg };
5247330f729Sjoerg
5257330f729Sjoerg } // namespace llvm
5267330f729Sjoerg
viewGraph()5277330f729Sjoerg void ModuleManager::viewGraph() {
5287330f729Sjoerg llvm::ViewGraph(*this, "Modules");
5297330f729Sjoerg }
5307330f729Sjoerg #endif
531