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> 2008-05-21 David S. Miller <davem@davemloft.net>
* config.gcc (sparc-*-linux*): Always include sparc/t-linux in * 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> 2008-05-12 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/35331 PR c++/35331

View File

@ -1,5 +1,5 @@
/* Name mangling for the 3.0 C++ ABI. /* 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. Free Software Foundation, Inc.
Written by Alex Samuel <samuel@codesourcery.com> Written by Alex Samuel <samuel@codesourcery.com>
@ -117,13 +117,6 @@ static struct obstack name_obstack;
allocated on the name_obstack. */ allocated on the name_obstack. */
static void *name_base; 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 /* Indices into subst_identifiers. These are identifiers used in
special substitution rules. */ special substitution rules. */
typedef enum typedef enum
@ -217,11 +210,11 @@ static int discriminator_for_string_literal (tree, tree);
static void write_discriminator (const int); static void write_discriminator (const int);
static void write_local_name (const tree, const tree, const tree); static void write_local_name (const tree, const tree, const tree);
static void dump_substitution_candidates (void); static void dump_substitution_candidates (void);
static const char *mangle_decl_string (const tree); static tree mangle_decl_string (const tree);
/* Control functions. */ /* 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 inline const char *finish_mangling (const bool);
static tree mangle_special_for_type (const tree, const char *); 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) \ #define write_unsigned_number(NUMBER) \
write_number ((NUMBER), /*unsigned_p=*/1, 10) 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 /* If DECL is a template instance, return nonzero and, if
TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info. TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
Otherwise return zero. */ Otherwise return zero. */
@ -743,9 +700,7 @@ write_encoding (const tree decl)
if (decl_is_template_id (decl, NULL)) if (decl_is_template_id (decl, NULL))
{ {
save_partially_mangled_name ();
fn_type = get_mostly_instantiated_function_type (decl); fn_type = get_mostly_instantiated_function_type (decl);
restore_partially_mangled_name ();
/* FN_TYPE will not have parameter types for in-charge or /* FN_TYPE will not have parameter types for in-charge or
VTT parameters. Therefore, we pass NULL_TREE to VTT parameters. Therefore, we pass NULL_TREE to
write_bare_function_type -- otherwise, it will get 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)) if (decl_is_template_id (decl, NULL))
{ {
tree fn_type; tree fn_type;
save_partially_mangled_name ();
fn_type = get_mostly_instantiated_function_type (decl); fn_type = get_mostly_instantiated_function_type (decl);
restore_partially_mangled_name ();
type = TREE_TYPE (fn_type); type = TREE_TYPE (fn_type);
} }
else else
@ -2566,26 +2519,21 @@ write_substitution (const int seq_id)
/* Start mangling ENTITY. */ /* Start mangling ENTITY. */
static inline void static inline void
start_mangling (const tree entity, const bool ident_p) start_mangling (const tree entity)
{ {
G.entity = entity; G.entity = entity;
G.need_abi_warning = false; G.need_abi_warning = false;
if (!ident_p) obstack_free (&name_obstack, name_base);
{ mangle_obstack = &name_obstack;
obstack_free (&name_obstack, name_base); name_base = obstack_alloc (&name_obstack, 0);
mangle_obstack = &name_obstack;
name_base = obstack_alloc (&name_obstack, 0);
}
else
mangle_obstack = &ident_hash->stack;
} }
/* Done with mangling. Return the generated mangled name. If WARN is /* Done with mangling. If WARN is true, and the name of G.entity will
true, and the name of G.entity will be mangled differently in a be mangled differently in a future version of the ABI, issue a
future version of the ABI, issue a warning. */ warning. */
static inline const char * static void
finish_mangling (const bool warn) finish_mangling_internal (const bool warn)
{ {
if (warn_abi && warn && G.need_abi_warning) if (warn_abi && warn && G.need_abi_warning)
warning (OPT_Wabi, "the mangled name of %qD will change in a future " 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. */ /* Null-terminate the string. */
write_char ('\0'); 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); 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. */ /* Initialize data structures for mangling. */
void void
@ -2622,41 +2589,31 @@ init_mangle (void)
/* Generate the mangled name of DECL. */ /* Generate the mangled name of DECL. */
static const char * static tree
mangle_decl_string (const tree decl) 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) if (TREE_CODE (decl) == TYPE_DECL)
write_type (TREE_TYPE (decl)); write_type (TREE_TYPE (decl));
else else
write_mangled_name (decl, true); write_mangled_name (decl, true);
result = finish_mangling (/*warn=*/true); result = finish_mangling_get_identifier (/*warn=*/true);
if (DEBUG_MANGLE) 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; 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. */ /* Create an identifier for the external mangled name of DECL. */
void void
mangle_decl (const tree decl) 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); id = targetm.mangle_decl_assembler_name (decl, id);
SET_DECL_ASSEMBLER_NAME (decl, id); SET_DECL_ASSEMBLER_NAME (decl, id);
} }
@ -2668,7 +2625,7 @@ mangle_type_string (const tree type)
{ {
const char *result; const char *result;
start_mangling (type, /*ident_p=*/false); start_mangling (type);
write_type (type); write_type (type);
result = finish_mangling (/*warn=*/false); result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE) if (DEBUG_MANGLE)
@ -2683,11 +2640,11 @@ mangle_type_string (const tree type)
static tree static tree
mangle_special_for_type (const tree type, const char *code) 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 don't have an actual decl here for the special component, so
we can't just process the <encoded-name>. Instead, fake it. */ we can't just process the <encoded-name>. Instead, fake it. */
start_mangling (type, /*ident_p=*/true); start_mangling (type);
/* Start the mangling. */ /* Start the mangling. */
write_string ("_Z"); write_string ("_Z");
@ -2695,12 +2652,13 @@ mangle_special_for_type (const tree type, const char *code)
/* Add the type. */ /* Add the type. */
write_type (type); write_type (type);
result = finish_mangling (/*warn=*/false); result = finish_mangling_get_identifier (/*warn=*/false);
if (DEBUG_MANGLE) 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 /* Create an identifier for the mangled representation of the typeinfo
@ -2754,9 +2712,9 @@ mangle_vtt_for_type (const tree type)
tree tree
mangle_ctor_vtbl_for_type (const tree type, const tree binfo) 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 ("_Z");
write_string ("TC"); write_string ("TC");
@ -2765,10 +2723,11 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
write_char ('_'); write_char ('_');
write_type (BINFO_TYPE (binfo)); write_type (BINFO_TYPE (binfo));
result = finish_mangling (/*warn=*/false); result = finish_mangling_get_identifier (/*warn=*/false);
if (DEBUG_MANGLE) if (DEBUG_MANGLE)
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result); fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
return get_identifier_nocopy (result); IDENTIFIER_POINTER (result));
return result;
} }
/* Mangle a this pointer or result pointer adjustment. /* 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, mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
tree virtual_offset) tree virtual_offset)
{ {
const char *result; tree result;
start_mangling (fn_decl, /*ident_p=*/true); start_mangling (fn_decl);
write_string ("_Z"); write_string ("_Z");
write_char ('T'); write_char ('T');
@ -2843,10 +2802,10 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
/* Scoped name. */ /* Scoped name. */
write_encoding (fn_decl); write_encoding (fn_decl);
result = finish_mangling (/*warn=*/false); result = finish_mangling_get_identifier (/*warn=*/false);
if (DEBUG_MANGLE) if (DEBUG_MANGLE)
fprintf (stderr, "mangle_thunk = %s\n\n", result); fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
return get_identifier_nocopy (result); return result;
} }
/* This hash table maps TYPEs to the IDENTIFIER for a conversion /* 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 tree
mangle_guard_variable (const tree variable) mangle_guard_variable (const tree variable)
{ {
start_mangling (variable, /*ident_p=*/true); start_mangling (variable);
write_string ("_ZGV"); write_string ("_ZGV");
if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0) if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
/* The name of a guard variable for a reference temporary should refer /* 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); write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
else else
write_name (variable, /*ignore_local_scope=*/0); 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 /* Return an identifier for the name of a temporary variable used to
@ -2936,10 +2895,10 @@ mangle_guard_variable (const tree variable)
tree tree
mangle_ref_init_variable (const tree variable) mangle_ref_init_variable (const tree variable)
{ {
start_mangling (variable, /*ident_p=*/true); start_mangling (variable);
write_string ("_ZGR"); write_string ("_ZGR");
write_name (variable, /*ignore_local_scope=*/0); 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; break;
case TYPE_STRING: case TYPE_STRING:
if (wtd->param_prefix == NULL)
break;
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_UNION: case TYPE_UNION:
case TYPE_LANG_STRUCT: 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, " &%s,\n", name);
oprintf (f, " 1, \n"); oprintf (f, " 1, \n");
oprintf (f, " sizeof (%s),\n", v->name); 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, " (gt_pointer_walker) &gt_pch_n_S\n");
oprintf (f, " },\n"); oprintf (f, " },\n");
} }

