forked from OSchip/llvm-project
Allow skipping imports in the module visitor.
Skip imports when we know that we do not need to visit any imports because we've already deserialized the redecls from a module. llvm-svn: 237782
This commit is contained in:
parent
38810f430b
commit
9eff8b1426
|
@ -33,6 +33,10 @@ class ModuleManager {
|
||||||
/// user, the last one is the one that doesn't depend on anything further.
|
/// user, the last one is the one that doesn't depend on anything further.
|
||||||
SmallVector<ModuleFile *, 2> Chain;
|
SmallVector<ModuleFile *, 2> Chain;
|
||||||
|
|
||||||
|
// \brief The roots of the dependency DAG of AST files. This is used
|
||||||
|
// to implement short-circuiting logic when running DFS over the dependencies.
|
||||||
|
SmallVector<ModuleFile *, 2> Roots;
|
||||||
|
|
||||||
/// \brief All loaded modules, indexed by name.
|
/// \brief All loaded modules, indexed by name.
|
||||||
llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;
|
llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;
|
||||||
|
|
||||||
|
@ -265,24 +269,34 @@ public:
|
||||||
void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData,
|
void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData,
|
||||||
llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit = nullptr);
|
llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit = nullptr);
|
||||||
|
|
||||||
|
/// \brief Control DFS behavior during preorder visitation.
|
||||||
|
enum DFSPreorderControl {
|
||||||
|
Continue, /// Continue visiting all nodes.
|
||||||
|
Abort, /// Stop the visitation immediately.
|
||||||
|
SkipImports, /// Do not visit imports of the current node.
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Visit each of the modules with a depth-first traversal.
|
/// \brief Visit each of the modules with a depth-first traversal.
|
||||||
///
|
///
|
||||||
/// This routine visits each of the modules known to the module
|
/// This routine visits each of the modules known to the module
|
||||||
/// manager using a depth-first search, starting with the first
|
/// manager using a depth-first search, starting with the first
|
||||||
/// loaded module. The traversal invokes the callback both before
|
/// loaded module. The traversal invokes one callback before
|
||||||
/// traversing the children (preorder traversal) and after
|
/// traversing the imports (preorder traversal) and one after
|
||||||
/// traversing the children (postorder traversal).
|
/// traversing the imports (postorder traversal).
|
||||||
///
|
///
|
||||||
/// \param Visitor A visitor function that will be invoked with each
|
/// \param PreorderVisitor A visitor function that will be invoked with each
|
||||||
/// module and given a \c Preorder flag that indicates whether we're
|
/// module before visiting its imports. The visitor can control how to
|
||||||
/// visiting the module before or after visiting its children. The
|
/// continue the visitation through its return value.
|
||||||
/// visitor may return true at any time to abort the depth-first
|
///
|
||||||
/// visitation.
|
/// \param PostorderVisitor A visitor function taht will be invoked with each
|
||||||
|
/// module after visiting its imports. The visitor may return true at any time
|
||||||
|
/// to abort the depth-first visitation.
|
||||||
///
|
///
|
||||||
/// \param UserData User data ssociated with the visitor object,
|
/// \param UserData User data ssociated with the visitor object,
|
||||||
/// which will be passed along to the user.
|
/// which will be passed along to the user.
|
||||||
void visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
|
void visitDepthFirst(DFSPreorderControl (*PreorderVisitor)(ModuleFile &M,
|
||||||
void *UserData),
|
void *UserData),
|
||||||
|
bool (*PostorderVisitor)(ModuleFile &M, void *UserData),
|
||||||
void *UserData);
|
void *UserData);
|
||||||
|
|
||||||
/// \brief Attempt to resolve the given module file name to a file entry.
|
/// \brief Attempt to resolve the given module file name to a file entry.
|
||||||
|
|
|
@ -6157,10 +6157,7 @@ namespace {
|
||||||
PredefsVisited[I] = false;
|
PredefsVisited[I] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
|
static bool visitPostorder(ModuleFile &M, void *UserData) {
|
||||||
if (Preorder)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FindExternalLexicalDeclsVisitor *This
|
FindExternalLexicalDeclsVisitor *This
|
||||||
= static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
|
= static_cast<FindExternalLexicalDeclsVisitor *>(UserData);
|
||||||
|
|
||||||
|
@ -6202,7 +6199,8 @@ ExternalLoadResult ASTReader::FindExternalLexicalDecls(const DeclContext *DC,
|
||||||
// There might be lexical decls in multiple modules, for the TU at
|
// There might be lexical decls in multiple modules, for the TU at
|
||||||
// least. Walk all of the modules in the order they were loaded.
|
// least. Walk all of the modules in the order they were loaded.
|
||||||
FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
|
FindExternalLexicalDeclsVisitor Visitor(*this, DC, isKindWeWant, Decls);
|
||||||
ModuleMgr.visitDepthFirst(&FindExternalLexicalDeclsVisitor::visit, &Visitor);
|
ModuleMgr.visitDepthFirst(
|
||||||
|
nullptr, &FindExternalLexicalDeclsVisitor::visitPostorder, &Visitor);
|
||||||
++NumLexicalDeclContextsRead;
|
++NumLexicalDeclContextsRead;
|
||||||
return ELR_Success;
|
return ELR_Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3311,11 +3311,13 @@ namespace {
|
||||||
addToChain(Reader.GetDecl(CanonID));
|
addToChain(Reader.GetDecl(CanonID));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
|
static ModuleManager::DFSPreorderControl
|
||||||
if (Preorder)
|
visitPreorder(ModuleFile &M, void *UserData) {
|
||||||
return false;
|
return static_cast<RedeclChainVisitor *>(UserData)->visitPreorder(M);
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<RedeclChainVisitor *>(UserData)->visit(M);
|
static bool visitPostorder(ModuleFile &M, void *UserData) {
|
||||||
|
return static_cast<RedeclChainVisitor *>(UserData)->visitPostorder(M);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addToChain(Decl *D) {
|
void addToChain(Decl *D) {
|
||||||
|
@ -3369,7 +3371,35 @@ namespace {
|
||||||
addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
|
addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit(ModuleFile &M) {
|
bool needsToVisitImports(ModuleFile &M, GlobalDeclID GlobalID) {
|
||||||
|
DeclID ID = Reader.mapGlobalIDToModuleFileGlobalID(M, GlobalID);
|
||||||
|
if (!ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const LocalRedeclarationsInfo Compare = {ID, 0};
|
||||||
|
const LocalRedeclarationsInfo *Result = std::lower_bound(
|
||||||
|
M.RedeclarationsMap,
|
||||||
|
M.RedeclarationsMap + M.LocalNumRedeclarationsInMap, Compare);
|
||||||
|
if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
|
||||||
|
Result->FirstID != ID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
unsigned Offset = Result->Offset;
|
||||||
|
unsigned N = M.RedeclarationChains[Offset];
|
||||||
|
// We don't need to visit a module or any of its imports if we've already
|
||||||
|
// deserialized the redecls from this module.
|
||||||
|
return N != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleManager::DFSPreorderControl visitPreorder(ModuleFile &M) {
|
||||||
|
for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I) {
|
||||||
|
if (needsToVisitImports(M, SearchDecls[I]))
|
||||||
|
return ModuleManager::Continue;
|
||||||
|
}
|
||||||
|
return ModuleManager::SkipImports;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool visitPostorder(ModuleFile &M) {
|
||||||
// Visit each of the declarations.
|
// Visit each of the declarations.
|
||||||
for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
|
for (unsigned I = 0, N = SearchDecls.size(); I != N; ++I)
|
||||||
searchForID(M, SearchDecls[I]);
|
searchForID(M, SearchDecls[I]);
|
||||||
|
@ -3401,11 +3431,12 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
|
||||||
|
|
||||||
// Build up the list of redeclarations.
|
// Build up the list of redeclarations.
|
||||||
RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
|
RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
|
||||||
ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor);
|
ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visitPreorder,
|
||||||
|
&RedeclChainVisitor::visitPostorder, &Visitor);
|
||||||
|
|
||||||
// Retrieve the chains.
|
// Retrieve the chains.
|
||||||
ArrayRef<Decl *> Chain = Visitor.getChain();
|
ArrayRef<Decl *> Chain = Visitor.getChain();
|
||||||
if (Chain.empty())
|
if (Chain.empty() || (Chain.size() == 1 && Chain[0] == CanonDecl))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Hook up the chains.
|
// Hook up the chains.
|
||||||
|
|
|
@ -94,6 +94,8 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
|
||||||
New->File = Entry;
|
New->File = Entry;
|
||||||
New->ImportLoc = ImportLoc;
|
New->ImportLoc = ImportLoc;
|
||||||
Chain.push_back(New);
|
Chain.push_back(New);
|
||||||
|
if (!ImportedBy)
|
||||||
|
Roots.push_back(New);
|
||||||
NewModule = true;
|
NewModule = true;
|
||||||
ModuleEntry = New;
|
ModuleEntry = New;
|
||||||
|
|
||||||
|
@ -155,7 +157,12 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
|
||||||
// invalidate the file cache for Entry, and that is not safe if this
|
// invalidate the file cache for Entry, and that is not safe if this
|
||||||
// module is *itself* up to date, but has an out-of-date importer.
|
// module is *itself* up to date, but has an out-of-date importer.
|
||||||
Modules.erase(Entry);
|
Modules.erase(Entry);
|
||||||
|
assert(Chain.back() == ModuleEntry);
|
||||||
Chain.pop_back();
|
Chain.pop_back();
|
||||||
|
if (Roots.back() == ModuleEntry)
|
||||||
|
Roots.pop_back();
|
||||||
|
else
|
||||||
|
assert(ImportedBy);
|
||||||
delete ModuleEntry;
|
delete ModuleEntry;
|
||||||
}
|
}
|
||||||
return OutOfDate;
|
return OutOfDate;
|
||||||
|
@ -186,12 +193,15 @@ void ModuleManager::removeModules(
|
||||||
// Collect the set of module file pointers that we'll be removing.
|
// Collect the set of module file pointers that we'll be removing.
|
||||||
llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
|
llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last);
|
||||||
|
|
||||||
|
auto IsVictim = [&](ModuleFile *MF) {
|
||||||
|
return victimSet.count(MF);
|
||||||
|
};
|
||||||
// Remove any references to the now-destroyed modules.
|
// Remove any references to the now-destroyed modules.
|
||||||
for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
|
for (unsigned i = 0, n = Chain.size(); i != n; ++i) {
|
||||||
Chain[i]->ImportedBy.remove_if([&](ModuleFile *MF) {
|
Chain[i]->ImportedBy.remove_if(IsVictim);
|
||||||
return victimSet.count(MF);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
|
||||||
|
Roots.end());
|
||||||
|
|
||||||
// Delete the modules and erase them from the various structures.
|
// Delete the modules and erase them from the various structures.
|
||||||
for (ModuleIterator victim = first; victim != last; ++victim) {
|
for (ModuleIterator victim = first; victim != last; ++victim) {
|
||||||
|
@ -398,15 +408,37 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
|
||||||
returnVisitState(State);
|
returnVisitState(State);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Perform a depth-first visit of the current module.
|
static void markVisitedDepthFirst(ModuleFile &M,
|
||||||
static bool visitDepthFirst(ModuleFile &M,
|
|
||||||
bool (*Visitor)(ModuleFile &M, bool Preorder,
|
|
||||||
void *UserData),
|
|
||||||
void *UserData,
|
|
||||||
SmallVectorImpl<bool> &Visited) {
|
SmallVectorImpl<bool> &Visited) {
|
||||||
// Preorder visitation
|
for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
|
||||||
if (Visitor(M, /*Preorder=*/true, UserData))
|
IMEnd = M.Imports.end();
|
||||||
|
IM != IMEnd; ++IM) {
|
||||||
|
if (Visited[(*IM)->Index])
|
||||||
|
continue;
|
||||||
|
Visited[(*IM)->Index] = true;
|
||||||
|
if (!M.DirectlyImported)
|
||||||
|
markVisitedDepthFirst(**IM, Visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Perform a depth-first visit of the current module.
|
||||||
|
static bool visitDepthFirst(
|
||||||
|
ModuleFile &M,
|
||||||
|
ModuleManager::DFSPreorderControl (*PreorderVisitor)(ModuleFile &M,
|
||||||
|
void *UserData),
|
||||||
|
bool (*PostorderVisitor)(ModuleFile &M, void *UserData), void *UserData,
|
||||||
|
SmallVectorImpl<bool> &Visited) {
|
||||||
|
if (PreorderVisitor) {
|
||||||
|
switch (PreorderVisitor(M, UserData)) {
|
||||||
|
case ModuleManager::Abort:
|
||||||
return true;
|
return true;
|
||||||
|
case ModuleManager::SkipImports:
|
||||||
|
markVisitedDepthFirst(M, Visited);
|
||||||
|
return false;
|
||||||
|
case ModuleManager::Continue:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Visit children
|
// Visit children
|
||||||
for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
|
for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
|
||||||
|
@ -416,24 +448,27 @@ static bool visitDepthFirst(ModuleFile &M,
|
||||||
continue;
|
continue;
|
||||||
Visited[(*IM)->Index] = true;
|
Visited[(*IM)->Index] = true;
|
||||||
|
|
||||||
if (visitDepthFirst(**IM, Visitor, UserData, Visited))
|
if (visitDepthFirst(**IM, PreorderVisitor, PostorderVisitor, UserData, Visited))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Postorder visitation
|
if (PostorderVisitor)
|
||||||
return Visitor(M, /*Preorder=*/false, UserData);
|
return PostorderVisitor(M, UserData);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
|
void ModuleManager::visitDepthFirst(
|
||||||
|
ModuleManager::DFSPreorderControl (*PreorderVisitor)(ModuleFile &M,
|
||||||
void *UserData),
|
void *UserData),
|
||||||
void *UserData) {
|
bool (*PostorderVisitor)(ModuleFile &M, void *UserData), void *UserData) {
|
||||||
SmallVector<bool, 16> Visited(size(), false);
|
SmallVector<bool, 16> Visited(size(), false);
|
||||||
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
|
for (unsigned I = 0, N = Roots.size(); I != N; ++I) {
|
||||||
if (Visited[Chain[I]->Index])
|
if (Visited[Roots[I]->Index])
|
||||||
continue;
|
continue;
|
||||||
Visited[Chain[I]->Index] = true;
|
Visited[Roots[I]->Index] = true;
|
||||||
|
|
||||||
if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
|
if (::visitDepthFirst(*Roots[I], PreorderVisitor, PostorderVisitor, UserData, Visited))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue