This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB 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]

Re: [patch] [1/5] Types reference counting [base]


Hi Eli,

included an updated patch, only the doc part is updated.


On Sat, 11 Apr 2009 13:24:56 +0200, Eli Zaretskii wrote:
> > +(@pxref{Builtin Types}) or reclaimable types which will be deallocated after the
> > +last object referencing them is removed.
> 
> But the text below says that actually they will be deallocated only
> when GDB becomes idle, right?

You are right, now it reads:

Types with null @code{TYPE_OBJFILE} can be either permanent types
(@pxref{Builtin Types}) or reclaimable types which will be deallocated at the 
first idle @value{GDBN} moment if the last object referencing them is removed.


> > +as through @code{TYPE_TARGET_TYPE}, @code{TYPE_POINTER_TYPE} etc. and prevents
>                                                                    ^^
> Please add either a @: or a comma after any period that doesn't end a
> sentence, so that TeX would not typeset that as a sentence end.

Done, BTW do you know some way how to generate .tex (not .dvi or .pdf) from
.texinfo?


Thanks,
Jan


gdb/
2009-04-11  Tom Tromey  <tromey@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>

	Start reference counting standalone allocated types.
	* gdbtypes.c (struct type_group, struct type_group_link)
	(type_group_link_table, type_group_age, alloc_type_discardable)
	(alloc_type_as_parent): New.
	(make_pointer_type, make_reference_type): Change alloc_type for
	alloc_type_as_parent.
	(copy_type_recursive): Change alloc_type for alloc_type_discardable.
	(type_group_link_hash, type_group_link_equal, type_init_group)
	(type_incref, type_decref): New.
	(_initialize_gdbtypes): Initialize `type_group_link_table'.
	* gdbtypes.h (type_incref, type_decref): New prototypes.
	* value.c (allocate_value_lazy, deprecated_set_value_type, value_free)
	(value_copy, preserve_one_value, value_static_field)
	(value_primitive_field): Call type_incref and type_decref appropriately.

gdb/doc/
2009-04-11  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdbint.texinfo (Symbol Handling): New menu.
	(Partial Symbol Tables, Object File Formats, Debugging File Formats)
	(Adding a New Symbol Reader to GDB): New nodes from existing sections.
	(Types): New node from existing section.  New anchor `Builtin Types'.
	(Memory Management for Symbol Files): New node from existing section.
	Move types to ...
	(Memory Management for Types): ... here, in a new node.

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index fb52e1a..c866353 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -146,7 +146,56 @@ 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_group (struct type *type);
 
+/* Any type structures which are connected through their `struct type *' are
+   tracked by the same type_group.  Only the discardable (neither permanent
+   types nor types allocated from objfile obstack) type structures get tracked
+   by type_group structures.  */
+
+struct type_group
+{
+  /* Sum of all the external references to any of the type structures tracked
+     by this type_group.  */
+  int use_count;
+
+  /* Number of the type_group_links structures tracked by this type_group.  It
+     matches the length of list `link_list->group_next->...->group_next'.  */
+  int link_count;
+
+  /* Head of an unordered list of all type structures of this type_group.  Next
+     items are linked by `type_group_link->group_next'.  */
+  struct type_group_link *link_list;
+};
+
+/* Linking entry between a type structure and type_group structure.  Only
+   discardable types have such link present.  This link exists only once for
+   each discardable main_type, all type instances for such one main_type should
+   be iterated by `TYPE_CHAIN (type_group_link->type)'.  */
+
+struct type_group_link
+{
+  /* Arbitrary type for main_type being represented by this type_group_link.
+     Each discardable main_type gets its separate type_group_link.  */
+  struct type *type;
+
+  /* Marker this type_group_link has been visited by the type_group_link_check
+     graph traversal by this pass.  Current pass is represented by
+     TYPE_GROUP_AGE.  */
+  unsigned age : 1;
+
+  struct type_group *group;
+
+  /* Next type_group_link belonging to this type_group structure or NULL for
+     the last node of the list.  */
+  struct type_group_link *group_next;
+};
+
+/* The hash table holding all `struct type_group_link *' references.  */
+static htab_t type_group_link_table;
+
+/* Current type_group_link_check pass used for `type_group_link->age'.  */
+static unsigned type_group_age;
 
 /* Alloc a new type structure and fill it with some defaults.  If
    OBJFILE is non-NULL, then allocate the space for the type structure
@@ -183,6 +232,43 @@ alloc_type (struct objfile *objfile)
   return type;
 }
 
+/* Allocate a new type by an alloc_type call but make the new type discardable
+   on next garbage collection by free_all_types.  Use type_incref for reference
+   counting of such new type.  */
+
+static struct type *
+alloc_type_discardable (void)
+{
+  struct type *type = alloc_type (NULL);
+
+  type_init_group (type);
+
+  return type;
+}
+
+/* Allocate a new type like alloc_type or alloc_type_discardable copying the
+   discardability state of PARENT_TYPE (its current reference count
+   notwithstanding).  */
+
+static struct type *
+alloc_type_as_parent (struct type *parent_type)
+{
+  struct type *type = alloc_type (TYPE_OBJFILE (parent_type));
+
+  if (TYPE_OBJFILE (parent_type) == NULL)
+    {
+      struct type_group_link link, *found;
+
+      link.type = type;
+      found = htab_find (type_group_link_table, &link);
+      /* Not a permanent type?  */
+      if (found)
+	type_init_group (type);
+    }
+
+  return type;
+}
+
 /* Alloc a new type instance structure, fill it with some defaults,
    and point it at OLDTYPE.  Allocate the new type instance from the
    same place as OLDTYPE.  */
