[v2,22/22] Introduce and use bcache_up

Message ID 20190227201849.32210-23-tom@tromey.com
State New
Headers show
Series
  • Remove cleanups
Related show

Commit Message

Tom Tromey Feb. 27, 2019, 8:18 p.m.
This introduces a new bcache_up typedef, which is a unique_ptr
specialization for managing a bcache.  Then, this changes various
spots to use this object, rather than manually calling bcache_xfree.
This lets us remove a try/catch that only existed to call
bcache_xfree.

gdb/ChangeLog
2019-02-27  Tom Tromey  <tom@tromey.com>

	* symmisc.c (print_symbol_bcache_statistics)
	(print_objfile_statistics): Update.
	* symfile.c (allocate_symtab): Update.
	* psymtab.c (allocate_psymtab): Update.
	* objfiles.h (struct objfile_per_bfd_storage) <filename_cache,
	macro_cache>: Change type to bcache_up.
	* objfiles.c (get_objfile_bfd_data): Update.
	(free_objfile_per_bfd_storage): Don't call bcache_xfree.
	* gdbtypes.c (types_deeply_equal): Use bcache_up.
	* elfread.c (elf_symtab_read): Update.
	* buildsym.c (buildsym_compunit::get_macro_table): Update.
	* bcache.h (struct bcache_deleter): New.
	(bcache_up): New typedef.
---
 gdb/ChangeLog  | 16 ++++++++++++++++
 gdb/bcache.h   | 12 ++++++++++++
 gdb/buildsym.c |  2 +-
 gdb/elfread.c  |  2 +-
 gdb/gdbtypes.c | 26 ++------------------------
 gdb/objfiles.c |  6 ++----
 gdb/objfiles.h |  6 +++---
 gdb/psymtab.c  |  2 +-
 gdb/symfile.c  |  2 +-
 gdb/symmisc.c  |  8 ++++----
 10 files changed, 43 insertions(+), 39 deletions(-)

-- 
2.17.2

Comments

Pedro Alves March 6, 2019, 10:03 p.m. | #1
On 02/27/2019 08:18 PM, Tom Tromey wrote:
> This introduces a new bcache_up typedef, which is a unique_ptr

> specialization for managing a bcache.  Then, this changes various

> spots to use this object, rather than manually calling bcache_xfree.

> This lets us remove a try/catch that only existed to call

> bcache_xfree.


I won't object, but is seems to me that it'd be better to
make bcache_xmalloc / bcache_free ctors/dtors of struct bcache,
and then we'd allocate a bcache object on the stack (and likewise
hold bcache objects in structures instead of bcache pointers).

Thanks,
Pedro Alves
Tom Tromey March 7, 2019, 4:53 p.m. | #2
>> This introduces a new bcache_up typedef, which is a unique_ptr

>> specialization for managing a bcache.  Then, this changes various

>> spots to use this object, rather than manually calling bcache_xfree.

>> This lets us remove a try/catch that only existed to call

>> bcache_xfree.


Pedro> I won't object, but is seems to me that it'd be better to
Pedro> make bcache_xmalloc / bcache_free ctors/dtors of struct bcache,
Pedro> and then we'd allocate a bcache object on the stack (and likewise
Pedro> hold bcache objects in structures instead of bcache pointers).

I broke this one out from the series.  Let me know what you think.

Tom

commit 64ade377efa115d64318be2dbbf40df9d58b9d42
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.
            * 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.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d3d6e5b4ee6..88fe03cc2e7 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.
+	* 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..17593c42d27 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;
+  expand_count++;
+  expand_hash_count += unique_count;
 
   /* Find the next size.  */
-  new_num_buckets = bcache->num_buckets * 2;
+  new_num_buckets = num_buckets * 2;
   for (i = 0; i < (sizeof (sizes) / sizeof (sizes[0])); i++)
-    if (sizes[i] > bcache->num_buckets)
+    if (sizes[i] > 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;
+    structure_size -= num_buckets * sizeof (bucket[0]);
+    structure_size += new_size;
   }
 
   /* Rehash all existing strings.  */
