Patchwork [v2,22/22] Introduce and use bcache_up

login
register
mail settings
Submitter Tom Tromey
Date March 7, 2019, 5:41 p.m.
Message ID <87o96meg49.fsf@tromey.com>
Download mbox | patch
Permalink /patch/31771/
State New
Headers show

Comments

Tom Tromey - March 7, 2019, 5:41 p.m.
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Pedro> Almost perfect.  On a quick skim, the only thing missing is
Pedro> renaming the now-private fields of struct bcache to have
Pedro> an "m_" prefix.  I think it's worth doing here since it'll
Pedro> end up touching many of the same same lines you're already
Pedro> touching in bcache.c.  LGTM with that change.

Thanks.  Here is what I am checking in.

Tom

commit a99eb1e73b1b66143d670322ebeb639c82468aed
Author: Tom Tromey <tom@tromey.com>
Date:   Thu Mar 7 04:20:19 2019 -0700

    C++-ify bcache
    
    This somewhat C++-ifies bcache.  It replaces bcache_xmalloc and
    bcache_xfree with constructors; changes some functions into methods;
    and changes various structures to include a bcache directly (as
    opposed to a pointer to a bcache).
    
    Tested by the buildbot.
    
    gdb/ChangeLog
    2019-03-07  Tom Tromey  <tom@tromey.com>
    
            * symmisc.c (print_symbol_bcache_statistics): Update.
            (print_objfile_statistics): Update.
            * symfile.c (allocate_symtab): Update.
            * stabsread.c: Don't include bcache.h.
            * psymtab.h (struct psymbol_bcache): Don't declare.
            (class psymtab_storage) <psymbol_cache>: Now a bcache.
            (psymbol_bcache_init, psymbol_bcache_free)
            (psymbol_bcache_get_bcache): Don't declare.
            * psymtab.c (struct psymbol_bcache): Remove.
            (psymtab_storage::psymtab_storage): Update.
            (psymtab_storage::~psymtab_storage): Update.
            (psymbol_bcache_init, psymbol_bcache_free)
            (psymbol_bcache_get_bcache, psymbol_bcache_full): Remove.
            (add_psymbol_to_bcache): Update.
            (allocate_psymtab): Update.
            * objfiles.h (struct objfile_per_bfd_storage) <filename_cache,
            macro_cache>: No longer pointers.
            * objfiles.c (get_objfile_bfd_data): Don't call bcache_xmalloc.
            (free_objfile_per_bfd_storage): Don't call bcache_xfree.
            * macrotab.c (macro_bcache): Update.
            * macroexp.c: Don't include bcache.h.
            * gdbtypes.c (check_types_worklist): Update.
            (types_deeply_equal): Remove TRY/CATCH.  Update.
            * elfread.c (elf_symtab_read): Update.
            * dwarf2read.c: Don't include bcache.h.
            * buildsym.c (buildsym_compunit::get_macro_table): Update.
            * bcache.h (bcache, bcache_full, bcache_xffree, bcache_xmalloc)
            (print_bcache_statistics, bcache_memory_used): Don't declare.
            (struct bcache): Move from bcache.c.  Add constructor, destructor,
            methods.  Rename all data members.
            * bcache.c (struct bcache): Move to bcache.h.
            (bcache::expand_hash_table): Rename from expand_hash_table.
            (bcache): Remove.
            (bcache::insert): Rename from bcache_full.
            (bcache::compare): Rename from bcache_compare.
            (bcache_xmalloc): Remove.
            (bcache::~bcache): Rename from bcache_xfree.
            (bcache::print_statistics): Rename from print_bcache_statistics.
            (bcache::memory_used): Rename from bcache_memory_used.

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d3d6e5b4ee6..331bc740c6f 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,45 @@ 
+2019-03-07  Tom Tromey  <tom@tromey.com>
+
+	* symmisc.c (print_symbol_bcache_statistics): Update.
+	(print_objfile_statistics): Update.
+	* symfile.c (allocate_symtab): Update.
+	* stabsread.c: Don't include bcache.h.
+	* psymtab.h (struct psymbol_bcache): Don't declare.
+	(class psymtab_storage) <psymbol_cache>: Now a bcache.
+	(psymbol_bcache_init, psymbol_bcache_free)
+	(psymbol_bcache_get_bcache): Don't declare.
+	* psymtab.c (struct psymbol_bcache): Remove.
+	(psymtab_storage::psymtab_storage): Update.
+	(psymtab_storage::~psymtab_storage): Update.
+	(psymbol_bcache_init, psymbol_bcache_free)
+	(psymbol_bcache_get_bcache, psymbol_bcache_full): Remove.
+	(add_psymbol_to_bcache): Update.
+	(allocate_psymtab): Update.
+	* objfiles.h (struct objfile_per_bfd_storage) <filename_cache,
+	macro_cache>: No longer pointers.
+	* objfiles.c (get_objfile_bfd_data): Don't call bcache_xmalloc.
+	(free_objfile_per_bfd_storage): Don't call bcache_xfree.
+	* macrotab.c (macro_bcache): Update.
+	* macroexp.c: Don't include bcache.h.
+	* gdbtypes.c (check_types_worklist): Update.
+	(types_deeply_equal): Remove TRY/CATCH.  Update.
+	* elfread.c (elf_symtab_read): Update.
+	* dwarf2read.c: Don't include bcache.h.
+	* buildsym.c (buildsym_compunit::get_macro_table): Update.
+	* bcache.h (bcache, bcache_full, bcache_xffree, bcache_xmalloc)
+	(print_bcache_statistics, bcache_memory_used): Don't declare.
+	(struct bcache): Move from bcache.c.  Add constructor, destructor,
+	methods.  Rename all data members.
+	* bcache.c (struct bcache): Move to bcache.h.
+	(bcache::expand_hash_table): Rename from expand_hash_table.
+	(bcache): Remove.
+	(bcache::insert): Rename from bcache_full.
+	(bcache::compare): Rename from bcache_compare.
+	(bcache_xmalloc): Remove.
+	(bcache::~bcache): Rename from bcache_xfree.
+	(bcache::print_statistics): Rename from print_bcache_statistics.
+	(bcache::memory_used): Rename from bcache_memory_used.
+
 2019-03-07  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* f-lang.c (value_from_host_double): Moved to...
