ModuleManager.cpp revision 226586
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
23using namespace clang;
24using namespace serialization;
25
26Module *ModuleManager::lookup(StringRef Name) {
27  const FileEntry *Entry = FileMgr.getFile(Name);
28  return Modules[Entry];
29}
30
31llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
32  const FileEntry *Entry = FileMgr.getFile(Name);
33  return InMemoryBuffers[Entry];
34}
35
36std::pair<Module *, bool>
37ModuleManager::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
89void 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
97ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { }
98
99ModuleManager::~ModuleManager() {
100  for (unsigned i = 0, e = Chain.size(); i != e; ++i)
101    delete Chain[e - i - 1];
102}
103
104void 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.
173static 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
197void 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
211namespace 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
250void ModuleManager::viewGraph() {
251  llvm::ViewGraph(*this, "Modules");
252}
253#endif
254