symtab.h (HT_ALLOCED): Remove.

libcpp
	* include/symtab.h (HT_ALLOCED): Remove.
	(ht_purge): Declare.
	* symtab.c (DELETED): New define.
	(ht_lookup): Update comment.
	(ht_lookup_with_hash): Handle deleted entries.  Remove HT_ALLOCED
	code.  Use subobject allocator for strings, if it exists.
	(ht_expand): Handle deleted entries.
	(ht_forall): Likewise.
	(ht_purge): New function.
	(ht_dump_statistics): Print deletion statistics.
gcc
	* ggc-zone.c (lookup_page_table_if_allocated): New function.
	(zone_find_object_offset): Likewise.
	(gt_ggc_m_S): Likewise.
	(highest_bit): Likewise.
	* ggc-page.c (gt_ggc_m_S): New function.
	* stringpool.c (string_stack): Remove.
	(init_stringpool): Update.
	(ggc_alloc_string): Use ggc_alloc.
	(maybe_delete_ident): New function.
	(ggc_purge_stringpool): Likewise.
	(gt_ggc_m_S): Remove.
	* ggc-common.c (ggc_protect_identifiers): New global.
	(ggc_mark_roots): Call ggc_purge_stringpool.  Use
	ggc_protect_identifiers.
	* ggc.h (ggc_protect_identifiers): Declare.
	(gt_ggc_m_S): Update.
	(ggc_purge_stringpool): Declare.
	* toplev.c (compile_file): Set and reset ggc_protect_identifiers.
	* gengtype.c (write_types_process_field) <TYPE_STRING>: Remove
	special case.
	(write_root): Cast gt_ggc_m_S to gt_pointer_walker.
gcc/cp
	* mangle.c (save_partially_mangled_name): Remove.
	(restore_partially_mangled_name): Likewise.
	(write_encoding): Update.
	(write_unqualified_name): Likewise.
	(start_mangling): Always use name_obstack.  Remove 'ident_p'
	argument.
	(get_identifier_nocopy): Remove.
	(finish_mangling_internal): Rename from finish_mangling.
	(finish_mangling): New function.
	(finish_mangling_get_identifier): Likewise.
	(partially_mangled_name, partially_mangled_name_len): Remove.
	(mangle_decl_string): Change return type.  Update.
	(mangle_decl, mangle_type_string, mangle_special_for_type,
	mangle_ctor_vtbl_for_type, mangle_thunk, mangle_guard_variable,
	mangle_ref_init_variable): Update.

From-SVN: r135720
This commit is contained in:
Tom Tromey 2008-05-21 15:00:59 +00:00 committed by Tom Tromey
parent ccbdd3bc4e
commit dae4174e53
13 changed files with 431 additions and 159 deletions

View File

@ -1,3 +1,27 @@
2008-05-21 Tom Tromey <tromey@redhat.com>
* ggc-zone.c (lookup_page_table_if_allocated): New function.
(zone_find_object_offset): Likewise.
(gt_ggc_m_S): Likewise.
(highest_bit): Likewise.
* ggc-page.c (gt_ggc_m_S): New function.
* stringpool.c (string_stack): Remove.
(init_stringpool): Update.
(ggc_alloc_string): Use ggc_alloc.
(maybe_delete_ident): New function.
(ggc_purge_stringpool): Likewise.
(gt_ggc_m_S): Remove.
* ggc-common.c (ggc_protect_identifiers): New global.
(ggc_mark_roots): Call ggc_purge_stringpool. Use
ggc_protect_identifiers.
* ggc.h (ggc_protect_identifiers): Declare.
(gt_ggc_m_S): Update.
(ggc_purge_stringpool): Declare.
* toplev.c (compile_file): Set and reset ggc_protect_identifiers.
* gengtype.c (write_types_process_field) <TYPE_STRING>: Remove
special case.
(write_root): Cast gt_ggc_m_S to gt_pointer_walker.
2008-05-21 David S. Miller <davem@davemloft.net>
* config.gcc (sparc-*-linux*): Always include sparc/t-linux in

View File

