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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to