2010-05-23 Doug Kwan <dougkwan@google.com>
authorDoug Kwan <dougkwan@google.com>
Sun, 23 May 2010 07:43:39 +0000 (07:43 +0000)
committerDoug Kwan <dougkwan@google.com>
Sun, 23 May 2010 07:43:39 +0000 (07:43 +0000)
* arm.cc (Arm_input_section::do_output_offset): Use convert_types
instead of a cast.
(Target_arm::apply_cortex_a8_workaround): Rewrite a conditional branch
with a direct branch, not a conditional branch, to a stub.
* merge.cc (Output_merge_base::record_input_section): New method
defintion.
(Output_merge_data::do_add_input_section): Record input section if
keeps-input-sections flag is set.
(Output_merge_string::do_add_input_section): Ditto.
* merge.h (Output_merge_base::Output_merge_base): Initialize new data
members KEEPS_INPUT_SECTIONS_, FIRST_RELOBJ_, FIRST_SHNDX_ and
INPUT_SECTIONS_.
(Output_merge_base::keeps_input_sections,
Output_merge_base::set_keeps_input_sections,
Output_merge_base::first_relobj, Output_merge_base::first_shndx): New
method definitions.
(Output_merge_base::Input_sections): New type declaration.
(Output_merge_base::input_sections_begin,
Output_merge_base::input_sections_end,
Output_merge_base::do_set_keeps_input_sections): New method definitions.
(Output_merge_base::bool keeps_input_sections_,
Output_merge_base::first_relobj_, Output_merge_base::first_shndx_,
Output_merge_base::input_sections_): New data members.
(Output_merge_data::do_set_keeps_input_sections): New method
defintion.
(Output_merge_string::do_set_keeps_input_sections): Ditto.
* output.cc (Output_section::Input_section::relobj): Move method
defintion from class declaration to here and handle merge sections.
(Output_section::Input_section::shndx): Ditto.
(Output_section::Output_section): Remove initializations of removed
data members and initialize new data member LOOKUP_MAPS_.
(Output_section::add_input_section): Set keeps-input-sections flag
for a newly created merge output section as appropriate.  Adjust code
to use Output_section_lookup_maps class.
(Output_section::add_relaxed_input_section): Adjst code for lookup
maps code refactoring.
  (Output_section::add_merge_input_section): Add a new parameter
KEEPS_INPUT_SECTION.  Adjust code to use Output_section_lookup_maps
class.  If adding input section to a newly created merge output
section fails, remove the new merge section.
(Output_section::convert_input_sections_in_list_to_relaxed_input_sections):
Adjust code for use of the Output_section_lookup_maps class.
  (Output_section::find_merge_section): Ditto.
(Output_section::build_lookup_maps): New method defintion.
  (Output_section::find_relaxed_input_section): Adjust code to use
Output_section_lookup_maps class.
(Output_section::get_input_sections): Export merge sections.  Adjust
code to use Output_section_lookup_maps class.
(Output_section:::add_script_input_section): Adjust code to use
Output_section_lookup_maps class.  Update lookup maps for merge
sections also.
(Output_section::discard_states): Use Output_section_lookup_maps.
(Output_section::restore_states): Same.
* output.h (Merge_section_properties): Move class defintion out of
Output_section.
(Output_section_lookup_maps): New class.
(Output_section::Input_section::is_merge_section): New method
defintion.
(Output_section::Input_section::relobj): Move defintion out of class
defintion.  Declare method only.
(Output_section::Input_section::shndx): Ditto.
(Output_section::Input_section::output_merge_base): New method defintion.
      (Output_section::Input_section::u2_.pomb): New union field.
(Output_section::Merge_section_by_properties_map,
Output_section::Output_section_data_by_input_section_map,
Output_section::Ouptut_relaxed_input_section_by_input_section_map):
Remove types.
    (Output_section::add_merge_input_section): Add new parameter
KEEPS_INPUT_SECTIONS.
(Output_section::build_lookup_maps): New method declaration.
(Output_section::merge_section_map_,
Output_section::merge_section_by_properties_map_,
Output_section::relaxed_input_section_map_,
Output_section::is_relaxed_input_section_map_valid_): Remove data
members.
(Output_section::lookup_maps_): New data member.

gold/ChangeLog
gold/arm.cc
gold/merge.cc
gold/merge.h
gold/output.cc
gold/output.h

