blob: a9fe64d42bdba3ba602cbcb818c5abde67a0b40e [file] [log] [blame]
Douglas Gregor98339b92011-08-25 20:47:51 +00001//===--- 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
19using namespace clang;
20using namespace serialization;
21
22Module *ModuleManager::lookup(StringRef Name) {
23 const FileEntry *Entry = FileMgr.getFile(Name);
24 return Modules[Entry];
25}
26
27llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
28 const FileEntry *Entry = FileMgr.getFile(Name);
29 return InMemoryBuffers[Entry];
30}
31
32std::pair<Module *, bool>
33ModuleManager::addModule(StringRef FileName, ModuleKind Type,
34 Module *ImportedBy, std::string &ErrorStr) {
35 const FileEntry *Entry = FileMgr.getFile(FileName);
36 if (!Entry && FileName != "-") {
37 ErrorStr = "file not found";
38 return std::make_pair(static_cast<Module*>(0), false);
39 }
40
41 // Check whether we already loaded this module, before
42 Module *&ModuleEntry = Modules[Entry];
43 bool NewModule = false;
44 if (!ModuleEntry) {
45 // Allocate a new module.
46 Module *New = new Module(Type);
47 New->FileName = FileName.str();
48 Chain.push_back(New);
49 NewModule = true;
50 ModuleEntry = New;
51
52 // Load the contents of the module
53 if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
54 // The buffer was already provided for us.
55 assert(Buffer && "Passed null buffer");
56 New->Buffer.reset(Buffer);
57 } else {
58 // Open the AST file.
59 llvm::error_code ec;
60 if (FileName == "-") {
61 ec = llvm::MemoryBuffer::getSTDIN(New->Buffer);
62 if (ec)
63 ErrorStr = ec.message();
64 } else
65 New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
66
67 if (!New->Buffer)
68 return std::make_pair(static_cast<Module*>(0), false);
69 }
70
71 // Initialize the stream
72 New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
73 (const unsigned char *)New->Buffer->getBufferEnd()); }
74
75 if (ImportedBy) {
76 ModuleEntry->ImportedBy.insert(ImportedBy);
77 ImportedBy->Imports.insert(ModuleEntry);
78 } else {
79 ModuleEntry->DirectlyImported = true;
80 }
81
82 return std::make_pair(ModuleEntry, NewModule);
83}
84
85void ModuleManager::addInMemoryBuffer(StringRef FileName,
86 llvm::MemoryBuffer *Buffer) {
87
88 const FileEntry *Entry = FileMgr.getVirtualFile(FileName,
89 Buffer->getBufferSize(), 0);
90 InMemoryBuffers[Entry] = Buffer;
91}
92
93ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { }
94
95ModuleManager::~ModuleManager() {
96 for (unsigned i = 0, e = Chain.size(); i != e; ++i)
97 delete Chain[e - i - 1];
98}
99
100void ModuleManager::visit(bool (*Visitor)(Module &M, void *UserData),
101 void *UserData) {
102 unsigned N = size();
103
104 // Record the number of incoming edges for each module. When we
105 // encounter a module with no incoming edges, push it into the queue
106 // to seed the queue.
107 SmallVector<Module *, 4> Queue;
108 Queue.reserve(N);
109 llvm::DenseMap<Module *, unsigned> UnusedIncomingEdges;
110 for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
111 if (unsigned Size = (*M)->ImportedBy.size())
112 UnusedIncomingEdges[*M] = Size;
113 else
114 Queue.push_back(*M);
115 }
116
117 llvm::SmallPtrSet<Module *, 4> Skipped;
118 unsigned QueueStart = 0;
119 while (QueueStart < Queue.size()) {
120 Module *CurrentModule = Queue[QueueStart++];
121
122 // Check whether this module should be skipped.
123 if (Skipped.count(CurrentModule))
124 continue;
125
126 if (Visitor(*CurrentModule, UserData)) {
127 // The visitor has requested that cut off visitation of any
128 // module that the current module depends on. To indicate this
129 // behavior, we mark all of the reachable modules as having N
130 // incoming edges (which is impossible otherwise).
131 SmallVector<Module *, 4> Stack;
132 Stack.push_back(CurrentModule);
133 Skipped.insert(CurrentModule);
134 while (!Stack.empty()) {
135 Module *NextModule = Stack.back();
136 Stack.pop_back();
137
138 // For any module that this module depends on, push it on the
139 // stack (if it hasn't already been marked as visited).
140 for (llvm::SetVector<Module *>::iterator
141 M = NextModule->Imports.begin(),
142 MEnd = NextModule->Imports.end();
143 M != MEnd; ++M) {
144 if (Skipped.insert(*M))
145 Stack.push_back(*M);
146 }
147 }
148 continue;
149 }
150
151 // For any module that this module depends on, push it on the
152 // stack (if it hasn't already been marked as visited).
153 for (llvm::SetVector<Module *>::iterator M = CurrentModule->Imports.begin(),
154 MEnd = CurrentModule->Imports.end();
155 M != MEnd; ++M) {
156
157 // Remove our current module as an impediment to visiting the
158 // module we depend on. If we were the last unvisited module
159 // that depends on this particular module, push it into the
160 // queue to be visited.
161 unsigned &NumUnusedEdges = UnusedIncomingEdges[*M];
162 if (NumUnusedEdges && (--NumUnusedEdges == 0))
163 Queue.push_back(*M);
164 }
165 }
166}
167
168/// \brief Perform a depth-first visit of the current module.
169static bool visitDepthFirst(Module &M,
170 bool (*Visitor)(Module &M, bool Preorder,
171 void *UserData),
172 void *UserData,
173 llvm::SmallPtrSet<Module *, 4> &Visited) {
174 // Preorder visitation
175 if (Visitor(M, /*Preorder=*/true, UserData))
176 return true;
177
178 // Visit children
179 for (llvm::SetVector<Module *>::iterator IM = M.Imports.begin(),
180 IMEnd = M.Imports.end();
181 IM != IMEnd; ++IM) {
182 if (!Visited.insert(*IM))
183 continue;
184
185 if (visitDepthFirst(**IM, Visitor, UserData, Visited))
186 return true;
187 }
188
189 // Postorder visitation
190 return Visitor(M, /*Preorder=*/false, UserData);
191}
192
193void ModuleManager::visitDepthFirst(bool (*Visitor)(Module &M, bool Preorder,
194 void *UserData),
195 void *UserData) {
196 llvm::SmallPtrSet<Module *, 4> Visited;
197 for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
198 if (!Visited.insert(Chain[I]))
199 continue;
200
201 if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
202 return;
203 }
204}