зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
5f04881eb0
Коммит
52e7108f51
|
@ -71,16 +71,38 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: This is a lightweight shim that is used by FileManager to cache
|
/// \brief Abstract interface for introducing a FileManager cache for 'stat'
|
||||||
// 'stat' system calls. We will use it with PTH to identify if caching
|
/// system calls, which is used by precompiled and pretokenized headers to
|
||||||
// stat calls in PTH files is a performance win.
|
/// improve performance.
|
||||||
class StatSysCallCache {
|
class StatSysCallCache {
|
||||||
|
protected:
|
||||||
|
llvm::OwningPtr<StatSysCallCache> NextStatCache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~StatSysCallCache() {}
|
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
|
/// track of the results of stat() calls that occur throughout the
|
||||||
/// execution of the front end.
|
/// execution of the front end.
|
||||||
class MemorizeStatCalls : public StatSysCallCache {
|
class MemorizeStatCalls : public StatSysCallCache {
|
||||||
|
@ -144,12 +166,21 @@ public:
|
||||||
FileManager();
|
FileManager();
|
||||||
~FileManager();
|
~FileManager();
|
||||||
|
|
||||||
/// setStatCache - Installs the provided StatSysCallCache object within
|
/// \brief Installs the provided StatSysCallCache object within
|
||||||
/// the FileManager. Ownership of this object is transferred to the
|
/// the FileManager.
|
||||||
/// FileManager.
|
///
|
||||||
void setStatCache(StatSysCallCache *statCache) {
|
/// Ownership of this object is transferred to the FileManager.
|
||||||
StatCache.reset(statCache);
|
///
|
||||||
}
|
/// \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
|
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||||
/// returns null if the directory doesn't exist.
|
/// returns null if the directory doesn't exist.
|
||||||
|
|
|
@ -169,6 +169,11 @@ private:
|
||||||
/// \brief The AST context into which we'll read the PCH file.
|
/// \brief The AST context into which we'll read the PCH file.
|
||||||
ASTContext *Context;
|
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.
|
/// \brief The AST consumer.
|
||||||
ASTConsumer *Consumer;
|
ASTConsumer *Consumer;
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,41 @@ FileManager::~FileManager() {
|
||||||
delete &UniqueFiles;
|
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
|
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||||
/// returns null if the directory doesn't exist.
|
/// returns null if the directory doesn't exist.
|
||||||
///
|
///
|
||||||
|
@ -290,7 +325,7 @@ void FileManager::PrintStats() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
|
int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
|
||||||
int result = ::stat(path, buf);
|
int result = StatSysCallCache::stat(path, buf);
|
||||||
|
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
// Cache failed 'stat' results.
|
// Cache failed 'stat' results.
|
||||||
|
|
|
@ -516,7 +516,7 @@ public:
|
||||||
~StatListener() {}
|
~StatListener() {}
|
||||||
|
|
||||||
int stat(const char *path, struct stat *buf) {
|
int stat(const char *path, struct stat *buf) {
|
||||||
int result = ::stat(path, buf);
|
int result = StatSysCallCache::stat(path, buf);
|
||||||
|
|
||||||
if (result != 0) // Failed 'stat'.
|
if (result != 0) // Failed 'stat'.
|
||||||
PM.insert(path, PTHEntry());
|
PM.insert(path, PTHEntry());
|
||||||
|
@ -553,7 +553,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) {
|
||||||
PTHWriter PW(*OS, PP);
|
PTHWriter PW(*OS, PP);
|
||||||
|
|
||||||
// Install the 'stat' system call listener in the FileManager.
|
// 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
|
// Lex through the entire file. This will populate SourceManager with
|
||||||
// all of the header information.
|
// 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));
|
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
|
||||||
|
|
||||||
// Generate the PTH file.
|
// Generate the PTH file.
|
||||||
PP.getFileManager().setStatCache(0);
|
PP.getFileManager().removeStatCache(StatCache);
|
||||||
PW.GeneratePTH(&MainFileName);
|
PW.GeneratePTH(&MainFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP,
|
||||||
// Install a stat() listener to keep track of all of the stat()
|
// Install a stat() listener to keep track of all of the stat()
|
||||||
// calls.
|
// calls.
|
||||||
StatCalls = new MemorizeStatCalls;
|
StatCalls = new MemorizeStatCalls;
|
||||||
PP.getFileManager().setStatCache(StatCalls);
|
PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
|
void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
|
||||||
|
|
|
@ -335,8 +335,6 @@ void PCHValidator::ReadCounter(unsigned Value) {
|
||||||
PP.setCounterValue(Value);
|
PP.setCounterValue(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// PCH reader implementation
|
// PCH reader implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -345,7 +343,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
|
||||||
const char *isysroot)
|
const char *isysroot)
|
||||||
: Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()),
|
: Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()),
|
||||||
FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
|
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),
|
IdentifierTableData(0), IdentifierLookupTable(0),
|
||||||
IdentifierOffsets(0),
|
IdentifierOffsets(0),
|
||||||
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
||||||
|
@ -362,7 +360,7 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
|
||||||
PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
|
PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
|
||||||
Diagnostic &Diags, const char *isysroot)
|
Diagnostic &Diags, const char *isysroot)
|
||||||
: SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags),
|
: 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),
|
IdentifierTableData(0), IdentifierLookupTable(0),
|
||||||
IdentifierOffsets(0),
|
IdentifierOffsets(0),
|
||||||
MethodPoolLookupTable(0), MethodPoolLookupTableData(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 we don't get a hit in the PCH file just forward to 'stat'.
|
||||||
if (I == Cache->end()) {
|
if (I == Cache->end()) {
|
||||||
++NumStatMisses;
|
++NumStatMisses;
|
||||||
return ::stat(path, buf);
|
return StatSysCallCache::stat(path, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
++NumStatHits;
|
++NumStatHits;
|
||||||
|
@ -1352,12 +1350,15 @@ PCHReader::ReadPCHBlock() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pch::STAT_CACHE:
|
case pch::STAT_CACHE: {
|
||||||
FileMgr.setStatCache(
|
PCHStatCache *MyStatCache =
|
||||||
new PCHStatCache((const unsigned char *)BlobStart + Record[0],
|
new PCHStatCache((const unsigned char *)BlobStart + Record[0],
|
||||||
(const unsigned char *)BlobStart,
|
(const unsigned char *)BlobStart,
|
||||||
NumStatHits, NumStatMisses));
|
NumStatHits, NumStatMisses);
|
||||||
|
FileMgr.addStatCache(MyStatCache);
|
||||||
|
StatCache = MyStatCache;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case pch::EXT_VECTOR_DECLS:
|
case pch::EXT_VECTOR_DECLS:
|
||||||
if (!ExtVectorDecls.empty()) {
|
if (!ExtVectorDecls.empty()) {
|
||||||
|
@ -1466,7 +1467,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
|
||||||
SourceMgr.ClearPreallocatedSLocEntries();
|
SourceMgr.ClearPreallocatedSLocEntries();
|
||||||
|
|
||||||
// Remove the stat cache.
|
// Remove the stat cache.
|
||||||
FileMgr.setStatCache(0);
|
if (StatCache)
|
||||||
|
FileMgr.removeStatCache((PCHStatCache*)StatCache);
|
||||||
|
|
||||||
return IgnorePCH;
|
return IgnorePCH;
|
||||||
}
|
}
|
||||||
|
|
|
@ -679,7 +679,8 @@ public:
|
||||||
CacheTy::iterator I = Cache.find(path);
|
CacheTy::iterator I = Cache.find(path);
|
||||||
|
|
||||||
// If we don't get a hit in the PTH file just forward to 'stat'.
|
// 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;
|
const PTHStatData& Data = *I;
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ Preprocessor::~Preprocessor() {
|
||||||
|
|
||||||
void Preprocessor::setPTHManager(PTHManager* pm) {
|
void Preprocessor::setPTHManager(PTHManager* pm) {
|
||||||
PTH.reset(pm);
|
PTH.reset(pm);
|
||||||
FileMgr.setStatCache(PTH->createStatCache());
|
FileMgr.addStatCache(PTH->createStatCache());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
|
void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
|
||||||
|
|
|
@ -45,7 +45,7 @@ if(PYTHONINTERP_FOUND)
|
||||||
${LLVM_SOURCE_DIR}/utils/lit/lit.py
|
${LLVM_SOURCE_DIR}/utils/lit/lit.py
|
||||||
-sv ${CLANG_TEST_EXTRA_ARGS}
|
-sv ${CLANG_TEST_EXTRA_ARGS}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/${testdir}
|
${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}")
|
COMMENT "Running Clang regression tests in ${testdir}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ if(PYTHONINTERP_FOUND)
|
||||||
${LLVM_SOURCE_DIR}/utils/lit/lit.py
|
${LLVM_SOURCE_DIR}/utils/lit/lit.py
|
||||||
-sv ${CLANG_TEST_EXTRA_ARGS}
|
-sv ${CLANG_TEST_EXTRA_ARGS}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
DEPENDS clang clang-cc index-test
|
DEPENDS clang clang-cc index-test c-index-test
|
||||||
COMMENT "Running Clang regression tests")
|
COMMENT "Running Clang regression tests")
|
||||||
|
|
||||||
add_custom_target(clang-c++tests
|
add_custom_target(clang-c++tests
|
||||||
|
@ -78,6 +78,6 @@ if(PYTHONINTERP_FOUND)
|
||||||
${LLVM_SOURCE_DIR}/utils/lit/lit.py
|
${LLVM_SOURCE_DIR}/utils/lit/lit.py
|
||||||
-sv ${CLANG_TEST_EXTRA_ARGS}
|
-sv ${CLANG_TEST_EXTRA_ARGS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests
|
${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")
|
COMMENT "Running Clang regression tests")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -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);
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче