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