diff options
Diffstat (limited to 'lib/Frontend/ASTUnit.cpp')
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 260 |
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; |