From c019c04618a1909f589706ffab894db401de63f2 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Fri, 30 Jan 2026 23:32:49 -0500 Subject: [PATCH] gdb/dwarf: make abbrev_table_cache read-through, make it mandatory This patch implements some performance improvements initially sent as part of this series [1], but now as a single patch. There was some push back from Tom regarding the increased memory usage, but I think that my solution is still desirable: it makes the code simpler, and I think that the memory usage it not an issue (the usage is transient and the amount of memory used by the abbrev tables is relatively low). As a reminder, here is the problem I'm looking to solve: when using split DWARF (.dwo files) plus type units, all units inside a .dwo file (generally one compile unit plus many type units) share the same abbrev table. So we end up re-reading that same abbrev tables many times, and its gets very noticeable in function process_skeletonless_type_units. cooked_index_worker_debug_info::process_type_units does some work to avoid this problem, but it only works when everything is in the main file (not using split DWARF). Right now, we cache abbrev tables only in specific cases during indexing, like when one CU imports things from another CU. My previous series changed cutu_reader so that it would add any abbrev table it would read to the abbrev table cache (if it was passed one as a parameter). This allowed using a cache in process_skeletonless_type_units and cut the time down significantly. This patch goes a bit further in order to simplify cutu_reader even further: - It makes the abbrev table cache read-through, meaning that when you request an abbrev table and it's not in the cache, it will go read it (and cache it). - It makes passing an abbrev table cache to the constructors mandatory (even when we wouldn't benefit from using a cache). The result is that cutu_reader doesn't need to manage multiple cases of how to obtain an abbrev table, and it doesn't need to manage adding abbrev tables to the cache. It no longer needs to manage the ownership of the abbrev tables either: the abbrev tables are always owned by the cache. And the cases of abbrev table sharing are well handled transparently. This means that we pay a small price when we don't necessarily need to (sometimes building and destroying an abbrev_table_cache for just one cutu_reader), but I think that this price is not significant and the code simplification is welcome. In concrete terms, this patch: - changes abbrev_table_cache::find to become abbrev_table_cache::get, making it read-through - removes abbrev_table_cache::add - removes the abbrev_table parameter from the main cutu_reader constructor - makes the abbrev_table_cache parameter mandatory (a reference) in the main cutu_reader constructor, adds it to the alternative constructor, and passes it down to a few methods - adjusts the cutu_reader code obtaining an abbrev table to just call abbrev_table_cache::get - adjusts all the cutu_reader users to pass an abbrev_table_cache (if not already) - removes the code in cooked_index_worker_debug_info::process_type_units meant to efficiently handle TUs that share abbrev tables - the cache now does this The specific split DWARF + type units performance problem at the origin of this work gets fixed by the fact that cooked_index_worker_debug_info::process_skeletonless_type_unit now passes an abbrev table cache to cutu_reader, and cutu_reader::read_cutu_die_from_dwo uses it. As a test, I'm using a build of Blender compiled with -gsplit-dwarf and -fdebug-types-section. I run this: $ ./gdb -nx -q --data-directory=data-directory -ex 'maint set dwarf sync on' -ex 'maintenance set per-command time on' -ex "file /data1/smarchi/blender-build/relwithdebinfo-clang-debugtypes-splitdwarf/bin/blender" -batch and look at the time taken by the "DWARF skeletonless type units" step. Before looks like: Time for "DWARF skeletonless type units": wall 11.131, user 10.699, sys 0.431, user+sys 11.130, 100.0 % CPU and after looks like: Time for "DWARF skeletonless type units": wall 1.751, user 1.221, sys 0.518, user+sys 1.739, 99.3 % CPU The total run time (wall clock time) of the command goes from about 18.5 seconds to about 9.5 seconds. I removed this assert in cutu_reader, because it relies on abbrev_cache as a flag for whether we're in the indexer: /* If an existing_cu is provided, a dwarf2_cu must not exist for this_cu in per_objfile yet. Here, CACHE doubles as a flag to let us know that the CU is being scanned using the parallel indexer. This assert is avoided in this case because (1) it is irrelevant, and (2) the get_cu method is not thread-safe. */ gdb_assert (abbrev_cache != nullptr || per_objfile.get_cu (&this_cu) == nullptr); It's not clear to me if this assert is important or how to implement it differently. [1] https://inbox.sourceware.org/gdb-patches/20250326200002.136200-4-simon.marchi@efficios.com/ Change-Id: Idf8a514326fb35be8bda0d7ebe3cee4b7304941a Approved-By: Tom Tromey --- gdb/Makefile.in | 1 - gdb/dwarf2/abbrev-table-cache.h | 18 +-- gdb/dwarf2/cooked-index-worker.c | 2 - gdb/dwarf2/cooked-index-worker.h | 4 + gdb/dwarf2/cooked-indexer.c | 7 +- gdb/dwarf2/read.c | 225 +++++++++---------------------- gdb/dwarf2/read.h | 28 ++-- 7 files changed, 81 insertions(+), 204 deletions(-) diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 2138d7566dd..713c0920f6a 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2006,7 +2006,6 @@ TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR) # Files that are used to support certain debuginfo formats DWARF2_SRCS = \ dwarf2/abbrev.c \ - dwarf2/abbrev-table-cache.c \ dwarf2/ada-imported.c \ dwarf2/aranges.c \ dwarf2/attribute.c \ diff --git a/gdb/dwarf2/abbrev-table-cache.h b/gdb/dwarf2/abbrev-table-cache.h index 30babbc3374..be141dceb15 100644 --- a/gdb/dwarf2/abbrev-table-cache.h +++ b/gdb/dwarf2/abbrev-table-cache.h @@ -34,27 +34,19 @@ public: abbrev_table_cache &operator= (abbrev_table_cache &&) = default; /* Find an abbrev table coming from the abbrev section SECTION at - offset OFFSET. Return the table, or nullptr if it has not yet - been registered. */ - const abbrev_table *find (dwarf2_section_info *section, - sect_offset offset) const + offset OFFSET. Read it in if necessary. */ + const abbrev_table &get (dwarf2_section_info *section, sect_offset offset) { abbrev_table_search_key key {section, offset}; if (auto iter = m_tables.find (key); iter != m_tables.end ()) - return iter->get (); + return **iter; - return nullptr; + auto table = abbrev_table::read (section, offset); + return **m_tables.insert (std::move (table)).first; } - /* Add TABLE to this cache. Ownership of TABLE is transferred to - the cache. Note that a table at a given section+offset may only - be registered once -- a violation of this will cause an assert. - To avoid this, call the 'find' method first, to see if the table - has already been read. */ - void add (abbrev_table_up table); - private: /* Key used to search for an existing abbrev table in M_TABLES. */ struct abbrev_table_search_key diff --git a/gdb/dwarf2/cooked-index-worker.c b/gdb/dwarf2/cooked-index-worker.c index 24be57edfb5..ef2427d0a71 100644 --- a/gdb/dwarf2/cooked-index-worker.c +++ b/gdb/dwarf2/cooked-index-worker.c @@ -46,8 +46,6 @@ cooked_index_worker_result::get_reader (dwarf2_per_cu *per_cu) cutu_reader * cooked_index_worker_result::preserve (cutu_reader_up reader) { - m_abbrev_table_cache.add (reader->release_abbrev_table ()); - auto [it, inserted] = m_reader_hash.insert (std::move (reader)); gdb_assert (inserted); diff --git a/gdb/dwarf2/cooked-index-worker.h b/gdb/dwarf2/cooked-index-worker.h index 847b8ce5589..d46415bf8bc 100644 --- a/gdb/dwarf2/cooked-index-worker.h +++ b/gdb/dwarf2/cooked-index-worker.h @@ -49,6 +49,10 @@ public: cooked_index_worker_result &operator= (cooked_index_worker_result &&) = default; + /* Return the current abbrev table_cache. */ + abbrev_table_cache &get_abbrev_table_cache () + { return m_abbrev_table_cache; } + /* Return the current abbrev table_cache. */ const abbrev_table_cache &get_abbrev_table_cache () const { return m_abbrev_table_cache; } diff --git a/gdb/dwarf2/cooked-indexer.c b/gdb/dwarf2/cooked-indexer.c index 1d5b5bcca40..40f62de80eb 100644 --- a/gdb/dwarf2/cooked-indexer.c +++ b/gdb/dwarf2/cooked-indexer.c @@ -110,12 +110,11 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader, cutu_reader *result = m_index_storage->get_reader (per_cu); if (result == nullptr) { - const abbrev_table_cache &abbrev_table_cache + abbrev_table_cache &abbrev_table_cache = m_index_storage->get_abbrev_table_cache (); auto new_reader - = std::make_unique (*per_cu, *per_objfile, nullptr, - nullptr, false, m_language, - &abbrev_table_cache); + = std::make_unique (*per_cu, *per_objfile, nullptr, false, + m_language, abbrev_table_cache); if (new_reader->is_dummy ()) return nullptr; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 341872c22b1..c023ce0f1cd 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -704,9 +704,6 @@ static unsigned int peek_abbrev_code (bfd *, const gdb_byte *); static unrelocated_addr read_addr_index (struct dwarf2_cu *cu, unsigned int addr_index); -static sect_offset read_abbrev_offset (dwarf2_per_objfile *per_objfile, - dwarf2_section_info *, sect_offset); - static const char *read_indirect_string (dwarf2_per_objfile *per_objfile, bfd *, const gdb_byte *, const unit_head *, unsigned int *); @@ -1850,9 +1847,9 @@ dw2_get_file_names (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile) if (this_cu->files_read) return this_cu->file_names; - cutu_reader reader (*this_cu, *per_objfile, nullptr, - per_objfile->get_cu (this_cu), true, std::nullopt, - nullptr); + abbrev_table_cache abbrev_table_cache; + cutu_reader reader (*this_cu, *per_objfile, per_objfile->get_cu (this_cu), + true, std::nullopt, abbrev_table_cache); if (reader.is_dummy ()) { /* Make sure we don't re-read the dummy CU. */ @@ -2444,35 +2441,6 @@ all_units_less_than (const dwarf2_per_cu &lhs, const section_and_offset &rhs) return lhs.sect_off () < rhs.offset; } -/* Fetch the abbreviation table offset from a comp or type unit header. */ - -static sect_offset -read_abbrev_offset (dwarf2_per_objfile *per_objfile, - struct dwarf2_section_info *section, - sect_offset sect_off) -{ - bfd *abfd = section->get_bfd_owner (); - const gdb_byte *info_ptr; - unsigned int initial_length_size, offset_size; - uint16_t version; - - section->read (per_objfile->objfile); - info_ptr = section->buffer + to_underlying (sect_off); - read_initial_length (abfd, info_ptr, &initial_length_size); - offset_size = initial_length_size == 4 ? 4 : 8; - info_ptr += initial_length_size; - - version = read_2_bytes (abfd, info_ptr); - info_ptr += 2; - if (version >= 5) - { - /* Skip unit type and address size. */ - info_ptr += 2; - } - - return (sect_offset) read_offset (abfd, info_ptr, offset_size); -} - /* Add an entry for signature SIG to per_bfd->signatured_types. This functions leaves PER_BFD::ALL_UNITS unsorted. The caller must call @@ -2667,7 +2635,7 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig) void cutu_reader::init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section, struct dwo_file *dwo_file, - const struct abbrev_table *abbrev_table) + const abbrev_table &abbrev_table) { gdb_assert (section->read_in && section->buffer != NULL); m_abfd = section->get_bfd_owner (); @@ -2676,7 +2644,7 @@ cutu_reader::init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section, m_die_section = section; m_buffer = section->buffer; m_buffer_end = section->buffer + section->size; - m_abbrev_table = abbrev_table; + m_abbrev_table = &abbrev_table; } /* Subroutine of cutu_reader to simplify it. @@ -2702,7 +2670,8 @@ cutu_reader::init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section, void cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, die_info *stub_comp_unit_die, - const char *stub_comp_dir) + const char *stub_comp_dir, + abbrev_table_cache &abbrev_table_cache) { dwarf2_per_cu *per_cu = cu->per_cu; struct objfile *objfile = cu->per_objfile->objfile; @@ -2826,11 +2795,9 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, ? cu->header.addr_size : cu->header.offset_size); - dwo_abbrev_section->read (objfile); - m_dwo_abbrev_table - = abbrev_table::read (dwo_abbrev_section, cu->header.abbrev_sect_off); - this->init_cu_die_reader (cu, section, dwo_unit->dwo_file, - m_dwo_abbrev_table.get ()); + const abbrev_table &abbrev_table + = abbrev_table_cache.get (dwo_abbrev_section, cu->header.abbrev_sect_off); + this->init_cu_die_reader (cu, section, dwo_unit->dwo_file, abbrev_table); /* Skip dummy compilation units. */ if (m_info_ptr >= begin_info_ptr + dwo_unit->length @@ -2910,7 +2877,8 @@ void cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile, dwarf2_cu *existing_cu, - std::optional pretend_language) + std::optional pretend_language, + abbrev_table_cache &abbrev_table_cache) { signatured_type *sig_type = this_cu->as_signatured_type (); @@ -2941,7 +2909,8 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu, could share abbrev tables. */ read_cutu_die_from_dwo (cu, sig_type->dwo_unit, NULL /* stub_comp_unit_die */, - sig_type->dwo_unit->dwo_file->comp_dir); + sig_type->dwo_unit->dwo_file->comp_dir, + abbrev_table_cache); prepare_one_comp_unit (cu, pretend_language); } @@ -2957,11 +2926,10 @@ cutu_reader::init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu, cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, dwarf2_per_objfile &per_objfile, - const struct abbrev_table *abbrev_table, dwarf2_cu *existing_cu, bool skip_partial, std::optional pretend_language, - const abbrev_table_cache *abbrev_cache) + abbrev_table_cache &abbrev_table_cache) { struct objfile *objfile = per_objfile.objfile; struct dwarf2_section_info *section = this_cu.section (); @@ -2984,9 +2952,8 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, { /* Narrow down the scope of possibilities to have to understand. */ gdb_assert (this_cu.is_debug_types ()); - gdb_assert (abbrev_table == NULL); init_tu_and_read_dwo_dies (&this_cu, &per_objfile, existing_cu, - pretend_language); + pretend_language, abbrev_table_cache); return; } @@ -3014,14 +2981,6 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, } else { - /* If an existing_cu is provided, a dwarf2_cu must not exist for - this_cu in per_objfile yet. Here, CACHE doubles as a flag to - let us know that the CU is being scanned using the parallel - indexer. This assert is avoided in this case because (1) it - is irrelevant, and (2) the get_cu method is not - thread-safe. */ - gdb_assert (abbrev_cache != nullptr - || per_objfile.get_cu (&this_cu) == nullptr); m_new_cu = std::make_unique (&this_cu, &per_objfile); cu = m_new_cu.get (); } @@ -3081,25 +3040,9 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, m_dummy_p = true; else { - /* If we don't have them yet, read the abbrevs for this - compilation unit. And if we need to read them now, make sure - they're freed when we're done. */ - if (abbrev_table != NULL) - gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off); - else - { - if (abbrev_cache != nullptr) - abbrev_table = abbrev_cache->find (abbrev_section, - cu->header.abbrev_sect_off); - if (abbrev_table == nullptr) - { - abbrev_section->read (objfile); - m_abbrev_table_holder - = abbrev_table::read (abbrev_section, - cu->header.abbrev_sect_off); - abbrev_table = m_abbrev_table_holder.get (); - } - } + abbrev_section->read (objfile); + const abbrev_table &abbrev_table + = abbrev_table_cache.get (abbrev_section, cu->header.abbrev_sect_off); /* Read the top level CU/TU die. */ this->init_cu_die_reader (cu, section, NULL, abbrev_table); @@ -3134,7 +3077,8 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, dwo_unit = lookup_dwo_unit (cu, m_top_level_die, dwo_name); if (dwo_unit != NULL) - read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die, nullptr); + read_cutu_die_from_dwo (cu, dwo_unit, m_top_level_die, nullptr, + abbrev_table_cache); else { /* Yikes, we couldn't find the rest of the DIE, we only have @@ -3179,7 +3123,8 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, dwarf2_per_objfile &per_objfile, std::optional pretend_language, dwarf2_cu &parent_cu, - dwo_file &dwo_file) + dwo_file &dwo_file, + abbrev_table_cache &abbrev_table_cache) { struct objfile *objfile = per_objfile.objfile; struct dwarf2_section_info *section = this_cu.section (); @@ -3218,13 +3163,12 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, m_dummy_p = true; else { - abbrev_section->read (objfile); - m_abbrev_table_holder - = abbrev_table::read (abbrev_section, - m_new_cu->header.abbrev_sect_off); + const abbrev_table &abbrev_table + = abbrev_table_cache.get (abbrev_section, + m_new_cu->header.abbrev_sect_off); this->init_cu_die_reader (m_new_cu.get (), section, &dwo_file, - m_abbrev_table_holder.get ()); + abbrev_table); m_top_level_die = this->read_toplevel_die (); } @@ -3364,8 +3308,6 @@ private: dwarf_read_debug_printf ("Type unit statistics:"); dwarf_read_debug_printf (" %d TUs", per_bfd->num_type_units); - dwarf_read_debug_printf (" %d uniq abbrev tables", - tu_stats->nr_uniq_abbrev_tables); dwarf_read_debug_printf (" %d symtabs from stmt_list entries", tu_stats->nr_symtabs); dwarf_read_debug_printf (" %d symtab sharers", @@ -3433,12 +3375,10 @@ cooked_index_worker_debug_info::process_unit cutu_reader *reader = storage->get_reader (this_cu); if (reader == nullptr) { - const abbrev_table_cache &abbrev_table_cache - = storage->get_abbrev_table_cache (); - auto new_reader = std::make_unique (*this_cu, *per_objfile, - nullptr, nullptr, false, - std::nullopt, - &abbrev_table_cache); + auto new_reader + = std::make_unique (*this_cu, *per_objfile, nullptr, + false, std::nullopt, + storage->get_abbrev_table_cache ()); if (new_reader->is_dummy ()) return; @@ -3503,74 +3443,23 @@ void cooked_index_worker_debug_info::process_type_units (dwarf2_per_objfile *per_objfile, cooked_index_worker_result *storage) { - struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats; - abbrev_table_up abbrev_table; - if (per_objfile->per_bfd->num_type_units == 0) return; - /* TUs typically share abbrev tables, and there can be way more TUs than - abbrev tables. Sort by abbrev table to reduce the number of times we - read each abbrev table in. - Alternatives are to punt or to maintain a cache of abbrev tables. - This is simpler and efficient enough for now. - - Later we group TUs by their DW_AT_stmt_list value (as this defines the - symtab to use). Typically TUs with the same abbrev offset have the same - stmt_list value too so in practice this should work well. - - The basic algorithm here is: - - sort TUs by abbrev table - for each TU with same abbrev table: - read abbrev table if first user - read TU top level DIE - [IWBN if DWO skeletons had DW_AT_stmt_list] - call FUNC */ - - dwarf_read_debug_printf ("Building type unit groups ..."); - - /* Sort in a separate table to maintain the order of all_units - for .gdb_index: TU indices directly index all_type_units. */ - std::vector sorted_by_abbrev; - sorted_by_abbrev.reserve (per_objfile->per_bfd->num_type_units); - for (const auto &cu : per_objfile->per_bfd->all_units) if (signatured_type *sig_type = cu->as_signatured_type (); sig_type != nullptr) { - sect_offset abbrev_offset - = read_abbrev_offset (per_objfile, sig_type->section (), - sig_type->sect_off ()); - sorted_by_abbrev.emplace_back (sig_type, abbrev_offset); + cutu_reader reader (*sig_type, *per_objfile, nullptr, false, + std::nullopt, + storage->get_abbrev_table_cache ()); + + if (!reader.is_dummy ()) + storage->catch_error ([&] () + { + process_type_unit (&reader, storage); + }); } - - std::sort (sorted_by_abbrev.begin (), sorted_by_abbrev.end ()); - - sect_offset abbrev_offset = (sect_offset) ~(unsigned) 0; - - for (const tu_abbrev_offset &tu : sorted_by_abbrev) - { - /* Switch to the next abbrev table if necessary. */ - if (abbrev_table == NULL - || tu.abbrev_offset != abbrev_offset) - { - abbrev_offset = tu.abbrev_offset; - per_objfile->per_bfd->abbrev.read (per_objfile->objfile); - abbrev_table = - abbrev_table::read (&per_objfile->per_bfd->abbrev, abbrev_offset); - ++tu_stats->nr_uniq_abbrev_tables; - } - - cutu_reader reader (*tu.sig_type, *per_objfile, - abbrev_table.get (), nullptr, false, - std::nullopt); - if (!reader.is_dummy ()) - storage->catch_error ([&] () - { - process_type_unit (&reader, storage); - }); - } } void @@ -3597,8 +3486,8 @@ cooked_index_worker_debug_info::process_skeletonless_type_unit fill_in_sig_entry_from_dwo_entry (per_objfile, *sig_type_it, dwo_unit); /* This does the job that build_type_psymtabs would have done. */ - cutu_reader reader (**sig_type_it, *per_objfile, nullptr, nullptr, false, - std::nullopt); + cutu_reader reader (**sig_type_it, *per_objfile, nullptr, false, + std::nullopt, storage->get_abbrev_table_cache ()); if (!reader.is_dummy ()) process_type_unit (&reader, storage); } @@ -4182,8 +4071,9 @@ load_full_comp_unit (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile, gdb_assert (!this_cu->is_debug_types ()); gdb_assert (per_objfile->get_cu (this_cu) == nullptr); - cutu_reader reader (*this_cu, *per_objfile, nullptr, nullptr, skip_partial, - pretend_language); + abbrev_table_cache abbrev_table_cache; + cutu_reader reader (*this_cu, *per_objfile, nullptr, skip_partial, + pretend_language, abbrev_table_cache); if (reader.is_dummy ()) return; @@ -6322,6 +6212,7 @@ cutu_reader::create_dwo_unit_hash_tables (dwo_file &dwo_file, section.get_file_name ()); const gdb_byte *end_ptr = info_ptr + section.size; + abbrev_table_cache abbrev_table_cache; while (info_ptr < end_ptr) { @@ -6362,7 +6253,7 @@ cutu_reader::create_dwo_unit_hash_tables (dwo_file &dwo_file, dwarf2_per_cu per_cu (&per_bfd, §ion, sect_off, length, false /* is_dwz */); cutu_reader reader (per_cu, per_objfile, std::nullopt, - skeleton_cu, dwo_file); + skeleton_cu, dwo_file, abbrev_table_cache); std::optional opt_signature = lookup_dwo_id (reader.cu (), reader.top_level_die ()); @@ -14975,8 +14866,9 @@ dwarf2_read_addr_index (dwarf2_per_cu *per_cu, dwarf2_per_objfile *per_objfile, } else { - cutu_reader reader (*per_cu, *per_objfile, nullptr, nullptr, false, - std::nullopt); + abbrev_table_cache abbrev_table_cache; + cutu_reader reader (*per_cu, *per_objfile, nullptr, false, + std::nullopt, abbrev_table_cache); addr_base = reader.cu ()->addr_base; addr_size = reader.cu ()->header.addr_size; } @@ -17576,8 +17468,9 @@ read_signatured_type (signatured_type *sig_type, gdb_assert (sig_type->is_debug_types ()); gdb_assert (per_objfile->get_cu (sig_type) == nullptr); - cutu_reader reader (*sig_type, *per_objfile, nullptr, nullptr, false, - std::nullopt); + abbrev_table_cache abbrev_table_cache; + cutu_reader reader (*sig_type, *per_objfile, nullptr, false, + std::nullopt, abbrev_table_cache); if (!reader.is_dummy ()) { @@ -18045,8 +17938,9 @@ dwarf2_per_cu::ensure_lang (dwarf2_per_objfile *per_objfile) /* Constructing this object will set the language as a side effect. */ - cutu_reader reader (*this, *per_objfile, nullptr, per_objfile->get_cu (this), - true, std::nullopt, nullptr); + abbrev_table_cache abbrev_table_cache; + cutu_reader reader (*this, *per_objfile, per_objfile->get_cu (this), + true, std::nullopt, abbrev_table_cache); } /* Return the unit from ALL_UNITS that potentially contains TARGET. @@ -18126,8 +18020,11 @@ dwarf2_find_containing_unit (const section_and_offset &target, Even though it should happen too often, it could be replaced with something more lightweight that has the same effect. */ if (!per_cu->length_is_set ()) - cutu_reader (*per_cu, *per_objfile, nullptr, nullptr, false, - std::nullopt); + { + abbrev_table_cache abbrev_table_cache; + cutu_reader (*per_cu, *per_objfile, nullptr, false, std::nullopt, + abbrev_table_cache); + } /* Now we can check if the target section offset is within PER_CU's range. */ if (target.offset < per_cu->sect_off () diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 172d718e6b7..bf1fab4c34f 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -40,7 +40,6 @@ extern struct cmd_list_element *show_dwarf_cmdlist; struct tu_stats { - int nr_uniq_abbrev_tables = 0; int nr_symtabs = 0; int nr_symtab_sharers = 0; int nr_stmt_less_type_units = 0; @@ -1016,17 +1015,17 @@ public: cutu_reader (dwarf2_per_cu &this_cu, dwarf2_per_objfile &per_objfile, - const struct abbrev_table *abbrev_table, dwarf2_cu *existing_cu, bool skip_partial, std::optional pretend_language, - const abbrev_table_cache *abbrev_cache = nullptr); + abbrev_table_cache &abbrev_cache); cutu_reader (dwarf2_per_cu &this_cu, dwarf2_per_objfile &per_objfile, std::optional pretend_language, struct dwarf2_cu &parent_cu, - struct dwo_file &dwo_file); + struct dwo_file &dwo_file, + abbrev_table_cache &abbrev_table_cache); DISABLE_COPY_AND_ASSIGN (cutu_reader); @@ -1054,13 +1053,6 @@ public: /* Release the CU created by this cutu_reader. */ dwarf2_cu_up release_cu (); - /* Release the abbrev table, transferring ownership to the - caller. */ - abbrev_table_up release_abbrev_table () - { - return std::move (m_abbrev_table_holder); - } - /* Read all DIES of the debug info section in memory. */ void read_all_dies (); @@ -1085,16 +1077,18 @@ private: void init_cu_die_reader (dwarf2_cu *cu, dwarf2_section_info *section, struct dwo_file *dwo_file, - const struct abbrev_table *abbrev_table); + const abbrev_table &abbrev_table); void init_tu_and_read_dwo_dies (dwarf2_per_cu *this_cu, dwarf2_per_objfile *per_objfile, dwarf2_cu *existing_cu, - std::optional pretend_language); + std::optional pretend_language, + abbrev_table_cache &abbrev_table_cache); void read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, die_info *stub_comp_unit_die, - const char *stub_comp_dir); + const char *stub_comp_dir, + abbrev_table_cache &abbrev_table_cache); void prepare_one_comp_unit (struct dwarf2_cu *cu, std::optional pretend_language); @@ -1171,12 +1165,6 @@ private: bool m_dummy_p = false; dwarf2_cu_up m_new_cu; - - /* The ordinary abbreviation table. */ - abbrev_table_up m_abbrev_table_holder; - - /* The DWO abbreviation table. */ - abbrev_table_up m_dwo_abbrev_table; }; /* Converts DWARF language names to GDB language names. */