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