@ -1,3 +1,21 @@
2008-05-21 Tom Tromey <tromey@redhat.com>
* mangle.c (save_partially_mangled_name): Remove.
(restore_partially_mangled_name): Likewise.
(write_encoding): Update.
(write_unqualified_name): Likewise.
(start_mangling): Always use name_obstack. Remove 'ident_p'
argument.
(get_identifier_nocopy): Remove.
(finish_mangling_internal): Rename from finish_mangling.
(finish_mangling): New function.
(finish_mangling_get_identifier): Likewise.
(partially_mangled_name, partially_mangled_name_len): Remove.
(mangle_decl_string): Change return type. Update.
(mangle_decl, mangle_type_string, mangle_special_for_type,
mangle_ctor_vtbl_for_type, mangle_thunk, mangle_guard_variable,
mangle_ref_init_variable): Update.
2008-05-12 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/35331

View File

@ -1,5 +1,5 @@
/* Name mangling for the 3.0 C++ ABI.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
Written by Alex Samuel <samuel@codesourcery.com>
@ -117,13 +117,6 @@ static struct obstack name_obstack;
allocated on the name_obstack. */
static void *name_base;
/* An incomplete mangled name. There will be no NUL terminator. If
there is no incomplete mangled name, this variable is NULL. */
static char *partially_mangled_name;
/* The number of characters in the PARTIALLY_MANGLED_NAME. */
static size_t partially_mangled_name_len;
/* Indices into subst_identifiers. These are identifiers used in
special substitution rules. */
typedef enum
@ -217,11 +210,11 @@ static int discriminator_for_string_literal (tree, tree);
static void write_discriminator (const int);
static void write_local_name (const tree, const tree, const tree);
static void dump_substitution_candidates (void);
static const char *mangle_decl_string (const tree);
static tree mangle_decl_string (const tree);
/* Control functions. */
static inline void start_mangling (const tree, bool);
static inline void start_mangling (const tree);
static inline const char *finish_mangling (const bool);
static tree mangle_special_for_type (const tree, const char *);
@ -259,42 +252,6 @@ static void write_java_integer_type_codes (const tree);
#define write_unsigned_number(NUMBER) \
write_number ((NUMBER), /*unsigned_p=*/1, 10)
/* Save the current (incomplete) mangled name and release the obstack
storage holding it. This function should be used during mangling
when making a call that could result in a call to get_identifier,
as such a call will clobber the same obstack being used for
mangling. This function may not be called twice without an
intervening call to restore_partially_mangled_name. */
static void
save_partially_mangled_name (void)
{
if (mangle_obstack == &ident_hash->stack)
{
gcc_assert (!partially_mangled_name);
partially_mangled_name_len = obstack_object_size (mangle_obstack);
partially_mangled_name = XNEWVEC (char, partially_mangled_name_len);
memcpy (partially_mangled_name, obstack_base (mangle_obstack),
partially_mangled_name_len);
obstack_free (mangle_obstack, obstack_finish (mangle_obstack));
}
}
/* Restore the incomplete mangled name saved with
save_partially_mangled_name. */
static void
restore_partially_mangled_name (void)
{
if (partially_mangled_name)
{
obstack_grow (mangle_obstack, partially_mangled_name,
partially_mangled_name_len);
free (partially_mangled_name);
partially_mangled_name = NULL;
}
}
/* If DECL is a template instance, return nonzero and, if
TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
Otherwise return zero. */
@ -743,9 +700,7 @@ write_encoding (const tree decl)
if (decl_is_template_id (decl, NULL))
{
save_partially_mangled_name ();
fn_type = get_mostly_instantiated_function_type (decl);
restore_partially_mangled_name ();
/* FN_TYPE will not have parameter types for in-charge or
VTT parameters. Therefore, we pass NULL_TREE to
write_bare_function_type -- otherwise, it will get
@ -1110,9 +1065,7 @@ write_unqualified_name (const tree decl)
if (decl_is_template_id (decl, NULL))
{
tree fn_type;
save_partially_mangled_name ();
fn_type = get_mostly_instantiated_function_type (decl);
restore_partially_mangled_name ();
type = TREE_TYPE (fn_type);
}
else
@ -2566,26 +2519,21 @@ write_substitution (const int seq_id)
/* Start mangling ENTITY. */
static inline void
start_mangling (const tree entity, const bool ident_p)
start_mangling (const tree entity)
{
G.entity = entity;
G.need_abi_warning = false;
if (!ident_p)
{
obstack_free (&name_obstack, name_base);
mangle_obstack = &name_obstack;
name_base = obstack_alloc (&name_obstack, 0);
}
else
mangle_obstack = &ident_hash->stack;
obstack_free (&name_obstack, name_base);
mangle_obstack = &name_obstack;
name_base = obstack_alloc (&name_obstack, 0);
}
/* Done with mangling. Return the generated mangled name. If WARN is
true, and the name of G.entity will be mangled differently in a
future version of the ABI, issue a warning. */
/* Done with mangling. If WARN is true, and the name of G.entity will
be mangled differently in a future version of the ABI, issue a
warning. */
static inline const char *
finish_mangling (const bool warn)
static void
finish_mangling_internal (const bool warn)
{
if (warn_abi && warn && G.need_abi_warning)
warning (OPT_Wabi, "the mangled name of %qD will change in a future "
@ -2597,10 +2545,29 @@ finish_mangling (const bool warn)
/* Null-terminate the string. */
write_char ('\0');
}
/* Like finish_mangling_internal, but return the mangled string. */
static inline const char *
finish_mangling (const bool warn)
{
finish_mangling_internal (warn);
return (const char *) obstack_finish (mangle_obstack);
}
/* Like finish_mangling_internal, but return an identifier. */
static tree
finish_mangling_get_identifier (const bool warn)
{
finish_mangling_internal (warn);
/* Don't obstack_finish here, and the next start_mangling will
remove the identifier. */
return get_identifier ((const char *) name_base);
}
/* Initialize data structures for mangling. */
void
@ -2622,41 +2589,31 @@ init_mangle (void)
/* Generate the mangled name of DECL. */
static const char *
static tree
mangle_decl_string (const tree decl)
{
const char *result;
tree result;
start_mangling (decl, /*ident_p=*/true);
start_mangling (decl);
if (TREE_CODE (decl) == TYPE_DECL)
write_type (TREE_TYPE (decl));
else
write_mangled_name (decl, true);
result = finish_mangling (/*warn=*/true);
result = finish_mangling_get_identifier (/*warn=*/true);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
fprintf (stderr, "mangle_decl_string = '%s'\n\n",
IDENTIFIER_POINTER (result));
return result;
}
/* Like get_identifier, except that NAME is assumed to have been
allocated on the obstack used by the identifier hash table. */
static inline tree
get_identifier_nocopy (const char *name)
{
hashnode ht_node = ht_lookup (ident_hash, (const unsigned char *) name,
strlen (name), HT_ALLOCED);
return HT_IDENT_TO_GCC_IDENT (ht_node);
}
/* Create an identifier for the external mangled name of DECL. */
void
mangle_decl (const tree decl)
{
tree id = get_identifier_nocopy (mangle_decl_string (decl));
tree id = mangle_decl_string (decl);
id = targetm.mangle_decl_assembler_name (decl, id);
SET_DECL_ASSEMBLER_NAME (decl, id);
}
@ -2668,7 +2625,7 @@ mangle_type_string (const tree type)
{
const char *result;
start_mangling (type, /*ident_p=*/false);
start_mangling (type);
write_type (type);
result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
@ -2683,11 +2640,11 @@ mangle_type_string (const tree type)
static tree
mangle_special_for_type (const tree type, const char *code)
{
const char *result;
tree result;
/* We don't have an actual decl here for the special component, so
we can't just process the <encoded-name>. Instead, fake it. */
start_mangling (type, /*ident_p=*/true);
start_mangling (type);
/* Start the mangling. */
write_string ("_Z");
@ -2695,12 +2652,13 @@ mangle_special_for_type (const tree type, const char *code)
/* Add the type. */
write_type (type);
result = finish_mangling (/*warn=*/false);
result = finish_mangling_get_identifier (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
fprintf (stderr, "mangle_special_for_type = %s\n\n",
IDENTIFIER_POINTER (result));
return get_identifier_nocopy (result);
return result;
}
/* Create an identifier for the mangled representation of the typeinfo
@ -2754,9 +2712,9 @@ mangle_vtt_for_type (const tree type)
tree
mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
{
const char *result;
tree result;
start_mangling (type, /*ident_p=*/true);
start_mangling (type);
write_string ("_Z");
write_string ("TC");
@ -2765,10 +2723,11 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
write_char ('_');
write_type (BINFO_TYPE (binfo));
result = finish_mangling (/*warn=*/false);
result = finish_mangling_get_identifier (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
return get_identifier_nocopy (result);
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
IDENTIFIER_POINTER (result));
return result;
}
/* Mangle a this pointer or result pointer adjustment.
@ -2810,9 +2769,9 @@ tree
mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
tree virtual_offset)
{
const char *result;
tree result;
start_mangling (fn_decl, /*ident_p=*/true);
start_mangling (fn_decl);
write_string ("_Z");
write_char ('T');
@ -2843,10 +2802,10 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
/* Scoped name. */
write_encoding (fn_decl);
result = finish_mangling (/*warn=*/false);
result = finish_mangling_get_identifier (/*warn=*/false);
if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", result);
return get_identifier_nocopy (result);
fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
return result;
}
/* This hash table maps TYPEs to the IDENTIFIER for a conversion
@ -2918,7 +2877,7 @@ mangle_conv_op_name_for_type (const tree type)
tree
mangle_guard_variable (const tree variable)
{
start_mangling (variable, /*ident_p=*/true);
start_mangling (variable);
write_string ("_ZGV");
if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
/* The name of a guard variable for a reference temporary should refer
@ -2926,7 +2885,7 @@ mangle_guard_variable (const tree variable)
write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
else
write_name (variable, /*ignore_local_scope=*/0);
return get_identifier_nocopy (finish_mangling (/*warn=*/false));
return finish_mangling_get_identifier (/*warn=*/false);
}
/* Return an identifier for the name of a temporary variable used to
@ -2936,10 +2895,10 @@ mangle_guard_variable (const tree variable)
tree
mangle_ref_init_variable (const tree variable)
{
start_mangling (variable, /*ident_p=*/true);
start_mangling (variable);
write_string ("_ZGR");
write_name (variable, /*ignore_local_scope=*/0);
return get_identifier_nocopy (finish_mangling (/*warn=*/false));
return finish_mangling_get_identifier (/*warn=*/false);
}

