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