]> granicus.if.org Git - clang/commitdiff
Improve our uniquing of file entries when files are re-saved or are
authorDouglas Gregor <dgregor@apple.com>
Sat, 5 Feb 2011 19:42:43 +0000 (19:42 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 5 Feb 2011 19:42:43 +0000 (19:42 +0000)
overridden via remapping. Thus, when we create a "virtual" file in the
file manager, we still stat() the real file that lives behind it so
that we can provide proper uniquing based on inodes. This helps keep
the file manager much more consistent.

To take advantage of this when reparsing files in libclang, we disable
the use of the stat() cache when reparsing or performing code
completion, since the stat() cache is very likely to be out of date in
this use case.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124971 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Frontend/CompilerInstance.h
include/clang/Frontend/PreprocessorOptions.h
include/clang/Serialization/ASTReader.h
lib/Basic/FileManager.cpp
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/FrontendAction.cpp
lib/Sema/SemaType.cpp
lib/Serialization/ASTReader.cpp

index fd6224bd3c3f17ad98d897bb8425f2194e57f0b3..430cc603c78f0079315f7d5d0a4aa5cc12544985 100644 (file)
@@ -537,6 +537,7 @@ public:
   /// context.
   void createPCHExternalASTSource(llvm::StringRef Path,
                                   bool DisablePCHValidation,
+                                  bool DisableStatCache,
                                   void *DeserializationListener);
 
   /// Create an external AST source to read a PCH file.
@@ -545,6 +546,7 @@ public:
   static ExternalASTSource *
   createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot,
                              bool DisablePCHValidation,
+                             bool DisableStatCache,
                              Preprocessor &PP, ASTContext &Context,
                              void *DeserializationListener, bool Preamble);
 
index 2a540b61df7ff1dd8c437ca3384584e4aeaea26e..0d52e53ea16a18844cdebcba8c1b2a727074c11c 100644 (file)
@@ -48,6 +48,10 @@ public:
   /// precompiled headers.
   bool DisablePCHValidation;
 
+  /// \brief When true, disables the use of the stat cache within a
+  /// precompiled header or AST file.
+  bool DisableStatCache;
+
   /// \brief Dump declarations that are deserialized from PCH, for testing.
   bool DumpDeserializedPCHDecls;
 
@@ -125,7 +129,7 @@ public:
   
 public:
   PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
-                          DisablePCHValidation(false),
+                          DisablePCHValidation(false), DisableStatCache(false),
                           DumpDeserializedPCHDecls(false),
                           PrecompiledPreambleBytes(0, true),
                           RetainRemappedFileBuffers(false) { }
index 38b0c57d221c768dbe4c7094d5c8d2a01260bf4a..b9bf5f60b69e9c828663c3c85daf1e4827366b79 100644 (file)
@@ -590,6 +590,9 @@ private:
   /// headers when they are loaded.
   bool DisableValidation;
       
+  /// \brief Whether to disable the use of stat caches in AST files.
+  bool DisableStatCache;
+
   /// \brief Mapping from switch-case IDs in the chain to switch-case statements
   ///
   /// Statements usually don't have IDs, but switch cases need them, so that the
@@ -783,8 +786,14 @@ public:
   /// \param DisableValidation If true, the AST reader will suppress most
   /// of its regular consistency checking, allowing the use of precompiled
   /// headers that cannot be determined to be compatible.
+  ///
+  /// \param DisableStatCache If true, the AST reader will ignore the
+  /// stat cache in the AST files. This performance pessimization can
+  /// help when an AST file is being used in cases where the
+  /// underlying files in the file system may have changed, but
+  /// parsing should still continue.
   ASTReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0,
-            bool DisableValidation = false);
+            bool DisableValidation = false, bool DisableStatCache = false);
 
   /// \brief Load the AST file without using any pre-initialized Preprocessor.
   ///
@@ -805,9 +814,15 @@ public:
   /// \param DisableValidation If true, the AST reader will suppress most
   /// of its regular consistency checking, allowing the use of precompiled
   /// headers that cannot be determined to be compatible.
+  ///
+  /// \param DisableStatCache If true, the AST reader will ignore the
+  /// stat cache in the AST files. This performance pessimization can
+  /// help when an AST file is being used in cases where the
+  /// underlying files in the file system may have changed, but
+  /// parsing should still continue.
   ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
             Diagnostic &Diags, const char *isysroot = 0,
