• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/Serialization/ModuleManager.h"
15 #include "clang/Serialization/GlobalModuleIndex.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "llvm/Support/system_error.h"
19 
20 #ifndef NDEBUG
21 #include "llvm/Support/GraphWriter.h"
22 #endif
23 
24 using namespace clang;
25 using namespace serialization;
26 
lookup(StringRef Name)27 ModuleFile *ModuleManager::lookup(StringRef Name) {
28   const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
29                                            /*cacheFailure=*/false);
30   return Modules[Entry];
31 }
32 
lookupBuffer(StringRef Name)33 llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
34   const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
35                                            /*cacheFailure=*/false);
36   return InMemoryBuffers[Entry];
37 }
38 
39 std::pair<ModuleFile *, bool>
addModule(StringRef FileName,ModuleKind Type,SourceLocation ImportLoc,ModuleFile * ImportedBy,unsigned Generation,std::string & ErrorStr)40 ModuleManager::addModule(StringRef FileName, ModuleKind Type,
41                          SourceLocation ImportLoc, ModuleFile *ImportedBy,
42                          unsigned Generation, std::string &ErrorStr) {
43   const FileEntry *Entry = FileMgr.getFile(FileName, /*openFile=*/false,
44                                            /*cacheFailure=*/false);
45   if (!Entry && FileName != "-") {
46     ErrorStr = "file not found";
47     return std::make_pair(static_cast<ModuleFile*>(0), false);
48   }
49 
50   // Check whether we already loaded this module, before
51   ModuleFile *&ModuleEntry = Modules[Entry];
52   bool NewModule = false;
53   if (!ModuleEntry) {
54     // Allocate a new module.
55     ModuleFile *New = new ModuleFile(Type, Generation);
56     New->Index = Chain.size();
57     New->FileName = FileName.str();
58     New->File = Entry;
59     New->ImportLoc = ImportLoc;
60     Chain.push_back(New);
61     NewModule = true;
62     ModuleEntry = New;
63 
64     // Load the contents of the module
65     if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
66       // The buffer was already provided for us.
67       assert(Buffer && "Passed null buffer");
68       New->Buffer.reset(Buffer);
69     } else {
70       // Open the AST file.
71       llvm::error_code ec;
72       if (FileName == "-") {
73         ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
74         if (ec)
75           ErrorStr = ec.message();
76       } else
77         New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
78 
79       if (!New->Buffer)
80         return std::make_pair(static_cast<ModuleFile*>(0), false);
81     }
82 
83     // Initialize the stream
84     New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
85                          (const unsigned char *)New->Buffer->getBufferEnd());     }
86 
87   if (ImportedBy) {
88     ModuleEntry->ImportedBy.insert(ImportedBy);
89     ImportedBy->Imports.insert(ModuleEntry);
90   } else {
91     if (!ModuleEntry->DirectlyImported)
92       ModuleEntry->ImportLoc = ImportLoc;
93 
94     ModuleEntry->DirectlyImported = true;
95   }
96 
97   return std::make_pair(ModuleEntry, NewModule);
98 }
99 
100 namespace {
101   /// \brief Predicate that checks whether a module file occurs within
102   /// the given set.
103   class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> {
104     llvm::SmallPtrSet<ModuleFile *, 4> &Removed;
105 
106   public:
IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *,4> & Removed)107     IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed)
108     : Removed(Removed) { }
109 
operator ()(ModuleFile * MF) const110     bool operator()(ModuleFile *MF) const {
111       return Removed.count(MF);
112     }
113   };
114 }
115 
removeModules(ModuleIterator first,ModuleIterator last)116 void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
117   if (first == last)
118     return;
119 
120   // Collect the set of module file pointers that we'll be removing.
121   llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
122 
123   // Remove any references to the now-destroyed modules.
124   IsInModuleFileSet checkInSet(victimSet);
125   for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
126     Chain[i]->ImportedBy.remove_if(checkInSet);
127   }
128 
129   // Delete the modules and erase them from the various structures.
130   for (ModuleIterator victim = first; victim != last; ++victim) {
131     Modules.erase((*victim)->File);
132     delete *victim;
133   }
134 
135   // Remove the modules from the chain.
136   Chain.erase(first, last);
137 }
138 
addInMemoryBuffer(StringRef FileName,llvm::MemoryBuffer * Buffer)139 void ModuleManager::addInMemoryBuffer(StringRef FileName,
140                                       llvm::MemoryBuffer *Buffer) {
141 
142   const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
143                                                   Buffer->getBufferSize(), 0);
144   InMemoryBuffers[Entry] = Buffer;
145 }
146 
updateModulesInCommonWithGlobalIndex()147 void ModuleManager::updateModulesInCommonWithGlobalIndex() {
148   ModulesInCommonWithGlobalIndex.clear();
149 
150   if (!GlobalIndex)
151     return;
152 
153   // Collect the set of modules known to the global index.
154   SmallVector<const FileEntry *, 16> KnownModules;
155   GlobalIndex->getKnownModules(KnownModules);
156 
157   // Map those modules to AST files known to the module manager.
158   for (unsigned I = 0, N = KnownModules.size(); I != N; ++I) {
159     llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
160       = Modules.find(KnownModules[I]);
161     if (Known == Modules.end())
162       continue;
163 
164     ModulesInCommonWithGlobalIndex.push_back(Known->second);
165   }
166 }
167 
allocateVisitState()168 ModuleManager::VisitState *ModuleManager::allocateVisitState() {
169   // Fast path: if we have a cached state, use it.
170   if (FirstVisitState) {
171     VisitState *Result = FirstVisitState;
172     FirstVisitState = FirstVisitState->NextState;
173     Result->NextState = 0;
174     return Result;
175   }
176 
177   // Allocate and return a new state.
178   return new VisitState(size());
179 }
180 
returnVisitState(VisitState * State)181 void ModuleManager::returnVisitState(VisitState *State) {
182   assert(State->NextState == 0 && "Visited state is in list?");
183   State->NextState = FirstVisitState;
184   FirstVisitState = State;
185 }
186 
setGlobalIndex(GlobalModuleIndex * Index)187 void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
188   GlobalIndex = Index;
189   updateModulesInCommonWithGlobalIndex();
190 }
191 
ModuleManager(FileManager & FileMgr)192 ModuleManager::ModuleManager(FileManager &FileMgr)
193   : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { }
194 
~ModuleManager()195 ModuleManager::~ModuleManager() {
196   for (unsigned i = 0, e = Chain.size(); i != e; ++i)
197     delete Chain[e - i - 1];
198   delete FirstVisitState;
199 }
200 
201 void
visit(bool (* Visitor)(ModuleFile & M,void * UserData),void * UserData,llvm::SmallPtrSet<const FileEntry *,4> * ModuleFilesHit)202 ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
203                      void *UserData,
204                      llvm::SmallPtrSet<const FileEntry *, 4> *ModuleFilesHit) {
205   // If the visitation order vector is the wrong size, recompute the order.
206   if (VisitOrder.size() != Chain.size()) {
207     unsigned N = size();
208     VisitOrder.clear();
209     VisitOrder.reserve(N);
210 
211     // Record the number of incoming edges for each module. When we
212     // encounter a module with no incoming edges, push it into the queue
213     // to seed the queue.
214     SmallVector<ModuleFile *, 4> Queue;
215     Queue.reserve(N);
216     llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
217     UnusedIncomingEdges.reserve(size());
218     for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
219       if (unsigned Size = (*M)->ImportedBy.size())
220         UnusedIncomingEdges.push_back(Size);
221       else {
222         UnusedIncomingEdges.push_back(0);
223         Queue.push_back(*M);
224       }
225     }
226 
227     // Traverse the graph, making sure to visit a module before visiting any
228     // of its dependencies.
229     unsigned QueueStart = 0;
230     while (QueueStart < Queue.size()) {
231       ModuleFile *CurrentModule = Queue[QueueStart++];
232       VisitOrder.push_back(CurrentModule);
233 
234       // For any module that this module depends on, push it on the
235       // stack (if it hasn't already been marked as visited).
236       for (llvm::SetVector<ModuleFile *>::iterator
237              M = CurrentModule->Imports.begin(),
238              MEnd = CurrentModule->Imports.end();
239            M != MEnd; ++M) {
240         // Remove our current module as an impediment to visiting the
241         // module we depend on. If we were the last unvisited module
242         // that depends on this particular module, push it into the
243         // queue to be visited.
244         unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
245         if (NumUnusedEdges && (--NumUnusedEdges == 0))
246           Queue.push_back(*M);
247       }
248     }
249 
250     assert(VisitOrder.size() == N && "Visitation order is wrong?");
251 
252     // We may need to update the set of modules we have in common with the
253     // global module index, since modules could have been added to the module
254     // manager since we loaded the global module index.
255     updateModulesInCommonWithGlobalIndex();
256 
257     delete FirstVisitState;
258     FirstVisitState = 0;
259   }
260 
261   VisitState *State = allocateVisitState();
262   unsigned VisitNumber = State->NextVisitNumber++;
263 
264   // If the caller has provided us with a hit-set that came from the global
265   // module index, mark every module file in common with the global module
266   // index that is *not* in that set as 'visited'.
267   if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
268     for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
269     {
270       ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
271       if (!ModuleFilesHit->count(M->File))
272         State->VisitNumber[M->Index] = VisitNumber;
273     }
274   }
275 
276   for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
277     ModuleFile *CurrentModule = VisitOrder[I];
278     // Should we skip this module file?
279     if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
280       continue;
281 
282     // Visit the module.
283     assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
284     State->VisitNumber[CurrentModule->Index] = VisitNumber;
285     if (!Visitor(*CurrentModule, UserData))
286       continue;
287 
288     // The visitor has requested that cut off visitation of any
289     // module that the current module depends on. To indicate this
290     // behavior, we mark all of the reachable modules as having been visited.
291     ModuleFile *NextModule = CurrentModule;
292     do {
293       // For any module that this module depends on, push it on the
294       // stack (if it hasn't already been marked as visited).
295       for (llvm::SetVector<ModuleFile *>::iterator
296              M = NextModule->Imports.begin(),
297              MEnd = NextModule->Imports.end();
298            M != MEnd; ++M) {
299         if (State->VisitNumber[(*M)->Index] != VisitNumber) {
300           State->Stack.push_back(*M);
301           State->VisitNumber[(*M)->Index] = VisitNumber;
302         }
303       }
304 
305       if (State->Stack.empty())
306         break;
307 
308       // Pop the next module off the stack.
309       NextModule = State->Stack.back();
310       State->Stack.pop_back();
311     } while (true);
312   }
313 
314   returnVisitState(State);
315 }
316 
317 /// \brief Perform a depth-first visit of the current module.
visitDepthFirst(ModuleFile & M,bool (* Visitor)(ModuleFile & M,bool Preorder,void * UserData),void * UserData,SmallVectorImpl<bool> & Visited)318 static bool visitDepthFirst(ModuleFile &M,
319                             bool (*Visitor)(ModuleFile &M, bool Preorder,
320                                             void *UserData),
321                             void *UserData,
322                             SmallVectorImpl<bool> &Visited) {
323   // Preorder visitation
324   if (Visitor(M, /*Preorder=*/true, UserData))
325     return true;
326 
327   // Visit children
328   for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
329                                             IMEnd = M.Imports.end();
330        IM != IMEnd; ++IM) {
331     if (Visited[(*IM)->Index])
332       continue;
333     Visited[(*IM)->Index] = true;
334 
335     if (visitDepthFirst(**IM, Visitor, UserData, Visited))
336       return true;
337   }
338 
339   // Postorder visitation
340   return Visitor(M, /*Preorder=*/false, UserData);
341 }
342 
visitDepthFirst(bool (* Visitor)(ModuleFile & M,bool Preorder,void * UserData),void * UserData)343 void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
344                                                     void *UserData),
345                                     void *UserData) {
346   SmallVector<bool, 16> Visited(size(), false);
347   for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
348     if (Visited[Chain[I]->Index])
349       continue;
350     Visited[Chain[I]->Index] = true;
351 
352     if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
353       return;
354   }
355 }
356 
357 #ifndef NDEBUG
358 namespace llvm {
359   template<>
360   struct GraphTraits<ModuleManager> {
361     typedef ModuleFile NodeType;
362     typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType;
363     typedef ModuleManager::ModuleConstIterator nodes_iterator;
364 
child_beginllvm::GraphTraits365     static ChildIteratorType child_begin(NodeType *Node) {
366       return Node->Imports.begin();
367     }
368 
child_endllvm::GraphTraits369     static ChildIteratorType child_end(NodeType *Node) {
370       return Node->Imports.end();
371     }
372 
nodes_beginllvm::GraphTraits373     static nodes_iterator nodes_begin(const ModuleManager &Manager) {
374       return Manager.begin();
375     }
376 
nodes_endllvm::GraphTraits377     static nodes_iterator nodes_end(const ModuleManager &Manager) {
378       return Manager.end();
379     }
380   };
381 
382   template<>
383   struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits384     explicit DOTGraphTraits(bool IsSimple = false)
385       : DefaultDOTGraphTraits(IsSimple) { }
386 
renderGraphFromBottomUpllvm::DOTGraphTraits387     static bool renderGraphFromBottomUp() {
388       return true;
389     }
390 
getNodeLabelllvm::DOTGraphTraits391     std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
392       return llvm::sys::path::stem(M->FileName);
393     }
394   };
395 }
396 
viewGraph()397 void ModuleManager::viewGraph() {
398   llvm::ViewGraph(*this, "Modules");
399 }
400 #endif
401