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