Don't open or fstat files twice in llvm-ar.
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 22 Jan 2014 16:43:45 +0000 (16:43 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 22 Jan 2014 16:43:45 +0000 (16:43 +0000)
We still read/mmap them twice, but the fix for that is a bit more complex.

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

tools/llvm-ar/llvm-ar.cpp

index d4fe7d789c8bc55efc590315e5da9d4139943459..b2081e1a7b09f4938165c8536d929fb6ce7b82da 100644 (file)
@@ -395,17 +395,25 @@ namespace {
 class NewArchiveIterator {
   bool IsNewMember;
   StringRef Name;
+
   object::Archive::child_iterator OldI;
+
   std::string NewFilename;
+  mutable int NewFD;
+  mutable sys::fs::file_status NewStatus;
 
 public:
   NewArchiveIterator(object::Archive::child_iterator I, StringRef Name);
   NewArchiveIterator(std::string *I, StringRef Name);
   NewArchiveIterator();
   bool isNewMember() const;
+  StringRef getName() const;
+
   object::Archive::child_iterator getOld() const;
+
   const char *getNew() const;
-  StringRef getName() const;
+  int getFD() const;
+  const sys::fs::file_status &getStatus() const;
 };
 }
 
@@ -416,7 +424,7 @@ NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I,
     : IsNewMember(false), Name(Name), OldI(I) {}
 
 NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name)
-    : IsNewMember(true), Name(Name), NewFilename(*NewFilename) {}
+    : IsNewMember(true), Name(Name), NewFilename(*NewFilename), NewFD(-1) {}
 
 StringRef NewArchiveIterator::getName() const { return Name; }
 
@@ -432,6 +440,31 @@ const char *NewArchiveIterator::getNew() const {
   return NewFilename.c_str();
 }
 
+int NewArchiveIterator::getFD() const {
+  assert(IsNewMember);
+  if (NewFD != -1)
+    return NewFD;
+  failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename);
+  assert(NewFD != -1);
+
+  failIfError(sys::fs::status(NewFD, NewStatus), NewFilename);
+
+  // Opening a directory doesn't make sense. Let it fail.
+  // Linux cannot open directories with open(2), although
+  // cygwin and *bsd can.
+  if (NewStatus.type() == sys::fs::file_type::directory_file)
+    failIfError(error_code(errc::is_a_directory, posix_category()),
+                NewFilename);
+
+  return NewFD;
+}
+
+const sys::fs::file_status &NewArchiveIterator::getStatus() const {
+  assert(IsNewMember);
+  assert(NewFD != -1 && "Must call getFD first");
+  return NewStatus;
+}
+
 template <typename T>
 void addMember(std::vector<NewArchiveIterator> &Members, T I, StringRef Name,
                int Pos = -1) {
@@ -670,8 +703,16 @@ static void writeSymbolTable(
     object::ObjectFile *Obj;
     if (I->isNewMember()) {
       const char *Filename = I->getNew();
+      int FD = I->getFD();
+      const sys::fs::file_status &Status = I->getStatus();
+
+      OwningPtr<MemoryBuffer> File;
+      failIfError(MemoryBuffer::getOpenFile(FD, Filename, File,
+                                            Status.getSize(), false),
+                  Filename);
+
       if (ErrorOr<object::ObjectFile *> ObjOrErr =
-              object::ObjectFile::createObjectFile(Filename))
+              object::ObjectFile::createObjectFile(File.take()))
         Obj = ObjOrErr.get();
       else
         Obj = NULL;
@@ -786,19 +827,8 @@ static void performWriteOperation(ArchiveOperation Operation,
 
     if (I->isNewMember()) {
       const char *FileName = I->getNew();
-
-      int FD;
-      failIfError(sys::fs::openFileForRead(FileName, FD), FileName);
-
-      sys::fs::file_status Status;
-      failIfError(sys::fs::status(FD, Status), FileName);
-
-      // Opening a directory doesn't make sense. Let it failed.
-      // Linux cannot open directories with open(2), although
-      // cygwin and *bsd can.
-      if (Status.type() == sys::fs::file_type::directory_file)
-        failIfError(error_code(errc::is_a_directory, posix_category()),
-                    FileName);
+      int FD = I->getFD();
+      const sys::fs::file_status &Status = I->getStatus();
 
       OwningPtr<MemoryBuffer> File;
       failIfError(MemoryBuffer::getOpenFile(FD, FileName, File,