summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog.intercu13
-rw-r--r--gdb/dwarf2read.c89
2 files changed, 88 insertions, 14 deletions
diff --git a/gdb/ChangeLog.intercu b/gdb/ChangeLog.intercu
index 2782fab9444..8dffa9d911e 100644
--- a/gdb/ChangeLog.intercu
+++ b/gdb/ChangeLog.intercu
@@ -1,5 +1,18 @@
2004-02-22 Daniel Jacobowitz <drow@mvista.com>
+ * dwarf2read.c (MAX_CACHE_AGE): Define.
+ (struct dwarf2_cu): Add last_used counter.
+ (free_comp_units_worker): New function, based on
+ clear_per_cu_pointer. Support aging.
+ (clear_per_cu_pointer): Use it.
+ (free_cached_comp_units, free_one_cached_comp_unit): New functions.
+ (dwarf2_build_psymtabs_hard): Keep read_in_chain across iterations.
+ Free all cached comp units after building psymtabs. Free any cached
+ copy of a comp unit before building a psymtab for it.
+ (find_partial_die): Clear the last_used counter.
+
+2004-02-22 Daniel Jacobowitz <drow@mvista.com>
+
* dwarf2read.c (partial_die_full_name): Always return NULL or
malloc'd memory. Don't try to free real_parent->full_name.
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 7b36f678a30..dafee420268 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -52,6 +52,10 @@
#include "gdb_assert.h"
#include <sys/types.h>
+/* Loaded secondary compilation units are kept in memory until they have not
+ been referenced for the processing of this many compilation units. */
+#define MAX_CACHE_AGE 20
+
#ifndef DWARF2_REG_TO_REGNUM
#define DWARF2_REG_TO_REGNUM(REG) (REG)
#endif
@@ -274,6 +278,9 @@ struct dwarf2_cu
/* Backchain to our per_cu entry if the tree has been built. */
struct dwarf2_per_cu_data *per_cu;
+
+ /* How many compilation units ago was this CU last referenced? */
+ int last_used;
};
static const struct objfile_data *dwarf2_cu_tree;
@@ -970,7 +977,11 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit
(unsigned long offset, struct dwarf2_cu *cu);
-static void clear_per_cu_pointer (void *data);
+static void clear_per_cu_pointer (void *);
+
+static void free_cached_comp_units (void *);
+
+static void free_one_cached_comp_unit (struct dwarf2_cu *, struct dwarf2_cu *);
/* Allocation function for the libiberty splay tree which uses an obstack. */
static void *
@@ -1270,6 +1281,7 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
struct cleanup *back_to;
CORE_ADDR lowpc, highpc, baseaddr;
splay_tree cu_tree = NULL;
+ struct dwarf2_cu cu;
info_ptr = dwarf_info_buffer;
@@ -1304,6 +1316,13 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
obstack_init (&dwarf2_tmp_obstack);
back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL);
+ /* read_in_chain, unlike every other field in the dwarf2_cu object,
+ is live across the loop. The function clear_per_cu_pointer will
+ free any allocated compilation units that have not been used in
+ several psymtabs. Others will remain on the list. */
+ cu.read_in_chain = NULL;
+ make_cleanup (free_cached_comp_units, &cu);
+
/* Since the objects we're extracting from dwarf_info_buffer vary in
length, only the individual functions to extract them (like
read_comp_unit_head and load_partial_die) can really know whether
@@ -1320,7 +1339,6 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
while (info_ptr < dwarf_info_buffer + dwarf_info_size)
{
struct cleanup *back_to_inner;
- struct dwarf2_cu cu;
struct abbrev_info *abbrev;
unsigned int bytes_read;
struct dwarf2_per_cu_data *this_cu;
@@ -1390,6 +1408,14 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
node = splay_tree_lookup (cu_tree, cu.header.offset);
gdb_assert (node != NULL);
per_cu = (struct dwarf2_per_cu_data *) node->value;
+
+ /* If we were already read in, free ourselves to read in again.
+ Yes, this is pointless duplication. Fixing this will provide
+ a nice speed boost but require a lot of editing in this
+ function. */
+ if (per_cu->cu != NULL)
+ free_one_cached_comp_unit (&cu, per_cu->cu);
+
cu.per_cu = per_cu;
/* Note that this is a pointer to our stack frame. It will
@@ -1401,7 +1427,6 @@ dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline)
cu.per_cu = NULL;
make_cleanup (clear_per_cu_pointer, &cu);
- cu.read_in_chain = NULL;
/* Check if comp unit has_children.
If so, read the rest of the partial symbols from this comp unit.
@@ -5064,6 +5089,7 @@ find_partial_die (unsigned long offset, struct dwarf2_cu *cu,
cu->read_in_chain = per_cu;
}
+ per_cu->cu->last_used = 0;
*target_cu = per_cu->cu;
return find_partial_die_in_comp_unit (offset, per_cu->cu);
}
@@ -8765,31 +8791,66 @@ dwarf2_find_containing_comp_unit (unsigned long offset,
}
static void
-clear_per_cu_pointer (void *data)
+free_comp_units_worker (struct dwarf2_cu *cu, int aging,
+ struct dwarf2_cu *target_cu)
{
- struct dwarf2_per_cu_data *this_cu, *per_cu;
- struct dwarf2_cu *cu = data;
+ struct dwarf2_per_cu_data *this_cu, *per_cu, **last_chain;
this_cu = cu->per_cu;
- if (this_cu == NULL)
+ if (this_cu == NULL && target_cu == NULL)
return;
- per_cu = this_cu->cu->read_in_chain;
+ per_cu = cu->read_in_chain;
+ last_chain = &cu->read_in_chain;
while (per_cu != NULL)
{
struct dwarf2_per_cu_data *next_cu;
- obstack_free (&per_cu->cu->partial_die_obstack, NULL);
-
next_cu = per_cu->cu->read_in_chain;
- xfree (per_cu->cu);
- per_cu->cu = NULL;
+
+ if ((aging && per_cu->cu->last_used < MAX_CACHE_AGE)
+ || (target_cu && per_cu->cu == target_cu)
+ || (!aging && target_cu == NULL))
+ {
+ obstack_free (&per_cu->cu->partial_die_obstack, NULL);
+ xfree (per_cu->cu);
+ per_cu->cu = NULL;
+ *last_chain = next_cu;
+ }
+ else
+ {
+ per_cu->cu->last_used++;
+ last_chain = &per_cu->cu->read_in_chain;
+ }
+
per_cu = next_cu;
}
/* This compilation unit is on the stack in dwarf2_build_psymtabs_hard,
- so we should not xfree it. */
- this_cu->cu = NULL;
+ so we should not xfree it. Just unlink it. */
+ if (target_cu == NULL)
+ {
+ cu->per_cu = NULL;
+ this_cu->cu = NULL;
+ }
+}
+
+static void
+clear_per_cu_pointer (void *data)
+{
+ free_comp_units_worker (data, 1, NULL);
+}
+
+static void
+free_cached_comp_units (void *data)
+{
+ free_comp_units_worker (data, 0, NULL);
+}
+
+static void
+free_one_cached_comp_unit (struct dwarf2_cu *cu, struct dwarf2_cu *target_cu)
+{
+ free_comp_units_worker (cu, 0, target_cu);
}
void _initialize_dwarf2_read (void);