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