Reduce the number of system calls. Use readv instead of pread. Do
authorIan Lance Taylor <iant@google.com>
Wed, 2 Jan 2008 23:48:49 +0000 (23:48 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 2 Jan 2008 23:48:49 +0000 (23:48 +0000)
better handling of cached views.

12 files changed:
gold/archive.cc
gold/archive.h
gold/dynobj.cc
gold/fileread.cc
gold/fileread.h
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/reloc.cc
gold/symtab.cc
gold/symtab.h

index 53b5cd0de650b7df44c86da27dee2b04acc68456..2125608e7d95214e88ce418e2cbce775a3e8c7c5 100644 (file)
@@ -85,7 +85,8 @@ Archive::setup(Task* task)
   // The first member of the archive should be the symbol table.
   std::string armap_name;
   section_size_type armap_size =
-    convert_to_section_size_type(this->read_header(sarmag, &armap_name));
+    convert_to_section_size_type(this->read_header(sarmag, false,
+                                                  &armap_name));
   off_t off = sarmag;
   if (armap_name.empty())
     {
@@ -96,15 +97,18 @@ Archive::setup(Task* task)
     gold_error(_("%s: no archive symbol table (run ranlib)"),
               this->name().c_str());
 
-  // See if there is an extended name table.
+  // See if there is an extended name table.  We cache these views
+  // because it is likely that we will want to read the following
+  // header in the add_symbols routine.
   if ((off & 1) != 0)
     ++off;
   std::string xname;
-  off_t extended_size = this->read_header(off, &xname);
+  section_size_type extended_size =
+    convert_to_section_size_type(this->read_header(off, true, &xname));
   if (xname == "/")
     {
       const unsigned char* p = this->get_view(off + sizeof(Archive_header),
-                                              extended_size, false);
+                                              extended_size, true);
       const char* px = reinterpret_cast<const char*>(p);
       this->extended_names_.assign(px, extended_size);
     }
@@ -157,9 +161,9 @@ Archive::read_armap(off_t start, section_size_type size)
 // of the member.
 
 off_t
-Archive::read_header(off_t off, std::string* pname)
+Archive::read_header(off_t off, bool cache, std::string* pname)
 {
-  const unsigned char* p = this->get_view(off, sizeof(Archive_header), false);
+  const unsigned char* p = this->get_view(off, sizeof(Archive_header), cache);
   const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
   return this->interpret_header(hdr, off,  pname);
 }
@@ -370,7 +374,7 @@ Archive::include_member(Symbol_table* symtab, Layout* layout,
                        Input_objects* input_objects, off_t off)
 {
   std::string n;
-  this->read_header(off, &n);
+  this->read_header(off, false, &n);
 
   const off_t memoff = off + static_cast<off_t>(sizeof(Archive_header));
 
index fb83ea629c608dd907b09a3381d4bcaf6ad22a6b..0dfaf92d06fa22edc8166a5ec6bf39704a104af8 100644 (file)
@@ -117,10 +117,11 @@ class Archive
   void
   read_armap(off_t start, section_size_type size);
 
-  // Read an archive member header at OFF.  Return the size of the
-  // member, and set *PNAME to the name.
+  // Read an archive member header at OFF.  CACHE is whether to cache
+  // the file view.  Return the size of the member, and set *PNAME to
+  // the name.
   off_t
-  read_header(off_t off, std::string* pname);
+  read_header(off_t off, bool cache, std::string* pname);
 
   // Interpret an archive header HDR at OFF.  Return the size of the
   // member, and set *PNAME to the name.
index 7e610074ca8b4455c461a004478010c10bffd8d8..3c3549d8e27ba1310f9aac961c747687db5e3f06 100644 (file)
@@ -335,7 +335,7 @@ Sized_dynobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
 
       sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(),
                                                strtabshdr.get_sh_size(),
-                                               true);
+                                               false);
       sd->symbol_names_size =
        convert_to_section_size_type(strtabshdr.get_sh_size());
 
@@ -667,6 +667,10 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
       delete sd->verneed;
       sd->verneed = NULL;
     }
+
+  // This is normally the last time we will read any data from this
+  // file.
+  this->clear_view_cache_marks();
 }
 
 // Given a vector of hash codes, compute the number of hash buckets to
