1d44252ecSDouglas Gregor //===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// 2d44252ecSDouglas Gregor // 3d44252ecSDouglas Gregor // The LLVM Compiler Infrastructure 4d44252ecSDouglas Gregor // 5d44252ecSDouglas Gregor // This file is distributed under the University of Illinois Open Source 6d44252ecSDouglas Gregor // License. See LICENSE.TXT for details. 7d44252ecSDouglas Gregor // 8d44252ecSDouglas Gregor //===----------------------------------------------------------------------===// 9d44252ecSDouglas Gregor // 10d44252ecSDouglas Gregor // This file defines the ModuleManager class, which manages a set of loaded 11d44252ecSDouglas Gregor // modules for the ASTReader. 12d44252ecSDouglas Gregor // 13d44252ecSDouglas Gregor //===----------------------------------------------------------------------===// 14d44252ecSDouglas Gregor #include "clang/Serialization/ModuleManager.h" 15d44252ecSDouglas Gregor #include "llvm/Support/MemoryBuffer.h" 16d44252ecSDouglas Gregor #include "llvm/Support/raw_ostream.h" 17d44252ecSDouglas Gregor #include "llvm/Support/system_error.h" 18d44252ecSDouglas Gregor 199d7c1a2aSDouglas Gregor #ifndef NDEBUG 209d7c1a2aSDouglas Gregor #include "llvm/Support/GraphWriter.h" 219d7c1a2aSDouglas Gregor #endif 229d7c1a2aSDouglas Gregor 23d44252ecSDouglas Gregor using namespace clang; 24d44252ecSDouglas Gregor using namespace serialization; 25d44252ecSDouglas Gregor 26de3ef502SDouglas Gregor ModuleFile *ModuleManager::lookup(StringRef Name) { 27d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getFile(Name); 28d44252ecSDouglas Gregor return Modules[Entry]; 29d44252ecSDouglas Gregor } 30d44252ecSDouglas Gregor 31d44252ecSDouglas Gregor llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) { 32d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getFile(Name); 33d44252ecSDouglas Gregor return InMemoryBuffers[Entry]; 34d44252ecSDouglas Gregor } 35d44252ecSDouglas Gregor 36de3ef502SDouglas Gregor std::pair<ModuleFile *, bool> 37d44252ecSDouglas Gregor ModuleManager::addModule(StringRef FileName, ModuleKind Type, 384fc9f3e8SDouglas Gregor ModuleFile *ImportedBy, unsigned Generation, 394fc9f3e8SDouglas Gregor std::string &ErrorStr) { 40d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getFile(FileName); 41d44252ecSDouglas Gregor if (!Entry && FileName != "-") { 42d44252ecSDouglas Gregor ErrorStr = "file not found"; 43de3ef502SDouglas Gregor return std::make_pair(static_cast<ModuleFile*>(0), false); 44d44252ecSDouglas Gregor } 45d44252ecSDouglas Gregor 46d44252ecSDouglas Gregor // Check whether we already loaded this module, before 47de3ef502SDouglas Gregor ModuleFile *&ModuleEntry = Modules[Entry]; 48d44252ecSDouglas Gregor bool NewModule = false; 49d44252ecSDouglas Gregor if (!ModuleEntry) { 50d44252ecSDouglas Gregor // Allocate a new module. 514fc9f3e8SDouglas Gregor ModuleFile *New = new ModuleFile(Type, Generation); 52d44252ecSDouglas Gregor New->FileName = FileName.str(); 53aedf7144SArgyrios Kyrtzidis New->File = Entry; 54d44252ecSDouglas Gregor Chain.push_back(New); 55d44252ecSDouglas Gregor NewModule = true; 56d44252ecSDouglas Gregor ModuleEntry = New; 57d44252ecSDouglas Gregor 58d44252ecSDouglas Gregor // Load the contents of the module 59d44252ecSDouglas Gregor if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { 60d44252ecSDouglas Gregor // The buffer was already provided for us. 61d44252ecSDouglas Gregor assert(Buffer && "Passed null buffer"); 62d44252ecSDouglas Gregor New->Buffer.reset(Buffer); 63d44252ecSDouglas Gregor } else { 64d44252ecSDouglas Gregor // Open the AST file. 65d44252ecSDouglas Gregor llvm::error_code ec; 66d44252ecSDouglas Gregor if (FileName == "-") { 67d44252ecSDouglas Gregor ec = llvm::MemoryBuffer::getSTDIN(New->Buffer); 68d44252ecSDouglas Gregor if (ec) 69d44252ecSDouglas Gregor ErrorStr = ec.message(); 70d44252ecSDouglas Gregor } else 71d44252ecSDouglas Gregor New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); 72d44252ecSDouglas Gregor 73d44252ecSDouglas Gregor if (!New->Buffer) 74de3ef502SDouglas Gregor return std::make_pair(static_cast<ModuleFile*>(0), false); 75d44252ecSDouglas Gregor } 76d44252ecSDouglas Gregor 77d44252ecSDouglas Gregor // Initialize the stream 78d44252ecSDouglas Gregor New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), 79d44252ecSDouglas Gregor (const unsigned char *)New->Buffer->getBufferEnd()); } 80d44252ecSDouglas Gregor 81d44252ecSDouglas Gregor if (ImportedBy) { 82d44252ecSDouglas Gregor ModuleEntry->ImportedBy.insert(ImportedBy); 83d44252ecSDouglas Gregor ImportedBy->Imports.insert(ModuleEntry); 84d44252ecSDouglas Gregor } else { 85d44252ecSDouglas Gregor ModuleEntry->DirectlyImported = true; 86d44252ecSDouglas Gregor } 87d44252ecSDouglas Gregor 88d44252ecSDouglas Gregor return std::make_pair(ModuleEntry, NewModule); 89d44252ecSDouglas Gregor } 90d44252ecSDouglas Gregor 91*188dbef2SDouglas Gregor namespace { 92*188dbef2SDouglas Gregor /// \brief Predicate that checks whether a module file occurs within 93*188dbef2SDouglas Gregor /// the given set. 94*188dbef2SDouglas Gregor class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> { 95*188dbef2SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> &Removed; 96*188dbef2SDouglas Gregor 97*188dbef2SDouglas Gregor public: 98*188dbef2SDouglas Gregor IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed) 99*188dbef2SDouglas Gregor : Removed(Removed) { } 100*188dbef2SDouglas Gregor 101*188dbef2SDouglas Gregor bool operator()(ModuleFile *MF) const { 102*188dbef2SDouglas Gregor return Removed.count(MF); 103*188dbef2SDouglas Gregor } 104*188dbef2SDouglas Gregor }; 105*188dbef2SDouglas Gregor } 106*188dbef2SDouglas Gregor 107*188dbef2SDouglas Gregor void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { 108*188dbef2SDouglas Gregor if (first == last) 109*188dbef2SDouglas Gregor return; 110*188dbef2SDouglas Gregor 111*188dbef2SDouglas Gregor // Collect the set of module file pointers that we'll be removing. 112*188dbef2SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last); 113*188dbef2SDouglas Gregor 114*188dbef2SDouglas Gregor // Remove any references to the now-destroyed modules. 115*188dbef2SDouglas Gregor IsInModuleFileSet checkInSet(victimSet); 116*188dbef2SDouglas Gregor for (unsigned i = 0, n = Chain.size(); i != n; ++i) { 117*188dbef2SDouglas Gregor Chain[i]->ImportedBy.remove_if(checkInSet); 118*188dbef2SDouglas Gregor } 119*188dbef2SDouglas Gregor 120*188dbef2SDouglas Gregor // Delete the modules and erase them from the various structures. 121*188dbef2SDouglas Gregor for (ModuleIterator victim = first; victim != last; ++victim) { 122*188dbef2SDouglas Gregor Modules.erase((*victim)->File); 123*188dbef2SDouglas Gregor delete *victim; 124*188dbef2SDouglas Gregor } 125*188dbef2SDouglas Gregor 126*188dbef2SDouglas Gregor // Remove the modules from the chain. 127*188dbef2SDouglas Gregor Chain.erase(first, last); 128*188dbef2SDouglas Gregor } 129*188dbef2SDouglas Gregor 130d44252ecSDouglas Gregor void ModuleManager::addInMemoryBuffer(StringRef FileName, 131d44252ecSDouglas Gregor llvm::MemoryBuffer *Buffer) { 132d44252ecSDouglas Gregor 133d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getVirtualFile(FileName, 134d44252ecSDouglas Gregor Buffer->getBufferSize(), 0); 135d44252ecSDouglas Gregor InMemoryBuffers[Entry] = Buffer; 136d44252ecSDouglas Gregor } 137d44252ecSDouglas Gregor 138aedf7144SArgyrios Kyrtzidis ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { } 139d44252ecSDouglas Gregor 140d44252ecSDouglas Gregor ModuleManager::~ModuleManager() { 141d44252ecSDouglas Gregor for (unsigned i = 0, e = Chain.size(); i != e; ++i) 142d44252ecSDouglas Gregor delete Chain[e - i - 1]; 143d44252ecSDouglas Gregor } 144d44252ecSDouglas Gregor 145de3ef502SDouglas Gregor void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), 146d44252ecSDouglas Gregor void *UserData) { 147d44252ecSDouglas Gregor unsigned N = size(); 148d44252ecSDouglas Gregor 149d44252ecSDouglas Gregor // Record the number of incoming edges for each module. When we 150d44252ecSDouglas Gregor // encounter a module with no incoming edges, push it into the queue 151d44252ecSDouglas Gregor // to seed the queue. 152de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Queue; 153d44252ecSDouglas Gregor Queue.reserve(N); 154de3ef502SDouglas Gregor llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges; 155d44252ecSDouglas Gregor for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { 156d44252ecSDouglas Gregor if (unsigned Size = (*M)->ImportedBy.size()) 157d44252ecSDouglas Gregor UnusedIncomingEdges[*M] = Size; 158d44252ecSDouglas Gregor else 159d44252ecSDouglas Gregor Queue.push_back(*M); 160d44252ecSDouglas Gregor } 161d44252ecSDouglas Gregor 162de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Skipped; 163d44252ecSDouglas Gregor unsigned QueueStart = 0; 164d44252ecSDouglas Gregor while (QueueStart < Queue.size()) { 165de3ef502SDouglas Gregor ModuleFile *CurrentModule = Queue[QueueStart++]; 166d44252ecSDouglas Gregor 167d44252ecSDouglas Gregor // Check whether this module should be skipped. 168d44252ecSDouglas Gregor if (Skipped.count(CurrentModule)) 169d44252ecSDouglas Gregor continue; 170d44252ecSDouglas Gregor 171d44252ecSDouglas Gregor if (Visitor(*CurrentModule, UserData)) { 172d44252ecSDouglas Gregor // The visitor has requested that cut off visitation of any 173d44252ecSDouglas Gregor // module that the current module depends on. To indicate this 174d44252ecSDouglas Gregor // behavior, we mark all of the reachable modules as having N 175d44252ecSDouglas Gregor // incoming edges (which is impossible otherwise). 176de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Stack; 177d44252ecSDouglas Gregor Stack.push_back(CurrentModule); 178d44252ecSDouglas Gregor Skipped.insert(CurrentModule); 179d44252ecSDouglas Gregor while (!Stack.empty()) { 180de3ef502SDouglas Gregor ModuleFile *NextModule = Stack.back(); 181d44252ecSDouglas Gregor Stack.pop_back(); 182d44252ecSDouglas Gregor 183d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 184d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 185de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator 186d44252ecSDouglas Gregor M = NextModule->Imports.begin(), 187d44252ecSDouglas Gregor MEnd = NextModule->Imports.end(); 188d44252ecSDouglas Gregor M != MEnd; ++M) { 189d44252ecSDouglas Gregor if (Skipped.insert(*M)) 190d44252ecSDouglas Gregor Stack.push_back(*M); 191d44252ecSDouglas Gregor } 192d44252ecSDouglas Gregor } 193d44252ecSDouglas Gregor continue; 194d44252ecSDouglas Gregor } 195d44252ecSDouglas Gregor 196d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 197d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 198de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(), 199d44252ecSDouglas Gregor MEnd = CurrentModule->Imports.end(); 200d44252ecSDouglas Gregor M != MEnd; ++M) { 201d44252ecSDouglas Gregor 202d44252ecSDouglas Gregor // Remove our current module as an impediment to visiting the 203d44252ecSDouglas Gregor // module we depend on. If we were the last unvisited module 204d44252ecSDouglas Gregor // that depends on this particular module, push it into the 205d44252ecSDouglas Gregor // queue to be visited. 206d44252ecSDouglas Gregor unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; 207d44252ecSDouglas Gregor if (NumUnusedEdges && (--NumUnusedEdges == 0)) 208d44252ecSDouglas Gregor Queue.push_back(*M); 209d44252ecSDouglas Gregor } 210d44252ecSDouglas Gregor } 211d44252ecSDouglas Gregor } 212d44252ecSDouglas Gregor 213d44252ecSDouglas Gregor /// \brief Perform a depth-first visit of the current module. 214de3ef502SDouglas Gregor static bool visitDepthFirst(ModuleFile &M, 215de3ef502SDouglas Gregor bool (*Visitor)(ModuleFile &M, bool Preorder, 216d44252ecSDouglas Gregor void *UserData), 217d44252ecSDouglas Gregor void *UserData, 218de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> &Visited) { 219d44252ecSDouglas Gregor // Preorder visitation 220d44252ecSDouglas Gregor if (Visitor(M, /*Preorder=*/true, UserData)) 221d44252ecSDouglas Gregor return true; 222d44252ecSDouglas Gregor 223d44252ecSDouglas Gregor // Visit children 224de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), 225d44252ecSDouglas Gregor IMEnd = M.Imports.end(); 226d44252ecSDouglas Gregor IM != IMEnd; ++IM) { 227d44252ecSDouglas Gregor if (!Visited.insert(*IM)) 228d44252ecSDouglas Gregor continue; 229d44252ecSDouglas Gregor 230d44252ecSDouglas Gregor if (visitDepthFirst(**IM, Visitor, UserData, Visited)) 231d44252ecSDouglas Gregor return true; 232d44252ecSDouglas Gregor } 233d44252ecSDouglas Gregor 234d44252ecSDouglas Gregor // Postorder visitation 235d44252ecSDouglas Gregor return Visitor(M, /*Preorder=*/false, UserData); 236d44252ecSDouglas Gregor } 237d44252ecSDouglas Gregor 238de3ef502SDouglas Gregor void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, 239d44252ecSDouglas Gregor void *UserData), 240d44252ecSDouglas Gregor void *UserData) { 241de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Visited; 242d44252ecSDouglas Gregor for (unsigned I = 0, N = Chain.size(); I != N; ++I) { 243d44252ecSDouglas Gregor if (!Visited.insert(Chain[I])) 244d44252ecSDouglas Gregor continue; 245d44252ecSDouglas Gregor 246d44252ecSDouglas Gregor if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) 247d44252ecSDouglas Gregor return; 248d44252ecSDouglas Gregor } 249d44252ecSDouglas Gregor } 2509d7c1a2aSDouglas Gregor 2519d7c1a2aSDouglas Gregor #ifndef NDEBUG 2529d7c1a2aSDouglas Gregor namespace llvm { 2539d7c1a2aSDouglas Gregor template<> 2549d7c1a2aSDouglas Gregor struct GraphTraits<ModuleManager> { 255de3ef502SDouglas Gregor typedef ModuleFile NodeType; 256de3ef502SDouglas Gregor typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType; 2579d7c1a2aSDouglas Gregor typedef ModuleManager::ModuleConstIterator nodes_iterator; 2589d7c1a2aSDouglas Gregor 2599d7c1a2aSDouglas Gregor static ChildIteratorType child_begin(NodeType *Node) { 2609d7c1a2aSDouglas Gregor return Node->Imports.begin(); 2619d7c1a2aSDouglas Gregor } 2629d7c1a2aSDouglas Gregor 2639d7c1a2aSDouglas Gregor static ChildIteratorType child_end(NodeType *Node) { 2649d7c1a2aSDouglas Gregor return Node->Imports.end(); 2659d7c1a2aSDouglas Gregor } 2669d7c1a2aSDouglas Gregor 2679d7c1a2aSDouglas Gregor static nodes_iterator nodes_begin(const ModuleManager &Manager) { 2689d7c1a2aSDouglas Gregor return Manager.begin(); 2699d7c1a2aSDouglas Gregor } 2709d7c1a2aSDouglas Gregor 2719d7c1a2aSDouglas Gregor static nodes_iterator nodes_end(const ModuleManager &Manager) { 2729d7c1a2aSDouglas Gregor return Manager.end(); 2739d7c1a2aSDouglas Gregor } 2749d7c1a2aSDouglas Gregor }; 2759d7c1a2aSDouglas Gregor 2769d7c1a2aSDouglas Gregor template<> 2779d7c1a2aSDouglas Gregor struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { 2789d7c1a2aSDouglas Gregor explicit DOTGraphTraits(bool IsSimple = false) 2799d7c1a2aSDouglas Gregor : DefaultDOTGraphTraits(IsSimple) { } 2809d7c1a2aSDouglas Gregor 2819d7c1a2aSDouglas Gregor static bool renderGraphFromBottomUp() { 2829d7c1a2aSDouglas Gregor return true; 2839d7c1a2aSDouglas Gregor } 2849d7c1a2aSDouglas Gregor 285de3ef502SDouglas Gregor std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { 2869d7c1a2aSDouglas Gregor return llvm::sys::path::stem(M->FileName); 2879d7c1a2aSDouglas Gregor } 2889d7c1a2aSDouglas Gregor }; 2899d7c1a2aSDouglas Gregor } 2909d7c1a2aSDouglas Gregor 2919d7c1a2aSDouglas Gregor void ModuleManager::viewGraph() { 2929d7c1a2aSDouglas Gregor llvm::ViewGraph(*this, "Modules"); 2939d7c1a2aSDouglas Gregor } 2949d7c1a2aSDouglas Gregor #endif 295