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