index defb3a02560f9a683ef3e2267c5958502af5d2c4..010c2eebbad9bac95e11ab9184defcde32a40841 100644 (file)
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/uio.h>
 #include "filenames.h"
 
 #include "options.h"
@@ -194,11 +195,21 @@ inline File_read::View*
 File_read::find_view(off_t start, section_size_type size) const
 {
   off_t page = File_read::page_offset(start);
-  Views::const_iterator p = this->views_.find(page);
-  if (p == this->views_.end())
-    return NULL;
-  if (p->second->size() - (start - page) < size)
+
+  Views::const_iterator p = this->views_.lower_bound(page);
+  if (p == this->views_.end() || p->first > page)
+    {
+      if (p == this->views_.begin())
+       return NULL;
+      --p;
+    }
+
+  if (p->second->start() + static_cast<off_t>(p->second->size())
+      < start + static_cast<off_t>(size))
     return NULL;
+
+  p->second->set_accessed();
+
   return p->second;
 }
 
@@ -244,7 +255,7 @@ File_read::do_read(off_t start, section_size_type size, void* p) const
 void
 File_read::read(off_t start, section_size_type size, void* p) const
 {
-  File_read::View* pv = this->find_view(start, size);
+  const File_read::View* pv = this->find_view(start, size);
   if (pv != NULL)
     {
       memcpy(p, pv->data() + (start - pv->start()), size);
@@ -262,6 +273,14 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache)
   gold_assert(!this->token_.is_writable());
   this->released_ = false;
 
+  File_read::View* v = this->find_view(start, size);
+  if (v != NULL)
+    {
+      if (cache)
+       v->set_cache();
+      return v;
+    }
+
   off_t poff = File_read::page_offset(start);
 
   File_read::View* const vnull = NULL;
@@ -270,21 +289,19 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache)
 
   if (!ins.second)
     {
-      // There was an existing view at this offset.
-      File_read::View* v = ins.first->second;
-      if (v->size() - (start - v->start()) >= size)
-       {
-         if (cache)
-           v->set_cache();
-         return v;
-       }
-
-      // This view is not large enough.
+      // There was an existing view at this offset.  It must not be
+      // large enough.  We can't delete it here, since something might
+      // be using it; put it on a list to be deleted when the file is
+      // unlocked.
+      v = ins.first->second;
+      gold_assert(v->size() - (start - v->start()) < size);
+      if (v->should_cache())
+       cache = true;
+      v->clear_cache();
       this->saved_views_.push_back(v);
     }
 
-  // We need to read data from the file.  We read full pages for
-  // greater efficiency on small files.
+  // We need to map data from the file.
 
   section_size_type psize = File_read::pages(size + (start - poff));
 
@@ -294,8 +311,6 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache)
       gold_assert(psize >= size);
     }
 
