Optimize unqualified/global name lookup in modules by introducing a

generational scheme for identifiers that avoids searching the hash
tables of a given module more than once for a given
identifier. Previously, loading any new module invalidated all of the
previous lookup results for all identifiers, causing us to perform the
lookups repeatedly.

llvm-svn: 148412
This commit is contained in:
Douglas Gregor 2012-01-18 20:56:22 +00:00
parent c3cc110bb4
commit 4fc9f3e819
6 changed files with 60 additions and 17 deletions

View File

@ -579,6 +579,10 @@ private:
/// \brief Whether to disable the use of stat caches in AST files.
bool DisableStatCache;
/// \brief The current "generation" of the module file import stack, which
/// indicates how many separate module file load operations have occurred.
unsigned CurrentGeneration;
/// \brief Mapping from switch-case IDs in the chain to switch-case statements
///
/// Statements usually don't have IDs, but switch cases need them, so that the
@ -652,6 +656,9 @@ private:
/// loaded once the recursive loading has completed.
std::deque<PendingIdentifierInfo> PendingIdentifierInfos;
/// \brief The generation number of
llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;
/// \brief Contains declarations and definitions that will be
/// "interesting" to the ASTConsumer, when we get that AST consumer.
///
@ -1432,6 +1439,9 @@ public:
/// \brief Update an out-of-date identifier.
virtual void updateOutOfDateIdentifier(IdentifierInfo &II);
/// \brief Note that this identifier is up-to-date.
void markIdentifierUpToDate(IdentifierInfo *II);
/// \brief Read the macro definition corresponding to this iterator
/// into the unread macro record offsets table.
void LoadMacroDefinition(

View File

@ -57,7 +57,7 @@ struct DeclContextInfo {
/// other modules.
class ModuleFile {
public:
ModuleFile(ModuleKind Kind);
ModuleFile(ModuleKind Kind, unsigned Generation);
~ModuleFile();
// === General information ===
@ -72,6 +72,9 @@ public:
/// user.
bool DirectlyImported;
/// \brief The generation of which this module file is a part.
unsigned Generation;
/// \brief The memory buffer that stores the data associated with
/// this AST file.
llvm::OwningPtr<llvm::MemoryBuffer> Buffer;

View File

@ -95,6 +95,8 @@ public:
/// \param ImportedBy The module that is importing this module, or NULL if
/// this module is imported directly by the user.
///
/// \param Generation The generation in which this module was loaded.
///
/// \param ErrorStr Will be set to a non-empty string if any errors occurred
/// while trying to load the module.
///
@ -102,7 +104,7 @@ public:
/// and a boolean indicating whether the module was newly added.
std::pair<ModuleFile *, bool>
addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy,
std::string &ErrorStr);
unsigned Generation, std::string &ErrorStr);
/// \brief Add an in-memory buffer the list of known buffers
void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);

View File

@ -514,7 +514,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
Reader.SetIdentifierInfo(ID, II);
II->setIsFromAST();
II->setOutOfDate(false);
Reader.markIdentifierUpToDate(II);
return II;
}
@ -540,7 +540,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
IdentifierInfo *II = KnownII;
if (!II)
II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
II->setOutOfDate(false);
Reader.markIdentifierUpToDate(II);
II->setIsFromAST();
// Set or check the various bits in the IdentifierInfo structure.
@ -1560,14 +1560,20 @@ namespace {
/// \brief Visitor class used to look up identifirs in an AST file.
class IdentifierLookupVisitor {
StringRef Name;
unsigned PriorGeneration;
IdentifierInfo *Found;
public:
explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { }
IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
: Name(Name), PriorGeneration(PriorGeneration), Found() { }
static bool visit(ModuleFile &M, void *UserData) {
IdentifierLookupVisitor *This
= static_cast<IdentifierLookupVisitor *>(UserData);
// If we've already searched this module file, skip it now.
if (M.Generation <= This->PriorGeneration)
return true;
ASTIdentifierLookupTable *IdTable
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
if (!IdTable)
@ -1593,7 +1599,24 @@ namespace {
}
void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
get(II.getName());
unsigned PriorGeneration = 0;
if (getContext().getLangOptions().Modules)
PriorGeneration = IdentifierGeneration[&II];
IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
markIdentifierUpToDate(&II);
}
void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
if (!II)
return;
II->setOutOfDate(false);
// Update the generation for this identifier.
if (getContext().getLangOptions().Modules)
IdentifierGeneration[II] = CurrentGeneration;
}
const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {
@ -2612,6 +2635,9 @@ void ASTReader::makeModuleVisible(Module *Mod,
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type) {
// Bump the generation number.
++CurrentGeneration;
switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) {
case Failure: return Failure;
case IgnorePCH: return IgnorePCH;
@ -2619,7 +2645,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
}
// Here comes stuff that we only do once the entire chain is loaded.
// Check the predefines buffers.
if (!DisableValidation && Type == MK_PCH &&
// FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
@ -2635,7 +2661,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
IdEnd = PP.getIdentifierTable().end();
Id != IdEnd; ++Id)
Id->second->setOutOfDate(true);
// Resolve any unresolved module exports.
for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
@ -2683,7 +2709,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
bool NewModule;
std::string ErrorStr;
llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
ErrorStr);
CurrentGeneration, ErrorStr);
if (!M) {
// We couldn't load the module.
@ -5109,11 +5135,11 @@ void ASTReader::InitializeSema(Sema &S) {
}
IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {
IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart));
IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart),
/*PriorGeneration=*/0);
ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
IdentifierInfo *II = Visitor.getIdentifierInfo();
if (II)
II->setOutOfDate(false);
markIdentifierUpToDate(II);
return II;
}
@ -6236,7 +6262,8 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()),
RelocatablePCH(false), isysroot(isysroot),
DisableValidation(DisableValidation),
DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0),
DisableStatCache(DisableStatCache),
CurrentGeneration(0), NumStatHits(0), NumStatMisses(0),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),

View File

@ -20,8 +20,8 @@ using namespace clang;
using namespace serialization;
using namespace reader;
ModuleFile::ModuleFile(ModuleKind Kind)
: Kind(Kind), DirectlyImported(false), SizeInBits(0),
ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
: Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0),
LocalNumSLocEntries(0), SLocEntryBaseID(0),
SLocEntryBaseOffset(0), SLocEntryOffsets(0),
SLocFileOffsets(0), LocalNumIdentifiers(0),

View File

@ -35,7 +35,8 @@ llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
std::pair<ModuleFile *, bool>
ModuleManager::addModule(StringRef FileName, ModuleKind Type,
ModuleFile *ImportedBy, std::string &ErrorStr) {
ModuleFile *ImportedBy, unsigned Generation,
std::string &ErrorStr) {
const FileEntry *Entry = FileMgr.getFile(FileName);
if (!Entry && FileName != "-") {
ErrorStr = "file not found";
@ -47,7 +48,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
bool NewModule = false;
if (!ModuleEntry) {
// Allocate a new module.
ModuleFile *New = new ModuleFile(Type);
ModuleFile *New = new ModuleFile(Type, Generation);
New->FileName = FileName.str();
Chain.push_back(New);
NewModule = true;