+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
+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
/* 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>
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
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 *);
#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. */
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
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
/* 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 "
/* 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
/* 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);
}
{
const char *result;
- start_mangling (type, /*ident_p=*/false);
+ start_mangling (type);
write_type (type);
result = finish_mangling (/*warn=*/false);
if (DEBUG_MANGLE)
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");
/* 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
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");
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.
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');
/* 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
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
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
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);
}
\f
break;
case TYPE_STRING:
- if (wtd->param_prefix == NULL)
- break;
-
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_LANG_STRUCT:
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");
}
/* 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.
/* 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;
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. */
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. */
/* "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.
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. */
/* "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
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. */
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
}
}
+/* 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. */
/* 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.
/* 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);
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);
/* 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)
/* 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.
};
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 *);
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. */
const char *
ggc_alloc_string (const char *contents, int length)
{
+ char *result;
+
if (length == -1)
length = strlen (contents);
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).
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)
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
{
/* Initialize yet another pass. */
+ ggc_protect_identifiers = true;
+
init_cgraph ();
init_final (main_input_filename);
coverage_init (aux_base_name);
if (flag_syntax_only)
return;
+ ggc_protect_identifiers = false;
+
lang_hooks.decls.final_write_globals ();
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>
PR preprocessor/22168:
/* 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
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
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);
/* 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
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
}
/* 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)
{
unsigned int hash2;
unsigned int index;
+ unsigned int deleted_index = table->nslots;
size_t sizemask;
hashnode node;
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. */
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. */
p = table->entries;
limit = p + table->nslots;
do
- if (*p)
+ if (*p && *p != DELETED)
{
unsigned int index, hash, hash2;
p = table->entries;
limit = p + table->nslots;
do
- if (*p)
+ if (*p && *p != DELETED)
{
if ((*cb) (table->pfile, *p, v) == 0)
break;
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,
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;
p = table->entries;
limit = p + table->nslots;
do
- if (*p)
+ if (*p == DELETED)
+ ++deleted;
+ else if (*p)
{
size_t n = HT_LEN (*p);
(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));