OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / stringpool.c
index 0346dcf..d8d66f2 100644 (file)
@@ -1,41 +1,39 @@
 /* String pool for GCC.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
-/* String pool allocator.  All strings allocated by ggc_alloc_string are
-   uniquified and stored in an obstack which is never shrunk.  You can
-   associate a tree with a string if you wish; this is used to implement
-   get_identifier.
+/* String text, identifier text and identifier node allocator.
+   Identifiers are uniquely stored in a hash table.
 
-   We have our own private hash table implementation which is similar
-   to the one in cpphash.c (actually, it's a further refinement of
-   that code).  libiberty's hashtab.c is not used because it requires
-   100% average space overhead per string, which is unacceptable.
-   Also, this algorithm is faster.  */
+   We use cpplib's hash table implementation.  libiberty's
+   hashtab.c is not used because it requires 100% average space
+   overhead per string, which is unacceptable.  Also, this algorithm
+   is faster.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "ggc.h"
 #include "tree.h"
-#include "obstack.h"
-#include "flags.h"
-#include "toplev.h"
+#include "symtab.h"
+#include "cpplib.h"
 
 /* The "" allocated string.  */
 const char empty_string[] = "";
@@ -47,350 +45,217 @@ const char digit_vector[] = {
   '5', 0, '6', 0, '7', 0, '8', 0, '9', 0
 };
 
-static struct obstack string_stack;
+struct ht *ident_hash;
 
-/* Each hashnode is just a pointer to a TREE_IDENTIFIER.  */
-typedef struct tree_identifier *sp_hashnode;
+static hashnode alloc_node (hash_table *);
+static int mark_ident (struct cpp_reader *, hashnode, const void *);
 
-#define SP_EMPTY(NODE) ((NODE) == NULL)
-#define SP_LEN(NODE) ((NODE)->length)
-#define SP_TREE(NODE) ((tree) NODE)
-#define SP_STR(NODE) ((NODE)->pointer)
-#define SP_VALID(NODE) (TREE_CODE (SP_TREE (NODE)) == IDENTIFIER_NODE)
+static void *
+stringpool_ggc_alloc (size_t x)
+{
+  return ggc_alloc (x);
+}
 
-/* This is the hash table structure.  There's only one.  */
-struct str_hash
+/* Initialize the string pool.  */
+void
+init_stringpool (void)
 {
-  sp_hashnode *entries;
-  size_t nslots;       /* total slots in the entries array */
-  size_t nelements;    /* number of live elements */
+  /* Create with 16K (2^14) entries.  */
+  ident_hash = ht_create (14);
+  ident_hash->alloc_node = alloc_node;
+  ident_hash->alloc_subobject = stringpool_ggc_alloc;
+}
 
-  /* table usage statistics */
-  unsigned int searches;
-  unsigned int collisions;
-};
-#define INITIAL_HASHSIZE (16*1024)
+/* Allocate a hash node.  */
+static hashnode
+alloc_node (hash_table *table ATTRIBUTE_UNUSED)
+{
+  return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
+}
 
-static struct str_hash string_hash = { 0, INITIAL_HASHSIZE, 0, 0, 0 };
+/* Allocate and return a string constant of length LENGTH, containing
+   CONTENTS.  If LENGTH is -1, CONTENTS is assumed to be a
+   nul-terminated string, and the length is calculated using strlen.  */
 
-enum insert_option { INSERT, NO_INSERT };
+const char *
+ggc_alloc_string (const char *contents, int length)
+{
+  char *result;
 
-static sp_hashnode alloc_ident PARAMS ((const char *, size_t,
-                                       enum insert_option));
-static inline unsigned int calc_hash PARAMS ((const unsigned char *, size_t));
-static void mark_string_hash PARAMS ((void *));
-static void expand_string_table PARAMS ((void));
+  if (length == -1)
+    length = strlen (contents);
 
-/* Convenience macro for iterating over the hash table.  E is set to
-   each live entry in turn.  */
-#define FORALL_IDS(E) \
-for (E = string_hash.entries; E < string_hash.entries+string_hash.nslots; E++) \
-  if (!SP_EMPTY (*E) && SP_VALID (*E))
+  if (length == 0)
+    return empty_string;
+  if (length == 1 && ISDIGIT (contents[0]))
+    return digit_string (contents[0] - '0');
 
-/* 0 while creating built-in identifiers.  */
-static int do_identifier_warnings;
+  result = GGC_NEWVAR (char, length + 1);
+  memcpy (result, contents, length);
+  result[length] = '\0';
+  return (const char *) result;
+}
 
-/* Initialize the string pool.  */
-void
-init_stringpool ()
+/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
+   If an identifier with that name has previously been referred to,
+   the same node is returned this time.  */
+
+#undef get_identifier
+
+tree
+get_identifier (const char *text)
 {
-  gcc_obstack_init (&string_stack);
-  ggc_add_root (&string_hash, 1, sizeof string_hash, mark_string_hash);
+  hashnode ht_node = ht_lookup (ident_hash,
+                               (const unsigned char *) text,
+                               strlen (text), HT_ALLOC);
+
+  /* ht_node can't be NULL here.  */
+  return HT_IDENT_TO_GCC_IDENT (ht_node);
+}
 
-  /* Strings need no alignment.  */
-  obstack_alignment_mask (&string_stack) = 0;
+/* Identical to get_identifier, except that the length is assumed
+   known.  */
 
-  string_hash.entries = (sp_hashnode *)
-    xcalloc (string_hash.nslots, sizeof (sp_hashnode));
+tree
+get_identifier_with_length (const char *text, size_t length)
+{
+  hashnode ht_node = ht_lookup (ident_hash,
+                               (const unsigned char *) text,
+                               length, HT_ALLOC);
+
+  /* ht_node can't be NULL here.  */
+  return HT_IDENT_TO_GCC_IDENT (ht_node);
 }
 
-/* Enable warnings on similar identifiers (if requested).
-   Done after the built-in identifiers are created.  */
-void
-start_identifier_warnings ()
+/* If an identifier with the name TEXT (a null-terminated string) has
+   previously been referred to, return that node; otherwise return
+   NULL_TREE.  */
+
+tree
+maybe_get_identifier (const char *text)
 {
-  do_identifier_warnings = 1;
+  hashnode ht_node;
+
+  ht_node = ht_lookup (ident_hash, (const unsigned char *) text,
+                      strlen (text), HT_NO_INSERT);
+  if (ht_node)
+    return HT_IDENT_TO_GCC_IDENT (ht_node);
+
+  return NULL_TREE;
 }
 
-/* Record the size of an identifier node for the language in use.
-   SIZE is the total size in bytes.
-   This is called by the language-specific files.  This must be
-   called before allocating any identifiers.  */
+/* Report some basic statistics about the string pool.  */
+
 void
-set_identifier_size (size)
-     int size;
+stringpool_statistics (void)
 {
-  tree_code_length[(int) IDENTIFIER_NODE]
-    = (size - sizeof (struct tree_common)) / sizeof (tree);
+  ht_dump_statistics (ident_hash);
 }
+\f
+/* Mark an identifier for GC.  */
 
-/* Calculate the hash of the string STR, which is of length LEN.  */
-static inline unsigned int
-calc_hash (str, len)
-     const unsigned char *str;
-     size_t len;
+static int
+mark_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
+           const void *v ATTRIBUTE_UNUSED)
 {
-  size_t n = len;
-  unsigned int r = 0;
-#define HASHSTEP(r, c) ((r) * 67 + (c - 113));
-
-  while (n--)
-    r = HASHSTEP (r, *str++);
-
-  return r + len;
-#undef HASHSTEP
+  gt_ggc_m_9tree_node (HT_IDENT_TO_GCC_IDENT (h));
+  return 1;
 }
 
-/* Internal primitive: returns the header structure for the identifier
-   of length LENGTH, containing CONTENTS.  If that identifier already
-   exists in the table, returns the existing entry.  If the identifier
-   hasn't been seen before and the last argument is INSERT, inserts
-   and returns a new entry. Otherwise returns NULL.  */
-static sp_hashnode
-alloc_ident (contents, length, insert)
-     const char *contents;
-     size_t length;
-     enum insert_option insert;
+/* 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)
 {
-  unsigned int hash = calc_hash ((const unsigned char *)contents, length);
-  unsigned int hash2;
-  unsigned int index;
-  size_t sizemask;
-  sp_hashnode entry;
-
-  sizemask = string_hash.nslots - 1;
-  index = hash & sizemask;
-
-  /* hash2 must be odd, so we're guaranteed to visit every possible
-     location in the table during rehashing.  */
-  hash2 = ((hash * 17) & sizemask) | 1;
-  string_hash.searches++;
-
-  for (;;)
-    {
-      entry = string_hash.entries[index];
-
-      if (SP_EMPTY (entry))
-       break;
-
-      if ((size_t) SP_LEN (entry) == length
-         && !memcmp (SP_STR (entry), contents, length))
-       return entry;
-
-      index = (index + hash2) & sizemask;
-      string_hash.collisions++;
-    }
-
-  if (insert == NO_INSERT)
-    return NULL;
-
-  entry = (sp_hashnode) make_node (IDENTIFIER_NODE);
-  string_hash.entries[index] = entry;
-  SP_STR (entry) = ggc_alloc_string (contents, length);
-  SP_LEN (entry) = length;
-  /* This is not yet an identifier.  */
-  TREE_SET_CODE (entry, ERROR_MARK);
-
-  if (++string_hash.nelements * 4 >= string_hash.nslots * 3)
-    /* Must expand the string table.  */
-    expand_string_table ();
-
-  return entry;
+  return !ggc_marked_p (HT_IDENT_TO_GCC_IDENT (h));
 }
 
