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/ErrorOr.h"
32#include "llvm/Support/GraphWriter.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/VirtualFileSystem.h"
35#include <cassert>
36#include <memory>
37#include <string>
38#include <system_error>
39
40using namespace clang;
41using namespace serialization;
42
44 if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
45 if (const ModuleFileName *FileName = Mod->getASTFileName())
47
48 return nullptr;
49}
50
52 std::optional<ModuleFileKey> Key = Name.makeKey(FileMgr);
53 return Key ? lookup(*Key) : nullptr;
54}
55
57 return Modules.lookup(Key);
58}
59
60std::unique_ptr<llvm::MemoryBuffer>
62 auto Entry = FileMgr.getOptionalFileRef(Name, /*OpenFile=*/false,
63 /*CacheFailure=*/false);
64 if (!Entry)
65 return nullptr;
66 return std::move(InMemoryBuffers[*Entry]);
67}
68
69static bool checkModuleFile(off_t Size, time_t ModTime, off_t ExpectedSize,
70 time_t ExpectedModTime, std::string &ErrorStr) {
71 if (ExpectedSize && ExpectedSize != Size) {
72 ErrorStr = "module file has a different size than expected";
73 return true;
74 }
75
76 if (ExpectedModTime && ExpectedModTime != ModTime) {
77 ErrorStr = "module file has a different modification time than expected";
78 return true;
79 }
80
81 return false;
82}
83
84static bool checkSignature(ASTFileSignature Signature,
85 ASTFileSignature ExpectedSignature,
86 std::string &ErrorStr) {
87 if (!ExpectedSignature || Signature == ExpectedSignature)
88 return false;
89
90 ErrorStr =
91 Signature ? "signature mismatch" : "could not read module signature";
92 return true;
93}
94
95static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
96 SourceLocation ImportLoc) {
97 if (ImportedBy) {
98 MF.ImportedBy.insert(ImportedBy);
99 ImportedBy->Imports.insert(&MF);
100 } else {
101 if (!MF.DirectlyImported)
102 MF.ImportLoc = ImportLoc;
103
104 MF.DirectlyImported = true;
105 }
106}
107
110 ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize,
111 time_t ExpectedModTime, ASTFileSignature ExpectedSignature,
113 std::string &ErrorStr) {
114 Module = nullptr;
115
116 uint64_t InputFilesValidationTimestamp = 0;
117 if (Type == MK_ImplicitModule)
118 InputFilesValidationTimestamp = ModCache.getModuleTimestamp(FileName);
119
120 bool IgnoreModTime = Type == MK_ExplicitModule || Type == MK_PrebuiltModule;
121 if (ImportedBy)
122 IgnoreModTime &= ImportedBy->Kind == MK_ExplicitModule ||
123 ImportedBy->Kind == MK_PrebuiltModule;
124 if (IgnoreModTime) {
125 // If neither this file nor the importer are in the module cache, this file
126 // might have a different mtime due to being moved across filesystems in
127 // a distributed build. The size must still match, though. (As must the
128 // contents, but we can't check that.)
129 ExpectedModTime = 0;
130 }
131
132 std::optional<ModuleFileKey> FileKey = FileName.makeKey(FileMgr);
133 if (!FileKey) {
134 ErrorStr = "module file not found";
135 return Missing;
136 }
137
138 // Check whether we already loaded this module, before
139 if (ModuleFile *ModuleEntry = lookup(*FileKey)) {
140 // Check file properties.
141 if (checkModuleFile(ModuleEntry->Size, ModuleEntry->ModTime, ExpectedSize,
142 ExpectedModTime, ErrorStr))
143 return OutOfDate;
144
145 // Check the stored signature.
146 if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
147 return OutOfDate;
148
149 Module = ModuleEntry;
150 updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
151 return AlreadyLoaded;
152 }
153
154 // Load the contents of the module
155 off_t Size = ExpectedSize;
156 time_t ModTime = ExpectedModTime;
157 llvm::MemoryBuffer *ModuleBuffer = nullptr;
158 std::unique_ptr<llvm::MemoryBuffer> NewFileBuffer = nullptr;
159 if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
160 // The buffer was already provided for us.
162 FileName, std::move(Buffer));
163 } else if (llvm::MemoryBuffer *Buffer =
164 getModuleCache().getInMemoryModuleCache().lookupPCM(
165 FileName)) {
166 ModuleBuffer = Buffer;
167 if (!FileName.getImplicitModuleSuffixLength()) {
168 // Explicitly-built PCM files maintain consistency via mtime/size
169 // expectations on their imports. Even if we've previously successfully
170 // loaded a PCM file and stored it in the in-memory module cache, that
171 // does not mean its mtime/size matches current importer's expectations.
172 // Get that information so that it can be checked below.
173 // FIXME: Even though this FileManager access is likely already cached, we
174 // should store this directly in the in-memory module cache.
176 FileMgr.getOptionalFileRef(FileName, /*OpenFile=*/true,
177 /*CacheFailure=*/false);
178 if (!Entry) {
179 ErrorStr = "module file not found";
180 return Missing;
181 }
182 ModTime = Entry->getModificationTime();
183 Size = Entry->getSize();
184 }
185 } else if (getModuleCache().getInMemoryModuleCache().shouldBuildPCM(
186 FileName)) {
187 // Report that the module is out of date, since we tried (and failed) to
188 // import it earlier.
189 return OutOfDate;
190 } else {
192 expectedToOptional(FileName == StringRef("-")
193 ? FileMgr.getSTDIN()
194 : FileMgr.getFileRef(FileName, /*OpenFile=*/true,
195 /*CacheFailure=*/false));
196 if (!Entry) {
197 ErrorStr = "module file not found";
198 return Missing;
199 }
200
201 // Get a buffer of the file and close the file descriptor when done.
202 // The file is volatile because in a parallel build we expect multiple
203 // compiler processes to use the same module file rebuilding it if needed.
204 //
205 // RequiresNullTerminator is false because module files don't need it, and
206 // this allows the file to still be mmapped.
207 auto Buf = FileMgr.getBufferForFile(*Entry,
208 /*IsVolatile=*/true,
209 /*RequiresNullTerminator=*/false);
210
211 if (!Buf) {
212 ErrorStr = Buf.getError().message();
213 return Missing;
214 }
215
216 Size = Entry->getSize();
217 ModTime = Entry->getModificationTime();
218 NewFileBuffer = std::move(*Buf);
219 ModuleBuffer = NewFileBuffer.get();
220 }
221
222 // Allocate a new module.
223 auto NewModule = std::make_unique<ModuleFile>(Type, *FileKey, Generation);
224 NewModule->Index = Chain.size();
225 NewModule->FileName = FileName;
226 NewModule->ImportLoc = ImportLoc;
227 NewModule->InputFilesValidationTimestamp = InputFilesValidationTimestamp;
228 NewModule->Size = Size;
229 NewModule->ModTime = ModTime;
230 NewModule->Buffer = ModuleBuffer;
231 // Initialize the stream.
232 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
233
234 // Check file properties.
235 if (checkModuleFile(Size, ModTime, ExpectedSize, ExpectedModTime, ErrorStr))
236 return OutOfDate;
237
238 // Read the signature eagerly now so that we can check it. Avoid calling
239 // ReadSignature unless there's something to check though.
240 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
241 ExpectedSignature, ErrorStr))
242 return OutOfDate;
243
244 if (NewFileBuffer)
246 std::move(NewFileBuffer));
247
248 // We're keeping this module. Store it in the map.
249 Module = Modules[*FileKey] = NewModule.get();
250
251 updateModuleImports(*NewModule, ImportedBy, ImportLoc);
252
253 if (!NewModule->isModule())
254 PCHChain.push_back(NewModule.get());
255 if (!ImportedBy)
256 Roots.push_back(NewModule.get());
257
258 Chain.push_back(std::move(NewModule));
259 return NewlyLoaded;
260}
261
263 auto Last = end();
264 if (First == Last)
265 return;
266
267 // Explicitly clear VisitOrder since we might not notice it is stale.
268 VisitOrder.clear();
269
270 // Collect the set of module file pointers that we'll be removing.
272 (llvm::pointer_iterator<ModuleIterator>(First)),
273 (llvm::pointer_iterator<ModuleIterator>(Last)));
274
275 auto IsVictim = [&](ModuleFile *MF) {
276 return victimSet.count(MF);
277 };
278 // Remove any references to the now-destroyed modules.
279 for (auto I = begin(); I != First; ++I) {
280 I->Imports.remove_if(IsVictim);
281 I->ImportedBy.remove_if(IsVictim);
282 }
283 llvm::erase_if(Roots, IsVictim);
284
285 // Remove the modules from the PCH chain.
286 for (auto I = First; I != Last; ++I) {
287 if (!I->isModule()) {
288 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
289 break;
290 }
291 }
292
293 // Delete the modules.
294 for (ModuleIterator victim = First; victim != Last; ++victim)
295 Modules.erase(victim->FileKey);
296
297 Chain.erase(Chain.begin() + (First - begin()), Chain.end());
298}
299
300void
302 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
303 FileEntryRef Entry =
304 FileMgr.getVirtualFileRef(FileName, Buffer->getBufferSize(), 0);
305 InMemoryBuffers[Entry] = std::move(Buffer);
306}
307
308std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
309 // Fast path: if we have a cached state, use it.
310 if (FirstVisitState) {
311 auto Result = std::move(FirstVisitState);
312 FirstVisitState = std::move(Result->NextState);
313 return Result;
314 }
315
316 // Allocate and return a new state.
317 return std::make_unique<VisitState>(size());
318}
319
320void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
321 assert(State->NextState == nullptr && "Visited state is in list?");
322 State->NextState = std::move(FirstVisitState);
323 FirstVisitState = std::move(State);
324}
325
327 GlobalIndex = Index;
328 if (!GlobalIndex) {
329 ModulesInCommonWithGlobalIndex.clear();
330 return;
331 }
332
333 // Notify the global module index about all of the modules we've already
334 // loaded.
335 for (ModuleFile &M : *this)
336 if (!GlobalIndex->loadedModuleFile(&M))
337 ModulesInCommonWithGlobalIndex.push_back(&M);
338}
339
341 if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
342 return;
343
344 ModulesInCommonWithGlobalIndex.push_back(MF);
345}
346
348 const PCHContainerReader &PCHContainerRdr,
349 const HeaderSearch &HeaderSearchInfo)
350 : FileMgr(FileMgr), ModCache(ModCache), PCHContainerRdr(PCHContainerRdr),
351 HeaderSearchInfo(HeaderSearchInfo) {}
352
353void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
354 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
355 // If the visitation order vector is the wrong size, recompute the order.
356 if (VisitOrder.size() != Chain.size()) {
357 unsigned N = size();
358 VisitOrder.clear();
359 VisitOrder.reserve(N);
360
361 // Record the number of incoming edges for each module. When we
362 // encounter a module with no incoming edges, push it into the queue
363 // to seed the queue.
365 Queue.reserve(N);
366 llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
367 UnusedIncomingEdges.resize(size());
368 for (ModuleFile &M : llvm::reverse(*this)) {
369 unsigned Size = M.ImportedBy.size();
370 UnusedIncomingEdges[M.Index] = Size;
371 if (!Size)
372 Queue.push_back(&M);
373 }
374
375 // Traverse the graph, making sure to visit a module before visiting any
376 // of its dependencies.
377 while (!Queue.empty()) {
378 ModuleFile *CurrentModule = Queue.pop_back_val();
379 VisitOrder.push_back(CurrentModule);
380
381 // For any module that this module depends on, push it on the
382 // stack (if it hasn't already been marked as visited).
383 for (ModuleFile *M : llvm::reverse(CurrentModule->Imports)) {
384 // Remove our current module as an impediment to visiting the
385 // module we depend on. If we were the last unvisited module
386 // that depends on this particular module, push it into the
387 // queue to be visited.
388 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->Index];
389 if (NumUnusedEdges && (--NumUnusedEdges == 0))
390 Queue.push_back(M);
391 }
392 }
393
394 assert(VisitOrder.size() == N && "Visitation order is wrong?");
395
396 FirstVisitState = nullptr;
397 }
398
399 auto State = allocateVisitState();
400 unsigned VisitNumber = State->NextVisitNumber++;
401
402 // If the caller has provided us with a hit-set that came from the global
403 // module index, mark every module file in common with the global module
404 // index that is *not* in that set as 'visited'.
405 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
406 for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
407 {
408 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
409 if (!ModuleFilesHit->count(M))
410 State->VisitNumber[M->Index] = VisitNumber;
411 }
412 }
413
414 for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
415 ModuleFile *CurrentModule = VisitOrder[I];
416 // Should we skip this module file?
417 if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
418 continue;
419
420 // Visit the module.
421 assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
422 State->VisitNumber[CurrentModule->Index] = VisitNumber;
423 if (!Visitor(*CurrentModule))
424 continue;
425
426 // The visitor has requested that cut off visitation of any
427 // module that the current module depends on. To indicate this
428 // behavior, we mark all of the reachable modules as having been visited.
429 ModuleFile *NextModule = CurrentModule;
430 do {
431 // For any module that this module depends on, push it on the
432 // stack (if it hasn't already been marked as visited).
433 for (llvm::SetVector<ModuleFile *>::iterator
434 M = NextModule->Imports.begin(),
435 MEnd = NextModule->Imports.end();
436 M != MEnd; ++M) {
437 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
438 State->Stack.push_back(*M);
439 State->VisitNumber[(*M)->Index] = VisitNumber;
440 }
441 }
442
443 if (State->Stack.empty())
444 break;
445
446 // Pop the next module off the stack.
447 NextModule = State->Stack.pop_back_val();
448 } while (true);
449 }
450
451 returnVisitState(std::move(State));
452}
453
454#ifndef NDEBUG
455namespace llvm {
456
457 template<>
458 struct GraphTraits<ModuleManager> {
460 using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
461 using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
462
464 return Node->Imports.begin();
465 }
466
468 return Node->Imports.end();
469 }
470
471 static nodes_iterator nodes_begin(const ModuleManager &Manager) {
472 return nodes_iterator(Manager.begin());
473 }
474
475 static nodes_iterator nodes_end(const ModuleManager &Manager) {
476 return nodes_iterator(Manager.end());
477 }
478 };
479
480 template<>
482 explicit DOTGraphTraits(bool IsSimple = false)
483 : DefaultDOTGraphTraits(IsSimple) {}
484
485 static bool renderGraphFromBottomUp() { return true; }
486
487 std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
488 return M->ModuleName;
489 }
490 };
491
492} // namespace llvm
493
495 llvm::ViewGraph(*this, "Modules");
496}
497#endif
Defines the clang::FileManager interface and associated types.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static bool checkSignature(ASTFileSignature Signature, ASTFileSignature ExpectedSignature, std::string &ErrorStr)
static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, SourceLocation ImportLoc)
static bool checkModuleFile(off_t Size, time_t ModTime, off_t ExpectedSize, time_t ExpectedModTime, std::string &ErrorStr)
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition FileEntry.h:57
time_t getModificationTime() const
Definition FileEntry.h:354
off_t getSize() const
Definition FileEntry.h:346
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 & addBuiltPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Store a just-built PCM under the Filename.
llvm::MemoryBuffer & addPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Store the PCM under the Filename.
The module cache used for compiling modules implicitly.
Definition ModuleCache.h:25
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
Information about a module that has been loaded by the ASTReader.
Definition ModuleFile.h:145
bool DirectlyImported
Whether this module has been directly imported by the user.
Definition ModuleFile.h:224
llvm::SetVector< ModuleFile * > ImportedBy
List of modules which depend on this module.
Definition ModuleFile.h:520
SourceLocation ImportLoc
The source location where this module was first imported.
Definition ModuleFile.h:260
unsigned Index
The index of this module in the list of modules.
Definition ModuleFile.h:154
llvm::SetVector< ModuleFile * > Imports
List of modules which this module directly imported.
Definition ModuleFile.h:523
ModuleKind Kind
The type of this module.
Definition ModuleFile.h:157
std::string ModuleName
The name of the module.
Definition ModuleFile.h:166
Manages the set of modules loaded by an AST reader.
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
AddModuleResult
The result of attempting to add a new module.
@ Missing
The module file is missing.
@ OutOfDate
The module file is out-of-date.
@ NewlyLoaded
The module file was just loaded in response to this call.
@ AlreadyLoaded
The module file had already been loaded.
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.
std::unique_ptr< llvm::MemoryBuffer > lookupBuffer(StringRef Name)
Returns the in-memory (virtual file) buffer with the given name.
void addInMemoryBuffer(StringRef FileName, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Add an in-memory buffer the list of known buffers.
AddModuleResult addModule(ModuleFileName FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, ASTFileSignatureReader ReadSignature, ModuleFile *&Module, std::string &ErrorStr)
Attempts to create a new module and add it to the list of known modules.
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.
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h:43
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition ModuleFile.h:48
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition ModuleFile.h:45
@ MK_PrebuiltModule
File is from a prebuilt module path.
Definition ModuleFile.h:60
The JSON file list parser is used to communicate input to InstallAPI.
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:208
@ 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)