diff --git a/gdb/bcache.c b/gdb/bcache.c
index 1430953ac62..14a78474962 100644
--- a/gdb/bcache.c
+++ b/gdb/bcache.c
@@ -49,48 +49,6 @@  struct bstring
   d;
 };
 
-
-/* The structure for a bcache itself.  The bcache is initialized, in
-   bcache_xmalloc(), by filling it with zeros and then setting the
-   corresponding obstack's malloc() and free() methods.  */
-
-struct bcache
-{
-  /* All the bstrings are allocated here.  */
-  struct obstack cache;
-
-  /* How many hash buckets we're using.  */
-  unsigned int num_buckets;
-  
-  /* Hash buckets.  This table is allocated using malloc, so when we
-     grow the table we can return the old table to the system.  */
-  struct bstring **bucket;
-
-  /* Statistics.  */
-  unsigned long unique_count;	/* number of unique strings */
-  long total_count;	/* total number of strings cached, including dups */
-  long unique_size;	/* size of unique strings, in bytes */
-  long total_size;      /* total number of bytes cached, including dups */
-  long structure_size;	/* total size of bcache, including infrastructure */
-  /* Number of times that the hash table is expanded and hence
-     re-built, and the corresponding number of times that a string is
-     [re]hashed as part of entering it into the expanded table.  The
-     total number of hashes can be computed by adding TOTAL_COUNT to
-     expand_hash_count.  */
-  unsigned long expand_count;
-  unsigned long expand_hash_count;
-  /* Number of times that the half-hash compare hit (compare the upper
-     16 bits of hash values) hit, but the corresponding combined
-     length/data compare missed.  */
-  unsigned long half_hash_miss_count;
-
-  /* Hash function to be used for this bcache object.  */
-  unsigned long (*hash_function)(const void *addr, int length);
-
-  /* Compare function to be used for this bcache object.  */
-  int (*compare_function)(const void *, const void *, int length);
-};
-
 /* The old hash function was stolen from SDBM. This is what DB 3.0
    uses now, and is better than the old one.  */
 
@@ -123,8 +81,8 @@  hash_continue (const void *addr, int length, unsigned long h)
    resize our hash table.  */
 #define CHAIN_LENGTH_THRESHOLD (5)
 
