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 23 using namespace clang; 24 using namespace serialization; 25 26 ModuleFile *ModuleManager::lookup(StringRef Name) { 27 const FileEntry *Entry = FileMgr.getFile(Name); 28 return Modules[Entry]; 29 } 30 31 llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { 32 const FileEntry *Entry = FileMgr.getFile(Name); 33 return InMemoryBuffers[Entry]; 34 } 35 36 std::pair<ModuleFile *, bool> 37 ModuleManager::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 90 void 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 98 ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { } 99 100 ModuleManager::~ModuleManager() { 101 for (unsigned i = 0, e = Chain.size(); i != e; ++i) 102 delete Chain[e - i - 1]; 103 } 104 105 void 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. 174 static 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 198 void 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 212 namespace 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 251 void ModuleManager::viewGraph() { 252 llvm::ViewGraph(*this, "Modules"); 253 } 254 #endif 255