-  File_read::View* v;
-
   if (this->contents_ != NULL)
     {
       unsigned char* p = new unsigned char[psize];
@@ -304,7 +319,7 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache)
     }
   else
     {
-      void* p = ::mmap(NULL, psize, PROT_READ, MAP_SHARED,
+      void* p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE,
                        this->descriptor_, poff);
       if (p == MAP_FAILED)
        gold_fatal(_("%s: mmap offset %lld size %lld failed: %s"),
@@ -340,7 +355,143 @@ File_read::get_lasting_view(off_t start, section_size_type size, bool cache)
   return new File_view(*this, pv, pv->data() + (start - pv->start()));
 }
 
-// Remove all the file views.
+// Use readv to read COUNT entries from RM starting at START.  BASE
+// must be added to all file offsets in RM.
+
+void
+File_read::do_readv(off_t base, const Read_multiple& rm, size_t start,
+                   size_t count)
+{
+  unsigned char discard[File_read::page_size];
+  iovec iov[File_read::max_readv_entries * 2];
+  size_t iov_index = 0;
+
+  off_t first_offset = rm[start].file_offset;
+  off_t last_offset = first_offset;
+  ssize_t want = 0;
+  for (size_t i = 0; i < count; ++i)
+    {
+      const Read_multiple_entry& i_entry(rm[start + i]);
+
+      if (i_entry.file_offset > last_offset)
+       {
+         size_t skip = i_entry.file_offset - last_offset;
+         gold_assert(skip <= sizeof discard);
+
+         iov[iov_index].iov_base = discard;
+         iov[iov_index].iov_len = skip;
+         ++iov_index;
+
+         want += skip;
+       }
+
+      iov[iov_index].iov_base = i_entry.buffer;
+      iov[iov_index].iov_len = i_entry.size;
+      ++iov_index;
+
+      want += i_entry.size;
+
+      last_offset = i_entry.file_offset + i_entry.size;
+    }
+
+  gold_assert(iov_index < sizeof iov / sizeof iov[0]);
+
+  if (::lseek(this->descriptor_, base + first_offset, SEEK_SET) < 0)
+    gold_fatal(_("%s: lseek failed: %s"),
+              this->filename().c_str(), strerror(errno));
+
+  ssize_t got = ::readv(this->descriptor_, iov, iov_index);
+
+  if (got < 0)
+    gold_fatal(_("%s: readv failed: %s"),
+              this->filename().c_str(), strerror(errno));
+  if (got != want)
+    gold_fatal(_("%s: file too short: read only %zd of %zd bytes at %lld"),
+              this->filename().c_str(),
+              got, want, static_cast<long long>(base + first_offset));
+}
+
+// Read several pieces of data from the file.
+
+void
+File_read::read_multiple(off_t base, const Read_multiple& rm)
+{
+  size_t count = rm.size();
+  size_t i = 0;
+  while (i < count)
+    {
+      // Find up to MAX_READV_ENTRIES consecutive entries which are
+      // less than one page apart.
+      const Read_multiple_entry& i_entry(rm[i]);
+      off_t i_off = i_entry.file_offset;
+      off_t end_off = i_off + i_entry.size;
+      size_t j;
+      for (j = i + 1; j < count; ++j)
+       {
+         if (j - i >= File_read::max_readv_entries)
+           break;
+         const Read_multiple_entry& j_entry(rm[j]);
+         off_t j_off = j_entry.file_offset;
+         gold_assert(j_off >= end_off);
+         off_t j_end_off = j_off + j_entry.size;
+         if (j_end_off - end_off >= File_read::page_size)
+           break;
+         end_off = j_end_off;
+       }
+
+      if (j == i + 1)
+       this->read(base + i_off, i_entry.size, i_entry.buffer);
+      else
+       {
+         File_read::View* view = this->find_view(base + i_off,
+                                                 end_off - i_off);
+         if (view == NULL)
+           this->do_readv(base, rm, i, j - i);
+         else
+           {
+             const unsigned char* v = (view->data()
+                                       + (base + i_off - view->start()));
+             for (size_t k = i; k < j; ++k)
+               {
+                 const Read_multiple_entry& k_entry(rm[k]);
+                 gold_assert(k_entry.file_offset - i_off + k_entry.size
+                             <= end_off - i_off);
+                 memcpy(k_entry.buffer,
+                        v + (k_entry.file_offset - i_off),
+                        k_entry.size);
+               }
+           }
+       }
+
+      i = j;
+    }
+}
+
+// Mark all views as no longer cached.
+
+void
+File_read::clear_view_cache_marks()
+{
+  // Just ignore this if there are multiple objects associated with
+  // the file.  Otherwise we will wind up uncaching and freeing some
+  // views for other objects.
+  if (this->object_count_ > 1)
+    return;
+
+  for (Views::iterator p = this->views_.begin();
+       p != this->views_.end();
+       ++p)
+    p->second->clear_cache();
+  for (Saved_views::iterator p = this->saved_views_.begin();
+       p != this->saved_views_.end();
+       ++p)
+    (*p)->clear_cache();
+}
+
+// Remove all the file views.  For a file which has multiple
+// associated objects (i.e., an archive), we keep accessed views
+// around until next time, in the hopes that they will be useful for
+// the next object.
 
 void
 File_read::clear_views(bool destroying)
@@ -348,8 +499,19 @@ File_read::clear_views(bool destroying)
   Views::iterator p = this->views_.begin();
   while (p != this->views_.end())
     {
-      if (!p->second->is_locked()
-         && (destroying || !p->second->should_cache()))
+      bool should_delete;
+      if (p->second->is_locked())
+       should_delete = false;
+      else if (destroying)
+       should_delete = true;
+      else if (p->second->should_cache())
+       should_delete = false;
+      else if (this->object_count_ > 1 && p->second->accessed())
+       should_delete = false;
+      else
+       should_delete = true;
+
+      if (should_delete)
        {
          delete p->second;
 
@@ -362,6 +524,7 @@ File_read::clear_views(bool destroying)
       else
        {
          gold_assert(!destroying);
+         p->second->clear_accessed();
          ++p;
        }
     }
@@ -369,8 +532,7 @@ File_read::clear_views(bool destroying)
   Saved_views::iterator q = this->saved_views_.begin();
   while (q != this->saved_views_.end())
     {
-      if (!(*q)->is_locked()
-         && (destroying || !(*q)->should_cache()))
+      if (!(*q)->is_locked())
        {
          delete *q;
          q = this->saved_views_.erase(q);
index 1c47f24e47c81e8eea825deeb3053166902f5cee..428c2f040318717e9720b4a2d3e215268178e63f 100644 (file)
@@ -46,8 +46,9 @@ class File_read
 {
  public:
   File_read()
-    : name_(), descriptor_(-1), size_(0), token_(false), views_(),
-      saved_views_(), contents_(NULL), mapped_bytes_(0), released_(true)
+    : name_(), descriptor_(-1), object_count_(0), size_(0), token_(false),
+      views_(), saved_views_(), contents_(NULL), mapped_bytes_(0),
+      released_(true)
   { }
 
   ~File_read();
@@ -68,6 +69,16 @@ class File_read
   filename() const
   { return this->name_; }
 
+  // Add an object associated with a file.
+  void
+  add_object()
+  { ++this->object_count_; }
+
+  // Remove an object associated with a file.
+  void
+  remove_object()
+  { --this->object_count_; }
+
   // Lock the file for exclusive access within a particular Task::run
   // execution.  This means that the descriptor can not be closed.
   // This routine may only be called when the workqueue lock is held.
@@ -126,6 +137,34 @@ class File_read
   File_view*
   get_lasting_view(off_t start, section_size_type size, bool cache);
 
+  // Mark all views as no longer cached.
+  void
+  clear_view_cache_marks();
+
+  // A struct used to do a multiple read.
+  struct Read_multiple_entry
+  {
+    // The file offset of the data to read.
+    off_t file_offset;
+    // The amount of data to read.
+    section_size_type size;
+    // The buffer where the data should be placed.
+    unsigned char* buffer;
+
+    Read_multiple_entry(off_t o, section_size_type s, unsigned char* b)
+      : file_offset(o), size(s), buffer(b)
+    { }
+  };
+
+  typedef std::vector<Read_multiple_entry> Read_multiple;
+
+  // Read a bunch of data from the file into various different
+  // locations.  The vector must be sorted by ascending file_offset.
+  // BASE is a base offset to be added to all the offsets in the
+  // vector.
+  void
+  read_multiple(off_t base, const Read_multiple&);
+
   // Dump statistical information to stderr.
   static void
   print_stats();
@@ -154,7 +193,7 @@ class File_read
     View(off_t start, section_size_type size, const unsigned char* data,
         bool cache, bool mapped)
       : start_(start), size_(size), data_(data), lock_count_(0),
-       cache_(cache), mapped_(mapped)
+       cache_(cache), mapped_(mapped), accessed_(true)
     { }
 
     ~View();
@@ -184,10 +223,26 @@ class File_read
     set_cache()
     { this->cache_ = true; }
 
+    void
+    clear_cache()
+    { this->cache_ = false; }
+
     bool
     should_cache() const
     { return this->cache_; }
 
+    void
+    set_accessed()
+    { this->accessed_ = true; }
+
+    void
+    clear_accessed()
+    { this->accessed_= false; }
+
+    bool
+    accessed() const
+    { return this->accessed_; }
+
    private:
     View(const View&);
     View& operator=(const View&);
@@ -198,6 +253,7 @@ class File_read
     int lock_count_;
     bool cache_;
     bool mapped_;
+    bool accessed_;
   };
 
   friend class View;
@@ -238,10 +294,20 @@ class File_read
   // A simple list of Views.
   typedef std::list<View*> Saved_views;
 
+  // The maximum number of entries we will pass to ::readv.
+  static const size_t max_readv_entries = 128;
+
+  // Use readv to read data.
+  void
+  do_readv(off_t base, const Read_multiple&, size_t start, size_t count);
+
   // File name.
   std::string name_;
   // File descriptor.
   int descriptor_;
+  // The number of objects associated with this file.  This will be
+  // more than 1 in the case of an archive.
+  int object_count_;
   // File size.
   off_t size_;
   // A token used to lock the file.
index 3897ec7c24c98436da3bf96f833f15181715b51a..eebb26c5686fdfa0a97742ef3e5639977445d720 100644 (file)
@@ -739,7 +739,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS);
 
   // Create the symbol table sections.
-  this->create_symtab_sections(input_objects, symtab, task, &off);
+  this->create_symtab_sections(input_objects, symtab, &off);
   if (!parameters->doing_static_link())
     this->assign_local_dynsym_offsets(input_objects);
 
@@ -1212,7 +1212,6 @@ Layout::count_local_symbols(const Task* task,
 void
 Layout::create_symtab_sections(const Input_objects* input_objects,
                               Symbol_table* symtab,
-                              const Task* task,
                               off_t* poff)
 {
   int symsize;
@@ -1286,7 +1285,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
                  == this->dynsym_section_->data_size() - locsize);
     }
 
-  off = symtab->finalize(task, local_symcount, off, dynoff, dyn_global_index,
+  off = symtab->finalize(local_symcount, off, dynoff, dyn_global_index,
                         dyncount, &this->sympool_);
 
   if (!parameters->strip_all())
index 3084d606a3e95e785b45034e298e131e8035fe4e..131d6a6cd38f691a1b6d95e24c93dceda8880edc 100644 (file)
@@ -292,8 +292,7 @@ class Layout
 
   // Create the output sections for the symbol table.
   void
-  create_symtab_sections(const Input_objects*, Symbol_table*, const Task*,
-                        off_t*);
+  create_symtab_sections(const Input_objects*, Symbol_table*, off_t*);
 
   // Create the .shstrtab section.
   Output_section*
index 1a0d0647ebaa5a5400830c79a43d2cc1075d684d..e56f6a4c7cc025b9c6c80ab08ae95887d7c2bf2a 100644 (file)
@@ -125,7 +125,17 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
   const int warn_prefix_len = sizeof warn_prefix - 1;
   if (strncmp(name, warn_prefix, warn_prefix_len) == 0)
     {
-      symtab->add_warning(name + warn_prefix_len, this, shndx);
+      // Read the section contents to get the warning text.  It would
+      // be nicer if we only did this if we have to actually issue a
+      // warning.  Unfortunately, warnings are issued as we relocate
+      // sections.  That means that we can not lock the object then,
+      // as we might try to issue the same warning multiple times
+      // simultaneously.
+      section_size_type len;
+      const unsigned char* contents = this->section_contents(shndx, &len,
+                                                            false);
+      std::string warning(reinterpret_cast<const char*>(contents), len);
+      symtab->add_warning(name + warn_prefix_len, this, warning);
       return true;
     }
   return false;
@@ -404,7 +414,7 @@ Sized_relobj<size, big_endian>::include_section_group(
       return false;
     }
   off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
-  const unsigned char* psym = this->get_view(symoff, This::sym_size, true);
+  const unsigned char* psym = this->get_view(symoff, This::sym_size, false);
   elfcpp::Sym<size, big_endian> sym(psym);
 
   // Read the symbol table names.
@@ -729,10 +739,11 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
   sd->symbol_names = NULL;
 }
 
-// Finalize the local symbols.  Here we add their names to *POOL and
-// *DYNPOOL, and we add their values to THIS->LOCAL_VALUES_.  This
-// function is always called from a singleton thread.  The actual
-// output of the local symbols will occur in a separate task.
+// First pass over the local symbols.  Here we add their names to
+// *POOL and *DYNPOOL, and we store the symbol value in
+// THIS->LOCAL_VALUES_.  This function is always called from a
+// singleton thread.  This is followed by a call to
+// finalize_local_symbols.
 
 template<int size, bool big_endian>
 void
@@ -833,7 +844,7 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
   this->output_local_dynsym_count_ = dyncount;
 }
 
-// Finalize the local symbols.  Here we add their values to
+// Finalize the local symbols.  Here we set the final value in
 // THIS->LOCAL_VALUES_ and set their output symbol table indexes.
 // This function is always called from a singleton thread.  The actual
 // output of the local symbols will occur in a separate task.
@@ -1008,7 +1019,7 @@ Sized_relobj<size, big_endian>::write_local_symbols(
   section_size_type strtab_size;
   const unsigned char* pnamesu = this->section_contents(strtab_shndx,
                                                        &strtab_size,
-                                                       true);
+                                                       false);
   const char* pnames = reinterpret_cast<const char*>(pnamesu);
 
   // Get views into the output file for the portions of the symbol table
index f5e4ab62482b2210216eb276fff7c33a45eee393..e4140be8fc14dc59925e8dab163e26c3e18f9fbb 100644 (file)
@@ -139,10 +139,10 @@ class Object
         off_t offset = 0)
     : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
       is_dynamic_(is_dynamic), target_(NULL)
-  { }
+  { input_file->file().add_object(); }
 
   virtual ~Object()
-  { }
+  { this->input_file_->file().remove_object(); }
 
   // Return the name of the object as we would report it to the tuser.
   const std::string&
@@ -294,6 +294,37 @@ class Object
   View view(Location loc)
   { return View(this->get_view(loc.file_offset, loc.data_size, true)); }
 
+  // Get a view into the underlying file.
+  const unsigned char*
+  get_view(off_t start, section_size_type size, bool cache)
+  {
+    return this->input_file()->file().get_view(start + this->offset_, size,
+                                              cache);
+  }
+
+  // Get a lasting view into the underlying file.
+  File_view*
+  get_lasting_view(off_t start, section_size_type size, bool cache)
+  {
+    return this->input_file()->file().get_lasting_view(start + this->offset_,
+                                                      size, cache);
+  }
+
+  // Read data from the underlying file.
+  void
+  read(off_t start, section_size_type size, void* p) const
+  { this->input_file()->file().read(start + this->offset_, size, p); }
+
+  // Read multiple data from the underlying file.
+  void
+  read_multiple(const File_read::Read_multiple& rm)
+  { this->input_file()->file().read_multiple(this->offset_, rm); }
+
+  // Stop caching views in the underlying file.
+  void
+  clear_view_cache_marks()
+  { this->input_file()->file().clear_view_cache_marks(); }
+
  protected:
   // Read the symbols--implemented by child class.
   virtual void
@@ -342,27 +373,6 @@ class Object
   input_file() const
   { return this->input_file_; }
 
-  // Get a view into the underlying file.
-  const unsigned char*
-  get_view(off_t start, section_size_type size, bool cache)
-  {
-    return this->input_file()->file().get_view(start + this->offset_, size,
-                                              cache);
-  }
-
-  // Get a lasting view into the underlying file.
-  File_view*
-  get_lasting_view(off_t start, section_size_type size, bool cache)
-  {
-    return this->input_file()->file().get_lasting_view(start + this->offset_,
-                                                      size, cache);
-  }
-
-  // Read data from the underlying file.
-  void
-  read(off_t start, section_size_type size, void* p) const
-  { this->input_file()->file().read(start + this->offset_, size, p); }
-
   // Set the target.
   void
   set_target(int machine, int size, bool big_endian, int osabi,
@@ -1206,7 +1216,7 @@ class Sized_relobj : public Relobj
   // Write section data to the output file.  Record the views and
   // sizes in VIEWS for use when relocating.
   void
-  write_sections(const unsigned char* pshdrs, Output_file*, Views*) const;
+  write_sections(const unsigned char* pshdrs, Output_file*, Views*);
 
   // Relocate the sections in the output file.
   void
@@ -1229,6 +1239,15 @@ class Sized_relobj : public Relobj
                      const Stringpool_template<char>*,
                      const Stringpool_template<char>*);
 
+  // Clear the local symbol information.
+  void
+  clear_local_symbols()
+  {
+    this->local_values_.clear();
+    this->local_got_offsets_.clear();
+    this->local_tls_got_offsets_.clear();
+  }
+
   // The GOT offsets of local symbols. This map also stores GOT offsets
   // for tp-relative offsets for TLS symbols.
   typedef Unordered_map<unsigned int, unsigned int> Local_got_offsets;
index f88151fb0ec19c86e57538867094efc86d4f7c6c..d361f165d9fc92b6cab74ed947ce756492f11447 100644 (file)
@@ -22,6 +22,8 @@
 
 #include "gold.h"
 
+#include <algorithm>
+
 #include "workqueue.h"
 #include "symtab.h"
 #include "output.h"
@@ -159,6 +161,11 @@ Relocate_task::run(Workqueue*)
 {
   this->object_->relocate(this->options_, this->symtab_, this->layout_,
                          this->of_);
+
+  // This is normally the last thing we will do with an object, so
+  // uncache all views.
+  this->object_->clear_view_cache_marks();
+
   this->object_->release();
 }
 
@@ -376,8 +383,20 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
 
   // Write out the local symbols.
   this->write_local_symbols(of, layout->sympool(), layout->dynpool());
+
+  // We should no longer need the local symbol values.
+  this->clear_local_symbols();
 }
 
