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