index c9ecbe7994e805d39f6c99375f59cfb3b04325fa..b66743ae339b09188f096b889fc09faa9fc97d15 100644 (file)
@@ -1,3 +1,82 @@
+2010-05-23  Doug Kwan  <dougkwan@google.com>
+
+       * arm.cc (Arm_input_section::do_output_offset): Use convert_types
+       instead of a cast.
+       (Target_arm::apply_cortex_a8_workaround): Rewrite a conditional branch
+       with a direct branch, not a conditional branch, to a stub.
+       * merge.cc (Output_merge_base::record_input_section): New method
+       defintion.
+       (Output_merge_data::do_add_input_section): Record input section if
+       keeps-input-sections flag is set.
+       (Output_merge_string::do_add_input_section): Ditto.
+       * merge.h (Output_merge_base::Output_merge_base): Initialize new data
+       members KEEPS_INPUT_SECTIONS_, FIRST_RELOBJ_, FIRST_SHNDX_ and
+       INPUT_SECTIONS_.
+       (Output_merge_base::keeps_input_sections,
+       Output_merge_base::set_keeps_input_sections,
+       Output_merge_base::first_relobj, Output_merge_base::first_shndx): New
+       method definitions.
+       (Output_merge_base::Input_sections): New type declaration.
+       (Output_merge_base::input_sections_begin,
+       Output_merge_base::input_sections_end,
+       Output_merge_base::do_set_keeps_input_sections): New method definitions.
+       (Output_merge_base::bool keeps_input_sections_,
+       Output_merge_base::first_relobj_, Output_merge_base::first_shndx_,
+       Output_merge_base::input_sections_): New data members.
+       (Output_merge_data::do_set_keeps_input_sections): New method
+       defintion.
+       (Output_merge_string::do_set_keeps_input_sections): Ditto.
+       * output.cc (Output_section::Input_section::relobj): Move method
+       defintion from class declaration to here and handle merge sections.
+       (Output_section::Input_section::shndx): Ditto.
+       (Output_section::Output_section): Remove initializations of removed
+       data members and initialize new data member LOOKUP_MAPS_.
+       (Output_section::add_input_section): Set keeps-input-sections flag
+       for a newly created merge output section as appropriate.  Adjust code
+       to use Output_section_lookup_maps class.
+       (Output_section::add_relaxed_input_section): Adjst code for lookup
+       maps code refactoring.
+       (Output_section::add_merge_input_section): Add a new parameter
+       KEEPS_INPUT_SECTION.  Adjust code to use Output_section_lookup_maps
+       class.  If adding input section to a newly created merge output
+       section fails, remove the new merge section.
+       (Output_section::convert_input_sections_in_list_to_relaxed_input_sections):
+       Adjust code for use of the Output_section_lookup_maps class. 
+       (Output_section::find_merge_section): Ditto.
+       (Output_section::build_lookup_maps): New method defintion.
+       (Output_section::find_relaxed_input_section): Adjust code to use
+       Output_section_lookup_maps class.
+       (Output_section::get_input_sections): Export merge sections.  Adjust
+       code to use Output_section_lookup_maps class.
+       (Output_section:::add_script_input_section): Adjust code to use
+       Output_section_lookup_maps class.  Update lookup maps for merge
+       sections also.
+       (Output_section::discard_states): Use Output_section_lookup_maps.
+       (Output_section::restore_states): Same.
+       * output.h (Merge_section_properties): Move class defintion out of
+       Output_section.
+       (Output_section_lookup_maps): New class.
+       (Output_section::Input_section::is_merge_section): New method
+       defintion.
+       (Output_section::Input_section::relobj): Move defintion out of class
+       defintion.  Declare method only.
+       (Output_section::Input_section::shndx): Ditto.
+       (Output_section::Input_section::output_merge_base): New method defintion.
+       (Output_section::Input_section::u2_.pomb): New union field.
+       (Output_section::Merge_section_by_properties_map,
+       Output_section::Output_section_data_by_input_section_map,
+       Output_section::Ouptut_relaxed_input_section_by_input_section_map):
+       Remove types.
+       (Output_section::add_merge_input_section): Add new parameter
+       KEEPS_INPUT_SECTIONS.
+       (Output_section::build_lookup_maps): New method declaration.
+       (Output_section::merge_section_map_,
+       Output_section::merge_section_by_properties_map_,
+       Output_section::relaxed_input_section_map_,
+       Output_section::is_relaxed_input_section_map_valid_): Remove data
+       members.
+       (Output_section::lookup_maps_): New data member.
+
 2010-05-21  Doug Kwan  <dougkwan@google.com>
 
        PR gold/11619
index 31454e9562a068a4871f7c8fa33e5ec8c21469ff..8bcd5d2225cd68050928ed6158dc5c891d9a8bb9 100644 (file)
@@ -1202,7 +1202,8 @@ class Arm_input_section : public Output_relaxed_input_section
     if ((object == this->relobj())
        && (shndx == this->shndx())
        && (offset >= 0)
-       && (offset <= static_cast<section_offset_type>(this->original_size_)))
+       && (offset <=
+           convert_types<section_offset_type, uint32_t>(this->original_size_)))
       {
        *poutput = offset;
        return true;
@@ -10898,13 +10899,11 @@ Target_arm<big_endian>::apply_cortex_a8_workaround(
   switch (stub->stub_template()->type())
     {
     case arm_stub_a8_veneer_b_cond:
-      gold_assert(!utils::has_overflow<21>(branch_offset));
-      upper_insn = RelocFuncs::thumb32_cond_branch_upper(upper_insn,
-                                                        branch_offset);
-      lower_insn = RelocFuncs::thumb32_cond_branch_lower(lower_insn,
-                                                        branch_offset);
-      break;
-
+      // For a conditional branch, we re-write it to be a uncondition
+      // branch to the stub.  We use the THUMB-2 encoding here.
+      upper_insn = 0xf000U;
+      lower_insn = 0xb800U;
+      // Fall through
     case arm_stub_a8_veneer_b:
     case arm_stub_a8_veneer_bl:
     case arm_stub_a8_veneer_blx:
index e2b6eef2f7af5fb4de3437fd9850eaab7e2c78b8..6e44ddd44711440aa3b385a0c8531ea80c00bb5a 100644 (file)
@@ -304,6 +304,26 @@ Output_merge_base::do_is_merge_section_for(const Relobj* object,
   return this->merge_map_.is_merge_section_for(object, shndx);
 }
 
+// Record a merged input section for script processing.
+
+void
+Output_merge_base::record_input_section(Relobj* relobj, unsigned int shndx)
+{
+  gold_assert(this->keeps_input_sections_ && relobj != NULL);
+  // If this is the first input section, record it.  We need do this because
+  // this->input_sections_ is unordered.
+  if (this->first_relobj_ == NULL)
+    {
+      this->first_relobj_ = relobj;
+      this->first_shndx_ = shndx;
+    }
+
+  std::pair<Input_sections::iterator, bool> result =
+    this->input_sections_.insert(Section_id(relobj, shndx));
+  // We should insert a merge section once only.
+  gold_assert(result.second);
+}
+
 // Class Output_merge_data.
 
 // Compute the hash code for a fixed-size constant.
@@ -414,6 +434,10 @@ Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx)
       this->add_mapping(object, shndx, i, entsize, k);
     }
 
+  // For script processing, we keep the input sections.
+  if (this->keeps_input_sections())
+    record_input_section(object, shndx);
+
   return true;
 }
 