View File

@ -2357,9 +2357,6 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
break;
case TYPE_STRING:
if (wtd->param_prefix == NULL)
break;
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_LANG_STRUCT:
@ -3134,7 +3131,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
oprintf (f, " &%s,\n", name);
oprintf (f, " 1, \n");
oprintf (f, " sizeof (%s),\n", v->name);
oprintf (f, " &gt_ggc_m_S,\n");
oprintf (f, " (gt_pointer_walker) &gt_ggc_m_S,\n");
oprintf (f, " (gt_pointer_walker) &gt_pch_n_S\n");
oprintf (f, " },\n");
}

View File

@ -1,5 +1,5 @@
/* Simple garbage collection for the GNU compiler.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
@ -50,6 +50,9 @@ along with GCC; see the file COPYING3. If not see
/* When set, ggc_collect will do collection. */
bool ggc_force_collect;
/* When true, protect the contents of the identifier hash table. */
bool ggc_protect_identifiers = true;
/* Statistics about the allocation. */
static ggc_statistics *ggc_stats;
@ -103,7 +106,8 @@ ggc_mark_roots (void)
for (i = 0; i < rti->nelt; i++)
(*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
ggc_mark_stringpool ();
if (ggc_protect_identifiers)
ggc_mark_stringpool ();
/* Now scan all hash tables that have objects which are to be deleted if
they are not already marked. */
@ -115,6 +119,9 @@ ggc_mark_roots (void)
htab_traverse_noresize (*cti->base, ggc_htab_delete, (void *) cti);
ggc_set_mark ((*cti->base)->entries);
}
if (! ggc_protect_identifiers)
ggc_purge_stringpool ();
}
/* Allocate a block of memory, then clear it. */