+// Sort a Read_multiple vector by file offset.
+struct Read_multiple_compare
+{
+  inline bool
+  operator()(const File_read::Read_multiple_entry& rme1,
+            const File_read::Read_multiple_entry& rme2) const
+  { return rme1.file_offset < rme2.file_offset; }
+};
+
 // Write section data to the output file.  PSHDRS points to the
 // section headers.  Record the views in *PVIEWS for use when
 // relocating.
@@ -386,11 +405,14 @@ template<int size, bool big_endian>
 void
 Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
                                               Output_file* of,
-                                              Views* pviews) const
+                                              Views* pviews)
 {
   unsigned int shnum = this->shnum();
   const std::vector<Map_to_output>& map_sections(this->map_to_output());
 
+  File_read::Read_multiple rm;
+  bool is_sorted = true;
+
   const unsigned char* p = pshdrs + This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
     {
@@ -468,7 +490,13 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
          unsigned char* buffer = os->postprocessing_buffer();
          view = buffer + view_start;
          if (output_offset != -1)
-           this->read(shdr.get_sh_offset(), view_size, view);
+           {
+             off_t sh_offset = shdr.get_sh_offset();
+             if (!rm.empty() && rm.back().file_offset > sh_offset)
+               is_sorted = false;
+             rm.push_back(File_read::Read_multiple_entry(sh_offset,
+                                                         view_size, view));
+           }
        }
       else
        {
@@ -477,7 +505,11 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
          else
            {
              view = of->get_output_view(view_start, view_size);
-             this->read(shdr.get_sh_offset(), view_size, view);
+             off_t sh_offset = shdr.get_sh_offset();
+             if (!rm.empty() && rm.back().file_offset > sh_offset)
+               is_sorted = false;
+             rm.push_back(File_read::Read_multiple_entry(sh_offset,
+                                                         view_size, view));
            }
        }
 
@@ -490,6 +522,14 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
       pvs->is_input_output_view = output_offset == -1;
       pvs->is_postprocessing_view = os->requires_postprocessing();
     }