-static void
-expand_hash_table (struct bcache *bcache)
+void
+bcache::expand_hash_table ()
 {
   /* A table of good hash table sizes.  Whenever we grow, we pick the
      next larger size from this table.  sizes[i] is close to 1 << (i+10),
@@ -143,13 +101,13 @@  expand_hash_table (struct bcache *bcache)
 
   /* Count the stats.  Every unique item needs to be re-hashed and
      re-entered.  */
-  bcache->expand_count++;
-  bcache->expand_hash_count += bcache->unique_count;
+  m_expand_count++;
+  m_expand_hash_count += m_unique_count;
 
   /* Find the next size.  */
-  new_num_buckets = bcache->num_buckets * 2;
+  new_num_buckets = m_num_buckets * 2;
   for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
-    if (sizes[i] > bcache->num_buckets)
+    if (sizes[i] > m_num_buckets)
       {
 	new_num_buckets = sizes[i];
 	break;
@@ -162,23 +120,21 @@  expand_hash_table (struct bcache *bcache)
     new_buckets = (struct bstring **) xmalloc (new_size);
     memset (new_buckets, 0, new_size);
 
-    bcache->structure_size -= (bcache->num_buckets
-			       * sizeof (bcache->bucket[0]));
-    bcache->structure_size += new_size;
+    m_structure_size -= m_num_buckets * sizeof (m_bucket[0]);
+    m_structure_size += new_size;
   }
 
   /* Rehash all existing strings.  */
-  for (i = 0; i < bcache->num_buckets; i++)
+  for (i = 0; i < m_num_buckets; i++)
     {
       struct bstring *s, *next;
 
-      for (s = bcache->bucket[i]; s; s = next)
+      for (s = m_bucket[i]; s; s = next)
 	{
 	  struct bstring **new_bucket;
 	  next = s->next;
 
-	  new_bucket = &new_buckets[(bcache->hash_function (&s->d.data,
-							    s->length)
+	  new_bucket = &new_buckets[(m_hash_function (&s->d.data, s->length)
 				     % new_num_buckets)];
 	  s->next = *new_bucket;
 	  *new_bucket = s;
@@ -186,10 +142,9 @@  expand_hash_table (struct bcache *bcache)
     }
 
   /* Plug in the new table.  */
-  if (bcache->bucket)
-    xfree (bcache->bucket);
-  bcache->bucket = new_buckets;
-  bcache->num_buckets = new_num_buckets;
+  xfree (m_bucket);
+  m_bucket = new_buckets;
+  m_num_buckets = new_num_buckets;
 }
 
 
@@ -199,15 +154,6 @@  expand_hash_table (struct bcache *bcache)
    is N bytes long.  */
 #define BSTRING_SIZE(n) (offsetof (struct bstring, d.data) + (n))
 
-/* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
-   never seen those bytes before, add a copy of them to BCACHE.  In
-   either case, return a pointer to BCACHE's copy of that string.  */
-const void *
-bcache (const void *addr, int length, struct bcache *cache)
-{
-  return bcache_full (addr, length, cache, NULL);
-}
-
 /* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
    never seen those bytes before, add a copy of them to BCACHE.  In
    either case, return a pointer to BCACHE's copy of that string.  If
@@ -215,7 +161,7 @@  bcache (const void *addr, int length, struct bcache *cache)
    returning an old entry.  */
 
 const void *
-bcache_full (const void *addr, int length, struct bcache *bcache, int *added)
+bcache::insert (const void *addr, int length, int *added)
 {
   unsigned long full_hash;
   unsigned short half_hash;
@@ -227,56 +173,56 @@  bcache_full (const void *addr, int length, struct bcache *bcache, int *added)
 
   /* Lazily initialize the obstack.  This can save quite a bit of
      memory in some cases.  */
-  if (bcache->total_count == 0)
+  if (m_total_count == 0)
     {
       /* We could use obstack_specify_allocation here instead, but
 	 gdb_obstack.h specifies the allocation/deallocation
 	 functions.  */
-      obstack_init (&bcache->cache);
+      obstack_init (&m_cache);
     }
 
   /* If our average chain length is too high, expand the hash table.  */
-  if (bcache->unique_count >= bcache->num_buckets * CHAIN_LENGTH_THRESHOLD)
-    expand_hash_table (bcache);
+  if (m_unique_count >= m_num_buckets * CHAIN_LENGTH_THRESHOLD)
+    expand_hash_table ();
 
-  bcache->total_count++;
-  bcache->total_size += length;
+  m_total_count++;
+  m_total_size += length;
 
-  full_hash = bcache->hash_function (addr, length);
+  full_hash = m_hash_function (addr, length);
 
   half_hash = (full_hash >> 16);
-  hash_index = full_hash % bcache->num_buckets;
+  hash_index = full_hash % m_num_buckets;
 
-  /* Search the hash bucket for a string identical to the caller's.
+  /* Search the hash m_bucket for a string identical to the caller's.
      As a short-circuit first compare the upper part of each hash
      values.  */
-  for (s = bcache->bucket[hash_index]; s; s = s->next)
+  for (s = m_bucket[hash_index]; s; s = s->next)
     {
       if (s->half_hash == half_hash)
 	{
 	  if (s->length == length
-	      && bcache->compare_function (&s->d.data, addr, length))
+	      && m_compare_function (&s->d.data, addr, length))
 	    return &s->d.data;
 	  else
-	    bcache->half_hash_miss_count++;
+	    m_half_hash_miss_count++;
 	}
     }
 
   /* The user's string isn't in the list.  Insert it after *ps.  */
   {
     struct bstring *newobj
-      = (struct bstring *) obstack_alloc (&bcache->cache,
+      = (struct bstring *) obstack_alloc (&m_cache,
 					  BSTRING_SIZE (length));
 
     memcpy (&newobj->d.data, addr, length);
     newobj->length = length;
-    newobj->next = bcache->bucket[hash_index];
+    newobj->next = m_bucket[hash_index];
     newobj->half_hash = half_hash;
-    bcache->bucket[hash_index] = newobj;
+    m_bucket[hash_index] = newobj;
 
-    bcache->unique_count++;
-    bcache->unique_size += length;
-    bcache->structure_size += BSTRING_SIZE (length);
+    m_unique_count++;
+    m_unique_size += length;
+    m_structure_size += BSTRING_SIZE (length);
 
     if (added)
       *added = 1;
@@ -289,51 +235,19 @@  bcache_full (const void *addr, int length, struct bcache *bcache, int *added)
 /* Compare the byte string at ADDR1 of lenght LENGHT to the
    string at ADDR2.  Return 1 if they are equal.  */
 
-static int
-bcache_compare (const void *addr1, const void *addr2, int length)
+int
+bcache::compare (const void *addr1, const void *addr2, int length)
 {
   return memcmp (addr1, addr2, length) == 0;
 }
 
-/* Allocating and freeing bcaches.  */
-
-/* Allocated a bcache.  HASH_FUNCTION and COMPARE_FUNCTION can be used
-   to pass in custom hash, and compare functions to be used by this
-   bcache.  If HASH_FUNCTION is NULL hash() is used and if
-   COMPARE_FUNCTION is NULL memcmp() is used.  */
-
-struct bcache *
-bcache_xmalloc (unsigned long (*hash_function)(const void *, int length),
-                int (*compare_function)(const void *, 
-					const void *, 
-					int length))
-{
-  /* Allocate the bcache pre-zeroed.  */
-  struct bcache *b = XCNEW (struct bcache);
-
-  if (hash_function)
-    b->hash_function = hash_function;
-  else
-    b->hash_function = hash;
-
-  if (compare_function)
-    b->compare_function = compare_function;
-  else
-    b->compare_function = bcache_compare;
-  return b;
-}
-
 /* Free all the storage associated with BCACHE.  */
-void
-bcache_xfree (struct bcache *bcache)
+bcache::~bcache ()
 {
-  if (bcache == NULL)
-    return;
   /* Only free the obstack if we actually initialized it.  */
-  if (bcache->total_count > 0)
-    obstack_free (&bcache->cache, 0);
-  xfree (bcache->bucket);
-  xfree (bcache);
+  if (m_total_count > 0)
+    obstack_free (&m_cache, 0);
+  xfree (m_bucket);
 }
 
 
@@ -356,7 +270,7 @@  print_percentage (int portion, int total)
    BCACHE holds.  Statistics are printed using `printf_filtered' and
    its ilk.  */
 void
-print_bcache_statistics (struct bcache *c, const char *type)
+bcache::print_statistics (const char *type)
 {
   int occupied_buckets;
   int max_chain_length;
@@ -368,15 +282,15 @@  print_bcache_statistics (struct bcache *c, const char *type)
      lengths, and measure chain lengths.  */
   {
     unsigned int b;
-    int *chain_length = XCNEWVEC (int, c->num_buckets + 1);
-    int *entry_size = XCNEWVEC (int, c->unique_count + 1);
+    int *chain_length = XCNEWVEC (int, m_num_buckets + 1);
+    int *entry_size = XCNEWVEC (int, m_unique_count + 1);
     int stringi = 0;
 
     occupied_buckets = 0;
 
-    for (b = 0; b < c->num_buckets; b++)
+    for (b = 0; b < m_num_buckets; b++)
       {
-	struct bstring *s = c->bucket[b];
+	struct bstring *s = m_bucket[b];
 
 	chain_length[b] = 0;
 
@@ -386,9 +300,9 @@  print_bcache_statistics (struct bcache *c, const char *type)
 	    
 	    while (s)
 	      {
-		gdb_assert (b < c->num_buckets);
+		gdb_assert (b < m_num_buckets);
 		chain_length[b]++;
-		gdb_assert (stringi < c->unique_count);
+		gdb_assert (stringi < m_unique_count);
 		entry_size[stringi++] = s->length;
 		s = s->next;
 	      }
@@ -397,25 +311,25 @@  print_bcache_statistics (struct bcache *c, const char *type)
 
     /* To compute the median, we need the set of chain lengths
        sorted.  */
-    qsort (chain_length, c->num_buckets, sizeof (chain_length[0]),
+    qsort (chain_length, m_num_buckets, sizeof (chain_length[0]),
 	   compare_positive_ints);
-    qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
+    qsort (entry_size, m_unique_count, sizeof (entry_size[0]),
 	   compare_positive_ints);
 
-    if (c->num_buckets > 0)
+    if (m_num_buckets > 0)
       {
-	max_chain_length = chain_length[c->num_buckets - 1];
-	median_chain_length = chain_length[c->num_buckets / 2];
+	max_chain_length = chain_length[m_num_buckets - 1];
+	median_chain_length = chain_length[m_num_buckets / 2];
       }
     else
       {
 	max_chain_length = 0;
 	median_chain_length = 0;
       }
-    if (c->unique_count > 0)
+    if (m_unique_count > 0)
       {
-	max_entry_size = entry_size[c->unique_count - 1];
-	median_entry_size = entry_size[c->unique_count / 2];
+	max_entry_size = entry_size[m_unique_count - 1];
+	median_entry_size = entry_size[m_unique_count / 2];
       }
     else
       {
@@ -427,23 +341,23 @@  print_bcache_statistics (struct bcache *c, const char *type)
     xfree (entry_size);
   }
 
-  printf_filtered (_("  Cached '%s' statistics:\n"), type);
-  printf_filtered (_("    Total object count:  %ld\n"), c->total_count);
-  printf_filtered (_("    Unique object count: %lu\n"), c->unique_count);
+  printf_filtered (_("  M_Cached '%s' statistics:\n"), type);
+  printf_filtered (_("    Total object count:  %ld\n"), m_total_count);
+  printf_filtered (_("    Unique object count: %lu\n"), m_unique_count);
   printf_filtered (_("    Percentage of duplicates, by count: "));
-  print_percentage (c->total_count - c->unique_count, c->total_count);
+  print_percentage (m_total_count - m_unique_count, m_total_count);
   printf_filtered ("\n");
 
-  printf_filtered (_("    Total object size:   %ld\n"), c->total_size);
-  printf_filtered (_("    Unique object size:  %ld\n"), c->unique_size);
+  printf_filtered (_("    Total object size:   %ld\n"), m_total_size);
+  printf_filtered (_("    Unique object size:  %ld\n"), m_unique_size);
   printf_filtered (_("    Percentage of duplicates, by size:  "));
-  print_percentage (c->total_size - c->unique_size, c->total_size);
+  print_percentage (m_total_size - m_unique_size, m_total_size);
   printf_filtered ("\n");
 
   printf_filtered (_("    Max entry size:     %d\n"), max_entry_size);
   printf_filtered (_("    Average entry size: "));
-  if (c->unique_count > 0)
-    printf_filtered ("%ld\n", c->unique_size / c->unique_count);
+  if (m_unique_count > 0)
+    printf_filtered ("%ld\n", m_unique_size / m_unique_count);
   else
     /* i18n: "Average entry size: (not applicable)".  */
     printf_filtered (_("(not applicable)\n"));    
@@ -452,28 +366,28 @@  print_bcache_statistics (struct bcache *c, const char *type)
 
   printf_filtered (_("    \
 Total memory used by bcache, including overhead: %ld\n"),
-		   c->structure_size);
+		   m_structure_size);
   printf_filtered (_("    Percentage memory overhead: "));
-  print_percentage (c->structure_size - c->unique_size, c->unique_size);
+  print_percentage (m_structure_size - m_unique_size, m_unique_size);
   printf_filtered (_("    Net memory savings:         "));
-  print_percentage (c->total_size - c->structure_size, c->total_size);
+  print_percentage (m_total_size - m_structure_size, m_total_size);
   printf_filtered ("\n");
 
   printf_filtered (_("    Hash table size:           %3d\n"), 
-		   c->num_buckets);
+		   m_num_buckets);
   printf_filtered (_("    Hash table expands:        %lu\n"),
-		   c->expand_count);
+		   m_expand_count);
   printf_filtered (_("    Hash table hashes:         %lu\n"),
-		   c->total_count + c->expand_hash_count);
+		   m_total_count + m_expand_hash_count);
   printf_filtered (_("    Half hash misses:          %lu\n"),
-		   c->half_hash_miss_count);
+		   m_half_hash_miss_count);
   printf_filtered (_("    Hash table population:     "));
-  print_percentage (occupied_buckets, c->num_buckets);
+  print_percentage (occupied_buckets, m_num_buckets);
   printf_filtered (_("    Median hash chain length:  %3d\n"),
 		   median_chain_length);
   printf_filtered (_("    Average hash chain length: "));
-  if (c->num_buckets > 0)
-    printf_filtered ("%3lu\n", c->unique_count / c->num_buckets);
+  if (m_num_buckets > 0)
+    printf_filtered ("%3lu\n", m_unique_count / m_num_buckets);
   else
     /* i18n: "Average hash chain length: (not applicable)".  */
     printf_filtered (_("(not applicable)\n"));
@@ -483,9 +397,9 @@  Total memory used by bcache, including overhead: %ld\n"),
 }
 
 int
-bcache_memory_used (struct bcache *bcache)
+bcache::memory_used ()
 {
-  if (bcache->total_count == 0)
+  if (m_total_count == 0)
     return 0;
-  return obstack_memory_used (&bcache->cache);
+  return obstack_memory_used (&m_cache);
 }
diff --git a/gdb/bcache.h b/gdb/bcache.h
index aa0147926c6..15dcc63440f 100644
--- a/gdb/bcache.h
+++ b/gdb/bcache.h
@@ -136,41 +136,89 @@ 
   
 */
 
-
-struct bcache;
-
-/* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
-   never seen those bytes before, add a copy of them to BCACHE.  In
-   either case, return a pointer to BCACHE's copy of that string.
-   Since the cached value is ment to be read-only, return a const
-   buffer.  */
-extern const void *bcache (const void *addr, int length,
-			   struct bcache *bcache);
-
-/* Like bcache, but if ADDED is not NULL, set *ADDED to true if the
-   bytes were newly added to the cache, or to false if the bytes were
-   found in the cache.  */
-extern const void *bcache_full (const void *addr, int length,
-				struct bcache *bcache, int *added);
-
-/* Free all the storage used by BCACHE.  */
-extern void bcache_xfree (struct bcache *bcache);
-
-/* Create a new bcache object.  */
-extern struct bcache *bcache_xmalloc (
-    unsigned long (*hash_function)(const void *, int length),
-    int (*compare_function)(const void *, const void *, int length));
-
-/* Print statistics on BCACHE's memory usage and efficacity at
-   eliminating duplication.  TYPE should be a string describing the
-   kind of data BCACHE holds.  Statistics are printed using
-   `printf_filtered' and its ilk.  */
-extern void print_bcache_statistics (struct bcache *bcache, const char *type);
-extern int bcache_memory_used (struct bcache *bcache);
+struct bstring;
 
 /* The hash functions */
-extern unsigned long hash(const void *addr, int length);
+extern unsigned long hash (const void *addr, int length);
 extern unsigned long hash_continue (const void *addr, int length,
                                     unsigned long h);
 
+struct bcache
+{
+  /* Allocate a bcache.  HASH_FN and COMPARE_FN can be used to pass in
+     custom hash, and compare functions to be used by this bcache.  If
+     HASH_FUNCTION is NULL hash() is used and if COMPARE_FUNCTION is
+     NULL memcmp() is used.  */
+
+  explicit bcache (unsigned long (*hash_fn)(const void *,
+					    int length) = nullptr,
+		   int (*compare_fn)(const void *, const void *,
+				     int length) = nullptr)
+    : m_hash_function (hash_fn == nullptr ? hash : hash_fn),
+      m_compare_function (compare_fn == nullptr ? compare : compare_fn)
+  {
+  }
+
+  ~bcache ();
+
+  /* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
+     never seen those bytes before, add a copy of them to BCACHE.  In
+     either case, return a pointer to BCACHE's copy of that string.
+     Since the cached value is ment to be read-only, return a const
+     buffer.  If ADDED is not NULL, set *ADDED to true if the bytes
+     were newly added to the cache, or to false if the bytes were
+     found in the cache.  */
+
+  const void *insert (const void *addr, int length, int *added = nullptr);
+
+  /* Print statistics on this bcache's memory usage and efficacity at
+     eliminating duplication.  TYPE should be a string describing the
+     kind of data this bcache holds.  Statistics are printed using
+     `printf_filtered' and its ilk.  */
+  void print_statistics (const char *type);
+  int memory_used ();
+
+private:
+
+  /* All the bstrings are allocated here.  */
+  struct obstack m_cache {};
+
+  /* How many hash buckets we're using.  */
+  unsigned int m_num_buckets = 0;
+
+  /* Hash buckets.  This table is allocated using malloc, so when we
+     grow the table we can return the old table to the system.  */
+  struct bstring **m_bucket = nullptr;
+
+  /* Statistics.  */
+  unsigned long m_unique_count = 0;	/* number of unique strings */
+  long m_total_count = 0;	/* total number of strings cached, including dups */
+  long m_unique_size = 0;	/* size of unique strings, in bytes */
+  long m_total_size = 0;      /* total number of bytes cached, including dups */
+  long m_structure_size = 0;	/* total size of bcache, including infrastructure */
+  /* Number of times that the hash table is expanded and hence
+     re-built, and the corresponding number of times that a string is
+     [re]hashed as part of entering it into the expanded table.  The
+     total number of hashes can be computed by adding TOTAL_COUNT to
+     expand_hash_count.  */
+  unsigned long m_expand_count = 0;
+  unsigned long m_expand_hash_count = 0;
+  /* Number of times that the half-hash compare hit (compare the upper
+     16 bits of hash values) hit, but the corresponding combined
+     length/data compare missed.  */
+  unsigned long m_half_hash_miss_count = 0;
+
+  /* Hash function to be used for this bcache object.  */
+  unsigned long (*m_hash_function)(const void *addr, int length);
+
+  /* Compare function to be used for this bcache object.  */
+  int (*m_compare_function)(const void *, const void *, int length);
+
+  /* Default compare function.  */
+  static int compare (const void *addr1, const void *addr2, int length);
+
+  /* Expand the hash table.  */
+  void expand_hash_table ();
+};
+
 #endif /* BCACHE_H */
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index bd0f25e061e..9a23c8f5254 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -122,7 +122,7 @@  buildsym_compunit::get_macro_table ()
 {
   if (m_pending_macros == nullptr)
     m_pending_macros = new_macro_table (&m_objfile->per_bfd->storage_obstack,
-					m_objfile->per_bfd->macro_cache,
+					&m_objfile->per_bfd->macro_cache,
 					m_compunit_symtab);
   return m_pending_macros;
 }
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 2d6cb353fbb..0c59dcd2042 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -46,7 +46,6 @@ 
 #include "macrotab.h"
 #include "language.h"
 #include "complaints.h"
-#include "bcache.h"
 #include "dwarf2expr.h"
 #include "dwarf2loc.h"
 #include "cp-support.h"
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 8fc6692b112..55a16bb2f8e 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -334,8 +334,8 @@  elf_symtab_read (minimal_symbol_reader &reader,
       if (sym->flags & BSF_FILE)
 	{
 	  filesymname
-	    = (const char *) bcache (sym->name, strlen (sym->name) + 1,
-				     objfile->per_bfd->filename_cache);
+	    = ((const char *) objfile->per_bfd->filename_cache.insert
+	       (sym->name, strlen (sym->name) + 1));
 	}
       else if (sym->flags & BSF_SECTION_SYM)
 	continue;
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index b5f269241c4..8e48587caa4 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3732,7 +3732,7 @@  check_types_worklist (std::vector<type_equality_entry> *worklist,
 
       /* If the type pair has already been visited, we know it is
 	 ok.  */
-      bcache_full (&entry, sizeof (entry), cache, &added);
+      cache->insert (&entry, sizeof (entry), &added);
       if (!added)
 	continue;
 
@@ -3749,9 +3749,6 @@  check_types_worklist (std::vector<type_equality_entry> *worklist,
 bool
 types_deeply_equal (struct type *type1, struct type *type2)
 {
-  struct gdb_exception except = exception_none;
-  bool result = false;
-  struct bcache *cache;
   std::vector<type_equality_entry> worklist;
 
   gdb_assert (type1 != NULL && type2 != NULL);
@@ -3760,31 +3757,9 @@  types_deeply_equal (struct type *type1, struct type *type2)
   if (type1 == type2)
     return true;
 
-  cache = bcache_xmalloc (NULL, NULL);
-
+  struct bcache cache (nullptr, nullptr);
   worklist.emplace_back (type1, type2);
-
-  /* check_types_worklist calls several nested helper functions, some
-     of which can raise a GDB exception, so we just check and rethrow
-     here.  If there is a GDB exception, a comparison is not capable
-     (or trusted), so exit.  */
-  TRY
-    {
-      result = check_types_worklist (&worklist, cache);
-    }
-  CATCH (ex, RETURN_MASK_ALL)
-    {
-      except = ex;
-    }
-  END_CATCH
-
-  bcache_xfree (cache);
-
-  /* Rethrow if there was a problem.  */
-  if (except.reason < 0)
-    throw_exception (except);
-
-  return result;
+  return check_types_worklist (&worklist, &cache);
 }
 
 /* Allocated status of type TYPE.  Return zero if type TYPE is allocated.
diff --git a/gdb/macroexp.c b/gdb/macroexp.c
index a588cc836fe..33a72a7271f 100644
--- a/gdb/macroexp.c
+++ b/gdb/macroexp.c
@@ -19,7 +19,6 @@ 
 
 #include "defs.h"
 #include "gdb_obstack.h"
-#include "bcache.h"
 #include "macrotab.h"
 #include "macroexp.h"
 #include "c-lang.h"
diff --git a/gdb/macrotab.c b/gdb/macrotab.c
index fa3061616bd..90f29439c09 100644
--- a/gdb/macrotab.c
+++ b/gdb/macrotab.c
@@ -113,7 +113,7 @@  static const void *
 macro_bcache (struct macro_table *t, const void *addr, int len)
 {
   if (t->bcache)
-    return bcache (addr, len, t->bcache);
+    return t->bcache->insert (addr, len);
   else
     {
       void *copy = xmalloc (len);
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 34b271e86de..4091b42dbf1 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -157,8 +157,6 @@  get_objfile_bfd_data (struct objfile *objfile, struct bfd *abfd)
       if (abfd != NULL)
 	storage->gdbarch = gdbarch_from_bfd (abfd);
 
-      storage->filename_cache = bcache_xmalloc (NULL, NULL);
-      storage->macro_cache = bcache_xmalloc (NULL, NULL);
       storage->language_of_main = language_unknown;
     }
 
@@ -170,8 +168,6 @@  get_objfile_bfd_data (struct objfile *objfile, struct bfd *abfd)
 static void
 free_objfile_per_bfd_storage (struct objfile_per_bfd_storage *storage)
 {
-  bcache_xfree (storage->filename_cache);
-  bcache_xfree (storage->macro_cache);
   if (storage->demangled_names_hash)
     htab_delete (storage->demangled_names_hash);
   storage->~objfile_per_bfd_storage ();
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a10781f598e..c5ce9eec955 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -240,11 +240,11 @@  struct objfile_per_bfd_storage
 
   /* Byte cache for file names.  */
 
-  struct bcache *filename_cache = NULL;
+  struct bcache filename_cache;
 
   /* Byte cache for macros.  */
 
-  struct bcache *macro_cache = NULL;
+  struct bcache macro_cache;
 
   /* The gdbarch associated with the BFD.  Note that this gdbarch is
      determined solely from BFD information, without looking at target
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 17db29759c4..96b4fa0bf88 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -26,7 +26,6 @@ 
 #include "source.h"
 #include "addrmap.h"
 #include "gdbtypes.h"
-#include "bcache.h"
 #include "ui-out.h"
 #include "command.h"
 #include "readline/readline.h"
@@ -38,11 +37,6 @@ 
 #include <algorithm>
 #include <set>
 
-struct psymbol_bcache
-{
-  struct bcache *bcache;
-};
-
 static struct partial_symbol *match_partial_symbol (struct objfile *,
 						    struct partial_symtab *,
 						    int,
@@ -67,14 +61,16 @@  static struct compunit_symtab *psymtab_to_symtab (struct objfile *objfile,
 
 
 
+static unsigned long psymbol_hash (const void *addr, int length);
+static int psymbol_compare (const void *addr1, const void *addr2, int length);
+
 psymtab_storage::psymtab_storage ()
-  : psymbol_cache (psymbol_bcache_init ())
+  : psymbol_cache (psymbol_hash, psymbol_compare)
 {
 }
 
 psymtab_storage::~psymtab_storage ()
 {
-  psymbol_bcache_free (psymbol_cache);
 }
 
 /* See psymtab.h.  */
@@ -1589,52 +1585,6 @@  psymbol_compare (const void *addr1, const void *addr2, int length)
           && sym1->name == sym2->name);
 }
 
-/* Initialize a partial symbol bcache.  */
-
-struct psymbol_bcache *
-psymbol_bcache_init (void)
-{
-  struct psymbol_bcache *bcache = XCNEW (struct psymbol_bcache);
-
-  bcache->bcache = bcache_xmalloc (psymbol_hash, psymbol_compare);
-  return bcache;
-}
-
-/* Free a partial symbol bcache.  */
-
-void
-psymbol_bcache_free (struct psymbol_bcache *bcache)
-{
-  if (bcache == NULL)
-    return;
-
-  bcache_xfree (bcache->bcache);
-  xfree (bcache);
-}
-
-/* Return the internal bcache of the psymbol_bcache BCACHE.  */
-
-struct bcache *
-psymbol_bcache_get_bcache (struct psymbol_bcache *bcache)
-{
-  return bcache->bcache;
-}
-
-/* Find a copy of the SYM in BCACHE.  If BCACHE has never seen this
-   symbol before, add a copy to BCACHE.  In either case, return a pointer
-   to BCACHE's copy of the symbol.  If optional ADDED is not NULL, return
-   1 in case of new entry or 0 if returning an old entry.  */
-
-static struct partial_symbol *
-psymbol_bcache_full (struct partial_symbol *sym,
-                     struct psymbol_bcache *bcache,
-                     int *added)
-{
-  return ((struct partial_symbol *)
-	  bcache_full (sym, sizeof (struct partial_symbol), bcache->bcache,
-		       added));
-}
-
 /* Helper function, initialises partial symbol structure and stashes
    it into objfile's bcache.  Note that our caching mechanism will
    use all fields of struct partial_symbol to determine hash value of the
@@ -1664,9 +1614,9 @@  add_psymbol_to_bcache (const char *name, int namelength, int copy_name,
   symbol_set_names (&psymbol, name, namelength, copy_name, objfile->per_bfd);
 
   /* Stash the partial symbol away in the cache.  */
-  return psymbol_bcache_full (&psymbol,
-			      objfile->partial_symtabs->psymbol_cache,
-			      added);
+  return ((struct partial_symbol *)
+	  objfile->partial_symtabs->psymbol_cache.insert
+	  (&psymbol, sizeof (struct partial_symbol), added));
 }
 
 /* Helper function, adds partial symbol to the given partial symbol list.  */
@@ -1741,8 +1691,8 @@  allocate_psymtab (const char *filename, struct objfile *objfile)
     = objfile->partial_symtabs->allocate_psymtab ();
 
   psymtab->filename
-    = (const char *) bcache (filename, strlen (filename) + 1,
-			     objfile->per_bfd->filename_cache);
+    = ((const char *) objfile->per_bfd->filename_cache.insert
+       (filename, strlen (filename) + 1));
   psymtab->compunit_symtab = NULL;
 
   if (symtab_create_debug)
diff --git a/gdb/psymtab.h b/gdb/psymtab.h
index 3ee5eee0b65..c761fa72222 100644
--- a/gdb/psymtab.h
+++ b/gdb/psymtab.h
@@ -23,13 +23,10 @@ 
 #include "gdb_obstack.h"
 #include "symfile.h"
 #include "common/next-iterator.h"
+#include "bcache.h"
 
 struct partial_symbol;
 
-/* A bcache for partial symbols.  */
-
-struct psymbol_bcache;
-
 /* An instance of this class manages the partial symbol tables and
    partial symbols for a given objfile.
 
@@ -119,7 +116,7 @@  public:
   /* A byte cache where we can stash arbitrary "chunks" of bytes that
      will not change.  */
 
-  struct psymbol_bcache *psymbol_cache;
+  struct bcache psymbol_cache;
 
   /* Vectors of all partial symbols read in from file.  The actual data
      is stored in the objfile_obstack.  */
@@ -140,10 +137,6 @@  private:
 };
 
 
-extern struct psymbol_bcache *psymbol_bcache_init (void);
-extern void psymbol_bcache_free (struct psymbol_bcache *);
-extern struct bcache *psymbol_bcache_get_bcache (struct psymbol_bcache *);
-
 extern const struct quick_symbol_functions psym_functions;
 
 extern const struct quick_symbol_functions dwarf2_gdb_index_functions;
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index ac33465c13b..3f340dbf20d 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -44,7 +44,6 @@ 
 #include "target-float.h"
 #include "cp-abi.h"
 #include "cp-support.h"
-#include "bcache.h"
 #include <ctype.h>
 
 #include "stabsread.h"
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 61483824f63..2214f16b431 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -2795,8 +2795,8 @@  allocate_symtab (struct compunit_symtab *cust, const char *filename)
     = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symtab);
 
   symtab->filename
-    = (const char *) bcache (filename, strlen (filename) + 1,
-			     objfile->per_bfd->filename_cache);
+    = ((const char *) objfile->per_bfd->filename_cache.insert
+       (filename, strlen (filename) + 1));
   symtab->fullname = NULL;
   symtab->language = deduce_language_from_filename (filename);
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index bb4fdfd1ed9..cb0b5a52e47 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -69,13 +69,11 @@  print_symbol_bcache_statistics (void)
 	QUIT;
 	printf_filtered (_("Byte cache statistics for '%s':\n"),
 			 objfile_name (objfile));
-	print_bcache_statistics
-	  (psymbol_bcache_get_bcache (objfile->partial_symtabs->psymbol_cache),
-	   "partial symbol cache");
-	print_bcache_statistics (objfile->per_bfd->macro_cache,
-				 "preprocessor macro cache");
-	print_bcache_statistics (objfile->per_bfd->filename_cache,
-				 "file name cache");
+	objfile->partial_symtabs->psymbol_cache.print_statistics
+	  ("partial symbol cache");
+	objfile->per_bfd->macro_cache.print_statistics
+	  ("preprocessor macro cache");
+	objfile->per_bfd->filename_cache.print_statistics ("file name cache");
       }
 }
 
@@ -136,12 +134,11 @@  print_objfile_statistics (void)
 						       ->storage_obstack)));
       printf_filtered
 	(_("  Total memory used for psymbol cache: %d\n"),
-	 bcache_memory_used (psymbol_bcache_get_bcache
-			     (objfile->partial_symtabs->psymbol_cache)));
+	 objfile->partial_symtabs->psymbol_cache.memory_used ());
       printf_filtered (_("  Total memory used for macro cache: %d\n"),
-		       bcache_memory_used (objfile->per_bfd->macro_cache));
+		       objfile->per_bfd->macro_cache.memory_used ());
       printf_filtered (_("  Total memory used for file name cache: %d\n"),
-		       bcache_memory_used (objfile->per_bfd->filename_cache));
+		       objfile->per_bfd->filename_cache.memory_used ());
     }
 }