-  for (i = 0; i < bcache->num_buckets; i++)
+  for (i = 0; i < num_buckets; i++)
     {
       struct bstring *s, *next;
 
-      for (s = bcache->bucket[i]; s; s = next)
+      for (s = 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[(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 (bucket);
+  bucket = new_buckets;
+  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 (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 (&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 (unique_count >= num_buckets * CHAIN_LENGTH_THRESHOLD)
+    expand_hash_table ();
 
-  bcache->total_count++;
-  bcache->total_size += length;
+  total_count++;
+  total_size += length;
 
-  full_hash = bcache->hash_function (addr, length);
+  full_hash = hash_function (addr, length);
 
   half_hash = (full_hash >> 16);
-  hash_index = full_hash % bcache->num_buckets;
+  hash_index = full_hash % num_buckets;
 
   /* Search the hash 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 = 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))
+	      && compare_function (&s->d.data, addr, length))
 	    return &s->d.data;
 	  else
-	    bcache->half_hash_miss_count++;
+	    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 (&cache,
 					  BSTRING_SIZE (length));
 
     memcpy (&newobj->d.data, addr, length);
     newobj->length = length;
-    newobj->next = bcache->bucket[hash_index];
+    newobj->next = bucket[hash_index];
     newobj->half_hash = half_hash;
-    bcache->bucket[hash_index] = newobj;
+    bucket[hash_index] = newobj;
 
-    bcache->unique_count++;
-    bcache->unique_size += length;
-    bcache->structure_size += BSTRING_SIZE (length);
+    unique_count++;
+    unique_size += length;
+    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 (total_count > 0)
+    obstack_free (&cache, 0);
+  xfree (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, num_buckets + 1);
+    int *entry_size = XCNEWVEC (int, unique_count + 1);
     int stringi = 0;
 
     occupied_buckets = 0;
 
-    for (b = 0; b < c->num_buckets; b++)
+    for (b = 0; b < num_buckets; b++)
       {
-	struct bstring *s = c->bucket[b];
+	struct bstring *s = 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 < num_buckets);
 		chain_length[b]++;
-		gdb_assert (stringi < c->unique_count);
+		gdb_assert (stringi < 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, num_buckets, sizeof (chain_length[0]),
 	   compare_positive_ints);
-    qsort (entry_size, c->unique_count, sizeof (entry_size[0]),
+    qsort (entry_size, unique_count, sizeof (entry_size[0]),
 	   compare_positive_ints);
 
-    if (c->num_buckets > 0)
+    if (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[num_buckets - 1];
+	median_chain_length = chain_length[num_buckets / 2];
       }
     else
       {
 	max_chain_length = 0;
 	median_chain_length = 0;
       }
-    if (c->unique_count > 0)
+    if (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[unique_count - 1];
+	median_entry_size = entry_size[unique_count / 2];
       }
     else
       {
@@ -428,22 +342,22 @@ print_bcache_statistics (struct bcache *c, const char *type)
   }
 
   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 (_("    Total object count:  %ld\n"), total_count);
+  printf_filtered (_("    Unique object count: %lu\n"), unique_count);
   printf_filtered (_("    Percentage of duplicates, by count: "));
-  print_percentage (c->total_count - c->unique_count, c->total_count);
+  print_percentage (total_count - unique_count, 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"), total_size);
+  printf_filtered (_("    Unique object size:  %ld\n"), unique_size);
   printf_filtered (_("    Percentage of duplicates, by size:  "));
-  print_percentage (c->total_size - c->unique_size, c->total_size);
+  print_percentage (total_size - unique_size, 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 (unique_count > 0)
+    printf_filtered ("%ld\n", unique_size / 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);
+		   structure_size);
   printf_filtered (_("    Percentage memory overhead: "));
-  print_percentage (c->structure_size - c->unique_size, c->unique_size);
+  print_percentage (structure_size - unique_size, unique_size);
   printf_filtered (_("    Net memory savings:         "));
-  print_percentage (c->total_size - c->structure_size, c->total_size);
+  print_percentage (total_size - structure_size, total_size);
   printf_filtered ("\n");
 
   printf_filtered (_("    Hash table size:           %3d\n"), 
-		   c->num_buckets);
+		   num_buckets);
   printf_filtered (_("    Hash table expands:        %lu\n"),
-		   c->expand_count);
+		   expand_count);
   printf_filtered (_("    Hash table hashes:         %lu\n"),
-		   c->total_count + c->expand_hash_count);
+		   total_count + expand_hash_count);
   printf_filtered (_("    Half hash misses:          %lu\n"),
-		   c->half_hash_miss_count);
+		   half_hash_miss_count);
   printf_filtered (_("    Hash table population:     "));
-  print_percentage (occupied_buckets, c->num_buckets);
+  print_percentage (occupied_buckets, 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 (num_buckets > 0)
+    printf_filtered ("%3lu\n", unique_count / 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 (total_count == 0)
     return 0;
-  return obstack_memory_used (&bcache->cache);
+  return obstack_memory_used (&cache);
 }
diff --git a/gdb/bcache.h b/gdb/bcache.h
index aa0147926c6..2725a994533 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)
+    : hash_function (hash_fn == nullptr ? hash : hash_fn),
+      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 cache {};
+
+  /* How many hash buckets we're using.  */
+  unsigned int 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 **bucket = nullptr;
+
+  /* Statistics.  */
+  unsigned long unique_count = 0;	/* number of unique strings */
+  long total_count = 0;	/* total number of strings cached, including dups */
+  long unique_size = 0;	/* size of unique strings, in bytes */
+  long total_size = 0;      /* total number of bytes cached, including dups */
+  long 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 expand_count = 0;
+  unsigned long 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 half_hash_miss_count = 0;
+
+  /* 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);
+
+  /* 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 ());
     }
 }
Pedro Alves March 7, 2019, 5:09 p.m. | #3
On 03/07/2019 04:53 PM, Tom Tromey wrote:
>>> This introduces a new bcache_up typedef, which is a unique_ptr

>>> specialization for managing a bcache.  Then, this changes various

>>> spots to use this object, rather than manually calling bcache_xfree.

>>> This lets us remove a try/catch that only existed to call

>>> bcache_xfree.

> 

> Pedro> I won't object, but is seems to me that it'd be better to

> Pedro> make bcache_xmalloc / bcache_free ctors/dtors of struct bcache,

> Pedro> and then we'd allocate a bcache object on the stack (and likewise

> Pedro> hold bcache objects in structures instead of bcache pointers).

> 

> I broke this one out from the series.  Let me know what you think.


Thanks!

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

Thanks,
Pedro Alves
Tom Tromey March 7, 2019, 5:41 p.m. | #4
>>>>> "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.

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 ());
     }
 }

Patch

diff --git a/gdb/bcache.h b/gdb/bcache.h
index aa0147926c6..9c1f71b6018 100644
--- a/gdb/bcache.h
+++ b/gdb/bcache.h
@@ -156,6 +156,18 @@  extern const void *bcache_full (const void *addr, int length,
 /* Free all the storage used by BCACHE.  */
 extern void bcache_xfree (struct bcache *bcache);
 
+/* A deleter that calls bcache_xfree.  */
+struct bcache_deleter
+{
+  void operator() (struct bcache *bcache)
+  {
+    bcache_xfree (bcache);
+  }
+};
+
+/* A unique pointer specialization for bcache.  */
+typedef std::unique_ptr<struct bcache, bcache_deleter> bcache_up;
+
 /* Create a new bcache object.  */
 extern struct bcache *bcache_xmalloc (
     unsigned long (*hash_function)(const void *, int length),
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index bd0f25e061e..2b70d43e3a0 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.get (),
 					m_compunit_symtab);
   return m_pending_macros;
 }
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 8fc6692b112..2f274692348 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -335,7 +335,7 @@  elf_symtab_read (minimal_symbol_reader &reader,
 	{
 	  filesymname
 	    = (const char *) bcache (sym->name, strlen (sym->name) + 1,
-				     objfile->per_bfd->filename_cache);
+				     objfile->per_bfd->filename_cache.get ());
 	}
       else if (sym->flags & BSF_SECTION_SYM)
 	continue;
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 08c292457d2..defefeabb21 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3748,9 +3748,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);
@@ -3759,30 +3756,11 @@  types_deeply_equal (struct type *type1, struct type *type2)
   if (type1 == type2)
     return true;
 
-  cache = bcache_xmalloc (NULL, NULL);
+  bcache_up cache (bcache_xmalloc (NULL, NULL));
 
   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 (const struct gdb_exception &ex)
-    {
-      except = ex;
-    }
-
-  bcache_xfree (cache);
-
-  /* Rethrow if there was a problem.  */
-  if (except.reason < 0)
-    throw_exception (except);
-
-  return result;
+  return check_types_worklist (&worklist, cache.get ());
 }
 
 /* Allocated status of type TYPE.  Return zero if type TYPE is allocated.
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 34b271e86de..47bb5a83538 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -157,8 +157,8 @@  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->filename_cache.reset (bcache_xmalloc (NULL, NULL));
+      storage->macro_cache.reset (bcache_xmalloc (NULL, NULL));
       storage->language_of_main = language_unknown;
     }
 
@@ -170,8 +170,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..272fd6a6204 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -31,8 +31,8 @@ 
 #include <vector>
 #include "common/next-iterator.h"
 #include "common/safe-iterator.h"
+#include "bcache.h"
 
-struct bcache;
 struct htab;
 struct objfile_data;
 struct partial_symbol;
@@ -240,11 +240,11 @@  struct objfile_per_bfd_storage
 
   /* Byte cache for file names.  */
 
-  struct bcache *filename_cache = NULL;
+  bcache_up filename_cache;
 
   /* Byte cache for macros.  */
 
-  struct bcache *macro_cache = NULL;
+  bcache_up 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..d6a5db47188 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1742,7 +1742,7 @@  allocate_psymtab (const char *filename, struct objfile *objfile)
 
   psymtab->filename
     = (const char *) bcache (filename, strlen (filename) + 1,
-			     objfile->per_bfd->filename_cache);
+			     objfile->per_bfd->filename_cache.get ());
   psymtab->compunit_symtab = NULL;
 
   if (symtab_create_debug)
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 61483824f63..7ea060c437c 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -2796,7 +2796,7 @@  allocate_symtab (struct compunit_symtab *cust, const char *filename)
 
   symtab->filename
     = (const char *) bcache (filename, strlen (filename) + 1,
-			     objfile->per_bfd->filename_cache);
+			     objfile->per_bfd->filename_cache.get ());
   symtab->fullname = NULL;
   symtab->language = deduce_language_from_filename (filename);
 
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
index 9025217a106..5967d19d16b 100644
--- a/gdb/symmisc.c
+++ b/gdb/symmisc.c
@@ -72,9 +72,9 @@  print_symbol_bcache_statistics (void)
 	print_bcache_statistics
 	  (psymbol_bcache_get_bcache (objfile->partial_symtabs->psymbol_cache),
 	   "partial symbol cache");
-	print_bcache_statistics (objfile->per_bfd->macro_cache,
+	print_bcache_statistics (objfile->per_bfd->macro_cache.get (),
 				 "preprocessor macro cache");
-	print_bcache_statistics (objfile->per_bfd->filename_cache,
+	print_bcache_statistics (objfile->per_bfd->filename_cache.get (),
 				 "file name cache");
       }
 }
@@ -139,9 +139,9 @@  print_objfile_statistics (void)
 	 bcache_memory_used (psymbol_bcache_get_bcache
 			     (objfile->partial_symtabs->psymbol_cache)));
       printf_filtered (_("  Total memory used for macro cache: %d\n"),
-		       bcache_memory_used (objfile->per_bfd->macro_cache));
+		       bcache_memory_used (objfile->per_bfd->macro_cache.get ()));
       printf_filtered (_("  Total memory used for file name cache: %d\n"),
-		       bcache_memory_used (objfile->per_bfd->filename_cache));
+		       bcache_memory_used (objfile->per_bfd->filename_cache.get ()));
     }
 }