+
+  // Actually read the data.
+  if (!rm.empty())
+    {
+      if (!is_sorted)
+       std::sort(rm.begin(), rm.end(), Read_multiple_compare());
+      this->read_multiple(rm);
+    }
 }
 
 // Relocate section data.  VIEWS points to the section data as views
index 4a1c5ee9ef78cb362ad1f1a7e0a0c9e10fbd6653..a9f51386d475268b59e4b4a45387c50f663bb936 100644 (file)
@@ -1403,8 +1403,8 @@ Symbol_table::set_dynsym_indexes(const Target* target,
 // OFF.  Add their names to POOL.  Return the new file offset.
 
 off_t
-Symbol_table::finalize(const Task* task, unsigned int index, off_t off,
-                      off_t dynoff, size_t dyn_global_index, size_t dyncount,
+Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff,
+                      size_t dyn_global_index, size_t dyncount,
                       Stringpool* pool)
 {
   off_t ret;
@@ -1437,7 +1437,7 @@ Symbol_table::finalize(const Task* task, unsigned int index, off_t off,
 
   // Now that we have the final symbol table, we can reliably note
   // which symbols should get warnings.
-  this->warnings_.note_warnings(this, task);
+  this->warnings_.note_warnings(this);
 
   return ret;
 }
@@ -2004,10 +2004,10 @@ Symbol_table::detect_odr_violations(const Task* task,
 
 void
 Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
-                     unsigned int shndx)
+                     const std::string& warning)
 {
   name = symtab->canonicalize_name(name);
-  this->warnings_[name].set(obj, shndx);
+  this->warnings_[name].set(obj, warning);
 }
 
 // Look through the warnings and mark the symbols for which we should
@@ -2015,7 +2015,7 @@ Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
 // sources for all the symbols.
 
 void
-Warnings::note_warnings(Symbol_table* symtab, const Task* task)
+Warnings::note_warnings(Symbol_table* symtab)
 {
   for (Warning_table::iterator p = this->warnings_.begin();
        p != this->warnings_.end();
@@ -2025,24 +2025,7 @@ Warnings::note_warnings(Symbol_table* symtab, const Task* task)
       if (sym != NULL
          && sym->source() == Symbol::FROM_OBJECT
          && sym->object() == p->second.object)
-       {
-         sym->set_has_warning();
-
-         // Read the section contents to get the warning text.  It
-         // would be nicer if we only did this if we have to actually
-         // issue a warning.  Unfortunately, warnings are issued as
-         // we relocate sections.  That means that we can not lock
-         // the object then, as we might try to issue the same
-         // warning multiple times simultaneously.
-         {
-           Task_lock_obj<Object> tl(task, p->second.object);
-           const unsigned char* c;
-           section_size_type len;
-           c = p->second.object->section_contents(p->second.shndx, &len,
-                                                  false);
-           p->second.set_text(reinterpret_cast<const char*>(c), len);
-         }
-       }
+       sym->set_has_warning();
     }
 }
 
index 786e5cb5a8019264433f1769784d3302c494c88e..59cda2e9d060fc34852f30030fc014aa64efd494 100644 (file)
@@ -897,15 +897,16 @@ class Warnings
     : warnings_()
   { }
 
-  // Add a warning for symbol NAME in section SHNDX in object OBJ.
+  // Add a warning for symbol NAME in object OBJ.  WARNING is the text
+  // of the warning.
   void
   add_warning(Symbol_table* symtab, const char* name, Object* obj,
-             unsigned int shndx);
+             const std::string& warning);
 
   // For each symbol for which we should give a warning, make a note
   // on the symbol.
   void