-/* Subroutine of alloc_ident which doubles the size of the hash table
-   and rehashes all the strings into the new table.  Returns the entry
-   in the new table corresponding to ENTRY.  */
-static void
-expand_string_table ()
+/* 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
+ggc_mark_stringpool (void)
 {
-  sp_hashnode *nentries;
-  sp_hashnode *e;
-  size_t size, sizemask;
-
-  size = string_hash.nslots * 2;
-  nentries = (sp_hashnode *) xcalloc (size, sizeof (sp_hashnode));
-  sizemask = size - 1;
-
-  FORALL_IDS (e)
-    {
-      unsigned int index, hash, hash2;
-
-      hash = calc_hash ((const unsigned char *) SP_STR (*e), SP_LEN (*e));
-      hash2 = ((hash * 17) & sizemask) | 1;
-      index = hash & sizemask;
-
-      for (;;)
-       {
-         if (SP_EMPTY (nentries[index]))
-           {
-             nentries[index] = *e;
-             break;
-           }
-
-         index = (index + hash2) & sizemask;
-       }
-    }
-
-  free (string_hash.entries);
-  string_hash.entries = nentries;
-  string_hash.nslots = size;
+  ht_forall (ident_hash, mark_ident, NULL);
 }
 
-/* Allocate and return a string constant of length LENGTH, containing
-   CONTENTS.  If LENGTH is -1, CONTENTS is assumed to be a
-   nul-terminated string, and the length is calculated using strlen.
-   If the same string constant has been allocated before, that copy is
-   returned this time too.  */
+/* Purge the identifier hash of identifiers which are no longer
+   referenced.  */
 
-const char *
-ggc_alloc_string (contents, length)
-     const char *contents;
-     int length;
+void
+ggc_purge_stringpool (void)
 {
-  if (length == -1)
-    length = strlen (contents);
+  ht_purge (ident_hash, maybe_delete_ident, NULL);
+}
 
-  if (length == 0)
-    return empty_string;
-  if (length == 1 && contents[0] >= '0' && contents[0] <= '9')
-    return digit_string (contents[0] - '0');
+/* Pointer-walking routine for strings (not very interesting, since
+   strings don't contain pointers).  */
 
-  obstack_grow0 (&string_stack, contents, length);
-  return obstack_finish (&string_stack);
+void
+gt_pch_p_S (void *obj ATTRIBUTE_UNUSED, void *x ATTRIBUTE_UNUSED,
+           gt_pointer_operator op ATTRIBUTE_UNUSED,
+           void *cookie ATTRIBUTE_UNUSED)
+{
 }
 
-/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
-   If an identifier with that name has previously been referred to,
-   the same node is returned this time.  */
-tree
-get_identifier (text)
-     const char *text;
+/* PCH pointer-walking routine for strings.  */
+
+void
+gt_pch_n_S (const void *x)
 {
-  sp_hashnode node;
-  size_t length = strlen (text);
-
-  node = alloc_ident (text, length, INSERT);
-  if (!SP_VALID (node))
-    {
-      /* If this identifier is longer than the clash-warning length,
-        do a brute force search of the entire table for clashes.  */
-      if (warn_id_clash && do_identifier_warnings && length >= (size_t) id_clash_len)
-       {
-         sp_hashnode *e;
-         FORALL_IDS (e)
-           {
-             if (SP_LEN (*e) >= id_clash_len
-                 && !strncmp (SP_STR (*e), text, id_clash_len))
-               {
-                 warning ("\"%s\" and \"%s\" identical in first %d characters",
-                          text, SP_STR (*e), id_clash_len);
-                 break;
-               }
-           }
-       }
-
-      TREE_SET_CODE (node, IDENTIFIER_NODE);
-#ifdef GATHER_STATISTICS
-      id_string_size += length;
-#endif
-    }
-
-  return SP_TREE (node);
+  gt_pch_note_object (CONST_CAST (void *, x), CONST_CAST (void *, x),
+                     &gt_pch_p_S, gt_types_enum_last);
 }
