[cfe-commits] r84263 - in /cfe/trunk: include/clang/Basic/FileManager.h include/clang/Frontend/PCHReader.h lib/Basic/FileManager.cpp lib/Frontend/CacheTokens.cpp lib/Frontend/GeneratePCH.cpp lib/Frontend/PCHReader.cpp lib/Lex/PTHLexer.cpp lib/Lex/Preprocessor.cpp test/CMakeLists.txt test/Index/c-index-pch.c test/Index/c-index-pch.h

Douglas Gregor dgregor at apple.com
Fri Oct 16 11:18:30 PDT 2009


Author: dgregor
Date: Fri Oct 16 13:18:30 2009
New Revision: 84263

URL: http://llvm.org/viewvc/llvm-project?rev=84263&view=rev
Log:
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.

Added:
    cfe/trunk/test/Index/c-index-pch.c
    cfe/trunk/test/Index/c-index-pch.h
Modified:
    cfe/trunk/include/clang/Basic/FileManager.h
    cfe/trunk/include/clang/Frontend/PCHReader.h
    cfe/trunk/lib/Basic/FileManager.cpp
    cfe/trunk/lib/Frontend/CacheTokens.cpp
    cfe/trunk/lib/Frontend/GeneratePCH.cpp
    cfe/trunk/lib/Frontend/PCHReader.cpp
    cfe/trunk/lib/Lex/PTHLexer.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp
    cfe/trunk/test/CMakeLists.txt

Modified: cfe/trunk/include/clang/Basic/FileManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileManager.h?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/FileManager.h (original)
+++ cfe/trunk/include/clang/Basic/FileManager.h Fri Oct 16 13:18:30 2009
@@ -71,16 +71,38 @@
   }
 };
 
-// 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 @@
   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.
   ///

Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHReader.h Fri Oct 16 13:18:30 2009
@@ -169,6 +169,11 @@
   /// \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 @@
   /// \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

Modified: cfe/trunk/lib/Basic/FileManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/FileManager.cpp (original)
+++ cfe/trunk/lib/Basic/FileManager.cpp Fri Oct 16 13:18:30 2009
@@ -149,6 +149,41 @@
   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 @@
 }
 
 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;

Modified: cfe/trunk/lib/Frontend/CacheTokens.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CacheTokens.cpp?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CacheTokens.cpp (original)
+++ cfe/trunk/lib/Frontend/CacheTokens.cpp Fri Oct 16 13:18:30 2009
@@ -516,7 +516,7 @@
   ~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 @@
   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 @@
   do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
 
   // Generate the PTH file.
-  PP.getFileManager().setStatCache(0);
+  PP.getFileManager().removeStatCache(StatCache);
   PW.GeneratePTH(&MainFileName);
 }
 

Modified: cfe/trunk/lib/Frontend/GeneratePCH.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/GeneratePCH.cpp?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/GeneratePCH.cpp (original)
+++ cfe/trunk/lib/Frontend/GeneratePCH.cpp Fri Oct 16 13:18:30 2009
@@ -53,7 +53,7 @@
   // 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) {

Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReader.cpp Fri Oct 16 13:18:30 2009
@@ -335,8 +335,6 @@
   PP.setCounterValue(Value);
 }
 
-
-
 //===----------------------------------------------------------------------===//
 // PCH reader implementation
 //===----------------------------------------------------------------------===//
@@ -345,7 +343,7 @@
                      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(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 @@
     // 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 @@
       }
       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 @@
         SourceMgr.ClearPreallocatedSLocEntries();
 
         // Remove the stat cache.
-        FileMgr.setStatCache(0);
+        if (StatCache)
+          FileMgr.removeStatCache((PCHStatCache*)StatCache);
 
         return IgnorePCH;
       }

Modified: cfe/trunk/lib/Lex/PTHLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PTHLexer.cpp?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/PTHLexer.cpp (original)
+++ cfe/trunk/lib/Lex/PTHLexer.cpp Fri Oct 16 13:18:30 2009
@@ -679,7 +679,8 @@
     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;
 

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Fri Oct 16 13:18:30 2009
@@ -122,7 +122,7 @@
 
 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 {

Modified: cfe/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CMakeLists.txt?rev=84263&r1=84262&r2=84263&view=diff

==============================================================================
--- cfe/trunk/test/CMakeLists.txt (original)
+++ cfe/trunk/test/CMakeLists.txt Fri Oct 16 13:18:30 2009
@@ -45,7 +45,7 @@
                   ${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 @@
                 ${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 @@
                 ${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()  

Added: cfe/trunk/test/Index/c-index-pch.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/c-index-pch.c?rev=84263&view=auto

==============================================================================
--- cfe/trunk/test/Index/c-index-pch.c (added)
+++ cfe/trunk/test/Index/c-index-pch.c Fri Oct 16 13:18:30 2009
@@ -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);

Added: cfe/trunk/test/Index/c-index-pch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/c-index-pch.h?rev=84263&view=auto

==============================================================================
--- cfe/trunk/test/Index/c-index-pch.h (added)
+++ cfe/trunk/test/Index/c-index-pch.h Fri Oct 16 13:18:30 2009
@@ -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





More information about the cfe-commits mailing list