rework the stat cache, pulling it out of FileManager.h into
its own header and giving it some more structure.  No 
functionality change.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120030 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index f7dd8c1..12bc7d4 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -6,6 +6,7 @@
   Diagnostic.cpp
   DiagnosticIDs.cpp
   FileManager.cpp
+  FileSystemStatCache.cpp
   IdentifierTable.cpp
   SourceLocation.cpp
   SourceManager.cpp
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 9066359..9572aaad 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -1,4 +1,4 @@
-///===--- FileManager.cpp - File System Probing and Caching ----------------===//
+//===--- FileManager.cpp - File System Probing and Caching ----------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -18,7 +18,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/FileSystemStatCache.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -162,7 +162,8 @@
     delete *V;
 }
 
-void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
+void FileManager::addStatCache(FileSystemStatCache *statCache,
+                               bool AtBeginning) {
   assert(statCache && "No stat cache provided?");
   if (AtBeginning || StatCache.get() == 0) {
     statCache->setNextStatCache(StatCache.take());
@@ -170,14 +171,14 @@
     return;
   }
   
-  StatSysCallCache *LastCache = StatCache.get();
+  FileSystemStatCache *LastCache = StatCache.get();
   while (LastCache->getNextStatCache())
     LastCache = LastCache->getNextStatCache();
   
   LastCache->setNextStatCache(statCache);
 }
 
-void FileManager::removeStatCache(StatSysCallCache *statCache) {
+void FileManager::removeStatCache(FileSystemStatCache *statCache) {
   if (!statCache)
     return;
   
@@ -188,7 +189,7 @@
   }
   
   // Find the stat cache in the list.
-  StatSysCallCache *PrevCache = StatCache.get();
+  FileSystemStatCache *PrevCache = StatCache.get();
   while (PrevCache && PrevCache->getNextStatCache() != statCache)
     PrevCache = PrevCache->getNextStatCache();
   if (PrevCache)
@@ -249,8 +250,8 @@
 
   // Check to see if the directory exists.
   struct stat StatBuf;
-  if (stat_cached(InterndDirName, &StatBuf) ||   // Error stat'ing.
-      !S_ISDIR(StatBuf.st_mode))          // Not a directory?
+  if (getStatValue(InterndDirName, StatBuf) ||    // Error stat'ing.
+      !S_ISDIR(StatBuf.st_mode))                  // Not a directory?
     return 0;
 
   // It exists.  See if we have already opened a directory with the same inode.
@@ -306,8 +307,8 @@
   // Nope, there isn't.  Check to see if the file exists.
   struct stat StatBuf;
   //llvm::errs() << "STATING: " << Filename;
-  if (stat_cached(InterndFileName, &StatBuf) ||   // Error stat'ing.
-      S_ISDIR(StatBuf.st_mode)) {                 // A directory?
+  if (getStatValue(InterndFileName, StatBuf) ||    // Error stat'ing.
+      S_ISDIR(StatBuf.st_mode)) {                  // A directory?
     // If this file doesn't exist, we leave a null in FileEntries for this path.
     //llvm::errs() << ": Not existing\n";
     return 0;
@@ -370,7 +371,7 @@
   // newly-created file entry.
   const char *InterndFileName = NamedFileEnt.getKeyData();
   struct stat StatBuf;
-  if (!stat_cached(InterndFileName, &StatBuf) &&
+  if (!getStatValue(InterndFileName, StatBuf) &&
       !S_ISDIR(StatBuf.st_mode)) {
     llvm::sys::Path FilePath(InterndFileName);
     FilePath.makeAbsolute();
@@ -410,17 +411,36 @@
   return llvm::MemoryBuffer::getFile(FilePath.c_str(), ErrorStr);
 }
 
-int FileManager::stat_cached(const char *path, struct stat *buf) {
-  if (FileSystemOpts.WorkingDir.empty())
-    return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf);
-
-  llvm::sys::Path FilePath(path);
+/// getStatValue - Get the 'stat' information for the specified path, using the
+/// cache to accellerate it if possible.  This returns true if the path does not
+/// exist or false if it exists.
+bool FileManager::getStatValue(const char *Path, struct stat &StatBuf) {
+  FileSystemStatCache::LookupResult Result = FileSystemStatCache::CacheMiss;
+  
+  // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
+  // absolute!
+  if (FileSystemOpts.WorkingDir.empty()) {
+    if (StatCache.get())
+      Result = StatCache->getStat(Path, StatBuf);
+    
+    if (Result == FileSystemStatCache::CacheMiss)
+      return ::stat(Path, &StatBuf);
+    return Result == FileSystemStatCache::CacheHitMissing;
+  }
+  
+  llvm::sys::Path FilePath(Path);
   FixupRelativePath(FilePath, FileSystemOpts);
-
-  return StatCache.get() ? StatCache->stat(FilePath.c_str(), buf)
-                         : stat(FilePath.c_str(), buf);
+  
+  if (StatCache.get())
+    Result = StatCache->getStat(FilePath.c_str(), StatBuf);
+  
+  if (Result == FileSystemStatCache::CacheMiss)
+    return ::stat(FilePath.c_str(), &StatBuf);
+  return Result == FileSystemStatCache::CacheHitMissing;
 }
 
+
+
 void FileManager::PrintStats() const {
   llvm::errs() << "\n*** File Manager Stats:\n";
   llvm::errs() << UniqueFiles.size() << " files found, "
@@ -433,19 +453,3 @@
   //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
 }
 
-int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
-  int result = StatSysCallCache::stat(path, buf);
-  
-  // Do not cache failed stats, it is easy to construct common inconsistent
-  // situations if we do, and they are not important for PCH performance (which
-  // currently only needs the stats to construct the initial FileManager
-  // entries).
-  if (result != 0)
-    return result;
-
-  // Cache file 'stat' results and directories with absolutely paths.
-  if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute())
-    StatCalls[path] = StatResult(result, *buf);
-
-  return result;
-}
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
new file mode 100644
index 0000000..8fd31d5
--- /dev/null
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -0,0 +1,40 @@
+//===--- FileSystemStatCache.cpp - Caching for 'stat' calls ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the FileSystemStatCache interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/FileSystemStatCache.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+MemorizeStatCalls::LookupResult
+MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf) {
+  LookupResult Result = statChained(Path, StatBuf);
+  
+  // If the chained cache didn't know anything about the file, do the stat now
+  // so we can record the result.
+  if (Result == CacheMiss)
+    Result = ::stat(Path, &StatBuf) ? CacheHitMissing : CacheHitExists;
+  
+  
+  // Do not cache failed stats, it is easy to construct common inconsistent
+  // situations if we do, and they are not important for PCH performance (which
+  // currently only needs the stats to construct the initial FileManager
+  // entries).
+  if (Result == CacheHitMissing)
+    return Result;
+  
+  // Cache file 'stat' results and directories with absolutely paths.
+  if (!S_ISDIR(StatBuf.st_mode) || llvm::sys::Path(Path).isAbsolute())
+    StatCalls[Path] = StatResult(Result, StatBuf);
+  
+  return Result;
+}