[patch] [1/5] Types reference counting [base]
Jan Kratochvil
jan.kratochvil@redhat.com
Sat Apr 11 10:21:00 GMT 2009
Hi,
a base implementation of types reference counting.
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 anchor `Builtin Types'. Move
types `from Memory Management for Symbol Files' to a new subsection
`Memory Management for Types'.
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..ea8696c 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -2320,6 +2320,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
@@ -2523,10 +2524,39 @@ 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.
+@subsection Memory Management for Types
+
+@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 reclaimable types.
+
+Types with @code{NULL TYPE_OBJFILE} can be either permanent types
+(@pxref{Builtin Types}) or reclaimable types which will be deallocated after 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.
+
+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
More information about the Gdb-patches
mailing list