-            bool DisableValidation = false);
+            bool DisableValidation = false, bool DisableStatCache = false);
   ~ASTReader();
 
   /// \brief Load the precompiled header designated by the given file
index cbe90bfdc167be89f0a3a3685428f3e07e311360..138b54cc0865dd9bff7bd71861818b1f184532b4 100644 (file)
@@ -359,12 +359,43 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   NamedFileEnt.setValue(NON_EXISTENT_FILE);
 
   // We allow the directory to not exist. If it does exist we store it.
-  // 
+  FileEntry *UFE = 0;
   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
+  if (DirInfo) {
+    // Check to see if the file exists. If so, drop the virtual file
+    int FileDescriptor = -1;
+    struct stat StatBuf;
+    const char *InterndFileName = NamedFileEnt.getKeyData();
+    if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
+      // If the stat process opened the file, close it to avoid a FD leak.
+      if (FileDescriptor != -1)
+        close(FileDescriptor);
+
+      StatBuf.st_size = Size;
+      StatBuf.st_mtime = ModificationTime;
+      UFE = &UniqueFiles.getFile(InterndFileName, StatBuf);
+
+      NamedFileEnt.setValue(UFE);
+
+      // If we had already opened this file, close it now so we don't
+      // leak the descriptor. We're not going to use the file
+      // descriptor anyway, since this is a virtual file.
+      if (UFE->FD != -1) {
+        close(UFE->FD); 
+        UFE->FD = -1;
+      }
+
+      // If we already have an entry with this inode, return it.
+      if (UFE->getName()) 
+        return UFE;
+    }
+  }
 
-  FileEntry *UFE = new FileEntry();
-  VirtualFileEntries.push_back(UFE);
-  NamedFileEnt.setValue(UFE);
+  if (!UFE) {
+    UFE = new FileEntry();
+    VirtualFileEntries.push_back(UFE);
+    NamedFileEnt.setValue(UFE);
+  }
 
   // Get the null-terminated file name as stored as the key of the
   // FileEntries map.
@@ -375,23 +406,7 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   UFE->ModTime = ModificationTime;
   UFE->Dir     = DirInfo;
   UFE->UID     = NextFileUID++;
-  
-  // If this virtual file resolves to a file, also map that file to the 
-  // newly-created file entry.
-  int FileDescriptor = -1;
-  struct stat StatBuf;
-  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
-    // If the stat process opened the file, close it to avoid a FD leak.
-    if (FileDescriptor != -1)
-      close(FileDescriptor);
-
-    return UFE;
-  }
-  
-  UFE->FD = FileDescriptor;
-  llvm::SmallString<128> FilePath(UFE->Name);
-  llvm::sys::fs::make_absolute(FilePath);
-  FileEntries[FilePath] = UFE;
+  UFE->FD      = -1;
   return UFE;
 }
 
index 1db81cb13e8a293e10fd7d741a4eb95fc85cd6a5..1138cd7db0ddb3b890205c98a826c133eff3e092 100644 (file)
@@ -1580,6 +1580,7 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
 
   // Remap files.
   PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts();
+  PPOpts.DisableStatCache = true;
   for (PreprocessorOptions::remapped_file_buffer_iterator 
          R = PPOpts.remapped_file_buffer_begin(),
          REnd = PPOpts.remapped_file_buffer_end();
@@ -1948,6 +1949,7 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
 
   // If the main file has been overridden due to the use of a preamble,
   // make that override happen and introduce the preamble.
+  PreprocessorOpts.DisableStatCache = true;
   StoredDiagnostics.insert(StoredDiagnostics.end(),
                            this->StoredDiagnostics.begin(),
              this->StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver);
index 92aed39b5c34fc32cbced5812656b9e227cd391a..412e7111e4801bc8bca1a7da227020487f885f68 100644 (file)
@@ -234,11 +234,13 @@ void CompilerInstance::createASTContext() {
 
 void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
                                                   bool DisablePCHValidation,
+                                                  bool DisableStatCache,
                                                  void *DeserializationListener){
   llvm::OwningPtr<ExternalASTSource> Source;
   bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
   Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
-                                          DisablePCHValidation,
+                                          DisablePCHValidation, 
+                                          DisableStatCache,
                                           getPreprocessor(), getASTContext(),
                                           DeserializationListener,
                                           Preamble));
@@ -249,6 +251,7 @@ ExternalASTSource *
 CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
                                              const std::string &Sysroot,
                                              bool DisablePCHValidation,
