yvvan created this revision.
yvvan added reviewers: ilya-biryukov, arphaman, erikjv.
In case two translation units are created for the same file - reuse preamble
data to reduce memory and save time on extra preamble generation.
https://reviews.llvm.org/D48314
Files:
include/clang/Frontend/ASTUnit.h
lib/Frontend/ASTUnit.cpp
Index: lib/Frontend/ASTUnit.cpp
===================================================================
--- lib/Frontend/ASTUnit.cpp
+++ lib/Frontend/ASTUnit.cpp
@@ -214,6 +214,9 @@
return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath);
}
+std::recursive_mutex ASTUnit::CacheMutex;
+llvm::StringMap<ASTUnit::ASTUnitCache> ASTUnit::ASTUnitCacheMap;
+
struct ASTUnit::ASTWriterData {
SmallString<128> Buffer;
llvm::BitstreamWriter Stream;
@@ -253,6 +256,16 @@
getDiagnostics().getClient()->EndSourceFile();
}
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ StringRef MainFilePath = getMainFileName();
+ if (ASTUnitCacheMap.find(MainFilePath) == ASTUnitCacheMap.end())
+ return;
+
+ if (ASTUnitCacheMap[MainFilePath].getRefCount() == 1)
+ ASTUnitCacheMap.erase(MainFilePath);
+ else
+ ASTUnitCacheMap[MainFilePath].Release();
+
clearFileLevelDecls();
// Free the buffers associated with remapped files. We are required to
@@ -264,13 +277,18 @@
for (const auto &RB : PPOpts.RemappedFileBuffers)
delete RB.second;
}
-
- ClearCachedCompletionResults();
-
+
if (getenv("LIBCLANG_OBJTRACKING"))
fprintf(stderr, "--- %u translation units\n", --ActiveASTUnitObjects);
}
+void ASTUnit::initCache() {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ StringRef MainFilePath = getMainFileName();
+
+ ASTUnitCacheMap[MainFilePath].Retain();
+}
+
void ASTUnit::setPreprocessor(std::shared_ptr<Preprocessor> PP) {
this->PP = std::move(PP);
}
@@ -841,6 +859,8 @@
// Tell the diagnostic client that we have started a source file.
AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP);
+ AST->initCache();
+
return AST;
}
@@ -1079,7 +1099,10 @@
return true;
auto CCInvocation = std::make_shared<CompilerInvocation>(*Invocation);
+ auto MainFilePath = getMainFileName();
if (OverrideMainBuffer) {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ auto &Preamble = ASTUnitCacheMap[MainFilePath].Preamble;
assert(Preamble &&
"No preamble was built, but OverrideMainBuffer is not null");
IntrusiveRefCntPtr<vfs::FileSystem> OldVFS = VFS;
@@ -1147,7 +1170,8 @@
UserFilesAreVolatile);
if (!OverrideMainBuffer) {
checkAndRemoveNonDriverDiags(StoredDiagnostics);
- TopLevelDeclsInPreamble.clear();
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ ASTUnitCacheMap[MainFilePath].TopLevelDeclsInPreamble.clear();
}
// Create a file manager object to provide access to and cache the filesystem.
@@ -1180,11 +1204,16 @@
if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0]))
goto error;
- if (SavedMainFileBuffer)
- TranslateStoredDiagnostics(getFileManager(), getSourceManager(),
- PreambleDiagnostics, StoredDiagnostics);
- else
- PreambleSrcLocCache.clear();
+ {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ if (SavedMainFileBuffer) {
+ TranslateStoredDiagnostics(
+ getFileManager(), getSourceManager(),
+ ASTUnitCacheMap[MainFilePath].PreambleDiagnostics, StoredDiagnostics);
+ } else {
+ ASTUnitCacheMap[MainFilePath].PreambleSrcLocCache.clear();
+ }
+ }
if (!Act->Execute())
goto error;
@@ -1295,38 +1324,41 @@
if (!Bounds.Size)
return nullptr;
- if (Preamble) {
- if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
- VFS.get())) {
- // Okay! We can re-use the precompiled preamble.
-
- // Set the state of the diagnostic object to mimic its state
- // after parsing the preamble.
- getDiagnostics().Reset();
- ProcessWarningOptions(getDiagnostics(),
- PreambleInvocationIn.getDiagnosticOpts());
- getDiagnostics().setNumWarnings(NumWarningsInPreamble);
-
- PreambleRebuildCounter = 1;
- return MainFileBuffer;
- } else {
- Preamble.reset();
- PreambleDiagnostics.clear();
- TopLevelDeclsInPreamble.clear();
- PreambleSrcLocCache.clear();
- PreambleRebuildCounter = 1;
+ {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ auto &Preamble = ASTUnitCacheMap[MainFilePath].Preamble;
+ if (Preamble) {
+ if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
+ VFS.get())) {
+ // Okay! We can re-use the precompiled preamble.
+
+ // Set the state of the diagnostic object to mimic its state
+ // after parsing the preamble.
+ getDiagnostics().Reset();
+ ProcessWarningOptions(getDiagnostics(),
+ PreambleInvocationIn.getDiagnosticOpts());
+ getDiagnostics().setNumWarnings(NumWarningsInPreamble);
+
+ ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter = 1;
+ return MainFileBuffer;
+ } else {
+ Preamble.reset();
+ ASTUnitCacheMap[MainFilePath].PreambleDiagnostics.clear();
+ ASTUnitCacheMap[MainFilePath].TopLevelDeclsInPreamble.clear();
+ ASTUnitCacheMap[MainFilePath].PreambleSrcLocCache.clear();
+ ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter = 1;
+ }
}
- }
- // If the preamble rebuild counter > 1, it's because we previously
- // failed to build a preamble and we're not yet ready to try
- // again. Decrement the counter and return a failure.
- if (PreambleRebuildCounter > 1) {
- --PreambleRebuildCounter;
- return nullptr;
+ // If the preamble rebuild counter > 1, it's because we previously
+ // failed to build a preamble and we're not yet ready to try
+ // again. Decrement the counter and return a failure.
+ if (ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter > 1) {
+ --ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter;
+ return nullptr;
+ }
}
- assert(!Preamble && "No Preamble should be stored at that point");
// If we aren't allowed to rebuild the precompiled preamble, just
// return now.
if (!AllowRebuild)
@@ -1357,54 +1389,61 @@
PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies =
PreviousSkipFunctionBodies;
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
if (NewPreamble) {
- Preamble = std::move(*NewPreamble);
- PreambleRebuildCounter = 1;
+ ASTUnitCacheMap[MainFilePath].Preamble = std::move(*NewPreamble);
+ ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter = 1;
+ assert(ASTUnitCacheMap[MainFilePath].Preamble && "Preamble wasn't built");
} else {
switch (static_cast<BuildPreambleError>(NewPreamble.getError().value())) {
case BuildPreambleError::CouldntCreateTempFile:
case BuildPreambleError::PreambleIsEmpty:
// Try again next time.
- PreambleRebuildCounter = 1;
+ ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter = 1;
return nullptr;
case BuildPreambleError::CouldntCreateTargetInfo:
case BuildPreambleError::BeginSourceFileFailed:
case BuildPreambleError::CouldntEmitPCH:
// These erros are more likely to repeat, retry after some period.
- PreambleRebuildCounter = DefaultPreambleRebuildInterval;
+ ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter = DefaultPreambleRebuildInterval;
return nullptr;
}
llvm_unreachable("unexpected BuildPreambleError");
}
}
- assert(Preamble && "Preamble wasn't built");
-
TopLevelDecls.clear();
- TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
- PreambleTopLevelHashValue = Callbacks.getHash();
+
+ unsigned NewPreambleTopLevelHashValue = Callbacks.getHash();
NumWarningsInPreamble = getDiagnostics().getNumWarnings();
checkAndRemoveNonDriverDiags(NewPreambleDiags);
StoredDiagnostics = std::move(NewPreambleDiags);
- PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ ASTUnitCacheMap[MainFilePath].TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs();
+ ASTUnitCacheMap[MainFilePath].PreambleDiagnostics = std::move(NewPreambleDiagsStandalone);
+
+ auto &PreambleTopLevelHashValue = ASTUnitCacheMap[MainFilePath].PreambleTopLevelHashValue;
// 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) {
+ if (NewPreambleTopLevelHashValue != PreambleTopLevelHashValue) {
CompletionCacheTopLevelHashValue = 0;
- PreambleTopLevelHashValue = CurrentTopLevelHashValue;
+ PreambleTopLevelHashValue = NewPreambleTopLevelHashValue;
}
return MainFileBuffer;
}
void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
- assert(Preamble && "Should only be called when preamble was built");
+ auto MainFilePath = getMainFileName();
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ assert(ASTUnitCacheMap[MainFilePath].Preamble && "Should only be called when preamble was built");
std::vector<Decl *> Resolved;
+ auto &TopLevelDeclsInPreamble = ASTUnitCacheMap[MainFilePath].TopLevelDeclsInPreamble;
Resolved.reserve(TopLevelDeclsInPreamble.size());
ExternalASTSource &Source = *getASTContext().getExternalSource();
for (const auto TopLevelDecl : TopLevelDeclsInPreamble) {
@@ -1480,6 +1519,8 @@
UserFilesAreVolatile);
AST->PCMCache = new MemoryBufferCache;
+ AST->initCache();
+
return AST;
}
@@ -1510,8 +1551,10 @@
}
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
- if (PrecompilePreambleAfterNParses > 0)
- AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses;
+ if (PrecompilePreambleAfterNParses > 0) {
+ std::lock_guard<std::recursive_mutex> Lock(AST->getCacheMutex());
+ AST->getCache().PreambleRebuildCounter = PrecompilePreambleAfterNParses;
+ }
AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->IncludeBriefCommentsInCodeCompletion
@@ -1637,15 +1680,19 @@
assert(VFS && "VFS is null");
+ initCache();
+
// We'll manage file buffers ourselves.
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Invocation->getFrontendOpts().DisableFree = false;
getDiagnostics().Reset();
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (PrecompilePreambleAfterNParses > 0) {
- PreambleRebuildCounter = PrecompilePreambleAfterNParses;
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ ASTUnitCacheMap[getMainFileName()].PreambleRebuildCounter =
+ PrecompilePreambleAfterNParses;
OverrideMainBuffer =
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
getDiagnostics().Reset();
@@ -1823,9 +1870,15 @@
// If we have a preamble file lying around, or if we might try to
// build a precompiled preamble, do so now.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (Preamble || PreambleRebuildCounter > 0)
- OverrideMainBuffer =
- getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS);
+ StringRef MainFilePath = getMainFileName();
+ {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ if (ASTUnitCacheMap[MainFilePath].Preamble ||
+ ASTUnitCacheMap[MainFilePath].PreambleRebuildCounter > 0) {
+ OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
+ PCHContainerOps, *Invocation, VFS);
+ }
+ }
// Clear out the diagnostics state.
FileMgr.reset();
@@ -2122,11 +2175,12 @@
FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts();
CodeCompleteOptions &CodeCompleteOpts = FrontendOpts.CodeCompleteOpts;
PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts();
+ StringRef MainFilePath = getMainFileName();
CodeCompleteOpts.IncludeMacros = IncludeMacros &&
CachedCompletionResults.empty();
- CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns;
CodeCompleteOpts.IncludeGlobals = CachedCompletionResults.empty();
+ CodeCompleteOpts.IncludeCodePatterns = IncludeCodePatterns;
CodeCompleteOpts.IncludeBriefComments = IncludeBriefComments;
CodeCompleteOpts.LoadExternal = Consumer.loadExternal();
CodeCompleteOpts.IncludeFixIts = Consumer.includeFixIts();
@@ -2208,42 +2262,46 @@
// point is within the main file, after the end of the precompiled
// preamble.
std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
- if (Preamble) {
- std::string CompleteFilePath(File);
-
- auto VFS = FileMgr.getVirtualFileSystem();
- auto CompleteFileStatus = VFS->status(CompleteFilePath);
- if (CompleteFileStatus) {
- llvm::sys::fs::UniqueID CompleteFileID = CompleteFileStatus->getUniqueID();
-
- std::string MainPath(OriginalSourceFile);
- auto MainStatus = VFS->status(MainPath);
- if (MainStatus) {
- llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
- if (CompleteFileID == MainID && Line > 1)
- OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
- PCHContainerOps, Inv, VFS, false, Line - 1);
+ {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ if (ASTUnitCacheMap[MainFilePath].Preamble) {
+ std::string CompleteFilePath(File);
+
+ auto VFS = FileMgr.getVirtualFileSystem();
+ auto CompleteFileStatus = VFS->status(CompleteFilePath);
+ if (CompleteFileStatus) {
+ llvm::sys::fs::UniqueID CompleteFileID =
+ CompleteFileStatus->getUniqueID();
+
+ std::string MainPath(OriginalSourceFile);
+ auto MainStatus = VFS->status(MainPath);
+ if (MainStatus) {
+ llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID();
+ if (CompleteFileID == MainID && Line > 1)
+ OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(
+ PCHContainerOps, Inv, VFS, false, Line - 1);
+ }
}
}
- }
- // If the main file has been overridden due to the use of a preamble,
- // make that override happen and introduce the preamble.
- if (OverrideMainBuffer) {
- assert(Preamble &&
- "No preamble was built, but OverrideMainBuffer is not null");
-
- auto VFS = FileMgr.getVirtualFileSystem();
- Preamble->AddImplicitPreamble(Clang->getInvocation(), VFS,
- OverrideMainBuffer.get());
- // FIXME: there is no way to update VFS if it was changed by
- // AddImplicitPreamble as FileMgr is accepted as a parameter by this method.
- // We use on-disk preambles instead and rely on FileMgr's VFS to ensure the
- // PCH files are always readable.
- OwnedBuffers.push_back(OverrideMainBuffer.release());
- } else {
- PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
- PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+ // If the main file has been overridden due to the use of a preamble,
+ // make that override happen and introduce the preamble.
+ if (OverrideMainBuffer) {
+ assert(ASTUnitCacheMap[MainFilePath].Preamble &&
+ "No preamble was built, but OverrideMainBuffer is not null");
+
+ auto VFS = FileMgr.getVirtualFileSystem();
+ ASTUnitCacheMap[MainFilePath].Preamble->AddImplicitPreamble(
+ Clang->getInvocation(), VFS, OverrideMainBuffer.get());
+ // FIXME: there is no way to update VFS if it was changed by
+ // AddImplicitPreamble as FileMgr is accepted as a parameter by this
+ // method. We use on-disk preambles instead and rely on FileMgr's VFS to
+ // ensure the PCH files are always readable.
+ OwnedBuffers.push_back(OverrideMainBuffer.release());
+ } else {
+ PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
+ PreprocessorOpts.PrecompiledPreambleBytes.second = false;
+ }
}
// Disable the preprocessing record if modules are not enabled.
@@ -2341,13 +2399,18 @@
if (!FE)
continue;
SourceLocation FileLoc;
- auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
- if (ItFileID == PreambleSrcLocCache.end()) {
- FileID FID = SrcMgr.translateFile(FE);
- FileLoc = SrcMgr.getLocForStartOfFile(FID);
- PreambleSrcLocCache[SD.Filename] = FileLoc;
- } else {
- FileLoc = ItFileID->getValue();
+ {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ llvm::StringMap<SourceLocation> &PreambleSrcLocCache =
+ ASTUnitCacheMap[getMainFileName()].PreambleSrcLocCache;
+ auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
+ if (ItFileID == PreambleSrcLocCache.end()) {
+ FileID FID = SrcMgr.translateFile(FE);
+ FileLoc = SrcMgr.getLocForStartOfFile(FID);
+ PreambleSrcLocCache[SD.Filename] = FileLoc;
+ } else {
+ FileLoc = ItFileID->getValue();
+ }
}
if (FileLoc.isInvalid())
@@ -2486,6 +2549,8 @@
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ auto &Preamble = ASTUnitCacheMap[getMainFileName()].Preamble;
if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
@@ -2507,6 +2572,8 @@
if (SourceMgr)
PreambleID = SourceMgr->getPreambleFileID();
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
+ auto &Preamble = ASTUnitCacheMap[getMainFileName()].Preamble;
if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid())
return Loc;
Index: include/clang/Frontend/ASTUnit.h
===================================================================
--- include/clang/Frontend/ASTUnit.h
+++ include/clang/Frontend/ASTUnit.h
@@ -180,9 +180,6 @@
/// The name of the original source file used to generate this ASTUnit.
std::string OriginalSourceFile;
- /// The set of diagnostics produced when creating the preamble.
- SmallVector<StandaloneDiagnostic, 4> PreambleDiagnostics;
-
/// The set of diagnostics produced when creating this
/// translation unit.
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -197,28 +194,6 @@
/// Diagnostics that come from the driver are retained from one parse to
/// the next.
unsigned NumStoredDiagnosticsFromDriver = 0;
-
- /// Counter that determines when we want to try building a
- /// precompiled preamble.
- ///
- /// If zero, we will never build a precompiled preamble. Otherwise,
- /// it's treated as a counter that decrements each time we reparse
- /// without the benefit of a precompiled preamble. When it hits 1,
- /// we'll attempt to rebuild the precompiled header. This way, if
- /// building the precompiled preamble fails, we won't try again for
- /// some number of calls.
- unsigned PreambleRebuildCounter = 0;
-
- /// Cache pairs "filename - source location"
- ///
- /// Cache contains only source locations from preamble so it is
- /// guaranteed that they stay valid when the SourceManager is recreated.
- /// This cache is used when loading preamble to increase performance
- /// of that loading. It must be cleared when preamble is recreated.
- llvm::StringMap<SourceLocation> PreambleSrcLocCache;
-
- /// The contents of the preamble.
- llvm::Optional<PrecompiledPreamble> Preamble;
/// When non-NULL, this is the buffer used to store the contents of
/// the main file when it has been padded for use with the precompiled
@@ -233,10 +208,6 @@
/// when any errors are present.
unsigned NumWarningsInPreamble = 0;
- /// A list of the serialization ID numbers for each of the top-level
- /// declarations parsed within the precompiled preamble.
- std::vector<serialization::DeclID> TopLevelDeclsInPreamble;
-
/// Whether we should be caching code-completion results.
bool ShouldCacheCodeCompletionResults : 1;
@@ -296,7 +267,64 @@
/// for more information.
unsigned Type;
};
-
+
+ /// The cache to reuse the sharable data if there's more than 1 ASTUnit
+ /// for the same file.
+ class ASTUnitCache {
+ mutable unsigned RefCount = 0;
+
+ public:
+ ASTUnitCache() = default;
+ ASTUnitCache(const ASTUnitCache &) {}
+ void Retain() const { ++RefCount; }
+ void Release() const {
+ assert(RefCount > 0 && "Reference count is already zero.");
+ if (--RefCount == 0)
+ delete this;
+ }
+ unsigned getRefCount() const { return RefCount; }
+
+ /// The contents of the preamble.
+ llvm::Optional<PrecompiledPreamble> Preamble;
+
+ /// A list of the serialization ID numbers for each of the top-level
+ /// declarations parsed within the precompiled preamble.
+ std::vector<serialization::DeclID> TopLevelDeclsInPreamble;
+
+ /// The set of diagnostics produced when creating the preamble.
+ SmallVector<StandaloneDiagnostic, 4> PreambleDiagnostics;
+
+ /// Cache pairs "filename - source location"
+ ///
+ /// Cache contains only source locations from preamble so it is
+ /// guaranteed that they stay valid when the SourceManager is recreated.
+ /// This cache is used when loading preamble to increase performance
+ /// of that loading. It must be cleared when preamble is recreated.
+ llvm::StringMap<SourceLocation> PreambleSrcLocCache;
+
+ /// Counter that determines when we want to try building a
+ /// precompiled preamble.
+ ///
+ /// If zero, we will never build a precompiled preamble. Otherwise,
+ /// it's treated as a counter that decrements each time we reparse
+ /// without the benefit of a precompiled preamble. When it hits 1,
+ /// we'll attempt to rebuild the precompiled header. This way, if
+ /// building the precompiled preamble fails, we won't try again for
+ /// some number of calls.
+ unsigned PreambleRebuildCounter = 0;
+
+ /// 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 = 0;
+ };
+
+ void initCache();
+ ASTUnitCache &getCache() { return ASTUnitCacheMap[getMainFileName()]; }
+ static std::recursive_mutex &getCacheMutex() { return CacheMutex; }
+
/// Retrieve the mapping from formatted type names to unique type
/// identifiers.
llvm::StringMap<unsigned> &getCachedCompletionTypes() {
@@ -317,14 +345,17 @@
}
private:
+ static std::recursive_mutex CacheMutex;
+ static llvm::StringMap<ASTUnitCache> ASTUnitCacheMap;
+
/// Allocator used to store cached code completions.
std::shared_ptr<GlobalCodeCompletionAllocator> CachedCompletionAllocator;
std::unique_ptr<CodeCompletionTUInfo> CCTUInfo;
/// The set of cached code-completion results.
std::vector<CachedCodeCompletionResult> CachedCompletionResults;
-
+
/// A mapping from the formatted type name to a unique number for that
/// type, which is used for type equality comparisons.
llvm::StringMap<unsigned> CachedCompletionTypes;
@@ -336,13 +367,6 @@
/// global code-completion cache.
unsigned CompletionCacheTopLevelHashValue = 0;
- /// 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 = 0;
-
/// The current hash value for the top-level declaration and macro
/// definition names
unsigned CurrentTopLevelHashValue = 0;
@@ -496,27 +520,31 @@
using top_level_iterator = std::vector<Decl *>::iterator;
top_level_iterator top_level_begin() {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
- if (!TopLevelDeclsInPreamble.empty())
+ if (!ASTUnitCacheMap[getMainFileName()].TopLevelDeclsInPreamble.empty())
RealizeTopLevelDeclsFromPreamble();
return TopLevelDecls.begin();
}
top_level_iterator top_level_end() {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
- if (!TopLevelDeclsInPreamble.empty())
+ if (!ASTUnitCacheMap[getMainFileName()].TopLevelDeclsInPreamble.empty())
RealizeTopLevelDeclsFromPreamble();
return TopLevelDecls.end();
}
std::size_t top_level_size() const {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
- return TopLevelDeclsInPreamble.size() + TopLevelDecls.size();
+ return ASTUnitCacheMap[getMainFileName()].TopLevelDeclsInPreamble.size() + TopLevelDecls.size();
}
bool top_level_empty() const {
+ std::lock_guard<std::recursive_mutex> Lock(CacheMutex);
assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!");
- return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty();
+ return ASTUnitCacheMap[getMainFileName()].TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty();
}
/// Add a new top-level declaration.
@@ -616,7 +644,7 @@
}
unsigned cached_completion_size() const {
- return CachedCompletionResults.size();
+ return CachedCompletionResults.size();
}
/// Returns an iterator range for the local preprocessing entities
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits