stringpool.c revision 132718
1/* String pool for GCC.
2   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 2, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING.  If not, write to the Free
18Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA.  */
20
21/* String text, identifier text and identifier node allocator.  Strings
22   allocated by ggc_alloc_string are stored in an obstack which is
23   never shrunk.  Identifiers are uniquely stored in a hash table.
24
25   We have our own private hash table implementation.  libiberty's
26   hashtab.c is not used because it requires 100% average space
27   overhead per string, which is unacceptable.  Also, this algorithm
28   is faster.  */
29
30#include "config.h"
31#include "system.h"
32#include "coretypes.h"
33#include "tm.h"
34#include "ggc.h"
35#include "tree.h"
36#include "hashtable.h"
37#include "cpplib.h"
38
39/* The "" allocated string.  */
40const char empty_string[] = "";
41
42/* Character strings, each containing a single decimal digit.
43   Written this way to save space.  */
44const char digit_vector[] = {
45  '0', 0, '1', 0, '2', 0, '3', 0, '4', 0,
46  '5', 0, '6', 0, '7', 0, '8', 0, '9', 0
47};
48
49struct ht *ident_hash;
50static struct obstack string_stack;
51
52static hashnode alloc_node (hash_table *);
53static int mark_ident (struct cpp_reader *, hashnode, const void *);
54static int ht_copy_and_clear (struct cpp_reader *, hashnode, const void *);
55
56/* Initialize the string pool.  */
57void
58init_stringpool (void)
59{
60  /* Create with 16K (2^14) entries.  */
61  ident_hash = ht_create (14);
62  ident_hash->alloc_node = alloc_node;
63  gcc_obstack_init (&string_stack);
64}
65
66/* Allocate a hash node.  */
67static hashnode
68alloc_node (hash_table *table ATTRIBUTE_UNUSED)
69{
70  return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
71}
72
73/* Allocate and return a string constant of length LENGTH, containing
74   CONTENTS.  If LENGTH is -1, CONTENTS is assumed to be a
75   nul-terminated string, and the length is calculated using strlen.
76   If the same string constant has been allocated before, that copy is
77   returned this time too.  */
78
79const char *
80ggc_alloc_string (const char *contents, int length)
81{
82  if (length == -1)
83    length = strlen (contents);
84
85  if (length == 0)
86    return empty_string;
87  if (length == 1 && ISDIGIT (contents[0]))
88    return digit_string (contents[0] - '0');
89
90  obstack_grow0 (&string_stack, contents, length);
91  return obstack_finish (&string_stack);
92}
93
94/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
95   If an identifier with that name has previously been referred to,
96   the same node is returned this time.  */
97
98#undef get_identifier
99
100tree
101get_identifier (const char *text)
102{
103  hashnode ht_node = ht_lookup (ident_hash,
104				(const unsigned char *) text,
105				strlen (text), HT_ALLOC);
106
107  /* ht_node can't be NULL here.  */
108  return HT_IDENT_TO_GCC_IDENT (ht_node);
109}
110
111/* Identical to get_identifier, except that the length is assumed
112   known.  */
113
114tree
115get_identifier_with_length (const char *text, size_t length)
116{
117  hashnode ht_node = ht_lookup (ident_hash,
118				(const unsigned char *) text,
119				length, HT_ALLOC);
120
121  /* ht_node can't be NULL here.  */
122  return HT_IDENT_TO_GCC_IDENT (ht_node);
123}
124
125/* If an identifier with the name TEXT (a null-terminated string) has
126   previously been referred to, return that node; otherwise return
127   NULL_TREE.  */
128
129tree
130maybe_get_identifier (const char *text)
131{
132  hashnode ht_node;
133
134  ht_node = ht_lookup (ident_hash, (const unsigned char *) text,
135		       strlen (text), HT_NO_INSERT);
136  if (ht_node)
137    return HT_IDENT_TO_GCC_IDENT (ht_node);
138
139  return NULL_TREE;
140}
141
142/* Report some basic statistics about the string pool.  */
143
144void
145stringpool_statistics (void)
146{
147  ht_dump_statistics (ident_hash);
148}
149
150/* Mark an identifier for GC.  */
151
152static int
153mark_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
154	    const void *v ATTRIBUTE_UNUSED)
155{
156  gt_ggc_m_9tree_node (HT_IDENT_TO_GCC_IDENT (h));
157  return 1;
158}
159
160/* Mark the trees hanging off the identifier node for GGC.  These are
161   handled specially (not using gengtype) because of the special
162   treatment for strings.  */
163
164void
165ggc_mark_stringpool (void)
166{
167  ht_forall (ident_hash, mark_ident, NULL);
168}
169
170/* Strings are _not_ GCed, but this routine exists so that a separate
171   roots table isn't needed for the few global variables that refer
172   to strings.  */
173
174void
175gt_ggc_m_S (void *x ATTRIBUTE_UNUSED)
176{
177}
178
179/* Pointer-walking routine for strings (not very interesting, since
180   strings don't contain pointers).  */
181
182void
183gt_pch_p_S (void *obj ATTRIBUTE_UNUSED, void *x ATTRIBUTE_UNUSED,
184	    gt_pointer_operator op ATTRIBUTE_UNUSED,
185	    void *cookie ATTRIBUTE_UNUSED)
186{
187}
188
189/* PCH pointer-walking routine for strings.  */
190
191void
192gt_pch_n_S (const void *x)
193{
194  gt_pch_note_object ((void *)x, (void *)x, &gt_pch_p_S);
195}
196
197/* Handle saving and restoring the string pool for PCH.  */
198
199struct string_pool_data GTY(())
200{
201  tree * GTY((length ("%h.nslots"))) entries;
202  unsigned int nslots;
203  unsigned int nelements;
204};
205
206static GTY(()) struct string_pool_data * spd;
207
208static int
209ht_copy_and_clear (cpp_reader *r ATTRIBUTE_UNUSED, hashnode hp, const void *ht2_p)
210{
211  cpp_hashnode *h = CPP_HASHNODE (hp);
212  struct ht *ht2 = (struct ht *) ht2_p;
213
214  if (h->type != NT_VOID
215      && (h->flags & NODE_BUILTIN) == 0)
216    {
217      cpp_hashnode *h2 = CPP_HASHNODE (ht_lookup (ht2,
218						  NODE_NAME (h),
219						  NODE_LEN (h),
220						  HT_ALLOC));
221      h2->type = h->type;
222      memcpy (&h2->value, &h->value, sizeof (h->value));
223
224      h->type = NT_VOID;
225      memset (&h->value, 0, sizeof (h->value));
226    }
227  return 1;
228}
229
230static struct ht *saved_ident_hash;
231
232void
233gt_pch_save_stringpool (void)
234{
235  unsigned int i;
236
237  spd = ggc_alloc (sizeof (*spd));
238  spd->nslots = ident_hash->nslots;
239  spd->nelements = ident_hash->nelements;
240  spd->entries = ggc_alloc (sizeof (tree *) * spd->nslots);
241  for (i = 0; i < spd->nslots; i++)
242    if (ident_hash->entries[i] != NULL)
243      spd->entries[i] = HT_IDENT_TO_GCC_IDENT (ident_hash->entries[i]);
244    else
245      spd->entries[i] = NULL;
246
247  saved_ident_hash = ht_create (14);
248  saved_ident_hash->alloc_node = alloc_node;
249  ht_forall (ident_hash, ht_copy_and_clear, saved_ident_hash);
250}
251
252void
253gt_pch_fixup_stringpool (void)
254{
255  ht_forall (saved_ident_hash, ht_copy_and_clear, ident_hash);
256  ht_destroy (saved_ident_hash);
257  saved_ident_hash = 0;
258}
259
260void
261gt_pch_restore_stringpool (void)
262{
263  unsigned int i;
264
265  ident_hash->nslots = spd->nslots;
266  ident_hash->nelements = spd->nelements;
267  ident_hash->entries = xrealloc (ident_hash->entries,
268				  sizeof (hashnode) * spd->nslots);
269  for (i = 0; i < spd->nslots; i++)
270    if (spd->entries[i] != NULL)
271      ident_hash->entries[i] = GCC_IDENT_TO_HT_IDENT (spd->entries[i]);
272    else
273      ident_hash->entries[i] = NULL;
274
275  spd = NULL;
276}
277
278#include "gt-stringpool.h"
279