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