nik created this revision.

When a preamble is created an unsaved file not existing on disk is
already part of PrecompiledPreamble::FilesInPreamble. However, when
checking whether the preamble can be re-used, a failed stat of such an
unsaved file invalidated the preamble, which led to pointless and time
consuming preamble regenerations on subsequent reparses.

Do not require anymore that unsaved files should exist on disk.

This avoids costly preamble invalidations depending on timing issues for
the cases where the file on disk might be removed just to be regenerated
a bit later.

It also allows an IDE to provide in-memory files that might not exist on
disk, e.g. because the build system hasn't generated those yet.


Repository:
  rC Clang

https://reviews.llvm.org/D41005

Files:
  include/clang/Frontend/ASTUnit.h
  include/clang/Frontend/PrecompiledPreamble.h
  lib/Frontend/ASTUnit.cpp
  lib/Frontend/PrecompiledPreamble.cpp
  unittests/Frontend/PCHPreambleTest.cpp

Index: unittests/Frontend/PCHPreambleTest.cpp
===================================================================
--- unittests/Frontend/PCHPreambleTest.cpp
+++ unittests/Frontend/PCHPreambleTest.cpp
@@ -124,6 +124,23 @@
   }
 };
 
+TEST_F(PCHPreambleTest, ReparseDoesNotInvalidatePreambleDueToNotExistingUnsavedFile) {
+  std::string Header1 = "//./header1.h";
+  std::string MainName = "//./main.cpp";
+  AddFile(MainName, "#include \"//./header1.h\"\n"
+                    "int main() { return ZERO; }");
+
+  std::unique_ptr<ASTUnit> AST(ParseAST(MainName));
+  ASSERT_TRUE(AST.get());
+  auto InitialPreambleCreationTimePoint = AST->getPreambleCreationTimePoint();
+  ASSERT_NE(std::chrono::steady_clock::time_point(), InitialPreambleCreationTimePoint);
+
+  RemapFile(Header1, "#define ZERO 0\n");
+  ASSERT_TRUE(ReparseAST(AST));
+
+  ASSERT_EQ(InitialPreambleCreationTimePoint, AST->getPreambleCreationTimePoint());
+}
+
 TEST_F(PCHPreambleTest, ReparseWithOverriddenFileDoesNotInvalidatePreamble) {
   std::string Header1 = "//./header1.h";
   std::string Header2 = "//./header2.h";
Index: lib/Frontend/PrecompiledPreamble.cpp
===================================================================
--- lib/Frontend/PrecompiledPreamble.cpp
+++ lib/Frontend/PrecompiledPreamble.cpp
@@ -390,10 +390,10 @@
   return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine);
 }
 
-bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation,
-                                   const llvm::MemoryBuffer *MainFileBuffer,
-                                   PreambleBounds Bounds,
-                                   vfs::FileSystem *VFS) const {
+bool PrecompiledPreamble::CanReuse(
+    const CompilerInvocation &Invocation,
+    const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
+    IntrusiveRefCntPtr<vfs::FileSystem> VFS) const {
 
   assert(
       Bounds.Size <= MainFileBuffer->getBufferSize() &&
@@ -434,19 +434,22 @@
         Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime()));
   }
 
+  vfs::OverlayFileSystem OFS(VFS);
+  IntrusiveRefCntPtr<vfs::InMemoryFileSystem> IMFS(
+      new vfs::InMemoryFileSystem());
+  OFS.pushOverlay(IMFS);
   for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) {
+    IMFS->addFile(RB.first, 0, llvm::MemoryBuffer::getMemBuffer(""));
     vfs::Status Status;
-    if (!moveOnNoError(VFS->status(RB.first), Status))
-      return false;
-
+    assert(moveOnNoError(IMFS->status(RB.first), Status));
     OverriddenFiles[Status.getUniqueID()] =
         PreambleFileHash::createForMemoryBuffer(RB.second);
   }
 
   // Check whether anything has changed.
   for (const auto &F : FilesInPreamble) {
     vfs::Status Status;
-    if (!moveOnNoError(VFS->status(F.first()), Status)) {
+    if (!moveOnNoError(OFS.status(F.first()), Status)) {
       // If we can't stat the file, assume that something horrible happened.
       return false;
     }
@@ -495,7 +498,8 @@
     llvm::StringMap<PreambleFileHash> FilesInPreamble)
     : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)),
       PreambleBytes(std::move(PreambleBytes)),
-      PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {
+      PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine),
+      CreationTimePoint(std::chrono::steady_clock::now()){
   assert(this->Storage.getKind() != PCHStorage::Kind::Empty);
 }
 
Index: lib/Frontend/ASTUnit.cpp
===================================================================
--- lib/Frontend/ASTUnit.cpp
+++ lib/Frontend/ASTUnit.cpp
@@ -1244,7 +1244,7 @@
 
   if (Preamble) {
     if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds,
-                           VFS.get())) {
+                           VFS)) {
       // Okay! We can re-use the precompiled preamble.
 
       // Set the state of the diagnostic object to mimic its state
Index: include/clang/Frontend/PrecompiledPreamble.h
===================================================================
--- include/clang/Frontend/PrecompiledPreamble.h
+++ include/clang/Frontend/PrecompiledPreamble.h
@@ -93,7 +93,7 @@
   /// MainFileBuffer) of the main file.
   bool CanReuse(const CompilerInvocation &Invocation,
                 const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds,
-                vfs::FileSystem *VFS) const;
+                IntrusiveRefCntPtr<vfs::FileSystem> VFS) const;
 
   /// Changes options inside \p CI to use PCH from this preamble. Also remaps
   /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble
@@ -106,6 +106,10 @@
                            IntrusiveRefCntPtr<vfs::FileSystem> &VFS,
                            llvm::MemoryBuffer *MainFileBuffer) const;
 
+  std::chrono::steady_clock::time_point getCreationTimePoint() const {
+    return CreationTimePoint;
+  }
+
 private:
   PrecompiledPreamble(PCHStorage Storage, std::vector<char> PreambleBytes,
                       bool PreambleEndsAtStartOfLine,
@@ -237,6 +241,7 @@
   std::vector<char> PreambleBytes;
   /// See PreambleBounds::PreambleEndsAtStartOfLine
   bool PreambleEndsAtStartOfLine;
+  std::chrono::steady_clock::time_point CreationTimePoint;
 };
 
 /// A set of callbacks to gather useful information while building a preamble.
Index: include/clang/Frontend/ASTUnit.h
===================================================================
--- include/clang/Frontend/ASTUnit.h
+++ include/clang/Frontend/ASTUnit.h
@@ -547,6 +547,13 @@
     return SourceRange(mapLocationToPreamble(R.getBegin()),
                        mapLocationToPreamble(R.getEnd()));
   }
+
+  std::chrono::steady_clock::time_point getPreambleCreationTimePoint() const
+  {
+      if (Preamble)
+          return Preamble->getCreationTimePoint();
+      return std::chrono::steady_clock::time_point();
+  }
   
   // Retrieve the diagnostics associated with this AST
   typedef StoredDiagnostic *stored_diag_iterator;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to