xref: /openbsd-src/gnu/gcc/libcpp/symtab.c (revision 404b540a9034ac75a6199ad1a32d1bbc7a0d4210)
1*404b540aSrobert /* Hash tables.
2*404b540aSrobert    Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
3*404b540aSrobert 
4*404b540aSrobert This program is free software; you can redistribute it and/or modify it
5*404b540aSrobert under the terms of the GNU General Public License as published by the
6*404b540aSrobert Free Software Foundation; either version 2, or (at your option) any
7*404b540aSrobert later version.
8*404b540aSrobert 
9*404b540aSrobert This program is distributed in the hope that it will be useful,
10*404b540aSrobert but WITHOUT ANY WARRANTY; without even the implied warranty of
11*404b540aSrobert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*404b540aSrobert GNU General Public License for more details.
13*404b540aSrobert 
14*404b540aSrobert You should have received a copy of the GNU General Public License
15*404b540aSrobert along with this program; if not, write to the Free Software
16*404b540aSrobert Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17*404b540aSrobert 
18*404b540aSrobert  In other words, you are welcome to use, share and improve this program.
19*404b540aSrobert  You are forbidden to forbid anyone else to use, share and improve
20*404b540aSrobert  what you give them.   Help stamp out software-hoarding!  */
21*404b540aSrobert 
22*404b540aSrobert #include "config.h"
23*404b540aSrobert #include "system.h"
24*404b540aSrobert #include "symtab.h"
25*404b540aSrobert 
26*404b540aSrobert /* The code below is a specialization of Vladimir Makarov's expandable
27*404b540aSrobert    hash tables (see libiberty/hashtab.c).  The abstraction penalty was
28*404b540aSrobert    too high to continue using the generic form.  This code knows
29*404b540aSrobert    intrinsically how to calculate a hash value, and how to compare an
30*404b540aSrobert    existing entry with a potential new one.  Also, the ability to
31*404b540aSrobert    delete members from the table has been removed.  */
32*404b540aSrobert 
33*404b540aSrobert static unsigned int calc_hash (const unsigned char *, size_t);
34*404b540aSrobert static void ht_expand (hash_table *);
35*404b540aSrobert static double approx_sqrt (double);
36*404b540aSrobert 
37*404b540aSrobert /* Calculate the hash of the string STR of length LEN.  */
38*404b540aSrobert 
39*404b540aSrobert static unsigned int
calc_hash(const unsigned char * str,size_t len)40*404b540aSrobert calc_hash (const unsigned char *str, size_t len)
41*404b540aSrobert {
42*404b540aSrobert   size_t n = len;
43*404b540aSrobert   unsigned int r = 0;
44*404b540aSrobert 
45*404b540aSrobert   while (n--)
46*404b540aSrobert     r = HT_HASHSTEP (r, *str++);
47*404b540aSrobert 
48*404b540aSrobert   return HT_HASHFINISH (r, len);
49*404b540aSrobert }
50*404b540aSrobert 
51*404b540aSrobert /* Initialize an identifier hashtable.  */
52*404b540aSrobert 
53*404b540aSrobert hash_table *
ht_create(unsigned int order)54*404b540aSrobert ht_create (unsigned int order)
55*404b540aSrobert {
56*404b540aSrobert   unsigned int nslots = 1 << order;
57*404b540aSrobert   hash_table *table;
58*404b540aSrobert 
59*404b540aSrobert   table = XCNEW (hash_table);
60*404b540aSrobert 
61*404b540aSrobert   /* Strings need no alignment.  */
62*404b540aSrobert   _obstack_begin (&table->stack, 0, 0,
63*404b540aSrobert 		  (void *(*) (long)) xmalloc,
64*404b540aSrobert 		  (void (*) (void *)) free);
65*404b540aSrobert 
66*404b540aSrobert   obstack_alignment_mask (&table->stack) = 0;
67*404b540aSrobert 
68*404b540aSrobert   table->entries = XCNEWVEC (hashnode, nslots);
69*404b540aSrobert   table->entries_owned = true;
70*404b540aSrobert   table->nslots = nslots;
71*404b540aSrobert   return table;
72*404b540aSrobert }
73*404b540aSrobert 
74*404b540aSrobert /* Frees all memory associated with a hash table.  */
75*404b540aSrobert 
76*404b540aSrobert void
ht_destroy(hash_table * table)77*404b540aSrobert ht_destroy (hash_table *table)
78*404b540aSrobert {
79*404b540aSrobert   obstack_free (&table->stack, NULL);
80*404b540aSrobert   if (table->entries_owned)
81*404b540aSrobert     free (table->entries);
82*404b540aSrobert   free (table);
83*404b540aSrobert }
84*404b540aSrobert 
85*404b540aSrobert /* Returns the hash entry for the a STR of length LEN.  If that string
86*404b540aSrobert    already exists in the table, returns the existing entry, and, if
87*404b540aSrobert    INSERT is CPP_ALLOCED, frees the last obstack object.  If the
88*404b540aSrobert    identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
89*404b540aSrobert    returns NULL.  Otherwise insert and returns a new entry.  A new
90*404b540aSrobert    string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is
91*404b540aSrobert    CPP_ALLOCED and the item is assumed to be at the top of the
92*404b540aSrobert    obstack.  */
93*404b540aSrobert hashnode
ht_lookup(hash_table * table,const unsigned char * str,size_t len,enum ht_lookup_option insert)94*404b540aSrobert ht_lookup (hash_table *table, const unsigned char *str, size_t len,
95*404b540aSrobert 	   enum ht_lookup_option insert)
96*404b540aSrobert {
97*404b540aSrobert   return ht_lookup_with_hash (table, str, len, calc_hash (str, len),
98*404b540aSrobert 			      insert);
99*404b540aSrobert }
100*404b540aSrobert 
101*404b540aSrobert hashnode
ht_lookup_with_hash(hash_table * table,const unsigned char * str,size_t len,unsigned int hash,enum ht_lookup_option insert)102*404b540aSrobert ht_lookup_with_hash (hash_table *table, const unsigned char *str,
103*404b540aSrobert 		     size_t len, unsigned int hash,
104*404b540aSrobert 		     enum ht_lookup_option insert)
105*404b540aSrobert {
106*404b540aSrobert   unsigned int hash2;
107*404b540aSrobert   unsigned int index;
108*404b540aSrobert   size_t sizemask;
109*404b540aSrobert   hashnode node;
110*404b540aSrobert 
111*404b540aSrobert   sizemask = table->nslots - 1;
112*404b540aSrobert   index = hash & sizemask;
113*404b540aSrobert   table->searches++;
114*404b540aSrobert 
115*404b540aSrobert   node = table->entries[index];
116*404b540aSrobert 
117*404b540aSrobert   if (node != NULL)
118*404b540aSrobert     {
119*404b540aSrobert       if (node->hash_value == hash
120*404b540aSrobert 	  && HT_LEN (node) == (unsigned int) len
121*404b540aSrobert 	  && !memcmp (HT_STR (node), str, len))
122*404b540aSrobert 	{
123*404b540aSrobert 	  if (insert == HT_ALLOCED)
124*404b540aSrobert 	    /* The string we search for was placed at the end of the
125*404b540aSrobert 	       obstack.  Release it.  */
126*404b540aSrobert 	    obstack_free (&table->stack, (void *) str);
127*404b540aSrobert 	  return node;
128*404b540aSrobert 	}
129*404b540aSrobert 
130*404b540aSrobert       /* hash2 must be odd, so we're guaranteed to visit every possible
131*404b540aSrobert 	 location in the table during rehashing.  */
132*404b540aSrobert       hash2 = ((hash * 17) & sizemask) | 1;
133*404b540aSrobert 
134*404b540aSrobert       for (;;)
135*404b540aSrobert 	{
136*404b540aSrobert 	  table->collisions++;
137*404b540aSrobert 	  index = (index + hash2) & sizemask;
138*404b540aSrobert 	  node = table->entries[index];
139*404b540aSrobert 	  if (node == NULL)
140*404b540aSrobert 	    break;
141*404b540aSrobert 
142*404b540aSrobert 	  if (node->hash_value == hash
143*404b540aSrobert 	      && HT_LEN (node) == (unsigned int) len
144*404b540aSrobert 	      && !memcmp (HT_STR (node), str, len))
145*404b540aSrobert 	    {
146*404b540aSrobert 	      if (insert == HT_ALLOCED)
147*404b540aSrobert 	      /* The string we search for was placed at the end of the
148*404b540aSrobert 		 obstack.  Release it.  */
149*404b540aSrobert 		obstack_free (&table->stack, (void *) str);
150*404b540aSrobert 	      return node;
151*404b540aSrobert 	    }
152*404b540aSrobert 	}
153*404b540aSrobert     }
154*404b540aSrobert 
155*404b540aSrobert   if (insert == HT_NO_INSERT)
156*404b540aSrobert     return NULL;
157*404b540aSrobert 
158*404b540aSrobert   node = (*table->alloc_node) (table);
159*404b540aSrobert   table->entries[index] = node;
160*404b540aSrobert 
161*404b540aSrobert   HT_LEN (node) = (unsigned int) len;
162*404b540aSrobert   node->hash_value = hash;
163*404b540aSrobert   if (insert == HT_ALLOC)
164*404b540aSrobert     HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
165*404b540aSrobert                                                            str, len);
166*404b540aSrobert   else
167*404b540aSrobert     HT_STR (node) = str;
168*404b540aSrobert 
169*404b540aSrobert   if (++table->nelements * 4 >= table->nslots * 3)
170*404b540aSrobert     /* Must expand the string table.  */
171*404b540aSrobert     ht_expand (table);
172*404b540aSrobert 
173*404b540aSrobert   return node;
174*404b540aSrobert }
175*404b540aSrobert 
176*404b540aSrobert /* Double the size of a hash table, re-hashing existing entries.  */
177*404b540aSrobert 
178*404b540aSrobert static void
ht_expand(hash_table * table)179*404b540aSrobert ht_expand (hash_table *table)
180*404b540aSrobert {
181*404b540aSrobert   hashnode *nentries, *p, *limit;
182*404b540aSrobert   unsigned int size, sizemask;
183*404b540aSrobert 
184*404b540aSrobert   size = table->nslots * 2;
185*404b540aSrobert   nentries = XCNEWVEC (hashnode, size);
186*404b540aSrobert   sizemask = size - 1;
187*404b540aSrobert 
188*404b540aSrobert   p = table->entries;
189*404b540aSrobert   limit = p + table->nslots;
190*404b540aSrobert   do
191*404b540aSrobert     if (*p)
192*404b540aSrobert       {
193*404b540aSrobert 	unsigned int index, hash, hash2;
194*404b540aSrobert 
195*404b540aSrobert 	hash = (*p)->hash_value;
196*404b540aSrobert 	index = hash & sizemask;
197*404b540aSrobert 
198*404b540aSrobert 	if (nentries[index])
199*404b540aSrobert 	  {
200*404b540aSrobert 	    hash2 = ((hash * 17) & sizemask) | 1;
201*404b540aSrobert 	    do
202*404b540aSrobert 	      {
203*404b540aSrobert 		index = (index + hash2) & sizemask;
204*404b540aSrobert 	      }
205*404b540aSrobert 	    while (nentries[index]);
206*404b540aSrobert 	  }
207*404b540aSrobert 	nentries[index] = *p;
208*404b540aSrobert       }
209*404b540aSrobert   while (++p < limit);
210*404b540aSrobert 
211*404b540aSrobert   if (table->entries_owned)
212*404b540aSrobert     free (table->entries);
213*404b540aSrobert   table->entries_owned = true;
214*404b540aSrobert   table->entries = nentries;
215*404b540aSrobert   table->nslots = size;
216*404b540aSrobert }
217*404b540aSrobert 
218*404b540aSrobert /* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
219*404b540aSrobert    the node, and V.  */
220*404b540aSrobert void
ht_forall(hash_table * table,ht_cb cb,const void * v)221*404b540aSrobert ht_forall (hash_table *table, ht_cb cb, const void *v)
222*404b540aSrobert {
223*404b540aSrobert   hashnode *p, *limit;
224*404b540aSrobert 
225*404b540aSrobert   p = table->entries;
226*404b540aSrobert   limit = p + table->nslots;
227*404b540aSrobert   do
228*404b540aSrobert     if (*p)
229*404b540aSrobert       {
230*404b540aSrobert 	if ((*cb) (table->pfile, *p, v) == 0)
231*404b540aSrobert 	  break;
232*404b540aSrobert       }
233*404b540aSrobert   while (++p < limit);
234*404b540aSrobert }
235*404b540aSrobert 
236*404b540aSrobert /* Restore the hash table.  */
237*404b540aSrobert void
ht_load(hash_table * ht,hashnode * entries,unsigned int nslots,unsigned int nelements,bool own)238*404b540aSrobert ht_load (hash_table *ht, hashnode *entries,
239*404b540aSrobert 	 unsigned int nslots, unsigned int nelements,
240*404b540aSrobert 	 bool own)
241*404b540aSrobert {
242*404b540aSrobert   if (ht->entries_owned)
243*404b540aSrobert     free (ht->entries);
244*404b540aSrobert   ht->entries = entries;
245*404b540aSrobert   ht->nslots = nslots;
246*404b540aSrobert   ht->nelements = nelements;
247*404b540aSrobert   ht->entries_owned = own;
248*404b540aSrobert }
249*404b540aSrobert 
250*404b540aSrobert /* Dump allocation statistics to stderr.  */
251*404b540aSrobert 
252*404b540aSrobert void
ht_dump_statistics(hash_table * table)253*404b540aSrobert ht_dump_statistics (hash_table *table)
254*404b540aSrobert {
255*404b540aSrobert   size_t nelts, nids, overhead, headers;
256*404b540aSrobert   size_t total_bytes, longest;
257*404b540aSrobert   double sum_of_squares, exp_len, exp_len2, exp2_len;
258*404b540aSrobert   hashnode *p, *limit;
259*404b540aSrobert 
260*404b540aSrobert #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
261*404b540aSrobert 		  ? (x) \
262*404b540aSrobert 		  : ((x) < 1024*1024*10 \
263*404b540aSrobert 		     ? (x) / 1024 \
264*404b540aSrobert 		     : (x) / (1024*1024))))
265*404b540aSrobert #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
266*404b540aSrobert 
267*404b540aSrobert   total_bytes = longest = sum_of_squares = nids = 0;
268*404b540aSrobert   p = table->entries;
269*404b540aSrobert   limit = p + table->nslots;
270*404b540aSrobert   do
271*404b540aSrobert     if (*p)
272*404b540aSrobert       {
273*404b540aSrobert 	size_t n = HT_LEN (*p);
274*404b540aSrobert 
275*404b540aSrobert 	total_bytes += n;
276*404b540aSrobert 	sum_of_squares += (double) n * n;
277*404b540aSrobert 	if (n > longest)
278*404b540aSrobert 	  longest = n;
279*404b540aSrobert 	nids++;
280*404b540aSrobert       }
281*404b540aSrobert   while (++p < limit);
282*404b540aSrobert 
283*404b540aSrobert   nelts = table->nelements;
284*404b540aSrobert   overhead = obstack_memory_used (&table->stack) - total_bytes;
285*404b540aSrobert   headers = table->nslots * sizeof (hashnode);
286*404b540aSrobert 
287*404b540aSrobert   fprintf (stderr, "\nString pool\nentries\t\t%lu\n",
288*404b540aSrobert 	   (unsigned long) nelts);
289*404b540aSrobert   fprintf (stderr, "identifiers\t%lu (%.2f%%)\n",
290*404b540aSrobert 	   (unsigned long) nids, nids * 100.0 / nelts);
291*404b540aSrobert   fprintf (stderr, "slots\t\t%lu\n",
292*404b540aSrobert 	   (unsigned long) table->nslots);
293*404b540aSrobert   fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
294*404b540aSrobert 	   SCALE (total_bytes), LABEL (total_bytes),
295*404b540aSrobert 	   SCALE (overhead), LABEL (overhead));
296*404b540aSrobert   fprintf (stderr, "table size\t%lu%c\n",
297*404b540aSrobert 	   SCALE (headers), LABEL (headers));
298*404b540aSrobert 
299*404b540aSrobert   exp_len = (double)total_bytes / (double)nelts;
300*404b540aSrobert   exp2_len = exp_len * exp_len;
301*404b540aSrobert   exp_len2 = (double) sum_of_squares / (double) nelts;
302*404b540aSrobert 
303*404b540aSrobert   fprintf (stderr, "coll/search\t%.4f\n",
304*404b540aSrobert 	   (double) table->collisions / (double) table->searches);
305*404b540aSrobert   fprintf (stderr, "ins/search\t%.4f\n",
306*404b540aSrobert 	   (double) nelts / (double) table->searches);
307*404b540aSrobert   fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n",
308*404b540aSrobert 	   exp_len, approx_sqrt (exp_len2 - exp2_len));
309*404b540aSrobert   fprintf (stderr, "longest entry\t%lu\n",
310*404b540aSrobert 	   (unsigned long) longest);
311*404b540aSrobert #undef SCALE
312*404b540aSrobert #undef LABEL
313*404b540aSrobert }
314*404b540aSrobert 
315*404b540aSrobert /* Return the approximate positive square root of a number N.  This is for
316*404b540aSrobert    statistical reports, not code generation.  */
317*404b540aSrobert static double
approx_sqrt(double x)318*404b540aSrobert approx_sqrt (double x)
319*404b540aSrobert {
320*404b540aSrobert   double s, d;
321*404b540aSrobert 
322*404b540aSrobert   if (x < 0)
323*404b540aSrobert     abort ();
324*404b540aSrobert   if (x == 0)
325*404b540aSrobert     return 0;
326*404b540aSrobert 
327*404b540aSrobert   s = x;
328*404b540aSrobert   do
329*404b540aSrobert     {
330*404b540aSrobert       d = (s * s - x) / (2 * s);
331*404b540aSrobert       s -= d;
332*404b540aSrobert     }
333*404b540aSrobert   while (d > .0001);
334*404b540aSrobert   return s;
335*404b540aSrobert }
336