@@ -248,7 +334,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_as_parent (type);
       if (typeptr)
 	*typeptr = ntype;
     }
@@ -328,7 +414,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_as_parent (type);
       if (typeptr)
 	*typeptr = ntype;
     }
@@ -2954,7 +3040,7 @@ copy_type_recursive (struct objfile *objfile,
   if (*slot != NULL)
     return ((struct type_pair *) *slot)->new;
 
-  new_type = alloc_type (NULL);
+  new_type = alloc_type_discardable ();
 
   /* We must add the new type to the hash table immediately, in case
      we encounter this type again during a recursive call below.  */
@@ -3068,6 +3154,102 @@ copy_type (const struct type *type)
   return new_type;
 }
 
+/* Hash function for type_group_link_table.  */
+
+static hashval_t
+type_group_link_hash (const void *p)
+{
+  const struct type_group_link *link = p;
+
+  return htab_hash_pointer (TYPE_MAIN_TYPE (link->type));
+}
+
+/* Equality function for type_group_link_table.  */
+
+static int
+type_group_link_equal (const void *a, const void *b)
+{
+  const struct type_group_link *left = a;
+  const struct type_group_link *right = b;
+
+  return TYPE_MAIN_TYPE (left->type) == TYPE_MAIN_TYPE (right->type);
+}
+
+/* Define currently permanent TYPE as being reclaimable during free_all_types.
+   TYPE is required to be now permanent.  TYPE will be left with zero reference
+   count, early type_incref call is probably appropriate.  */
+
+static void
+type_init_group (struct type *type)
+{
+  void **slot;
+  struct type_group *group;
+  struct type_group_link *link;
+
+  gdb_assert (TYPE_OBJFILE (type) == NULL);
+
+  group = XNEW (struct type_group);
+  link = XNEW (struct type_group_link);
+
+  group->use_count = 0;
+  group->link_count = 1;
+  group->link_list = link;
+
+  link->type = type;
+  link->age = type_group_age;
+  link->group = group;
+  link->group_next = NULL;
+
+  slot = htab_find_slot (type_group_link_table, link, INSERT);
+  gdb_assert (!*slot);
+  *slot = link;
+}
+
+/* Increment the reference count for TYPE.  For permanent or objfile associated
+   types nothing happens.  */
+
+void
+type_incref (struct type *type)
+{
+  struct type_group_link link, *found;
+
+  if (TYPE_OBJFILE (type))
+    return;
+
+  link.type = type;
+  found = htab_find (type_group_link_table, &link);
+  /* A permanent type?  */
+  if (!found)
+    return;
+
+  found->group->use_count++;
+}
+
+/* Decrement the reference count for TYPE.  For permanent or objfile associated
+   types nothing happens.  
+
+   Even if TYPE has no more references still do not delete it as callers may
+   hold pointers to types dynamically generated by check_typedef.  Always rely
+   just on the free_all_types garbage collector.  */
+
+void
+type_decref (struct type *type)
+{
+  struct type_group_link link, *found;
+
+  if (TYPE_OBJFILE (type))
+    return;
+
+  link.type = type;
+  found = htab_find (type_group_link_table, &link);
+  /* A permanent type?  */
+  if (!found)
+    return;
+
+  gdb_assert (found->group->use_count > 0);
+  found->group->use_count--;
+}
+
 static struct type *
 build_flt (int bit, char *name, const struct floatformat **floatformats)
 {
@@ -3276,6 +3458,10 @@ _initialize_gdbtypes (void)
 {
   gdbtypes_data = gdbarch_data_register_post_init (gdbtypes_post_init);
 
+  type_group_link_table = htab_create_alloc (20, type_group_link_hash,
+					     type_group_link_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 3c4e948..41cd7a3 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1275,4 +1275,8 @@ extern struct type *copy_type_recursive (struct objfile *objfile,
 
 extern struct type *copy_type (const struct type *type);
 
+extern void type_incref (struct type *type);
+
+extern void type_decref (struct type *type);
+
 #endif /* GDBTYPES_H */
diff --git a/gdb/value.c b/gdb/value.c
index 9c08a41..38b4f91 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -247,7 +247,9 @@ allocate_value_lazy (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;
   VALUE_ADDRESS (val) = 0;
   VALUE_FRAME_ID (val) = null_frame_id;
@@ -357,6 +359,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;
 }
 
@@ -574,6 +578,9 @@ value_free (struct value *val)
 {
   if (val)
     {
+      type_decref (val->type);
+      type_decref (val->enclosing_type);
+
       if (VALUE_LVAL (val) == lval_computed)
 	{
 	  struct lval_funcs *funcs = val->location.computed.funcs;
@@ -677,6 +684,8 @@ value_copy (struct value *arg)
     val = allocate_value_lazy (encl_type);
   else
     val = allocate_value (encl_type);
+  type_incref (arg->type);
+  type_decref (val->type);
   val->type = arg->type;
   VALUE_LVAL (val) = VALUE_LVAL (arg);
   val->location = arg->location;
@@ -1163,12 +1172,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
@@ -1557,6 +1576,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->contents =
       (gdb_byte *) xrealloc (val->contents, TYPE_LENGTH (new_encl_type));
@@ -1612,6 +1633,8 @@ value_primitive_field (struct value *arg1, int offset,
 	  memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1),
 		  TYPE_LENGTH (value_enclosing_type (arg1)));
 	}
+      type_incref (type);
+      type_decref (v->type);
       v->type = type;
       v->offset = value_offset (arg1);
       v->embedded_offset = (offset + value_embedded_offset (arg1)
diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo
index 187da2f..e937663 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -2111,6 +2111,18 @@ time, and so we attempt to handle symbols incrementally.  For instance,
 we create @dfn{partial symbol tables} consisting of only selected
 symbols, and only expand them to full symbol tables when necessary.
 
+@menu
+* Symbol Reading::
+* Partial Symbol Tables::
+* Types::
+* Object File Formats::
+* Debugging File Formats::
+* Adding a New Symbol Reader to GDB::
+* Memory Management for Symbol Files::
+* Memory Management for Types::
+@end menu
+
+@node Symbol Reading
 @section Symbol Reading
 
 @cindex symbol reading
@@ -2203,6 +2215,7 @@ symtab.  Upon return, @code{pst->readin} should have been set to 1, and
 zero if there were no symbols in that part of the symbol file.
 @end table
 
+@node Partial Symbol Tables
 @section Partial Symbol Tables
 
 @value{GDBN} has three types of symbol tables:
@@ -2298,6 +2311,7 @@ and all the psymbols themselves are allocated in a pair of large arrays
 on an obstack, so there is little to be gained by trying to free them
 unless you want to do a lot more work.
 
+@node Types
 @section Types
 
 @unnumberedsubsec Fundamental Types (e.g., @code{FT_VOID}, @code{FT_BOOLEAN}).
@@ -2320,6 +2334,7 @@ types map to one @code{TYPE_CODE_*} type, and are distinguished by
 other members of the type struct, such as whether the type is signed
 or unsigned, and how many bits it uses.
 
+@anchor{Builtin Types}
 @unnumberedsubsec Builtin Types (e.g., @code{builtin_type_void}, @code{builtin_type_char}).
 
 These are instances of type structs that roughly correspond to
@@ -2334,6 +2349,7 @@ only one instance exists, while @file{c-lang.c} builds as many
 @code{TYPE_CODE_INT} types as needed, with each one associated with
 some particular objfile.
 
+@node Object File Formats
 @section Object File Formats
 @cindex object file formats
 
@@ -2419,6 +2435,7 @@ SOM, which is a cross-language ABI).
 
 The SOM reader is in @file{somread.c}.
 
+@node Debugging File Formats
 @section Debugging File Formats
 
 This section describes characteristics of debugging information that
@@ -2490,6 +2507,7 @@ DWARF 3 is an improved version of DWARF 2.
 @cindex SOM debugging info
 Like COFF, the SOM definition includes debugging information.
 
+@node Adding a New Symbol Reader to GDB
 @section Adding a New Symbol Reader to @value{GDBN}
 
 @cindex adding debugging info reader
@@ -2512,6 +2530,7 @@ will only ever be implemented by one object file format may be called
 directly.  This interface should be described in a file
 @file{bfd/lib@var{xyz}.h}, which is included by @value{GDBN}.
 
+@node Memory Management for Symbol Files
 @section Memory Management for Symbol Files
 
 Most memory associated with a loaded symbol file is stored on
@@ -2523,10 +2542,46 @@ released when the objfile is unloaded or reloaded.  Therefore one
 objfile must not reference symbol or type data from another objfile;
 they could be unloaded at different times.
 
-User convenience variables, et cetera, have associated types.  Normally
-these types live in the associated objfile.  However, when the objfile
-is unloaded, those types are deep copied to global memory, so that
-the values of the user variables and history items are not lost.
+@node Memory Management for Types
+@section Memory Management for Types
+@cindex memory management for types
+
+@findex TYPE_OBJFILE
+@code{TYPE_OBJFILE} macro indicates the current memory owner of the type.
+Non-@code{NULL} value indicates it is owned by an objfile (specifically by its
+obstack) and in such case the type remains valid till the objfile is unloaded
+or reloaded.  For such types with an associated objfile no reference counting
+is being made.
+
+User convenience variables, et cetera, have associated types.  Normally these
+types live in the associated objfile.  However, when the objfile is unloaded,
+those types are deep copied to global memory, so that the values of the user
+variables and history items are not lost.  During the copy they will get their
+@code{TYPE_OBJFILE} set to @code{NULL} and become so-called @dfn{reclaimable}
+types.
+
+Types with null @code{TYPE_OBJFILE} can be either permanent types
+(@pxref{Builtin Types}) or reclaimable types which will be deallocated at the
+first idle @value{GDBN} moment if the last object referencing them is removed.
+Permanent types are allocated by the function @code{alloc_type} (and its
+derivations like @code{init_type}) specifying objfile as @code{NULL}.  The
+reclaimable types are created the same way but moreover they need to have
+@code{type_init_group} called to start their tracking as being possibly
+deallocatable.
+
+@findex free_all_types
+When @value{GDBN} gets idle it always calls the @code{free_all_types} function
+which deallocates any unused types.  To prevent deallocation of types still in
+use you must use @code{type_incref} (and matching @code{type_decref}) for
+reference counting of any reclaimable type.  You will probably need to first
+increase the reference count right after calling @code{type_init_group}.
+
+@code{free_all_types} automatically checks for any cross-type references such
+as through @code{TYPE_TARGET_TYPE}, @code{TYPE_POINTER_TYPE} etc.@: and
+prevents early deallocation for any such existing references.  Reclaimable
+types may reference any other reclaimable types or even permanent types.  But
+permanent types must not reference reclaimable types (nor an objfile associated
+type).
 
 
 @node Language Support


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