This is the mail archive of the archer@sourceware.org mailing list for the Archer project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[python] type reference counting


This patch adds reference counting for objfile-less types.

It fixes the memory leak from gdb.Type, and it also fixes a couple
other type allocation bugs.  I noted these by removing the FIXME
comments where I thought it was appropriate.

To fix all the type allocation bugs, I really do think we need some
kind of tracing type GC.  This is a bit more complicated, though.  For
example, we would need to treat breakpoint expressions as roots, and
walk the expression tree looking for types.

I did a regression test on the compile farm with this patch, and I
also ran a few scenarios under valgrind.  Also I took a cue from Jan
and did a second regression test, this time adding -lmcheck to the
link line.  The only failures from this were unrelated to this patch.

Let me know if this causes any problems for you.  If so, we can always
back it out; the worst case is having a few memory leaks in a somewhat
artificial situation.

Tom

2008-12-01  Tom Tromey  <tromey@redhat.com>

	* value.c (allocate_value): Update reference counts.
	(value_free): Likewise.
	(deprecated_set_value_type): Likewise.
	(value_copy): Likewise.
	(preserve_one_value): Likewise.
	(value_change_enclosing_type): Likewise.
	(value_primitive_field): Likewise.
	(allocate_repeat_value): Remove FIXME comments.
	(_initialize_values): Update.
	* valops.c (value_cast): Remove FIXME.
	(value_slice): Likewise.
	* stabsread.c (dbx_alloc_type): Update.
	* python/python-type.c (clean_up_objfile_types): Increment
	reference count.
	(set_type): Likewise.
	(typy_dealloc): Decrement reference count.
	* mdebugread.c (new_type): Update.
	* jv-lang.c (type_from_class): Update.
	* gdbtypes.h (alloc_type): Update.
	(type_incref, type_decref): Declare.
	(create_deleted_types_hash, delete_type_recursive): Remove.
	* gdbtypes.c (struct type_refc_entry): New struct.
	(type_refc_table): New global.
	(alloc_type): Add 'parent' argument.  Init refc.
	(alloc_type_instance): Init refc.
	(make_pointer_type): Update.
	(make_reference_type): Update.
	(make_function_type): Update.
	(make_qualified_type): Update.
	(lookup_memberptr_type): Update.
	(lookup_methodptr_type): Update.
	(create_range_type): Update.
	(create_array_type): Update.
	(create_set_type): Update.
	(check_typedef): Update.
	(init_type): Update.  Increment reference count.
	(copy_type_recursive_1): New function.
	(copy_type_recursive): Use it.
	(copy_type): Update.
	(create_deleted_types_hash): Now static.
	(delete_type_recursive): Likewise.
	(type_refc_hash): New function.
	(type_refc_equal): Likewise.
	(type_init_refc): Likewise.
	(type_incref): Likewise.
	(type_refc_remove): Likewise.
	(type_decref): Likewise.
	(_initialize_gdbtypes): Initialize type_refc_table.
	* dwarf2read.c (dwarf2_add_member_fn): Update.
	(quirk_gcc_member_function_pointer): Update.
	(read_structure_type): Update.
	(read_enumeration_type): Update.
	* coffread.c (coff_alloc_type): Update.
	* ada-lang.c (ada_type_of_array): Update.
	(packed_array_type): Update.
	(empty_record): Update.
	(ada_template_to_fixed_record_type_1): Update.
	(template_to_static_fixed_type): Update.
	(to_record_with_fixed_variant_part): Update.
	(to_fixed_array_type): Update.
	(to_fixed_array_type): Update.
	(to_fixed_range_type): Update.
	(to_fixed_range_type): Update.

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 9989c03..31b68d2 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -1666,8 +1666,8 @@ ada_type_of_array (struct value *arr, int bounds)
         return NULL;
       while (arity > 0)
         {
-          struct type *range_type = alloc_type (objf);
-          struct type *array_type = alloc_type (objf);
+          struct type *range_type = alloc_type (objf, NULL);
+          struct type *array_type = alloc_type (objf, NULL);
           struct value *low = desc_one_bound (descriptor, arity, 0);
           struct value *high = desc_one_bound (descriptor, arity, 1);
           arity -= 1;
@@ -1774,9 +1774,9 @@ packed_array_type (struct type *type, long *elt_bits)
   if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
     return type;
 
-  new_type = alloc_type (TYPE_OBJFILE (type));
   new_elt_type = packed_array_type (ada_check_typedef (TYPE_TARGET_TYPE (type)),
                                     elt_bits);
+  new_type = alloc_type (TYPE_OBJFILE (type), new_elt_type);
   create_array_type (new_type, new_elt_type, TYPE_FIELD_TYPE (type, 0));
   TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits;
   TYPE_NAME (new_type) = ada_type_name (type);
@@ -6799,7 +6799,7 @@ variant_field_index (struct type *type)
 static struct type *
 empty_record (struct objfile *objfile)
 {
-  struct type *type = alloc_type (objfile);
+  struct type *type = alloc_type (objfile, NULL);
   TYPE_CODE (type) = TYPE_CODE_STRUCT;
   TYPE_NFIELDS (type) = 0;
   TYPE_FIELDS (type) = NULL;
@@ -6856,7 +6856,7 @@ ada_template_to_fixed_record_type_1 (struct type *type,
         nfields++;
     }
 
-  rtype = alloc_type (TYPE_OBJFILE (type));
+  rtype = alloc_type (TYPE_OBJFILE (type), NULL);
   TYPE_CODE (rtype) = TYPE_CODE_STRUCT;
   INIT_CPLUS_SPECIFIC (rtype);
   TYPE_NFIELDS (rtype) = nfields;
@@ -7035,7 +7035,8 @@ template_to_static_fixed_type (struct type *type0)
         new_type = static_unwrap_type (field_type);
       if (type == type0 && new_type != field_type)
         {
-          TYPE_TARGET_TYPE (type0) = type = alloc_type (TYPE_OBJFILE (type0));
+          TYPE_TARGET_TYPE (type0) = type = alloc_type (TYPE_OBJFILE (type0),
+							NULL);
           TYPE_CODE (type) = TYPE_CODE (type0);
           INIT_CPLUS_SPECIFIC (type);
           TYPE_NFIELDS (type) = nfields;
@@ -7080,7 +7081,7 @@ to_record_with_fixed_variant_part (struct type *type, const gdb_byte *valaddr,
   else
     dval = dval0;
 
-  rtype = alloc_type (TYPE_OBJFILE (type));
+  rtype = alloc_type (TYPE_OBJFILE (type), NULL);
   TYPE_CODE (rtype) = TYPE_CODE_STRUCT;
   INIT_CPLUS_SPECIFIC (rtype);
   TYPE_NFIELDS (rtype) = nfields;
@@ -7252,7 +7253,7 @@ to_fixed_array_type (struct type *type0, struct value *dval,
       if (elt_type0 == elt_type)
         result = type0;
       else
-        result = create_array_type (alloc_type (TYPE_OBJFILE (type0)),
+        result = create_array_type (alloc_type (TYPE_OBJFILE (type0), NULL),
                                     elt_type, TYPE_INDEX_TYPE (type0));
     }
   else
@@ -7282,7 +7283,7 @@ to_fixed_array_type (struct type *type0, struct value *dval,
           struct type *range_type =
             to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, i),
                                  dval, TYPE_OBJFILE (type0));
-          result = create_array_type (alloc_type (TYPE_OBJFILE (type0)),
+          result = create_array_type (alloc_type (TYPE_OBJFILE (type0), NULL),
                                       result, range_type);
         }
       if (!ignore_too_big && TYPE_LENGTH (result) > varsize_limit)
@@ -9547,7 +9548,7 @@ to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile)
       if (L < INT_MIN || U > INT_MAX)
 	return raw_type;
       else
-	return create_range_type (alloc_type (objfile), raw_type, 
+	return create_range_type (alloc_type (objfile, NULL), raw_type, 
 				  discrete_type_low_bound (raw_type),
 				  discrete_type_high_bound (raw_type));
     }
@@ -9612,7 +9613,7 @@ to_fixed_range_type (char *name, struct value *dval, struct objfile *objfile)
 
       if (objfile == NULL)
         objfile = TYPE_OBJFILE (base_type);
-      type = create_range_type (alloc_type (objfile), base_type, L, U);
+      type = create_range_type (alloc_type (objfile, NULL), base_type, L, U);
       TYPE_NAME (type) = name;
       return type;
     }
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 8697554..f561382 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -346,7 +346,7 @@ coff_alloc_type (int index)
      We will fill it in later if we find out how.  */
   if (type == NULL)
     {
-      type = alloc_type (current_objfile);
+      type = alloc_type (current_objfile, NULL);
       *type_addr = type;
     }
   return type;
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 39fe1c1..6af8a7c 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -3894,7 +3894,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
   /* The name is already allocated along with this objfile, so we don't
      need to duplicate it for the type.  */
   fnp->physname = physname ? physname : "";
-  fnp->type = alloc_type (objfile);
+  fnp->type = alloc_type (objfile, NULL);
   this_type = read_type_die (die, cu);
   if (this_type && TYPE_CODE (this_type) == TYPE_CODE_FUNC)
     {
@@ -4078,7 +4078,7 @@ quirk_gcc_member_function_pointer (struct die_info *die, struct dwarf2_cu *cu)
     return NULL;
 
   domain_type = TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (pfn_type, 0));
-  type = alloc_type (objfile);
+  type = alloc_type (objfile, NULL);
   smash_to_method_type (type, domain_type, TYPE_TARGET_TYPE (pfn_type),
 			TYPE_FIELDS (pfn_type), TYPE_NFIELDS (pfn_type),
 			TYPE_VARARGS (pfn_type));
@@ -4115,7 +4115,7 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
   if (type)
     return type;
 
-  type = alloc_type (objfile);
+  type = alloc_type (objfile, NULL);
   INIT_CPLUS_SPECIFIC (type);
   name = dwarf2_name (die, cu);
   if (name != NULL)
@@ -4328,7 +4328,7 @@ read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu)
   struct attribute *attr;
   const char *name;
 
-  type = alloc_type (objfile);
+  type = alloc_type (objfile, NULL);
 
   TYPE_CODE (type) = TYPE_CODE_ENUM;
   name = dwarf2_full_name (die, cu);
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index faba6e7..96a15f5 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -146,6 +146,23 @@ static void print_bit_vector (B_TYPE *, int);
 static void print_arg_types (struct field *, int, int);
 static void dump_fn_fieldlists (struct type *, int);
 static void print_cplus_stuff (struct type *, int);
+static void type_init_refc (struct type *new_type, struct type *parent_type);
+
+/* A reference count structure for the type reference count map.  Each
+   type in a hierarchy of types is mapped to the same reference
+   count.  */
+struct type_refc_entry
+{
+  /* One type in the hierarchy.  Each type in the hierarchy gets its
+     own slot.  */
+  struct type *type;
+
+  /* A pointer to the shared reference count.  */
+  int *refc;
+};
+
+/* The hash table holding all reference counts.  */
+static htab_t type_refc_table;
 
 
 /* Alloc a new type structure and fill it with some defaults.  If
@@ -154,7 +171,7 @@ static void print_cplus_stuff (struct type *, int);
    structure by xmalloc () (for permanent types).  */
 
 struct type *
-alloc_type (struct objfile *objfile)
+alloc_type (struct objfile *objfile, struct type *parent)
 {
   struct type *type;
 
@@ -184,6 +201,9 @@ alloc_type (struct objfile *objfile)
   TYPE_VPTR_FIELDNO (type) = -1;
   TYPE_CHAIN (type) = type;	/* Chain back to itself.  */
 
+  if (objfile == NULL)
+    type_init_refc (type, parent);
+
   return (type);
 }
 
@@ -213,6 +233,9 @@ alloc_type_instance (struct type *oldtype)
 
   TYPE_CHAIN (type) = type;	/* Chain back to itself for now.  */
 
+  if (TYPE_OBJFILE (oldtype) == NULL)
+    type_init_refc (type, oldtype);
+
   return (type);
 }
 
