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