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