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