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, 38*6fb03aeaSDouglas Gregor SourceLocation ImportLoc, ModuleFile *ImportedBy, 39*6fb03aeaSDouglas Gregor unsigned Generation, 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; 54*6fb03aeaSDouglas Gregor New->ImportLoc = ImportLoc; 55d44252ecSDouglas Gregor Chain.push_back(New); 56d44252ecSDouglas Gregor NewModule = true; 57d44252ecSDouglas Gregor ModuleEntry = New; 58d44252ecSDouglas Gregor 59d44252ecSDouglas Gregor // Load the contents of the module 60d44252ecSDouglas Gregor if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { 61d44252ecSDouglas Gregor // The buffer was already provided for us. 62d44252ecSDouglas Gregor assert(Buffer && "Passed null buffer"); 63d44252ecSDouglas Gregor New->Buffer.reset(Buffer); 64d44252ecSDouglas Gregor } else { 65d44252ecSDouglas Gregor // Open the AST file. 66d44252ecSDouglas Gregor llvm::error_code ec; 67d44252ecSDouglas Gregor if (FileName == "-") { 68d44252ecSDouglas Gregor ec = llvm::MemoryBuffer::getSTDIN(New->Buffer); 69d44252ecSDouglas Gregor if (ec) 70d44252ecSDouglas Gregor ErrorStr = ec.message(); 71d44252ecSDouglas Gregor } else 72d44252ecSDouglas Gregor New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); 73d44252ecSDouglas Gregor 74d44252ecSDouglas Gregor if (!New->Buffer) 75de3ef502SDouglas Gregor return std::make_pair(static_cast<ModuleFile*>(0), false); 76d44252ecSDouglas Gregor } 77d44252ecSDouglas Gregor 78d44252ecSDouglas Gregor // Initialize the stream 79d44252ecSDouglas Gregor New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), 80d44252ecSDouglas Gregor (const unsigned char *)New->Buffer->getBufferEnd()); } 81d44252ecSDouglas Gregor 82d44252ecSDouglas Gregor if (ImportedBy) { 83d44252ecSDouglas Gregor ModuleEntry->ImportedBy.insert(ImportedBy); 84d44252ecSDouglas Gregor ImportedBy->Imports.insert(ModuleEntry); 85d44252ecSDouglas Gregor } else { 86*6fb03aeaSDouglas Gregor if (!ModuleEntry->DirectlyImported) 87*6fb03aeaSDouglas Gregor ModuleEntry->ImportLoc = ImportLoc; 88*6fb03aeaSDouglas Gregor 89d44252ecSDouglas Gregor ModuleEntry->DirectlyImported = true; 90d44252ecSDouglas Gregor } 91d44252ecSDouglas Gregor 92d44252ecSDouglas Gregor return std::make_pair(ModuleEntry, NewModule); 93d44252ecSDouglas Gregor } 94d44252ecSDouglas Gregor 95188dbef2SDouglas Gregor namespace { 96188dbef2SDouglas Gregor /// \brief Predicate that checks whether a module file occurs within 97188dbef2SDouglas Gregor /// the given set. 98188dbef2SDouglas Gregor class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> { 99188dbef2SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> &Removed; 100188dbef2SDouglas Gregor 101188dbef2SDouglas Gregor public: 102188dbef2SDouglas Gregor IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed) 103188dbef2SDouglas Gregor : Removed(Removed) { } 104188dbef2SDouglas Gregor 105188dbef2SDouglas Gregor bool operator()(ModuleFile *MF) const { 106188dbef2SDouglas Gregor return Removed.count(MF); 107188dbef2SDouglas Gregor } 108188dbef2SDouglas Gregor }; 109188dbef2SDouglas Gregor } 110188dbef2SDouglas Gregor 111188dbef2SDouglas Gregor void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { 112188dbef2SDouglas Gregor if (first == last) 113188dbef2SDouglas Gregor return; 114188dbef2SDouglas Gregor 115188dbef2SDouglas Gregor // Collect the set of module file pointers that we'll be removing. 116188dbef2SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last); 117188dbef2SDouglas Gregor 118188dbef2SDouglas Gregor // Remove any references to the now-destroyed modules. 119188dbef2SDouglas Gregor IsInModuleFileSet checkInSet(victimSet); 120188dbef2SDouglas Gregor for (unsigned i = 0, n = Chain.size(); i != n; ++i) { 121188dbef2SDouglas Gregor Chain[i]->ImportedBy.remove_if(checkInSet); 122188dbef2SDouglas Gregor } 123188dbef2SDouglas Gregor 124188dbef2SDouglas Gregor // Delete the modules and erase them from the various structures. 125188dbef2SDouglas Gregor for (ModuleIterator victim = first; victim != last; ++victim) { 126188dbef2SDouglas Gregor Modules.erase((*victim)->File); 127188dbef2SDouglas Gregor delete *victim; 128188dbef2SDouglas Gregor } 129188dbef2SDouglas Gregor 130188dbef2SDouglas Gregor // Remove the modules from the chain. 131188dbef2SDouglas Gregor Chain.erase(first, last); 132188dbef2SDouglas Gregor } 133188dbef2SDouglas Gregor 134d44252ecSDouglas Gregor void ModuleManager::addInMemoryBuffer(StringRef FileName, 135d44252ecSDouglas Gregor llvm::MemoryBuffer *Buffer) { 136d44252ecSDouglas Gregor 137d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getVirtualFile(FileName, 138d44252ecSDouglas Gregor Buffer->getBufferSize(), 0); 139d44252ecSDouglas Gregor InMemoryBuffers[Entry] = Buffer; 140d44252ecSDouglas Gregor } 141d44252ecSDouglas Gregor 142aedf7144SArgyrios Kyrtzidis ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { } 143d44252ecSDouglas Gregor 144d44252ecSDouglas Gregor ModuleManager::~ModuleManager() { 145d44252ecSDouglas Gregor for (unsigned i = 0, e = Chain.size(); i != e; ++i) 146d44252ecSDouglas Gregor delete Chain[e - i - 1]; 147d44252ecSDouglas Gregor } 148d44252ecSDouglas Gregor 149de3ef502SDouglas Gregor void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), 150d44252ecSDouglas Gregor void *UserData) { 151d44252ecSDouglas Gregor unsigned N = size(); 152d44252ecSDouglas Gregor 153d44252ecSDouglas Gregor // Record the number of incoming edges for each module. When we 154d44252ecSDouglas Gregor // encounter a module with no incoming edges, push it into the queue 155d44252ecSDouglas Gregor // to seed the queue. 156de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Queue; 157d44252ecSDouglas Gregor Queue.reserve(N); 158de3ef502SDouglas Gregor llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges; 159d44252ecSDouglas Gregor for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { 160d44252ecSDouglas Gregor if (unsigned Size = (*M)->ImportedBy.size()) 161d44252ecSDouglas Gregor UnusedIncomingEdges[*M] = Size; 162d44252ecSDouglas Gregor else 163d44252ecSDouglas Gregor Queue.push_back(*M); 164d44252ecSDouglas Gregor } 165d44252ecSDouglas Gregor 166de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Skipped; 167d44252ecSDouglas Gregor unsigned QueueStart = 0; 168d44252ecSDouglas Gregor while (QueueStart < Queue.size()) { 169de3ef502SDouglas Gregor ModuleFile *CurrentModule = Queue[QueueStart++]; 170d44252ecSDouglas Gregor 171d44252ecSDouglas Gregor // Check whether this module should be skipped. 172d44252ecSDouglas Gregor if (Skipped.count(CurrentModule)) 173d44252ecSDouglas Gregor continue; 174d44252ecSDouglas Gregor 175d44252ecSDouglas Gregor if (Visitor(*CurrentModule, UserData)) { 176d44252ecSDouglas Gregor // The visitor has requested that cut off visitation of any 177d44252ecSDouglas Gregor // module that the current module depends on. To indicate this 178d44252ecSDouglas Gregor // behavior, we mark all of the reachable modules as having N 179d44252ecSDouglas Gregor // incoming edges (which is impossible otherwise). 180de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Stack; 181d44252ecSDouglas Gregor Stack.push_back(CurrentModule); 182d44252ecSDouglas Gregor Skipped.insert(CurrentModule); 183d44252ecSDouglas Gregor while (!Stack.empty()) { 184de3ef502SDouglas Gregor ModuleFile *NextModule = Stack.back(); 185d44252ecSDouglas Gregor Stack.pop_back(); 186d44252ecSDouglas Gregor 187d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 188d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 189de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator 190d44252ecSDouglas Gregor M = NextModule->Imports.begin(), 191d44252ecSDouglas Gregor MEnd = NextModule->Imports.end(); 192d44252ecSDouglas Gregor M != MEnd; ++M) { 193d44252ecSDouglas Gregor if (Skipped.insert(*M)) 194d44252ecSDouglas Gregor Stack.push_back(*M); 195d44252ecSDouglas Gregor } 196d44252ecSDouglas Gregor } 197d44252ecSDouglas Gregor continue; 198d44252ecSDouglas Gregor } 199d44252ecSDouglas Gregor 200d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 201d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 202de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(), 203d44252ecSDouglas Gregor MEnd = CurrentModule->Imports.end(); 204d44252ecSDouglas Gregor M != MEnd; ++M) { 205d44252ecSDouglas Gregor 206d44252ecSDouglas Gregor // Remove our current module as an impediment to visiting the 207d44252ecSDouglas Gregor // module we depend on. If we were the last unvisited module 208d44252ecSDouglas Gregor // that depends on this particular module, push it into the 209d44252ecSDouglas Gregor // queue to be visited. 210d44252ecSDouglas Gregor unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; 211d44252ecSDouglas Gregor if (NumUnusedEdges && (--NumUnusedEdges == 0)) 212d44252ecSDouglas Gregor Queue.push_back(*M); 213d44252ecSDouglas Gregor } 214d44252ecSDouglas Gregor } 215d44252ecSDouglas Gregor } 216d44252ecSDouglas Gregor 217d44252ecSDouglas Gregor /// \brief Perform a depth-first visit of the current module. 218de3ef502SDouglas Gregor static bool visitDepthFirst(ModuleFile &M, 219de3ef502SDouglas Gregor bool (*Visitor)(ModuleFile &M, bool Preorder, 220d44252ecSDouglas Gregor void *UserData), 221d44252ecSDouglas Gregor void *UserData, 222de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> &Visited) { 223d44252ecSDouglas Gregor // Preorder visitation 224d44252ecSDouglas Gregor if (Visitor(M, /*Preorder=*/true, UserData)) 225d44252ecSDouglas Gregor return true; 226d44252ecSDouglas Gregor 227d44252ecSDouglas Gregor // Visit children 228de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), 229d44252ecSDouglas Gregor IMEnd = M.Imports.end(); 230d44252ecSDouglas Gregor IM != IMEnd; ++IM) { 231d44252ecSDouglas Gregor if (!Visited.insert(*IM)) 232d44252ecSDouglas Gregor continue; 233d44252ecSDouglas Gregor 234d44252ecSDouglas Gregor if (visitDepthFirst(**IM, Visitor, UserData, Visited)) 235d44252ecSDouglas Gregor return true; 236d44252ecSDouglas Gregor } 237d44252ecSDouglas Gregor 238d44252ecSDouglas Gregor // Postorder visitation 239d44252ecSDouglas Gregor return Visitor(M, /*Preorder=*/false, UserData); 240d44252ecSDouglas Gregor } 241d44252ecSDouglas Gregor 242de3ef502SDouglas Gregor void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, 243d44252ecSDouglas Gregor void *UserData), 244d44252ecSDouglas Gregor void *UserData) { 245de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Visited; 246d44252ecSDouglas Gregor for (unsigned I = 0, N = Chain.size(); I != N; ++I) { 247d44252ecSDouglas Gregor if (!Visited.insert(Chain[I])) 248d44252ecSDouglas Gregor continue; 249d44252ecSDouglas Gregor 250d44252ecSDouglas Gregor if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) 251d44252ecSDouglas Gregor return; 252d44252ecSDouglas Gregor } 253d44252ecSDouglas Gregor } 2549d7c1a2aSDouglas Gregor 2559d7c1a2aSDouglas Gregor #ifndef NDEBUG 2569d7c1a2aSDouglas Gregor namespace llvm { 2579d7c1a2aSDouglas Gregor template<> 2589d7c1a2aSDouglas Gregor struct GraphTraits<ModuleManager> { 259de3ef502SDouglas Gregor typedef ModuleFile NodeType; 260de3ef502SDouglas Gregor typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType; 2619d7c1a2aSDouglas Gregor typedef ModuleManager::ModuleConstIterator nodes_iterator; 2629d7c1a2aSDouglas Gregor 2639d7c1a2aSDouglas Gregor static ChildIteratorType child_begin(NodeType *Node) { 2649d7c1a2aSDouglas Gregor return Node->Imports.begin(); 2659d7c1a2aSDouglas Gregor } 2669d7c1a2aSDouglas Gregor 2679d7c1a2aSDouglas Gregor static ChildIteratorType child_end(NodeType *Node) { 2689d7c1a2aSDouglas Gregor return Node->Imports.end(); 2699d7c1a2aSDouglas Gregor } 2709d7c1a2aSDouglas Gregor 2719d7c1a2aSDouglas Gregor static nodes_iterator nodes_begin(const ModuleManager &Manager) { 2729d7c1a2aSDouglas Gregor return Manager.begin(); 2739d7c1a2aSDouglas Gregor } 2749d7c1a2aSDouglas Gregor 2759d7c1a2aSDouglas Gregor static nodes_iterator nodes_end(const ModuleManager &Manager) { 2769d7c1a2aSDouglas Gregor return Manager.end(); 2779d7c1a2aSDouglas Gregor } 2789d7c1a2aSDouglas Gregor }; 2799d7c1a2aSDouglas Gregor 2809d7c1a2aSDouglas Gregor template<> 2819d7c1a2aSDouglas Gregor struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { 2829d7c1a2aSDouglas Gregor explicit DOTGraphTraits(bool IsSimple = false) 2839d7c1a2aSDouglas Gregor : DefaultDOTGraphTraits(IsSimple) { } 2849d7c1a2aSDouglas Gregor 2859d7c1a2aSDouglas Gregor static bool renderGraphFromBottomUp() { 2869d7c1a2aSDouglas Gregor return true; 2879d7c1a2aSDouglas Gregor } 2889d7c1a2aSDouglas Gregor 289de3ef502SDouglas Gregor std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { 2909d7c1a2aSDouglas Gregor return llvm::sys::path::stem(M->FileName); 2919d7c1a2aSDouglas Gregor } 2929d7c1a2aSDouglas Gregor }; 2939d7c1a2aSDouglas Gregor } 2949d7c1a2aSDouglas Gregor 2959d7c1a2aSDouglas Gregor void ModuleManager::viewGraph() { 2969d7c1a2aSDouglas Gregor llvm::ViewGraph(*this, "Modules"); 2979d7c1a2aSDouglas Gregor } 2989d7c1a2aSDouglas Gregor #endif 299