[PATCH][GOLD] Make string offset assignment independent of implementation of unordered map elements order.

Doug Kwan (關振德) dougkwan@google.com
Sun Mar 14 07:16:00 GMT 2010


Hi,

    Currently Stringpool_template::set_string_offsets transverse an
unordered map and assign string offsets for unoptimized string pools.
The ordered of elements in an unordered map depends on many things
like the version of STL used and the with of size_t.   This leads to
different outputs generated from the same input.  This patch fixes
this problem by assigning strings offsets in the order strings are
inserted into a string pool.    The patch was tested on both x86_64
Linux and ARM Linux natively.

-Doug

2010-03-13  Doug Kwan  <dougkwan@google.com>

        * stringpool.cc (Stringpool_template::set_string_offsets): Set
        string offsets in the order strings are inserted.
        * stringpool.h (Chunked_vector::Chunked_vector): Initialize data
        member size_.
        (Chunked_vector::clear): Clear size_.
        (Chunked_vector::reserve): Call reserve method of all Element_vectors.
        (Chunked_vector::size): Return size_.
        (Chunked_vector::push_back): Use size_ to find insert position.
        (Chunked_vector::size_): New data member.
-------------- next part --------------
Index: gold/stringpool.cc
===================================================================
RCS file: /cvs/src/src/gold/stringpool.cc,v
retrieving revision 1.30
diff -u -u -p -r1.30 stringpool.cc
--- gold/stringpool.cc	21 Oct 2009 08:08:41 -0000	1.30
+++ gold/stringpool.cc	13 Mar 2010 22:49:25 -0000
@@ -390,19 +390,47 @@ Stringpool_template<Stringpool_char>::se
   // take the time to sort when the user asks for heavy optimization.
   if (!this->optimize_)
     {
+      // We do not want offset assignment to depend on implementation of
+      // unordered_map.  So we go over the keys twice.  We first compute
+      // the sizes of strings.  Then we assign offests in the order strings
+      // are inserted.
+      size_t key_count = this->key_to_offset_.size();
+      gold_assert(this->string_set_.size() == key_count);
+      const section_offset_type no_size = 0;
+      const section_offset_type zero_null_size = -1;
+      std::vector<section_offset_type> key_to_size(key_count, no_size);
+
       for (typename String_set_type::iterator curr = this->string_set_.begin();
            curr != this->string_set_.end();
            curr++)
         {
-	  section_offset_type* poff = &this->key_to_offset_[curr->second - 1];
+	  section_offset_type size;
           if (this->zero_null_ && curr->first.string[0] == 0)
-            *poff = 0;
+            size = zero_null_size;
           else
             {
-              *poff = offset;
-              offset += (curr->first.length + 1) * charsize;
+	      size = (curr->first.length + 1) * charsize;
+	      gold_assert(size > 0);
             }
+	  key_to_size[curr->second - 1 ] = size;
         }
+
+      for (size_t i = 0; i < key_count; ++i)
+	{
+	  section_offset_type string_size = key_to_size[i];
+	  section_offset_type string_offset;
+	  if (string_size > 0)
+	    {
+	      string_offset = offset;
+	      offset += string_size;
+	    }
+	  else
+	    {
+	      gold_assert(string_size == zero_null_size);
+	      string_offset = 0;
+	    }
+	  this->key_to_offset_[i] = string_offset;
+	}
     }
   else
     {
Index: gold/stringpool.h
===================================================================
RCS file: /cvs/src/src/gold/stringpool.h,v
retrieving revision 1.23
diff -u -u -p -r1.23 stringpool.h
--- gold/stringpool.h	23 Jun 2009 07:04:10 -0000	1.23
+++ gold/stringpool.h	13 Mar 2010 22:49:25 -0000
@@ -77,48 +77,50 @@ class Chunked_vector
 {
  public:
   Chunked_vector()
-    : chunks_()
+    : chunks_(), size_(0)
   { }
 
   // Clear the elements.
   void
   clear()
-  { this->chunks_.clear(); }
+  {
+    this->chunks_.clear();
+    this->size_ = 0;
+  }
 
   // Reserve elements.
   void
   reserve(unsigned int n)
   {
-    n += chunk_size - 1;
-    while (n >= chunk_size)
+    if (n > this->chunks_.size() * chunk_size)
       {
-	this->chunks_.push_back(Element_vector());
-	this->chunks_.back().reserve(chunk_size);
-	n -= chunk_size;
+	this->chunks_.resize((n + chunk_size - 1) / chunk_size);
+	// We need to call reserve() of all chunks since changing
+	// this->chunks_ casues Element_vectors to be copied.  The
+	// reserved capacity of an Element_vector may be lost in copying.
+	for (size_t i = 0; i < this->chunks_.size(); ++i)
+	  this->chunks_[i].reserve(chunk_size);
       }
   }
 
   // Get the number of elements.
   size_t
   size() const
-  {
-    if (this->chunks_.empty())
-      return 0;
-    else
-      return ((this->chunks_.size() - 1) * chunk_size
-	      + this->chunks_.back().size());
-  }
+  { return this->size_; }
 
   // Push a new element on the back of the vector.
   void
   push_back(const Element& element)
   {
-    if (this->chunks_.empty() || this->chunks_.back().size() == chunk_size)
+    size_t chunk_index = this->size_ / chunk_size;
+    if (chunk_index >= this->chunks_.size())
       {
 	this->chunks_.push_back(Element_vector());
 	this->chunks_.back().reserve(chunk_size);
+	gold_assert(chunk_index < this->chunks_.size());
       }
-    this->chunks_.back().push_back(element);
+    this->chunks_[chunk_index].push_back(element);
+    this->size_++;
   }
 
   // Return a reference to an entry in the vector.
@@ -137,6 +139,7 @@ class Chunked_vector
   typedef std::vector<Element_vector> Chunk_vector;
 
   Chunk_vector chunks_;
+  size_t size_;
 };
 
 


More information about the Binutils mailing list