From: Roland McGrath Date: Tue, 7 Jul 2009 07:40:37 +0000 (-0700) Subject: dwarf_output::attributes_type (full attr set) in collector set. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ec9127b9217541c5e39ee94777eec17e70cd7344;p=thirdparty%2Felfutils.git dwarf_output::attributes_type (full attr set) in collector set. --- diff --git a/libdw/c++/dwarf_data b/libdw/c++/dwarf_data index 38f2afe45..0c04eb826 100644 --- a/libdw/c++/dwarf_data +++ b/libdw/c++/dwarf_data @@ -765,7 +765,6 @@ namespace elfutils std::string to_string () const; }; - public: template struct value { @@ -778,6 +777,31 @@ namespace elfutils static const bool delete_value = alloc_values; + template + static inline flavor & + variant (flavor *&, const value_dispatch *&) + { + assert (!alloc_values); + throw std::logic_error ("can't happen!"); + } + + template + static inline flavor & + variant (flavor *&result, value_dispatch *&value) + { + assert (alloc_values); + if (value == NULL) + { + result = new flavor; + value = result; + return *result; + } + result = dynamic_cast (value); + if (result == NULL) + throw std::runtime_error ("wrong value type"); + return *result; + } + template static inline value_dispatch * make (flavor *&result, int /*whatattr*/, const input &x, arg_type &arg) @@ -1069,8 +1093,9 @@ namespace elfutils class attr_value { friend class attributes_type; + friend class value; - private: + protected: typename vw::value_cell_type *_m_value; typedef typename impl::debug_info_entry::pointer die_ptr; @@ -1153,9 +1178,8 @@ namespace elfutils template inline flavor &variant () { - if (_m_value == NULL) - _m_value = new flavor; - return const_variant (); + flavor *p; + return vw::variant (p, _m_value); } public: @@ -1431,15 +1455,24 @@ namespace elfutils template class attributes_type - : public std::map > + : public std::map { friend class impl::debug_info_entry; private: - typedef std::map > base_type; + typedef std::map base_type; protected: inline attributes_type () {} + template + inline void set (const input &other, arg_type &c) + { + for (typename input::const_iterator attr = other.begin (); + attr != other.end (); + ++attr) + (*this)[(*attr).first].set ((*attr).first, (*attr).second, c); + } + public: // XXX should be protected /* We don't use the base_type (begin, end) iterator constructor here @@ -1453,23 +1486,9 @@ namespace elfutils inline attributes_type (const input &other, arg_type &c) : base_type () { - for (typename input::const_iterator attr = other.begin (); - attr != other.end (); - ++attr) - (*this)[(*attr).first].set ((*attr).first, (*attr).second, c); + set (other, c); } -#if 0 - // dwarf_output probably will do it this way (?) - template - inline attributes_type (const input &other, arg_type &c) - : base_type (subr::argify2nd - (other.begin (), c), - subr::argify2nd - (other.end (), c)) - {} -#endif - public: typedef typename base_type::key_type key_type; typedef typename base_type::value_type value_type; diff --git a/libdw/c++/dwarf_output b/libdw/c++/dwarf_output index c0f638fe3..3d8ea2eb2 100644 --- a/libdw/c++/dwarf_output +++ b/libdw/c++/dwarf_output @@ -53,6 +53,7 @@ #include "dwarf_edit" #include "dwarf_ref_maker" #include +#include /* Read the comments for elfutils::dwarf first. @@ -287,6 +288,7 @@ namespace elfutils class compile_units; class debug_info_entry; + class attr_value; protected: template class copier; // Below. @@ -422,14 +424,55 @@ namespace elfutils public: - typedef dwarf_data::attr_value attr_value; - class debug_info_entry { friend class subr::create_container; public: - typedef dwarf_data::attributes_type attributes_type; + class attributes_type + : public dwarf_data::attributes_type + { + friend class debug_info_entry; + + private: + typedef dwarf_data::attributes_type _base; + + size_t _m_hash; + + inline attributes_type () + : _base (), _m_hash (0) + {} + + struct same_attr : public std::equal_to + { + bool operator () (const value_type &a, + const value_type &b) const + { + return a.first == b.first && a.second.is (b.second); + } + }; + + public: + friend class subr::hashed_hasher; + typedef subr::hashed_hasher hasher; + + template + inline attributes_type (const input &other, arg_type &c) + : _base (other, c), _m_hash (0) + { + // Precompute our hash value based on our contents. + for (iterator i = begin (); i != end (); ++i) + subr::hash_combine (_m_hash, *i); + } + + inline bool are (const attributes_type &these) const + { + return (_m_hash == these._m_hash + && size () == these.size () + && std::equal (begin (), end (), these.begin (), + same_attr ())); + } + }; class children_type : public std::list { @@ -460,29 +503,30 @@ namespace elfutils protected: int _m_tag; - attributes_type _m_attributes; + const attributes_type *_m_attributes; children_type _m_children; // This is can only be used by the children_type constructor, // which immediately calls set. inline debug_info_entry () - : _m_tag (-1), _m_attributes (), _m_children () + : _m_tag (-1), _m_attributes (NULL), _m_children () {} - template - inline void set (const die_type &die, arg_type &arg) + template + inline void set (const die_type &die, copier &c) { + assert (_m_attributes == NULL); try { _m_tag = die.tag (); - _m_attributes.swap (attributes_type (die.attributes (), arg)); - _m_children.swap (children_type (die.children (), arg)); + _m_attributes = c.add_attributes (die.attributes ()); + _m_children.swap (children_type (die.children (), c)); } catch (...) { // Never leave a partially-formed DIE. _m_tag = -1; - _m_attributes.clear (); + _m_attributes = NULL; _m_children.clear (); throw; }; @@ -490,7 +534,7 @@ namespace elfutils public: inline debug_info_entry (int t) - : _m_tag (t), _m_attributes (), _m_children () + : _m_tag (t), _m_attributes (NULL), _m_children () { if (unlikely (t <= 0)) throw std::invalid_argument ("invalid tag"); @@ -498,11 +542,11 @@ namespace elfutils /* The template constructor lets us copy in from any class that has compatibly iterable containers for attributes and children. */ - template - debug_info_entry (const die_type &die, tracker &t) + template + debug_info_entry (const die_type &die, copier &c) : _m_tag (die.tag ()), - _m_attributes (die.attributes (), t), - _m_children (die.children (), t) + _m_attributes (c.add_attributes (die.attributes ())), + _m_children (die.children (), c) {} inline int tag () const @@ -522,7 +566,7 @@ namespace elfutils inline const attributes_type &attributes () const { - return _m_attributes; + return *_m_attributes; } template @@ -549,6 +593,55 @@ namespace elfutils } }; + class attr_value + : public dwarf_data::attr_value + { + private: + typedef dwarf_data::attr_value _base; + + public: + + /* These constructors can only be used by the containers + used in the collector. The attributes_type map in an + actual debug_info_entry object is always const. */ + inline attr_value () + : _base () + {} + + inline attr_value (const attr_value &other) + : _base () + { + this->_m_value = other._m_value; + } + + /* Two identical values in fact share the same cell in the collector. + So we can use simple pointer comparison here. */ + inline bool is (const attr_value &that) const + { + return this->_m_value == that._m_value; + } + + // The is () test works only on a dwarf_output sharing the same collector. + inline bool operator== (const attr_value &other) const + { + return is (other) || _base::operator== (other); + } + inline bool operator!= (const attr_value &other) const + { + return !(*this == other); + } + + /* We can use the _m_value pointer itself as a perfect hash, because + all identical values share the same cell in the collector. */ + struct hasher : public std::unary_function + { + inline size_t operator () (const attr_value &v) const + { + return (uintptr_t) v._m_value; + } + }; + }; + typedef debug_info_entry::attributes_type::value_type attribute; typedef dwarf_data::compile_unit compile_unit; @@ -620,6 +713,15 @@ namespace elfutils } }; + /* +template + inline flavor &dwarf_output::attr_value::_base::flavor () + { + assert (!"should be impossible"); + throw std::logic_error ("should be impossible"); + } + */ + // Explicit specializations. template<> std::string @@ -635,6 +737,9 @@ namespace elfutils friend class dwarf_output; private: + typedef dwarf_output::debug_info_entry die_type; + typedef die_type::attributes_type attrs_type; + subr::value_set _m_strings; subr::value_set _m_identifiers; subr::value_set _m_address; @@ -654,6 +759,32 @@ namespace elfutils { return flag ? &flag_true : &flag_false; } + + struct same_attrs : public std::equal_to + { + bool operator () (const die_type::attributes_type &a, + const die_type::attributes_type &b) const + { + return a.are (b); + } + }; + + typedef std::tr1::unordered_set attrs_set; + attrs_set _m_attr_sets; + + template + inline const attrs_type *add_attributes (const input &x, copier_type &c) + { + std::pair p + = _m_attr_sets.insert (attrs_type (x, c)); + if (p.second) + { + // XXX hook for collection: abbrev building, etc. + } + return &(*p.first); + } + }; template @@ -766,6 +897,13 @@ namespace elfutils { return _m_collector->_m_locations.add (x); } + + template + inline const debug_info_entry::attributes_type * + add_attributes (const input &x) + { + return _m_collector->add_attributes (x, *this); + } }; // Copy construction instantiates a copier derived from the collector. diff --git a/libdw/c++/output-values.cc b/libdw/c++/output-values.cc index aa45180ce..86b7e1f3a 100644 --- a/libdw/c++/output-values.cc +++ b/libdw/c++/output-values.cc @@ -55,8 +55,7 @@ using namespace elfutils; -// Actually both the same thing! -template dwarf::value_space dwarf_output::attr_value::what_space () const; +template class dwarf_data::attr_value; template<> std::string diff --git a/libdw/c++/subr.hh b/libdw/c++/subr.hh index 5b6859f09..4e1debb1e 100644 --- a/libdw/c++/subr.hh +++ b/libdw/c++/subr.hh @@ -67,6 +67,10 @@ namespace elfutils struct hash : public integer_hash {}; template<> struct hash : public integer_hash {}; +#if UINT64_MAX != UINTPTR_MAX + template<> + struct hash : public integer_hash {}; +#endif template struct hash > @@ -467,7 +471,7 @@ namespace elfutils public: typedef typename elt_type::value_type value_type; - private: + protected: size_t _m_hash; inline void set_hash () @@ -478,7 +482,7 @@ namespace elfutils hashit (size_t &h) : _m_hash (h) {} inline void operator () (const elt_type &p) { - subr::hash_combine (_m_hash, p.first); + subr::hash_combine (_m_hash, p); } }; std::for_each (_base::begin (), _base::end (), hashit (_m_hash));