View File

@ -1,5 +1,5 @@
/* "Bag-of-pages" garbage collector for the GNU compiler.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
@ -1256,6 +1256,57 @@ ggc_alloc_stat (size_t size MEM_STAT_DECL)
return result;
}
/* Mark function for strings. */
void
gt_ggc_m_S (const void *p)
{
page_entry *entry;
unsigned bit, word;
unsigned long mask;
unsigned long offset;
if (!p || !ggc_allocated_p (p))
return;
/* Look up the page on which the object is alloced. . */
entry = lookup_page_table_entry (p);
gcc_assert (entry);
/* Calculate the index of the object on the page; this is its bit
position in the in_use_p bitmap. Note that because a char* might
point to the middle of an object, we need special code here to
make sure P points to the start of an object. */
offset = ((const char *) p - entry->page) % object_size_table[entry->order];
if (offset)
{
/* Here we've seen a char* which does not point to the beginning
of an allocated object. We assume it points to the middle of
a STRING_CST. */
gcc_assert (offset == offsetof (struct tree_string, str));
p = ((const char *) p) - offset;
gt_ggc_mx_lang_tree_node ((void *) p);
return;
}
bit = OFFSET_TO_BIT (((const char *) p) - entry->page, entry->order);
word = bit / HOST_BITS_PER_LONG;
mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
/* If the bit was previously set, skip it. */
if (entry->in_use_p[word] & mask)
return;
/* Otherwise set it, and decrement the free object count. */
entry->in_use_p[word] |= mask;
entry->num_free_objects -= 1;
if (GGC_DEBUG_LEVEL >= 4)
fprintf (G.debug_file, "Marking %p\n", p);
return;
}
/* If P is not marked, marks it and return false. Otherwise return true.
P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */

View File

@ -1,5 +1,5 @@
/* "Bag-of-pages" zone garbage collector for the GNU compiler.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
Contributed by Richard Henderson (rth@redhat.com) and Daniel Berlin
@ -506,6 +506,47 @@ lookup_page_table_entry (const void *p)
return base[L1][L2];
}
/* Traverse the page table and find the entry for a page.
Return NULL if the object wasn't allocated via the GC. */
static inline page_entry *
lookup_page_table_if_allocated (const void *p)
{
page_entry ***base;
size_t L1, L2;
#if HOST_BITS_PER_PTR <= 32
base = &G.lookup[0];
#else
page_table table = G.lookup;
size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
while (1)
{
if (table == NULL)
return NULL;
if (table->high_bits == high_bits)
break;
table = table->next;
}
base = &table->table[0];
#endif
/* Extract the level 1 and 2 indices. */
L1 = LOOKUP_L1 (p);
if (! base[L1])
return NULL;
L2 = LOOKUP_L2 (p);
if (L2 >= PAGE_L2_SIZE)
return NULL;
/* We might have a page entry which does not correspond exactly to a
system page. */
if (base[L1][L2] && (char *) p < base[L1][L2]->page)
return NULL;
return base[L1][L2];
}
/* Set the page table entry for the page that starts at P. If ENTRY
is NULL, clear the entry. */
@ -680,6 +721,55 @@ zone_find_object_size (struct small_page_entry *page,
max_size);
}
/* highest_bit assumes that alloc_type is 32 bits. */
extern char check_alloc_type_size[(sizeof (alloc_type) == 4) ? 1 : -1];
/* Find the highest set bit in VALUE. Returns the bit number of that
bit, using the same values as ffs. */
static inline alloc_type
highest_bit (alloc_type value)
{
/* This also assumes that alloc_type is unsigned. */
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
value = value ^ (value >> 1);
return alloc_ffs (value);
}
/* Find the offset from the start of an object to P, which may point
into the interior of the object. */
static unsigned long
zone_find_object_offset (alloc_type *alloc_bits, size_t start_word,
size_t start_bit)
{
unsigned int offset_in_bits;
alloc_type alloc_word = alloc_bits[start_word];
/* Mask off any bits after the initial bit, but make sure to include
the initial bit in the result. Note that START_BIT is
0-based. */
if (start_bit < 8 * sizeof (alloc_type) - 1)
alloc_word &= (1 << (start_bit + 1)) - 1;
offset_in_bits = start_bit;
/* Search for the start of the object. */
while (alloc_word == 0 && start_word > 0)
{
alloc_word = alloc_bits[--start_word];
offset_in_bits += 8 * sizeof (alloc_type);
}
/* We must always find a set bit. */
gcc_assert (alloc_word != 0);
/* Note that the result of highest_bit is 1-based. */
offset_in_bits -= highest_bit (alloc_word) - 1;
return BYTES_PER_ALLOC_BIT * offset_in_bits;
}
/* Allocate the mark bits for every zone, and set the pointers on each
page. */
static void
@ -1353,6 +1443,65 @@ ggc_free (void *p)
}
}
/* Mark function for strings. */
void
gt_ggc_m_S (const void *p)
{
page_entry *entry;
unsigned long offset;
if (!p)
return;
/* Look up the page on which the object is alloced. . */
entry = lookup_page_table_if_allocated (p);
if (! entry)
return;
if (entry->pch_p)
{
size_t alloc_word, alloc_bit, t;
t = ((const char *) p - pch_zone.page) / BYTES_PER_ALLOC_BIT;
alloc_word = t / (8 * sizeof (alloc_type));
alloc_bit = t % (8 * sizeof (alloc_type));
offset = zone_find_object_offset (pch_zone.alloc_bits, alloc_word,
alloc_bit);
}
else if (entry->large_p)
{
struct large_page_entry *le = (struct large_page_entry *) entry;
offset = ((const char *) p) - entry->page;
gcc_assert (offset < le->bytes);
}
else
{
struct small_page_entry *se = (struct small_page_entry *) entry;
unsigned int start_word = zone_get_object_alloc_word (p);
unsigned int start_bit = zone_get_object_alloc_bit (p);
offset = zone_find_object_offset (se->alloc_bits, start_word, start_bit);
/* On some platforms a char* will not necessarily line up on an
allocation boundary, so we have to update the offset to
account for the leftover bytes. */
offset += (size_t) p % BYTES_PER_ALLOC_BIT;
}
if (offset)
{
/* Here we've seen a char* which does not point to the beginning
of an allocated object. We assume it points to the middle of
a STRING_CST. */
gcc_assert (offset == offsetof (struct tree_string, str));
p = ((const char *) p) - offset;
gt_ggc_mx_lang_tree_node ((void *) p);
return;
}
/* Inefficient, but also unlikely to matter. */
ggc_set_mark (p);
}
/* If P is not marked, mark it and return false. Otherwise return true.
P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */

View File

@ -1,5 +1,5 @@
/* Garbage collection for the GNU compiler.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
@ -120,6 +120,9 @@ extern int ggc_marked_p (const void *);
/* Mark the entries in the string pool. */
extern void ggc_mark_stringpool (void);
/* Purge the entries in the string pool. */
extern void ggc_purge_stringpool (void);
/* Call ggc_set_mark on all the roots. */
extern void ggc_mark_roots (void);
@ -134,7 +137,7 @@ extern void gt_pch_restore_stringpool (void);
extern void gt_pch_p_S (void *, void *, gt_pointer_operator, void *);
extern void gt_pch_n_S (const void *);
extern void gt_ggc_m_S (void *);
extern void gt_ggc_m_S (const void *);
/* Initialize the string pool. */
extern void init_stringpool (void);
@ -200,6 +203,12 @@ extern void ggc_pch_read (FILE *, void *);
/* When set, ggc_collect will do collection. */
extern bool ggc_force_collect;
/* When true, identifier nodes are considered as GC roots. When
false, identifier nodes are treated like any other GC-allocated
object, and the identifier hash table is treated as a weak
hash. */
extern bool ggc_protect_identifiers;
/* The internal primitive. */
extern void *ggc_alloc_stat (size_t MEM_STAT_DECL);
#define ggc_alloc(s) ggc_alloc_stat (s MEM_STAT_INFO)

View File

