stringpool.c revision 132718
1326938Sdim/* String pool for GCC.
2326938Sdim   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3353358Sdim
4353358SdimThis file is part of GCC.
5353358Sdim
6326938SdimGCC is free software; you can redistribute it and/or modify it under
7326938Sdimthe terms of the GNU General Public License as published by the Free
8326938SdimSoftware Foundation; either version 2, or (at your option) any later
9326938Sdimversion.
10326938Sdim
11326938SdimGCC is distributed in the hope that it will be useful, but WITHOUT ANY
12326938SdimWARRANTY; without even the implied warranty of MERCHANTABILITY or
13326938SdimFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14326938Sdimfor more details.
15326938Sdim
16326938SdimYou should have received a copy of the GNU General Public License
17326938Sdimalong with GCC; see the file COPYING.  If not, write to the Free
18326938SdimSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
19326938Sdim02111-1307, USA.  */
20326938Sdim
21326938Sdim/* String text, identifier text and identifier node allocator.  Strings
22326938Sdim   allocated by ggc_alloc_string are stored in an obstack which is
23326938Sdim   never shrunk.  Identifiers are uniquely stored in a hash table.
24326938Sdim
25326938Sdim   We have our own private hash table implementation.  libiberty's
26326938Sdim   hashtab.c is not used because it requires 100% average space
27326938Sdim   overhead per string, which is unacceptable.  Also, this algorithm
28326938Sdim   is faster.  */
29326938Sdim
30326938Sdim#include "config.h"
31326938Sdim#include "system.h"
32326938Sdim#include "coretypes.h"
33326938Sdim#include "tm.h"
34326938Sdim#include "ggc.h"
35326938Sdim#include "tree.h"
36326938Sdim#include "hashtable.h"
37326938Sdim#include "cpplib.h"
38326938Sdim
39326938Sdim/* The "" allocated string.  */
40326938Sdimconst char empty_string[] = "";
41326938Sdim
42326938Sdim/* Character strings, each containing a single decimal digit.
43326938Sdim   Written this way to save space.  */
44326938Sdimconst char digit_vector[] = {
45326938Sdim  '0', 0, '1', 0, '2', 0, '3', 0, '4', 0,
46326938Sdim  '5', 0, '6', 0, '7', 0, '8', 0, '9', 0
47326938Sdim};
48326938Sdim
49326938Sdimstruct ht *ident_hash;
50326938Sdimstatic struct obstack string_stack;
51326938Sdim
52326938Sdimstatic hashnode alloc_node (hash_table *);
53326938Sdimstatic int mark_ident (struct cpp_reader *, hashnode, const void *);
54326938Sdimstatic int ht_copy_and_clear (struct cpp_reader *, hashnode, const void *);
55326938Sdim
56326938Sdim/* Initialize the string pool.  */
57326938Sdimvoid
58326938Sdiminit_stringpool (void)
59326938Sdim{
60326938Sdim  /* Create with 16K (2^14) entries.  */
61326938Sdim  ident_hash = ht_create (14);
62326938Sdim  ident_hash->alloc_node = alloc_node;
63326938Sdim  gcc_obstack_init (&string_stack);
64326938Sdim}
65326938Sdim
66326938Sdim/* Allocate a hash node.  */
67326938Sdimstatic hashnode
68326938Sdimalloc_node (hash_table *table ATTRIBUTE_UNUSED)
69326938Sdim{
70326938Sdim  return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
71326938Sdim}
72326938Sdim
73326938Sdim/* Allocate and return a string constant of length LENGTH, containing
74326938Sdim   CONTENTS.  If LENGTH is -1, CONTENTS is assumed to be a
75326938Sdim   nul-terminated string, and the length is calculated using strlen.
76326938Sdim   If the same string constant has been allocated before, that copy is
77326938Sdim   returned this time too.  */
78326938Sdim
79326938Sdimconst char *
80326938Sdimggc_alloc_string (const char *contents, int length)
81326938Sdim{
82326938Sdim  if (length == -1)
83326938Sdim    length = strlen (contents);
84326938Sdim
85326938Sdim  if (length == 0)
86326938Sdim    return empty_string;
87326938Sdim  if (length == 1 && ISDIGIT (contents[0]))
88326938Sdim    return digit_string (contents[0] - '0');
89326938Sdim
90326938Sdim  obstack_grow0 (&string_stack, contents, length);
91326938Sdim  return obstack_finish (&string_stack);
92326938Sdim}
93326938Sdim
94326938Sdim/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
95326938Sdim   If an identifier with that name has previously been referred to,
96326938Sdim   the same node is returned this time.  */
97326938Sdim
98326938Sdim#undef get_identifier
99326938Sdim
100326938Sdimtree
101326938Sdimget_identifier (const char *text)
102344779Sdim{
103326938Sdim  hashnode ht_node = ht_lookup (ident_hash,
104326938Sdim				(const unsigned char *) text,
105326938Sdim				strlen (text), HT_ALLOC);
106326938Sdim
107326938Sdim  /* ht_node can't be NULL here.  */
108326938Sdim  return HT_IDENT_TO_GCC_IDENT (ht_node);
109326938Sdim}
110326938Sdim
111326938Sdim/* Identical to get_identifier, except that the length is assumed
112341825Sdim   known.  */
113326938Sdim
114326938Sdimtree
115326938Sdimget_identifier_with_length (const char *text, size_t length)
116326938Sdim{
117326938Sdim  hashnode ht_node = ht_lookup (ident_hash,
118326938Sdim				(const unsigned char *) text,
119326938Sdim				length, HT_ALLOC);
120326938Sdim
121326938Sdim  /* ht_node can't be NULL here.  */
122326938Sdim  return HT_IDENT_TO_GCC_IDENT (ht_node);
123326938Sdim}
124326938Sdim
125326938Sdim/* If an identifier with the name TEXT (a null-terminated string) has
126326938Sdim   previously been referred to, return that node; otherwise return
127326938Sdim   NULL_TREE.  */
128326938Sdim
129326938Sdimtree
130326938Sdimmaybe_get_identifier (const char *text)
131326938Sdim{
132326938Sdim  hashnode ht_node;
133326938Sdim
134326938Sdim  ht_node = ht_lookup (ident_hash, (const unsigned char *) text,
135326938Sdim		       strlen (text), HT_NO_INSERT);
136326938Sdim  if (ht_node)
137326938Sdim    return HT_IDENT_TO_GCC_IDENT (ht_node);
138326938Sdim
139326938Sdim  return NULL_TREE;
140344779Sdim}
141360784Sdim
142326938Sdim/* Report some basic statistics about the string pool.  */
143326938Sdim
144326938Sdimvoid
145326938Sdimstringpool_statistics (void)
146326938Sdim{
147326938Sdim  ht_dump_statistics (ident_hash);
148326938Sdim}
149326938Sdim
150326938Sdim/* Mark an identifier for GC.  */
151326938Sdim
152326938Sdimstatic int
153326938Sdimmark_ident (struct cpp_reader *pfile ATTRIBUTE_UNUSED, hashnode h,
154326938Sdim	    const void *v ATTRIBUTE_UNUSED)
155326938Sdim{
156326938Sdim  gt_ggc_m_9tree_node (HT_IDENT_TO_GCC_IDENT (h));
157326938Sdim  return 1;
158326938Sdim}
159326938Sdim
160326938Sdim/* Mark the trees hanging off the identifier node for GGC.  These are
161326938Sdim   handled specially (not using gengtype) because of the special
162326938Sdim   treatment for strings.  */
163326938Sdim
164326938Sdimvoid
165326938Sdimggc_mark_stringpool (void)
166326938Sdim{
167326938Sdim  ht_forall (ident_hash, mark_ident, NULL);
168326938Sdim}
169326938Sdim
170326938Sdim/* Strings are _not_ GCed, but this routine exists so that a separate
171326938Sdim   roots table isn't needed for the few global variables that refer
172326938Sdim   to strings.  */
173326938Sdim
174326938Sdimvoid
175326938Sdimgt_ggc_m_S (void *x ATTRIBUTE_UNUSED)
176326938Sdim{
177326938Sdim}
178326938Sdim
179326938Sdim/* Pointer-walking routine for strings (not very interesting, since
180326938Sdim   strings don't contain pointers).  */
181326938Sdim
182326938Sdimvoid
183326938Sdimgt_pch_p_S (void *obj ATTRIBUTE_UNUSED, void *x ATTRIBUTE_UNUSED,
184326938Sdim	    gt_pointer_operator op ATTRIBUTE_UNUSED,
185326938Sdim	    void *cookie ATTRIBUTE_UNUSED)
186326938Sdim{
187326938Sdim}
188326938Sdim
189326938Sdim/* PCH pointer-walking routine for strings.  */
190326938Sdim
191326938Sdimvoid
192326938Sdimgt_pch_n_S (const void *x)
193326938Sdim{
194326938Sdim  gt_pch_note_object ((void *)x, (void *)x, &gt_pch_p_S);
195326938Sdim}
196326938Sdim
197326938Sdim/* Handle saving and restoring the string pool for PCH.  */
198326938Sdim
199326938Sdimstruct string_pool_data GTY(())
200326938Sdim{
201326938Sdim  tree * GTY((length ("%h.nslots"))) entries;
202326938Sdim  unsigned int nslots;
203326938Sdim  unsigned int nelements;
204326938Sdim};
205326938Sdim
206326938Sdimstatic GTY(()) struct string_pool_data * spd;
207326938Sdim
208326938Sdimstatic int
209326938Sdimht_copy_and_clear (cpp_reader *r ATTRIBUTE_UNUSED, hashnode hp, const void *ht2_p)
210326938Sdim{
211326938Sdim  cpp_hashnode *h = CPP_HASHNODE (hp);
212326938Sdim  struct ht *ht2 = (struct ht *) ht2_p;
213326938Sdim
214326938Sdim  if (h->type != NT_VOID
215326938Sdim      && (h->flags & NODE_BUILTIN) == 0)
216326938Sdim    {
217326938Sdim      cpp_hashnode *h2 = CPP_HASHNODE (ht_lookup (ht2,
218326938Sdim						  NODE_NAME (h),
219326938Sdim						  NODE_LEN (h),
220326938Sdim						  HT_ALLOC));
221326938Sdim      h2->type = h->type;
222326938Sdim      memcpy (&h2->value, &h->value, sizeof (h->value));
223326938Sdim
224326938Sdim      h->type = NT_VOID;
225326938Sdim      memset (&h->value, 0, sizeof (h->value));
226326938Sdim    }
227326938Sdim  return 1;
228326938Sdim}
229326938Sdim
230326938Sdimstatic struct ht *saved_ident_hash;
231326938Sdim
232326938Sdimvoid
233326938Sdimgt_pch_save_stringpool (void)
234326938Sdim{
235360784Sdim  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