@@ -257,7 +280,7 @@ make_pointer_type (struct type *type, struct type **typeptr)
 
   if (typeptr == 0 || *typeptr == 0)	/* We'll need to allocate one.  */
     {
-      ntype = alloc_type (TYPE_OBJFILE (type));
+      ntype = alloc_type (TYPE_OBJFILE (type), type);
       if (typeptr)
 	*typeptr = ntype;
     }
@@ -269,6 +292,9 @@ make_pointer_type (struct type *type, struct type **typeptr)
       smash_type (ntype);
       TYPE_CHAIN (ntype) = chain;
       TYPE_OBJFILE (ntype) = objfile;
+
+      /* Callers may only supply storage if there is an objfile.  */
+      gdb_assert (objfile);
     }
 
   TYPE_TARGET_TYPE (ntype) = type;
@@ -337,7 +363,7 @@ make_reference_type (struct type *type, struct type **typeptr)
 
   if (typeptr == 0 || *typeptr == 0)	/* We'll need to allocate one.  */
     {
-      ntype = alloc_type (TYPE_OBJFILE (type));
+      ntype = alloc_type (TYPE_OBJFILE (type), type);
       if (typeptr)
 	*typeptr = ntype;
     }
@@ -349,6 +375,9 @@ make_reference_type (struct type *type, struct type **typeptr)
       smash_type (ntype);
       TYPE_CHAIN (ntype) = chain;
       TYPE_OBJFILE (ntype) = objfile;