@@ -517,6 +541,10 @@ Output_merge_string<Char_type>::do_add_input_section(Relobj* object,
 
   this->input_count_ += count;
 
+  // For script processing, we keep the input sections.
+  if (this->keeps_input_sections())
+    record_input_section(object, shndx);
+
   return true;
 }
 
index 345b1154ebe17e6b95e847867222675b6ee46e0f..c2d305bebcb1ee9be9422873d530bf44adb1b392 100644 (file)
@@ -216,7 +216,9 @@ class Output_merge_base : public Output_section_data
 {
  public:
   Output_merge_base(uint64_t entsize, uint64_t addralign)
-    : Output_section_data(addralign), merge_map_(), entsize_(entsize)
+    : Output_section_data(addralign), merge_map_(), entsize_(entsize),
+      keeps_input_sections_(false), first_relobj_(NULL), first_shndx_(-1),
+      input_sections_()
   { }
 
   // Return the entry size.
@@ -230,6 +232,52 @@ class Output_merge_base : public Output_section_data
   is_string()
   { return this->do_is_string(); }
 
+  // Whether this keeps input sections.
+  bool
+  keeps_input_sections() const
+  { return this->keeps_input_sections_; }
+
+  // Set the keeps-input-sections flag.  This is virtual so that sub-classes
+  // can perform additional checks.
+  void
+  set_keeps_input_sections()
+  { this->do_set_keeps_input_sections(); }
+
+  // Return the object of the first merged input section.  This used
+  // for script processing.  This is NULL if merge section is empty.
+  Relobj*
+  first_relobj() const
+  { return this->first_relobj_; }
+
+  // Return the section index of the first merged input section.  This
+  // is used for script processing.  This is valid only if merge section
+  // is not valid.
+  unsigned int
+  first_shndx() const
+  { 
+    gold_assert(this->first_relobj_ != NULL);
+    return this->first_shndx_;
+  }
+  // Set of merged input sections.
+  typedef Unordered_set<Section_id, Section_id_hash> Input_sections;
+
+  // Beginning of merged input sections.
+  Input_sections::const_iterator
+  input_sections_begin() const
+  {
+    gold_assert(this->keeps_input_sections_);
+    return this->input_sections_.begin();
+  }
+
+  // Beginning of merged input sections.
+  Input_sections::const_iterator
+  input_sections_end() const
+  {
+    gold_assert(this->keeps_input_sections_);
+    return this->input_sections_.end();
+  }
  protected:
   // Return the output offset for an input offset.
   bool
@@ -257,6 +305,15 @@ class Output_merge_base : public Output_section_data
   do_is_string()
   { return false; }
 
+  // This may be overridden by the child class.
+  virtual void
+  do_set_keeps_input_sections()
+  { this->keeps_input_sections_ = true; }
+
+  // Record the merged input section for script processing.
+  void
+  record_input_section(Relobj* relobj, unsigned int shndx);
+
  private:
   // A mapping from input object/section/offset to offset in output
   // section.
@@ -264,6 +321,15 @@ class Output_merge_base : public Output_section_data
   // The entry size.  For fixed-size constants, this is the size of
   // the constants.  For strings, this is the size of a character.
   uint64_t entsize_;
+  // Whether we keep input sections.
+  bool keeps_input_sections_;
+  // Object of the first merged input section.  We use this for script
+  // processing.
+  Relobj* first_relobj_;
+  // Section index of the first merged input section. 
+  unsigned int first_shndx_;
+  // Input sections.  We only keep them is keeps_input_sections_ is true.
+  Input_sections input_sections_;
 };
 
 // Handle SHF_MERGE sections with fixed-size constant data.
@@ -303,6 +369,14 @@ class Output_merge_data : public Output_merge_base
   void
   do_print_merge_stats(const char* section_name);
 
+  // Set keeps-input-sections flag.
+  void
+  do_set_keeps_input_sections()
+  {
+    gold_assert(this->input_count_ == 0);
+    Output_merge_base::do_set_keeps_input_sections();
+  }
+
  private:
   // We build a hash table of the fixed-size constants.  Each constant
   // is stored as a pointer into the section data we are accumulating.
