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*4fc9f3e8SDouglas Gregor ModuleFile *ImportedBy, unsigned Generation, 39*4fc9f3e8SDouglas 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. 51*4fc9f3e8SDouglas Gregor ModuleFile *New = new ModuleFile(Type, Generation); 52d44252ecSDouglas Gregor New->FileName = FileName.str(); 53d44252ecSDouglas Gregor Chain.push_back(New); 54d44252ecSDouglas Gregor NewModule = true; 55d44252ecSDouglas Gregor ModuleEntry = New; 56d44252ecSDouglas Gregor 57d44252ecSDouglas Gregor // Load the contents of the module 58d44252ecSDouglas Gregor if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) { 59d44252ecSDouglas Gregor // The buffer was already provided for us. 60d44252ecSDouglas Gregor assert(Buffer && "Passed null buffer"); 61d44252ecSDouglas Gregor New->Buffer.reset(Buffer); 62d44252ecSDouglas Gregor } else { 63d44252ecSDouglas Gregor // Open the AST file. 64d44252ecSDouglas Gregor llvm::error_code ec; 65d44252ecSDouglas Gregor if (FileName == "-") { 66d44252ecSDouglas Gregor ec = llvm::MemoryBuffer::getSTDIN(New->Buffer); 67d44252ecSDouglas Gregor if (ec) 68d44252ecSDouglas Gregor ErrorStr = ec.message(); 69d44252ecSDouglas Gregor } else 70d44252ecSDouglas Gregor New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr)); 71d44252ecSDouglas Gregor 72d44252ecSDouglas Gregor if (!New->Buffer) 73de3ef502SDouglas Gregor return std::make_pair(static_cast<ModuleFile*>(0), false); 74d44252ecSDouglas Gregor } 75d44252ecSDouglas Gregor 76d44252ecSDouglas Gregor // Initialize the stream 77d44252ecSDouglas Gregor New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(), 78d44252ecSDouglas Gregor (const unsigned char *)New->Buffer->getBufferEnd()); } 79d44252ecSDouglas Gregor 80d44252ecSDouglas Gregor if (ImportedBy) { 81d44252ecSDouglas Gregor ModuleEntry->ImportedBy.insert(ImportedBy); 82d44252ecSDouglas Gregor ImportedBy->Imports.insert(ModuleEntry); 83d44252ecSDouglas Gregor } else { 84d44252ecSDouglas Gregor ModuleEntry->DirectlyImported = true; 85d44252ecSDouglas Gregor } 86d44252ecSDouglas Gregor 87d44252ecSDouglas Gregor return std::make_pair(ModuleEntry, NewModule); 88d44252ecSDouglas Gregor } 89d44252ecSDouglas Gregor 90d44252ecSDouglas Gregor void ModuleManager::addInMemoryBuffer(StringRef FileName, 91d44252ecSDouglas Gregor llvm::MemoryBuffer *Buffer) { 92d44252ecSDouglas Gregor 93d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getVirtualFile(FileName, 94d44252ecSDouglas Gregor Buffer->getBufferSize(), 0); 95d44252ecSDouglas Gregor InMemoryBuffers[Entry] = Buffer; 96d44252ecSDouglas Gregor } 97d44252ecSDouglas Gregor 98d44252ecSDouglas Gregor ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { } 99d44252ecSDouglas Gregor 100d44252ecSDouglas Gregor ModuleManager::~ModuleManager() { 101d44252ecSDouglas Gregor for (unsigned i = 0, e = Chain.size(); i != e; ++i) 102d44252ecSDouglas Gregor delete Chain[e - i - 1]; 103d44252ecSDouglas Gregor } 104d44252ecSDouglas Gregor 105de3ef502SDouglas Gregor void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), 106d44252ecSDouglas Gregor void *UserData) { 107d44252ecSDouglas Gregor unsigned N = size(); 108d44252ecSDouglas Gregor 109d44252ecSDouglas Gregor // Record the number of incoming edges for each module. When we 110d44252ecSDouglas Gregor // encounter a module with no incoming edges, push it into the queue 111d44252ecSDouglas Gregor // to seed the queue. 112de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Queue; 113d44252ecSDouglas Gregor Queue.reserve(N); 114de3ef502SDouglas Gregor llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges; 115d44252ecSDouglas Gregor for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { 116d44252ecSDouglas Gregor if (unsigned Size = (*M)->ImportedBy.size()) 117d44252ecSDouglas Gregor UnusedIncomingEdges[*M] = Size; 118d44252ecSDouglas Gregor else 119d44252ecSDouglas Gregor Queue.push_back(*M); 120d44252ecSDouglas Gregor } 121d44252ecSDouglas Gregor 122de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Skipped; 123d44252ecSDouglas Gregor unsigned QueueStart = 0; 124d44252ecSDouglas Gregor while (QueueStart < Queue.size()) { 125de3ef502SDouglas Gregor ModuleFile *CurrentModule = Queue[QueueStart++]; 126d44252ecSDouglas Gregor 127d44252ecSDouglas Gregor // Check whether this module should be skipped. 128d44252ecSDouglas Gregor if (Skipped.count(CurrentModule)) 129d44252ecSDouglas Gregor continue; 130d44252ecSDouglas Gregor 131d44252ecSDouglas Gregor if (Visitor(*CurrentModule, UserData)) { 132d44252ecSDouglas Gregor // The visitor has requested that cut off visitation of any 133d44252ecSDouglas Gregor // module that the current module depends on. To indicate this 134d44252ecSDouglas Gregor // behavior, we mark all of the reachable modules as having N 135d44252ecSDouglas Gregor // incoming edges (which is impossible otherwise). 136de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Stack; 137d44252ecSDouglas Gregor Stack.push_back(CurrentModule); 138d44252ecSDouglas Gregor Skipped.insert(CurrentModule); 139d44252ecSDouglas Gregor while (!Stack.empty()) { 140de3ef502SDouglas Gregor ModuleFile *NextModule = Stack.back(); 141d44252ecSDouglas Gregor Stack.pop_back(); 142d44252ecSDouglas Gregor 143d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 144d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 145de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator 146d44252ecSDouglas Gregor M = NextModule->Imports.begin(), 147d44252ecSDouglas Gregor MEnd = NextModule->Imports.end(); 148d44252ecSDouglas Gregor M != MEnd; ++M) { 149d44252ecSDouglas Gregor if (Skipped.insert(*M)) 150d44252ecSDouglas Gregor Stack.push_back(*M); 151d44252ecSDouglas Gregor } 152d44252ecSDouglas Gregor } 153d44252ecSDouglas Gregor continue; 154d44252ecSDouglas Gregor } 155d44252ecSDouglas Gregor 156d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 157d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 158de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(), 159d44252ecSDouglas Gregor MEnd = CurrentModule->Imports.end(); 160d44252ecSDouglas Gregor M != MEnd; ++M) { 161d44252ecSDouglas Gregor 162d44252ecSDouglas Gregor // Remove our current module as an impediment to visiting the 163d44252ecSDouglas Gregor // module we depend on. If we were the last unvisited module 164d44252ecSDouglas Gregor // that depends on this particular module, push it into the 165d44252ecSDouglas Gregor // queue to be visited. 166d44252ecSDouglas Gregor unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; 167d44252ecSDouglas Gregor if (NumUnusedEdges && (--NumUnusedEdges == 0)) 168d44252ecSDouglas Gregor Queue.push_back(*M); 169d44252ecSDouglas Gregor } 170d44252ecSDouglas Gregor } 171d44252ecSDouglas Gregor } 172d44252ecSDouglas Gregor 173d44252ecSDouglas Gregor /// \brief Perform a depth-first visit of the current module. 174de3ef502SDouglas Gregor static bool visitDepthFirst(ModuleFile &M, 175de3ef502SDouglas Gregor bool (*Visitor)(ModuleFile &M, bool Preorder, 176d44252ecSDouglas Gregor void *UserData), 177d44252ecSDouglas Gregor void *UserData, 178de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> &Visited) { 179d44252ecSDouglas Gregor // Preorder visitation 180d44252ecSDouglas Gregor if (Visitor(M, /*Preorder=*/true, UserData)) 181d44252ecSDouglas Gregor return true; 182d44252ecSDouglas Gregor 183d44252ecSDouglas Gregor // Visit children 184de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), 185d44252ecSDouglas Gregor IMEnd = M.Imports.end(); 186d44252ecSDouglas Gregor IM != IMEnd; ++IM) { 187d44252ecSDouglas Gregor if (!Visited.insert(*IM)) 188d44252ecSDouglas Gregor continue; 189d44252ecSDouglas Gregor 190d44252ecSDouglas Gregor if (visitDepthFirst(**IM, Visitor, UserData, Visited)) 191d44252ecSDouglas Gregor return true; 192d44252ecSDouglas Gregor } 193d44252ecSDouglas Gregor 194d44252ecSDouglas Gregor // Postorder visitation 195d44252ecSDouglas Gregor return Visitor(M, /*Preorder=*/false, UserData); 196d44252ecSDouglas Gregor } 197d44252ecSDouglas Gregor 198de3ef502SDouglas Gregor void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, 199d44252ecSDouglas Gregor void *UserData), 200d44252ecSDouglas Gregor void *UserData) { 201de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Visited; 202d44252ecSDouglas Gregor for (unsigned I = 0, N = Chain.size(); I != N; ++I) { 203d44252ecSDouglas Gregor if (!Visited.insert(Chain[I])) 204d44252ecSDouglas Gregor continue; 205d44252ecSDouglas Gregor 206d44252ecSDouglas Gregor if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) 207d44252ecSDouglas Gregor return; 208d44252ecSDouglas Gregor } 209d44252ecSDouglas Gregor } 2109d7c1a2aSDouglas Gregor 2119d7c1a2aSDouglas Gregor #ifndef NDEBUG 2129d7c1a2aSDouglas Gregor namespace llvm { 2139d7c1a2aSDouglas Gregor template<> 2149d7c1a2aSDouglas Gregor struct GraphTraits<ModuleManager> { 215de3ef502SDouglas Gregor typedef ModuleFile NodeType; 216de3ef502SDouglas Gregor typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType; 2179d7c1a2aSDouglas Gregor typedef ModuleManager::ModuleConstIterator nodes_iterator; 2189d7c1a2aSDouglas Gregor 2199d7c1a2aSDouglas Gregor static ChildIteratorType child_begin(NodeType *Node) { 2209d7c1a2aSDouglas Gregor return Node->Imports.begin(); 2219d7c1a2aSDouglas Gregor } 2229d7c1a2aSDouglas Gregor 2239d7c1a2aSDouglas Gregor static ChildIteratorType child_end(NodeType *Node) { 2249d7c1a2aSDouglas Gregor return Node->Imports.end(); 2259d7c1a2aSDouglas Gregor } 2269d7c1a2aSDouglas Gregor 2279d7c1a2aSDouglas Gregor static nodes_iterator nodes_begin(const ModuleManager &Manager) { 2289d7c1a2aSDouglas Gregor return Manager.begin(); 2299d7c1a2aSDouglas Gregor } 2309d7c1a2aSDouglas Gregor 2319d7c1a2aSDouglas Gregor static nodes_iterator nodes_end(const ModuleManager &Manager) { 2329d7c1a2aSDouglas Gregor return Manager.end(); 2339d7c1a2aSDouglas Gregor } 2349d7c1a2aSDouglas Gregor }; 2359d7c1a2aSDouglas Gregor 2369d7c1a2aSDouglas Gregor template<> 2379d7c1a2aSDouglas Gregor struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { 2389d7c1a2aSDouglas Gregor explicit DOTGraphTraits(bool IsSimple = false) 2399d7c1a2aSDouglas Gregor : DefaultDOTGraphTraits(IsSimple) { } 2409d7c1a2aSDouglas Gregor 2419d7c1a2aSDouglas Gregor static bool renderGraphFromBottomUp() { 2429d7c1a2aSDouglas Gregor return true; 2439d7c1a2aSDouglas Gregor } 2449d7c1a2aSDouglas Gregor 245de3ef502SDouglas Gregor std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { 2469d7c1a2aSDouglas Gregor return llvm::sys::path::stem(M->FileName); 2479d7c1a2aSDouglas Gregor } 2489d7c1a2aSDouglas Gregor }; 2499d7c1a2aSDouglas Gregor } 2509d7c1a2aSDouglas Gregor 2519d7c1a2aSDouglas Gregor void ModuleManager::viewGraph() { 2529d7c1a2aSDouglas Gregor llvm::ViewGraph(*this, "Modules"); 2539d7c1a2aSDouglas Gregor } 2549d7c1a2aSDouglas Gregor #endif 255