+
+      /* Callers may only supply storage if there is an objfile.  */
+      gdb_assert (objfile);
     }
 
   TYPE_TARGET_TYPE (ntype) = type;
@@ -397,7 +426,7 @@ make_function_type (struct type *type, struct type **typeptr)
 
   if (typeptr == 0 || *typeptr == 0)	/* We'll need to allocate one.  */
     {
-      ntype = alloc_type (TYPE_OBJFILE (type));
+      ntype = alloc_type (TYPE_OBJFILE (type), type);
       if (typeptr)
 	*typeptr = ntype;
     }
@@ -407,6 +436,9 @@ make_function_type (struct type *type, struct type **typeptr)
       objfile = TYPE_OBJFILE (ntype);
       smash_type (ntype);
       TYPE_OBJFILE (ntype) = objfile;
+
+      /* Callers may only supply storage if there is an objfile.  */
+      gdb_assert (objfile);
     }
 
   TYPE_TARGET_TYPE (ntype) = type;
@@ -648,7 +680,7 @@ lookup_memberptr_type (struct type *type, struct type *domain)
 {
   struct type *mtype;
 
-  mtype = alloc_type (TYPE_OBJFILE (type));
+  mtype = alloc_type (TYPE_OBJFILE (type), NULL);
   smash_to_memberptr_type (mtype, domain, type);
   return (mtype);
 }
