[RFA/dwarf] Don't process types multiple times

Daniel Jacobowitz
2004-02-25T04:42:08Z

This independent patch is a performance and correctness fix for full symbol
processing. My description from the intercu branch posting:

There are two ways that we can process a general DIE: process_die or
read_type_die. Children of particular DIE types may be processed directly,
but these are the only major dispatch points. It's interesting to notice
that almost everything called from read_type_die starts with "if (die->type)
return": everything but enumeration types and aggregate types, in fact.
This means that if the first reference to an enumeration or aggregate type
is a DW_AT_type or DW_AT_containing_type in a DIE numerically before the
type's DIE, we'll end up calling new_symbol for it twice.

Fixing this saves about 8% memory and 4% time from gdb -readnow libc.so.6,
a lot of duplicate entries on maint print symbols which I vaguely recall
being confused about but never investigated, and some serious problems for
inter-CU support. Without this, types could be added to the wrong symbol
table.

Tested i686-pc-linux-gnu, no regressions. OK to commit?

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

2004-02-24 Daniel Jacobowitz <drow@mvista.com>

* dwarf2read.c (read_structure_scope): Don't create a symbol
or call process_die. Return immediately if die->type is set.
Call read_type_die before dwarf2_add_member_fn.
(process_structure_scope): New function.
(read_enumeration_type, read_enumeration_scope): New functions,
broken out from read_enumeration. Don't create the enumeration
type if it has already been created.
(read_enumeration): Removed.
(process_die): Call process_structure_scope, read_enumeration_type,
and read_enumeration_scope. Just call new_symbol for base and
subrange types. Add a comment about other type dies.
(read_type_die): Call read_enumeration_type.

Index: dwarf2read.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/dwarf2read.c,v
retrieving revision 1.135
diff -u -p -r1.135 dwarf2read.c
--- dwarf2read.c 21 Feb 2004 02:13:35 -0000 1.135
+++ dwarf2read.c 25 Feb 2004 04:29:12 -0000
@@ -806,6 +806,8 @@ static void dwarf2_attach_fn_fields_to_t

static void read_structure_scope (struct die_info *, struct dwarf2_cu *);

+static void process_structure_scope (struct die_info *, struct dwarf2_cu *);
+
static void read_common_block (struct die_info *, struct dwarf2_cu *);