@@ -440,6 +514,14 @@ class Output_merge_string : public Output_merge_base
   do_is_string()
   { return true; }
 
+  // Set keeps-input-sections flag.
+  void
+  do_set_keeps_input_sections()
+  {
+    gold_assert(this->input_count_ == 0);
+    Output_merge_base::do_set_keeps_input_sections();
+  }
+
  private:
   // The name of the string type, for stats.
   const char*
index 4c9776d6313742d749e207ae1b3b5ec70bcc81d6..752a1d37a044b09b386b47e8ee36e7e0ba6bf442 100644 (file)
@@ -1749,6 +1749,42 @@ Output_section::Input_section::data_size() const
     return this->u2_.posd->data_size();
 }
 
+// Return the object for an input section.
+
+Relobj*
+Output_section::Input_section::relobj() const
+{
+  if (this->is_input_section())
+    return this->u2_.object;
+  else if (this->is_merge_section())
+    {
+      gold_assert(this->u2_.pomb->first_relobj() != NULL);
+      return this->u2_.pomb->first_relobj();
+    }
+  else if (this->is_relaxed_input_section())
+    return this->u2_.poris->relobj();
+  else
+    gold_unreachable();
+}
+
+// Return the input section index for an input section.
+
+unsigned int
+Output_section::Input_section::shndx() const
+{
+  if (this->is_input_section())
+    return this->shndx_;
+  else if (this->is_merge_section())
+    {
+      gold_assert(this->u2_.pomb->first_relobj() != NULL);
+      return this->u2_.pomb->first_shndx();
+    }
+  else if (this->is_relaxed_input_section())
+    return this->u2_.poris->shndx();
+  else
+    gold_unreachable();
+}
+
 // Set the address and file offset.
 
 void
@@ -1914,10 +1950,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     is_noload_(false),
     tls_offset_(0),
     checkpoint_(NULL),
-    merge_section_map_(),
-    merge_section_by_properties_map_(),
-    relaxed_input_section_map_(),
-    is_relaxed_input_section_map_valid_(true)
+    lookup_maps_(new Output_section_lookup_maps)
 {
   // An unallocated section has no address.  Forcing this means that
   // we don't need special treatment for symbols defined in debug
@@ -2001,8 +2034,12 @@ Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
       && reloc_shndx == 0
       && shdr.get_sh_size() > 0)
     {
-      if (this->add_merge_input_section(object, shndx, sh_flags,
-                                       entsize, addralign))
+      // Keep information about merged input sections for rebuilding fast
+      // lookup maps if we have sections-script or we do relaxation.
+      bool keeps_input_sections =
+       have_sections_script || parameters->target().may_relax();
+      if (this->add_merge_input_section(object, shndx, sh_flags, entsize,
+                                       addralign, keeps_input_sections))
        {
          // Tell the relocation routines that they need to call the
          // output_offset method to determine the final address.
@@ -2092,11 +2129,9 @@ Output_section::add_relaxed_input_section(Output_relaxed_input_section* poris)
 {
   Input_section inp(poris);
   this->add_output_section_data(&inp);
-  if (this->is_relaxed_input_section_map_valid_)
-    {
-      Const_section_id csid(poris->relobj(), poris->shndx());
-      this->relaxed_input_section_map_[csid] = poris;
-    }
+  if (this->lookup_maps_->is_valid())
+    this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+                                                 poris->shndx(), poris);
 
   // For a relaxed section, we use the current data size.  Linker scripts
   // get all the input sections, including relaxed one from an output
@@ -2142,7 +2177,8 @@ Output_section::add_output_merge_section(Output_section_data* posd,
 bool
 Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
                                        uint64_t flags, uint64_t entsize,
-                                       uint64_t addralign)
+                                       uint64_t addralign,
+                                       bool keeps_input_sections)
 {
   bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
 
@@ -2155,13 +2191,15 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
   gold_assert(this->checkpoint_ == NULL);
 
   // Look up merge sections by required properties.
-  Output_merge_base* pomb;
+  // Currently, we only invalidate the lookup maps in script processing
+  // and relaxation.  We should not have done either when we reach here.
+  // So we assume that the lookup maps are valid to simply code.
+  gold_assert(this->lookup_maps_->is_valid());
   Merge_section_properties msp(is_string, entsize, addralign);
-  Merge_section_by_properties_map::const_iterator p =
-    this->merge_section_by_properties_map_.find(msp);
-  if (p != this->merge_section_by_properties_map_.end())
+  Output_merge_base* pomb = this->lookup_maps_->find_merge_section(msp);
+  bool is_new = false;
+  if (pomb != NULL)
     {
-      pomb = p->second;
       gold_assert(pomb->is_string() == is_string
                  && pomb->entsize() == entsize
                  && pomb->addralign() == addralign);
@@ -2188,22 +2226,36 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
              return false;
            }
        }
-      // Add new merge section to this output section and link merge
-      // section properties to new merge section in map.
-      this->add_output_merge_section(pomb, is_string, entsize);
-      this->merge_section_by_properties_map_[msp] = pomb;
+      // If we need to do script processing or relaxation, we need to keep
+      // the original input sections to rebuild the fast lookup maps.
+      if (keeps_input_sections)
+       pomb->set_keeps_input_sections();
+      is_new = true;
     }
 
   if (pomb->add_input_section(object, shndx))
     {
+      // Add new merge section to this output section and link merge
+      // section properties to new merge section in map.
+      if (is_new)
+       {
+         this->add_output_merge_section(pomb, is_string, entsize);
+         this->lookup_maps_->add_merge_section(msp, pomb);
+       }
+
       // Add input section to new merge section and link input section to new
       // merge section in map.
-      Const_section_id csid(object, shndx);
-      this->merge_section_map_[csid] = pomb;
+      this->lookup_maps_->add_merge_input_section(object, shndx, pomb);
       return true;
     }
   else