-  note_warnings(Symbol_table* symtab, const Task*);
+  note_warnings(Symbol_table* symtab);
 
   // Issue a warning for a reference to SYM at RELINFO's location.
   template<int size, bool big_endian>
@@ -922,25 +923,19 @@ class Warnings
   {
     // The object the warning is in.
     Object* object;
-    // The index of the warning section.
-    unsigned int shndx;
-    // The warning text if we have already loaded it.
+    // The warning text.
     std::string text;
 
     Warning_location()
-      : object(NULL), shndx(0), text()
+      : object(NULL), text()
     { }
 
     void
-    set(Object* o, unsigned int s)
+    set(Object* o, const std::string& t)
     {
       this->object = o;
-      this->shndx = s;
+      this->text = t;
     }
-
-    void
-    set_text(const char* t, section_size_type l)
-    { this->text.assign(t, l); }
   };
 
   // A mapping from warning symbol names (canonicalized in
@@ -1057,10 +1052,11 @@ class Symbol_table
   void
   allocate_commons(const General_options&, Layout*);
 
-  // Add a warning for symbol NAME in section SHNDX in object OBJ.
+  // Add a warning for symbol NAME in object OBJ.  WARNING is the text
+  // of the warning.
   void
-  add_warning(const char* name, Object* obj, unsigned int shndx)
-  { this->warnings_.add_warning(this, name, obj, shndx); }
+  add_warning(const char* name, Object* obj, const std::string& warning)
+  { this->warnings_.add_warning(this, name, obj, warning); }
 
   // Canonicalize a symbol name for use in the hash table.
   const char*
@@ -1103,7 +1099,7 @@ class Symbol_table
   // symbol, and DYNCOUNT is the number of global dynamic symbols.
   // This records the parameters, and returns the new file offset.
   off_t
-  finalize(const Task*, unsigned int index, off_t off, off_t dynoff,
+  finalize(unsigned int index, off_t off, off_t dynoff,
           size_t dyn_global_index, size_t dyncount, Stringpool* pool);
 
   // Write out the global symbols.