xref: /llvm-project/clang/lib/Serialization/ModuleManager.cpp (revision 7029ce1a0ce6bb88bebeb182376641d2c4a70bb0)
1 //===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines the ModuleManager class, which manages a set of loaded
11 //  modules for the ASTReader.
12 //
13 //===----------------------------------------------------------------------===//
14 #include "clang/Lex/ModuleMap.h"
15 #include "clang/Serialization/ModuleManager.h"
16 #include "clang/Serialization/GlobalModuleIndex.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Support/PathV2.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/Support/system_error.h"
21 
22 #ifndef NDEBUG
23 #include "llvm/Support/GraphWriter.h"
24 #endif
25 
26 using namespace clang;
27 using namespace serialization;
28 
29 ModuleFile *ModuleManager::lookup(StringRef Name) {
30   const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
31                                            /*cacheFailure=*/false);
32   return Modules[Entry];
33 }
34 
35 llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
36   const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
37                                            /*cacheFailure=*/false);
38   return InMemoryBuffers[Entry];
39 }
40 
41 ModuleManager::AddModuleResult
42 ModuleManager::addModule(StringRef FileName, ModuleKind Type,
43                          SourceLocation ImportLoc, ModuleFile *ImportedBy,
44                          unsigned Generation,
45                          off_t ExpectedSize, time_t ExpectedModTime,
46                          ModuleFile *&Module,
47                          std::string &ErrorStr) {
48   Module = 0;
49 
50   // Look for the file entry. This only fails if the expected size or
51   // modification time differ.
52   const FileEntry *Entry;
53   if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry))
54     return OutOfDate;
55 
56   if (!Entry && FileName != "-") {
57     ErrorStr = "file not found";
58     return Missing;
59   }
60 
61   // Check whether we already loaded this module, before
62   AddModuleResult Result = AlreadyLoaded;
63   ModuleFile *&ModuleEntry = Modules[Entry];
64   bool NewModule = false;
65   if (!ModuleEntry) {
66     // Allocate a new module.
67     ModuleFile *New = new ModuleFile(Type, Generation);
68     New->Index = Chain.size();
69     New->FileName = FileName.str();
70     New->File = Entry;
71     New->ImportLoc = ImportLoc;
72     Chain.push_back(New);
73     NewModule = true;
74     ModuleEntry = New;
75 
76     // Load the contents of the module
77     if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
78       // The buffer was already provided for us.
79       assert(Buffer && "Passed null buffer");
80       New->Buffer.reset(Buffer);
81     } else {
82       // Open the AST file.
83       llvm::error_code ec;
84       if (FileName == "-") {
85         ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
86         if (ec)
87           ErrorStr = ec.message();
88       } else
89         New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
90 
91       if (!New->Buffer)
92         return Missing;
93     }
94 
95     // Initialize the stream
96     New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
97                          (const unsigned char *)New->Buffer->getBufferEnd());
98 
99     Result = NewlyLoaded;
100   }
101 
102   if (ImportedBy) {
103     ModuleEntry->ImportedBy.insert(ImportedBy);
104     ImportedBy->Imports.insert(ModuleEntry);
105   } else {
106     if (!ModuleEntry->DirectlyImported)
107       ModuleEntry->ImportLoc = ImportLoc;
108 
109     ModuleEntry->DirectlyImported = true;
110   }
111 
112   Module = ModuleEntry;
113   return NewModule? NewlyLoaded : AlreadyLoaded;
114 }
115 
116 namespace {
117   /// \brief Predicate that checks whether a module file occurs within
118   /// the given set.
119   class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> {
120     llvm::SmallPtrSet<ModuleFile *, 4> &Removed;
121 
122   public:
123     IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed)
124     : Removed(Removed) { }
125 
126     bool operator()(ModuleFile *MF) const {
127       return Removed.count(MF);
128     }
129   };
130 }
131 
132 void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
133                                   ModuleMap *modMap) {
134   if (first == last)
135     return;
136 
137   // Collect the set of module file pointers that we'll be removing.
138   llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
139 
140   // Remove any references to the now-destroyed modules.
141   IsInModuleFileSet checkInSet(victimSet);
142   for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
143     Chain[i]->ImportedBy.remove_if(checkInSet);
144   }
145 
146   // Delete the modules and erase them from the various structures.
147   for (ModuleIterator victim = first; victim != last; ++victim) {
148     Modules.erase((*victim)->File);
149 
150     FileMgr.invalidateCache((*victim)->File);
151     if (modMap) {
152       StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName);
153       if (Module *mod = modMap->findModule(ModuleName)) {
154         mod->setASTFile(0);
155       }
156     }
157     delete *victim;
158   }
159 
160   // Remove the modules from the chain.
161   Chain.erase(first, last);
162 }
163 
164 void ModuleManager::addInMemoryBuffer(StringRef FileName,
165                                       llvm::MemoryBuffer *Buffer) {
166 
167   const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
168                                                   Buffer->getBufferSize(), 0);
169   InMemoryBuffers[Entry] = Buffer;
170 }
171 
172 void ModuleManager::updateModulesInCommonWithGlobalIndex() {
173   ModulesInCommonWithGlobalIndex.clear();
174 
175   if (!GlobalIndex)
176     return;
177 
178   // Collect the set of modules known to the global index.
179   GlobalIndex->noteAdditionalModulesLoaded();
180   GlobalIndex->getKnownModules(ModulesInCommonWithGlobalIndex);
181 }
182 
183 ModuleManager::VisitState *ModuleManager::allocateVisitState() {
184   // Fast path: if we have a cached state, use it.
185   if (FirstVisitState) {
186     VisitState *Result = FirstVisitState;
187     FirstVisitState = FirstVisitState->NextState;
188     Result->NextState = 0;
189     return Result;
190   }
191 
192   // Allocate and return a new state.
193   return new VisitState(size());
194 }
195 
196 void ModuleManager::returnVisitState(VisitState *State) {
197   assert(State->NextState == 0 && "Visited state is in list?");
198   State->NextState = FirstVisitState;
199   FirstVisitState = State;
200 }
201 
202 void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
203   GlobalIndex = Index;
204   if (GlobalIndex) {
205     GlobalIndex->setResolver(this);
206   }
207   updateModulesInCommonWithGlobalIndex();
208 }
209 
210 ModuleManager::ModuleManager(FileManager &FileMgr)
211   : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { }
212 
213 ModuleManager::~ModuleManager() {
214   for (unsigned i = 0, e = Chain.size(); i != e; ++i)
215     delete Chain[e - i - 1];
216   delete FirstVisitState;
217 }
218 
219 void
220 ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
221                      void *UserData,
222                      llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) {
223   // If the visitation order vector is the wrong size, recompute the order.
224   if (VisitOrder.size() != Chain.size()) {
225     unsigned N = size();
226     VisitOrder.clear();
227     VisitOrder.reserve(N);
228 
229     // Record the number of incoming edges for each module. When we
230     // encounter a module with no incoming edges, push it into the queue
231     // to seed the queue.
232     SmallVector<ModuleFile *, 4> Queue;
233     Queue.reserve(N);
234     llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
235     UnusedIncomingEdges.reserve(size());
236     for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
237       if (unsigned Size = (*M)->ImportedBy.size())
238         UnusedIncomingEdges.push_back(Size);
239       else {
240         UnusedIncomingEdges.push_back(0);
241         Queue.push_back(*M);
242       }
243     }
244 
245     // Traverse the graph, making sure to visit a module before visiting any
246     // of its dependencies.
247     unsigned QueueStart = 0;
248     while (QueueStart < Queue.size()) {
249       ModuleFile *CurrentModule = Queue[QueueStart++];
250       VisitOrder.push_back(CurrentModule);
251 
252       // For any module that this module depends on, push it on the
253       // stack (if it hasn't already been marked as visited).
254       for (llvm::SetVector<ModuleFile *>::iterator
255              M = CurrentModule->Imports.begin(),
256              MEnd = CurrentModule->Imports.end();
257            M != MEnd; ++M) {
258         // Remove our current module as an impediment to visiting the
259         // module we depend on. If we were the last unvisited module
260         // that depends on this particular module, push it into the
261         // queue to be visited.
262         unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
263         if (NumUnusedEdges && (--NumUnusedEdges == 0))
264           Queue.push_back(*M);
265       }
266     }
267 
268     assert(VisitOrder.size() == N && "Visitation order is wrong?");
269 
270     // We may need to update the set of modules we have in common with the
271     // global module index, since modules could have been added to the module
272     // manager since we loaded the global module index.
273     updateModulesInCommonWithGlobalIndex();
274 
275     delete FirstVisitState;
276     FirstVisitState = 0;
277   }
278 
279   VisitState *State = allocateVisitState();
280   unsigned VisitNumber = State->NextVisitNumber++;
281 
282   // If the caller has provided us with a hit-set that came from the global
283   // module index, mark every module file in common with the global module
284   // index that is *not* in that set as 'visited'.
285   if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
286     for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
287     {
288       ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
289       if (!ModuleFilesHit->count(M))
290         State->VisitNumber[M->Index] = VisitNumber;
291     }
292   }
293 
294   for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
295     ModuleFile *CurrentModule = VisitOrder[I];
296     // Should we skip this module file?
297     if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
298       continue;
299 
300     // Visit the module.
301     assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
302     State->VisitNumber[CurrentModule->Index] = VisitNumber;
303     if (!Visitor(*CurrentModule, UserData))
304       continue;
305 
306     // The visitor has requested that cut off visitation of any
307     // module that the current module depends on. To indicate this
308     // behavior, we mark all of the reachable modules as having been visited.
309     ModuleFile *NextModule = CurrentModule;
310     do {
311       // For any module that this module depends on, push it on the
312       // stack (if it hasn't already been marked as visited).
313       for (llvm::SetVector<ModuleFile *>::iterator
314              M = NextModule->Imports.begin(),
315              MEnd = NextModule->Imports.end();
316            M != MEnd; ++M) {
317         if (State->VisitNumber[(*M)->Index] != VisitNumber) {
318           State->Stack.push_back(*M);
319           State->VisitNumber[(*M)->Index] = VisitNumber;
320         }
321       }
322 
323       if (State->Stack.empty())
324         break;
325 
326       // Pop the next module off the stack.
327       NextModule = State->Stack.back();
328       State->Stack.pop_back();
329     } while (true);
330   }
331 
332   returnVisitState(State);
333 }
334 
335 /// \brief Perform a depth-first visit of the current module.
336 static bool visitDepthFirst(ModuleFile &M,
337                             bool (*Visitor)(ModuleFile &M, bool Preorder,
338                                             void *UserData),
339                             void *UserData,
340                             SmallVectorImpl<bool> &Visited) {
341   // Preorder visitation
342   if (Visitor(M, /*Preorder=*/true, UserData))
343     return true;
344 
345   // Visit children
346   for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
347                                             IMEnd = M.Imports.end();
348        IM != IMEnd; ++IM) {
349     if (Visited[(*IM)->Index])
350       continue;
351     Visited[(*IM)->Index] = true;
352 
353     if (visitDepthFirst(**IM, Visitor, UserData, Visited))
354       return true;
355   }
356 
357   // Postorder visitation
358   return Visitor(M, /*Preorder=*/false, UserData);
359 }
360 
361 void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
362                                                     void *UserData),
363                                     void *UserData) {
364   SmallVector<bool, 16> Visited(size(), false);
365   for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
366     if (Visited[Chain[I]->Index])
367       continue;
368     Visited[Chain[I]->Index] = true;
369 
370     if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
371       return;
372   }
373 }
374 
375 bool ModuleManager::lookupModuleFile(StringRef FileName,
376                                      off_t ExpectedSize,
377                                      time_t ExpectedModTime,
378                                      const FileEntry *&File) {
379   File = FileMgr.getFile(FileName, /*openFile=*/false, /*cacheFailure=*/false);
380 
381   if (!File && FileName != "-") {
382     return false;
383   }
384 
385   if ((ExpectedSize && ExpectedSize != File->getSize()) ||
386       (ExpectedModTime && ExpectedModTime != File->getModificationTime())) {
387     return true;
388   }
389 
390   return false;
391 }
392 
393 bool ModuleManager::resolveModuleFileName(StringRef FileName,
394                                           off_t ExpectedSize,
395                                           time_t ExpectedModTime,
396                                           ModuleFile *&File) {
397   File = 0;
398 
399   // Look for the file entry corresponding to this name.
400   const FileEntry *F;
401   if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, F))
402     return true;
403 
404   // If there is no file, we've succeeded (trivially).
405   if (!F)
406     return false;
407 
408   // Determine whether we have a module file associated with this file entry.
409   llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
410     = Modules.find(F);
411   if (Known == Modules.end()) {
412     // We don't know about this module file; invalidate the cache.
413     FileMgr.invalidateCache(F);
414     return false;
415   }
416 
417   File = Known->second;
418   return false;
419 }
420 
421 #ifndef NDEBUG
422 namespace llvm {
423   template<>
424   struct GraphTraits<ModuleManager> {
425     typedef ModuleFile NodeType;
426     typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
427     typedef ModuleManager::ModuleConstIterator nodes_iterator;
428 
429     static ChildIteratorType child_begin(NodeType *Node) {
430       return Node->Imports.begin();
431     }
432 
433     static ChildIteratorType child_end(NodeType *Node) {
434       return Node->Imports.end();
435     }
436 
437     static nodes_iterator nodes_begin(const ModuleManager &Manager) {
438       return Manager.begin();
439     }
440 
441     static nodes_iterator nodes_end(const ModuleManager &Manager) {
442       return Manager.end();
443     }
444   };
445 
446   template<>
447   struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
448     explicit DOTGraphTraits(bool IsSimple = false)
449       : DefaultDOTGraphTraits(IsSimple) { }
450 
451     static bool renderGraphFromBottomUp() {
452       return true;
453     }
454 
455     std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
456       return llvm::sys::path::stem(M->FileName);
457     }
458   };
459 }
460 
461 void ModuleManager::viewGraph() {
462   llvm::ViewGraph(*this, "Modules");
463 }
464 #endif
465