This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: identifier GC, take 2


Here is a rewrite of my identifier GC patch.

This patch is much simpler.  Rather than tack the identifier's string
contents onto the end of the tree, I simply allocate them separately.
This loses a bit of memory compared to the other approach (a pointer
plus wastage from alignment), but is simpler to understand.

I replaced the previous bogus libcpp re-hashing hack with real
deletion support for the identifier table.  Since I did not need the
ability to delete single elements I made this accessible only via an
ht_forall-like method.

I timed this building both libstdc++ and cc1.  In each case the time
difference was in the noise.

Richard and Mark asked me to look at memory use differences, due to
the cp/mangle.c change.  I did not look at that, because I think I
have come up with a simple explanation for why it will not matter.
The former mangling code would sometimes construct an identifier's
contents on the (now removed) identifier obstack.  The new code
instead copies that string into GC-allocated memory, and clears the
obstack.  We don't ever make an identifier tree in a situation where
we did not previously make one.  So, alignment wastage aside, we will
never use more memory with the new code.  (In fact I think the
alignment wastage is the only additional memory we will use anywhere
-- we're just moving the string data from an obstack to the GC heap.)

I also did not try to re-measure memory savings due to identifier
collection.  On my branch when compiling one of my standard test cases
(Gnome's zenity), I saw collections of 200k of identifier memory.  I
am reasonably sure there are savings for other programs as well; it is
an unusual program where every created identifier remains live
throughout compilation.

Note that I did not update the zone allocator, only ggc-page.c.
Is anyone using the zone allocator?  I could fix it if need be.

Bootstrapped and regtested on the compile farm (x86-64).
Ok?

Tom

libcpp/ChangeLog:
2008-04-04  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.

gcc/ChangeLog:
2008-04-04  Tom Tromey  <tromey@redhat.com>

	* 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_mark_stringpool): Add 'marking' argument.  Purge hash table
	when asked.
	(gt_ggc_m_S): Remove.
	* ggc-common.c (ggc_protect_identifiers): New global.
	(ggc_mark_roots): Update calls to ggc_mark_stringpool.
	* ggc.h (ggc_protect_identifiers): Declare.
	(ggc_mark_stringpool): Update.
	(gt_ggc_m_S): Update.
	* 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/ChangeLog:
2008-03-14  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.

Index: libcpp/symtab.c
===================================================================
--- libcpp/symtab.c	(revision 133869)
+++ libcpp/symtab.c	(working copy)
@@ -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 @@
    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 @@
 }
 
 /* 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 @@
 {
   unsigned int hash2;
   unsigned int index;
+  unsigned int deleted_index = table->nslots;
   size_t sizemask;
   hashnode node;
 
@@ -113,19 +113,15 @@
   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 @@
 	  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)
+
+  if (table->alloc_subobject)
+    {
+      char *chars = table->alloc_subobject (len + 1);
+      strncpy ((char *) chars, (char *) str, len);
+      chars[len] = '\0';
+      HT_STR (node) = (const unsigned char *) chars;
+    }
+  else
     HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
-                                                           str, len);
-  else
-    HT_STR (node) = str;
+							   str, len);
 
   if (++table->nelements * 4 >= table->nslots * 3)
     /* Must expand the string table.  */
@@ -188,7 +193,7 @@
   p = table->entries;
   limit = p + table->nslots;
   do
-    if (*p)
+    if (*p && *p != DELETED)
       {
 	unsigned int index, hash, hash2;
 
@@ -225,7 +230,7 @@
   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 @@
   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 @@
 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 @@
   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 @@
 	   (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));
Index: libcpp/include/symtab.h
===================================================================
--- libcpp/include/symtab.h	(revision 133869)
+++ libcpp/include/symtab.h	(working copy)
@@ -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 @@
 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 @@
 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);
Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 133869)
+++ gcc/gengtype.c	(working copy)
@@ -2355,9 +2355,6 @@
       break;
 
     case TYPE_STRING:
