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