summaryrefslogtreecommitdiffstats
path: root/lib/Frontend/ASTUnit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend/ASTUnit.cpp')
-rw-r--r--lib/Frontend/ASTUnit.cpp260
1 files changed, 162 insertions, 98 deletions
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 1ec4502ba5..b1a6583714 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -161,6 +161,9 @@ getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation,
}
}
+std::recursive_mutex ASTUnit::CacheMutex;
+llvm::StringMap<ASTUnit::ASTUnitCache> ASTUnit::ASTUnitCacheMap;
+
struct ASTUnit::ASTWriterData {
SmallString<128> Buffer;
llvm::BitstreamWriter Stream;
@@ -192,14 +195,11 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
TUKind(TU_Complete), WantTiming(getenv("LIBCLANG_TIMING")),
OwnsRemappedFileBuffers(true),
NumStoredDiagnosticsFromDriver(0),
- PreambleRebuildCounter(0),
NumWarningsInPreamble(0),
ShouldCacheCodeCompletionResults(false),
IncludeBriefCommentsInCodeCompletion(false), UserFilesAreVolatile(false),
- CompletionCacheTopLevelHashValue(0),
- PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
- UnsafeToFree(false) {
+ UnsafeToFree(false) {
if (getenv("LIBCLANG_OBJTRACKING"))
fprintf(stderr, "+++ %u translation units\n", ++ActiveASTUnitObjects);
}
@@ -210,6 +210,16 @@ ASTUnit::~ASTUnit() {
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
@@ -221,13 +231,18 @@ ASTUnit::~ASTUnit() {
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);
}
@@ -794,6 +809,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
// Tell the diagnostic client that we have started a source file.
AST->getDiagnostics().getClient()->BeginSourceFile(PP.getLangOpts(), &PP);
+ AST->initCache();
+
return AST;
}
@@ -1027,7 +1044,10 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
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;
@@ -1095,7 +1115,8 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
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.
@@ -1128,11 +1149,16 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
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;
@@ -1244,37 +1270,41 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
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();
- 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].PreambleRebuildCounter = 1;
+ }
}
- }
+ assert(!Preamble && "No Preamble should be stored at that point");
- // 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)
@@ -1305,55 +1335,62 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
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:
case BuildPreambleError::CouldntCreateVFSOverlay:
// 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 (serialization::DeclID TopLevelDecl : TopLevelDeclsInPreamble) {
@@ -1431,6 +1468,8 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
UserFilesAreVolatile);
AST->PCMCache = new MemoryBufferCache;
+ AST->initCache();
+
return AST;
}
@@ -1461,8 +1500,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
}
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
- if (PrecompilePreambleAfterNParses > 0)
- AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses;
+ if (PrecompilePreambleAfterNParses > 0) {
+ std::lock_guard<std::recursive_mutex> Lock(ASTUnit::getCacheMutex());
+ AST->getCache().PreambleRebuildCounter = PrecompilePreambleAfterNParses;
+ }
AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->IncludeBriefCommentsInCodeCompletion
@@ -1588,6 +1629,8 @@ bool ASTUnit::LoadFromCompilerInvocation(
assert(VFS && "VFS is null");
+ initCache();
+
// We'll manage file buffers ourselves.
Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
Invocation->getFrontendOpts().DisableFree = false;
@@ -1596,7 +1639,9 @@ bool ASTUnit::LoadFromCompilerInvocation(
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();
@@ -1777,10 +1822,15 @@ bool ASTUnit::Reparse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
// 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();
@@ -2076,11 +2126,12 @@ void ASTUnit::CodeComplete(
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.IncludeFixIts = Consumer.includeFixIts();
@@ -2161,42 +2212,46 @@ void ASTUnit::CodeComplete(
// 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.
@@ -2294,13 +2349,18 @@ void ASTUnit::TranslateStoredDiagnostics(
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())
@@ -2439,6 +2499,8 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) const {
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;
@@ -2460,6 +2522,8 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) const {
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;