-      if (wtd->param_prefix == NULL)
-	break;
-
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
@@ -3101,7 +3098,7 @@
 	oprintf (f, "    &%s,\n", name);
 	oprintf (f, "    1, \n");
 	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, "  },\n");
       }
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 133869)
+++ gcc/toplev.c	(working copy)
@@ -951,6 +951,8 @@
 {
   /* Initialize yet another pass.  */
 
+  ggc_protect_identifiers = true;
+
   init_cgraph ();
   init_final (main_input_filename);
   coverage_init (aux_base_name);
@@ -968,6 +970,8 @@
   if (flag_syntax_only)
     return;
 
+  ggc_protect_identifiers = false;
+
   lang_hooks.decls.final_write_globals ();
 
   if (errorcount || sorrycount)
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 133869)
+++ gcc/cp/mangle.c	(working copy)
@@ -1,5 +1,5 @@
 /* Name mangling for the 3.0 C++ ABI.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
    Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>
 
@@ -117,13 +117,6 @@
    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 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 @@
 #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 @@
 
       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 @@
       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
@@ -2562,26 +2515,21 @@
 /* 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 "
@@ -2593,10 +2541,29 @@
 
   /* 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
@@ -2618,41 +2585,31 @@
 
 /* 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);
 }
@@ -2664,7 +2621,7 @@
 {
   const char *result;
 
-  start_mangling (type, /*ident_p=*/false);
+  start_mangling (type);
   write_type (type);
   result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
@@ -2679,11 +2636,11 @@
 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");
@@ -2691,12 +2648,13 @@
 
   /* 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
@@ -2750,9 +2708,9 @@
 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");
@@ -2761,10 +2719,11 @@
   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.
@@ -2806,9 +2765,9 @@
 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');
@@ -2839,10 +2798,10 @@
   /* 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
@@ -2914,7 +2873,7 @@
 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
@@ -2922,7 +2881,7 @@
     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
@@ -2932,10 +2891,10 @@
 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);
 }
 
 
Index: gcc/ggc.h
===================================================================
--- gcc/ggc.h	(revision 133869)
+++ gcc/ggc.h	(working copy)
@@ -118,7 +118,7 @@
 extern int ggc_marked_p	(const void *);
 
 /* Mark the entries in the string pool.  */
-extern void ggc_mark_stringpool	(void);
+extern void ggc_mark_stringpool	(bool);
 
 /* Call ggc_set_mark on all the roots.  */
 
@@ -134,7 +134,7 @@
 
 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 +200,9 @@
 /* When set, ggc_collect will do collection.  */
 extern bool ggc_force_collect;
 
+/* When true, protect the contents of the identifier hash table.  */
+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)
Index: gcc/ggc-common.c
===================================================================
--- gcc/ggc-common.c	(revision 133869)
+++ gcc/ggc-common.c	(working copy)
@@ -50,6 +50,9 @@
 /* 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 @@
       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 (true);
 
   /* Now scan all hash tables that have objects which are to be deleted if
      they are not already marked.  */
@@ -115,6 +119,9 @@
 	  htab_traverse_noresize (*cti->base, ggc_htab_delete, (void *) cti);
 	  ggc_set_mark ((*cti->base)->entries);
 	}
+
+  if (! ggc_protect_identifiers)
+    ggc_mark_stringpool (false);
 }
 
 /* Allocate a block of memory, then clear it.  */
Index: gcc/stringpool.c
===================================================================
--- gcc/stringpool.c	(revision 133869)
+++ gcc/stringpool.c	(working copy)
@@ -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 @@
 };
 
 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 @@
   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 @@
 const char *
 ggc_alloc_string (const char *contents, int length)
 {
+  char *result;
+
   if (length == -1)
     length = strlen (contents);
 
@@ -93,8 +93,9 @@
   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,23 +164,26 @@
   return 1;
 }
 
-/* Mark the trees hanging off the identifier node for GGC.  These are
-   handled specially (not using gengtype) because of the special
-   treatment for strings.  */
+/* Return true if an identifier should be removed from the table.  */
 
-void
-ggc_mark_stringpool (void)
+static int
+maybe_delete_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
+		    const void *v ATTRIBUTE_UNUSED)
 {
-  ht_forall (ident_hash, mark_ident, NULL);
+  return !ggc_marked_p (HT_IDENT_TO_GCC_IDENT (h));
 }
 
-/* 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.  */
+/* Mark the trees hanging off the identifier node for GGC.  These are
+   handled specially (not using gengtype) because identifiers are only
+   roots during one part of compilation.  */
 
 void
-gt_ggc_m_S (void *x ATTRIBUTE_UNUSED)
+ggc_mark_stringpool (bool marking)
 {
+  if (marking)
+    ht_forall (ident_hash, mark_ident, NULL);
+  else
+    ht_purge (ident_hash, maybe_delete_ident, NULL);
 }
 
 /* Pointer-walking routine for strings (not very interesting, since
Index: gcc/ggc-page.c
===================================================================
--- gcc/ggc-page.c	(revision 133869)
+++ gcc/ggc-page.c	(working copy)
@@ -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,55 @@
   return result;
 }
 
+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.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]