-    return false;
+    {
+      // If add_input_section failed, delete new merge section to avoid
+      // exporting empty merge sections in Output_section::get_input_section.
+      if (is_new)
+       delete pomb;
+      return false;
+    }
 }
 
 // Build a relaxation map to speed up relaxation of existing input sections.
@@ -2298,12 +2350,12 @@ Output_section::convert_input_sections_to_relaxed_sections(
            &this->input_sections_);
 
   // Update fast look-up map.
-  if (this->is_relaxed_input_section_map_valid_)
+  if (this->lookup_maps_->is_valid())
     for (size_t i = 0; i < relaxed_sections.size(); ++i)
       {
        Output_relaxed_input_section* poris = relaxed_sections[i];
-       Const_section_id csid(poris->relobj(), poris->shndx());
-       this->relaxed_input_section_map_[csid] = poris;
+       this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+                                                     poris->shndx(), poris);
       }
 }
 
@@ -2348,17 +2400,47 @@ Output_section_data*
 Output_section::find_merge_section(const Relobj* object,
                                   unsigned int shndx) const
 {
-  Const_section_id csid(object, shndx);
-  Output_section_data_by_input_section_map::const_iterator p =
-    this->merge_section_map_.find(csid);
-  if (p != this->merge_section_map_.end())
+  if (!this->lookup_maps_->is_valid())
+    this->build_lookup_maps();
+  return this->lookup_maps_->find_merge_section(object, shndx);
+}
+
+// Build the lookup maps for merge and relaxed sections.  This is needs
+// to be declared as a const methods so that it is callable with a const
+// Output_section pointer.  The method only updates states of the maps.
+
+void
+Output_section::build_lookup_maps() const
+{
+  this->lookup_maps_->clear();
+  for (Input_section_list::const_iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
     {
-      Output_section_data* posd = p->second;
-      gold_assert(posd->is_merge_section_for(object, shndx));
-      return posd;
+      if (p->is_merge_section())
+       {
+         Output_merge_base* pomb = p->output_merge_base();
+         Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
+                                      pomb->addralign());
+         this->lookup_maps_->add_merge_section(msp, pomb);
+         for (Output_merge_base::Input_sections::const_iterator is =
+                pomb->input_sections_begin();
+              is != pomb->input_sections_end();
+              ++is) 
+           {
+             const Const_section_id& csid = *is;
+           this->lookup_maps_->add_merge_input_section(csid.first,
+                                                       csid.second, pomb);
+           }
+           
+       }
+      else if (p->is_relaxed_input_section())
+       {
+         Output_relaxed_input_section* poris = p->relaxed_input_section();
+         this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+                                                       poris->shndx(), poris);
+       }
     }
-  else
-    return NULL;
 }
 
 // Find an relaxed input section corresponding to an input section
@@ -2368,31 +2450,9 @@ const Output_relaxed_input_section*
 Output_section::find_relaxed_input_section(const Relobj* object,
                                           unsigned int shndx) const
 {
-  // Be careful that the map may not be valid due to input section export
-  // to scripts or a check-point restore.
-  if (!this->is_relaxed_input_section_map_valid_)
-    {
-      // Rebuild the map as needed.
-      this->relaxed_input_section_map_.clear();
-      for (Input_section_list::const_iterator p = this->input_sections_.begin();
-          p != this->input_sections_.end();
-          ++p)
-       if (p->is_relaxed_input_section())
-         {
-           Const_section_id csid(p->relobj(), p->shndx());
-           this->relaxed_input_section_map_[csid] =
-             p->relaxed_input_section();
-         }
-      this->is_relaxed_input_section_map_valid_ = true;
-    }
-
-  Const_section_id csid(object, shndx);
-  Output_relaxed_input_section_by_input_section_map::const_iterator p =
-    this->relaxed_input_section_map_.find(csid);
-  if (p != this->relaxed_input_section_map_.end())
-    return p->second;
-  else
-    return NULL;
+  if (!this->lookup_maps_->is_valid())
+    this->build_lookup_maps();
+  return this->lookup_maps_->find_relaxed_input_section(object, shndx);
 }
 
 // Given an address OFFSET relative to the start of input section
@@ -3052,8 +3112,8 @@ Output_section::get_input_sections(
       && !this->checkpoint_->input_sections_saved())
     this->checkpoint_->save_input_sections();
 
-  // Invalidate the relaxed input section map.
-  this->is_relaxed_input_section_map_valid_ = false;
+  // Invalidate fast look-up maps.
+  this->lookup_maps_->invalidate();
 
   uint64_t orig_address = address;
 
