ModuleManager.cpp revision 2492c89882b5c5ce03afb4704fee67b7eff8f5ee
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