+                                             bool DisableStatCache,
                                              Preprocessor &PP,
                                              ASTContext &Context,
                                              void *DeserializationListener,
@@ -256,7 +259,7 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
   llvm::OwningPtr<ASTReader> Reader;
   Reader.reset(new ASTReader(PP, &Context,
                              Sysroot.empty() ? 0 : Sysroot.c_str(),
-                             DisablePCHValidation));
+                             DisablePCHValidation, DisableStatCache));
 
   Reader->setDeserializationListener(
             static_cast<ASTDeserializationListener *>(DeserializationListener));
index 5f78fb17723d33eb3975eedd1cf0c038451f147e..af23923002dc32fb730dce5a00a56cf6a7f918dc 100644 (file)
@@ -224,6 +224,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
       CI.createPCHExternalASTSource(
                                 CI.getPreprocessorOpts().ImplicitPCHInclude,
                                 CI.getPreprocessorOpts().DisablePCHValidation,
+                                CI.getPreprocessorOpts().DisableStatCache,
                                 DeserialListener);
       if (!CI.getASTContext().getExternalSource())
         goto failure;
index a1908126efcb5719a1e9da0d2cdcce54c0374472..9206b1bed6ea11b3ad09eccb67e46417527abb63 100644 (file)
@@ -505,8 +505,6 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
         break;
       }
     }
-    assert(!isOnlyParens &&
-           "non-empty abstract-declarator contained only parens!");
   }
 #endif
 
index 68e2e79dde4a2310083285688e784946825c0b09..d2d20bfdbdf84b575baa35992314b69469ac92ff 100644 (file)
@@ -2034,12 +2034,14 @@ ASTReader::ReadASTBlock(PerFileData &F) {
       break;
 
     case STAT_CACHE: {
-      ASTStatCache *MyStatCache =
-        new ASTStatCache((const unsigned char *)BlobStart + Record[0],
-                         (const unsigned char *)BlobStart,
-                         NumStatHits, NumStatMisses);
-      FileMgr.addStatCache(MyStatCache);
-      F.StatCache = MyStatCache;
+      if (!DisableStatCache) {
+        ASTStatCache *MyStatCache =
+          new ASTStatCache((const unsigned char *)BlobStart + Record[0],
+                           (const unsigned char *)BlobStart,
+                           NumStatHits, NumStatMisses);
+        FileMgr.addStatCache(MyStatCache);
+        F.StatCache = MyStatCache;
+      }
       break;
     }
 
@@ -4668,28 +4670,32 @@ void ASTReader::FinishedDeserializing() {
 }
 
 ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context,
-                     const char *isysroot, bool DisableValidation)
+                     const char *isysroot, bool DisableValidation,
+                     bool DisableStatCache)
   : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
     SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
     Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context),
     Consumer(0), isysroot(isysroot), DisableValidation(DisableValidation),
-    NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0),
-    TotalNumSLocEntries(0), NextSLocOffset(0), NumStatementsRead(0),
-    TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0),
-    NumSelectorsRead(0), NumMethodPoolEntriesRead(0), NumMethodPoolMisses(0),
-    TotalNumMethodPoolEntries(0), NumLexicalDeclContextsRead(0),
-    TotalLexicalDeclContexts(0), NumVisibleDeclContextsRead(0),
-    TotalVisibleDeclContexts(0), NumCurrentElementsDeserializing(0) {
+    DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0), 
+    NumSLocEntriesRead(0), TotalNumSLocEntries(0), NextSLocOffset(0), 
+    NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), 
+    TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), 
+    NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0), 
+    NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0), 
+    NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0), 
+    NumCurrentElementsDeserializing(0) 
+{
   RelocatablePCH = false;
 }
 
 ASTReader::ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
                      Diagnostic &Diags, const char *isysroot,
-                     bool DisableValidation)
+                     bool DisableValidation, bool DisableStatCache)
   : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr),
     Diags(Diags), SemaObj(0), PP(0), Context(0), Consumer(0),
-    isysroot(isysroot), DisableValidation(DisableValidation), NumStatHits(0),
-    NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0),
+    isysroot(isysroot), DisableValidation(DisableValidation), 
+    DisableStatCache(DisableStatCache), NumStatHits(0), NumStatMisses(0), 
+    NumSLocEntriesRead(0), TotalNumSLocEntries(0),
     NextSLocOffset(0), NumStatementsRead(0), TotalNumStatements(0),
     NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0),
     NumMethodPoolEntriesRead(0), NumMethodPoolMisses(0),