clang 23.0.0git
ModuleManager.cpp
Go to the documentation of this file.
1//===- ModuleManager.cpp - Module Manager ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the ModuleManager class, which manages a set of loaded
10// modules for the ASTReader.
11//
12//===----------------------------------------------------------------------===//
13
16#include "clang/Basic/LLVM.h"
18#include "clang/Lex/ModuleMap.h"
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"
36#include <cassert>
37#include <memory>
38#include <string>
39#include <system_error>
40
41using namespace clang;
42using namespace serialization;
43
45 if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
46 if (const ModuleFileName *FileName = Mod->getASTFileName())
48
49 return nullptr;
50}
51
53 std::optional<ModuleFileKey> Key = Name.makeKey(FileMgr);
54 return Key ? lookup(*Key) : nullptr;
55}
56
58 return Modules.lookup(Key);
59}
60
61std::unique_ptr<llvm::MemoryBuffer>
62ModuleManager::lookupBuffer(StringRef Name, off_t &Size, time_t &ModTime) {
63 auto Entry = FileMgr.getOptionalFileRef(Name, /*OpenFile=*/false,
64 /*CacheFailure=*/false,
65 /*IsText=*/false);
66 if (!Entry)
67 return nullptr;
68 Size = Entry->getSize();
69 ModTime = Entry->getModificationTime();
70 return std::move(InMemoryBuffers[*Entry]);
71}
72
73bool ModuleManager::isModuleFileOutOfDate(off_t Size, time_t ModTime,
74 off_t ExpectedSize,
75 time_t ExpectedModTime,
77 bool OutOfDate = false;
78 if (ExpectedSize && ExpectedSize != Size) {
79 Result.Changes.push_back({Change::Size, ExpectedSize, Size});
80 OutOfDate = true;
81 }
82
83 if (ExpectedModTime && ExpectedModTime != ModTime) {
84 Result.Changes.push_back({Change::ModTime, ExpectedModTime, ModTime});
85 OutOfDate = true;
86 }
87
88 return OutOfDate;
89}
90
91bool ModuleManager::checkSignature(ASTFileSignature Signature,
92 ASTFileSignature ExpectedSignature,
94 if (!ExpectedSignature || Signature == ExpectedSignature)
95 return false;
96 Result.SignatureError =
97 Signature ? "signature mismatch" : "could not read module signature";
98 return true;
99}
100
101static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
102 SourceLocation ImportLoc) {
103 if (ImportedBy) {
104 MF.ImportedBy.insert(ImportedBy);
105 ImportedBy->Imports.insert(&MF);
106 } else {
107 if (!MF.DirectlyImported)
108 MF.ImportLoc = ImportLoc;
109
110 MF.DirectlyImported = true;
111 }
112}
113
116 ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize,
117 time_t ExpectedModTime, ASTFileSignature ExpectedSignature,
118 ASTFileSignatureReader ReadSignature) {
120
121 uint64_t InputFilesValidationTimestamp = 0;
122 if (Type == MK_ImplicitModule)
123 InputFilesValidationTimestamp = ModCache.getModuleTimestamp(FileName);
124
125 bool IgnoreModTime = Type == MK_ExplicitModule || Type == MK_PrebuiltModule;
126 if (ImportedBy)
127 IgnoreModTime &= ImportedBy->Kind == MK_ExplicitModule ||
128 ImportedBy->Kind == MK_PrebuiltModule;
129 if (IgnoreModTime) {
130 // If neither this file nor the importer are in the module cache, this file
131 // might have a different mtime due to being moved across filesystems in
132 // a distributed build. The size must still match, though. (As must the
133 // contents, but we can't check that.)
134 ExpectedModTime = 0;
135 }
136
137 std::optional<ModuleFileKey> FileKey = FileName.makeKey(FileMgr);
138 if (!FileKey) {
140 return Result;
141 }
142
143 // Check whether we already loaded this module before.
144 // Note: `isModuleFileOutOfDate` and `checkSignature` are mutually exclusive
145 // in practice. If a signature is stored, it means size/mtime values have been
146 // zeroed out. If size/mtime are non-NULL, the signature is empty.
147 if (ModuleFile *ModuleEntry = lookup(*FileKey)) {
148 if (isModuleFileOutOfDate(ModuleEntry->Size, ModuleEntry->ModTime,
149 ExpectedSize, ExpectedModTime, Result)) {
150 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
151 return Result;
152 }
153
154 // Check the stored signature.
155 if (checkSignature(ModuleEntry->Signature, ExpectedSignature, Result)) {
156 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
157 return Result;
158 }
159
160 Result.Module = ModuleEntry;
161 updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
163 return Result;
164 }
165
166 // Load the contents of the module
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 =
172 lookupBuffer(FileName, Size, ModTime)) {
173 // The buffer was already provided for us.
175 FileName, std::move(Buffer), Size, ModTime);
176 } else if (llvm::MemoryBuffer *Buffer =
177 getModuleCache().getInMemoryModuleCache().lookupPCM(
178 FileName, Size, ModTime)) {
179 ModuleBuffer = Buffer;
180 } else if (getModuleCache().getInMemoryModuleCache().shouldBuildPCM(
181 FileName)) {
182 // Report that the module is out of date, since we tried (and failed) to
183 // import it earlier. No ModuleFile exists yet, so derive the validation
184 // status from the module kind being loaded.
188 return Result;
189 } else {
190 auto Buf = [&]() -> Expected<std::unique_ptr<llvm::MemoryBuffer>> {
191 // Implicit modules live in the module cache.
192 if (FileName.getImplicitModuleSuffixLength())
193 return ModCache.read(FileName, Size, ModTime);
194
195 // Explicit modules are treated as any other compiler input file, load
196 // them via FileManager.
198 FileName == StringRef("-")
199 ? FileMgr.getSTDIN()
200 : FileMgr.getFileRef(FileName, /*OpenFile=*/true,
201 /*CacheFailure=*/false,
202 /*IsText=*/false);
203 if (!Entry)
204 return Entry.takeError();
205
206 Size = Entry->getSize();
207 ModTime = Entry->getModificationTime();
208
209 // RequiresNullTerminator is false because module files don't need it, and
210 // this allows the file to still be mmapped.
211 return llvm::errorOrToExpected(
212 FileMgr.getBufferForFile(*Entry, /*IsVolatile=*/false,
213 /*RequiresNullTerminator=*/false,
214 /*MaybeLimit=*/std::nullopt,
215 /*IsText=*/false));
216 }();
217
218 if (!Buf) {
219 Result.BufferError = llvm::toString(Buf.takeError());
221 return Result;
222 }
223
224 NewFileBuffer = std::move(*Buf);
225 ModuleBuffer = NewFileBuffer.get();
226 }
227
228 // Allocate bookkeeping for a module file not yet loaded into this reader.
229 auto NewModule = std::make_unique<ModuleFile>(Type, *FileKey, Generation);
230 NewModule->Index = Chain.size();
231 NewModule->FileName = FileName;
232 NewModule->ImportLoc = ImportLoc;
233 NewModule->InputFilesValidationTimestamp = InputFilesValidationTimestamp;
234 NewModule->Size = Size;
235 NewModule->ModTime = ModTime;
236 NewModule->Buffer = ModuleBuffer;
237 // Initialize the stream.
238 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
239
240 // Check file properties.
241 if (isModuleFileOutOfDate(Size, ModTime, ExpectedSize, ExpectedModTime,
242 Result)) {
243 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
244 return Result;
245 }
246
247 // Read the signature eagerly now so that we can check it. Avoid calling
248 // ReadSignature unless there's something to check though.
249 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
250 ExpectedSignature, Result)) {
251 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
252 return Result;
253 }
254
255 if (NewFileBuffer)
257 FileName, std::move(NewFileBuffer), Size, ModTime);
258
259 // We're keeping this module. Store it in the map.
260 Result.Module = Modules[*FileKey] = NewModule.get();
261
262 updateModuleImports(*NewModule, ImportedBy, ImportLoc);
263
264 if (!NewModule->isModule())
265 PCHChain.push_back(NewModule.get());
266 if (!ImportedBy)
267 Roots.push_back(NewModule.get());
268
269 Chain.push_back(std::move(NewModule));
271 return Result;
272}
273
275 auto Last = end();
276 if (First == Last)
277 return;
278
279 // Explicitly clear VisitOrder since we might not notice it is stale.
280 VisitOrder.clear();
281
282 // Collect the set of module file pointers that we'll be removing.
284 (llvm::pointer_iterator<ModuleIterator>(First)),
285 (llvm::pointer_iterator<ModuleIterator>(Last)));
286
287 auto IsVictim = [&](ModuleFile *MF) {
288 return victimSet.count(MF);
289 };
290 // Remove any references to the now-destroyed modules.
291 for (auto I = begin(); I != First; ++I) {
292 I->Imports.remove_if(IsVictim);
293 I->ImportedBy.remove_if(IsVictim);
294 }
295 llvm::erase_if(Roots, IsVictim);
296
297 // Remove the modules from the PCH chain.
298 for (auto I = First; I != Last; ++I) {
299 if (!I->isModule()) {
300 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
301 break;
302 }
303 }
304
305 // Delete the modules.
306 for (ModuleIterator victim = First; victim != Last; ++victim)
307 Modules.erase(victim->FileKey);
308
309 Chain.erase(Chain.begin() + (First - begin()), Chain.end());
310}
311
312void
314 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
315 FileEntryRef Entry =
316 FileMgr.getVirtualFileRef(FileName, Buffer->getBufferSize(), 0);
317 InMemoryBuffers[Entry] = std::move(Buffer);
318}
319
320std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
321 // Fast path: if we have a cached state, use it.
322 if (FirstVisitState) {
323 auto Result = std::move(FirstVisitState);
324 FirstVisitState = std::move(Result->NextState);
325 return Result;
326 }
327
328 // Allocate and return a new state.
329 return std::make_unique<VisitState>(size());
330}
331
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);
336}
337
339 GlobalIndex = Index;
340 if (!GlobalIndex) {
341 ModulesInCommonWithGlobalIndex.clear();
342 return;
343 }
344
345 // Notify the global module index about all of the modules we've already
346 // loaded.
347 for (ModuleFile &M : *this)
348 if (!GlobalIndex->loadedModuleFile(&M))
349 ModulesInCommonWithGlobalIndex.push_back(&M);
350}
351
353 if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
354 return;
355
356 ModulesInCommonWithGlobalIndex.push_back(MF);
357}
358
360 const PCHContainerReader &PCHContainerRdr,
361 const HeaderSearch &HeaderSearchInfo)
362 : FileMgr(FileMgr), ModCache(ModCache), PCHContainerRdr(PCHContainerRdr),
363 HeaderSearchInfo(HeaderSearchInfo) {}
364
365void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
366 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
367 // If the visitation order vector is the wrong size, recompute the order.
368 if (VisitOrder.size() != Chain.size()) {
369 unsigned N = size();
370 VisitOrder.clear();
371 VisitOrder.reserve(N);
372
373 // Record the number of incoming edges for each module. When we
374 // encounter a module with no incoming edges, push it into the queue
375 // to seed the queue.
377 Queue.reserve(N);
378 llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
379 UnusedIncomingEdges.resize(size());
380 for (ModuleFile &M : llvm::reverse(*this)) {
381 unsigned Size = M.ImportedBy.size();
382 UnusedIncomingEdges[M.Index] = Size;
383 if (!Size)
384 Queue.push_back(&M);
385 }
386
387 // Traverse the graph, making sure to visit a module before visiting any
388 // of its dependencies.
389 while (!Queue.empty()) {
390 ModuleFile *CurrentModule = Queue.pop_back_val();
391 VisitOrder.push_back(CurrentModule);
392
393 // For any module that this module depends on, push it on the
394 // stack (if it hasn't already been marked as visited).
395 for (ModuleFile *M : llvm::reverse(CurrentModule->Imports)) {
396 // Remove our current module as an impediment to visiting the
397 // module we depend on. If we were the last unvisited module
398 // that depends on this particular module, push it into the
399 // queue to be visited.
400 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->Index];
401 if (NumUnusedEdges && (--NumUnusedEdges == 0))
402 Queue.push_back(M);
403 }
404 }
405
406 assert(VisitOrder.size() == N && "Visitation order is wrong?");
407
408 FirstVisitState = nullptr;
409 }
410
411 auto State = allocateVisitState();
412 unsigned VisitNumber = State->NextVisitNumber++;
413
414 // If the caller has provided us with a hit-set that came from the global
415 // module index, mark every module file in common with the global module
416 // index that is *not* in that set as 'visited'.
417 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
418 for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
419 {
420 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
421 if (!ModuleFilesHit->count(M))
422 State->VisitNumber[M->Index] = VisitNumber;
423 }
424 }
425
426 for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
427 ModuleFile *CurrentModule = VisitOrder[I];
428 // Should we skip this module file?
429 if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
430 continue;
431
432 // Visit the module.
433 assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
434 State->VisitNumber[CurrentModule->Index] = VisitNumber;
435 if (!Visitor(*CurrentModule))
436 continue;
437
438 // The visitor has requested that cut off visitation of any
439 // module that the current module depends on. To indicate this
440 // behavior, we mark all of the reachable modules as having been visited.
441 ModuleFile *NextModule = CurrentModule;
442 do {
443 // For any module that this module depends on, push it on the
444 // stack (if it hasn't already been marked as visited).
445 for (llvm::SetVector<ModuleFile *>::iterator
446 M = NextModule->Imports.begin(),
447 MEnd = NextModule->Imports.end();
448 M != MEnd; ++M) {
449 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
450 State->Stack.push_back(*M);
451 State->VisitNumber[(*M)->Index] = VisitNumber;
452 }
453 }
454
455 if (State->Stack.empty())
456 break;
457
458 // Pop the next module off the stack.
459 NextModule = State->Stack.pop_back_val();
460 } while (true);
461 }
462
463 returnVisitState(std::move(State));
464}
465
466#ifndef NDEBUG
467namespace llvm {
468
469 template<>
470 struct GraphTraits<ModuleManager> {
472 using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
473 using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
474
476 return Node->Imports.begin();
477 }
478
480 return Node->Imports.end();
481 }
482
483 static nodes_iterator nodes_begin(const ModuleManager &Manager) {
484 return nodes_iterator(Manager.begin());
485 }
486
487 static nodes_iterator nodes_end(const ModuleManager &Manager) {
488 return nodes_iterator(Manager.end());
489 }
490 };
491
492 template<>
494 explicit DOTGraphTraits(bool IsSimple = false)
495 : DefaultDOTGraphTraits(IsSimple) {}
496
497 static bool renderGraphFromBottomUp() { return true; }
498
499 std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
500 return M->ModuleName;
501 }
502 };
503
504} // namespace llvm
505
507 llvm::ViewGraph(*this, "Modules");
508}
509#endif
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...
Definition FileEntry.h:57
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:53
A global index for a set of module files, providing information about the identifiers within those mo...
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
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.
Definition ModuleCache.h:30
virtual InMemoryModuleCache & getInMemoryModuleCache()=0
Returns this process's view of the module cache.
Deduplication key for a loaded module file in ModuleManager.
Definition Module.h:69
Identifies a module file to be loaded.
Definition Module.h:102
std::optional< ModuleFileKey > makeKey(FileManager &FileMgr) const
Creates the deduplication key for use in ModuleManager.
Definition Module.cpp:37
Describes a module or submodule.
Definition Module.h:246
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.
Definition TypeBase.h:1866
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.
Definition ModuleFile.h:158
bool DirectlyImported
Whether this module has been directly imported by the user.
Definition ModuleFile.h:241
llvm::SetVector< ModuleFile * > ImportedBy
List of modules which depend on this module.
Definition ModuleFile.h:536
SourceLocation ImportLoc
The source location where this module was first imported.
Definition ModuleFile.h:277
unsigned Index
The index of this module in the list of modules.
Definition ModuleFile.h:171
llvm::SetVector< ModuleFile * > Imports
List of modules which this module directly imported.
Definition ModuleFile.h:539
ModuleKind Kind
The type of this module.
Definition ModuleFile.h:174
std::string ModuleName
The name of the module.
Definition ModuleFile.h:183
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.
Definition ModuleFile.h:141
@ NotStarted
Initial value, before the validation has been performed.
Definition ModuleFile.h:139
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h:44
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition ModuleFile.h:49
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition ModuleFile.h:46
@ MK_PrebuiltModule
File is from a prebuilt module path.
Definition ModuleFile.h:61
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
The signature of a module, which is a hash of the AST content.
Definition Module.h:160
std::string getNodeLabel(ModuleFile *M, const ModuleManager &)
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)