@@ -3064,7 +3124,9 @@ Output_section::get_input_sections(
        p != this->input_sections_.end();
        ++p)
     {
-      if (p->is_input_section() || p->is_relaxed_input_section())
+      if (p->is_input_section()
+         || p->is_relaxed_input_section()
+         || p->is_merge_section())
        input_sections->push_back(*p);
       else
        {
@@ -3121,6 +3183,30 @@ Output_section::add_script_input_section(const Input_section& sis)
                                        + data_size);
 
   this->input_sections_.push_back(sis);
+
+  // Update fast lookup maps if necessary. 
+  if (this->lookup_maps_->is_valid())
+    {
+      if (sis.is_merge_section())
+       {
+         Output_merge_base* pomb = sis.output_merge_base();
+         Merge_section_properties msp(pomb->is_string(), pomb->entsize(),
+                                      pomb->addralign());
+         this->lookup_maps_->add_merge_section(msp, pomb);
+         for (Output_merge_base::Input_sections::const_iterator p =
+                pomb->input_sections_begin();
+              p != pomb->input_sections_end();
+              ++p)
+           this->lookup_maps_->add_merge_input_section(p->first, p->second,
+                                                       pomb);
+       }
+      else if (sis.is_relaxed_input_section())
+       {
+         Output_relaxed_input_section* poris = sis.relaxed_input_section();
+         this->lookup_maps_->add_relaxed_input_section(poris->relobj(),
+                                                       poris->shndx(), poris);
+       }
+    }
 }
 
 // Save states for relaxation.
@@ -3146,9 +3232,9 @@ Output_section::discard_states()
   this->checkpoint_ = NULL;
   gold_assert(this->fills_.empty());
 
-  // Simply invalidate the relaxed input section map since we do not keep
-  // track of it.
-  this->is_relaxed_input_section_map_valid_ = false;
+  // Simply invalidate the fast lookup maps since we do not keep
+  // track of them.
+  this->lookup_maps_->invalidate();
 }
 
 void
@@ -3180,9 +3266,9 @@ Output_section::restore_states()
   this->attached_input_sections_are_sorted_ =
     checkpoint->attached_input_sections_are_sorted();
 
-  // Simply invalidate the relaxed input section map since we do not keep
-  // track of it.
-  this->is_relaxed_input_section_map_valid_ = false;
+  // Simply invalidate the fast lookup maps since we do not keep
+  // track of them.
+  this->lookup_maps_->invalidate();
 }
 
 // Update the section offsets of input sections in this.  This is required if
index a15fe2718f9e786e8b2bbb9893f52ce74a686059..eb5d83671cc0be78afe11f871d9eade8a44f8d8f 100644 (file)
@@ -2314,6 +2314,188 @@ class Output_relaxed_input_section : public Output_section_data_build
   unsigned int shndx_;
 };
 
