From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3826 invoked by alias); 21 Sep 2004 02:31:42 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 3795 invoked from network); 21 Sep 2004 02:31:40 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sourceware.org with SMTP; 21 Sep 2004 02:31:40 -0000 Received: from drow by nevyn.them.org with local (Exim 4.34 #1 (Debian)) id 1C9aRP-0007Sw-T9; Mon, 20 Sep 2004 22:31:39 -0400 Date: Tue, 21 Sep 2004 02:31:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sources.redhat.com Cc: jimb@redhat.com Subject: [rfa/intercu] Preserve DIE types Message-ID: <20040921023139.GA25706@nevyn.them.org> Mail-Followup-To: gdb-patches@sources.redhat.com, jimb@redhat.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.5.1+cvs20040105i X-SW-Source: 2004-09/txt/msg00333.txt.bz2 In multiple-compilation-unit land, we may read a particular compilation unit from disk many times - once to build partial symbols, once to build full symbols, and then for both partial and full symbols any number of additional times after it falls out of cache. For partial symbols this is fine; the DIEs are self-contained. All we want from them is their attributes. If you take a look at struct die_info, though, you'll see the problem for full symbols - the "type" field. There is no way to repopulate the type when we reread the symbols. Not only would a lot of new lookup code have to be written, but for nameless DIEs we're simply up a creek. The only solution I could find was to cache this information, specifically the DIE -> type mapping. We could do it whenever the CU is flushed from the cache for the first time, but I think the difference would be negligible, so I build the hash table when each DIE is first assigned its type. This patch consists of code to create the hash table, code to repopulate the type fields from the hash table (tested that it compiles, and then #if'd it out, to prevent warnings about unused functions), and the mechanical change to use set_die_type everywhere we used to assign to die->type. A forthcoming patch will remove the #if 0's; I just wanted to break this chunk out so that it would be more readable. Tested on i686-pc-linux-gnu. OK? -- Daniel Jacobowitz 2004-09-20 Daniel Jacobowitz * dwarf2read.c (struct dwarf2_per_cu_data): New field type_hash. (struct dwarf2_offset_and_type): New. (set_die_type, reset_die_and_siblings_types, get_die_type) (offset_and_type_hash, offset_and_type_eq): New functions. (read_structure_type, read_enumeration_type, read_array_type) (read_namespace, read_tag_pointer_type, read_tag_ptr_to_member_type) (read_tag_reference_type, read_tag_const_type) (read_tag_volatile_type, read_tag_string_type, read_subroutine_type) (read_typedef, read_base_type, read_subrange_type): Use set_die_type. Index: dwarf2read.c =================================================================== RCS file: /cvs/src/src/gdb/dwarf2read.c,v retrieving revision 1.162 diff -u -p -r1.162 dwarf2read.c --- dwarf2read.c 20 Sep 2004 22:26:19 -0000 1.162 +++ dwarf2read.c 21 Sep 2004 02:20:39 -0000 @@ -353,6 +353,13 @@ struct dwarf2_per_cu_data /* Set iff currently read in. */ struct dwarf2_cu *cu; + + /* If full symbols for this CU have been read in, then this field + holds a map of DIE offsets to types. It isn't always possible + to reconstruct this information later, so we have to preserve + it. */ + + htab_t type_hash; }; /* The line number information for a compilation unit (found in the @@ -1035,6 +1042,14 @@ static void age_cached_comp_units (void) static void free_one_cached_comp_unit (void *); +static void set_die_type (struct die_info *, struct type *, + struct dwarf2_cu *); + +#if 0 +static void reset_die_and_siblings_types (struct die_info *, + struct dwarf2_cu *); +#endif + static void create_all_comp_units (struct objfile *); static void dwarf2_mark (struct dwarf2_cu *); @@ -3600,7 +3615,7 @@ read_structure_type (struct die_info *di /* We need to add the type field to the die immediately so we don't infinitely recurse when dealing with pointers to the structure type within the structure itself. */ - die->type = type; + set_die_type (die, type, cu); if (die->child != NULL && ! die_is_declaration (die, cu)) { @@ -3776,7 +3791,7 @@ read_enumeration_type (struct die_info * TYPE_LENGTH (type) = 0; } - die->type = type; + set_die_type (die, type, cu); } /* Determine the name of the type represented by DIE, which should be @@ -3942,7 +3957,8 @@ read_array_type (struct die_info *die, s { index_type = dwarf2_fundamental_type (objfile, FT_INTEGER, cu); range_type = create_range_type (NULL, index_type, 0, -1); - die->type = create_array_type (NULL, element_type, range_type); + set_die_type (die, create_array_type (NULL, element_type, range_type), + cu); return; } @@ -4002,7 +4018,7 @@ read_array_type (struct die_info *die, s do_cleanups (back_to); /* Install the type in the die. */ - die->type = type; + set_die_type (die, type, cu); } static enum dwarf_array_dim_ordering @@ -4129,7 +4145,7 @@ read_namespace (struct die_info *die, st TYPE_TAG_NAME (type) = TYPE_NAME (type); new_symbol (die, type, cu); - die->type = type; + set_die_type (die, type, cu); if (is_anonymous) cp_add_using_directive (processing_current_prefix, @@ -4236,7 +4252,7 @@ read_tag_pointer_type (struct die_info * } TYPE_LENGTH (type) = byte_size; - die->type = type; + set_die_type (die, type, cu); } /* Extract all information from a DW_TAG_ptr_to_member_type DIE and add to @@ -4260,7 +4276,7 @@ read_tag_ptr_to_member_type (struct die_ domain = die_containing_type (die, cu); smash_to_member_type (type, domain, to_type); - die->type = type; + set_die_type (die, type, cu); } /* Extract all information from a DW_TAG_reference_type DIE and add to @@ -4288,7 +4304,7 @@ read_tag_reference_type (struct die_info { TYPE_LENGTH (type) = cu_header->addr_size; } - die->type = type; + set_die_type (die, type, cu); } static void @@ -4302,7 +4318,8 @@ read_tag_const_type (struct die_info *di } base_type = die_type (die, cu); - die->type = make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0); + set_die_type (die, make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0), + cu); } static void @@ -4316,7 +4333,8 @@ read_tag_volatile_type (struct die_info } base_type = die_type (die, cu); - die->type = make_cv_type (TYPE_CONST (base_type), 1, base_type, 0); + set_die_type (die, make_cv_type (TYPE_CONST (base_type), 1, base_type, 0), + cu); } /* Extract all information from a DW_TAG_string_type DIE and add to @@ -4368,7 +4386,7 @@ read_tag_string_type (struct die_info *d char_type = dwarf2_fundamental_type (objfile, FT_CHAR, cu); type = create_string_type (char_type, range_type); } - die->type = type; + set_die_type (die, type, cu); } /* Handle DIES due to C code like: @@ -4450,7 +4468,7 @@ read_subroutine_type (struct die_info *d } } - die->type = ftype; + set_die_type (die, ftype, cu); } static void @@ -4467,7 +4485,9 @@ read_typedef (struct die_info *die, stru { name = DW_STRING (attr); } - die->type = init_type (TYPE_CODE_TYPEDEF, 0, TYPE_FLAG_TARGET_STUB, name, objfile); + set_die_type (die, init_type (TYPE_CODE_TYPEDEF, 0, + TYPE_FLAG_TARGET_STUB, name, objfile), + cu); TYPE_TARGET_TYPE (die->type) = die_type (die, cu); } } @@ -4555,7 +4575,7 @@ read_base_type (struct die_info *die, st { type = dwarf_base_type (encoding, size, cu); } - die->type = type; + set_die_type (die, type, cu); } /* Read the given DW_AT_subrange DIE. */ @@ -4626,7 +4646,7 @@ read_subrange_type (struct die_info *die if (attr) TYPE_LENGTH (range_type) = DW_UNSND (attr); - die->type = range_type; + set_die_type (die, range_type, cu); } @@ -9252,6 +9272,105 @@ free_one_cached_comp_unit (void *target_ } } +/* A pair of DIE offset and GDB type pointer. We store these + in a hash table separate from the DIEs, and preserve them + when the DIEs are flushed out of cache. */ + +struct dwarf2_offset_and_type +{ + unsigned int offset; + struct type *type; +}; + +/* Hash function for a dwarf2_offset_and_type. */ + +static hashval_t +offset_and_type_hash (const void *item) +{ + const struct dwarf2_offset_and_type *ofs = item; + return ofs->offset; +} + +/* Equality function for a dwarf2_offset_and_type. */ + +static int +offset_and_type_eq (const void *item_lhs, const void *item_rhs) +{ + const struct dwarf2_offset_and_type *ofs_lhs = item_lhs; + const struct dwarf2_offset_and_type *ofs_rhs = item_rhs; + return ofs_lhs->offset == ofs_rhs->offset; +} + +/* Set the type associated with DIE to TYPE. Save it in CU's hash + table if necessary. */ + +static void +set_die_type (struct die_info *die, struct type *type, struct dwarf2_cu *cu) +{ + struct dwarf2_offset_and_type **slot, ofs; + + die->type = type; + + if (cu->per_cu == NULL) + return; + + if (cu->per_cu->type_hash == NULL) + cu->per_cu->type_hash + = htab_create_alloc_ex (cu->header.length / 24, + offset_and_type_hash, + offset_and_type_eq, + NULL, + &cu->objfile->objfile_obstack, + hashtab_obstack_allocate, + dummy_obstack_deallocate); + + ofs.offset = die->offset; + ofs.type = type; + slot = (struct dwarf2_offset_and_type **) + htab_find_slot_with_hash (cu->per_cu->type_hash, &ofs, ofs.offset, INSERT); + *slot = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (**slot)); + **slot = ofs; +} + +#if 0 + +/* Find the type for DIE in TYPE_HASH, or return NULL if DIE does not + have a saved type. */ + +static struct type * +get_die_type (struct die_info *die, htab_t type_hash) +{ + struct dwarf2_offset_and_type *slot, ofs; + + ofs.offset = die->offset; + slot = htab_find_with_hash (type_hash, &ofs, ofs.offset); + if (slot) + return slot->type; + else + return NULL; +} + +/* Restore the types of the DIE tree starting at START_DIE from the hash + table saved in CU. */ + +static void +reset_die_and_siblings_types (struct die_info *start_die, struct dwarf2_cu *cu) +{ + struct die_info *die; + + if (cu->per_cu->type_hash == NULL) + return; + + for (die = start_die; die != NULL; die = die->sibling) + { + die->type = get_die_type (die, cu->per_cu->type_hash); + if (die->child != NULL) + reset_die_and_siblings_types (die->child, cu); + } +} + +#endif + /* Set the mark field in CU and in every other compilation unit in the cache that we must keep because we are keeping CU. */