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, >_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