From 2030fba084282b271caba7c8e32abfd847a8eca7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 19 Dec 2007 01:23:46 +0000 Subject: [PATCH] Move Stringpool offsets into a chunked_vector indexed by keys. --- gold/merge.cc | 9 ++-- gold/merge.h | 6 ++- gold/stringpool.cc | 74 ++++++++++++++----------------- gold/stringpool.h | 107 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 136 insertions(+), 60 deletions(-) diff --git a/gold/merge.cc b/gold/merge.cc index 2c76759db60..01f2a9e1380 100644 --- a/gold/merge.cc +++ b/gold/merge.cc @@ -520,12 +520,13 @@ Output_merge_string::do_add_input_section(Relobj* object, } } + Stringpool::Key key; const Char_type* str = this->stringpool_.add_with_length(p, pl - p, true, - NULL); + &key); section_size_type bytelen_with_null = ((pl - p) + 1) * sizeof(Char_type); this->merged_strings_.push_back(Merged_string(object, shndx, i, str, - bytelen_with_null)); + bytelen_with_null, key)); p = pl + 1; i += bytelen_with_null; @@ -551,10 +552,8 @@ Output_merge_string::finalize_merged_data() p != this->merged_strings_.end(); ++p) { - size_t charlen_without_null = (p->length / sizeof(Char_type)) - 1; section_offset_type offset = - this->stringpool_.get_offset_with_length(p->string, - charlen_without_null); + this->stringpool_.get_offset_from_key(p->stringpool_key); this->add_mapping(p->object, p->shndx, p->offset, p->length, offset); } diff --git a/gold/merge.h b/gold/merge.h index 056c2c67715..bf6a407ab71 100644 --- a/gold/merge.h +++ b/gold/merge.h @@ -279,12 +279,14 @@ class Output_merge_string : public Output_merge_base const Char_type* string; // The length of the string in bytes, including the null terminator. size_t length; + // The key in the Stringpool. + Stringpool::Key stringpool_key; Merged_string(Relobj *objecta, unsigned int shndxa, section_offset_type offseta, const Char_type* stringa, - size_t lengtha) + size_t lengtha, Stringpool::Key stringpool_keya) : object(objecta), shndx(shndxa), offset(offseta), string(stringa), - length(lengtha) + length(lengtha), stringpool_key(stringpool_keya) { } }; diff --git a/gold/stringpool.cc b/gold/stringpool.cc index 9ba505a0063..0e92ec1cf72 100644 --- a/gold/stringpool.cc +++ b/gold/stringpool.cc @@ -35,8 +35,8 @@ namespace gold template Stringpool_template::Stringpool_template() - : string_set_(), strings_(), strtab_size_(0), next_index_(1), - next_uncopied_key_(-1), zero_null_(true) + : string_set_(), key_to_offset_(), strings_(), strtab_size_(0), + zero_null_(true) { } @@ -49,6 +49,7 @@ Stringpool_template::clear() ++p) delete[] reinterpret_cast(*p); this->strings_.clear(); + this->key_to_offset_.clear(); this->string_set_.clear(); } @@ -67,6 +68,8 @@ template void Stringpool_template::reserve(unsigned int n) { + this->key_to_offset_.reserve(n); + #if defined(HAVE_TR1_UNORDERED_MAP) // rehash() implementation is broken in gcc 4.0.3's stl //this->string_set_.rehash(this->string_set_.size() + n); @@ -180,8 +183,7 @@ Stringpool_template::string_hash(const Stringpool_char* s, template const Stringpool_char* Stringpool_template::add_string(const Stringpool_char* s, - size_t len, - Key* pkey) + size_t len) { // We are in trouble if we've already computed the string offsets. gold_assert(this->strtab_size_ == 0); @@ -218,9 +220,6 @@ Stringpool_template::add_string(const Stringpool_char* s, memset(ret + len - sizeof(Stringpool_char), 0, sizeof(Stringpool_char)); - if (pkey != NULL) - *pkey = psd->index * key_mult + psd->len; - psd->len += len; return reinterpret_cast(ret); @@ -233,15 +232,6 @@ Stringpool_template::add_string(const Stringpool_char* s, memset(psd->data + len - sizeof(Stringpool_char), 0, sizeof(Stringpool_char)); psd->len = len; - psd->index = this->next_index_; - ++this->next_index_; - - if (pkey != NULL) - { - *pkey = psd->index * key_mult; - // Ensure there was no overflow. - gold_assert(*pkey / key_mult == psd->index); - } if (front) this->strings_.push_front(psd); @@ -270,15 +260,14 @@ Stringpool_template::add_with_length(const Stringpool_char* s, { typedef std::pair Insert_type; + const Key k = this->key_to_offset_.size(); + if (!copy) { // When we don't need to copy the string, we can call insert // directly. - const Key k = this->next_uncopied_key_; - const section_offset_type ozero = 0; - std::pair element(Hashkey(s, length), - std::make_pair(k, ozero)); + std::pair element(Hashkey(s, length), k); Insert_type ins = this->string_set_.insert(element); @@ -288,15 +277,15 @@ Stringpool_template::add_with_length(const Stringpool_char* s, { // We just added the string. The key value has now been // used. - --this->next_uncopied_key_; + this->key_to_offset_.push_back(0); } else { - gold_assert(k != p->second.first); + gold_assert(k != p->second); } if (pkey != NULL) - *pkey = p->second.first; + *pkey = p->second; return p->first.string; } @@ -310,17 +299,17 @@ Stringpool_template::add_with_length(const Stringpool_char* s, if (p != this->string_set_.end()) { if (pkey != NULL) - *pkey = p->second.first; + *pkey = p->second; return p->first.string; } - Key k; - hk.string = this->add_string(s, length, &k); + this->key_to_offset_.push_back(0); + + hk.string = this->add_string(s, length); // The contents of the string stay the same, so we don't need to // adjust hk.hash_code or hk.length. - const section_offset_type ozero = 0; - std::pair element(hk, std::make_pair(k, ozero)); + std::pair element(hk, k); Insert_type ins = this->string_set_.insert(element); gold_assert(ins.second); @@ -341,7 +330,7 @@ Stringpool_template::find(const Stringpool_char* s, return NULL; if (pkey != NULL) - *pkey = p->second.first; + *pkey = p->second; return p->first.string; } @@ -423,11 +412,12 @@ Stringpool_template::set_string_offsets() curr != this->string_set_.end(); curr++) { + section_offset_type* poff = &this->key_to_offset_[curr->second]; if (this->zero_null_ && curr->first.string[0] == 0) - curr->second.second = 0; + *poff = 0; else { - curr->second.second = offset; + *poff = offset; offset += (curr->first.length + 1) * charsize; } } @@ -446,27 +436,30 @@ Stringpool_template::set_string_offsets() std::sort(v.begin(), v.end(), Stringpool_sort_comparison()); + section_offset_type last_offset = -1; for (typename std::vector::iterator last = v.end(), curr = v.begin(); curr != v.end(); last = curr++) { + section_offset_type this_offset; if (this->zero_null_ && (*curr)->first.string[0] == 0) - (*curr)->second.second = 0; + this_offset = 0; else if (last != v.end() && is_suffix((*curr)->first.string, (*curr)->first.length, (*last)->first.string, (*last)->first.length)) - (*curr)->second.second = ((*last)->second.second - + (((*last)->first.length - - (*curr)->first.length) - * charsize)); + this_offset = (last_offset + + (((*last)->first.length - (*curr)->first.length) + * charsize)); else { - (*curr)->second.second = offset; + this_offset = offset; offset += ((*curr)->first.length + 1) * charsize; } + this->key_to_offset_[(*curr)->second] = this_offset; + last_offset = this_offset; } } @@ -494,7 +487,7 @@ Stringpool_template::get_offset_with_length( Hashkey hk(s, length); typename String_set_type::const_iterator p = this->string_set_.find(hk); if (p != this->string_set_.end()) - return p->second.second; + return this->key_to_offset_[p->second]; gold_unreachable(); } @@ -515,9 +508,10 @@ Stringpool_template::write_to_buffer( ++p) { const int len = (p->first.length + 1) * sizeof(Stringpool_char); - gold_assert(static_cast(p->second.second) + len + const section_offset_type offset = this->key_to_offset_[p->second]; + gold_assert(static_cast(offset) + len <= this->strtab_size_); - memcpy(buffer + p->second.second, p->first.string, len); + memcpy(buffer + offset, p->first.string, len); } } diff --git a/gold/stringpool.h b/gold/stringpool.h index 773bfc17af1..0257894a869 100644 --- a/gold/stringpool.h +++ b/gold/stringpool.h @@ -22,6 +22,7 @@ #include #include +#include #ifndef GOLD_STRINGPOOL_H #define GOLD_STRINGPOOL_H @@ -56,8 +57,9 @@ class Output_file; // single zero byte, as required for SHT_STRTAB sections. This // conversion is only permitted after all strings have been added to // the Stringpool. After doing this conversion, you can ask for the -// offset of any string in the stringpool in the string table, and you -// can write the resulting string table to an output file. +// offset of any string (or any key) in the stringpool in the string +// table, and you can write the resulting string table to an output +// file. // When a Stringpool is turned into a string table, then as an // optimization it will reuse string suffixes to avoid duplicating @@ -65,6 +67,79 @@ class Output_file; // string "abc" will be stored, and "bc" will be represented by an // offset into the middle of the string "abc". + +// A simple chunked vector class--this is a subset of std::vector +// which stores memory in chunks. We don't provide iterators, because +// we don't need them. + +template +class Chunked_vector +{ + public: + Chunked_vector() + : chunks_() + { } + + // Clear the elements. + void + clear() + { this->chunks_.clear(); } + + // Reserve elements. + void + reserve(unsigned int n) + { + n += chunk_size - 1; + while (n >= chunk_size) + { + this->chunks_.push_back(Element_vector()); + this->chunks_.back().reserve(chunk_size); + n -= 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()); + } + + // 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) + { + this->chunks_.push_back(Element_vector()); + this->chunks_.back().reserve(chunk_size); + } + this->chunks_.back().push_back(element); + } + + // Return a reference to an entry in the vector. + Element& + operator[](size_t i) + { return this->chunks_[i / chunk_size][i % chunk_size]; } + + const Element& + operator[](size_t i) const + { return this->chunks_[i / chunk_size][i % chunk_size]; } + + private: + static const unsigned int chunk_size = 8192; + + typedef std::vector Element_vector; + typedef std::vector Chunk_vector; + + Chunk_vector chunks_; +}; + + // Stringpools are implemented in terms of Stringpool_template, which // is generalized on the type of character used for the strings. Most // uses will want the Stringpool type which uses char. Other cases @@ -141,6 +216,14 @@ class Stringpool_template section_offset_type get_offset_with_length(const Stringpool_char* s, size_t length) const; + // Get the offset of the string with key K. + section_offset_type + get_offset_from_key(Key k) const + { + gold_assert(k < this->key_to_offset_.size()); + return this->key_to_offset_[k]; + } + // Get the size of the string table. This returns the number of // bytes, not in units of Stringpool_char. section_size_type @@ -189,15 +272,13 @@ class Stringpool_template size_t len; // Allocated size of buffer. size_t alc; - // Buffer index. - unsigned int index; // Buffer. char data[1]; }; // Copy a string into the buffers, returning a canonical string. const Stringpool_char* - add_string(const Stringpool_char*, size_t, Key*); + add_string(const Stringpool_char*, size_t); // Return whether s1 is a suffix of s2. static bool @@ -249,11 +330,9 @@ class Stringpool_template operator()(const Hashkey&, const Hashkey&) const; }; - // The hash table is a map from strings to a pair of Key and string - // table offsets. We only use the offsets if we turn this into an - // string table section. + // The hash table is a map from strings to Keys. - typedef std::pair Hashval; + typedef Key Hashval; typedef Unordered_map String_set_type; @@ -268,19 +347,21 @@ class Stringpool_template operator()(const Stringpool_sort_info&, const Stringpool_sort_info&) const; }; + // Keys map to offsets via a Chunked_vector. We only use the + // offsets if we turn this into an string table section. + typedef Chunked_vector Key_to_offset; + // List of Stringdata structures. typedef std::list Stringdata_list; // Mapping from const char* to namepool entry. String_set_type string_set_; + // Mapping from Key to string table offset. + Key_to_offset key_to_offset_; // List of buffers. Stringdata_list strings_; // Size of string table. section_size_type strtab_size_; - // Next Stringdata index. - unsigned int next_index_; - // Next key value for a string we don't copy. - int next_uncopied_key_; // Whether to reserve offset 0 to hold the null string. bool zero_null_; }; -- 2.30.2