+// This class describes properties of merge data sections.  It is used
+// as a key type for maps.
+class Merge_section_properties
+{
+ public:
+  Merge_section_properties(bool is_string, uint64_t entsize,
+                            uint64_t addralign)
+    : is_string_(is_string), entsize_(entsize), addralign_(addralign)
+  { }
+
+  // Whether this equals to another Merge_section_properties MSP.
+  bool
+  eq(const Merge_section_properties& msp) const
+  {
+    return ((this->is_string_ == msp.is_string_)
+           && (this->entsize_ == msp.entsize_)
+           && (this->addralign_ == msp.addralign_));
+  }
+
+  // Compute a hash value for this using 64-bit FNV-1a hash.
+  size_t
+  hash_value() const
+  {
+    uint64_t h = 14695981039346656037ULL;      // FNV offset basis.
+    uint64_t prime = 1099511628211ULL;
+    h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
+    h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
+    h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
+    return h;
+  }
+    
+  // Functors for associative containers.
+  struct equal_to
+  {
+    bool
+    operator()(const Merge_section_properties& msp1,
+              const Merge_section_properties& msp2) const
+    { return msp1.eq(msp2); }
+  };
+
+  struct hash
+  {
+    size_t
+    operator()(const Merge_section_properties& msp) const
+    { return msp.hash_value(); }
+  };
+
+ private:
+  // Whether this merge data section is for strings.
+  bool is_string_;
+  // Entsize of this merge data section.
+  uint64_t entsize_;
+  // Address alignment.
+  uint64_t addralign_;
+};
+
+// This class is used to speed up look up of special input sections in an
+// Output_section.
+
+class Output_section_lookup_maps
+{
+ public:
+  Output_section_lookup_maps()
+    : is_valid_(true), merge_sections_by_properties_(),
+      merge_sections_by_id_(), relaxed_input_sections_by_id_()
+  { }
+
+  // Whether the maps are valid.
+  bool
+  is_valid() const
+  { return this->is_valid_; }
+
+  // Invalidate the maps.
+  void
+  invalidate()
+  { this->is_valid_ = false; }
+
+  // Clear the maps.
+  void
+  clear()
+  {
+    this->merge_sections_by_properties_.clear();
+    this->merge_sections_by_id_.clear();
+    this->relaxed_input_sections_by_id_.clear();
+    // A cleared map is valid.
+    this->is_valid_ = true;
+  }
+  
+  // Find a merge section by merge section properties.  Return NULL if none
+  // is found.
+  Output_merge_base*
+  find_merge_section(const Merge_section_properties& msp) const
+  {
+    gold_assert(this->is_valid_);
+    Merge_sections_by_properties::const_iterator p =
+      this->merge_sections_by_properties_.find(msp);
+    return p != this->merge_sections_by_properties_.end() ? p->second : NULL;
+  }
+
+  // Find a merge section by section ID of a merge input section.  Return NULL
+  // if none is found.
+  Output_merge_base*
+  find_merge_section(const Object* object, unsigned int shndx) const
+  {
+    gold_assert(this->is_valid_);
+    Merge_sections_by_id::const_iterator p =
+      this->merge_sections_by_id_.find(Const_section_id(object, shndx));
+    return p != this->merge_sections_by_id_.end() ? p->second : NULL;
+  }
+
+  // Add a merge section pointed by POMB with properties MSP.
+  void
+  add_merge_section(const Merge_section_properties& msp,
+                   Output_merge_base* pomb)
+  {
+    std::pair<Merge_section_properties, Output_merge_base*> value(msp, pomb);
+    std::pair<Merge_sections_by_properties::iterator, bool> result =
+      this->merge_sections_by_properties_.insert(value);
+    gold_assert(value.second);
+  }
+  
+  // Add a mapping from a merged input section in OBJECT with index SHNDX
+  // to a merge output section pointed by POMB.
+  void
+  add_merge_input_section(const Object* object, unsigned int shndx,
+                         Output_merge_base* pomb)
+  {
+    Const_section_id csid(object, shndx);
+    std::pair<Const_section_id, Output_merge_base*> value(csid, pomb);
+    std::pair<Merge_sections_by_id::iterator, bool> result =
+      this->merge_sections_by_id_.insert(value);
+    gold_assert(value.second);
+  }
+
+  // Find a relaxed input section of OBJECT with index SHNDX.
+  Output_relaxed_input_section*
+  find_relaxed_input_section(const Object* object, unsigned int shndx) const
+  {
+    gold_assert(this->is_valid_);
+    Relaxed_input_sections_by_id::const_iterator p =
+      this->relaxed_input_sections_by_id_.find(Const_section_id(object, shndx));
+    return p != this->relaxed_input_sections_by_id_.end() ? p->second : NULL;
+  }
+
+  // Add a relaxed input section pointed by POMB and whose original input
+  // section is in OBJECT with index SHNDX.
+  void
+  add_relaxed_input_section(const Relobj* relobj, unsigned int shndx,
+                           Output_relaxed_input_section* poris)
+  {
+    Const_section_id csid(relobj, shndx);
+    std::pair<Const_section_id, Output_relaxed_input_section*>
+      value(csid, poris);
+    std::pair<Relaxed_input_sections_by_id::iterator, bool> result =
+      this->relaxed_input_sections_by_id_.insert(value);
+    gold_assert(value.second);
+  }
+
+ private:
+  typedef Unordered_map<Const_section_id, Output_merge_base*,
+                       Const_section_id_hash>
+    Merge_sections_by_id;
+
+  typedef Unordered_map<Merge_section_properties, Output_merge_base*,
+                       Merge_section_properties::hash,
+                       Merge_section_properties::equal_to>
+    Merge_sections_by_properties;
+
+  typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
+                       Const_section_id_hash>
+    Relaxed_input_sections_by_id;
+
+  // Whether this is valid
+  bool is_valid_;
+  // Merge sections by merge section properties.
+  Merge_sections_by_properties merge_sections_by_properties_;
+  // Merge sections by section IDs.
+  Merge_sections_by_id merge_sections_by_id_;
+  // Relaxed sections by section IDs.
+  Relaxed_input_sections_by_id relaxed_input_sections_by_id_;
+};
+
 // An output section.  We don't expect to have too many output
 // sections, so we don't bother to do a template on the size.
 
@@ -2881,6 +3063,14 @@ class Output_section : public Output_data
               && this->addralign() == addralign);
     }
 
+    // Return whether this is a merge section for some input section.
+    bool
+    is_merge_section() const
+    {
+      return (this->shndx_ == MERGE_DATA_SECTION_CODE
+             || this->shndx_ == MERGE_STRING_SECTION_CODE);
+    }
+
     // Return whether this is a relaxed input section.
     bool
     is_relaxed_input_section() const
@@ -2895,27 +3085,11 @@ class Output_section : public Output_data
 
     // Return the object for an input section.
     Relobj*
-    relobj() const
-    {
-      if (this->is_input_section())
-        return this->u2_.object;
-      else if (this->is_relaxed_input_section())
-       return this->u2_.poris->relobj();
-      else
-       gold_unreachable();
-    }
+    relobj() const;
 
     // Return the input section index for an input section.
     unsigned int
-    shndx() const
-    {
-      if (this->is_input_section())
-        return this->shndx_;
-      else if (this->is_relaxed_input_section())
-       return this->u2_.poris->shndx();
-      else
-       gold_unreachable();
-    }
+    shndx() const;
 
     // For non-input-sections, return the associated Output_section_data
     // object.
@@ -2926,6 +3100,14 @@ class Output_section : public Output_data
       return this->u2_.posd;
     }
  
+    // For a merge section, return the Output_merge_base pointer.
+    Output_merge_base*
+    output_merge_base() const
+    {
+      gold_assert(this->is_merge_section());
+      return this->u2_.pomb;
+    }
+
     // Return the Output_relaxed_input_section object.
     Output_relaxed_input_section*
     relaxed_input_section() const