+\f
+/* Handle saving and restoring the string pool for PCH.  */
 
-/* If an identifier with the name TEXT (a null-terminated string) has
-   previously been referred to, return that node; otherwise return
-   NULL_TREE.  */
+/* SPD is saved in the PCH file and holds the information needed
+   to restore the string pool.  */
 
-tree
-maybe_get_identifier (text)
-     const char *text;
+struct string_pool_data GTY(())
 {
-  sp_hashnode node;
-  size_t length = strlen (text);
+  struct ht_identifier * * 
+    GTY((length ("%h.nslots"),
+        nested_ptr (union tree_node, "%h ? GCC_IDENT_TO_HT_IDENT (%h) : NULL",
+                    "%h ? HT_IDENT_TO_GCC_IDENT (%h) : NULL")))
+    entries;
+  unsigned int nslots;
+  unsigned int nelements;
+};
 
-  node = alloc_ident (text, length, NO_INSERT);
-  if (!SP_EMPTY (node) && SP_VALID (node))
-    return SP_TREE (node);
+static GTY(()) struct string_pool_data * spd;
 
-  return NULL_TREE;
+/* Save the stringpool data in SPD.  */
+
+void
+gt_pch_save_stringpool (void)
+{
+  spd = GGC_NEW (struct string_pool_data);
+  spd->nslots = ident_hash->nslots;
+  spd->nelements = ident_hash->nelements;
+  spd->entries = GGC_NEWVEC (struct ht_identifier *, spd->nslots);
+  memcpy (spd->entries, ident_hash->entries,
+         spd->nslots * sizeof (spd->entries[0]));
 }
 
-/* Report some basic statistics about the string pool.  */
+/* Return the stringpool to its state before gt_pch_save_stringpool
+   was called.  */
 
 void
-stringpool_statistics ()
+gt_pch_fixup_stringpool (void)
 {
-  size_t nelts, nids, overhead, headers;
-  size_t total_bytes, longest, sum_of_squares;
-  double exp_len, exp_len2, exp2_len;
-  sp_hashnode *e;
-#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
-                 ? (x) \
-                 : ((x) < 1024*1024*10 \
-                    ? (x) / 1024 \
-                    : (x) / (1024*1024))))
-#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
-
-  total_bytes = longest = sum_of_squares = nids = 0;
-  FORALL_IDS (e)
-    {
-      size_t n = SP_LEN (*e);
-
-      total_bytes += n;
-      sum_of_squares += n*n;
-      if (n > longest)
-       longest = n;
-      if (SP_VALID (*e))
-       nids++;
-    }
-      
-  nelts = string_hash.nelements;
-  overhead = obstack_memory_used (&string_stack) - total_bytes;
-  headers = string_hash.nslots * sizeof (sp_hashnode);
-
-  fprintf (stderr,
-"\nString pool\n\
-entries\t\t%lu\n\
-identifiers\t%lu (%.2f%%)\n\
-slots\t\t%lu\n\
-bytes\t\t%lu%c (%lu%c overhead)\n\
-table size\t%lu%c\n",
-          (unsigned long) nelts,
-          (unsigned long) nids, nids * 100.0 / nelts,
-          (unsigned long) string_hash.nslots,
-          SCALE (total_bytes), LABEL (total_bytes),
-          SCALE (overhead), LABEL (overhead),
-          SCALE (headers), LABEL (headers));
-
-  exp_len = (double)total_bytes / (double)nelts;
-  exp2_len = exp_len * exp_len;
-  exp_len2 = (double)sum_of_squares / (double)nelts;
-
-  fprintf (stderr,
-"coll/search\t%.4f\n\
-ins/search\t%.4f\n\
-avg. entry\t%.2f bytes (+/- %.2f)\n\
-longest entry\t%lu\n",
-          (double) string_hash.collisions / (double) string_hash.searches,
-          (double) nelts / (double) string_hash.searches,
-          exp_len, approx_sqrt (exp_len2 - exp2_len),
-          (unsigned long) longest);
-#undef SCALE
-#undef LABEL
 }
 
-/* Mark the string hash for GC.  */
+/* A PCH file has been restored, which loaded SPD; fill the real hash table
+   from SPD.  */
 
-static void
-mark_string_hash (arg)
-     void *arg ATTRIBUTE_UNUSED;
+void
+gt_pch_restore_stringpool (void)
 {
-  sp_hashnode *h;
-
-  FORALL_IDS (h)
-    {
-      ggc_mark_tree (SP_TREE (*h));
-    }
+  ht_load (ident_hash, spd->entries, spd->nslots, spd->nelements, false);
+  spd = NULL;
 }
+
+#include "gt-stringpool.h"