This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
Re: some notes on dwarf_output::copier
- From: Roland McGrath <roland at redhat dot com>
- To: elfutils-devel at lists dot fedorahosted dot org
- Date: Mon, 10 Jan 2011 11:46:55 -0800
- Subject: Re: some notes on dwarf_output::copier
> The copier is instantiated when a dwarf_output object is instantiated
> and it creates the compile_units, which will call copier::make_unit ()
> through the cu_maker for each cu. make_unit () will create a
> copier::unit_copier for each cu using the
> compile_units_type::const_iterator, and then calls final_unit () on it,
> which just does a sanity check on the result, making sure there are no
> undefined entries left, and returns the final die_info_pair.
Correct. I think this spot is where the main control flow of the second
walk will be done.
> An entry_copier lives as long as the copier is transforming the
> input_die. It holds the copier, the copier::entry input die, and a
> copier::pending_entry output which gets created in the constructor from
> the input die tag. The constructor set the input copier::entry
> _m_building field to the entry_copier to indicate it is being
> constructed. The destructor clears it again. It doesn't hold the actual
> input_die as state, all methods take an input_die as argument.
Correct. The main reason for this kind of object is that running its
destructor is the unwind-protect mechanism. That is, the destructor gets
run even when an exception is thrown during the copying. It's also
possible to replace use of a temporary object that has a destructor with
just using 'try { ... } finally { ... }' clauses. Feel free to do that
when it seems simpler.
We also take advantage of the fact that we have this temporary object to
use a pointer to it as the circularity detection mechanism (_m_building).
> entry_copier::populate (as called from the unit_copier constructor)
> takes an input_die, sets the _m_pending field of the input entry to the
> output pending_entry of the entry_copier. It will populate the
> _m_attributes if the _m_out entry from the given input_die and call
> add_child() for each child of the given input_die. After that it will
> clear the _m_out field to indicate the we are done with the
> pending_entry. And call entry::defined_self () on the _m_in entry.
Right. defined_self triggers the final steps of state changes based on the
reference counts. All that will be changing and hopefully become far
simpler in the new plan.
> When the _m_attributes set of the entry is populated the value maker
> will call back into the entry_copier::add_reference() for each reference
> value. add_reference() will setup the copier to enter the input_die to
> which the attribute is pointing and provide a "backptr" to the
> entry::refer() method that fill it in with either the finalized entry
> itself (if it is finalized) or to the entry itself and pushes the
> backptr to the _m_pending_refs of pending_entry.
Correct.
> entry_copier::add_child will setup the copier to start copying the given
> child die and create a new copier::entry for it, add the child to the
> _m_out pending_entry. If the child is already know, but not yet final
> (because it comes from an DW_TAG_imported_unit in a logical walk) it
> will update the _m_parent and create a new entry_copier and populate
> that.
Right. That entry_copier is a temporary that lives only inside that
add_child frame, during the recursion into entry_copier::populate.
> entry_copier::final_unit() as called from make_unit() will do sanity
> checks to make sure the _m_in entry has really been finalized and return
> the die_info_pair stored in the collector.
Right. It may make sense to remove this method and change the details of
the unit_copier class and what methods it has, or perhaps final_unit can
stay as the place where all the finalization happens. Whatever works.
> A copier::entry holds the following state: _m_offset, the Dwarff_Off of
> the original die, _m_cost, the cost of the original die,
Right. _m_offset serves the original_offset method, and is only kept to
use in the debugging output and the collector's stats output. Nothing
about the actual workings uses it. Likewise _m_cost is the "cost", meaning
bytes occupied by the encoding, and is just for the statistics output where
we can show how much we saved by reducing duplicates. I have some thought
that eventually this cost calculation could be used in the output routines
to decide when it's worthwhile to generate a shared partial_unit vs just
copying very small DIEs in the output.
Thanks,
Roland