24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SetVector.h"
26#include "llvm/ADT/SmallPtrSet.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/ADT/iterator.h"
30#include "llvm/Support/DOTGraphTraits.h"
31#include "llvm/Support/Error.h"
32#include "llvm/Support/ErrorOr.h"
33#include "llvm/Support/GraphWriter.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/VirtualFileSystem.h"
39#include <system_error>
44std::optional<ModuleFileKey>
47 StringRef ModuleCachePath = StringRef(Name).drop_back(SuffixLen);
48 StringRef ImplicitModuleSuffix = StringRef(Name).take_back(SuffixLen);
49 if (
auto *ModuleCacheDir = ModCache.getDirectoryPtr(ModuleCachePath))
52 if (
auto ModuleFile = FileMgr.getOptionalFileRef(Name,
true,
62 if (
const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
70 std::optional<ModuleFileKey> Key =
makeKey(Name);
71 return Key ?
lookup(*Key) :
nullptr;
75 return Modules.lookup(Key);
78std::unique_ptr<llvm::MemoryBuffer>
80 auto Entry = FileMgr.getOptionalFileRef(Name,
false,
85 Size = Entry->getSize();
86 ModTime = Entry->getModificationTime();
87 return std::move(InMemoryBuffers[*Entry]);
90bool ModuleManager::isModuleFileOutOfDate(off_t Size, time_t ModTime,
92 time_t ExpectedModTime,
94 bool OutOfDate =
false;
95 if (ExpectedSize && ExpectedSize != Size) {
100 if (ExpectedModTime && ExpectedModTime != ModTime) {
108bool ModuleManager::checkSignature(ASTFileSignature Signature,
109 ASTFileSignature ExpectedSignature,
111 if (!ExpectedSignature || Signature == ExpectedSignature)
114 Signature ?
"signature mismatch" :
"could not read module signature";
122 ImportedBy->
Imports.insert(&MF);
133 ModuleFile *ImportedBy,
unsigned Generation, off_t ExpectedSize,
138 uint64_t InputFilesValidationTimestamp = 0;
140 InputFilesValidationTimestamp = ModCache.getModuleTimestamp(
FileName);
165 if (isModuleFileOutOfDate(ModuleEntry->Size, ModuleEntry->ModTime,
166 ExpectedSize, ExpectedModTime,
Result)) {
167 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
172 if (checkSignature(ModuleEntry->Signature, ExpectedSignature,
Result)) {
173 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
177 Result.Module = ModuleEntry;
184 off_t Size = ExpectedSize;
185 time_t ModTime = ExpectedModTime;
186 llvm::MemoryBuffer *ModuleBuffer =
nullptr;
187 std::unique_ptr<llvm::MemoryBuffer> NewFileBuffer =
nullptr;
188 if (std::unique_ptr<llvm::MemoryBuffer> Buffer =
192 FileName, std::move(Buffer), Size, ModTime);
193 }
else if (llvm::MemoryBuffer *Buffer =
196 ModuleBuffer = Buffer;
197 }
else if (
getModuleCache().getInMemoryModuleCache().shouldBuildPCM(
207 auto Buf = [&]() ->
Expected<std::unique_ptr<llvm::MemoryBuffer>> {
209 if (
FileName.getImplicitModuleSuffixLength())
210 return ModCache.read(
FileName, Size, ModTime);
217 : FileMgr.getFileRef(
FileName,
true,
221 return Entry.takeError();
223 Size = Entry->getSize();
224 ModTime = Entry->getModificationTime();
228 return llvm::errorOrToExpected(
229 FileMgr.getBufferForFile(*Entry,
false,
236 Result.BufferError = llvm::toString(Buf.takeError());
241 NewFileBuffer = std::move(*Buf);
242 ModuleBuffer = NewFileBuffer.get();
246 auto NewModule = std::make_unique<ModuleFile>(
Type, *FileKey, Generation);
247 NewModule->Index = Chain.size();
249 NewModule->ImportLoc = ImportLoc;
250 NewModule->InputFilesValidationTimestamp = InputFilesValidationTimestamp;
251 NewModule->Size = Size;
252 NewModule->ModTime = ModTime;
253 NewModule->Buffer = ModuleBuffer;
255 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
258 if (isModuleFileOutOfDate(Size, ModTime, ExpectedSize, ExpectedModTime,
260 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
266 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
267 ExpectedSignature,
Result)) {
268 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
274 FileName, std::move(NewFileBuffer), Size, ModTime);
277 Result.Module = Modules[*FileKey] = NewModule.get();
281 if (!NewModule->isModule())
282 PCHChain.push_back(NewModule.get());
284 Roots.push_back(NewModule.get());
286 Chain.push_back(std::move(NewModule));
301 (llvm::pointer_iterator<ModuleIterator>(
First)),
302 (llvm::pointer_iterator<ModuleIterator>(
Last)));
305 return victimSet.count(MF);
309 I->Imports.remove_if(IsVictim);
310 I->ImportedBy.remove_if(IsVictim);
312 llvm::erase_if(Roots, IsVictim);
316 if (!I->isModule()) {
317 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
324 Modules.erase(victim->FileKey);
326 Chain.erase(Chain.begin() + (
First -
begin()), Chain.end());
331 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
333 FileMgr.getVirtualFileRef(
FileName, Buffer->getBufferSize(), 0);
334 InMemoryBuffers[Entry] = std::move(Buffer);
337std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
339 if (FirstVisitState) {
340 auto Result = std::move(FirstVisitState);
341 FirstVisitState = std::move(
Result->NextState);
346 return std::make_unique<VisitState>(
size());
349void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
350 assert(State->NextState ==
nullptr &&
"Visited state is in list?");
351 State->NextState = std::move(FirstVisitState);
352 FirstVisitState = std::move(State);
358 ModulesInCommonWithGlobalIndex.clear();
365 if (!GlobalIndex->loadedModuleFile(&M))
366 ModulesInCommonWithGlobalIndex.push_back(&M);
370 if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
373 ModulesInCommonWithGlobalIndex.push_back(MF);
379 : FileMgr(FileMgr), ModCache(ModCache), PCHContainerRdr(PCHContainerRdr),
380 HeaderSearchInfo(HeaderSearchInfo) {}
383 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
385 if (VisitOrder.size() != Chain.size()) {
388 VisitOrder.reserve(N);
396 UnusedIncomingEdges.resize(
size());
399 UnusedIncomingEdges[M.
Index] = Size;
406 while (!Queue.empty()) {
407 ModuleFile *CurrentModule = Queue.pop_back_val();
408 VisitOrder.push_back(CurrentModule);
417 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->
Index];
418 if (NumUnusedEdges && (--NumUnusedEdges == 0))
423 assert(VisitOrder.size() == N &&
"Visitation order is wrong?");
425 FirstVisitState =
nullptr;
428 auto State = allocateVisitState();
429 unsigned VisitNumber = State->NextVisitNumber++;
434 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
435 for (
unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
437 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
438 if (!ModuleFilesHit->count(M))
439 State->VisitNumber[M->
Index] = VisitNumber;
443 for (
unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
446 if (State->VisitNumber[CurrentModule->
Index] == VisitNumber)
450 assert(State->VisitNumber[CurrentModule->
Index] == VisitNumber - 1);
451 State->VisitNumber[CurrentModule->
Index] = VisitNumber;
452 if (!Visitor(*CurrentModule))
462 for (llvm::SetVector<ModuleFile *>::iterator
463 M = NextModule->
Imports.begin(),
464 MEnd = NextModule->
Imports.end();
466 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
467 State->Stack.push_back(*M);
468 State->VisitNumber[(*M)->Index] = VisitNumber;
472 if (State->Stack.empty())
476 NextModule = State->Stack.pop_back_val();
480 returnVisitState(std::move(State));
524 llvm::ViewGraph(*
this,
"Modules");
Defines the clang::FileManager interface and associated types.
Result
Implement __builtin_bit_cast and related operations.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, SourceLocation ImportLoc)
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Implements support for file system lookup, file system caching, and directory search management.
A global index for a set of module files, providing information about the identifiers within those mo...
llvm::MemoryBuffer & addPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer, off_t Size, time_t ModTime)
Store the PCM under the Filename.
llvm::MemoryBuffer & addBuiltPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer, off_t Size, time_t ModTime)
Store a just-built PCM under the Filename.
The module cache used for compiling modules implicitly.
virtual InMemoryModuleCache & getInMemoryModuleCache()=0
Returns this process's view of the module cache.
Deduplication key for a loaded module file in ModuleManager.
Identifies a module file to be loaded.
unsigned getImplicitModuleSuffixLength() const
Returns the suffix length for an implicit module name, zero otherwise.
Describes a module or submodule.
This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...
Encodes a location in the source.
The base class of the type hierarchy.
The result of attempting to add a new module.
@ Missing
The module file is missing.
@ NewlyLoaded
The module file was just loaded in response to this call.
@ AlreadyLoaded
The module file had already been loaded.
Information about a module that has been loaded by the ASTReader.
bool DirectlyImported
Whether this module has been directly imported by the user.
llvm::SetVector< ModuleFile * > ImportedBy
List of modules which depend on this module.
SourceLocation ImportLoc
The source location where this module was first imported.
unsigned Index
The index of this module in the list of modules.
llvm::SetVector< ModuleFile * > Imports
List of modules which this module directly imported.
ModuleKind Kind
The type of this module.
std::string ModuleName
The name of the module.
Manages the set of modules loaded by an AST reader.
std::unique_ptr< llvm::MemoryBuffer > lookupBuffer(StringRef Name, off_t &Size, time_t &ModTime)
Returns the in-memory (virtual file) buffer with the given name.
AddModuleResult addModule(ModuleFileName FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, ASTFileSignatureReader ReadSignature)
Attempts to create a new module and add it to the list of known modules.
ModuleFile * lookup(ModuleFileKey Key) const
Returns the module associated with the given module file key.
llvm::pointee_iterator< SmallVectorImpl< std::unique_ptr< ModuleFile > >::iterator > ModuleIterator
void moduleFileAccepted(ModuleFile *MF)
Notification from the AST reader that the given module file has been "accepted", and will not (can no...
ModuleManager(FileManager &FileMgr, ModuleCache &ModCache, const PCHContainerReader &PCHContainerRdr, const HeaderSearch &HeaderSearchInfo)
void viewGraph()
View the graphviz representation of the module graph.
ModuleCache & getModuleCache() const
ModuleIterator begin()
Forward iterator to traverse all loaded modules.
std::optional< ModuleFileKey > makeKey(const ModuleFileName &Name) const
Creates the deduplication key for use in ModuleManager.
void setGlobalIndex(GlobalModuleIndex *Index)
Set the global module index.
void removeModules(ModuleIterator First)
Remove the modules starting from First (to the end).
ModuleIterator end()
Forward iterator end-point to traverse all loaded modules.
void addInMemoryBuffer(StringRef FileName, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Add an in-memory buffer the list of known buffers.
void visit(llvm::function_ref< bool(ModuleFile &M)> Visitor, llvm::SmallPtrSetImpl< ModuleFile * > *ModuleFilesHit=nullptr)
Visit each of the modules.
unsigned size() const
Number of modules loaded.
ModuleFile * lookupByFileName(ModuleFileName FileName) const
Returns the module associated with the given module file name.
ASTFileSignature(*)(StringRef) ASTFileSignatureReader
ModuleFile * lookupByModuleName(StringRef ModName) const
Returns the module associated with the given module name.
@ Disabled
When the validation is disabled. For example, for a precompiled header.
@ NotStarted
Initial value, before the validation has been performed.
ModuleKind
Specifies the kind of module that has been loaded.
@ MK_ExplicitModule
File is an explicitly-loaded module.
@ MK_ImplicitModule
File is an implicitly-loaded module.
@ MK_PrebuiltModule
File is from a prebuilt module path.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Diagnostic wrappers for TextAPI types for error reporting.
The signature of a module, which is a hash of the AST content.
DOTGraphTraits(bool IsSimple=false)
std::string getNodeLabel(ModuleFile *M, const ModuleManager &)
static bool renderGraphFromBottomUp()
static ChildIteratorType child_end(NodeRef Node)
static nodes_iterator nodes_begin(const ModuleManager &Manager)
static ChildIteratorType child_begin(NodeRef Node)
pointer_iterator< ModuleManager::ModuleConstIterator > nodes_iterator
llvm::SetVector< ModuleFile * >::const_iterator ChildIteratorType
static nodes_iterator nodes_end(const ModuleManager &Manager)