@@ -660,7 +692,7 @@ lookup_methodptr_type (struct type *to_type)
 {
   struct type *mtype;
 
-  mtype = alloc_type (TYPE_OBJFILE (to_type));
+  mtype = alloc_type (TYPE_OBJFILE (to_type), NULL);
   TYPE_TARGET_TYPE (mtype) = to_type;
   TYPE_DOMAIN_TYPE (mtype) = TYPE_DOMAIN_TYPE (to_type);
   TYPE_LENGTH (mtype) = cplus_method_ptr_size (to_type);
@@ -702,7 +734,7 @@ create_range_type (struct type *result_type, struct type *index_type,
 {
   if (result_type == NULL)
     {
-      result_type = alloc_type (TYPE_OBJFILE (index_type));
+      result_type = alloc_type (TYPE_OBJFILE (index_type), index_type);
     }
   TYPE_CODE (result_type) = TYPE_CODE_RANGE;
   TYPE_TARGET_TYPE (result_type) = index_type;
@@ -812,8 +844,14 @@ create_array_type (struct type *result_type,
 
   if (result_type == NULL)
     {
-      result_type = alloc_type (TYPE_OBJFILE (range_type));
+      result_type = alloc_type (TYPE_OBJFILE (range_type), element_type);
     }
+  else
+    {
+      /* Callers may only supply storage if there is an objfile.  */
+      gdb_assert (TYPE_OBJFILE (result_type));
+    }
+
   TYPE_CODE (result_type) = TYPE_CODE_ARRAY;
   TYPE_TARGET_TYPE (result_type) = element_type;
   if (get_discrete_bounds (range_type, &low_bound, &high_bound) < 0)
@@ -831,6 +869,7 @@ create_array_type (struct type *result_type,
   TYPE_FIELDS (result_type) =
     (struct field *) TYPE_ALLOC (result_type, sizeof (struct field));
   memset (TYPE_FIELDS (result_type), 0, sizeof (struct field));
+  /* FIXME: type alloc.  */
   TYPE_FIELD_TYPE (result_type, 0) = range_type;
   TYPE_VPTR_FIELDNO (result_type) = -1;
 
@@ -873,7 +912,12 @@ create_set_type (struct type *result_type, struct type *domain_type)
 {
   if (result_type == NULL)
     {
-      result_type = alloc_type (TYPE_OBJFILE (domain_type));
+      result_type = alloc_type (TYPE_OBJFILE (domain_type), domain_type);
+    }
+  else
+    {
+      /* Callers may only supply storage if there is an objfile.  */
+      gdb_assert (TYPE_OBJFILE (result_type));
     }
   TYPE_CODE (result_type) = TYPE_CODE_SET;
   TYPE_NFIELDS (result_type) = 1;
@@ -1432,7 +1476,7 @@ check_typedef (struct type *type)
 	  if (sym)
 	    TYPE_TARGET_TYPE (type) = SYMBOL_TYPE (sym);
 	  else					/* TYPE_CODE_UNDEF */
-	    TYPE_TARGET_TYPE (type) = alloc_type (NULL);
+	    TYPE_TARGET_TYPE (type) = alloc_type (NULL, NULL);
 	}
       type = TYPE_TARGET_TYPE (type);
     }
@@ -1765,7 +1809,7 @@ init_type (enum type_code code, int length, int flags,
 {
   struct type *type;
 
-  type = alloc_type (objfile);
+  type = alloc_type (objfile, NULL);
   TYPE_CODE (type) = code;
   TYPE_LENGTH (type) = length;
 
@@ -1800,9 +1844,9 @@ init_type (enum type_code code, int length, int flags,
       TYPE_NAME (type) = obsavestring (name, strlen (name), 
 				       &objfile->objfile_obstack);
     }
-  else
+  else if (name)
     {
-      TYPE_NAME (type) = name;
+      TYPE_NAME (type) = xstrdup (name);
     }
 
   /* C++ fancies.  */
@@ -1815,6 +1859,10 @@ init_type (enum type_code code, int length, int flags,
     {
       INIT_CPLUS_SPECIFIC (type);
     }
+
+  if (!objfile)
+    type_incref (type);
+
   return (type);
 }
 
@@ -2922,15 +2970,17 @@ create_copied_types_hash (struct objfile *objfile)
 			       dummy_obstack_deallocate);
 }
 
-/* Recursively copy (deep copy) TYPE, if it is associated with
-   OBJFILE.  Return a new type allocated using malloc, a saved type if
-   we have already visited TYPE (using COPIED_TYPES), or TYPE if it is
-   not associated with OBJFILE.  */
+/* A helper for copy_type_recursive.  This does all the work.
+   REPRESENTATIVE is a pointer to a type.  This is used to register
+   newly-created types in the type_refc_table.  Initially it pointer
+   to a NULL pointer, but it is filled in the first time a type is
+   copied.  */
 
-struct type *
-copy_type_recursive (struct objfile *objfile, 
-		     struct type *type,
-		     htab_t copied_types)
+static struct type *
+copy_type_recursive_1 (struct objfile *objfile, 
+		       struct type *type,
+		       htab_t copied_types,
+		       struct type **representative)
 {
   struct type_pair *stored, pair;
   void **slot;
@@ -2948,7 +2998,9 @@ copy_type_recursive (struct objfile *objfile,
   if (*slot != NULL)
     return ((struct type_pair *) *slot)->new;
 
-  new_type = alloc_type (NULL);
+  new_type = alloc_type (NULL, *representative);
+  if (!*representative)
+    *representative = new_type;
 
   /* We must add the new type to the hash table immediately, in case
      we encounter this type again during a recursive call below.  */
@@ -2985,8 +3037,8 @@ copy_type_recursive (struct objfile *objfile,
 	  TYPE_FIELD_BITSIZE (new_type, i) = TYPE_FIELD_BITSIZE (type, i);
 	  if (TYPE_FIELD_TYPE (type, i))
 	    TYPE_FIELD_TYPE (new_type, i)
-	      = copy_type_recursive (objfile, TYPE_FIELD_TYPE (type, i),
-				     copied_types);
+	      = copy_type_recursive_1 (objfile, TYPE_FIELD_TYPE (type, i),
+				       copied_types, representative);
 	  if (TYPE_FIELD_NAME (type, i))
 	    TYPE_FIELD_NAME (new_type, i) = 
 	      xstrdup (TYPE_FIELD_NAME (type, i));
@@ -3016,14 +3068,16 @@ copy_type_recursive (struct objfile *objfile,
   /* Copy pointers to other types.  */
   if (TYPE_TARGET_TYPE (type))
     TYPE_TARGET_TYPE (new_type) = 
-      copy_type_recursive (objfile, 
-			   TYPE_TARGET_TYPE (type),
-			   copied_types);
+      copy_type_recursive_1 (objfile, 
+			     TYPE_TARGET_TYPE (type),
+			     copied_types,
+			     representative);
   if (TYPE_VPTR_BASETYPE (type))
     TYPE_VPTR_BASETYPE (new_type) = 
-      copy_type_recursive (objfile,
-			   TYPE_VPTR_BASETYPE (type),
-			   copied_types);
+      copy_type_recursive_1 (objfile,
+			     TYPE_VPTR_BASETYPE (type),
+			     copied_types,
+			     representative);
   /* Maybe copy the type_specific bits.
 
      NOTE drow/2005-12-09: We do not copy the C++-specific bits like
@@ -3041,6 +3095,21 @@ copy_type_recursive (struct objfile *objfile,
   return new_type;
 }
 
+/* Recursively copy (deep copy) TYPE, if it is associated with
+   OBJFILE.  Return a new type allocated using malloc, a saved type if
+   we have already visited TYPE (using COPIED_TYPES), or TYPE if it is
+   not associated with OBJFILE.  */
+
+struct type *
+copy_type_recursive (struct objfile *objfile, 
+		     struct type *type,
+		     htab_t copied_types)
+{
+  struct type *representative = NULL;
+
+  return copy_type_recursive_1 (objfile, type, copied_types, &representative);
+}
+
 /* Make a copy of the given TYPE, except that the pointer & reference
    types are not preserved.
    
@@ -3054,7 +3123,7 @@ copy_type (const struct type *type)
 
   gdb_assert (TYPE_OBJFILE (type) != NULL);
 
-  new_type = alloc_type (TYPE_OBJFILE (type));
+  new_type = alloc_type (TYPE_OBJFILE (type), NULL);
   TYPE_INSTANCE_FLAGS (new_type) = TYPE_INSTANCE_FLAGS (type);
   TYPE_LENGTH (new_type) = TYPE_LENGTH (type);
   memcpy (TYPE_MAIN_TYPE (new_type), TYPE_MAIN_TYPE (type),
@@ -3065,12 +3134,14 @@ copy_type (const struct type *type)
 
 /* Allocate a hash table which is used when freeing a struct type.  */
 
-htab_t
+static htab_t
 create_deleted_types_hash (void)
 {
   return htab_create (1, htab_hash_pointer, htab_eq_pointer, NULL);
 }
 
+static void delete_type_recursive (struct type *type, htab_t deleted_types);
+
 /* A helper for delete_type_recursive which deletes a main_type and
    the things to which it refers.  TYPE is a type whose main_type we
    wish to destroy.  DELETED_TYPES is a hash holding already-seen
@@ -3121,7 +3192,7 @@ delete_main_type (struct type *type, htab_t deleted_types)
    create_deleted_types_hash, which is used for checking whether a
    type has already been deleted.  */
 
-void
+static void
 delete_type_recursive (struct type *type, htab_t deleted_types)
 {
   void **slot;
@@ -3147,6 +3218,132 @@ delete_type_recursive (struct type *type, htab_t deleted_types)
   xfree (type);
 }
 
+/* Hash function for type_refc_table.  */
+
+static hashval_t
+type_refc_hash (const void *p)
+{
+  const struct type_refc_entry *entry = p;
+  return htab_hash_pointer (entry->type);
+}
+
+/* Equality function for type_refc_table.  */
+
+static int
+type_refc_equal (const void *a, const void *b)
+{
+  const struct type_refc_entry *left = a;
+  const struct type_refc_entry *right = b;
+  return left->type == right->type;
+}
+
+/* Insert the new type NEW_TYPE into the table.  Does nothing if
+   NEW_TYPE has an objfile.  If PARENT_TYPE is not NULL, then NEW_TYPE
+   will be inserted into the same hierarchy as PARENT_TYPE.  In this
+   case, PARENT_TYPE must already exist in the reference count map.
+   If PARENT_TYPE is NULL, a new reference count is allocated and set
+   to one.  */
+
+static void
+type_init_refc (struct type *new_type, struct type *parent_type)
+{
+  int *refc;
+  void **slot;
+  struct type_refc_entry *new_entry;
+
+  if (TYPE_OBJFILE (new_type))
+    return;
+
+  if (parent_type)
+    {
+      struct type_refc_entry entry, *found;
+      entry.type = parent_type;
+      found = htab_find (type_refc_table, &entry);
+      gdb_assert (found);
+      refc = found->refc;
+    }
+  else
+    {
+      refc = xmalloc (sizeof (int));
+      *refc = 0;
+    }
+
+  new_entry = XNEW (struct type_refc_entry);
+  new_entry->type = new_type;
+  new_entry->refc = refc;
+
+  slot = htab_find_slot (type_refc_table, new_entry, INSERT);
+  gdb_assert (!*slot);
+  *slot = new_entry;
+}
+
+/* Increment the reference count for TYPE.  */
+
+void
+type_incref (struct type *type)
+{
+  struct type_refc_entry entry, *found;
+
+  if (TYPE_OBJFILE (type))
+    return;
+
+  entry.type = type;
+  found = htab_find (type_refc_table, &entry);
+  gdb_assert (found);
+  ++*(found->refc);
+}
+
+/* A traverse callback for type_refc_table which removes any entry
+   whose reference count pointer is REFC.  */
+
+static int
+type_refc_remove (void **slot, void *refc)
+{
+  struct type_refc_entry *entry = *slot;
+
+  if (entry->refc == refc)
+    {
+      xfree (entry);
+      htab_clear_slot (type_refc_table, slot);
+    }
+
+  return 1;
+}
+
+/* Decrement the reference count for TYPE.  If TYPE has no more
+   references, delete it.  */
+
+void
+type_decref (struct type *type)
+{
+  struct type_refc_entry entry, *found;
+
+  if (TYPE_OBJFILE (type))
+    return;
+
+  entry.type = type;
+  found = htab_find (type_refc_table, &entry);
+  gdb_assert (found);
+  --*(found->refc);
+  if (*(found->refc) == 0)
+    {
+      htab_t deleted;
+      void *refc = found->refc;
+      struct type *representative = found->type;
+
+      /* Clear all table entries referring to this count.  */
+      htab_traverse (type_refc_table, type_refc_remove, refc);
+
+      /* Delete the reference count itself.  */
+      xfree (refc);
+      
+      /* Delete the entire type hierarchy.  */
+      deleted = create_deleted_types_hash ();
+      delete_type_recursive (representative, deleted);
+      htab_delete (deleted);
+    }
+}
+
 static struct type *
 build_flt (int bit, char *name, const struct floatformat **floatformats)
 {
@@ -3355,6 +3552,9 @@ _initialize_gdbtypes (void)
 {
   gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init);
 
+  type_refc_table = htab_create_alloc (20, type_refc_hash, type_refc_equal,
+				       NULL, xcalloc, xfree);
+
   /* FIXME: The following types are architecture-neutral.  However,
      they contain pointer_type and reference_type fields potentially
      caching pointer or reference types that *are* architecture
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index c2d70fd..2a2e93e 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1101,7 +1101,7 @@ extern struct type *builtin_type_error;
 	      0, size)  \
     : xzalloc (size))
 
-extern struct type *alloc_type (struct objfile *);
+extern struct type *alloc_type (struct objfile *, struct type *);
 
 extern struct type *init_type (enum type_code, int, int, char *,
 			       struct objfile *);
@@ -1268,8 +1268,8 @@ extern struct type *copy_type_recursive (struct objfile *objfile,
 
 extern struct type *copy_type (const struct type *type);
 
-extern htab_t create_deleted_types_hash (void);
+extern void type_incref (struct type *type);
 
-extern void delete_type_recursive (struct type *type, htab_t copied_types);
+extern void type_decref (struct type *type);
 
 #endif /* GDBTYPES_H */
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 11cd321..83049b0 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -301,7 +301,7 @@ type_from_class (struct value *clas)
   if (type != NULL)
     return type;
 
-  type = alloc_type (objfile);
+  type = alloc_type (objfile, NULL);
   TYPE_CODE (type) = TYPE_CODE_STRUCT;
   INIT_CPLUS_SPECIFIC (type);
 
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index 3fa06e5..edc6ac0 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -4696,7 +4696,7 @@ new_type (char *name)
 {
   struct type *t;
 
-  t = alloc_type (current_objfile);
+  t = alloc_type (current_objfile, NULL);
   TYPE_NAME (t) = name;
   TYPE_CPLUS_SPECIFIC (t) = (struct cplus_struct_type *) &cplus_struct_default;
   return t;
diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c
index 0df5252..409a71d 100644
--- a/gdb/python/python-type.c
+++ b/gdb/python/python-type.c
@@ -495,10 +495,11 @@ clean_up_objfile_types (struct objfile *objfile, void *datum)
       type_object *next = obj->next;
 
       htab_empty (copied_types);
-      /* Note that we leak this memory.  There is no good way to
-	 handle freeing this, given things like Value.cast and other
-	 unconstrained operations on values.  */
+
+      /* No need to decref the old type here, since we know it has no
+	 reference count.  */
       obj->type = copy_type_recursive (objfile, obj->type, copied_types);
+      type_incref (obj->type);
 
       obj->next = NULL;
       obj->prev = NULL;
@@ -515,6 +516,7 @@ static void
 set_type (type_object *obj, struct type *type)
 {
   obj->type = type;
+  type_incref (type);
   obj->prev = NULL;
   if (type && TYPE_OBJFILE (type))
     {
@@ -575,6 +577,9 @@ typy_dealloc (PyObject *obj)
 {
   type_object *type = (type_object *) obj;
 
+  if (type->type)
+    type_decref (type->type);
+
   if (type->prev)
     type->prev->next = type->next;
   else if (type->type && TYPE_OBJFILE (type->type))
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index 16f589e..0f45398 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -322,7 +322,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile)
 
   if (typenums[0] == -1)
     {
-      return (alloc_type (objfile));
+      return (alloc_type (objfile, NULL));
     }
 
   type_addr = dbx_lookup_type (typenums);
@@ -332,7 +332,7 @@ dbx_alloc_type (int typenums[2], struct objfile *objfile)
      We will fill it in later if we find out how.  */
   if (*type_addr == 0)
     {
-      *type_addr = alloc_type (objfile);
+      *type_addr = alloc_type (objfile, NULL);
     }
 
   return (*type_addr);
diff --git a/gdb/valops.c b/gdb/valops.c
index a53a5d1..19b9a97 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -370,8 +370,6 @@ value_cast (struct type *type, struct value *arg2)
 	  new_length = val_length / element_length;
 	  if (val_length % element_length != 0)
 	    warning (_("array element type size does not divide object size in cast"));
-	  /* FIXME-type-allocation: need a way to free this type when
-	     we are done with it.  */
 	  range_type = create_range_type ((struct type *) NULL,
 					  TYPE_TARGET_TYPE (range_type),
 					  low_bound,
@@ -2917,8 +2915,6 @@ value_slice (struct value *array, int lowbound, int length)
       || lowbound + length - 1 > upperbound)
     error (_("slice out of range"));
 
-  /* FIXME-type-allocation: need a way to free this type when we are
-     done with it.  */
   slice_range_type = create_range_type ((struct type *) NULL,
 					TYPE_TARGET_TYPE (range_type),
 					lowbound, 
diff --git a/gdb/value.c b/gdb/value.c
index f49d651..d5b047f 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -251,7 +251,9 @@ allocate_value (struct type *type)
   val->next = all_values;
   all_values = val;
   val->type = type;
+  type_incref (type);
   val->enclosing_type = type;
+  type_incref (type);
   VALUE_LVAL (val) = not_lval;
   val->location.address = 0;
   VALUE_FRAME_ID (val) = null_frame_id;
@@ -273,6 +275,8 @@ allocate_value (struct type *type)
 void
 value_free (struct value *value)
 {
+  type_decref (value->type);
+  type_decref (value->enclosing_type);
   xfree (value);
 }
 
@@ -283,13 +287,9 @@ struct value *
 allocate_repeat_value (struct type *type, int count)
 {
   int low_bound = current_language->string_lower_bound;		/* ??? */
-  /* FIXME-type-allocation: need a way to free this type when we are
-     done with it.  */
   struct type *range_type
   = create_range_type ((struct type *) NULL, builtin_type_int32,
 		       low_bound, count + low_bound - 1);
-  /* FIXME-type-allocation: need a way to free this type when we are
-     done with it.  */
   return allocate_value (create_array_type ((struct type *) NULL,
 					    type, range_type));
 }
@@ -335,6 +335,8 @@ value_type (struct value *value)
 void
 deprecated_set_value_type (struct value *value, struct type *type)
 {
+  type_incref (type);
+  type_decref (value->type);
   value->type = type;
 }
 
@@ -634,6 +636,10 @@ value_copy (struct value *arg)
 {
   struct type *encl_type = value_enclosing_type (arg);
   struct value *val = allocate_value (encl_type);
+  struct type *old = val->type;
+
+  type_incref (arg->type);
+  type_decref (val->type);
   val->type = arg->type;
   VALUE_LVAL (val) = VALUE_LVAL (arg);
   val->location = arg->location;
@@ -1059,12 +1065,22 @@ preserve_one_value (struct value *value, struct objfile *objfile,
 		    htab_t copied_types)
 {
   if (TYPE_OBJFILE (value->type) == objfile)
-    value->type = copy_type_recursive (objfile, value->type, copied_types);
+    {
+      /* No need to decref the old type here, since we know it has no
+	 reference count.  */
+      value->type = copy_type_recursive (objfile, value->type, copied_types);
+      type_incref (value->type);
+    }
 
   if (TYPE_OBJFILE (value->enclosing_type) == objfile)
-    value->enclosing_type = copy_type_recursive (objfile,
-						 value->enclosing_type,
-						 copied_types);
+    {
+      /* No need to decref the old type here, since we know it has no
+	 reference count.  */
+      value->enclosing_type = copy_type_recursive (objfile,
+						   value->enclosing_type,
+						   copied_types);
+      type_incref (value->enclosing_type);
+    }
 }
 
 /* Update the internal variables and value history when OBJFILE is
@@ -1452,6 +1468,8 @@ value_static_field (struct type *type, int fieldno)
 struct value *
 value_change_enclosing_type (struct value *val, struct type *new_encl_type)
 {
+  type_incref (new_encl_type);
+  type_decref (val->enclosing_type);
   if (TYPE_LENGTH (new_encl_type) <= TYPE_LENGTH (value_enclosing_type (val))) 
     {
       val->enclosing_type = new_encl_type;
@@ -1522,6 +1540,8 @@ value_primitive_field (struct value *arg1, int offset,
          entire object's contents for later references to virtual
          bases, etc.  */
       v = allocate_value (value_enclosing_type (arg1));
+      type_incref (type);
+      type_decref (v->type);
       v->type = type;
 
       /* Lazy register values with offsets are not supported.  */
@@ -1968,7 +1988,7 @@ VARIABLE is already initialized."));
 Placeholder command for showing help on convenience functions."),
 		  &functionlist, "function ", 0, &cmdlist);
 
-  internal_fn_type = alloc_type (NULL);
+  internal_fn_type = alloc_type (NULL, NULL);
   TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION;
   TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *);
   TYPE_NAME (internal_fn_type) = "<internal function>";


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]