@ -1,5 +1,5 @@
/* String pool for GCC.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
@ -47,7 +47,6 @@ const char digit_vector[] = {
};
struct ht *ident_hash;
static struct obstack string_stack;
static hashnode alloc_node (hash_table *);
static int mark_ident (struct cpp_reader *, hashnode, const void *);
@ -66,7 +65,6 @@ init_stringpool (void)
ident_hash = ht_create (14);
ident_hash->alloc_node = alloc_node;
ident_hash->alloc_subobject = stringpool_ggc_alloc;
gcc_obstack_init (&string_stack);
}
/* Allocate a hash node. */
@ -85,6 +83,8 @@ alloc_node (hash_table *table ATTRIBUTE_UNUSED)
const char *
ggc_alloc_string (const char *contents, int length)
{
char *result;
if (length == -1)
length = strlen (contents);
@ -93,8 +93,9 @@ ggc_alloc_string (const char *contents, int length)
if (length == 1 && ISDIGIT (contents[0]))
return digit_string (contents[0] - '0');
obstack_grow0 (&string_stack, contents, length);
return XOBFINISH (&string_stack, const char *);
result = ggc_alloc (length + 1);
memcpy (result, contents, length + 1);
return (const char *) result;
}
/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
@ -163,9 +164,18 @@ mark_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
return 1;
}
/* Return true if an identifier should be removed from the table. */
static int
maybe_delete_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
const void *v ATTRIBUTE_UNUSED)
{
return !ggc_marked_p (HT_IDENT_TO_GCC_IDENT (h));
}
/* Mark the trees hanging off the identifier node for GGC. These are
handled specially (not using gengtype) because of the special
treatment for strings. */
handled specially (not using gengtype) because identifiers are only
roots during one part of compilation. */
void
ggc_mark_stringpool (void)
@ -173,13 +183,13 @@ ggc_mark_stringpool (void)
ht_forall (ident_hash, mark_ident, NULL);
}
/* Strings are _not_ GCed, but this routine exists so that a separate
roots table isn't needed for the few global variables that refer
to strings. */
/* Purge the identifier hash of identifiers which are no longer
referenced. */
void
gt_ggc_m_S (void *x ATTRIBUTE_UNUSED)
ggc_purge_stringpool (void)
{
ht_purge (ident_hash, maybe_delete_ident, NULL);
}
/* Pointer-walking routine for strings (not very interesting, since

View File

@ -951,6 +951,8 @@ compile_file (void)
{
/* Initialize yet another pass. */
ggc_protect_identifiers = true;
init_cgraph ();
init_final (main_input_filename);
coverage_init (aux_base_name);
@ -969,6 +971,8 @@ compile_file (void)
if (flag_syntax_only)
return;
ggc_protect_identifiers = false;
lang_hooks.decls.final_write_globals ();
if (errorcount || sorrycount)

View File

@ -1,3 +1,16 @@
2008-05-21 Tom Tromey <tromey@redhat.com>
* include/symtab.h (HT_ALLOCED): Remove.
(ht_purge): Declare.
* symtab.c (DELETED): New define.
(ht_lookup): Update comment.
(ht_lookup_with_hash): Handle deleted entries. Remove HT_ALLOCED
code. Use subobject allocator for strings, if it exists.
(ht_expand): Handle deleted entries.
(ht_forall): Likewise.
(ht_purge): New function.
(ht_dump_statistics): Print deletion statistics.
2008-05-13 Tom Tromey <tromey@redhat.com>
PR preprocessor/22168:

View File

@ -1,5 +1,5 @@
/* Hash tables.
Copyright (C) 2000, 2001, 2003, 2004, 2007 Free Software Foundation, Inc.
Copyright (C) 2000, 2001, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@ -39,7 +39,7 @@ struct ht_identifier GTY(())
typedef struct ht hash_table;
typedef struct ht_identifier *hashnode;
enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED};
enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC};
/* An identifier hash table for cpplib and the front ends. */
struct ht
@ -88,6 +88,10 @@ extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
extern void ht_forall (hash_table *, ht_cb, const void *);
/* For all nodes in TABLE, call the callback. If the callback returns
a nonzero value, the node is removed from the table. */
extern void ht_purge (hash_table *, ht_cb, const void *);
/* Restore the hash table. */
extern void ht_load (hash_table *ht, hashnode *entries,
unsigned int nslots, unsigned int nelements, bool own);

View File

