diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9ebf3410540..822d9c1e96e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2008-05-21 Tom Tromey + + * 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) : Remove + special case. + (write_root): Cast gt_ggc_m_S to gt_pointer_walker. + 2008-05-21 David S. Miller * config.gcc (sparc-*-linux*): Always include sparc/t-linux in diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 49f91bab0cf..d6787157f0e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2008-05-21 Tom Tromey + + * 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 PR c++/35331 diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 5ac5bcee04e..b23e781e99d 100644 --- a/gcc/cp/mangle.c +++ b/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 @@ -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 . 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); } diff --git a/gcc/gengtype.c b/gcc/gengtype.c index aef52e2cdca..62cac240011 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -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"); } diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 8e67f760b5c..17c1f50b608 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -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. */ diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index ea637b1b63c..f22ddf6e826 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -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. */ diff --git a/gcc/ggc-zone.c b/gcc/ggc-zone.c index e8185a06381..af211ad90dc 100644 --- a/gcc/ggc-zone.c +++ b/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. */ diff --git a/gcc/ggc.h b/gcc/ggc.h index e70afcf1dd9..03f534faaa5 100644 --- a/gcc/ggc.h +++ b/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) diff --git a/gcc/stringpool.c b/gcc/stringpool.c index d2e1ad3c32d..cc2dd35368d 100644 --- a/gcc/stringpool.c +++ b/gcc/stringpool.c @@ -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 diff --git a/gcc/toplev.c b/gcc/toplev.c index 3a2590ade83..a35c105160e 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -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) diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index fc226b452bb..58632e3f548 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,16 @@ +2008-05-21 Tom Tromey + + * 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 PR preprocessor/22168: diff --git a/libcpp/include/symtab.h b/libcpp/include/symtab.h index 2bd45cf7f19..c016be3755b 100644 --- a/libcpp/include/symtab.h +++ b/libcpp/include/symtab.h @@ -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); diff --git a/libcpp/symtab.c b/libcpp/symtab.c index ffa28f5f7a5..5414ff05fc9 100644 --- a/libcpp/symtab.c +++ b/libcpp/symtab.c @@ -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));