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:
parent
ccbdd3bc4e
commit
dae4174e53
@ -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
|
||||||
|
@ -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
|
||||||
|
161
gcc/cp/mangle.c
161
gcc/cp/mangle.c
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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, " >_ggc_m_S,\n");
|
oprintf (f, " (gt_pointer_walker) >_ggc_m_S,\n");
|
||||||
oprintf (f, " (gt_pointer_walker) >_pch_n_S\n");
|
oprintf (f, " (gt_pointer_walker) >_pch_n_S\n");
|
||||||
oprintf (f, " },\n");
|
oprintf (f, " },\n");
|
||||||
}
|
}
|
||||||
|
@ -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. */
|
||||||
|
@ -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. */
|
||||||
|
151
gcc/ggc-zone.c
151
gcc/ggc-zone.c
@ -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. */
|
||||||
|
13
gcc/ggc.h
13
gcc/ggc.h
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user