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>
45 if (
const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
53 std::optional<ModuleFileKey> Key = Name.
makeKey(FileMgr);
54 return Key ?
lookup(*Key) :
nullptr;
58 return Modules.lookup(Key);
61std::unique_ptr<llvm::MemoryBuffer>
63 auto Entry = FileMgr.getOptionalFileRef(Name,
false,
68 Size = Entry->getSize();
69 ModTime = Entry->getModificationTime();
70 return std::move(InMemoryBuffers[*Entry]);
73bool ModuleManager::isModuleFileOutOfDate(off_t Size, time_t ModTime,
75 time_t ExpectedModTime,
77 bool OutOfDate =
false;
78 if (ExpectedSize && ExpectedSize != Size) {
83 if (ExpectedModTime && ExpectedModTime != ModTime) {
91bool ModuleManager::checkSignature(ASTFileSignature Signature,
92 ASTFileSignature ExpectedSignature,
94 if (!ExpectedSignature || Signature == ExpectedSignature)
97 Signature ?
"signature mismatch" :
"could not read module signature";
105 ImportedBy->
Imports.insert(&MF);
116 ModuleFile *ImportedBy,
unsigned Generation, off_t ExpectedSize,
121 uint64_t InputFilesValidationTimestamp = 0;
123 InputFilesValidationTimestamp = ModCache.getModuleTimestamp(
FileName);
137 std::optional<ModuleFileKey> FileKey =
FileName.makeKey(FileMgr);
148 if (isModuleFileOutOfDate(ModuleEntry->Size, ModuleEntry->ModTime,
149 ExpectedSize, ExpectedModTime,
Result)) {
150 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
155 if (checkSignature(ModuleEntry->Signature, ExpectedSignature,
Result)) {
156 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
160 Result.Module = ModuleEntry;
167 off_t Size = ExpectedSize;
168 time_t ModTime = ExpectedModTime;
169 llvm::MemoryBuffer *ModuleBuffer =
nullptr;
170 std::unique_ptr<llvm::MemoryBuffer> NewFileBuffer =
nullptr;
171 if (std::unique_ptr<llvm::MemoryBuffer> Buffer =
175 FileName, std::move(Buffer), Size, ModTime);
176 }
else if (llvm::MemoryBuffer *Buffer =
179 ModuleBuffer = Buffer;
180 }
else if (
getModuleCache().getInMemoryModuleCache().shouldBuildPCM(
190 auto Buf = [&]() ->
Expected<std::unique_ptr<llvm::MemoryBuffer>> {
192 if (
FileName.getImplicitModuleSuffixLength())
193 return ModCache.read(
FileName, Size, ModTime);
200 : FileMgr.getFileRef(
FileName,
true,
204 return Entry.takeError();
206 Size = Entry->getSize();
207 ModTime = Entry->getModificationTime();
211 return llvm::errorOrToExpected(
212 FileMgr.getBufferForFile(*Entry,
false,
219 Result.BufferError = llvm::toString(Buf.takeError());
224 NewFileBuffer = std::move(*Buf);
225 ModuleBuffer = NewFileBuffer.get();
229 auto NewModule = std::make_unique<ModuleFile>(
Type, *FileKey, Generation);
230 NewModule->Index = Chain.size();
232 NewModule->ImportLoc = ImportLoc;
233 NewModule->InputFilesValidationTimestamp = InputFilesValidationTimestamp;
234 NewModule->Size = Size;
235 NewModule->ModTime = ModTime;
236 NewModule->Buffer = ModuleBuffer;
238 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
241 if (isModuleFileOutOfDate(Size, ModTime, ExpectedSize, ExpectedModTime,
243 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
249 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
250 ExpectedSignature,
Result)) {
251 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
257 FileName, std::move(NewFileBuffer), Size, ModTime);
260 Result.Module = Modules[*FileKey] = NewModule.get();
264 if (!NewModule->isModule())
265 PCHChain.push_back(NewModule.get());
267 Roots.push_back(NewModule.get());
269 Chain.push_back(std::move(NewModule));
284 (llvm::pointer_iterator<ModuleIterator>(
First)),
285 (llvm::pointer_iterator<ModuleIterator>(
Last)));
288 return victimSet.count(MF);
292 I->Imports.remove_if(IsVictim);
293 I->ImportedBy.remove_if(IsVictim);
295 llvm::erase_if(Roots, IsVictim);
299 if (!I->isModule()) {
300 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
307 Modules.erase(victim->FileKey);
309 Chain.erase(Chain.begin() + (
First -
begin()), Chain.end());
314 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
316 FileMgr.getVirtualFileRef(
FileName, Buffer->getBufferSize(), 0);
317 InMemoryBuffers[Entry] = std::move(Buffer);
320std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
322 if (FirstVisitState) {
323 auto Result = std::move(FirstVisitState);
324 FirstVisitState = std::move(
Result->NextState);
329 return std::make_unique<VisitState>(
size());
332void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
333 assert(State->NextState ==
nullptr &&
"Visited state is in list?");
334 State->NextState = std::move(FirstVisitState);
335 FirstVisitState = std::move(State);
341 ModulesInCommonWithGlobalIndex.clear();
348 if (!GlobalIndex->loadedModuleFile(&M))
349 ModulesInCommonWithGlobalIndex.push_back(&M);
353 if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
356 ModulesInCommonWithGlobalIndex.push_back(MF);
362 : FileMgr(FileMgr), ModCache(ModCache), PCHContainerRdr(PCHContainerRdr),
363 HeaderSearchInfo(HeaderSearchInfo) {}
366 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
368 if (VisitOrder.size() != Chain.size()) {
371 VisitOrder.reserve(N);
379 UnusedIncomingEdges.resize(
size());
382 UnusedIncomingEdges[M.
Index] = Size;
389 while (!Queue.empty()) {
390 ModuleFile *CurrentModule = Queue.pop_back_val();
391 VisitOrder.push_back(CurrentModule);
400 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->
Index];
401 if (NumUnusedEdges && (--NumUnusedEdges == 0))
406 assert(VisitOrder.size() == N &&
"Visitation order is wrong?");
408 FirstVisitState =
nullptr;
411 auto State = allocateVisitState();
412 unsigned VisitNumber = State->NextVisitNumber++;
417 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
418 for (
unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
420 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
421 if (!ModuleFilesHit->count(M))
422 State->VisitNumber[M->
Index] = VisitNumber;
426 for (
unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
429 if (State->VisitNumber[CurrentModule->
Index] == VisitNumber)
433 assert(State->VisitNumber[CurrentModule->
Index] == VisitNumber - 1);
434 State->VisitNumber[CurrentModule->
Index] = VisitNumber;
435 if (!Visitor(*CurrentModule))
445 for (llvm::SetVector<ModuleFile *>::iterator
446 M = NextModule->
Imports.begin(),
447 MEnd = NextModule->
Imports.end();
449 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
450 State->Stack.push_back(*M);
451 State->VisitNumber[(*M)->Index] = VisitNumber;
455 if (State->Stack.empty())
459 NextModule = State->Stack.pop_back_val();
463 returnVisitState(std::move(State));
507 llvm::ViewGraph(*
this,
"Modules");
Defines the clang::FileManager interface and associated types.
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.
std::optional< ModuleFileKey > makeKey(FileManager &FileMgr) const
Creates the deduplication key for use in ModuleManager.
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.
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)