View File

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

View File

@ -1,5 +1,5 @@
/* "Bag-of-pages" garbage collector for the GNU compiler. /* "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. Free Software Foundation, Inc.
This file is part of GCC. This file is part of GCC.
@ -1256,6 +1256,57 @@ ggc_alloc_stat (size_t size MEM_STAT_DECL)
return result; 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. /* 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 P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */ 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. /* "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. Free Software Foundation, Inc.
Contributed by Richard Henderson (rth@redhat.com) and Daniel Berlin 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]; 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 /* Set the page table entry for the page that starts at P. If ENTRY
is NULL, clear the entry. */ is NULL, clear the entry. */
@ -680,6 +721,55 @@ zone_find_object_size (struct small_page_entry *page,
max_size); 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 /* Allocate the mark bits for every zone, and set the pointers on each
page. */ page. */
static void 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. /* 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 P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */ static objects, stack variables, or memory allocated with malloc. */

View File

@ -1,5 +1,5 @@
/* Garbage collection for the GNU compiler. /* 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. Free Software Foundation, Inc.
This file is part of GCC. This file is part of GCC.
@ -120,6 +120,9 @@ extern int ggc_marked_p (const void *);
/* Mark the entries in the string pool. */ /* Mark the entries in the string pool. */
extern void ggc_mark_stringpool (void); 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. */ /* Call ggc_set_mark on all the roots. */
extern void ggc_mark_roots (void); 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_p_S (void *, void *, gt_pointer_operator, void *);
extern void gt_pch_n_S (const 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. */ /* Initialize the string pool. */
extern void init_stringpool (void); extern void init_stringpool (void);
@ -200,6 +203,12 @@ extern void ggc_pch_read (FILE *, void *);
/* When set, ggc_collect will do collection. */ /* When set, ggc_collect will do collection. */
extern bool ggc_force_collect; 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. */ /* The internal primitive. */
extern void *ggc_alloc_stat (size_t MEM_STAT_DECL); extern void *ggc_alloc_stat (size_t MEM_STAT_DECL);
#define ggc_alloc(s) ggc_alloc_stat (s MEM_STAT_INFO) #define ggc_alloc(s) ggc_alloc_stat (s MEM_STAT_INFO)

View File

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

View File

@ -951,6 +951,8 @@ compile_file (void)
{ {
/* Initialize yet another pass. */ /* Initialize yet another pass. */
ggc_protect_identifiers = true;
init_cgraph (); init_cgraph ();
init_final (main_input_filename); init_final (main_input_filename);
coverage_init (aux_base_name); coverage_init (aux_base_name);
@ -969,6 +971,8 @@ compile_file (void)
if (flag_syntax_only) if (flag_syntax_only)
return; return;
ggc_protect_identifiers = false;
lang_hooks.decls.final_write_globals (); lang_hooks.decls.final_write_globals ();
if (errorcount || sorrycount) 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> 2008-05-13 Tom Tromey <tromey@redhat.com>
PR preprocessor/22168: PR preprocessor/22168:

View File

@ -1,5 +1,5 @@
/* Hash tables. /* 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 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 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 hash_table;
typedef struct ht_identifier *hashnode; 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. */ /* An identifier hash table for cpplib and the front ends. */
struct ht 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 *); typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
extern void ht_forall (hash_table *, ht_cb, 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. */ /* Restore the hash table. */
extern void ht_load (hash_table *ht, hashnode *entries, extern void ht_load (hash_table *ht, hashnode *entries,
unsigned int nslots, unsigned int nelements, bool own); unsigned int nslots, unsigned int nelements, bool own);

View File

@ -1,5 +1,5 @@
/* Hash tables. /* 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 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 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 hash tables (see libiberty/hashtab.c). The abstraction penalty was
too high to continue using the generic form. This code knows too high to continue using the generic form. This code knows
intrinsically how to calculate a hash value, and how to compare an intrinsically how to calculate a hash value, and how to compare an
existing entry with a potential new one. Also, the ability to existing entry with a potential new one. */
delete members from the table has been removed. */
static unsigned int calc_hash (const unsigned char *, size_t); static unsigned int calc_hash (const unsigned char *, size_t);
static void ht_expand (hash_table *); static void ht_expand (hash_table *);
static double approx_sqrt (double); static double approx_sqrt (double);
/* A deleted entry. */
#define DELETED ((hashnode) -1)
/* Calculate the hash of the string STR of length LEN. */ /* Calculate the hash of the string STR of length LEN. */
static unsigned int 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 /* 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 already exists in the table, returns the existing entry. If the
INSERT is CPP_ALLOCED, frees the last obstack object. If the
identifier hasn't been seen before, and INSERT is CPP_NO_INSERT, identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
returns NULL. Otherwise insert and returns a new entry. A new returns NULL. Otherwise insert and returns a new entry. A new
string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is string is allocated. */
CPP_ALLOCED and the item is assumed to be at the top of the
obstack. */
hashnode hashnode
ht_lookup (hash_table *table, const unsigned char *str, size_t len, ht_lookup (hash_table *table, const unsigned char *str, size_t len,
enum ht_lookup_option insert) 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 hash2;
unsigned int index; unsigned int index;
unsigned int deleted_index = table->nslots;
size_t sizemask; size_t sizemask;
hashnode node; hashnode node;
@ -113,19 +113,15 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
table->searches++; table->searches++;
node = table->entries[index]; node = table->entries[index];
if (node != NULL) if (node != NULL)
{ {
if (node->hash_value == hash if (node == DELETED)
&& HT_LEN (node) == (unsigned int) len deleted_index = index;
&& !memcmp (HT_STR (node), str, len)) else if (node->hash_value == hash
{ && HT_LEN (node) == (unsigned int) len
if (insert == HT_ALLOCED) && !memcmp (HT_STR (node), str, len))
/* The string we search for was placed at the end of the return node;
obstack. Release it. */
obstack_free (&table->stack, (void *) str);
return node;
}
/* hash2 must be odd, so we're guaranteed to visit every possible /* hash2 must be odd, so we're guaranteed to visit every possible
location in the table during rehashing. */ location in the table during rehashing. */
@ -139,32 +135,41 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
if (node == NULL) if (node == NULL)
break; break;
if (node->hash_value == hash if (node == DELETED)
&& HT_LEN (node) == (unsigned int) len
&& !memcmp (HT_STR (node), str, len))
{ {
if (insert == HT_ALLOCED) if (deleted_index != table->nslots)
/* The string we search for was placed at the end of the deleted_index = index;
obstack. Release it. */
obstack_free (&table->stack, (void *) str);
return node;
} }
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) if (insert == HT_NO_INSERT)
return NULL; 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); node = (*table->alloc_node) (table);
table->entries[index] = node; table->entries[index] = node;
HT_LEN (node) = (unsigned int) len; HT_LEN (node) = (unsigned int) len;
node->hash_value = hash; node->hash_value = hash;
if (insert == HT_ALLOC)
HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack, if (table->alloc_subobject)
str, len); {
char *chars = table->alloc_subobject (len + 1);
memcpy (chars, str, len);
chars[len] = '\0';
HT_STR (node) = (const unsigned char *) chars;
}
else else
HT_STR (node) = str; HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
str, len);
if (++table->nelements * 4 >= table->nslots * 3) if (++table->nelements * 4 >= table->nslots * 3)
/* Must expand the string table. */ /* Must expand the string table. */
@ -188,7 +193,7 @@ ht_expand (hash_table *table)
p = table->entries; p = table->entries;
limit = p + table->nslots; limit = p + table->nslots;
do do
if (*p) if (*p && *p != DELETED)
{ {
unsigned int index, hash, hash2; unsigned int index, hash, hash2;
@ -225,7 +230,7 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
p = table->entries; p = table->entries;
limit = p + table->nslots; limit = p + table->nslots;
do do
if (*p) if (*p && *p != DELETED)
{ {
if ((*cb) (table->pfile, *p, v) == 0) if ((*cb) (table->pfile, *p, v) == 0)
break; break;
@ -233,6 +238,24 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
while (++p < limit); 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. */ /* Restore the hash table. */
void void
ht_load (hash_table *ht, hashnode *entries, ht_load (hash_table *ht, hashnode *entries,
@ -253,7 +276,7 @@ void
ht_dump_statistics (hash_table *table) ht_dump_statistics (hash_table *table)
{ {
size_t nelts, nids, overhead, headers; 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; double sum_of_squares, exp_len, exp_len2, exp2_len;
hashnode *p, *limit; hashnode *p, *limit;
@ -268,7 +291,9 @@ ht_dump_statistics (hash_table *table)
p = table->entries; p = table->entries;
limit = p + table->nslots; limit = p + table->nslots;
do do
if (*p) if (*p == DELETED)
++deleted;
else if (*p)
{ {
size_t n = HT_LEN (*p); size_t n = HT_LEN (*p);
@ -290,6 +315,8 @@ ht_dump_statistics (hash_table *table)
(unsigned long) nids, nids * 100.0 / nelts); (unsigned long) nids, nids * 100.0 / nelts);
fprintf (stderr, "slots\t\t%lu\n", fprintf (stderr, "slots\t\t%lu\n",
(unsigned long) table->nslots); (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", fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
SCALE (total_bytes), LABEL (total_bytes), SCALE (total_bytes), LABEL (total_bytes),
SCALE (overhead), LABEL (overhead)); SCALE (overhead), LABEL (overhead));