diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-16 18:18:30 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-16 18:18:30 +0000 |
commit | 52e7108f51a4a9f4d6e84f33fb594d06e1d79560 (patch) | |
tree | ff52750d5e8ccf5cb5cc260f3afd5e13014ed9b6 | |
parent | 5f04881eb025f61396d0555d8173730fe2759e0a (diff) |
Add support for a chain of stat caches in the FileManager, rather than
only supporting a single stat cache. The immediate benefit of this
change is that we can now generate a PCH/AST file when including
another PCH file; in the future, the chain of stat caches will likely
be useful with multiple levels of PCH files.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84263 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/FileManager.h | 55 | ||||
-rw-r--r-- | include/clang/Frontend/PCHReader.h | 9 | ||||
-rw-r--r-- | lib/Basic/FileManager.cpp | 39 | ||||
-rw-r--r-- | lib/Frontend/CacheTokens.cpp | 7 | ||||
-rw-r--r-- | lib/Frontend/GeneratePCH.cpp | 2 | ||||
-rw-r--r-- | lib/Frontend/PCHReader.cpp | 26 | ||||
-rw-r--r-- | lib/Lex/PTHLexer.cpp | 3 | ||||
-rw-r--r-- | lib/Lex/Preprocessor.cpp | 2 | ||||
-rw-r--r-- | test/CMakeLists.txt | 6 | ||||
-rw-r--r-- | test/Index/c-index-pch.c | 7 | ||||
-rw-r--r-- | test/Index/c-index-pch.h | 7 |
11 files changed, 126 insertions, 37 deletions
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index 7c9113c497..5e7ac4f3c8 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -71,16 +71,38 @@ public: } }; -// FIXME: This is a lightweight shim that is used by FileManager to cache -// 'stat' system calls. We will use it with PTH to identify if caching -// stat calls in PTH files is a performance win. +/// \brief Abstract interface for introducing a FileManager cache for 'stat' +/// system calls, which is used by precompiled and pretokenized headers to +/// improve performance. class StatSysCallCache { +protected: + llvm::OwningPtr<StatSysCallCache> NextStatCache; + public: virtual ~StatSysCallCache() {} - virtual int stat(const char *path, struct stat *buf) = 0; + virtual int stat(const char *path, struct stat *buf) { + if (getNextStatCache()) + return getNextStatCache()->stat(path, buf); + + return ::stat(path, buf); + } + + /// \brief Sets the next stat call cache in the chain of stat caches. + /// Takes ownership of the given stat cache. + void setNextStatCache(StatSysCallCache *Cache) { + NextStatCache.reset(Cache); + } + + /// \brief Retrieve the next stat call cache in the chain. + StatSysCallCache *getNextStatCache() { return NextStatCache.get(); } + + /// \brief Retrieve the next stat call cache in the chain, transferring + /// ownership of this cache (and, transitively, all of the remaining caches) + /// to the caller. + StatSysCallCache *takeNextStatCache() { return NextStatCache.take(); } }; -/// \brief A stat listener that can be used by FileManager to keep +/// \brief A stat "cache" that can be used by FileManager to keep /// track of the results of stat() calls that occur throughout the /// execution of the front end. class MemorizeStatCalls : public StatSysCallCache { @@ -144,13 +166,22 @@ public: FileManager(); ~FileManager(); - /// setStatCache - Installs the provided StatSysCallCache object within - /// the FileManager. Ownership of this object is transferred to the - /// FileManager. - void setStatCache(StatSysCallCache *statCache) { - StatCache.reset(statCache); - } - + /// \brief Installs the provided StatSysCallCache object within + /// the FileManager. + /// + /// Ownership of this object is transferred to the FileManager. + /// + /// \param statCache the new stat cache to install. Ownership of this + /// object is transferred to the FileManager. + /// + /// \param AtBeginning whether this new stat cache must be installed at the + /// beginning of the chain of stat caches. Otherwise, it will be added to + /// the end of the chain. + void addStatCache(StatSysCallCache *statCache, bool AtBeginning = false); + + /// \brief Removes the provided StatSysCallCache object from the file manager. + void removeStatCache(StatSysCallCache *statCache); + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 27e4d3f1cb..f1f58fac30 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -169,6 +169,11 @@ private: /// \brief The AST context into which we'll read the PCH file. ASTContext *Context; + /// \brief The PCH stat cache installed by this PCHReader, if any. + /// + /// The dynamic type of this stat cache is always PCHStatCache + void *StatCache; + /// \brief The AST consumer. ASTConsumer *Consumer; @@ -492,8 +497,8 @@ public: /// \param isysroot If non-NULL, the system include path specified by the /// user. This is only used with relocatable PCH files. If non-NULL, /// a relocatable PCH file will use the default path "/". - PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, - Diagnostic &Diags, const char *isysroot = 0); + PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, + Diagnostic &Diags, const char *isysroot = 0); ~PCHReader(); /// \brief Load the precompiled header designated by the given file diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index df86f9d047..ee4309de93 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -149,6 +149,41 @@ FileManager::~FileManager() { delete &UniqueFiles; } +void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { + assert(statCache && "No stat cache provided?"); + if (AtBeginning || StatCache.get() == 0) { + statCache->setNextStatCache(StatCache.take()); + StatCache.reset(statCache); + return; + } + + StatSysCallCache *LastCache = StatCache.get(); + while (LastCache->getNextStatCache()) + LastCache = LastCache->getNextStatCache(); + + LastCache->setNextStatCache(statCache); +} + +void FileManager::removeStatCache(StatSysCallCache *statCache) { + if (!statCache) + return; + + if (StatCache.get() == statCache) { + // This is the first stat cache. + StatCache.reset(StatCache->takeNextStatCache()); + return; + } + + // Find the stat cache in the list. + StatSysCallCache *PrevCache = StatCache.get(); + while (PrevCache && PrevCache->getNextStatCache() != statCache) + PrevCache = PrevCache->getNextStatCache(); + if (PrevCache) + PrevCache->setNextStatCache(statCache->getNextStatCache()); + else + assert(false && "Stat cache not found for removal"); +} + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// @@ -290,8 +325,8 @@ void FileManager::PrintStats() const { } int MemorizeStatCalls::stat(const char *path, struct stat *buf) { - int result = ::stat(path, buf); - + int result = StatSysCallCache::stat(path, buf); + if (result != 0) { // Cache failed 'stat' results. struct stat empty; diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index e7fc5660ad..169fd5ebf9 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -516,7 +516,7 @@ public: ~StatListener() {} int stat(const char *path, struct stat *buf) { - int result = ::stat(path, buf); + int result = StatSysCallCache::stat(path, buf); if (result != 0) // Failed 'stat'. PM.insert(path, PTHEntry()); @@ -553,7 +553,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { PTHWriter PW(*OS, PP); // Install the 'stat' system call listener in the FileManager. - PP.getFileManager().setStatCache(new StatListener(PW.getPM())); + StatListener *StatCache = new StatListener(PW.getPM()); + PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true); // Lex through the entire file. This will populate SourceManager with // all of the header information. @@ -562,7 +563,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); // Generate the PTH file. - PP.getFileManager().setStatCache(0); + PP.getFileManager().removeStatCache(StatCache); PW.GeneratePTH(&MainFileName); } diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp index bc45cc4225..0e4f83ff09 100644 --- a/lib/Frontend/GeneratePCH.cpp +++ b/lib/Frontend/GeneratePCH.cpp @@ -53,7 +53,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, // Install a stat() listener to keep track of all of the stat() // calls. StatCalls = new MemorizeStatCalls; - PP.getFileManager().setStatCache(StatCalls); + PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true); } void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index d9d3960f6f..141f7c8ab2 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -335,8 +335,6 @@ void PCHValidator::ReadCounter(unsigned Value) { PP.setCounterValue(Value); } - - //===----------------------------------------------------------------------===// // PCH reader implementation //===----------------------------------------------------------------------===// @@ -345,7 +343,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot) : Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), - SemaObj(0), PP(&PP), Context(Context), Consumer(0), + SemaObj(0), PP(&PP), Context(Context), StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -362,7 +360,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, Diagnostic &Diags, const char *isysroot) : SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags), - SemaObj(0), PP(0), Context(0), Consumer(0), + SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), @@ -794,7 +792,7 @@ public: // If we don't get a hit in the PCH file just forward to 'stat'. if (I == Cache->end()) { ++NumStatMisses; - return ::stat(path, buf); + return StatSysCallCache::stat(path, buf); } ++NumStatHits; @@ -1352,13 +1350,16 @@ PCHReader::ReadPCHBlock() { } break; - case pch::STAT_CACHE: - FileMgr.setStatCache( - new PCHStatCache((const unsigned char *)BlobStart + Record[0], - (const unsigned char *)BlobStart, - NumStatHits, NumStatMisses)); + case pch::STAT_CACHE: { + PCHStatCache *MyStatCache = + new PCHStatCache((const unsigned char *)BlobStart + Record[0], + (const unsigned char *)BlobStart, + NumStatHits, NumStatMisses); + FileMgr.addStatCache(MyStatCache); + StatCache = MyStatCache; break; - + } + case pch::EXT_VECTOR_DECLS: if (!ExtVectorDecls.empty()) { Error("duplicate EXT_VECTOR_DECLS record in PCH file"); @@ -1466,7 +1467,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { SourceMgr.ClearPreallocatedSLocEntries(); // Remove the stat cache. - FileMgr.setStatCache(0); + if (StatCache) + FileMgr.removeStatCache((PCHStatCache*)StatCache); return IgnorePCH; } diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index 36ace8be7e..f804f82c48 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -679,7 +679,8 @@ public: CacheTy::iterator I = Cache.find(path); // If we don't get a hit in the PTH file just forward to 'stat'. - if (I == Cache.end()) return ::stat(path, buf); + if (I == Cache.end()) + return StatSysCallCache::stat(path, buf); const PTHStatData& Data = *I; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index bfa090a09e..e41bc5cab1 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -122,7 +122,7 @@ Preprocessor::~Preprocessor() { void Preprocessor::setPTHManager(PTHManager* pm) { PTH.reset(pm); - FileMgr.setStatCache(PTH->createStatCache()); + FileMgr.addStatCache(PTH->createStatCache()); } void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2a7f132fb5..66f05bff69 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,7 +45,7 @@ if(PYTHONINTERP_FOUND) ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR}/${testdir} - DEPENDS clang clang-cc index-test + DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests in ${testdir}") endforeach() @@ -62,7 +62,7 @@ if(PYTHONINTERP_FOUND) ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS clang clang-cc index-test + DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests") add_custom_target(clang-c++tests @@ -78,6 +78,6 @@ if(PYTHONINTERP_FOUND) ${LLVM_SOURCE_DIR}/utils/lit/lit.py -sv ${CLANG_TEST_EXTRA_ARGS} ${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests - DEPENDS clang clang-cc index-test + DEPENDS clang clang-cc index-test c-index-test COMMENT "Running Clang regression tests") endif() diff --git a/test/Index/c-index-pch.c b/test/Index/c-index-pch.c new file mode 100644 index 0000000000..2298c8f207 --- /dev/null +++ b/test/Index/c-index-pch.c @@ -0,0 +1,7 @@ +// RUN: clang-cc -emit-pch -x c -o %t.pch %S/c-index-pch.h && +// RUN: clang-cc -include-pch %t.pch -x c -emit-pch -o %t.ast %s && +// RUN: c-index-test %t.ast all | FileCheck -check-prefix=ALL %s +// CHECK-ALL: FunctionDecl=foo +// CHECK-ALL: VarDecl=bar +// CHECK-ALL: FunctionDecl=wibble +void wibble(int i); diff --git a/test/Index/c-index-pch.h b/test/Index/c-index-pch.h new file mode 100644 index 0000000000..6dda18000c --- /dev/null +++ b/test/Index/c-index-pch.h @@ -0,0 +1,7 @@ +#ifndef C_INDEX_PCH_H +#define C_INDEX_PCH_H + +void foo(int i, float f); +extern int bar; + +#endif // C_INDEX_PCH_H |