From: Roland McGrath Date: Wed, 8 Jul 2009 09:16:14 +0000 (-0700) Subject: Collect unique DIE shapes in dwarf_output construction. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=babee18f99d88f91132c6ed03dfa91689a367cf4;p=thirdparty%2Felfutils.git Collect unique DIE shapes in dwarf_output construction. --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 8fef9dc46..81128e3d9 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,9 @@ +2009-07-08 Roland McGrath + + * c++/output-shape.cc: New file. + * Makefile.am (libdwpp_a_SOURCES): Add it. + * c++/dwarf_output: Call add_shape method there. + 2009-07-06 Roland McGrath * c++/dwarf_tracker (tracker): Break out private class into ... diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 0d3e636bb..baaa19054 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -98,7 +98,7 @@ libdwpp_a_SOURCES = c++/values.cc \ c++/known.cc \ c++/line_info.cc \ c++/edit-values.cc \ - c++/output-values.cc + c++/output-values.cc c++/output-shape.cc noinst_HEADERS = c++/dwarf-knowledge.cc \ c++/data-values.hh diff --git a/libdw/c++/dwarf_data b/libdw/c++/dwarf_data index 0c04eb826..c49360ce9 100644 --- a/libdw/c++/dwarf_data +++ b/libdw/c++/dwarf_data @@ -106,23 +106,15 @@ namespace elfutils friend class subr::create_container; friend class impl::compile_units; private: - inline compile_unit () : - impl::debug_info_entry (::DW_TAG_compile_unit) - {} - template - static inline const die_type &require_cu (const die_type &die) + template + inline void set (const die_type &die, arg_type &arg) { if (die.tag () != ::DW_TAG_compile_unit) throw std::invalid_argument ("not a compile_unit entry"); - return die; + impl::debug_info_entry::set (die, arg); } - template - inline compile_unit (const die_type &die, tracker &t) - : impl::debug_info_entry (require_cu (die), t) - {} - public: // Fetch the CU's DW_AT_stmt_list. diff --git a/libdw/c++/dwarf_edit b/libdw/c++/dwarf_edit index fbd59b3fd..ac0a30b42 100644 --- a/libdw/c++/dwarf_edit +++ b/libdw/c++/dwarf_edit @@ -117,7 +117,9 @@ namespace elfutils template static inline void equivalence (const iterator &out, - const typename input::const_iterator &in, tracker &t) + const typename input::const_iterator &in, + bool, // last-sibling + tracker &t) { t.equivalence (out, in); } diff --git a/libdw/c++/dwarf_output b/libdw/c++/dwarf_output index 3d8ea2eb2..8fed59403 100644 --- a/libdw/c++/dwarf_output +++ b/libdw/c++/dwarf_output @@ -52,7 +52,10 @@ #include "dwarf_edit" #include "dwarf_ref_maker" +#include #include +#include +#include #include /* Read the comments for elfutils::dwarf first. @@ -293,6 +296,7 @@ namespace elfutils protected: template class copier; // Below. +#if 0 /* An iterator adapter for use in iterator-based constructors. collectify (iterator) yields an iterator on input where *i constructs output::value_type (input::value_type v, collector). */ @@ -304,6 +308,7 @@ namespace elfutils { return subr::argifier (c) (in); } +#endif /* Every kind of value is made by calling into the copier, which returns a const pointer into a value_set living in the collector. */ @@ -426,6 +431,7 @@ namespace elfutils class debug_info_entry { + friend class dwarf_output_collector; friend class subr::create_container; public: @@ -480,18 +486,18 @@ namespace elfutils private: inline children_type () {} - template + template static inline void - equivalence (const iterator &out, - const typename input::const_iterator &in, tracker &t) + copied (const iterator &out, const typename input::const_iterator &in, + bool last_sibling, copier &c) { - t.equivalence (out, in); + c.copied (out, in, last_sibling); } - template - inline children_type (const input &other, tracker &t) + template + inline children_type (const input &other, copier &c) { - subr::create_container (this, other, t, equivalence); + subr::create_container (this, other, c, copied); } public: @@ -505,11 +511,12 @@ namespace elfutils int _m_tag; const attributes_type *_m_attributes; children_type _m_children; + void *_m_shape; // This is can only be used by the children_type constructor, // which immediately calls set. inline debug_info_entry () - : _m_tag (-1), _m_attributes (NULL), _m_children () + : _m_tag (-1), _m_attributes (NULL), _m_children (), _m_shape (NULL) {} template @@ -533,21 +540,6 @@ namespace elfutils } public: - inline debug_info_entry (int t) - : _m_tag (t), _m_attributes (NULL), _m_children () - { - if (unlikely (t <= 0)) - throw std::invalid_argument ("invalid tag"); - } - - /* 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, copier &c) - : _m_tag (die.tag ()), - _m_attributes (c.add_attributes (die.attributes ())), - _m_children (die.children (), c) - {} inline int tag () const { @@ -697,9 +689,12 @@ namespace elfutils // Constructor copying CUs from an input file (can be any of dwarf, // dwarf_edit, or dwarf_output). + // Copy construction instantiates a copier derived from the collector. template - inline dwarf_output (const input &, dwarf_output_collector &, - copier = copier ()); + inline dwarf_output (const input &dw, dwarf_output_collector &c, + copier maker = copier ()) + : _m_units (dw.compile_units (), maker (c)) + {} template inline bool operator== (const file &other) const @@ -713,15 +708,6 @@ 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 @@ -738,6 +724,7 @@ template private: typedef dwarf_output::debug_info_entry die_type; + typedef die_type::children_type::const_iterator die_ptr; typedef die_type::attributes_type attrs_type; subr::value_set _m_strings; @@ -776,15 +763,42 @@ template 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); + return &*_m_attr_sets.insert (attrs_type (x, c)).first; } + struct shape_type + { + typedef std::vector > attrs_type; + attrs_type _m_attrs; + bool _m_has_children; + size_t _m_hash; + + friend class subr::hashed_hasher; + typedef subr::hashed_hasher hasher; + + inline void hashnadd (int name, int form); + inline shape_type (const die_type &die, bool last_sibling); + + inline bool operator== (const shape_type &other) const + { + return (_m_hash == other._m_hash + && _m_has_children == other._m_has_children + && _m_attrs == other._m_attrs); + } + inline bool operator!= (const shape_type &other) const + { + return !(*this == other); + } + }; + + typedef subr::nothing shape_info; + + typedef std::tr1::unordered_map shape_map; + shape_map _m_shapes; + + void add_shape (die_type &die, bool last_sibling); + }; template @@ -904,15 +918,15 @@ template { return _m_collector->add_attributes (x, *this); } - }; - // Copy construction instantiates a copier derived from the collector. - template - inline dwarf_output::dwarf_output (const input &dw, - dwarf_output_collector &c, - copier maker) - : _m_units (dw.compile_units (), maker (c)) - {} + template + inline void copied (const debug_info_entry::children_type::iterator &out, + const input_iter &in, bool last_sibling) + { + equivalence (out, in); + _m_collector->add_shape (*out, last_sibling); + } + }; }; #endif // diff --git a/libdw/c++/output-shape.cc b/libdw/c++/output-shape.cc new file mode 100644 index 000000000..fdc40aed8 --- /dev/null +++ b/libdw/c++/output-shape.cc @@ -0,0 +1,153 @@ +/* elfutils::dwarf_output abbrev generation. + Copyright (C) 2009 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#include +#include "dwarf_output" + +using namespace elfutils; + +static inline int +attr_form (int tag, const dwarf_output::attribute &attr) +{ + switch (attr.second.what_space ()) + { + case dwarf::VS_address: + return DW_FORM_addr; + + case dwarf::VS_flag: + return DW_FORM_flag; + + case dwarf::VS_reference: + return DW_FORM_ref_addr; + + case dwarf::VS_string: + case dwarf::VS_identifier: + return DW_FORM_string; + + case dwarf::VS_constant: + if (! attr.second.constant_is_integer ()) + return DW_FORM_block; + /* Fall through. */ + + case dwarf::VS_dwarf_constant: + case dwarf::VS_lineptr: + case dwarf::VS_macptr: + case dwarf::VS_rangelistptr: + case dwarf::VS_source_line: + case dwarf::VS_source_column: + return DW_FORM_udata; + + case dwarf::VS_location: + return (attr.second.location ().is_list () + ? DW_FORM_udata : DW_FORM_block); + + + case dwarf::VS_source_file: + switch (attr.first) + { + case DW_AT_decl_file: + case DW_AT_call_file: + return DW_FORM_udata; + + case DW_AT_comp_dir: + return DW_FORM_string; + + case DW_AT_name: + switch (tag) + { + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + return DW_FORM_string; + } + break; + } + throw std::runtime_error ("source_file value unexpected in " + + to_string (attr)); + + case dwarf::VS_discr_list: + return DW_FORM_block; + } + + throw std::logic_error ("strange value_space"); +} + +inline void +dwarf_output_collector::shape_type::hashnadd (int name, int form) +{ + subr::hash_combine (_m_hash, name); + subr::hash_combine (_m_hash, form); + _m_attrs.push_back (std::make_pair (name, form)); +} + +inline +dwarf_output_collector::shape_type::shape_type (const die_type &die, + bool last_sibling) + : _m_has_children (die.has_children ()), _m_hash (8675309 << _m_has_children) +{ + if (!last_sibling) + hashnadd (DW_AT_sibling, DW_FORM_ref_udata); + + for (die_type::attributes_type::const_iterator it = die.attributes ().begin (); + it != die.attributes ().end (); + ++it) + hashnadd (it->first, attr_form (die.tag (), *it)); +} + +void +dwarf_output_collector::add_shape (die_type &die, bool last_sibling) +{ + assert (die._m_shape == NULL); + + shape_map::value_type &x + = *_m_shapes.insert (std::make_pair (shape_type (die, last_sibling), + shape_info ())).first; + // x.second.nusers++, etc. + + die._m_shape = &x; +} diff --git a/libdw/c++/subr.hh b/libdw/c++/subr.hh index 8d42a77eb..986b443ac 100644 --- a/libdw/c++/subr.hh +++ b/libdw/c++/subr.hh @@ -67,6 +67,8 @@ namespace elfutils struct hash : public integer_hash {}; template<> struct hash : public integer_hash {}; + template<> + struct hash : public integer_hash {}; template struct hash > @@ -837,16 +839,18 @@ namespace elfutils inline create_container (container *me, const input &other, arg_type &arg, hook_type &hook = hook_type ()) { - for (typename input::const_iterator in = other.begin (); - in != other.end (); - ++in) + typename input::const_iterator in = other.begin (); + bool last = in == other.end (); + while (!last) { /* Don't copy-construct the entry from *in here because that copies it again into the list and destroys the first copy. */ me->push_back (typename container::value_type ()); typename container::iterator out = --me->end (); out->set (*in, arg); - hook (out, in, arg); + const typename input::const_iterator here = in++; + last = in == other.end (); + hook (out, in, last, arg); } } };