[cfe-commits] r125670 - in /cfe/trunk: include/clang/Frontend/ASTUnit.h lib/Frontend/ASTUnit.cpp
Douglas Gregor
dgregor at apple.com
Wed Feb 16 10:16:54 PST 2011
Author: dgregor
Date: Wed Feb 16 12:16:54 2011
New Revision: 125670
URL: http://llvm.org/viewvc/llvm-project?rev=125670&view=rev
Log:
Improve the invalidation logic for the cache of global code
completions. We now compute a hash of the names of all top-level
declarations and macro definitions, and invalidate the cache when the
hash value changes.
Modified:
cfe/trunk/include/clang/Frontend/ASTUnit.h
cfe/trunk/lib/Frontend/ASTUnit.cpp
Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=125670&r1=125669&r2=125670&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Wed Feb 16 12:16:54 2011
@@ -298,20 +298,24 @@
/// type, which is used for type equality comparisons.
llvm::StringMap<unsigned> CachedCompletionTypes;
- /// \brief The number of top-level declarations present the last time we
- /// cached code-completion results.
+ /// \brief A string hash of the top-level declaration and macro definition
+ /// names processed the last time that we reparsed the file.
///
- /// The value is used to help detect when we should repopulate the global
- /// completion cache.
- unsigned NumTopLevelDeclsAtLastCompletionCache;
-
- /// \brief The number of reparses left until we'll consider updating the
- /// code-completion cache.
- ///
- /// This is meant to avoid thrashing during reparsing, by not allowing the
- /// code-completion cache to be updated on every reparse.
- unsigned CacheCodeCompletionCoolDown;
-
+ /// This hash value is used to determine when we need to refresh the
+ /// global code-completion cache.
+ unsigned CompletionCacheTopLevelHashValue;
+
+ /// \brief A string hash of the top-level declaration and macro definition
+ /// names processed the last time that we reparsed the precompiled preamble.
+ ///
+ /// This hash value is used to determine when we need to refresh the
+ /// global code-completion cache after a rebuild of the precompiled preamble.
+ unsigned PreambleTopLevelHashValue;
+
+ /// \brief The current hash value for the top-level declaration and macro
+ /// definition names
+ unsigned CurrentTopLevelHashValue;
+
/// \brief Bit used by CIndex to mark when a translation unit may be in an
/// inconsistent state, and is not safe to free.
unsigned UnsafeToFree : 1;
@@ -450,6 +454,11 @@
TopLevelDeclsInPreamble.push_back(D);
}
+ /// \brief Retrieve a reference to the current top-level name hash value.
+ ///
+ /// Note: This is used internally by the top-level tracking action
+ unsigned &getCurrentTopLevelHashValue() { return CurrentTopLevelHashValue; }
+
typedef std::vector<PreprocessedEntity *>::iterator pp_entity_iterator;
pp_entity_iterator pp_entity_begin();
Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=125670&r1=125669&r2=125670&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Wed Feb 16 12:16:54 2011
@@ -34,6 +34,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Atomic.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -95,8 +96,9 @@
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
- NumTopLevelDeclsAtLastCompletionCache(0),
- CacheCodeCompletionCoolDown(0),
+ CompletionCacheTopLevelHashValue(0),
+ PreambleTopLevelHashValue(0),
+ CurrentTopLevelHashValue(0),
UnsafeToFree(false) {
if (getenv("LIBCLANG_OBJTRACKING")) {
llvm::sys::AtomicIncrement(&ActiveASTUnitObjects);
@@ -343,9 +345,9 @@
}
}
}
-
- // Make a note of the state when we performed this caching.
- NumTopLevelDeclsAtLastCompletionCache = top_level_size();
+
+ // Save the current top-level hash value.
+ CompletionCacheTopLevelHashValue = CurrentTopLevelHashValue;
}
void ASTUnit::ClearCachedCompletionResults() {
@@ -603,12 +605,69 @@
namespace {
+/// \brief Preprocessor callback class that updates a hash value with the names
+/// of all macros that have been defined by the translation unit.
+class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
+ unsigned &Hash;
+
+public:
+ explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
+
+ virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
+ }
+};
+
+/// \brief Add the given declaration to the hash of all top-level entities.
+void AddTopLevelDeclarationToHash(Decl *D, unsigned &Hash) {
+ if (!D)
+ return;
+
+ DeclContext *DC = D->getDeclContext();
+ if (!DC)
+ return;
+
+ if (!(DC->isTranslationUnit() || DC->getLookupParent()->isTranslationUnit()))
+ return;
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ if (ND->getIdentifier())
+ Hash = llvm::HashString(ND->getIdentifier()->getName(), Hash);
+ else if (DeclarationName Name = ND->getDeclName()) {
+ std::string NameStr = Name.getAsString();
+ Hash = llvm::HashString(NameStr, Hash);
+ }
+ return;
+ }
+
+ if (ObjCForwardProtocolDecl *Forward
+ = dyn_cast<ObjCForwardProtocolDecl>(D)) {
+ for (ObjCForwardProtocolDecl::protocol_iterator
+ P = Forward->protocol_begin(),
+ PEnd = Forward->protocol_end();
+ P != PEnd; ++P)
+ AddTopLevelDeclarationToHash(*P, Hash);
+ return;
+ }
+
+ if (ObjCClassDecl *Class = llvm::dyn_cast<ObjCClassDecl>(D)) {
+ for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
+ I != IEnd; ++I)
+ AddTopLevelDeclarationToHash(I->getInterface(), Hash);
+ return;
+ }
+}
+
class TopLevelDeclTrackerConsumer : public ASTConsumer {
ASTUnit &Unit;
-
+ unsigned &Hash;
+
public:
- TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {}
-
+ TopLevelDeclTrackerConsumer(ASTUnit &_Unit, unsigned &Hash)
+ : Unit(_Unit), Hash(Hash) {
+ Hash = 0;
+ }
+
void HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
Decl *D = *it;
@@ -618,6 +677,8 @@
// fundamental problem in the parser right now.
if (isa<ObjCMethodDecl>(D))
continue;
+
+ AddTopLevelDeclarationToHash(D, Hash);
Unit.addTopLevelDecl(D);
}
}
@@ -632,7 +693,10 @@
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef InFile) {
- return new TopLevelDeclTrackerConsumer(Unit);
+ CI.getPreprocessor().addPPCallbacks(
+ new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
+ return new TopLevelDeclTrackerConsumer(Unit,
+ Unit.getCurrentTopLevelHashValue());
}
public:
@@ -647,13 +711,17 @@
class PrecompilePreambleConsumer : public PCHGenerator,
public ASTSerializationListener {
ASTUnit &Unit;
+ unsigned &Hash;
std::vector<Decl *> TopLevelDecls;
public:
PrecompilePreambleConsumer(ASTUnit &Unit,
const Preprocessor &PP, bool Chaining,
const char *isysroot, llvm::raw_ostream *Out)
- : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit) { }
+ : PCHGenerator(PP, "", Chaining, isysroot, Out), Unit(Unit),
+ Hash(Unit.getCurrentTopLevelHashValue()) {
+ Hash = 0;
+ }
virtual void HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) {
@@ -664,6 +732,7 @@
// fundamental problem in the parser right now.
if (isa<ObjCMethodDecl>(D))
continue;
+ AddTopLevelDeclarationToHash(D, Hash);
TopLevelDecls.push_back(D);
}
}
@@ -710,6 +779,8 @@
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
Sysroot.c_str() : 0;
+ CI.getPreprocessor().addPPCallbacks(
+ new MacroDefinitionTrackerPPCallbacks(Unit.getCurrentTopLevelHashValue()));
return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining,
isysroot, OS);
}
@@ -856,14 +927,6 @@
}
Invocation.reset(Clang.takeInvocation());
-
- if (ShouldCacheCodeCompletionResults) {
- if (CacheCodeCompletionCoolDown > 0)
- --CacheCodeCompletionCoolDown;
- else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache)
- CacheCodeCompletionResults();
- }
-
return false;
error:
@@ -1336,6 +1399,15 @@
PreambleRebuildCounter = 1;
PreprocessorOpts.eraseRemappedFile(
PreprocessorOpts.remapped_file_buffer_end() - 1);
+
+ // If the hash of top-level entities differs from the hash of the top-level
+ // entities the last time we rebuilt the preamble, clear out the completion
+ // cache.
+ if (CurrentTopLevelHashValue != PreambleTopLevelHashValue) {
+ CompletionCacheTopLevelHashValue = 0;
+ PreambleTopLevelHashValue = CurrentTopLevelHashValue;
+ }
+
return CreatePaddedMainFileBuffer(NewPreamble.first,
PreambleReservedSize,
FrontendOpts.Inputs[0].second);
@@ -1458,7 +1530,6 @@
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
- AST->CacheCodeCompletionCoolDown = 1;
AST->Invocation.reset(CI);
return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
@@ -1566,7 +1637,6 @@
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
- AST->CacheCodeCompletionCoolDown = 1;
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
@@ -1609,7 +1679,14 @@
}
// Parse the sources
- bool Result = Parse(OverrideMainBuffer);
+ bool Result = Parse(OverrideMainBuffer);
+
+ // If we're caching global code-completion results, and the top-level
+ // declarations have changed, clear out the code-completion cache.
+ if (!Result && ShouldCacheCodeCompletionResults &&
+ CurrentTopLevelHashValue != CompletionCacheTopLevelHashValue)
+ CacheCodeCompletionResults();
+
return Result;
}
More information about the cfe-commits
mailing list