@@ -3048,6 +3230,7 @@ class Output_section : public Output_data
       // For OUTPUT_SECTION_CODE or MERGE_DATA_SECTION_CODE or
       // MERGE_STRING_SECTION_CODE, the data.
       Output_section_data* posd;
+      Output_merge_base* pomb;
       // For RELAXED_INPUT_SECTION_CODE, the data.
       Output_relaxed_input_section* poris;
     } u2_;
@@ -3389,78 +3572,6 @@ class Output_section : public Output_data
 
   typedef std::vector<Fill> Fill_list;
 
-  // This class describes properties of merge data sections.  It is used
-  // as a key type for maps.
-  class Merge_section_properties
-  {
-   public:
-    Merge_section_properties(bool is_string, uint64_t entsize,
-                            uint64_t addralign)
-      : is_string_(is_string), entsize_(entsize), addralign_(addralign)
-    { }
-
-    // Whether this equals to another Merge_section_properties MSP.
-    bool
-    eq(const Merge_section_properties& msp) const
-    {
-      return ((this->is_string_ == msp.is_string_)
-             && (this->entsize_ == msp.entsize_)
-             && (this->addralign_ == msp.addralign_));
-    }
-
-    // Compute a hash value for this using 64-bit FNV-1a hash.
-    size_t
-    hash_value() const
-    {
-      uint64_t h = 14695981039346656037ULL;    // FNV offset basis.
-      uint64_t prime = 1099511628211ULL;
-      h = (h ^ static_cast<uint64_t>(this->is_string_)) * prime;
-      h = (h ^ static_cast<uint64_t>(this->entsize_)) * prime;
-      h = (h ^ static_cast<uint64_t>(this->addralign_)) * prime;
-      return h;
-    }
-    
-    // Functors for associative containers.
-    struct equal_to
-    {
-      bool
-      operator()(const Merge_section_properties& msp1,
-                const Merge_section_properties& msp2) const
-      { return msp1.eq(msp2); }
-    };
-
-    struct hash
-    {
-      size_t
-      operator()(const Merge_section_properties& msp) const
-      { return msp.hash_value(); }
-    };
-
-   private:
-    // Whether this merge data section is for strings.
-    bool is_string_;
-    // Entsize of this merge data section.
-    uint64_t entsize_;
-    // Address alignment.
-    uint64_t addralign_;
-  };
-
-  // Map that link Merge_section_properties to Output_merge_base.
-  typedef Unordered_map<Merge_section_properties, Output_merge_base*,
-                       Merge_section_properties::hash,
-                       Merge_section_properties::equal_to>
-    Merge_section_by_properties_map;
-
-  // Map that link Const_section_id to Output_section_data.
-  typedef Unordered_map<Const_section_id, Output_section_data*,
-                       Const_section_id_hash>
-    Output_section_data_by_input_section_map;
-
-  // Map that link Const_section_id to Output_relaxed_input_section.
-  typedef Unordered_map<Const_section_id, Output_relaxed_input_section*,
-                       Const_section_id_hash>
-    Output_relaxed_input_section_by_input_section_map;
-
   // Map used during relaxation of existing sections.  This map
   // a section id an input section list index.  We assume that
   // Input_section_list is a vector.
@@ -3471,10 +3582,12 @@ class Output_section : public Output_data
   add_output_section_data(Input_section*);
 
   // Add an SHF_MERGE input section.  Returns true if the section was
-  // handled.
+  // handled.  If KEEPS_INPUT_SECTIONS is true, the output merge section
+  // stores information about the merged input sections.
   bool
   add_merge_input_section(Relobj* object, unsigned int shndx, uint64_t flags,
-                         uint64_t entsize, uint64_t addralign);
+                         uint64_t entsize, uint64_t addralign,
+                         bool keeps_input_sections);
 
   // Add an output SHF_MERGE section POSD to this output section.
   // IS_STRING indicates whether it is a SHF_STRINGS section, and
@@ -3507,6 +3620,10 @@ class Output_section : public Output_data
       const Relaxation_map& map,
       Input_section_list* input_sections);
 
+  // Build the lookup maps for merge and relaxed input sections.
+  void
+  build_lookup_maps() const;
+
   // Most of these fields are only valid after layout.
 
   // The name of the section.  This will point into a Stringpool.
@@ -3629,17 +3746,8 @@ class Output_section : public Output_data
   uint64_t tls_offset_;
   // Saved checkpoint.
   Checkpoint_output_section* checkpoint_;
-  // Map from input sections to merge sections.
-  Output_section_data_by_input_section_map merge_section_map_;
-  // Map from merge section properties to merge_sections;
-  Merge_section_by_properties_map merge_section_by_properties_map_;
-  // Map from input sections to relaxed input sections.  This is mutable
-  // because it is updated lazily.  We may need to update it in a
-  // const qualified method.
-  mutable Output_relaxed_input_section_by_input_section_map
-    relaxed_input_section_map_;
-  // Whether relaxed_input_section_map_ is valid.
-  mutable bool is_relaxed_input_section_map_valid_;
+  // Fast lookup maps for merged and relaxed input sections.
+  Output_section_lookup_maps* lookup_maps_;
 };
 
 // An output segment.  PT_LOAD segments are built from collections of