From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31998 invoked by alias); 11 Apr 2009 18:15:41 -0000 Received: (qmail 31990 invoked by uid 22791); 11 Apr 2009 18:15:39 -0000 X-SWARE-Spam-Status: No, hits=-0.8 required=5.0 tests=AWL,BAYES_50,J_CHICKENPOX_44,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx2.redhat.com (HELO mx2.redhat.com) (66.187.237.31) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 11 Apr 2009 18:15:32 +0000 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n3BIFS1L030231; Sat, 11 Apr 2009 14:15:28 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n3BIFTnQ004554; Sat, 11 Apr 2009 14:15:29 -0400 Received: from host0.dyn.jankratochvil.net (sebastian-int.corp.redhat.com [172.16.52.221]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n3BIFQhn001626; Sat, 11 Apr 2009 14:15:27 -0400 Received: from host0.dyn.jankratochvil.net (localhost [127.0.0.1]) by host0.dyn.jankratochvil.net (8.14.3/8.14.3) with ESMTP id n3BIFOTj011504; Sat, 11 Apr 2009 20:15:25 +0200 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.14.3/8.14.2/Submit) id n3BIFNgs011496; Sat, 11 Apr 2009 20:15:23 +0200 Date: Sat, 11 Apr 2009 18:15:00 -0000 From: Jan Kratochvil To: Eli Zaretskii Cc: gdb-patches@sourceware.org Subject: Re: [patch] [1/5] Types reference counting [base] Message-ID: <20090411181523.GA24218@host0.dyn.jankratochvil.net> References: <20090411102044.GB32624@host0.dyn.jankratochvil.net> <838wm7301j.fsf@gnu.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <838wm7301j.fsf@gnu.org> User-Agent: Mutt/1.5.18 (2008-05-17) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-04/txt/msg00215.txt.bz2 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 Jan Kratochvil 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 * 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