static void read_namespace (struct die_info *die, struct dwarf2_cu *);
@@ -813,7 +815,9 @@ static void read_namespace (struct die_i
static const char *namespace_name (struct die_info *die,
int *is_anonymous, struct dwarf2_cu *);

-static void read_enumeration (struct die_info *, struct dwarf2_cu *);
+static void read_enumeration_type (struct die_info *, struct dwarf2_cu *);
+
+static void read_enumeration_scope (struct die_info *, struct dwarf2_cu *);

static struct type *dwarf_base_type (int, int, struct dwarf2_cu *);

@@ -1950,10 +1954,16 @@ process_die (struct die_info *die, struc
case DW_TAG_structure_type:
case DW_TAG_union_type:
read_structure_scope (die, cu);
+ process_structure_scope (die, cu);
break;
case DW_TAG_enumeration_type:
- read_enumeration (die, cu);
+ read_enumeration_type (die, cu);
+ read_enumeration_scope (die, cu);
break;
+
+ /* FIXME: These initialize die->type, but do not create a symbol
+ or process any children. Therefore it doesn't do anything that
+ won't be done on-demand by read_type_die. */
case DW_TAG_subroutine_type:
read_subroutine_type (die, cu);
break;
@@ -1972,21 +1982,19 @@ process_die (struct die_info *die, struc
case DW_TAG_string_type:
read_tag_string_type (die, cu);
break;
+ /* END FIXME */
+
case DW_TAG_base_type:
read_base_type (die, cu);
- if (dwarf2_attr (die, DW_AT_name, cu))
- {
- /* Add a typedef symbol for the base type definition. */
- new_symbol (die, die->type, cu);
- }
+ /* Add a typedef symbol for the type definition, if it has a
+ DW_AT_name. */
+ new_symbol (die, die->type, cu);
break;
case DW_TAG_subrange_type:
read_subrange_type (die, cu);
- if (dwarf2_attr (die, DW_AT_name, cu))
- {
- /* Add a typedef symbol for the base type definition. */
- new_symbol (die, die->type, cu);
- }
+ /* Add a typedef symbol for the type definition, if it has a
+ DW_AT_name. */
+ new_symbol (die, die->type, cu);
break;
case DW_TAG_common_block:
read_common_block (die, cu);
@@ -3008,6 +3016,9 @@ read_structure_scope (struct die_info *d
any. */
int need_to_update_name = 0;

+ if (die->type)
+ return;
+
type = alloc_type (objfile);

INIT_CPLUS_SPECIFIC (type);
@@ -3106,7 +3117,7 @@ read_structure_scope (struct die_info *d
else if (child_die->tag == DW_TAG_subprogram)
{
/* C++ member function. */
- process_die (child_die, cu);
+ read_type_die (child_die, cu);
dwarf2_add_member_fn (&fi, child_die, type, cu);
if (need_to_update_name)
{
@@ -3149,10 +3160,6 @@ read_structure_scope (struct die_info *d
/* C++ base class field. */
dwarf2_add_field (&fi, child_die, cu);
}
- else
- {
- process_die (child_die, cu);
- }
child_die = sibling_die (child_die);
}

@@ -3209,8 +3216,6 @@ read_structure_scope (struct die_info *d
}
}

- new_symbol (die, type, cu);
-
do_cleanups (back_to);
}
else
@@ -3224,26 +3229,53 @@ read_structure_scope (struct die_info *d
do_cleanups (back_to);
}

-/* Given a pointer to a die which begins an enumeration, process all
- the dies that define the members of the enumeration.
+static void
+process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ const char *previous_prefix = processing_current_prefix;

- This will be much nicer in draft 6 of the DWARF spec when our
- members will be dies instead squished into the DW_AT_element_list
- attribute.
+ if (TYPE_TAG_NAME (die->type) != NULL)
+ processing_current_prefix = TYPE_TAG_NAME (die->type);

- NOTE: We reverse the order of the element list. */
+ if (die->child != NULL && ! die_is_declaration (die, cu))
+ {
+ struct die_info *child_die;
+
+ child_die = die->child;
+
+ while (child_die && child_die->tag)
+ {
+ if (child_die->tag == DW_TAG_member
+ || child_die->tag == DW_TAG_variable
+ || child_die->tag == DW_TAG_inheritance)
+ {
+ /* Do nothing. */
+ }
+ else
+ process_die (child_die, cu);
+
+ child_die = sibling_die (child_die);
+ }
+
+ new_symbol (die, die->type, cu);
+ }
+
+ processing_current_prefix = previous_prefix;
+}
+
+/* Given a DW_AT_enumeration_type die, set its type. We do not
+ complete the type's fields yet, or create any symbols. */

static void
-read_enumeration (struct die_info *die, struct dwarf2_cu *cu)
+read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
{
struct objfile *objfile = cu->objfile;
- struct die_info *child_die;
struct type *type;
- struct field *fields;
struct attribute *attr;
- struct symbol *sym;
- int num_fields;
- int unsigned_enum = 1;
+
+ if (die->type)
+ return;

type = alloc_type (objfile);

@@ -3278,6 +3310,26 @@ read_enumeration (struct die_info *die,
TYPE_LENGTH (type) = 0;
}

+ die->type = type;
+}
+
+/* Given a pointer to a die which begins an enumeration, process all
+ the dies that define the members of the enumeration, and create the
+ symbol for the enumeration type.
+
+ NOTE: We reverse the order of the element list. */
+
+static void
+read_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+ struct objfile *objfile = cu->objfile;
+ struct die_info *child_die;
+ struct field *fields;
+ struct attribute *attr;
+ struct symbol *sym;
+ int num_fields;
+ int unsigned_enum = 1;
+
num_fields = 0;
fields = NULL;
if (die->child != NULL)
@@ -3294,7 +3346,7 @@ read_enumeration (struct die_info *die,
attr = dwarf2_attr (child_die, DW_AT_name, cu);
if (attr)
{
- sym = new_symbol (child_die, type, cu);
+ sym = new_symbol (child_die, die->type, cu);
if (SYMBOL_VALUE (sym) < 0)
unsigned_enum = 0;

@@ -3321,18 +3373,18 @@ read_enumeration (struct die_info *die,

if (num_fields)
{
- TYPE_NFIELDS (type) = num_fields;
- TYPE_FIELDS (type) = (struct field *)
- TYPE_ALLOC (type, sizeof (struct field) * num_fields);
- memcpy (TYPE_FIELDS (type), fields,
+ TYPE_NFIELDS (die->type) = num_fields;
+ TYPE_FIELDS (die->type) = (struct field *)
+ TYPE_ALLOC (die->type, sizeof (struct field) * num_fields);
+ memcpy (TYPE_FIELDS (die->type), fields,
sizeof (struct field) * num_fields);
xfree (fields);
}
if (unsigned_enum)
- TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+ TYPE_FLAGS (die->type) |= TYPE_FLAG_UNSIGNED;
}
- die->type = type;
- new_symbol (die, type, cu);
+
+ new_symbol (die, die->type, cu);
}

/* Extract all information from a DW_TAG_array_type DIE and put it in
@@ -6012,7 +6064,7 @@ read_type_die (struct die_info *die, str
read_structure_scope (die, cu);
break;
case DW_TAG_enumeration_type:
- read_enumeration (die, cu);
+ read_enumeration_type (die, cu);
break;