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(); 53*aedf7144SArgyrios 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 91d44252ecSDouglas Gregor void ModuleManager::addInMemoryBuffer(StringRef FileName, 92d44252ecSDouglas Gregor llvm::MemoryBuffer *Buffer) { 93d44252ecSDouglas Gregor 94d44252ecSDouglas Gregor const FileEntry *Entry = FileMgr.getVirtualFile(FileName, 95d44252ecSDouglas Gregor Buffer->getBufferSize(), 0); 96d44252ecSDouglas Gregor InMemoryBuffers[Entry] = Buffer; 97d44252ecSDouglas Gregor } 98d44252ecSDouglas Gregor 99*aedf7144SArgyrios Kyrtzidis ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { } 100d44252ecSDouglas Gregor 101d44252ecSDouglas Gregor ModuleManager::~ModuleManager() { 102d44252ecSDouglas Gregor for (unsigned i = 0, e = Chain.size(); i != e; ++i) 103d44252ecSDouglas Gregor delete Chain[e - i - 1]; 104d44252ecSDouglas Gregor } 105d44252ecSDouglas Gregor 106de3ef502SDouglas Gregor void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData), 107d44252ecSDouglas Gregor void *UserData) { 108d44252ecSDouglas Gregor unsigned N = size(); 109d44252ecSDouglas Gregor 110d44252ecSDouglas Gregor // Record the number of incoming edges for each module. When we 111d44252ecSDouglas Gregor // encounter a module with no incoming edges, push it into the queue 112d44252ecSDouglas Gregor // to seed the queue. 113de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Queue; 114d44252ecSDouglas Gregor Queue.reserve(N); 115de3ef502SDouglas Gregor llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges; 116d44252ecSDouglas Gregor for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) { 117d44252ecSDouglas Gregor if (unsigned Size = (*M)->ImportedBy.size()) 118d44252ecSDouglas Gregor UnusedIncomingEdges[*M] = Size; 119d44252ecSDouglas Gregor else 120d44252ecSDouglas Gregor Queue.push_back(*M); 121d44252ecSDouglas Gregor } 122d44252ecSDouglas Gregor 123de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Skipped; 124d44252ecSDouglas Gregor unsigned QueueStart = 0; 125d44252ecSDouglas Gregor while (QueueStart < Queue.size()) { 126de3ef502SDouglas Gregor ModuleFile *CurrentModule = Queue[QueueStart++]; 127d44252ecSDouglas Gregor 128d44252ecSDouglas Gregor // Check whether this module should be skipped. 129d44252ecSDouglas Gregor if (Skipped.count(CurrentModule)) 130d44252ecSDouglas Gregor continue; 131d44252ecSDouglas Gregor 132d44252ecSDouglas Gregor if (Visitor(*CurrentModule, UserData)) { 133d44252ecSDouglas Gregor // The visitor has requested that cut off visitation of any 134d44252ecSDouglas Gregor // module that the current module depends on. To indicate this 135d44252ecSDouglas Gregor // behavior, we mark all of the reachable modules as having N 136d44252ecSDouglas Gregor // incoming edges (which is impossible otherwise). 137de3ef502SDouglas Gregor SmallVector<ModuleFile *, 4> Stack; 138d44252ecSDouglas Gregor Stack.push_back(CurrentModule); 139d44252ecSDouglas Gregor Skipped.insert(CurrentModule); 140d44252ecSDouglas Gregor while (!Stack.empty()) { 141de3ef502SDouglas Gregor ModuleFile *NextModule = Stack.back(); 142d44252ecSDouglas Gregor Stack.pop_back(); 143d44252ecSDouglas Gregor 144d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 145d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 146de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator 147d44252ecSDouglas Gregor M = NextModule->Imports.begin(), 148d44252ecSDouglas Gregor MEnd = NextModule->Imports.end(); 149d44252ecSDouglas Gregor M != MEnd; ++M) { 150d44252ecSDouglas Gregor if (Skipped.insert(*M)) 151d44252ecSDouglas Gregor Stack.push_back(*M); 152d44252ecSDouglas Gregor } 153d44252ecSDouglas Gregor } 154d44252ecSDouglas Gregor continue; 155d44252ecSDouglas Gregor } 156d44252ecSDouglas Gregor 157d44252ecSDouglas Gregor // For any module that this module depends on, push it on the 158d44252ecSDouglas Gregor // stack (if it hasn't already been marked as visited). 159de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(), 160d44252ecSDouglas Gregor MEnd = CurrentModule->Imports.end(); 161d44252ecSDouglas Gregor M != MEnd; ++M) { 162d44252ecSDouglas Gregor 163d44252ecSDouglas Gregor // Remove our current module as an impediment to visiting the 164d44252ecSDouglas Gregor // module we depend on. If we were the last unvisited module 165d44252ecSDouglas Gregor // that depends on this particular module, push it into the 166d44252ecSDouglas Gregor // queue to be visited. 167d44252ecSDouglas Gregor unsigned &NumUnusedEdges = UnusedIncomingEdges[*M]; 168d44252ecSDouglas Gregor if (NumUnusedEdges && (--NumUnusedEdges == 0)) 169d44252ecSDouglas Gregor Queue.push_back(*M); 170d44252ecSDouglas Gregor } 171d44252ecSDouglas Gregor } 172d44252ecSDouglas Gregor } 173d44252ecSDouglas Gregor 174d44252ecSDouglas Gregor /// \brief Perform a depth-first visit of the current module. 175de3ef502SDouglas Gregor static bool visitDepthFirst(ModuleFile &M, 176de3ef502SDouglas Gregor bool (*Visitor)(ModuleFile &M, bool Preorder, 177d44252ecSDouglas Gregor void *UserData), 178d44252ecSDouglas Gregor void *UserData, 179de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> &Visited) { 180d44252ecSDouglas Gregor // Preorder visitation 181d44252ecSDouglas Gregor if (Visitor(M, /*Preorder=*/true, UserData)) 182d44252ecSDouglas Gregor return true; 183d44252ecSDouglas Gregor 184d44252ecSDouglas Gregor // Visit children 185de3ef502SDouglas Gregor for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(), 186d44252ecSDouglas Gregor IMEnd = M.Imports.end(); 187d44252ecSDouglas Gregor IM != IMEnd; ++IM) { 188d44252ecSDouglas Gregor if (!Visited.insert(*IM)) 189d44252ecSDouglas Gregor continue; 190d44252ecSDouglas Gregor 191d44252ecSDouglas Gregor if (visitDepthFirst(**IM, Visitor, UserData, Visited)) 192d44252ecSDouglas Gregor return true; 193d44252ecSDouglas Gregor } 194d44252ecSDouglas Gregor 195d44252ecSDouglas Gregor // Postorder visitation 196d44252ecSDouglas Gregor return Visitor(M, /*Preorder=*/false, UserData); 197d44252ecSDouglas Gregor } 198d44252ecSDouglas Gregor 199de3ef502SDouglas Gregor void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, 200d44252ecSDouglas Gregor void *UserData), 201d44252ecSDouglas Gregor void *UserData) { 202de3ef502SDouglas Gregor llvm::SmallPtrSet<ModuleFile *, 4> Visited; 203d44252ecSDouglas Gregor for (unsigned I = 0, N = Chain.size(); I != N; ++I) { 204d44252ecSDouglas Gregor if (!Visited.insert(Chain[I])) 205d44252ecSDouglas Gregor continue; 206d44252ecSDouglas Gregor 207d44252ecSDouglas Gregor if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited)) 208d44252ecSDouglas Gregor return; 209d44252ecSDouglas Gregor } 210d44252ecSDouglas Gregor } 2119d7c1a2aSDouglas Gregor 2129d7c1a2aSDouglas Gregor #ifndef NDEBUG 2139d7c1a2aSDouglas Gregor namespace llvm { 2149d7c1a2aSDouglas Gregor template<> 2159d7c1a2aSDouglas Gregor struct GraphTraits<ModuleManager> { 216de3ef502SDouglas Gregor typedef ModuleFile NodeType; 217de3ef502SDouglas Gregor typedef llvm::SetVector<ModuleFile *>::const_iterator ChildIteratorType; 2189d7c1a2aSDouglas Gregor typedef ModuleManager::ModuleConstIterator nodes_iterator; 2199d7c1a2aSDouglas Gregor 2209d7c1a2aSDouglas Gregor static ChildIteratorType child_begin(NodeType *Node) { 2219d7c1a2aSDouglas Gregor return Node->Imports.begin(); 2229d7c1a2aSDouglas Gregor } 2239d7c1a2aSDouglas Gregor 2249d7c1a2aSDouglas Gregor static ChildIteratorType child_end(NodeType *Node) { 2259d7c1a2aSDouglas Gregor return Node->Imports.end(); 2269d7c1a2aSDouglas Gregor } 2279d7c1a2aSDouglas Gregor 2289d7c1a2aSDouglas Gregor static nodes_iterator nodes_begin(const ModuleManager &Manager) { 2299d7c1a2aSDouglas Gregor return Manager.begin(); 2309d7c1a2aSDouglas Gregor } 2319d7c1a2aSDouglas Gregor 2329d7c1a2aSDouglas Gregor static nodes_iterator nodes_end(const ModuleManager &Manager) { 2339d7c1a2aSDouglas Gregor return Manager.end(); 2349d7c1a2aSDouglas Gregor } 2359d7c1a2aSDouglas Gregor }; 2369d7c1a2aSDouglas Gregor 2379d7c1a2aSDouglas Gregor template<> 2389d7c1a2aSDouglas Gregor struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { 2399d7c1a2aSDouglas Gregor explicit DOTGraphTraits(bool IsSimple = false) 2409d7c1a2aSDouglas Gregor : DefaultDOTGraphTraits(IsSimple) { } 2419d7c1a2aSDouglas Gregor 2429d7c1a2aSDouglas Gregor static bool renderGraphFromBottomUp() { 2439d7c1a2aSDouglas Gregor return true; 2449d7c1a2aSDouglas Gregor } 2459d7c1a2aSDouglas Gregor 246de3ef502SDouglas Gregor std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { 2479d7c1a2aSDouglas Gregor return llvm::sys::path::stem(M->FileName); 2489d7c1a2aSDouglas Gregor } 2499d7c1a2aSDouglas Gregor }; 2509d7c1a2aSDouglas Gregor } 2519d7c1a2aSDouglas Gregor 2529d7c1a2aSDouglas Gregor void ModuleManager::viewGraph() { 2539d7c1a2aSDouglas Gregor llvm::ViewGraph(*this, "Modules"); 2549d7c1a2aSDouglas Gregor } 2559d7c1a2aSDouglas Gregor #endif 256