]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / tools / clang / lib / Serialization / ModuleManager.cpp
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 "llvm/Support/MemoryBuffer.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "llvm/Support/system_error.h"
18
19 #ifndef NDEBUG
20 #include "llvm/Support/GraphWriter.h"
21 #endif
22
23 using namespace clang;
24 using namespace serialization;
25
26 Module *ModuleManager::lookup(StringRef Name) {
27   const FileEntry *Entry = FileMgr.getFile(Name);
28   return Modules[Entry];
29 }
30
31 llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
32   const FileEntry *Entry = FileMgr.getFile(Name);
33   return InMemoryBuffers[Entry];
34 }
35
36 std::pair<Module *, bool>
37 ModuleManager::addModule(StringRef FileName, ModuleKind Type, 
38                          Module *ImportedBy, std::string &ErrorStr) {
39   const FileEntry *Entry = FileMgr.getFile(FileName);
40   if (!Entry && FileName != "-") {
41     ErrorStr = "file not found";
42     return std::make_pair(static_cast<Module*>(0), false);
43   }
44   
45   // Check whether we already loaded this module, before 
46   Module *&ModuleEntry = Modules[Entry];
47   bool NewModule = false;
48   if (!ModuleEntry) {
49     // Allocate a new module.
50     Module *New = new Module(Type);
51     New->FileName = FileName.str();
52     Chain.push_back(New);
53     NewModule = true;
54     ModuleEntry = New;
55     
56     // Load the contents of the module
57     if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
58       // The buffer was already provided for us.
59       assert(Buffer && "Passed null buffer");
60       New->Buffer.reset(Buffer);
61     } else {
62       // Open the AST file.
63       llvm::error_code ec;
64       if (FileName == "-") {
65         ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
66         if (ec)
67           ErrorStr = ec.message();
68       } else
69         New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
70       
71       if (!New->Buffer)
72         return std::make_pair(static_cast<Module*>(0), false);
73     }
74     
75     // Initialize the stream
76     New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
77                          (const unsigned char *)New->Buffer->getBufferEnd());     }
78   
79   if (ImportedBy) {
80     ModuleEntry->ImportedBy.insert(ImportedBy);
81     ImportedBy->Imports.insert(ModuleEntry);
82   } else {
83     ModuleEntry->DirectlyImported = true;
84   }
85   
86   return std::make_pair(ModuleEntry, NewModule);
87 }
88
89 void ModuleManager::addInMemoryBuffer(StringRef FileName, 
90                                       llvm::MemoryBuffer *Buffer) {
91   
92   const FileEntry *Entry = FileMgr.getVirtualFile(FileName, 
93                                                   Buffer->getBufferSize(), 0);
94   InMemoryBuffers[Entry] = Buffer;
95 }
96
97 ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { }
98
99 ModuleManager::~ModuleManager() {
100   for (unsigned i = 0, e = Chain.size(); i != e; ++i)
101     delete Chain[e - i - 1];
102 }
103
104 void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData), 
105                           void *UserData) {
106   unsigned N = size();
107   
108   // Record the number of incoming edges for each module. When we
109   // encounter a module with no incoming edges, push it into the queue
110   // to seed the queue.
111   SmallVector<Module *, 4> Queue;
112   Queue.reserve(N);
113   llvm::DenseMap<Module *, unsigned> UnusedIncomingEdges; 
114   for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
115     if (unsigned Size = (*M)->ImportedBy.size())
116       UnusedIncomingEdges[*M] = Size;
117     else
118       Queue.push_back(*M);
119   }
120   
121   llvm::SmallPtrSet<Module *, 4> Skipped;
122   unsigned QueueStart = 0;
123   while (QueueStart < Queue.size()) {
124     Module *CurrentModule = Queue[QueueStart++];
125     
126     // Check whether this module should be skipped.
127     if (Skipped.count(CurrentModule))
128       continue;
129     
130     if (Visitor(*CurrentModule, UserData)) {
131       // The visitor has requested that cut off visitation of any
132       // module that the current module depends on. To indicate this
133       // behavior, we mark all of the reachable modules as having N
134       // incoming edges (which is impossible otherwise).
135       SmallVector<Module *, 4> Stack;
136       Stack.push_back(CurrentModule);
137       Skipped.insert(CurrentModule);
138       while (!Stack.empty()) {
139         Module *NextModule = Stack.back();
140         Stack.pop_back();
141         
142         // For any module that this module depends on, push it on the
143         // stack (if it hasn't already been marked as visited).
144         for (llvm::SetVector<Module *>::iterator 
145              M = NextModule->Imports.begin(),
146              MEnd = NextModule->Imports.end();
147              M != MEnd; ++M) {
148           if (Skipped.insert(*M))
149             Stack.push_back(*M);
150         }
151       }
152       continue;
153     }
154     
155     // For any module that this module depends on, push it on the
156     // stack (if it hasn't already been marked as visited).
157     for (llvm::SetVector<Module *>::iterator M = CurrentModule->Imports.begin(),
158          MEnd = CurrentModule->Imports.end();
159          M != MEnd; ++M) {
160       
161       // Remove our current module as an impediment to visiting the
162       // module we depend on. If we were the last unvisited module
163       // that depends on this particular module, push it into the
164       // queue to be visited.
165       unsigned &NumUnusedEdges = UnusedIncomingEdges[*M];
166       if (NumUnusedEdges && (--NumUnusedEdges == 0))
167         Queue.push_back(*M);
168     }
169   }
170 }
171
172 /// \brief Perform a depth-first visit of the current module.
173 static bool visitDepthFirst(Module &M, 
174                             bool (*Visitor)(Module &M, bool Preorder, 
175                                             void *UserData), 
176                             void *UserData,
177                             llvm::SmallPtrSet<Module *, 4> &Visited) {
178   // Preorder visitation
179   if (Visitor(M, /*Preorder=*/true, UserData))
180     return true;
181   
182   // Visit children
183   for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(),
184        IMEnd = M.Imports.end();
185        IM != IMEnd; ++IM) {
186     if (!Visited.insert(*IM))
187       continue;
188     
189     if (visitDepthFirst(**IM, Visitor, UserData, Visited))
190       return true;
191   }  
192   
193   // Postorder visitation
194   return Visitor(M, /*Preorder=*/false, UserData);
195 }
196
197 void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder, 
198                                                     void *UserData), 
199                                     void *UserData) {
200   llvm::SmallPtrSet<Module *, 4> Visited;
201   for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
202     if (!Visited.insert(Chain[I]))
203       continue;
204     
205     if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
206       return;
207   }
208 }
209
210 #ifndef NDEBUG
211 namespace llvm {
212   template<>
213   struct GraphTraits<ModuleManager> {
214     typedef Module NodeType;
215     typedef llvm::SetVector<Module *>::const_iterator ChildIteratorType;
216     typedef ModuleManager::ModuleConstIterator nodes_iterator;
217     
218     static ChildIteratorType child_begin(NodeType *Node) {
219       return Node->Imports.begin();
220     }
221
222     static ChildIteratorType child_end(NodeType *Node) {
223       return Node->Imports.end();
224     }
225     
226     static nodes_iterator nodes_begin(const ModuleManager &Manager) {
227       return Manager.begin();
228     }
229     
230     static nodes_iterator nodes_end(const ModuleManager &Manager) {
231       return Manager.end();
232     }
233   };
234   
235   template<>
236   struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
237     explicit DOTGraphTraits(bool IsSimple = false)
238       : DefaultDOTGraphTraits(IsSimple) { }
239     
240     static bool renderGraphFromBottomUp() {
241       return true;
242     }
243
244     std::string getNodeLabel(Module *M, const ModuleManager&) {
245       return llvm::sys::path::stem(M->FileName);
246     }
247   };
248 }
249
250 void ModuleManager::viewGraph() {
251   llvm::ViewGraph(*this, "Modules");
252 }
253 #endif