@ -1,5 +1,5 @@
/* Hash tables.
Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2000, 2001, 2003, 2004, 2008 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@ -27,13 +27,15 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
hash tables (see libiberty/hashtab.c). The abstraction penalty was
too high to continue using the generic form. This code knows
intrinsically how to calculate a hash value, and how to compare an
existing entry with a potential new one. Also, the ability to
delete members from the table has been removed. */
existing entry with a potential new one. */
static unsigned int calc_hash (const unsigned char *, size_t);
static void ht_expand (hash_table *);
static double approx_sqrt (double);
/* A deleted entry. */
#define DELETED ((hashnode) -1)
/* Calculate the hash of the string STR of length LEN. */
static unsigned int
@ -83,13 +85,10 @@ ht_destroy (hash_table *table)
}
/* Returns the hash entry for the a STR of length LEN. If that string
already exists in the table, returns the existing entry, and, if
INSERT is CPP_ALLOCED, frees the last obstack object. If the
already exists in the table, returns the existing entry. If the
identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
returns NULL. Otherwise insert and returns a new entry. A new
string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is
CPP_ALLOCED and the item is assumed to be at the top of the
obstack. */
string is allocated. */
hashnode
ht_lookup (hash_table *table, const unsigned char *str, size_t len,
enum ht_lookup_option insert)
@ -105,6 +104,7 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
{
unsigned int hash2;
unsigned int index;
unsigned int deleted_index = table->nslots;
size_t sizemask;
hashnode node;
@ -113,19 +113,15 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
table->searches++;
node = table->entries[index];
if (node != NULL)
{
if (node->hash_value == hash
&& HT_LEN (node) == (unsigned int) len
&& !memcmp (HT_STR (node), str, len))
{
if (insert == HT_ALLOCED)
/* The string we search for was placed at the end of the
obstack. Release it. */
obstack_free (&table->stack, (void *) str);
return node;
}
if (node == DELETED)
deleted_index = index;
else if (node->hash_value == hash
&& HT_LEN (node) == (unsigned int) len
&& !memcmp (HT_STR (node), str, len))
return node;
/* hash2 must be odd, so we're guaranteed to visit every possible
location in the table during rehashing. */
@ -139,32 +135,41 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
if (node == NULL)
break;
if (node->hash_value == hash
&& HT_LEN (node) == (unsigned int) len
&& !memcmp (HT_STR (node), str, len))
if (node == DELETED)
{
if (insert == HT_ALLOCED)
/* The string we search for was placed at the end of the
obstack. Release it. */
obstack_free (&table->stack, (void *) str);
return node;
if (deleted_index != table->nslots)
deleted_index = index;
}
else if (node->hash_value == hash
&& HT_LEN (node) == (unsigned int) len
&& !memcmp (HT_STR (node), str, len))
return node;
}
}
if (insert == HT_NO_INSERT)
return NULL;
/* We prefer to overwrite the first deleted slot we saw. */
if (deleted_index != table->nslots)
index = deleted_index;
node = (*table->alloc_node) (table);
table->entries[index] = node;
HT_LEN (node) = (unsigned int) len;
node->hash_value = hash;
if (insert == HT_ALLOC)
HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
str, len);
if (table->alloc_subobject)
{
char *chars = table->alloc_subobject (len + 1);
memcpy (chars, str, len);
chars[len] = '\0';
HT_STR (node) = (const unsigned char *) chars;
}
else
HT_STR (node) = str;
HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
str, len);
if (++table->nelements * 4 >= table->nslots * 3)
/* Must expand the string table. */
@ -188,7 +193,7 @@ ht_expand (hash_table *table)
p = table->entries;
limit = p + table->nslots;
do
if (*p)
if (*p && *p != DELETED)
{
unsigned int index, hash, hash2;
@ -225,7 +230,7 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
p = table->entries;
limit = p + table->nslots;
do
if (*p)
if (*p && *p != DELETED)
{
if ((*cb) (table->pfile, *p, v) == 0)
break;
@ -233,6 +238,24 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
while (++p < limit);
}
/* Like ht_forall, but a nonzero return from the callback means that
the entry should be removed from the table. */
void
ht_purge (hash_table *table, ht_cb cb, const void *v)
{
hashnode *p, *limit;
p = table->entries;
limit = p + table->nslots;
do
if (*p && *p != DELETED)
{
if ((*cb) (table->pfile, *p, v))
*p = DELETED;
}
while (++p < limit);
}
/* Restore the hash table. */
void
ht_load (hash_table *ht, hashnode *entries,
@ -253,7 +276,7 @@ void
ht_dump_statistics (hash_table *table)
{
size_t nelts, nids, overhead, headers;
size_t total_bytes, longest;
size_t total_bytes, longest, deleted = 0;
double sum_of_squares, exp_len, exp_len2, exp2_len;
hashnode *p, *limit;
@ -268,7 +291,9 @@ ht_dump_statistics (hash_table *table)
p = table->entries;
limit = p + table->nslots;
do
if (*p)
if (*p == DELETED)
++deleted;
else if (*p)
{
size_t n = HT_LEN (*p);
@ -290,6 +315,8 @@ ht_dump_statistics (hash_table *table)
(unsigned long) nids, nids * 100.0 / nelts);
fprintf (stderr, "slots\t\t%lu\n",
(unsigned long) table->nslots);
fprintf (stderr, "deleted\t\t%lu\n",
(unsigned long) deleted);
fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
SCALE (total_bytes), LABEL (total_bytes),
SCALE (overhead), LABEL (overhead));