mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-14 04:20:25 +08:00
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>
|
||||
|
||||
* 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>
|
||||
|
||||
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.
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
Written by Alex Samuel <samuel@codesourcery.com>
|
||||
|
||||
@ -117,13 +117,6 @@ static struct obstack name_obstack;
|
||||
allocated on the name_obstack. */
|
||||
static void *name_base;
|
||||
|
||||
/* An incomplete mangled name. There will be no NUL terminator. If
|
||||
there is no incomplete mangled name, this variable is NULL. */
|
||||
static char *partially_mangled_name;
|
||||
|
||||
/* The number of characters in the PARTIALLY_MANGLED_NAME. */
|
||||
static size_t partially_mangled_name_len;
|
||||
|
||||
/* Indices into subst_identifiers. These are identifiers used in
|
||||
special substitution rules. */
|
||||
typedef enum
|
||||
@ -217,11 +210,11 @@ static int discriminator_for_string_literal (tree, tree);
|
||||
static void write_discriminator (const int);
|
||||
static void write_local_name (const tree, const tree, const tree);
|
||||
static void dump_substitution_candidates (void);
|
||||
static const char *mangle_decl_string (const tree);
|
||||
static tree mangle_decl_string (const tree);
|
||||
|
||||
/* Control functions. */
|
||||
|
||||
static inline void start_mangling (const tree, bool);
|
||||
static inline void start_mangling (const tree);
|
||||
static inline const char *finish_mangling (const bool);
|
||||
static tree mangle_special_for_type (const tree, const char *);
|
||||
|
||||
@ -259,42 +252,6 @@ static void write_java_integer_type_codes (const tree);
|
||||
#define write_unsigned_number(NUMBER) \
|
||||
write_number ((NUMBER), /*unsigned_p=*/1, 10)
|
||||
|
||||
/* Save the current (incomplete) mangled name and release the obstack
|
||||
storage holding it. This function should be used during mangling
|
||||
when making a call that could result in a call to get_identifier,
|
||||
as such a call will clobber the same obstack being used for
|
||||
mangling. This function may not be called twice without an
|
||||
intervening call to restore_partially_mangled_name. */
|
||||
|
||||
static void
|
||||
save_partially_mangled_name (void)
|
||||
{
|
||||
if (mangle_obstack == &ident_hash->stack)
|
||||
{
|
||||
gcc_assert (!partially_mangled_name);
|
||||
partially_mangled_name_len = obstack_object_size (mangle_obstack);
|
||||
partially_mangled_name = XNEWVEC (char, partially_mangled_name_len);
|
||||
memcpy (partially_mangled_name, obstack_base (mangle_obstack),
|
||||
partially_mangled_name_len);
|
||||
obstack_free (mangle_obstack, obstack_finish (mangle_obstack));
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the incomplete mangled name saved with
|
||||
save_partially_mangled_name. */
|
||||
|
||||
static void
|
||||
restore_partially_mangled_name (void)
|
||||
{
|
||||
if (partially_mangled_name)
|
||||
{
|
||||
obstack_grow (mangle_obstack, partially_mangled_name,
|
||||
partially_mangled_name_len);
|
||||
free (partially_mangled_name);
|
||||
partially_mangled_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If DECL is a template instance, return nonzero and, if
|
||||
TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
|
||||
Otherwise return zero. */
|
||||
@ -743,9 +700,7 @@ write_encoding (const tree decl)
|
||||
|
||||
if (decl_is_template_id (decl, NULL))
|
||||
{
|
||||
save_partially_mangled_name ();
|
||||
fn_type = get_mostly_instantiated_function_type (decl);
|
||||
restore_partially_mangled_name ();
|
||||
/* FN_TYPE will not have parameter types for in-charge or
|
||||
VTT parameters. Therefore, we pass NULL_TREE to
|
||||
write_bare_function_type -- otherwise, it will get
|
||||
@ -1110,9 +1065,7 @@ write_unqualified_name (const tree decl)
|
||||
if (decl_is_template_id (decl, NULL))
|
||||
{
|
||||
tree fn_type;
|
||||
save_partially_mangled_name ();
|
||||
fn_type = get_mostly_instantiated_function_type (decl);
|
||||
restore_partially_mangled_name ();
|
||||
type = TREE_TYPE (fn_type);
|
||||
}
|
||||
else
|
||||
@ -2566,26 +2519,21 @@ write_substitution (const int seq_id)
|
||||
/* Start mangling ENTITY. */
|
||||
|
||||
static inline void
|
||||
start_mangling (const tree entity, const bool ident_p)
|
||||
start_mangling (const tree entity)
|
||||
{
|
||||
G.entity = entity;
|
||||
G.need_abi_warning = false;
|
||||
if (!ident_p)
|
||||
{
|
||||
obstack_free (&name_obstack, name_base);
|
||||
mangle_obstack = &name_obstack;
|
||||
name_base = obstack_alloc (&name_obstack, 0);
|
||||
}
|
||||
else
|
||||
mangle_obstack = &ident_hash->stack;
|
||||
obstack_free (&name_obstack, name_base);
|
||||
mangle_obstack = &name_obstack;
|
||||
name_base = obstack_alloc (&name_obstack, 0);
|
||||
}
|
||||
|
||||
/* Done with mangling. Return the generated mangled name. If WARN is
|
||||
true, and the name of G.entity will be mangled differently in a
|
||||
future version of the ABI, issue a warning. */
|
||||
/* Done with mangling. If WARN is true, and the name of G.entity will
|
||||
be mangled differently in a future version of the ABI, issue a
|
||||
warning. */
|
||||
|
||||
static inline const char *
|
||||
finish_mangling (const bool warn)
|
||||
static void
|
||||
finish_mangling_internal (const bool warn)
|
||||
{
|
||||
if (warn_abi && warn && G.need_abi_warning)
|
||||
warning (OPT_Wabi, "the mangled name of %qD will change in a future "
|
||||
@ -2597,10 +2545,29 @@ finish_mangling (const bool warn)
|
||||
|
||||
/* Null-terminate the string. */
|
||||
write_char ('\0');
|
||||
}
|
||||
|
||||
|
||||
/* Like finish_mangling_internal, but return the mangled string. */
|
||||
|
||||
static inline const char *
|
||||
finish_mangling (const bool warn)
|
||||
{
|
||||
finish_mangling_internal (warn);
|
||||
return (const char *) obstack_finish (mangle_obstack);
|
||||
}
|
||||
|
||||
/* Like finish_mangling_internal, but return an identifier. */
|
||||
|
||||
static tree
|
||||
finish_mangling_get_identifier (const bool warn)
|
||||
{
|
||||
finish_mangling_internal (warn);
|
||||
/* Don't obstack_finish here, and the next start_mangling will
|
||||
remove the identifier. */
|
||||
return get_identifier ((const char *) name_base);
|
||||
}
|
||||
|
||||
/* Initialize data structures for mangling. */
|
||||
|
||||
void
|
||||
@ -2622,41 +2589,31 @@ init_mangle (void)
|
||||
|
||||
/* Generate the mangled name of DECL. */
|
||||
|
||||
static const char *
|
||||
static tree
|
||||
mangle_decl_string (const tree decl)
|
||||
{
|
||||
const char *result;
|
||||
tree result;
|
||||
|
||||
start_mangling (decl, /*ident_p=*/true);
|
||||
start_mangling (decl);
|
||||
|
||||
if (TREE_CODE (decl) == TYPE_DECL)
|
||||
write_type (TREE_TYPE (decl));
|
||||
else
|
||||
write_mangled_name (decl, true);
|
||||
|
||||
result = finish_mangling (/*warn=*/true);
|
||||
result = finish_mangling_get_identifier (/*warn=*/true);
|
||||
if (DEBUG_MANGLE)
|
||||
fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
|
||||
fprintf (stderr, "mangle_decl_string = '%s'\n\n",
|
||||
IDENTIFIER_POINTER (result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Like get_identifier, except that NAME is assumed to have been
|
||||
allocated on the obstack used by the identifier hash table. */
|
||||
|
||||
static inline tree
|
||||
get_identifier_nocopy (const char *name)
|
||||
{
|
||||
hashnode ht_node = ht_lookup (ident_hash, (const unsigned char *) name,
|
||||
strlen (name), HT_ALLOCED);
|
||||
return HT_IDENT_TO_GCC_IDENT (ht_node);
|
||||
}
|
||||
|
||||
/* Create an identifier for the external mangled name of DECL. */
|
||||
|
||||
void
|
||||
mangle_decl (const tree decl)
|
||||
{
|
||||
tree id = get_identifier_nocopy (mangle_decl_string (decl));
|
||||
tree id = mangle_decl_string (decl);
|
||||
id = targetm.mangle_decl_assembler_name (decl, id);
|
||||
SET_DECL_ASSEMBLER_NAME (decl, id);
|
||||
}
|
||||
@ -2668,7 +2625,7 @@ mangle_type_string (const tree type)
|
||||
{
|
||||
const char *result;
|
||||
|
||||
start_mangling (type, /*ident_p=*/false);
|
||||
start_mangling (type);
|
||||
write_type (type);
|
||||
result = finish_mangling (/*warn=*/false);
|
||||
if (DEBUG_MANGLE)
|
||||
@ -2683,11 +2640,11 @@ mangle_type_string (const tree type)
|
||||
static tree
|
||||
mangle_special_for_type (const tree type, const char *code)
|
||||
{
|
||||
const char *result;
|
||||
tree result;
|
||||
|
||||
/* We don't have an actual decl here for the special component, so
|
||||
we can't just process the <encoded-name>. Instead, fake it. */
|
||||
start_mangling (type, /*ident_p=*/true);
|
||||
start_mangling (type);
|
||||
|
||||
/* Start the mangling. */
|
||||
write_string ("_Z");
|
||||
@ -2695,12 +2652,13 @@ mangle_special_for_type (const tree type, const char *code)
|
||||
|
||||
/* Add the type. */
|
||||
write_type (type);
|
||||
result = finish_mangling (/*warn=*/false);
|
||||
result = finish_mangling_get_identifier (/*warn=*/false);
|
||||
|
||||
if (DEBUG_MANGLE)
|
||||
fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
|
||||
fprintf (stderr, "mangle_special_for_type = %s\n\n",
|
||||
IDENTIFIER_POINTER (result));
|
||||
|
||||
return get_identifier_nocopy (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Create an identifier for the mangled representation of the typeinfo
|
||||
@ -2754,9 +2712,9 @@ mangle_vtt_for_type (const tree type)
|
||||
tree
|
||||
mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
|
||||
{
|
||||
const char *result;
|
||||
tree result;
|
||||
|
||||
start_mangling (type, /*ident_p=*/true);
|
||||
start_mangling (type);
|
||||
|
||||
write_string ("_Z");
|
||||
write_string ("TC");
|
||||
@ -2765,10 +2723,11 @@ mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
|
||||
write_char ('_');
|
||||
write_type (BINFO_TYPE (binfo));
|
||||
|
||||
result = finish_mangling (/*warn=*/false);
|
||||
result = finish_mangling_get_identifier (/*warn=*/false);
|
||||
if (DEBUG_MANGLE)
|
||||
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
|
||||
return get_identifier_nocopy (result);
|
||||
fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
|
||||
IDENTIFIER_POINTER (result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Mangle a this pointer or result pointer adjustment.
|
||||
@ -2810,9 +2769,9 @@ tree
|
||||
mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
|
||||
tree virtual_offset)
|
||||
{
|
||||
const char *result;
|
||||
tree result;
|
||||
|
||||
start_mangling (fn_decl, /*ident_p=*/true);
|
||||
start_mangling (fn_decl);
|
||||
|
||||
write_string ("_Z");
|
||||
write_char ('T');
|
||||
@ -2843,10 +2802,10 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
|
||||
/* Scoped name. */
|
||||
write_encoding (fn_decl);
|
||||
|
||||
result = finish_mangling (/*warn=*/false);
|
||||
result = finish_mangling_get_identifier (/*warn=*/false);
|
||||
if (DEBUG_MANGLE)
|
||||
fprintf (stderr, "mangle_thunk = %s\n\n", result);
|
||||
return get_identifier_nocopy (result);
|
||||
fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This hash table maps TYPEs to the IDENTIFIER for a conversion
|
||||
@ -2918,7 +2877,7 @@ mangle_conv_op_name_for_type (const tree type)
|
||||
tree
|
||||
mangle_guard_variable (const tree variable)
|
||||
{
|
||||
start_mangling (variable, /*ident_p=*/true);
|
||||
start_mangling (variable);
|
||||
write_string ("_ZGV");
|
||||
if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
|
||||
/* The name of a guard variable for a reference temporary should refer
|
||||
@ -2926,7 +2885,7 @@ mangle_guard_variable (const tree variable)
|
||||
write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
|
||||
else
|
||||
write_name (variable, /*ignore_local_scope=*/0);
|
||||
return get_identifier_nocopy (finish_mangling (/*warn=*/false));
|
||||
return finish_mangling_get_identifier (/*warn=*/false);
|
||||
}
|
||||
|
||||
/* Return an identifier for the name of a temporary variable used to
|
||||
@ -2936,10 +2895,10 @@ mangle_guard_variable (const tree variable)
|
||||
tree
|
||||
mangle_ref_init_variable (const tree variable)
|
||||
{
|
||||
start_mangling (variable, /*ident_p=*/true);
|
||||
start_mangling (variable);
|
||||
write_string ("_ZGR");
|
||||
write_name (variable, /*ignore_local_scope=*/0);
|
||||
return get_identifier_nocopy (finish_mangling (/*warn=*/false));
|
||||
return finish_mangling_get_identifier (/*warn=*/false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2357,9 +2357,6 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
|
||||
break;
|
||||
|
||||
case TYPE_STRING:
|
||||
if (wtd->param_prefix == NULL)
|
||||
break;
|
||||
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_LANG_STRUCT:
|
||||
@ -3134,7 +3131,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
|
||||
oprintf (f, " &%s,\n", name);
|
||||
oprintf (f, " 1, \n");
|
||||
oprintf (f, " sizeof (%s),\n", v->name);
|
||||
oprintf (f, " >_ggc_m_S,\n");
|
||||
oprintf (f, " (gt_pointer_walker) >_ggc_m_S,\n");
|
||||
oprintf (f, " (gt_pointer_walker) >_pch_n_S\n");
|
||||
oprintf (f, " },\n");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Simple garbage collection for the GNU compiler.
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -50,6 +50,9 @@ along with GCC; see the file COPYING3. If not see
|
||||
/* When set, ggc_collect will do collection. */
|
||||
bool ggc_force_collect;
|
||||
|
||||
/* When true, protect the contents of the identifier hash table. */
|
||||
bool ggc_protect_identifiers = true;
|
||||
|
||||
/* Statistics about the allocation. */
|
||||
static ggc_statistics *ggc_stats;
|
||||
|
||||
@ -103,7 +106,8 @@ ggc_mark_roots (void)
|
||||
for (i = 0; i < rti->nelt; i++)
|
||||
(*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
|
||||
|
||||
ggc_mark_stringpool ();
|
||||
if (ggc_protect_identifiers)
|
||||
ggc_mark_stringpool ();
|
||||
|
||||
/* Now scan all hash tables that have objects which are to be deleted if
|
||||
they are not already marked. */
|
||||
@ -115,6 +119,9 @@ ggc_mark_roots (void)
|
||||
htab_traverse_noresize (*cti->base, ggc_htab_delete, (void *) cti);
|
||||
ggc_set_mark ((*cti->base)->entries);
|
||||
}
|
||||
|
||||
if (! ggc_protect_identifiers)
|
||||
ggc_purge_stringpool ();
|
||||
}
|
||||
|
||||
/* Allocate a block of memory, then clear it. */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* "Bag-of-pages" garbage collector for the GNU compiler.
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -1256,6 +1256,57 @@ ggc_alloc_stat (size_t size MEM_STAT_DECL)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Mark function for strings. */
|
||||
|
||||
void
|
||||
gt_ggc_m_S (const void *p)
|
||||
{
|
||||
page_entry *entry;
|
||||
unsigned bit, word;
|
||||
unsigned long mask;
|
||||
unsigned long offset;
|
||||
|
||||
if (!p || !ggc_allocated_p (p))
|
||||
return;
|
||||
|
||||
/* Look up the page on which the object is alloced. . */
|
||||
entry = lookup_page_table_entry (p);
|
||||
gcc_assert (entry);
|
||||
|
||||
/* Calculate the index of the object on the page; this is its bit
|
||||
position in the in_use_p bitmap. Note that because a char* might
|
||||
point to the middle of an object, we need special code here to
|
||||
make sure P points to the start of an object. */
|
||||
offset = ((const char *) p - entry->page) % object_size_table[entry->order];
|
||||
if (offset)
|
||||
{
|
||||
/* Here we've seen a char* which does not point to the beginning
|
||||
of an allocated object. We assume it points to the middle of
|
||||
a STRING_CST. */
|
||||
gcc_assert (offset == offsetof (struct tree_string, str));
|
||||
p = ((const char *) p) - offset;
|
||||
gt_ggc_mx_lang_tree_node ((void *) p);
|
||||
return;
|
||||
}
|
||||
|
||||
bit = OFFSET_TO_BIT (((const char *) p) - entry->page, entry->order);
|
||||
word = bit / HOST_BITS_PER_LONG;
|
||||
mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
|
||||
|
||||
/* If the bit was previously set, skip it. */
|
||||
if (entry->in_use_p[word] & mask)
|
||||
return;
|
||||
|
||||
/* Otherwise set it, and decrement the free object count. */
|
||||
entry->in_use_p[word] |= mask;
|
||||
entry->num_free_objects -= 1;
|
||||
|
||||
if (GGC_DEBUG_LEVEL >= 4)
|
||||
fprintf (G.debug_file, "Marking %p\n", p);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* If P is not marked, marks it and return false. Otherwise return true.
|
||||
P must have been allocated by the GC allocator; it mustn't point to
|
||||
static objects, stack variables, or memory allocated with malloc. */
|
||||
|
151
gcc/ggc-zone.c
151
gcc/ggc-zone.c
@ -1,5 +1,5 @@
|
||||
/* "Bag-of-pages" zone garbage collector for the GNU compiler.
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
Contributed by Richard Henderson (rth@redhat.com) and Daniel Berlin
|
||||
@ -506,6 +506,47 @@ lookup_page_table_entry (const void *p)
|
||||
return base[L1][L2];
|
||||
}
|
||||
|
||||
/* Traverse the page table and find the entry for a page.
|
||||
Return NULL if the object wasn't allocated via the GC. */
|
||||
|
||||
static inline page_entry *
|
||||
lookup_page_table_if_allocated (const void *p)
|
||||
{
|
||||
page_entry ***base;
|
||||
size_t L1, L2;
|
||||
|
||||
#if HOST_BITS_PER_PTR <= 32
|
||||
base = &G.lookup[0];
|
||||
#else
|
||||
page_table table = G.lookup;
|
||||
size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
|
||||
while (1)
|
||||
{
|
||||
if (table == NULL)
|
||||
return NULL;
|
||||
if (table->high_bits == high_bits)
|
||||
break;
|
||||
table = table->next;
|
||||
}
|
||||
base = &table->table[0];
|
||||
#endif
|
||||
|
||||
/* Extract the level 1 and 2 indices. */
|
||||
L1 = LOOKUP_L1 (p);
|
||||
if (! base[L1])
|
||||
return NULL;
|
||||
|
||||
L2 = LOOKUP_L2 (p);
|
||||
if (L2 >= PAGE_L2_SIZE)
|
||||
return NULL;
|
||||
/* We might have a page entry which does not correspond exactly to a
|
||||
system page. */
|
||||
if (base[L1][L2] && (char *) p < base[L1][L2]->page)
|
||||
return NULL;
|
||||
|
||||
return base[L1][L2];
|
||||
}
|
||||
|
||||
/* Set the page table entry for the page that starts at P. If ENTRY
|
||||
is NULL, clear the entry. */
|
||||
|
||||
@ -680,6 +721,55 @@ zone_find_object_size (struct small_page_entry *page,
|
||||
max_size);
|
||||
}
|
||||
|
||||
/* highest_bit assumes that alloc_type is 32 bits. */
|
||||
extern char check_alloc_type_size[(sizeof (alloc_type) == 4) ? 1 : -1];
|
||||
|
||||
/* Find the highest set bit in VALUE. Returns the bit number of that
|
||||
bit, using the same values as ffs. */
|
||||
static inline alloc_type
|
||||
highest_bit (alloc_type value)
|
||||
{
|
||||
/* This also assumes that alloc_type is unsigned. */
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value = value ^ (value >> 1);
|
||||
return alloc_ffs (value);
|
||||
}
|
||||
|
||||
/* Find the offset from the start of an object to P, which may point
|
||||
into the interior of the object. */
|
||||
|
||||
static unsigned long
|
||||
zone_find_object_offset (alloc_type *alloc_bits, size_t start_word,
|
||||
size_t start_bit)
|
||||
{
|
||||
unsigned int offset_in_bits;
|
||||
alloc_type alloc_word = alloc_bits[start_word];
|
||||
|
||||
/* Mask off any bits after the initial bit, but make sure to include
|
||||
the initial bit in the result. Note that START_BIT is
|
||||
0-based. */
|
||||
if (start_bit < 8 * sizeof (alloc_type) - 1)
|
||||
alloc_word &= (1 << (start_bit + 1)) - 1;
|
||||
offset_in_bits = start_bit;
|
||||
|
||||
/* Search for the start of the object. */
|
||||
while (alloc_word == 0 && start_word > 0)
|
||||
{
|
||||
alloc_word = alloc_bits[--start_word];
|
||||
offset_in_bits += 8 * sizeof (alloc_type);
|
||||
}
|
||||
/* We must always find a set bit. */
|
||||
gcc_assert (alloc_word != 0);
|
||||
/* Note that the result of highest_bit is 1-based. */
|
||||
offset_in_bits -= highest_bit (alloc_word) - 1;
|
||||
|
||||
return BYTES_PER_ALLOC_BIT * offset_in_bits;
|
||||
}
|
||||
|
||||
/* Allocate the mark bits for every zone, and set the pointers on each
|
||||
page. */
|
||||
static void
|
||||
@ -1353,6 +1443,65 @@ ggc_free (void *p)
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark function for strings. */
|
||||
|
||||
void
|
||||
gt_ggc_m_S (const void *p)
|
||||
{
|
||||
page_entry *entry;
|
||||
unsigned long offset;
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
/* Look up the page on which the object is alloced. . */
|
||||
entry = lookup_page_table_if_allocated (p);
|
||||
if (! entry)
|
||||
return;
|
||||
|
||||
if (entry->pch_p)
|
||||
{
|
||||
size_t alloc_word, alloc_bit, t;
|
||||
t = ((const char *) p - pch_zone.page) / BYTES_PER_ALLOC_BIT;
|
||||
alloc_word = t / (8 * sizeof (alloc_type));
|
||||
alloc_bit = t % (8 * sizeof (alloc_type));
|
||||
offset = zone_find_object_offset (pch_zone.alloc_bits, alloc_word,
|
||||
alloc_bit);
|
||||
}
|
||||
else if (entry->large_p)
|
||||
{
|
||||
struct large_page_entry *le = (struct large_page_entry *) entry;
|
||||
offset = ((const char *) p) - entry->page;
|
||||
gcc_assert (offset < le->bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct small_page_entry *se = (struct small_page_entry *) entry;
|
||||
unsigned int start_word = zone_get_object_alloc_word (p);
|
||||
unsigned int start_bit = zone_get_object_alloc_bit (p);
|
||||
offset = zone_find_object_offset (se->alloc_bits, start_word, start_bit);
|
||||
|
||||
/* On some platforms a char* will not necessarily line up on an
|
||||
allocation boundary, so we have to update the offset to
|
||||
account for the leftover bytes. */
|
||||
offset += (size_t) p % BYTES_PER_ALLOC_BIT;
|
||||
}
|
||||
|
||||
if (offset)
|
||||
{
|
||||
/* Here we've seen a char* which does not point to the beginning
|
||||
of an allocated object. We assume it points to the middle of
|
||||
a STRING_CST. */
|
||||
gcc_assert (offset == offsetof (struct tree_string, str));
|
||||
p = ((const char *) p) - offset;
|
||||
gt_ggc_mx_lang_tree_node ((void *) p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Inefficient, but also unlikely to matter. */
|
||||
ggc_set_mark (p);
|
||||
}
|
||||
|
||||
/* If P is not marked, mark it and return false. Otherwise return true.
|
||||
P must have been allocated by the GC allocator; it mustn't point to
|
||||
static objects, stack variables, or memory allocated with malloc. */
|
||||
|
13
gcc/ggc.h
13
gcc/ggc.h
@ -1,5 +1,5 @@
|
||||
/* Garbage collection for the GNU compiler.
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -120,6 +120,9 @@ extern int ggc_marked_p (const void *);
|
||||
/* Mark the entries in the string pool. */
|
||||
extern void ggc_mark_stringpool (void);
|
||||
|
||||
/* Purge the entries in the string pool. */
|
||||
extern void ggc_purge_stringpool (void);
|
||||
|
||||
/* Call ggc_set_mark on all the roots. */
|
||||
|
||||
extern void ggc_mark_roots (void);
|
||||
@ -134,7 +137,7 @@ extern void gt_pch_restore_stringpool (void);
|
||||
|
||||
extern void gt_pch_p_S (void *, void *, gt_pointer_operator, void *);
|
||||
extern void gt_pch_n_S (const void *);
|
||||
extern void gt_ggc_m_S (void *);
|
||||
extern void gt_ggc_m_S (const void *);
|
||||
|
||||
/* Initialize the string pool. */
|
||||
extern void init_stringpool (void);
|
||||
@ -200,6 +203,12 @@ extern void ggc_pch_read (FILE *, void *);
|
||||
/* When set, ggc_collect will do collection. */
|
||||
extern bool ggc_force_collect;
|
||||
|
||||
/* When true, identifier nodes are considered as GC roots. When
|
||||
false, identifier nodes are treated like any other GC-allocated
|
||||
object, and the identifier hash table is treated as a weak
|
||||
hash. */
|
||||
extern bool ggc_protect_identifiers;
|
||||
|
||||
/* The internal primitive. */
|
||||
extern void *ggc_alloc_stat (size_t MEM_STAT_DECL);
|
||||
#define ggc_alloc(s) ggc_alloc_stat (s MEM_STAT_INFO)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* String pool for GCC.
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
|
||||
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
@ -47,7 +47,6 @@ const char digit_vector[] = {
|
||||
};
|
||||
|
||||
struct ht *ident_hash;
|
||||
static struct obstack string_stack;
|
||||
|
||||
static hashnode alloc_node (hash_table *);
|
||||
static int mark_ident (struct cpp_reader *, hashnode, const void *);
|
||||
@ -66,7 +65,6 @@ init_stringpool (void)
|
||||
ident_hash = ht_create (14);
|
||||
ident_hash->alloc_node = alloc_node;
|
||||
ident_hash->alloc_subobject = stringpool_ggc_alloc;
|
||||
gcc_obstack_init (&string_stack);
|
||||
}
|
||||
|
||||
/* Allocate a hash node. */
|
||||
@ -85,6 +83,8 @@ alloc_node (hash_table *table ATTRIBUTE_UNUSED)
|
||||
const char *
|
||||
ggc_alloc_string (const char *contents, int length)
|
||||
{
|
||||
char *result;
|
||||
|
||||
if (length == -1)
|
||||
length = strlen (contents);
|
||||
|
||||
@ -93,8 +93,9 @@ ggc_alloc_string (const char *contents, int length)
|
||||
if (length == 1 && ISDIGIT (contents[0]))
|
||||
return digit_string (contents[0] - '0');
|
||||
|
||||
obstack_grow0 (&string_stack, contents, length);
|
||||
return XOBFINISH (&string_stack, const char *);
|
||||
result = ggc_alloc (length + 1);
|
||||
memcpy (result, contents, length + 1);
|
||||
return (const char *) result;
|
||||
}
|
||||
|
||||
/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
|
||||
@ -163,9 +164,18 @@ mark_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return true if an identifier should be removed from the table. */
|
||||
|
||||
static int
|
||||
maybe_delete_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
|
||||
const void *v ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return !ggc_marked_p (HT_IDENT_TO_GCC_IDENT (h));
|
||||
}
|
||||
|
||||
/* Mark the trees hanging off the identifier node for GGC. These are
|
||||
handled specially (not using gengtype) because of the special
|
||||
treatment for strings. */
|
||||
handled specially (not using gengtype) because identifiers are only
|
||||
roots during one part of compilation. */
|
||||
|
||||
void
|
||||
ggc_mark_stringpool (void)
|
||||
@ -173,13 +183,13 @@ ggc_mark_stringpool (void)
|
||||
ht_forall (ident_hash, mark_ident, NULL);
|
||||
}
|
||||
|
||||
/* Strings are _not_ GCed, but this routine exists so that a separate
|
||||
roots table isn't needed for the few global variables that refer
|
||||
to strings. */
|
||||
/* Purge the identifier hash of identifiers which are no longer
|
||||
referenced. */
|
||||
|
||||
void
|
||||
gt_ggc_m_S (void *x ATTRIBUTE_UNUSED)
|
||||
ggc_purge_stringpool (void)
|
||||
{
|
||||
ht_purge (ident_hash, maybe_delete_ident, NULL);
|
||||
}
|
||||
|
||||
/* Pointer-walking routine for strings (not very interesting, since
|
||||
|
@ -951,6 +951,8 @@ compile_file (void)
|
||||
{
|
||||
/* Initialize yet another pass. */
|
||||
|
||||
ggc_protect_identifiers = true;
|
||||
|
||||
init_cgraph ();
|
||||
init_final (main_input_filename);
|
||||
coverage_init (aux_base_name);
|
||||
@ -969,6 +971,8 @@ compile_file (void)
|
||||
if (flag_syntax_only)
|
||||
return;
|
||||
|
||||
ggc_protect_identifiers = false;
|
||||
|
||||
lang_hooks.decls.final_write_globals ();
|
||||
|
||||
if (errorcount || sorrycount)
|
||||
|
@ -1,3 +1,16 @@
|
||||
2008-05-21 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* include/symtab.h (HT_ALLOCED): Remove.
|
||||
(ht_purge): Declare.
|
||||
* symtab.c (DELETED): New define.
|
||||
(ht_lookup): Update comment.
|
||||
(ht_lookup_with_hash): Handle deleted entries. Remove HT_ALLOCED
|
||||
code. Use subobject allocator for strings, if it exists.
|
||||
(ht_expand): Handle deleted entries.
|
||||
(ht_forall): Likewise.
|
||||
(ht_purge): New function.
|
||||
(ht_dump_statistics): Print deletion statistics.
|
||||
|
||||
2008-05-13 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
PR preprocessor/22168:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Hash tables.
|
||||
Copyright (C) 2000, 2001, 2003, 2004, 2007 Free Software Foundation, Inc.
|
||||
Copyright (C) 2000, 2001, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@ -39,7 +39,7 @@ struct ht_identifier GTY(())
|
||||
typedef struct ht hash_table;
|
||||
typedef struct ht_identifier *hashnode;
|
||||
|
||||
enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED};
|
||||
enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC};
|
||||
|
||||
/* An identifier hash table for cpplib and the front ends. */
|
||||
struct ht
|
||||
@ -88,6 +88,10 @@ extern hashnode ht_lookup_with_hash (hash_table *, const unsigned char *,
|
||||
typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
|
||||
extern void ht_forall (hash_table *, ht_cb, const void *);
|
||||
|
||||
/* For all nodes in TABLE, call the callback. If the callback returns
|
||||
a nonzero value, the node is removed from the table. */
|
||||
extern void ht_purge (hash_table *, ht_cb, const void *);
|
||||
|
||||
/* Restore the hash table. */
|
||||
extern void ht_load (hash_table *ht, hashnode *entries,
|
||||
unsigned int nslots, unsigned int nelements, bool own);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Hash tables.
|
||||
Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||
Copyright (C) 2000, 2001, 2003, 2004, 2008 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
@ -27,13 +27,15 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
hash tables (see libiberty/hashtab.c). The abstraction penalty was
|
||||
too high to continue using the generic form. This code knows
|
||||
intrinsically how to calculate a hash value, and how to compare an
|
||||
existing entry with a potential new one. Also, the ability to
|
||||
delete members from the table has been removed. */
|
||||
existing entry with a potential new one. */
|
||||
|
||||
static unsigned int calc_hash (const unsigned char *, size_t);
|
||||
static void ht_expand (hash_table *);
|
||||
static double approx_sqrt (double);
|
||||
|
||||
/* A deleted entry. */
|
||||
#define DELETED ((hashnode) -1)
|
||||
|
||||
/* Calculate the hash of the string STR of length LEN. */
|
||||
|
||||
static unsigned int
|
||||
@ -83,13 +85,10 @@ ht_destroy (hash_table *table)
|
||||
}
|
||||
|
||||
/* Returns the hash entry for the a STR of length LEN. If that string
|
||||
already exists in the table, returns the existing entry, and, if
|
||||
INSERT is CPP_ALLOCED, frees the last obstack object. If the
|
||||
already exists in the table, returns the existing entry. If the
|
||||
identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
|
||||
returns NULL. Otherwise insert and returns a new entry. A new
|
||||
string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is
|
||||
CPP_ALLOCED and the item is assumed to be at the top of the
|
||||
obstack. */
|
||||
string is allocated. */
|
||||
hashnode
|
||||
ht_lookup (hash_table *table, const unsigned char *str, size_t len,
|
||||
enum ht_lookup_option insert)
|
||||
@ -105,6 +104,7 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
|
||||
{
|
||||
unsigned int hash2;
|
||||
unsigned int index;
|
||||
unsigned int deleted_index = table->nslots;
|
||||
size_t sizemask;
|
||||
hashnode node;
|
||||
|
||||
@ -113,19 +113,15 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
|
||||
table->searches++;
|
||||
|
||||
node = table->entries[index];
|
||||
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
if (node->hash_value == hash
|
||||
&& HT_LEN (node) == (unsigned int) len
|
||||
&& !memcmp (HT_STR (node), str, len))
|
||||
{
|
||||
if (insert == HT_ALLOCED)
|
||||
/* The string we search for was placed at the end of the
|
||||
obstack. Release it. */
|
||||
obstack_free (&table->stack, (void *) str);
|
||||
return node;
|
||||
}
|
||||
if (node == DELETED)
|
||||
deleted_index = index;
|
||||
else if (node->hash_value == hash
|
||||
&& HT_LEN (node) == (unsigned int) len
|
||||
&& !memcmp (HT_STR (node), str, len))
|
||||
return node;
|
||||
|
||||
/* hash2 must be odd, so we're guaranteed to visit every possible
|
||||
location in the table during rehashing. */
|
||||
@ -139,32 +135,41 @@ ht_lookup_with_hash (hash_table *table, const unsigned char *str,
|
||||
if (node == NULL)
|
||||
break;
|
||||
|
||||
if (node->hash_value == hash
|
||||
&& HT_LEN (node) == (unsigned int) len
|
||||
&& !memcmp (HT_STR (node), str, len))
|
||||
if (node == DELETED)
|
||||
{
|
||||
if (insert == HT_ALLOCED)
|
||||
/* The string we search for was placed at the end of the
|
||||
obstack. Release it. */
|
||||
obstack_free (&table->stack, (void *) str);
|
||||
return node;
|
||||
if (deleted_index != table->nslots)
|
||||
deleted_index = index;
|
||||
}
|
||||
else if (node->hash_value == hash
|
||||
&& HT_LEN (node) == (unsigned int) len
|
||||
&& !memcmp (HT_STR (node), str, len))
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert == HT_NO_INSERT)
|
||||
return NULL;
|
||||
|
||||
/* We prefer to overwrite the first deleted slot we saw. */
|
||||
if (deleted_index != table->nslots)
|
||||
index = deleted_index;
|
||||
|
||||
node = (*table->alloc_node) (table);
|
||||
table->entries[index] = node;
|
||||
|
||||
HT_LEN (node) = (unsigned int) len;
|
||||
node->hash_value = hash;
|
||||
if (insert == HT_ALLOC)
|
||||
HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
|
||||
str, len);
|
||||
|
||||
if (table->alloc_subobject)
|
||||
{
|
||||
char *chars = table->alloc_subobject (len + 1);
|
||||
memcpy (chars, str, len);
|
||||
chars[len] = '\0';
|
||||
HT_STR (node) = (const unsigned char *) chars;
|
||||
}
|
||||
else
|
||||
HT_STR (node) = str;
|
||||
HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
|
||||
str, len);
|
||||
|
||||
if (++table->nelements * 4 >= table->nslots * 3)
|
||||
/* Must expand the string table. */
|
||||
@ -188,7 +193,7 @@ ht_expand (hash_table *table)
|
||||
p = table->entries;
|
||||
limit = p + table->nslots;
|
||||
do
|
||||
if (*p)
|
||||
if (*p && *p != DELETED)
|
||||
{
|
||||
unsigned int index, hash, hash2;
|
||||
|
||||
@ -225,7 +230,7 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
|
||||
p = table->entries;
|
||||
limit = p + table->nslots;
|
||||
do
|
||||
if (*p)
|
||||
if (*p && *p != DELETED)
|
||||
{
|
||||
if ((*cb) (table->pfile, *p, v) == 0)
|
||||
break;
|
||||
@ -233,6 +238,24 @@ ht_forall (hash_table *table, ht_cb cb, const void *v)
|
||||
while (++p < limit);
|
||||
}
|
||||
|
||||
/* Like ht_forall, but a nonzero return from the callback means that
|
||||
the entry should be removed from the table. */
|
||||
void
|
||||
ht_purge (hash_table *table, ht_cb cb, const void *v)
|
||||
{
|
||||
hashnode *p, *limit;
|
||||
|
||||
p = table->entries;
|
||||
limit = p + table->nslots;
|
||||
do
|
||||
if (*p && *p != DELETED)
|
||||
{
|
||||
if ((*cb) (table->pfile, *p, v))
|
||||
*p = DELETED;
|
||||
}
|
||||
while (++p < limit);
|
||||
}
|
||||
|
||||
/* Restore the hash table. */
|
||||
void
|
||||
ht_load (hash_table *ht, hashnode *entries,
|
||||
@ -253,7 +276,7 @@ void
|
||||
ht_dump_statistics (hash_table *table)
|
||||
{
|
||||
size_t nelts, nids, overhead, headers;
|
||||
size_t total_bytes, longest;
|
||||
size_t total_bytes, longest, deleted = 0;
|
||||
double sum_of_squares, exp_len, exp_len2, exp2_len;
|
||||
hashnode *p, *limit;
|
||||
|
||||
@ -268,7 +291,9 @@ ht_dump_statistics (hash_table *table)
|
||||
p = table->entries;
|
||||
limit = p + table->nslots;
|
||||
do
|
||||
if (*p)
|
||||
if (*p == DELETED)
|
||||
++deleted;
|
||||
else if (*p)
|
||||
{
|
||||
size_t n = HT_LEN (*p);
|
||||
|
||||
@ -290,6 +315,8 @@ ht_dump_statistics (hash_table *table)
|
||||
(unsigned long) nids, nids * 100.0 / nelts);
|
||||
fprintf (stderr, "slots\t\t%lu\n",
|
||||
(unsigned long) table->nslots);
|
||||
fprintf (stderr, "deleted\t\t%lu\n",
|
||||
(unsigned long) deleted);
|
||||
fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
|
||||
SCALE (total_bytes), LABEL (total_bytes),
|
||||
SCALE (overhead), LABEL (overhead));
|
||||
|
Loading…
x
Reference in New Issue
Block a user