Commit dae4174e by Tom Tromey Committed by Tom Tromey

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
parent ccbdd3bc
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
......
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
......
...@@ -2357,9 +2357,6 @@ write_types_process_field (type_p f, const struct walk_type_data *d) ...@@ -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, ...@@ -3134,7 +3131,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
oprintf (f, " &%s,\n", name); oprintf (f, " &%s,\n", name);
oprintf (f, " 1, \n"); oprintf (f, " 1, \n");
oprintf (f, " sizeof (%s),\n", v->name); oprintf (f, " sizeof (%s),\n", v->name);
oprintf (f, " &gt_ggc_m_S,\n"); oprintf (f, " (gt_pointer_walker) &gt_ggc_m_S,\n");
oprintf (f, " (gt_pointer_walker) &gt_pch_n_S\n"); oprintf (f, " (gt_pointer_walker) &gt_pch_n_S\n");
oprintf (f, " },\n"); oprintf (f, " },\n");
} }
......
/* 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 ...@@ -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) ...@@ -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) ...@@ -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. */
......
/* "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) ...@@ -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. */
......
/* "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) ...@@ -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, ...@@ -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) ...@@ -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. */
......
/* 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 *); ...@@ -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); ...@@ -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 *); ...@@ -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)
......
/* 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[] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
......
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:
......
/* 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(()) ...@@ -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 *, ...@@ -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);
......
/* 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. ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment