public inbox for gdb-cvs@sourceware.org
help / color / mirror / Atom feed
* [binutils-gdb] Rewrite registry.h
@ 2022-07-28 20:44 Tom Tromey
  0 siblings, 0 replies; only message in thread
From: Tom Tromey @ 2022-07-28 20:44 UTC (permalink / raw)
  To: gdb-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=08b8a139c9e8adcb4ec12a8a17e5836b8b5acb63

commit 08b8a139c9e8adcb4ec12a8a17e5836b8b5acb63
Author: Tom Tromey <tom@tromey.com>
Date:   Sun Oct 18 11:38:10 2020 -0600

    Rewrite registry.h
    
    This rewrites registry.h, removing all the macros and replacing it
    with relatively ordinary template classes.  The result is less code
    than the previous setup.  It replaces large macros with a relatively
    straightforward C++ class, and now manages its own cleanup.
    
    The existing type-safe "key" class is replaced with the equivalent
    template class.  This approach ended up requiring relatively few
    changes to the users of the registry code in gdb -- code using the key
    system just required a small change to the key's declaration.
    
    All existing users of the old C-like API are now converted to use the
    type-safe API.  This mostly involved changing explicit deletion
    functions to be an operator() in a deleter class.
    
    The old "save/free" two-phase process is removed, and replaced with a
    single "free" phase.  No existing code used both phases.
    
    The old "free" callbacks took a parameter for the enclosing container
    object.  However, this wasn't truly needed and is removed here as
    well.

Diff:
---
 gdb/Makefile.in            |   1 -
 gdb/ada-lang.c             |   5 +-
 gdb/ada-tasks.c            |   4 +-
 gdb/arm-tdep.c             |   4 +-
 gdb/auto-load.c            |   4 +-
 gdb/auxv.c                 |   2 +-
 gdb/break-catch-syscall.c  |   2 +-
 gdb/breakpoint.c           |   2 +-
 gdb/coffread.c             |   2 +-
 gdb/ctfread.c              |   8 +-
 gdb/dbxread.c              |   2 +-
 gdb/dwarf2/frame.c         |   4 +-
 gdb/dwarf2/read.c          |   8 +-
 gdb/elfread.c              |   4 +-
 gdb/fbsd-tdep.c            |   2 +-
 gdb/gdb-stabs.h            |   2 +-
 gdb/gdb_bfd.c              |  14 +-
 gdb/gdb_bfd.h              |   8 +-
 gdb/gdbtypes.c             |   6 +-
 gdb/guile/guile-internal.h |   2 +-
 gdb/guile/scm-block.c      |  75 ++++----
 gdb/guile/scm-frame.c      |  75 ++++----
 gdb/guile/scm-objfile.c    |  46 ++---
 gdb/guile/scm-progspace.c  |  47 ++---
 gdb/guile/scm-symbol.c     |  70 ++++---
 gdb/guile/scm-symtab.c     |  76 ++++----
 gdb/guile/scm-type.c       |  63 +++---
 gdb/hppa-tdep.c            |   3 +-
 gdb/inferior.c             |  11 +-
 gdb/inferior.h             |   7 +-
 gdb/inflow.c               |   2 +-
 gdb/linux-tdep.c           |   2 +-
 gdb/mdebugread.c           |   4 +-
 gdb/minidebug.c            |   2 +-
 gdb/nto-tdep.c             |   2 +-
 gdb/objc-lang.c            |   2 +-
 gdb/objfiles.c             |  15 +-
 gdb/objfiles.h             |   6 +-
 gdb/progspace.c            |  22 ---
 gdb/progspace.h            |  18 +-
 gdb/python/py-block.c      |  70 +++----
 gdb/python/py-inferior.c   |  68 +++----
 gdb/python/py-objfile.c    |  37 ++--
 gdb/python/py-progspace.c  |  59 +++---
 gdb/python/py-symbol.c     |  63 +++---
 gdb/python/py-symtab.c     | 142 ++++++--------
 gdb/python/py-type.c       |  59 +++---
 gdb/registry.c             | 112 -----------
 gdb/registry.h             | 470 +++++++++++++++++++--------------------------
 gdb/remote-sim.c           |   2 +-
 gdb/remote.c               |   2 +-
 gdb/rs6000-tdep.c          |   2 +-
 gdb/solib-aix.c            |   3 +-
 gdb/solib-darwin.c         |   3 +-
 gdb/solib-dsbt.c           |   2 +-
 gdb/solib-svr4.c           |   2 +-
 gdb/solib.c                |   3 +-
 gdb/source.c               |   3 +-
 gdb/stabsread.c            |   4 +-
 gdb/symfile-debug.c        |   2 +-
 gdb/symfile.c              |   4 +-
 gdb/symtab.c               |   4 +-
 gdb/target-dcache.c        |   2 +-
 gdb/xcoffread.c            |   2 +-
 64 files changed, 683 insertions(+), 1071 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index aebb7dc5ea3..2598b81d205 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1152,7 +1152,6 @@ COMMON_SFILES = \
 	regcache.c \
 	regcache-dump.c \
 	reggroups.c \
-	registry.c \
 	remote.c \
 	remote-fileio.c \
 	remote-notif.c \
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 650408134bb..d49baf99005 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -334,7 +334,7 @@ struct ada_inferior_data
 };
 
 /* Our key to this module's inferior data.  */
-static const struct inferior_key<ada_inferior_data> ada_inferior_data;
+static const registry<inferior>::key<ada_inferior_data> ada_inferior_data;
 
 /* Return our inferior data for the given inferior (INF).
 
@@ -376,7 +376,8 @@ struct ada_pspace_data
 };
 
 /* Key to our per-program-space data.  */
-static const struct program_space_key<ada_pspace_data> ada_pspace_data_handle;
+static const registry<program_space>::key<ada_pspace_data>
+  ada_pspace_data_handle;
 
 /* Return this module's data for the given program space (PSPACE).
    If not is found, add a zero'ed one now.
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 0043f2999d9..fda49557a4f 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -166,7 +166,7 @@ struct ada_tasks_pspace_data
 };
 
 /* Key to our per-program-space data.  */
-static const struct program_space_key<ada_tasks_pspace_data>
+static const registry<program_space>::key<ada_tasks_pspace_data>
   ada_tasks_pspace_data_handle;
 
 /* The kind of data structure used by the runtime to store the list
@@ -242,7 +242,7 @@ struct ada_tasks_inferior_data
 };
 
 /* Key to our per-inferior data.  */
-static const struct inferior_key<ada_tasks_inferior_data>
+static const registry<inferior>::key<ada_tasks_inferior_data>
   ada_tasks_inferior_data_handle;
 
 /* Return a string with TASKNO followed by the task name if TASK_INFO
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 7d8d040f8f1..d4c5beb5e06 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -123,7 +123,7 @@ struct arm_per_bfd
 };
 
 /* Per-bfd data used for mapping symbols.  */
-static bfd_key<arm_per_bfd> arm_bfd_data_key;
+static const registry<bfd>::key<arm_per_bfd> arm_bfd_data_key;
 
 /* The list of available "set arm ..." and "show arm ..." commands.  */
 static struct cmd_list_element *setarmcmdlist = NULL;
@@ -2407,7 +2407,7 @@ struct arm_exidx_data
 };
 
 /* Per-BFD key to store exception handling information.  */
-static const struct bfd_key<arm_exidx_data> arm_exidx_data_key;
+static const registry<bfd>::key<arm_exidx_data> arm_exidx_data_key;
 
 static struct obj_section *
 arm_obj_section_from_vma (struct objfile *objfile, bfd_vma vma)
diff --git a/gdb/auto-load.c b/gdb/auto-load.c
index b6056f5d60a..54ed73d1bf3 100644
--- a/gdb/auto-load.c
+++ b/gdb/auto-load.c
@@ -536,8 +536,8 @@ struct loaded_script
 };
 
 /* Per-program-space data key.  */
-static const struct program_space_key<struct auto_load_pspace_info>
-  auto_load_pspace_data;
+static const registry<program_space>::key<auto_load_pspace_info>
+     auto_load_pspace_data;
 
 /* Get the current autoload data.  If none is found yet, add it now.  This
    function always returns a valid object.  */
diff --git a/gdb/auxv.c b/gdb/auxv.c
index 8e175138f5d..6154988f6dd 100644
--- a/gdb/auxv.c
+++ b/gdb/auxv.c
@@ -332,7 +332,7 @@ struct auxv_info
 };
 
 /* Per-inferior data key for auxv.  */
-static const struct inferior_key<auxv_info> auxv_inferior_data;
+static const registry<inferior>::key<auxv_info> auxv_inferior_data;
 
 /* Invalidate INF's auxv cache.  */
 
diff --git a/gdb/break-catch-syscall.c b/gdb/break-catch-syscall.c
index 06d48466de7..805bb86cee6 100644
--- a/gdb/break-catch-syscall.c
+++ b/gdb/break-catch-syscall.c
@@ -79,7 +79,7 @@ struct catch_syscall_inferior_data
   int total_syscalls_count;
 };
 
-static const struct inferior_key<struct catch_syscall_inferior_data>
+static const registry<inferior>::key<catch_syscall_inferior_data>
   catch_syscall_inferior_data;
 
 static struct catch_syscall_inferior_data *
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 39a8eaa8a34..dae96d205be 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -3327,7 +3327,7 @@ struct breakpoint_objfile_data
   std::vector<probe *> exception_probes;
 };
 
-static const struct objfile_key<breakpoint_objfile_data>
+static const registry<objfile>::key<breakpoint_objfile_data>
   breakpoint_objfile_key;
 
 /* Minimal symbol not found sentinel.  */
diff --git a/gdb/coffread.c b/gdb/coffread.c
index 474a1aa02f5..f7f5bb007ca 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -61,7 +61,7 @@ struct coff_symfile_info
 
 /* Key for COFF-associated data.  */
 
-static const struct objfile_key<coff_symfile_info> coff_objfile_data_key;
+static const registry<objfile>::key<coff_symfile_info> coff_objfile_data_key;
 
 /* Translate an external name string into a user-visible name.  */
 #define	EXTERNAL_NAME(string, abfd) \
diff --git a/gdb/ctfread.c b/gdb/ctfread.c
index 828f300d29d..0da4f0d0720 100644
--- a/gdb/ctfread.c
+++ b/gdb/ctfread.c
@@ -87,7 +87,7 @@
 #include "ctf.h"
 #include "ctf-api.h"
 
-static const struct objfile_key<htab, htab_deleter> ctf_tid_key;
+static const registry<objfile>::key<htab, htab_deleter> ctf_tid_key;
 
 struct ctf_fp_info
 {
@@ -107,7 +107,7 @@ ctf_fp_info::~ctf_fp_info ()
   ctf_close (arc);
 }
 
-static const objfile_key<ctf_fp_info> ctf_dict_key;
+static const registry<objfile>::key<ctf_fp_info> ctf_dict_key;
 
 /* A CTF context consists of a file pointer and an objfile pointer.  */
 
@@ -243,7 +243,7 @@ set_tid_type (struct objfile *of, ctf_id_t tid, struct type *typ)
 {
   htab_t htab;
 
-  htab = (htab_t) ctf_tid_key.get (of);
+  htab = ctf_tid_key.get (of);
   if (htab == NULL)
     {
       htab = htab_create_alloc (1, tid_and_type_hash,
@@ -271,7 +271,7 @@ get_tid_type (struct objfile *of, ctf_id_t tid)
   struct ctf_tid_and_type *slot, ids;
   htab_t htab;
 
-  htab = (htab_t) ctf_tid_key.get (of);
+  htab = ctf_tid_key.get (of);
   if (htab == NULL)
     return nullptr;
 
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index bcf519000bc..e1bf9a01e30 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -57,7 +57,7 @@
 
 /* Key for dbx-associated data.  */
 
-objfile_key<dbx_symfile_info> dbx_objfile_data_key;
+const registry<objfile>::key<dbx_symfile_info> dbx_objfile_data_key;
 
 /* We put a pointer to this structure in the read_symtab_private field
    of the psymtab.  */
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index 5878d72f922..d7a06395acb 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -1370,12 +1370,12 @@ dwarf2_frame_cfa (struct frame_info *this_frame)
 \f
 /* We store the frame data on the BFD.  This is only done if it is
    independent of the address space and so can be shared.  */
-static const struct bfd_key<comp_unit> dwarf2_frame_bfd_data;
+static const registry<bfd>::key<comp_unit> dwarf2_frame_bfd_data;
 
 /* If any BFD sections require relocations (note; really should be if
    any debug info requires relocations), then we store the frame data
    on the objfile instead, and do not share it.  */
-const struct objfile_key<comp_unit> dwarf2_frame_objfile_data;
+static const registry<objfile>::key<comp_unit> dwarf2_frame_objfile_data;
 \f
 
 /* Pointer encoding helper functions.  */
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index f7e55af3e86..70419da13e4 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -124,7 +124,8 @@ static bool check_physname = false;
 static bool use_deprecated_index_sections = false;
 
 /* This is used to store the data that is always per objfile.  */
-static const objfile_key<dwarf2_per_objfile> dwarf2_objfile_data_key;
+static const registry<objfile>::key<dwarf2_per_objfile>
+     dwarf2_objfile_data_key;
 
 /* These are used to store the dwarf2_per_bfd objects.
 
@@ -134,8 +135,9 @@ static const objfile_key<dwarf2_per_objfile> dwarf2_objfile_data_key;
    Other objfiles are not going to share a dwarf2_per_bfd with any other
    objfiles, so they'll have their own version kept in the _objfile_data_key
    version.  */
-static const struct bfd_key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key;
-static const struct objfile_key<dwarf2_per_bfd> dwarf2_per_bfd_objfile_data_key;
+static const registry<bfd>::key<dwarf2_per_bfd> dwarf2_per_bfd_bfd_data_key;
+static const registry<objfile>::key<dwarf2_per_bfd>
+  dwarf2_per_bfd_objfile_data_key;
 
 /* The "aclass" indices for various kinds of computed DWARF symbols.  */
 
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 8ff62a1fed5..deed34c35c7 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -69,7 +69,7 @@ typedef std::vector<std::unique_ptr<probe>> elfread_data;
 
 /* Per-BFD data for probe info.  */
 
-static const struct bfd_key<elfread_data> probe_key;
+static const registry<bfd>::key<elfread_data> probe_key;
 
 /* Minimal symbols located at the GOT entries for .plt - that is the real
    pointer where the given entry will jump to.  It gets updated by the real
@@ -646,7 +646,7 @@ elf_rel_plt_read (minimal_symbol_reader &reader,
 
 /* The data pointer is htab_t for gnu_ifunc_record_cache_unchecked.  */
 
-static const struct objfile_key<htab, htab_deleter>
+static const registry<objfile>::key<htab, htab_deleter>
   elf_objfile_gnu_ifunc_cache_data;
 
 /* Map function names to CORE_ADDR in elf_objfile_gnu_ifunc_cache_data.  */
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index b241e855bd6..f2f961b5486 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -520,7 +520,7 @@ struct fbsd_pspace_data
 };
 
 /* Per-program-space data for FreeBSD architectures.  */
-static const struct program_space_key<fbsd_pspace_data>
+static const registry<program_space>::key<fbsd_pspace_data>
   fbsd_pspace_data_handle;
 
 static struct fbsd_pspace_data *
diff --git a/gdb/gdb-stabs.h b/gdb/gdb-stabs.h
index fef988524f2..5c697906cab 100644
--- a/gdb/gdb-stabs.h
+++ b/gdb/gdb-stabs.h
@@ -60,7 +60,7 @@ struct dbx_symfile_info
 
 /* The tag used to find the DBX info attached to an objfile.  This is
    global because it is referenced by several modules.  */
-extern objfile_key<dbx_symfile_info> dbx_objfile_data_key;
+extern const registry<objfile>::key<dbx_symfile_info> dbx_objfile_data_key;
 
 #define DBX_SYMFILE_INFO(o)	(dbx_objfile_data_key.get (o))
 #define DBX_TEXT_ADDR(o)	(DBX_SYMFILE_INFO(o)->text_addr)
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 22828482d5b..6c03ae5ef05 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -112,13 +112,15 @@ struct gdb_bfd_data
   std::vector<gdb_bfd_ref_ptr> included_bfds;
 
   /* The registry.  */
-  REGISTRY_FIELDS = {};
+  registry<bfd> registry_fields;
 };
 
-#define GDB_BFD_DATA_ACCESSOR(ABFD) \
-  ((struct gdb_bfd_data *) bfd_usrdata (ABFD))
-
-DEFINE_REGISTRY (bfd, GDB_BFD_DATA_ACCESSOR)
+registry<bfd> *
+registry_accessor<bfd>::get (bfd *abfd)
+{
+  struct gdb_bfd_data *gdata = (struct gdb_bfd_data *) bfd_usrdata (abfd);
+  return &gdata->registry_fields;
+}
 
 /* A hash table storing all the BFDs maintained in the cache.  */
 
@@ -498,7 +500,6 @@ gdb_bfd_init_data (struct bfd *abfd, struct stat *st)
 
   gdata = new gdb_bfd_data (abfd, st);
   bfd_set_usrdata (abfd, gdata);
-  bfd_alloc_data (abfd);
 
   /* This is the first we've seen it, so add it to the hash table.  */
   slot = htab_find_slot (all_bfds, abfd, INSERT);
@@ -725,7 +726,6 @@ gdb_bfd_unref (struct bfd *abfd)
 	htab_clear_slot (gdb_bfd_cache, slot);
     }
 
-  bfd_free_data (abfd);
   delete gdata;
   bfd_set_usrdata (abfd, NULL);  /* Paranoia.  */
 
diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h
index 6845d6ccef5..86f7be85f20 100644
--- a/gdb/gdb_bfd.h
+++ b/gdb/gdb_bfd.h
@@ -26,7 +26,13 @@
 #include "gdbsupport/iterator-range.h"
 #include "gdbsupport/next-iterator.h"
 
-DECLARE_REGISTRY (bfd);
+/* A registry adaptor for BFD.  This arranges to store the registry in
+   gdb's per-BFD data, which is stored as the bfd_usrdata.  */
+template<>
+struct registry_accessor<bfd>
+{
+  static registry<bfd> *get (bfd *abfd);
+};
 
 /* If supplied a path starting with this sequence, gdb_bfd_open will
    open BFDs using target fileio operations.  */
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 34da6d80e92..8ab0a898ba6 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -6078,7 +6078,7 @@ typedef std::vector<std::unique_ptr<fixed_point_type_info>>
     fixed_point_type_storage;
 
 /* Key used for managing the storage of fixed-point type info.  */
-static const struct objfile_key<fixed_point_type_storage>
+static const struct registry<objfile>::key<fixed_point_type_storage>
     fixed_point_objfile_key;
 
 /* See gdbtypes.h.  */
@@ -6305,8 +6305,8 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
 /* This set of objfile-based types is intended to be used by symbol
    readers as basic types.  */
 
-static const struct objfile_key<struct objfile_type,
-				gdb::noop_deleter<struct objfile_type>>
+static const registry<objfile>::key<struct objfile_type,
+				    gdb::noop_deleter<struct objfile_type>>
   objfile_type_data;
 
 const struct objfile_type *
diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
index 4cdb7e355d7..30cc5c307ae 100644
--- a/gdb/guile/guile-internal.h
+++ b/gdb/guile/guile-internal.h
@@ -28,6 +28,7 @@
 #include "extension-priv.h"
 #include "symtab.h"
 #include "libguile.h"
+#include "objfiles.h"
 
 struct block;
 struct frame_info;
@@ -272,7 +273,6 @@ struct eqable_gdb_smob
 #undef GDB_SMOB_HEAD
 
 struct objfile;
-struct objfile_data;
 
 /* A predicate that returns non-zero if an object is a particular kind
    of gsmob.  */
diff --git a/gdb/guile/scm-block.c b/gdb/guile/scm-block.c
index 41954c70519..a29c2db58f1 100644
--- a/gdb/guile/scm-block.c
+++ b/gdb/guile/scm-block.c
@@ -76,7 +76,37 @@ static scm_t_bits block_syms_progress_smob_tag;
 /* The "next!" block syms iterator method.  */
 static SCM bkscm_next_symbol_x_proc;
 
-static const struct objfile_data *bkscm_objfile_data_key;
+/* This is called when an objfile is about to be freed.
+   Invalidate the block as further actions on the block would result
+   in bad data.  All access to b_smob->block should be gated by
+   checks to ensure the block is (still) valid.  */
+struct bkscm_deleter
+{
+  /* Helper function for bkscm_del_objfile_blocks to mark the block
+     as invalid.  */
+
+  static int
+  bkscm_mark_block_invalid (void **slot, void *info)
+  {
+    block_smob *b_smob = (block_smob *) *slot;
+
+    b_smob->block = NULL;
+    b_smob->objfile = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, bkscm_deleter>
+     bkscm_objfile_data_key;
 \f
 /* Administrivia for block smobs.  */
 
@@ -108,13 +138,13 @@ bkscm_eq_block_smob (const void *ap, const void *bp)
 static htab_t
 bkscm_objfile_block_map (struct objfile *objfile)
 {
-  htab_t htab = (htab_t) objfile_data (objfile, bkscm_objfile_data_key);
+  htab_t htab = bkscm_objfile_data_key.get (objfile);
 
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (bkscm_hash_block_smob,
 						 bkscm_eq_block_smob);
-      set_objfile_data (objfile, bkscm_objfile_data_key, htab);
+      bkscm_objfile_data_key.set (objfile, htab);
     }
 
   return htab;
@@ -326,35 +356,6 @@ bkscm_scm_to_block (SCM block_scm, int arg_pos, const char *func_name,
   return NULL;
 }
 
-/* Helper function for bkscm_del_objfile_blocks to mark the block
-   as invalid.  */
-
-static int
-bkscm_mark_block_invalid (void **slot, void *info)
-{
-  block_smob *b_smob = (block_smob *) *slot;
-
-  b_smob->block = NULL;
-  b_smob->objfile = NULL;
-  return 1;
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the block as further actions on the block would result
-   in bad data.  All access to b_smob->block should be gated by
-   checks to ensure the block is (still) valid.  */
-
-static void
-bkscm_del_objfile_blocks (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, bkscm_mark_block_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Block methods.  */
 
@@ -800,13 +801,3 @@ gdbscm_initialize_blocks (void)
 				gdbscm_scm_from_c_string ("\
 Internal function to assist the block symbols iterator."));
 }
-
-void _initialize_scm_block ();
-void
-_initialize_scm_block ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate blocks when an object file is about to be deleted.  */
-  bkscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, bkscm_del_objfile_blocks);
-}
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 6bbb6f81d68..4132bb246d8 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -74,7 +74,37 @@ static scm_t_bits frame_smob_tag;
 /* Keywords used in argument passing.  */
 static SCM block_keyword;
 
-static const struct inferior_data *frscm_inferior_data_key;
+/* This is called when an inferior is about to be freed.
+   Invalidate the frame as further actions on the frame could result
+   in bad data.  All access to the frame should be gated by
+   frscm_get_frame_smob_arg_unsafe which will raise an exception on
+   invalid frames.  */
+struct frscm_deleter
+{
+  /* Helper function for frscm_del_inferior_frames to mark the frame
+     as invalid.  */
+
+  static int
+  frscm_mark_frame_invalid (void **slot, void *info)
+  {
+    frame_smob *f_smob = (frame_smob *) *slot;
+
+    f_smob->inferior = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<inferior>::key<htab, frscm_deleter>
+    frscm_inferior_data_key;
 \f
 /* Administrivia for frame smobs.  */
 
@@ -117,13 +147,13 @@ frscm_eq_frame_smob (const void *ap, const void *bp)
 static htab_t
 frscm_inferior_frame_map (struct inferior *inferior)
 {
-  htab_t htab = (htab_t) inferior_data (inferior, frscm_inferior_data_key);
+  htab_t htab = frscm_inferior_data_key.get (inferior);
 
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (frscm_hash_frame_smob,
 						 frscm_eq_frame_smob);
-      set_inferior_data (inferior, frscm_inferior_data_key, htab);
+      frscm_inferior_data_key.set (inferior, htab);
     }
 
   return htab;
@@ -346,35 +376,6 @@ frscm_frame_smob_to_frame (frame_smob *f_smob)
   return frame;
 }
 
-/* Helper function for frscm_del_inferior_frames to mark the frame
-   as invalid.  */
-
-static int
-frscm_mark_frame_invalid (void **slot, void *info)
-{
-  frame_smob *f_smob = (frame_smob *) *slot;
-
-  f_smob->inferior = NULL;
-  return 1;
-}
-
-/* This function is called when an inferior is about to be freed.
-   Invalidate the frame as further actions on the frame could result
-   in bad data.  All access to the frame should be gated by
-   frscm_get_frame_smob_arg_unsafe which will raise an exception on
-   invalid frames.  */
-
-static void
-frscm_del_inferior_frames (struct inferior *inferior, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, frscm_mark_frame_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Frame methods.  */
 
@@ -1170,13 +1171,3 @@ gdbscm_initialize_frames (void)
 
   block_keyword = scm_from_latin1_keyword ("block");
 }
-
-void _initialize_scm_frame ();
-void
-_initialize_scm_frame ()
-{
-  /* Register an inferior "free" callback so we can properly
-     invalidate frames when an inferior file is about to be deleted.  */
-  frscm_inferior_data_key
-    = register_inferior_data_with_cleanup (NULL, frscm_del_inferior_frames);
-}
diff --git a/gdb/guile/scm-objfile.c b/gdb/guile/scm-objfile.c
index 760d5aa1f4b..1a87dcf74fa 100644
--- a/gdb/guile/scm-objfile.c
+++ b/gdb/guile/scm-objfile.c
@@ -49,7 +49,18 @@ static const char objfile_smob_name[] = "gdb:objfile";
 /* The tag Guile knows the objfile smob by.  */
 static scm_t_bits objfile_smob_tag;
 
-static const struct objfile_data *ofscm_objfile_data_key;
+/* Objfile registry cleanup handler for when an objfile is deleted.  */
+struct ofscm_deleter
+{
+  void operator() (objfile_smob *o_smob)
+  {
+    o_smob->objfile = NULL;
+    scm_gc_unprotect_object (o_smob->containing_scm);
+  }
+};
+
+static const registry<objfile>::key<objfile_smob, ofscm_deleter>
+     ofscm_objfile_data_key;
 
 /* Return the list of pretty-printers registered with O_SMOB.  */
 
@@ -101,27 +112,6 @@ ofscm_make_objfile_smob (void)
   return o_scm;
 }
 
-/* Clear the OBJFILE pointer in O_SMOB and unprotect the object from GC.  */
-
-static void
-ofscm_release_objfile (objfile_smob *o_smob)
-{
-  o_smob->objfile = NULL;
-  scm_gc_unprotect_object (o_smob->containing_scm);
-}
-
-/* Objfile registry cleanup handler for when an objfile is deleted.  */
-
-static void
-ofscm_handle_objfile_deleted (struct objfile *objfile, void *datum)
-{
-  objfile_smob *o_smob = (objfile_smob *) datum;
-
-  gdb_assert (o_smob->objfile == objfile);
-
-  ofscm_release_objfile (o_smob);
-}
-
 /* Return non-zero if SCM is a <gdb:objfile> object.  */
 
 static int
@@ -147,7 +137,7 @@ ofscm_objfile_smob_from_objfile (struct objfile *objfile)
 {
   objfile_smob *o_smob;
 
-  o_smob = (objfile_smob *) objfile_data (objfile, ofscm_objfile_data_key);
+  o_smob = ofscm_objfile_data_key.get (objfile);
   if (o_smob == NULL)
     {
       SCM o_scm = ofscm_make_objfile_smob ();
@@ -155,7 +145,7 @@ ofscm_objfile_smob_from_objfile (struct objfile *objfile)
       o_smob = (objfile_smob *) SCM_SMOB_DATA (o_scm);
       o_smob->objfile = objfile;
 
-      set_objfile_data (objfile, ofscm_objfile_data_key, o_smob);
+      ofscm_objfile_data_key.set (objfile, o_smob);
       scm_gc_protect_object (o_smob->containing_scm);
     }
 
@@ -424,11 +414,3 @@ gdbscm_initialize_objfiles (void)
 
   gdbscm_define_functions (objfile_functions, 1);
 }
-
-void _initialize_scm_objfile ();
-void
-_initialize_scm_objfile ()
-{
-  ofscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, ofscm_handle_objfile_deleted);
-}
diff --git a/gdb/guile/scm-progspace.c b/gdb/guile/scm-progspace.c
index c48da761945..7a197d76543 100644
--- a/gdb/guile/scm-progspace.c
+++ b/gdb/guile/scm-progspace.c
@@ -52,7 +52,18 @@ static const char pspace_smob_name[] = "gdb:progspace";
 /* The tag Guile knows the pspace smob by.  */
 static scm_t_bits pspace_smob_tag;
 
-static const struct program_space_data *psscm_pspace_data_key;
+/* Progspace registry cleanup handler for when a progspace is deleted.  */
+struct psscm_deleter
+{
+  void operator() (pspace_smob *p_smob)
+  {
+    p_smob->pspace = NULL;
+    scm_gc_unprotect_object (p_smob->containing_scm);
+  }
+};
+
+static const registry<program_space>::key<pspace_smob, psscm_deleter>
+     psscm_pspace_data_key;
 
 /* Return the list of pretty-printers registered with P_SMOB.  */
 
@@ -111,27 +122,6 @@ psscm_make_pspace_smob (void)
   return p_scm;
 }
 
-/* Clear the progspace pointer in P_SMOB and unprotect the object from GC.  */
-
-static void
-psscm_release_pspace (pspace_smob *p_smob)
-{
-  p_smob->pspace = NULL;
-  scm_gc_unprotect_object (p_smob->containing_scm);
-}
-
-/* Progspace registry cleanup handler for when a progspace is deleted.  */
-
-static void
-psscm_handle_pspace_deleted (struct program_space *pspace, void *datum)
-{
-  pspace_smob *p_smob = (pspace_smob *) datum;
-
-  gdb_assert (p_smob->pspace == pspace);
-
-  psscm_release_pspace (p_smob);
-}
-
 /* Return non-zero if SCM is a <gdb:progspace> object.  */
 
 static int
@@ -157,7 +147,7 @@ psscm_pspace_smob_from_pspace (struct program_space *pspace)
 {
   pspace_smob *p_smob;
 
-  p_smob = (pspace_smob *) program_space_data (pspace, psscm_pspace_data_key);
+  p_smob = psscm_pspace_data_key.get (pspace);
   if (p_smob == NULL)
     {
       SCM p_scm = psscm_make_pspace_smob ();
@@ -165,7 +155,7 @@ psscm_pspace_smob_from_pspace (struct program_space *pspace)
       p_smob = (pspace_smob *) SCM_SMOB_DATA (p_scm);
       p_smob->pspace = pspace;
 
-      set_program_space_data (pspace, psscm_pspace_data_key, p_smob);
+      psscm_pspace_data_key.set (pspace, p_smob);
       scm_gc_protect_object (p_smob->containing_scm);
     }
 
@@ -418,12 +408,3 @@ gdbscm_initialize_pspaces (void)
 
   gdbscm_define_functions (pspace_functions, 1);
 }
-
-void _initialize_scm_progspace ();
-void
-_initialize_scm_progspace ()
-{
-  psscm_pspace_data_key
-    = register_program_space_data_with_cleanup (NULL,
-						psscm_handle_pspace_deleted);
-}
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 55eac3cfff6..0b96e5a02c1 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -49,7 +49,37 @@ static SCM block_keyword;
 static SCM domain_keyword;
 static SCM frame_keyword;
 
-static const struct objfile_data *syscm_objfile_data_key;
+/* This is called when an objfile is about to be freed.
+   Invalidate the symbol as further actions on the symbol would result
+   in bad data.  All access to s_smob->symbol should be gated by
+   syscm_get_valid_symbol_smob_arg_unsafe which will raise an exception on
+   invalid symbols.  */
+struct syscm_deleter
+{
+  /* Helper function for syscm_del_objfile_symbols to mark the symbol
+     as invalid.  */
+
+  static int
+  syscm_mark_symbol_invalid (void **slot, void *info)
+  {
+    symbol_smob *s_smob = (symbol_smob *) *slot;
+
+    s_smob->symbol = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, syscm_deleter>
+     syscm_objfile_data_key;
 static struct gdbarch_data *syscm_gdbarch_data_key;
 
 struct syscm_gdbarch_data
@@ -105,12 +135,12 @@ syscm_get_symbol_map (struct symbol *symbol)
     {
       struct objfile *objfile = symbol->objfile ();
 
-      htab = (htab_t) objfile_data (objfile, syscm_objfile_data_key);
+      htab = syscm_objfile_data_key.get (objfile);
       if (htab == NULL)
 	{
 	  htab = gdbscm_create_eqable_gsmob_ptr_map (syscm_hash_symbol_smob,
 						     syscm_eq_symbol_smob);
-	  set_objfile_data (objfile, syscm_objfile_data_key, htab);
+	  syscm_objfile_data_key.set (objfile, htab);
 	}
     }
   else
@@ -291,35 +321,6 @@ syscm_get_valid_symbol_arg_unsafe (SCM self, int arg_pos,
   return s_smob->symbol;
 }
 
-/* Helper function for syscm_del_objfile_symbols to mark the symbol
-   as invalid.  */
-
-static int
-syscm_mark_symbol_invalid (void **slot, void *info)
-{
-  symbol_smob *s_smob = (symbol_smob *) *slot;
-
-  s_smob->symbol = NULL;
-  return 1;
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol as further actions on the symbol would result
-   in bad data.  All access to s_smob->symbol should be gated by
-   syscm_get_valid_symbol_smob_arg_unsafe which will raise an exception on
-   invalid symbols.  */
-
-static void
-syscm_del_objfile_symbols (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, syscm_mark_symbol_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Symbol methods.  */
 
@@ -823,11 +824,6 @@ void _initialize_scm_symbol ();
 void
 _initialize_scm_symbol ()
 {
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbols when an object file is about to be deleted.  */
-  syscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, syscm_del_objfile_symbols);
-
   /* Arch-specific symbol data.  */
   syscm_gdbarch_data_key
     = gdbarch_data_register_post_init (syscm_init_arch_symbols);
diff --git a/gdb/guile/scm-symtab.c b/gdb/guile/scm-symtab.c
index 518ceeaa15d..940823147bf 100644
--- a/gdb/guile/scm-symtab.c
+++ b/gdb/guile/scm-symtab.c
@@ -77,7 +77,37 @@ static const char sal_smob_name[] = "gdb:sal";
 static scm_t_bits symtab_smob_tag;
 static scm_t_bits sal_smob_tag;
 
-static const struct objfile_data *stscm_objfile_data_key;
+/* This is called when an objfile is about to be freed.
+   Invalidate the symbol table as further actions on the symbol table
+   would result in bad data.  All access to st_smob->symtab should be
+   gated by stscm_get_valid_symtab_smob_arg_unsafe which will raise an
+   exception on invalid symbol tables.  */
+struct stscm_deleter
+{
+  /* Helper function for stscm_del_objfile_symtabs to mark the symtab
+     as invalid.  */
+
+  static int
+  stscm_mark_symtab_invalid (void **slot, void *info)
+  {
+    symtab_smob *st_smob = (symtab_smob *) *slot;
+
+    st_smob->symtab = NULL;
+    return 1;
+  }
+
+  void operator() (htab_t htab)
+  {
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, stscm_deleter>
+     stscm_objfile_data_key;
 \f
 /* Administrivia for symtab smobs.  */
 
@@ -110,13 +140,13 @@ static htab_t
 stscm_objfile_symtab_map (struct symtab *symtab)
 {
   struct objfile *objfile = symtab->compunit ()->objfile ();
-  htab_t htab = (htab_t) objfile_data (objfile, stscm_objfile_data_key);
+  htab_t htab = stscm_objfile_data_key.get (objfile);
 
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (stscm_hash_symtab_smob,
 						 stscm_eq_symtab_smob);
-      set_objfile_data (objfile, stscm_objfile_data_key, htab);
+      stscm_objfile_data_key.set (objfile, htab);
     }
 
   return htab;
@@ -271,35 +301,6 @@ stscm_get_valid_symtab_smob_arg_unsafe (SCM self, int arg_pos,
   return st_smob;
 }
 
-/* Helper function for stscm_del_objfile_symtabs to mark the symtab
-   as invalid.  */
-
-static int
-stscm_mark_symtab_invalid (void **slot, void *info)
-{
-  symtab_smob *st_smob = (symtab_smob *) *slot;
-
-  st_smob->symtab = NULL;
-  return 1;
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol table as further actions on the symbol table
-   would result in bad data.  All access to st_smob->symtab should be
-   gated by stscm_get_valid_symtab_smob_arg_unsafe which will raise an
-   exception on invalid symbol tables.  */
-
-static void
-stscm_del_objfile_symtabs (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, stscm_mark_symtab_invalid, NULL);
-      htab_delete (htab);
-    }
-}
 \f
 /* Symbol table methods.  */
 
@@ -687,14 +688,3 @@ gdbscm_initialize_symtabs (void)
 
   gdbscm_define_functions (symtab_functions, 1);
 }
-
-void _initialize_scm_symtab ();
-void
-_initialize_scm_symtab ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbol tables, and symbol table and line data
-     structures when an object file that is about to be deleted.  */
-  stscm_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, stscm_del_objfile_symtabs);
-}
diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
index dd7eace8d40..2dadbefb3a4 100644
--- a/gdb/guile/scm-type.c
+++ b/gdb/guile/scm-type.c
@@ -81,7 +81,30 @@ static SCM tyscm_next_field_x_proc;
 /* Keywords used in argument passing.  */
 static SCM block_keyword;
 
-static const struct objfile_data *tyscm_objfile_data_key;
+static int tyscm_copy_type_recursive (void **slot, void *info);
+
+/* Called when an objfile is about to be deleted.
+   Make a copy of all types associated with OBJFILE.  */
+
+struct tyscm_deleter
+{
+  void operator() (htab_t htab)
+  {
+    if (!gdb_scheme_initialized)
+      return;
+
+    htab_up copied_types = create_copied_types_hash ();
+
+    if (htab != NULL)
+      {
+	htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
+	htab_delete (htab);
+      }
+  }
+};
+
+static const registry<objfile>::key<htab, tyscm_deleter>
+     tyscm_objfile_data_key;
 
 /* Hash table to uniquify global (non-objfile-owned) types.  */
 static htab_t global_types_map;
@@ -158,12 +181,12 @@ tyscm_type_map (struct type *type)
   if (objfile == NULL)
     return global_types_map;
 
-  htab = (htab_t) objfile_data (objfile, tyscm_objfile_data_key);
+  htab = tyscm_objfile_data_key.get (objfile);
   if (htab == NULL)
     {
       htab = gdbscm_create_eqable_gsmob_ptr_map (tyscm_hash_type_smob,
 						 tyscm_eq_type_smob);
-      set_objfile_data (objfile, tyscm_objfile_data_key, htab);
+      tyscm_objfile_data_key.set (objfile, htab);
     }
 
   return htab;
@@ -345,20 +368,17 @@ tyscm_scm_to_type (SCM t_scm)
   return t_smob->type;
 }
 
-/* Helper function for save_objfile_types to make a deep copy of the type.  */
+/* Helper function to make a deep copy of the type.  */
 
 static int
 tyscm_copy_type_recursive (void **slot, void *info)
 {
   type_smob *t_smob = (type_smob *) *slot;
   htab_t copied_types = (htab_t) info;
-  struct objfile *objfile = t_smob->type->objfile_owner ();
   htab_t htab;
   eqable_gdb_smob **new_slot;
   type_smob t_smob_for_lookup;
 
-  gdb_assert (objfile != NULL);
-
   htab_empty (copied_types);
   t_smob->type = copy_type_recursive (t_smob->type, copied_types);
 
@@ -380,25 +400,6 @@ tyscm_copy_type_recursive (void **slot, void *info)
   return 1;
 }
 
-/* Called when OBJFILE is about to be deleted.
-   Make a copy of all types associated with OBJFILE.  */
-
-static void
-save_objfile_types (struct objfile *objfile, void *datum)
-{
-  htab_t htab = (htab_t) datum;
-
-  if (!gdb_scheme_initialized)
-    return;
-
-  htab_up copied_types = create_copied_types_hash ();
-
-  if (htab != NULL)
-    {
-      htab_traverse_noresize (htab, tyscm_copy_type_recursive, copied_types.get ());
-      htab_delete (htab);
-    }
-}
 \f
 /* Administrivia for field smobs.  */
 
@@ -1510,13 +1511,3 @@ Internal function to assist the type fields iterator."));
   global_types_map = gdbscm_create_eqable_gsmob_ptr_map (tyscm_hash_type_smob,
 							 tyscm_eq_type_smob);
 }
-
-void _initialize_scm_type ();
-void
-_initialize_scm_type ()
-{
-  /* Register an objfile "free" callback so we can properly copy types
-     associated with the objfile when it's about to be deleted.  */
-  tyscm_objfile_data_key
-    = register_objfile_data_with_cleanup (save_objfile_types, NULL);
-}
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 9f93a945a6a..54b3d22a2d0 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -84,7 +84,8 @@ struct hppa_objfile_private
    that separately and make this static. The solib data is probably hpux-
    specific, so we can create a separate extern objfile_data that is registered
    by hppa-hpux-tdep.c and shared with pa64solib.c and somsolib.c.  */
-static const struct objfile_key<hppa_objfile_private> hppa_objfile_priv_data;
+static const registry<objfile>::key<hppa_objfile_private>
+  hppa_objfile_priv_data;
 
 /* Get at various relevant fields of an instruction word.  */
 #define MASK_5 0x1f
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 606b4189181..7eb2bd97907 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -38,11 +38,6 @@
 #include "gdbsupport/buildargv.h"
 #include "cli/cli-style.h"
 
-/* Keep a registry of per-inferior data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (inferior, REGISTRY_ACCESS_FIELD)
-
 intrusive_list<inferior> inferior_list;
 static int highest_inferior_num;
 
@@ -76,18 +71,14 @@ inferior::~inferior ()
   inferior *inf = this;
 
   m_continuations.clear ();
-  inferior_free_data (inf);
   target_desc_info_free (inf->tdesc_info);
 }
 
 inferior::inferior (int pid_)
   : num (++highest_inferior_num),
     pid (pid_),
-    environment (gdb_environ::from_host_environ ()),
-    registry_data ()
+    environment (gdb_environ::from_host_environ ())
 {
-  inferior_alloc_data (this);
-
   m_target_stack.push (get_dummy_target ());
 }
 
diff --git a/gdb/inferior.h b/gdb/inferior.h
index c376d780de0..017800165b4 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -595,7 +595,7 @@ public:
   displaced_step_inferior_state displaced_step_state;
 
   /* Per inferior data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS;
+  registry<inferior> registry_fields;
 
 private:
   /* The inferior's target stack.  */
@@ -615,11 +615,6 @@ private:
   std::string m_cwd;
 };
 
-/* Keep a registry of per-inferior data-pointers required by other GDB
-   modules.  */
-
-DECLARE_REGISTRY (inferior);
-
 /* Add an inferior to the inferior list, print a message that a new
    inferior is found, and return the pointer to the new inferior.
    Caller may use this pointer to initialize the private inferior
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 9c7e2907625..5477624bcd5 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -599,7 +599,7 @@ child_pass_ctrlc (struct target_ops *self)
 }
 
 /* Per-inferior data key.  */
-static const struct inferior_key<terminal_info> inflow_inferior_data;
+static const registry<inferior>::key<terminal_info> inflow_inferior_data;
 
 terminal_info::~terminal_info ()
 {
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 8a83ed320cf..4e6a48b1d20 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -236,7 +236,7 @@ struct linux_info
 };
 
 /* Per-inferior data key.  */
-static const struct inferior_key<linux_info> linux_inferior_data;
+static const registry<inferior>::key<linux_info> linux_inferior_data;
 
 /* Frees whatever allocated space there is to be freed and sets INF's
    linux cache data pointer to NULL.  */
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index a2280c3ba8d..001042b9cf5 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -1354,8 +1354,8 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char *ext_sh, int bigend,
 
 /* Basic types.  */
 
-static const struct objfile_key<struct type *,
-				gdb::noop_deleter<struct type *>>
+static const registry<objfile>::key<struct type *,
+				    gdb::noop_deleter<struct type *>>
   basic_type_data;
 
 static struct type *
diff --git a/gdb/minidebug.c b/gdb/minidebug.c
index e94768ac69c..dbbdf85e08c 100644
--- a/gdb/minidebug.c
+++ b/gdb/minidebug.c
@@ -28,7 +28,7 @@
 
 /* We stash a reference to the .gnu_debugdata BFD on the enclosing
    BFD.  */
-static const bfd_key<gdb_bfd_ref_ptr> gnu_debug_key;
+static const registry<bfd>::key<gdb_bfd_ref_ptr> gnu_debug_key;
 
 #include <lzma.h>
 
diff --git a/gdb/nto-tdep.c b/gdb/nto-tdep.c
index 9b08adfa18c..301d403eb13 100644
--- a/gdb/nto-tdep.c
+++ b/gdb/nto-tdep.c
@@ -51,7 +51,7 @@ static char default_nto_target[] = "";
 
 struct nto_target_ops current_nto_target;
 
-static const struct inferior_key<struct nto_inferior_data>
+static const registry<inferior>::key<struct nto_inferior_data>
   nto_inferior_data_reg;
 
 static char *
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index 37008da529a..4429d4a7d44 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -76,7 +76,7 @@ struct objc_method {
   CORE_ADDR imp;
 };
 
-static const struct objfile_key<unsigned int> objc_objfile_data;
+static const registry<objfile>::key<unsigned int> objc_objfile_data;
 
 /* Lookup a structure type named "struct NAME", visible in lexical
    block BLOCK.  If NOERR is nonzero, return zero if NAME is not
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index f4625575473..7759311afca 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -57,11 +57,6 @@
 #include <algorithm>
 #include <vector>
 
-/* Keep a registry of per-objfile data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (objfile, REGISTRY_ACCESS_FIELD)
-
 /* Externally visible variables that are owned by this module.
    See declarations in objfile.h for more info.  */
 
@@ -85,7 +80,7 @@ struct objfile_pspace_info
 };
 
 /* Per-program-space data key.  */
-static const struct program_space_key<objfile_pspace_info>
+static const registry<program_space>::key<objfile_pspace_info>
   objfiles_pspace_data;
 
 objfile_pspace_info::~objfile_pspace_info ()
@@ -112,7 +107,7 @@ get_objfile_pspace_data (struct program_space *pspace)
 
 /* Per-BFD data key.  */
 
-static const struct bfd_key<objfile_per_bfd_storage> objfiles_bfd_data;
+static const registry<bfd>::key<objfile_per_bfd_storage> objfiles_bfd_data;
 
 objfile_per_bfd_storage::~objfile_per_bfd_storage ()
 {
@@ -329,8 +324,6 @@ objfile::objfile (bfd *abfd, const char *name, objfile_flags flags_)
      gdb_obstack.h specifies the alloc/dealloc functions.  */
   obstack_init (&objfile_obstack);
 
-  objfile_alloc_data (this);
-
   std::string name_holder;
   if (name == NULL)
     {
@@ -563,10 +556,6 @@ objfile::~objfile ()
   if (sf != NULL)
     (*sf->sym_finish) (this);
 
-  /* Discard any data modules have associated with the objfile.  The function
-     still may reference obfd.  */
-  objfile_free_data (this);
-
   if (obfd)
     gdb_bfd_unref (obfd);
   else
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index a7098b46279..e724a4e8764 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -682,7 +682,7 @@ public:
 
   /* Per objfile data-pointers required by other GDB modules.  */
 
-  REGISTRY_FIELDS {};
+  registry<objfile> registry_fields;
 
   /* Set of relocation offsets to apply to each section.
      The table is indexed by the_bfd_section->index, thus it is generally
@@ -900,10 +900,6 @@ in_plt_section (CORE_ADDR pc)
 	  || pc_in_section (pc, ".plt.sec"));
 }
 
-/* Keep a registry of per-objfile data-pointers required by other GDB
-   modules.  */
-DECLARE_REGISTRY(objfile);
-
 /* In normal use, the section map will be rebuilt by find_pc_section
    if objfiles have been added, removed or relocated since it was last
    called.  Calling inhibit_section_map_updates will inhibit this
diff --git a/gdb/progspace.c b/gdb/progspace.c
index c2e2da5a7dc..90003d964fe 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -43,24 +43,11 @@ static int highest_address_space_num;
 
 \f
 
-/* Keep a registry of per-program_space data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (program_space, REGISTRY_ACCESS_FIELD)
-
-/* Keep a registry of per-address_space data-pointers required by other GDB
-   modules.  */
-
-DEFINE_REGISTRY (address_space, REGISTRY_ACCESS_FIELD)
-
-\f
-
 /* Create a new address space object, and add it to the list.  */
 
 address_space::address_space ()
   : m_num (++highest_address_space_num)
 {
-  address_space_alloc_data (this);
 }
 
 /* Maybe create a new address space object, and add it to the list, or
@@ -81,11 +68,6 @@ maybe_new_address_space (void)
   return new address_space ();
 }
 
-address_space::~address_space ()
-{
-  address_space_free_data (this);
-}
-
 /* Start counting over from scratch.  */
 
 static void
@@ -115,8 +97,6 @@ program_space::program_space (address_space *aspace_)
   : num (++last_program_space_num),
     aspace (aspace_)
 {
-  program_space_alloc_data (this);
-
   program_spaces.push_back (this);
 }
 
@@ -140,8 +120,6 @@ program_space::~program_space ()
   clear_symtab_users (SYMFILE_DEFER_BP_RESET);
   if (!gdbarch_has_shared_address_space (target_gdbarch ()))
     delete this->aspace;
-    /* Discard any data modules have associated with the PSPACE.  */
-  program_space_free_data (this);
 }
 
 /* See progspace.h.  */
diff --git a/gdb/progspace.h b/gdb/progspace.h
index 8531da4a095..febdcef4028 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -37,8 +37,7 @@ struct objfile;
 struct inferior;
 struct exec;
 struct address_space;
-struct program_space_data;
-struct address_space_data;
+struct program_space;
 struct so_list;
 
 typedef std::list<std::unique_ptr<objfile>> objfile_list;
@@ -372,7 +371,7 @@ struct program_space
   std::vector<std::string> deleted_solibs;
 
   /* Per pspace data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS {};
+  registry<program_space> registry_fields;
 
 private:
   /* The set of target sections matching the sections mapped into
@@ -387,7 +386,6 @@ struct address_space
 {
   /* Create a new address space object, and add it to the list.  */
   address_space ();
-  ~address_space ();
   DISABLE_COPY_AND_ASSIGN (address_space);
 
   /* Returns the integer address space id of this address space.  */
@@ -397,7 +395,7 @@ struct address_space
   }
 
   /* Per aspace data-pointers required by other GDB modules.  */
-  REGISTRY_FIELDS {};
+  registry<address_space> registry_fields;
 
 private:
   int m_num;
@@ -457,14 +455,4 @@ extern struct address_space *maybe_new_address_space (void);
    mappings.  */
 extern void update_address_spaces (void);
 
-/* Keep a registry of per-pspace data-pointers required by other GDB
-   modules.  */
-
-DECLARE_REGISTRY (program_space);
-
-/* Keep a registry of per-aspace data-pointers required by other GDB
-   modules.  */
-
-DECLARE_REGISTRY (address_space);
-
 #endif
diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c
index 872fb89ba83..b9aea3aca69 100644
--- a/gdb/python/py-block.c
+++ b/gdb/python/py-block.c
@@ -77,9 +77,33 @@ struct block_syms_iterator_object {
       }									\
   } while (0)
 
+/* This is called when an objfile is about to be freed.
+   Invalidate the block as further actions on the block would result
+   in bad data.  All access to obj->symbol should be gated by
+   BLPY_REQUIRE_VALID which will raise an exception on invalid
+   blocks.  */
+struct blpy_deleter
+{
+  void operator() (block_object *obj)
+  {
+    while (obj)
+      {
+	block_object *next = obj->next;
+
+	obj->block = NULL;
+	obj->objfile = NULL;
+	obj->next = NULL;
+	obj->prev = NULL;
+
+	obj = next;
+      }
+  }
+};
+
 extern PyTypeObject block_syms_iterator_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("block_syms_iterator_object");
-static const struct objfile_data *blpy_objfile_data_key;
+static const registry<objfile>::key<block_object, blpy_deleter>
+     blpy_objfile_data_key;
 
 static PyObject *
 blpy_iter (PyObject *self)
@@ -269,10 +293,7 @@ blpy_dealloc (PyObject *obj)
   if (block->prev)
     block->prev->next = block->next;
   else if (block->objfile)
-    {
-      set_objfile_data (block->objfile, blpy_objfile_data_key,
-			block->next);
-    }
+    blpy_objfile_data_key.set (block->objfile, block->next);
   if (block->next)
     block->next->prev = block->prev;
   block->block = NULL;
@@ -293,11 +314,10 @@ set_block (block_object *obj, const struct block *block,
   if (objfile)
     {
       obj->objfile = objfile;
-      obj->next = ((block_object *)
-		   objfile_data (objfile, blpy_objfile_data_key));
+      obj->next = blpy_objfile_data_key.get (objfile);
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (objfile, blpy_objfile_data_key, obj);
+      blpy_objfile_data_key.set (objfile, obj);
     }
   else
     obj->next = NULL;
@@ -404,40 +424,6 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
   Py_RETURN_TRUE;
 }
 
-/* This function is called when an objfile is about to be freed.
-   Invalidate the block as further actions on the block would result
-   in bad data.  All access to obj->symbol should be gated by
-   BLPY_REQUIRE_VALID which will raise an exception on invalid
-   blocks.  */
-static void
-del_objfile_blocks (struct objfile *objfile, void *datum)
-{
-  block_object *obj = (block_object *) datum;
-
-  while (obj)
-    {
-      block_object *next = obj->next;
-
-      obj->block = NULL;
-      obj->objfile = NULL;
-      obj->next = NULL;
-      obj->prev = NULL;
-
-      obj = next;
-    }
-}
-
-void _initialize_py_block ();
-void
-_initialize_py_block ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate blocks when an object file is about to be
-     deleted.  */
-  blpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_blocks);
-}
-
 int
 gdbpy_initialize_blocks (void)
 {
diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c
index 61ed342d1c1..6ea384e26a0 100644
--- a/gdb/python/py-inferior.c
+++ b/gdb/python/py-inferior.c
@@ -60,7 +60,35 @@ struct inferior_object
 extern PyTypeObject inferior_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("inferior_object");
 
-static const struct inferior_data *infpy_inf_data_key;
+/* Deleter to clean up when an inferior is removed.  */
+struct infpy_deleter
+{
+  void operator() (inferior_object *obj)
+  {
+    struct threadlist_entry *th_entry, *th_tmp;
+
+    if (!gdb_python_initialized)
+      return;
+
+    gdbpy_enter enter_py;
+    gdbpy_ref<inferior_object> inf_obj (obj);
+
+    inf_obj->inferior = NULL;
+
+    /* Deallocate threads list.  */
+    for (th_entry = inf_obj->threads; th_entry != NULL;)
+      {
+	th_tmp = th_entry;
+	th_entry = th_entry->next;
+	delete th_tmp;
+      }
+
+    inf_obj->nthreads = 0;
+  }
+};
+
+static const registry<inferior>::key<inferior_object, infpy_deleter>
+     infpy_inf_data_key;
 
 /* Require that INFERIOR be a valid inferior ID.  */
 #define INFPY_REQUIRE_VALID(Inferior)				\
@@ -221,7 +249,7 @@ inferior_to_inferior_object (struct inferior *inferior)
 {
   inferior_object *inf_obj;
 
-  inf_obj = (inferior_object *) inferior_data (inferior, infpy_inf_data_key);
+  inf_obj = infpy_inf_data_key.get (inferior);
   if (!inf_obj)
     {
       inf_obj = PyObject_New (inferior_object, &inferior_object_type);
@@ -234,7 +262,7 @@ inferior_to_inferior_object (struct inferior *inferior)
 
       /* PyObject_New initializes the new object with a refcount of 1.  This
 	 counts for the reference we are keeping in the inferior data.  */
-      set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
+      infpy_inf_data_key.set (inferior, inf_obj);
     }
 
   /* We are returning a new reference.  */
@@ -795,32 +823,6 @@ infpy_dealloc (PyObject *obj)
   Py_TYPE (obj)->tp_free (obj);
 }
 
-/* Clear the INFERIOR pointer in an Inferior object and clear the
-   thread list.  */
-static void
-py_free_inferior (struct inferior *inf, void *datum)
-{
-  struct threadlist_entry *th_entry, *th_tmp;
-
-  if (!gdb_python_initialized)
-    return;
-
-  gdbpy_enter enter_py;
-  gdbpy_ref<inferior_object> inf_obj ((inferior_object *) datum);
-
-  inf_obj->inferior = NULL;
-
-  /* Deallocate threads list.  */
-  for (th_entry = inf_obj->threads; th_entry != NULL;)
-    {
-      th_tmp = th_entry;
-      th_entry = th_entry->next;
-      delete th_tmp;
-    }
-
-  inf_obj->nthreads = 0;
-}
-
 /* Implementation of gdb.selected_inferior() -> gdb.Inferior.
    Returns the current inferior object.  */
 
@@ -831,14 +833,6 @@ gdbpy_selected_inferior (PyObject *self, PyObject *args)
 	  inferior_to_inferior_object (current_inferior ()).release ());
 }
 
-void _initialize_py_inferior ();
-void
-_initialize_py_inferior ()
-{
-  infpy_inf_data_key =
-    register_inferior_data_with_cleanup (NULL, py_free_inferior);
-}
-
 int
 gdbpy_initialize_inferior (void)
 {
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 298f3f23632..4cc570286dc 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -55,7 +55,20 @@ struct objfile_object
 extern PyTypeObject objfile_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("objfile_object");
 
-static const struct objfile_data *objfpy_objfile_data_key;
+/* Clear the OBJFILE pointer in an Objfile object and remove the
+   reference.  */
+struct objfpy_deleter
+{
+  void operator() (objfile_object *obj)
+  {
+    gdbpy_enter enter_py;
+    gdbpy_ref<objfile_object> object (obj);
+    object->objfile = nullptr;
+  }
+};
+
+static const registry<objfile>::key<objfile_object, objfpy_deleter>
+     objfpy_objfile_data_key;
 
 /* Require that OBJF be a valid objfile.  */
 #define OBJFPY_REQUIRE_VALID(obj)				\
@@ -668,16 +681,6 @@ gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw)
 
 \f
 
-/* Clear the OBJFILE pointer in an Objfile object and remove the
-   reference.  */
-static void
-py_free_objfile (struct objfile *objfile, void *datum)
-{
-  gdbpy_enter enter_py (objfile->arch ());
-  gdbpy_ref<objfile_object> object ((objfile_object *) datum);
-  object->objfile = NULL;
-}
-
 /* Return a new reference to the Python object of type Objfile
    representing OBJFILE.  If the object has already been created,
    return it.  Otherwise, create it.  Return NULL and set the Python
@@ -687,7 +690,7 @@ gdbpy_ref<>
 objfile_to_objfile_object (struct objfile *objfile)
 {
   PyObject *result
-    = ((PyObject *) objfile_data (objfile, objfpy_objfile_data_key));
+    = (PyObject *) objfpy_objfile_data_key.get (objfile);
   if (result == NULL)
     {
       gdbpy_ref<objfile_object> object
@@ -698,21 +701,13 @@ objfile_to_objfile_object (struct objfile *objfile)
 	return NULL;
 
       object->objfile = objfile;
-      set_objfile_data (objfile, objfpy_objfile_data_key, object.get ());
+      objfpy_objfile_data_key.set (objfile, object.get ());
       result = (PyObject *) object.release ();
     }
 
   return gdbpy_ref<>::new_reference (result);
 }
 
-void _initialize_py_objfile ();
-void
-_initialize_py_objfile ()
-{
-  objfpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, py_free_objfile);
-}
-
 int
 gdbpy_initialize_objfile (void)
 {
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index 5ec5986fce8..4eb33e8292f 100644
--- a/gdb/python/py-progspace.c
+++ b/gdb/python/py-progspace.c
@@ -57,7 +57,30 @@ struct pspace_object
 extern PyTypeObject pspace_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pspace_object");
 
-static const struct program_space_data *pspy_pspace_data_key;
+/* Clear the PSPACE pointer in a Pspace object and remove the reference.  */
+struct pspace_deleter
+{
+  void operator() (pspace_object *obj)
+  {
+    /* This is a fiction, but we're in a nasty spot: The pspace is in the
+       process of being deleted, we can't rely on anything in it.  Plus
+       this is one time when the current program space and current inferior
+       are not in sync: All inferiors that use PSPACE may no longer exist.
+       We don't need to do much here, and since "there is always an inferior"
+       using target_gdbarch suffices.
+       Note: We cannot call get_current_arch because it may try to access
+       the target, which may involve accessing data in the pspace currently
+       being deleted.  */
+    struct gdbarch *arch = target_gdbarch ();
+
+    gdbpy_enter enter_py (arch);
+    gdbpy_ref<pspace_object> object (obj);
+    object->pspace = NULL;
+  }
+};
+
+static const registry<program_space>::key<pspace_object, pspace_deleter>
+     pspy_pspace_data_key;
 
 /* Require that PSPACE_OBJ be a valid program space ID.  */
 #define PSPY_REQUIRE_VALID(pspace_obj)				\
@@ -463,27 +486,6 @@ pspy_is_valid (PyObject *o, PyObject *args)
 
 \f
 
-/* Clear the PSPACE pointer in a Pspace object and remove the reference.  */
-
-static void
-py_free_pspace (struct program_space *pspace, void *datum)
-{
-  /* This is a fiction, but we're in a nasty spot: The pspace is in the
-     process of being deleted, we can't rely on anything in it.  Plus
-     this is one time when the current program space and current inferior
-     are not in sync: All inferiors that use PSPACE may no longer exist.
-     We don't need to do much here, and since "there is always an inferior"
-     using target_gdbarch suffices.
-     Note: We cannot call get_current_arch because it may try to access
-     the target, which may involve accessing data in the pspace currently
-     being deleted.  */
-  struct gdbarch *arch = target_gdbarch ();
-
-  gdbpy_enter enter_py (arch);
-  gdbpy_ref<pspace_object> object ((pspace_object *) datum);
-  object->pspace = NULL;
-}
-
 /* Return a new reference to the Python object of type Pspace
    representing PSPACE.  If the object has already been created,
    return it.  Otherwise, create it.  Return NULL and set the Python
@@ -492,8 +494,7 @@ py_free_pspace (struct program_space *pspace, void *datum)
 gdbpy_ref<>
 pspace_to_pspace_object (struct program_space *pspace)
 {
-  PyObject *result
-    ((PyObject *) program_space_data (pspace, pspy_pspace_data_key));
+  PyObject *result = (PyObject *) pspy_pspace_data_key.get (pspace);
   if (result == NULL)
     {
       gdbpy_ref<pspace_object> object
@@ -504,7 +505,7 @@ pspace_to_pspace_object (struct program_space *pspace)
 	return NULL;
 
       object->pspace = pspace;
-      set_program_space_data (pspace, pspy_pspace_data_key, object.get ());
+      pspy_pspace_data_key.set (pspace, object.get ());
       result = (PyObject *) object.release ();
     }
 
@@ -528,14 +529,6 @@ gdbpy_is_progspace (PyObject *obj)
   return PyObject_TypeCheck (obj, &pspace_object_type);
 }
 
-void _initialize_py_progspace ();
-void
-_initialize_py_progspace ()
-{
-  pspy_pspace_data_key
-    = register_program_space_data_with_cleanup (NULL, py_free_pspace);
-}
-
 int
 gdbpy_initialize_pspace (void)
 {
diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c
index 23495b66d42..e5fe5cf8c92 100644
--- a/gdb/python/py-symbol.c
+++ b/gdb/python/py-symbol.c
@@ -50,7 +50,26 @@ struct symbol_object {
       }							\
   } while (0)
 
-static const struct objfile_data *sympy_objfile_data_key;
+/* A deleter that is used when an objfile is about to be freed.  */
+struct symbol_object_deleter
+{
+  void operator() (symbol_object *obj)
+  {
+    while (obj)
+      {
+	symbol_object *next = obj->next;
+
+	obj->symbol = NULL;
+	obj->next = NULL;
+	obj->prev = NULL;
+
+	obj = next;
+      }
+  }
+};
+
+static const registry<objfile>::key<symbol_object, symbol_object_deleter>
+     sympy_objfile_data_key;
 
 static PyObject *
 sympy_str (PyObject *self)
@@ -307,11 +326,10 @@ set_symbol (symbol_object *obj, struct symbol *symbol)
     {
       struct objfile *objfile = symbol->objfile ();
 
-      obj->next = ((symbol_object *)
-		   objfile_data (objfile, sympy_objfile_data_key));
+      obj->next = sympy_objfile_data_key.get (objfile);
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (objfile, sympy_objfile_data_key, obj);
+      sympy_objfile_data_key.set (objfile, obj);
     }
   else
     obj->next = NULL;
@@ -350,10 +368,7 @@ sympy_dealloc (PyObject *obj)
   else if (sym_obj->symbol != NULL
 	   && sym_obj->symbol->is_objfile_owned ()
 	   && sym_obj->symbol->symtab () != NULL)
-    {
-      set_objfile_data (sym_obj->symbol->objfile (),
-			sympy_objfile_data_key, sym_obj->next);
-    }
+    sympy_objfile_data_key.set (sym_obj->symbol->objfile (), sym_obj->next);
   if (sym_obj->next)
     sym_obj->next->prev = sym_obj->prev;
   sym_obj->symbol = NULL;
@@ -596,38 +611,6 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
   return return_list.release ();
 }
 
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol as further actions on the symbol would result
-   in bad data.  All access to obj->symbol should be gated by
-   SYMPY_REQUIRE_VALID which will raise an exception on invalid
-   symbols.  */
-static void
-del_objfile_symbols (struct objfile *objfile, void *datum)
-{
-  symbol_object *obj = (symbol_object *) datum;
-  while (obj)
-    {
-      symbol_object *next = obj->next;
-
-      obj->symbol = NULL;
-      obj->next = NULL;
-      obj->prev = NULL;
-
-      obj = next;
-    }
-}
-
-void _initialize_py_symbol ();
-void
-_initialize_py_symbol ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbol when an object file that is about to be
-     deleted.  */
-  sympy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_symbols);
-}
-
 int
 gdbpy_initialize_symbols (void)
 {
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 7ed62716b67..03c274dfff6 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -37,9 +37,31 @@ struct symtab_object {
   symtab_object *next;
 };
 
+/* This function is called when an objfile is about to be freed.
+   Invalidate the symbol table as further actions on the symbol table
+   would result in bad data.  All access to obj->symtab should be
+   gated by STPY_REQUIRE_VALID which will raise an exception on
+   invalid symbol tables.  */
+struct stpy_deleter
+{
+  void operator() (symtab_object *obj)
+  {
+    while (obj)
+      {
+	symtab_object *next = obj->next;
+
+	obj->symtab = NULL;
+	obj->next = NULL;
+	obj->prev = NULL;
+	obj = next;
+      }
+  }
+};
+
 extern PyTypeObject symtab_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("symtab_object");
-static const struct objfile_data *stpy_objfile_data_key;
+static const registry<objfile>::key<symtab_object, stpy_deleter>
+     stpy_objfile_data_key;
 
 /* Require a valid symbol table.  All access to symtab_object->symtab
    should be gated by this call.  */
@@ -68,9 +90,39 @@ struct sal_object {
   sal_object *next;
 };
 
+/* This is called when an objfile is about to be freed.  Invalidate
+   the sal object as further actions on the sal would result in bad
+   data.  All access to obj->sal should be gated by
+   SALPY_REQUIRE_VALID which will raise an exception on invalid symbol
+   table and line objects.  */
+struct salpy_deleter
+{
+  void operator() (sal_object *obj)
+  {
+    gdbpy_enter enter_py;
+
+    while (obj)
+      {
+	sal_object *next = obj->next;
+
+	gdbpy_ref<> tmp (obj->symtab);
+	obj->symtab = Py_None;
+	Py_INCREF (Py_None);
+
+	obj->next = NULL;
+	obj->prev = NULL;
+	xfree (obj->sal);
+	obj->sal = NULL;
+
+	obj = next;
+      }
+  }
+};
+
 extern PyTypeObject sal_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("sal_object");
-static const struct objfile_data *salpy_objfile_data_key;
+static const registry<objfile>::key<sal_object, salpy_deleter>
+     salpy_objfile_data_key;
 
 /* Require a valid symbol table and line object.  All access to
    sal_object->sal should be gated by this call.  */
@@ -246,10 +298,8 @@ stpy_dealloc (PyObject *obj)
   if (symtab->prev)
     symtab->prev->next = symtab->next;
   else if (symtab->symtab)
-    {
-      set_objfile_data (symtab->symtab->compunit ()->objfile (),
-			stpy_objfile_data_key, symtab->next);
-    }
+    stpy_objfile_data_key.set (symtab->symtab->compunit ()->objfile (),
+			       symtab->next);
   if (symtab->next)
     symtab->next->prev = symtab->prev;
   symtab->symtab = NULL;
@@ -329,9 +379,9 @@ salpy_dealloc (PyObject *self)
   if (self_sal->prev)
     self_sal->prev->next = self_sal->next;
   else if (self_sal->symtab != Py_None)
-    set_objfile_data
+    salpy_objfile_data_key.set
       (symtab_object_to_symtab (self_sal->symtab)->compunit ()->objfile (),
-       salpy_objfile_data_key, self_sal->next);
+       self_sal->next);
 
   if (self_sal->next)
     self_sal->next->prev = self_sal->prev;
@@ -378,13 +428,11 @@ set_sal (sal_object *sal_obj, struct symtab_and_line sal)
       symtab *symtab = symtab_object_to_symtab (sal_obj->symtab);
 
       sal_obj->next
-	= ((sal_object *) objfile_data (symtab->compunit ()->objfile (),
-					salpy_objfile_data_key));
+	= salpy_objfile_data_key.get (symtab->compunit ()->objfile ());
       if (sal_obj->next)
 	sal_obj->next->prev = sal_obj;
 
-      set_objfile_data (symtab->compunit ()->objfile (),
-			salpy_objfile_data_key, sal_obj);
+      salpy_objfile_data_key.set (symtab->compunit ()->objfile (), sal_obj);
     }
   else
     sal_obj->next = NULL;
@@ -404,14 +452,10 @@ set_symtab (symtab_object *obj, struct symtab *symtab)
   obj->prev = NULL;
   if (symtab)
     {
-      obj->next
-	= ((symtab_object *)
-	   objfile_data (symtab->compunit ()->objfile (),
-			 stpy_objfile_data_key));
+      obj->next = stpy_objfile_data_key.get (symtab->compunit ()->objfile ());
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (symtab->compunit ()->objfile (),
-			stpy_objfile_data_key, obj);
+      stpy_objfile_data_key.set (symtab->compunit ()->objfile (), obj);
     }
   else
     obj->next = NULL;
@@ -465,68 +509,6 @@ symtab_object_to_symtab (PyObject *obj)
   return ((symtab_object *) obj)->symtab;
 }
 
-/* This function is called when an objfile is about to be freed.
-   Invalidate the symbol table as further actions on the symbol table
-   would result in bad data.  All access to obj->symtab should be
-   gated by STPY_REQUIRE_VALID which will raise an exception on
-   invalid symbol tables.  */
-static void
-del_objfile_symtab (struct objfile *objfile, void *datum)
-{
-  symtab_object *obj = (symtab_object *) datum;
-
-  while (obj)
-    {
-      symtab_object *next = obj->next;
-
-      obj->symtab = NULL;
-      obj->next = NULL;
-      obj->prev = NULL;
-      obj = next;
-    }
-}
-
-/* This function is called when an objfile is about to be freed.
-   Invalidate the sal object as further actions on the sal
-   would result in bad data.  All access to obj->sal should be
-   gated by SALPY_REQUIRE_VALID which will raise an exception on
-   invalid symbol table and line objects.  */
-static void
-del_objfile_sal (struct objfile *objfile, void *datum)
-{
-  sal_object *obj = (sal_object *) datum;
-
-  while (obj)
-    {
-      sal_object *next = obj->next;
-
-      gdbpy_ref<> tmp (obj->symtab);
-      obj->symtab = Py_None;
-      Py_INCREF (Py_None);
-
-      obj->next = NULL;
-      obj->prev = NULL;
-      xfree (obj->sal);
-      obj->sal = NULL;
-
-      obj = next;
-    }
-}
-
-void _initialize_py_symtab ();
-void
-_initialize_py_symtab ()
-{
-  /* Register an objfile "free" callback so we can properly
-     invalidate symbol tables, and symbol table and line data
-     structures when an object file that is about to be
-     deleted.  */
-  stpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_symtab);
-  salpy_objfile_data_key
-    = register_objfile_data_with_cleanup (NULL, del_objfile_sal);
-}
-
 int
 gdbpy_initialize_symtabs (void)
 {
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 7cfc8d16233..d14f9e42853 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -1109,36 +1109,38 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
 
 \f
 
-static const struct objfile_data *typy_objfile_data_key;
-
-static void
-save_objfile_types (struct objfile *objfile, void *datum)
+/* Deleter that saves types when an objfile is being destroyed.  */
+struct typy_deleter
 {
-  type_object *obj = (type_object *) datum;
+  void operator() (type_object *obj)
+  {
+    if (!gdb_python_initialized)
+      return;
 
-  if (!gdb_python_initialized)
-    return;
+    /* This prevents another thread from freeing the objects we're
+       operating on.  */
+    gdbpy_enter enter_py;
 
-  /* This prevents another thread from freeing the objects we're
-     operating on.  */
-  gdbpy_enter enter_py (objfile->arch ());
+    htab_up copied_types = create_copied_types_hash ();
 
-  htab_up copied_types = create_copied_types_hash ();
+    while (obj)
+      {
+	type_object *next = obj->next;
 
-  while (obj)
-    {
-      type_object *next = obj->next;
+	htab_empty (copied_types.get ());
 
-      htab_empty (copied_types.get ());
+	obj->type = copy_type_recursive (obj->type, copied_types.get ());
 
-      obj->type = copy_type_recursive (obj->type, copied_types.get ());
+	obj->next = NULL;
+	obj->prev = NULL;
 
-      obj->next = NULL;
-      obj->prev = NULL;
+	obj = next;
+      }
+  }
+};
 
-      obj = next;
-    }
-}
+static const registry<objfile>::key<type_object, typy_deleter>
+     typy_objfile_data_key;
 
 static void
 set_type (type_object *obj, struct type *type)
@@ -1149,11 +1151,10 @@ set_type (type_object *obj, struct type *type)
     {
       struct objfile *objfile = type->objfile_owner ();
 
-      obj->next = ((type_object *)
-		   objfile_data (objfile, typy_objfile_data_key));
+      obj->next = typy_objfile_data_key.get (objfile);
       if (obj->next)
 	obj->next->prev = obj;
-      set_objfile_data (objfile, typy_objfile_data_key, obj);
+      typy_objfile_data_key.set (objfile, obj);
     }
   else
     obj->next = NULL;
@@ -1172,7 +1173,7 @@ typy_dealloc (PyObject *obj)
       struct objfile *objfile = type->type->objfile_owner ();
 
       if (objfile)
-	set_objfile_data (objfile, typy_objfile_data_key, type->next);
+	typy_objfile_data_key.set (objfile, type->next);
     }
   if (type->next)
     type->next->prev = type->prev;
@@ -1464,14 +1465,6 @@ gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
   return type_to_type_object (type);
 }
 
-void _initialize_py_type ();
-void
-_initialize_py_type ()
-{
-  typy_objfile_data_key
-    = register_objfile_data_with_cleanup (save_objfile_types, NULL);
-}
-
 int
 gdbpy_initialize_types (void)
 {
diff --git a/gdb/registry.c b/gdb/registry.c
deleted file mode 100644
index 2e977e2528f..00000000000
--- a/gdb/registry.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Support functions for general registry objects.
-
-   Copyright (C) 2011-2022 Free Software Foundation, Inc.
-
-   This file is part of GDB.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include "defs.h"
-#include "registry.h"
-const struct registry_data *
-register_data_with_cleanup (struct registry_data_registry *registry,
-			    registry_data_callback save,
-			    registry_data_callback free)
-{
-  struct registry_data_registration **curr;
-
-  /* Append new registration.  */
-  for (curr = &registry->registrations;
-       *curr != NULL;
-       curr = &(*curr)->next)
-    ;
-
-  *curr = XNEW (struct registry_data_registration);
-  (*curr)->next = NULL;
-  (*curr)->data = XNEW (struct registry_data);
-  (*curr)->data->index = registry->num_registrations++;
-  (*curr)->data->save = save;
-  (*curr)->data->free = free;
-
-  return (*curr)->data;
-}
-
-void
-registry_alloc_data (struct registry_data_registry *registry,
-		       struct registry_fields *fields)
-{
-  gdb_assert (fields->data == NULL);
-  fields->num_data = registry->num_registrations;
-  fields->data = XCNEWVEC (void *, fields->num_data);
-}
-
-void
-registry_clear_data (struct registry_data_registry *data_registry,
-		     registry_callback_adaptor adaptor,
-		     struct registry_container *container,
-		     struct registry_fields *fields)
-{
-  struct registry_data_registration *registration;
-  int i;
-
-  gdb_assert (fields->data != NULL);
-
-  /* Process all the save handlers.  */
-
-  for (registration = data_registry->registrations, i = 0;
-       i < fields->num_data;
-       registration = registration->next, i++)
-    if (fields->data[i] != NULL && registration->data->save != NULL)
-      adaptor (registration->data->save, container, fields->data[i]);
-
-  /* Now process all the free handlers.  */
-
-  for (registration = data_registry->registrations, i = 0;
-       i < fields->num_data;
-       registration = registration->next, i++)
-    if (fields->data[i] != NULL && registration->data->free != NULL)
-      adaptor (registration->data->free, container, fields->data[i]);
-
-  memset (fields->data, 0, fields->num_data * sizeof (void *));
-}
-
-void
-registry_container_free_data (struct registry_data_registry *data_registry,
-			      registry_callback_adaptor adaptor,
-			      struct registry_container *container,
-			      struct registry_fields *fields)
-{
-  void ***rdata = &fields->data;
-  gdb_assert (*rdata != NULL);
-  registry_clear_data (data_registry, adaptor, container, fields);
-  xfree (*rdata);
-  *rdata = NULL;
-}
-
-void
-registry_set_data (struct registry_fields *fields,
-		   const struct registry_data *data,
-		   void *value)
-{
-  gdb_assert (data->index < fields->num_data);
-  fields->data[data->index] = value;
-}
-
-void *
-registry_data (struct registry_fields *fields,
-	       const struct registry_data *data)
-{
-  gdb_assert (data->index < fields->num_data);
-  return fields->data[data->index];
-}
diff --git a/gdb/registry.h b/gdb/registry.h
index 1475fd2ec26..cab9f44e3ba 100644
--- a/gdb/registry.h
+++ b/gdb/registry.h
@@ -22,288 +22,214 @@
 
 #include <type_traits>
 
-/* The macros here implement a template type and functions for
-   associating some user data with a container object.
-
-   A registry is associated with a struct tag name.  To attach a
-   registry to a structure, use DEFINE_REGISTRY.  This takes the
-   structure tag and an access method as arguments.  In the usual
-   case, where the registry fields appear directly in the struct, you
-   can use the 'REGISTRY_FIELDS' macro to declare the fields in the
-   struct definition, and you can pass 'REGISTRY_ACCESS_FIELD' as the
-   access argument to DEFINE_REGISTRY.  In other cases, use
-   REGISTRY_FIELDS to define the fields in the appropriate spot, and
-   then define your own accessor to find the registry field structure
-   given an instance of your type.
-
-   The API user requests a key from a registry during gdb
-   initialization.  Later this key can be used to associate some
-   module-specific data with a specific container object.
-
-   The exported API is best used via the wrapper macros:
-   
-   - register_TAG_data(TAG)
-   Get a new key for the container type TAG.
-   
-   - register_TAG_data_with_cleanup(TAG, SAVE, FREE)
-   Get a new key for the container type TAG.
-   SAVE and FREE are defined as void (*) (struct TAG *object, void *data)
-   When the container object OBJECT is destroyed, first all registered SAVE
-   functions are called.
-   Then all FREE functions are called.
-   Either or both may be NULL.  DATA is the data associated with the
-   container object OBJECT.
-   
-   - clear_TAG_data(TAG, OBJECT)
-   Clear all the data associated with OBJECT.  Should be called by the
-   container implementation when a container object is destroyed.
-   
-   - set_TAG_data(TAG, OBJECT, KEY, DATA)
-   Set the data on an object.
-   
-   - TAG_data(TAG, OBJECT, KEY)
-   Fetch the data for an object; returns NULL if it has not been set.
-*/
-
-/* This structure is used in a container to hold the data that the
-   registry uses.  */
-
-struct registry_fields
-{
-  void **data;
-  unsigned num_data;
-};
+template<typename T> class registry;
 
-/* This macro is used in a container struct definition to define the
-   fields used by the registry code.  */
+/* An accessor class that is used by registry_key.
 
-#define REGISTRY_FIELDS				\
-  struct registry_fields registry_data
+   Normally, a container class has a registry<> field named
+   "registry_fields".  In this case, the default accessor is used, as
+   it simply returns the object.
 
-/* A convenience macro for the typical case where the registry data is
-   kept as fields of the object.  This can be passed as the ACCESS
-   method to DEFINE_REGISTRY.  */
+   However, a container may sometimes need to store the registry
+   elsewhere.  In this case, registry_accessor can be specialized to
+   perform the needed indirection.  */
 
-#define REGISTRY_ACCESS_FIELD(CONTAINER) \
-  (CONTAINER)
+template<typename T>
+struct registry_accessor
+{
+  /* Given a container of type T, return its registry.  */
+  static registry<T> *get (T *obj)
+  {
+    return &obj->registry_fields;
+  }
+};
 
-/* Opaque type representing a container type with a registry.  This
-   type is never defined.  This is used to factor out common
-   functionality of all struct tag names into common code.  IOW,
-   "struct tag name" pointers are cast to and from "struct
-   registry_container" pointers when calling the common registry
-   "backend" functions.  */
-struct registry_container;
+/* In gdb, sometimes there is a need for one module (e.g., the Python
+   Type code) to attach some data to another object (e.g., an
+   objfile); but it's also desirable that this be done such that the
+   base object (the objfile in this example) not need to know anything
+   about the attaching module (the Python code).
 
-/* Registry callbacks have this type.  */
-typedef void (*registry_data_callback) (struct registry_container *, void *);
+   This is handled using the registry system.
 
-struct registry_data
-{
-  unsigned index;
-  registry_data_callback save;
-  registry_data_callback free;
-};
+   A class needing to allow this sort registration can add a registry
+   field.  For example, you would write:
 
-struct registry_data_registration
-{
-  struct registry_data *data;
-  struct registry_data_registration *next;
-};
+   class some_container { registry<some_container> registry_fields; };
 
-struct registry_data_registry
-{
-  struct registry_data_registration *registrations;
-  unsigned num_registrations;
-};
+   The name of the field matters by default, see registry_accessor.
+
+   A module wanting to attach data to instances of some_container uses
+   the "key" class to register a key.  This key can then be passed to
+   the "get" and "set" methods to handle this module's data.  */
 
-/* Registry backend functions.  Client code uses the frontend
-   functions defined by DEFINE_REGISTRY below instead.  */
-
-const struct registry_data *register_data_with_cleanup
-  (struct registry_data_registry *registry,
-   registry_data_callback save,
-   registry_data_callback free);
-
-void registry_alloc_data (struct registry_data_registry *registry,
-			  struct registry_fields *registry_fields);
-
-/* Cast FUNC and CONTAINER to the real types, and call FUNC, also
-   passing DATA.  */
-typedef void (*registry_callback_adaptor) (registry_data_callback func,
-					   struct registry_container *container,
-					   void *data);
-
-void registry_clear_data (struct registry_data_registry *data_registry,
-			  registry_callback_adaptor adaptor,
-			  struct registry_container *container,
-			  struct registry_fields *fields);
-
-void registry_container_free_data (struct registry_data_registry *data_registry,
-				   registry_callback_adaptor adaptor,
-				   struct registry_container *container,
-				   struct registry_fields *fields);
-
-void registry_set_data (struct registry_fields *fields,
-			const struct registry_data *data,
-			void *value);
-
-void *registry_data (struct registry_fields *fields,
-		     const struct registry_data *data);
-
-/* Define a new registry implementation.  */
-
-#define DEFINE_REGISTRY(TAG, ACCESS)					\
-static struct registry_data_registry TAG ## _data_registry = { NULL, 0 }; \
-									\
-const struct TAG ## _data *						\
-register_ ## TAG ## _data_with_cleanup (void (*save) (struct TAG *, void *), \
-					void (*free) (struct TAG *, void *)) \
-{									\
-  return (struct TAG ## _data *)					\
-    register_data_with_cleanup (&TAG ## _data_registry,			\
-				(registry_data_callback) save,		\
-				(registry_data_callback) free);		\
-}									\
-									\
-const struct TAG ## _data *						\
-register_ ## TAG ## _data (void)					\
-{									\
-  return register_ ## TAG ## _data_with_cleanup (NULL, NULL);		\
-}									\
-									\
-static void								\
-TAG ## _alloc_data (struct TAG *container)				\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_alloc_data (&TAG ## _data_registry, rdata);			\
-}									\
-									\
-static void								\
-TAG ## registry_callback_adaptor (registry_data_callback func,		\
-				  struct registry_container *container, \
-				  void *data)				\
-{									\
-  struct TAG *tagged_container = (struct TAG *) container;		\
-									\
-  registry_ ## TAG ## _callback tagged_func				\
-    = (registry_ ## TAG ## _callback) func;				\
-									\
-  tagged_func (tagged_container, data);					\
-}									\
-									\
-void									\
-clear_ ## TAG ## _data (struct TAG *container)				\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_clear_data (&TAG ## _data_registry,				\
-		       TAG ## registry_callback_adaptor,		\
-		       (struct registry_container *) container,		\
-		       rdata);						\
-}									\
-									\
-static void								\
-TAG ## _free_data (struct TAG *container)				\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_container_free_data (&TAG ## _data_registry,			\
-				TAG ## registry_callback_adaptor,	\
-				(struct registry_container *) container, \
-				rdata);					\
-}									\
-									\
-void									\
-set_ ## TAG ## _data (struct TAG *container,				\
-		      const struct TAG ## _data *data,			\
-		      void *value)					\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  registry_set_data (rdata,						\
-		     (struct registry_data *) data,			\
-		     value);						\
-}									\
-									\
-void *									\
-TAG ## _data (struct TAG *container, const struct TAG ## _data *data)	\
-{									\
-  struct registry_fields *rdata = &ACCESS (container)->registry_data;	\
-									\
-  return registry_data (rdata,						\
-			(struct registry_data *) data);			\
-}
-
-
-/* External declarations for the registry functions.  */
-
-#define DECLARE_REGISTRY(TAG)						\
-struct TAG ## _data;							\
-typedef void (*registry_ ## TAG ## _callback) (struct TAG *, void *);	\
-extern const struct TAG ## _data *register_ ## TAG ## _data (void);	\
-extern const struct TAG ## _data *register_ ## TAG ## _data_with_cleanup \
- (registry_ ## TAG ## _callback save, registry_ ## TAG ## _callback free); \
-extern void clear_ ## TAG ## _data (struct TAG *);			\
-extern void set_ ## TAG ## _data (struct TAG *,				\
-				  const struct TAG ## _data *data,	\
-				  void *value);				\
-extern void *TAG ## _data (struct TAG *,				\
-			   const struct TAG ## _data *data);		\
-									\
-template<typename DATA, typename Deleter = std::default_delete<DATA>>	\
-class TAG ## _key							\
-{									\
-public:									\
-									\
-  TAG ## _key ()							\
-    : m_key (register_ ## TAG ## _data_with_cleanup (nullptr,		\
-						     cleanup))		\
-  {									\
-  }									\
-									\
-  DATA *get (struct TAG *obj) const					\
-  {									\
-    return (DATA *) TAG ## _data (obj, m_key);				\
-  }									\
-									\
-  void set (struct TAG *obj, DATA *data) const				\
-  {									\
-    set_ ## TAG ## _data (obj, m_key, data);				\
-  }									\
-									\
-  template<typename Dummy = DATA *, typename... Args>			\
-  typename std::enable_if<std::is_same<Deleter,				\
-				       std::default_delete<DATA>>::value, \
-			  Dummy>::type					\
-  emplace (struct TAG *obj, Args &&...args) const			\
-  {									\
-    DATA *result = new DATA (std::forward<Args> (args)...);		\
-    set (obj, result);							\
-    return result;							\
-  }									\
-									\
-  void clear (struct TAG *obj) const					\
-  {									\
-    DATA *datum = get (obj);						\
-    if (datum != nullptr)						\
-      {									\
-	cleanup (obj, datum);						\
-	set (obj, nullptr);						\
-      }									\
-  }									\
-									\
-private:								\
-									\
-  static void cleanup (struct TAG *obj, void *arg)			\
-  {									\
-    DATA *datum = (DATA *) arg;						\
-    Deleter d;								\
-    d (datum);								\
-  }									\
-									\
-  const struct TAG ## _data *m_key;					\
+template<typename T>
+class registry
+{
+public:
+
+  registry ()
+    : m_fields (get_registrations ().size ())
+  {
+  }
+
+  ~registry ()
+  {
+    clear_registry ();
+  }
+
+  DISABLE_COPY_AND_ASSIGN (registry);
+
+  /* A type-safe registry key.
+
+     The registry itself holds just a "void *".  This is not always
+     convenient to manage, so this template class can be used instead,
+     to provide a type-safe interface, that also helps manage the
+     lifetime of the stored objects.
+
+     When the container is destroyed, this key arranges to destroy the
+     underlying data using Deleter.  This defaults to
+     std::default_delete.  */
+
+  template<typename DATA, typename Deleter = std::default_delete<DATA>>
+  class key
+  {
+  public:
+
+    key ()
+      : m_key (registry<T>::new_key (cleanup))
+    {
+    }
+
+    DISABLE_COPY_AND_ASSIGN (key);
+
+    /* Fetch the data attached to OBJ that is associated with this key.
+       If no such data has been attached, nullptr is returned.  */
+    DATA *get (T *obj) const
+    {
+      registry<T> *reg_obj = registry_accessor<T>::get (obj);
+      return (DATA *) reg_obj->get (m_key);
+    }
+
+    /* Attach DATA to OBJ, associated with this key.  Note that any
+       previous data is simply dropped -- if destruction is needed,
+       'clear' should be called.  */
+    void set (T *obj, DATA *data) const
+    {
+      registry<T> *reg_obj = registry_accessor<T>::get (obj);
+      reg_obj->set (m_key, data);
+    }
+
+    /* If this key uses the default deleter, then this method is
+       available.  It emplaces a new instance of the associated data
+       type and attaches it to OBJ using this key.  The arguments, if
+       any, are forwarded to the constructor.  */
+    template<typename Dummy = DATA *, typename... Args>
+    typename std::enable_if<std::is_same<Deleter,
+					 std::default_delete<DATA>>::value,
+			    Dummy>::type
+    emplace (T *obj, Args &&...args) const
+    {
+      DATA *result = new DATA (std::forward<Args> (args)...);
+      set (obj, result);
+      return result;
+    }
+
+    /* Clear the data attached to OBJ that is associated with this KEY.
+       Any existing data is destroyed using the deleter, and the data is
+       reset to nullptr.  */
+    void clear (T *obj) const
+    {
+      DATA *datum = get (obj);
+      if (datum != nullptr)
+	{
+	  cleanup (datum);
+	  set (obj, nullptr);
+	}
+    }
+
+  private:
+
+    /* A helper function that is called by the registry to delete the
+       contained object.  */
+    static void cleanup (void *arg)
+    {
+      DATA *datum = (DATA *) arg;
+      Deleter d;
+      d (datum);
+    }
+
+    /* The underlying key.  */
+    const typename registry<T>::registry_data *m_key;
+  };
+
+  /* Clear all the data associated with this container.  This is
+     dangerous and should not normally be done.  */
+  void clear_registry ()
+  {
+    /* Call all the free functions.  */
+    for (const auto &datum : get_registrations ())
+      {
+	void *elt = m_fields[datum->index];
+	if (elt != nullptr)
+	  {
+	    datum->free (elt);
+	    m_fields[datum->index] = nullptr;
+	  }
+      }
+  }
+
+private:
+
+  /* Registry callbacks have this type.  */
+  typedef void (*registry_data_callback) (void *);
+
+  /* The type of a key.  */
+  struct registry_data
+  {
+    unsigned index;
+    registry_data_callback free;
+  };
+
+  /* Get a new key for this particular registry.  FREE is a callback.
+     When the container object is destroyed, all FREE functions are
+     called.  The data associated with the container object is passed
+     to the callback.  */
+  static const registry_data *new_key (registry_data_callback free)
+  {
+    std::unique_ptr<registry_data> result (new registry_data);
+    std::vector<std::unique_ptr<registry_data>> &registrations
+      = get_registrations ();
+    result->index = registrations.size ();
+    result->free = free;
+    registrations.emplace_back (std::move (result));
+    return registrations.back ().get ();
+  }
+
+  /* Set the datum associated with KEY in this container.  */
+  void set (const registry_data *key, void *datum)
+  {
+    m_fields[key->index] = datum;
+  }
+
+  /* Fetch the datum associated with KEY in this container.  If 'set'
+     has not been called for this key, nullptr is returned.  */
+  void *get (const registry_data *key)
+  {
+    return m_fields[key->index];
+  }
+
+  /* The data stored in this instance.  */
+  std::vector<void *> m_fields;
+
+  /* Return a reference to the vector of all the registrations that
+     have been made.  We do separate allocations here so that the
+     addresses are stable and can be used as keys.  */
+  static std::vector<std::unique_ptr<registry_data>> &get_registrations ()
+  {
+    static std::vector<std::unique_ptr<registry_data>> registrations;
+    return registrations;
+  }
 };
 
 #endif /* REGISTRY_H */
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 4b8afd27688..01f88fc9da2 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -178,7 +178,7 @@ private:
 
 static struct gdbsim_target gdbsim_ops;
 
-static inferior_key<sim_inferior_data> sim_inferior_data_key;
+static const registry<inferior>::key<sim_inferior_data> sim_inferior_data_key;
 
 /* Flag indicating the "open" status of this module.  It's set to 1
    in gdbsim_open() and 0 in gdbsim_close().  */
diff --git a/gdb/remote.c b/gdb/remote.c
index f91973458ea..39d0a794a21 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1033,7 +1033,7 @@ is_remote_target (process_stratum_target *target)
 }
 
 /* Per-program-space data key.  */
-static const struct program_space_key<char, gdb::xfree_deleter<char>>
+static const registry<program_space>::key<char, gdb::xfree_deleter<char>>
   remote_pspace_data;
 
 /* The variable registered as the control variable used by the
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 640459f1c28..1be3e4d61cd 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -155,7 +155,7 @@ static const char *powerpc_vector_abi_string = "auto";
 
 /* PowerPC-related per-inferior data.  */
 
-static inferior_key<ppc_inferior_data> ppc_inferior_data_key;
+static registry<inferior>::key<ppc_inferior_data> ppc_inferior_data_key;
 
 /* Get the per-inferior PowerPC data for INF.  */
 
diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
index 3a8debf2c5a..33b15a9d8ad 100644
--- a/gdb/solib-aix.c
+++ b/gdb/solib-aix.c
@@ -80,7 +80,8 @@ struct solib_aix_inferior_data
 };
 
 /* Key to our per-inferior data.  */
-static inferior_key<solib_aix_inferior_data> solib_aix_inferior_data_handle;
+static const registry<inferior>::key<solib_aix_inferior_data>
+  solib_aix_inferior_data_handle;
 
 /* Return this module's data for the given inferior.
    If none is found, add a zero'ed one now.  */
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index d7789f68dfe..e61ec0d4bf3 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -80,7 +80,8 @@ struct darwin_info
 };
 
 /* Per-program-space data key.  */
-static program_space_key<darwin_info> solib_darwin_pspace_data;
+static const registry<program_space>::key<darwin_info>
+  solib_darwin_pspace_data;
 
 /* Get the current darwin data.  If none is found yet, add it now.  This
    function always returns a valid object.  */
diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
index 6af47217261..b4cd16327a6 100644
--- a/gdb/solib-dsbt.c
+++ b/gdb/solib-dsbt.c
@@ -164,7 +164,7 @@ struct dsbt_info
 };
 
 /* Per-program-space data key.  */
-static program_space_key<dsbt_info> solib_dsbt_pspace_data;
+static const registry<program_space>::key<dsbt_info> solib_dsbt_pspace_data;
 
 /* Get the current dsbt data.  If none is found yet, add it now.  This
    function always returns a valid object.  */
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 5c046d3fab5..f9a43e23969 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -365,7 +365,7 @@ struct svr4_info
 };
 
 /* Per-program-space data key.  */
-static const struct program_space_key<svr4_info> solib_svr4_pspace_data;
+static const registry<program_space>::key<svr4_info> solib_svr4_pspace_data;
 
 /* Free the probes table.  */
 
diff --git a/gdb/solib.c b/gdb/solib.c
index 7d4734b0012..b9ddd049b00 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -529,7 +529,8 @@ typedef std::unordered_map<std::string, std::string> soname_build_id_map;
 
 /* Key used to associate a soname_build_id_map to a core file bfd.  */
 
-static const struct bfd_key<soname_build_id_map> cbfd_soname_build_id_data_key;
+static const struct registry<bfd>::key<soname_build_id_map>
+     cbfd_soname_build_id_data_key;
 
 /* See solib.h.  */
 
diff --git a/gdb/source.c b/gdb/source.c
index 8691113c729..425b02fc3a0 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -115,7 +115,8 @@ private:
   int m_line = 0;
 };
 
-static program_space_key<current_source_location> current_source_key;
+static const registry<program_space>::key<current_source_location>
+     current_source_key;
 
 /* Default number of lines to print with commands like "list".
    This is based on guessing how many long (i.e. more than chars_per_line
diff --git a/gdb/stabsread.c b/gdb/stabsread.c
index ab74cee6487..cd6e6a92f85 100644
--- a/gdb/stabsread.c
+++ b/gdb/stabsread.c
@@ -2016,8 +2016,8 @@ again:
 /* RS/6000 xlc/dbx combination uses a set of builtin types, starting from -1.
    Return the proper type node for a given builtin type number.  */
 
-static const struct objfile_key<struct type *,
-				gdb::noop_deleter<struct type *>>
+static const registry<objfile>::key<struct type *,
+				    gdb::noop_deleter<struct type *>>
   rs6000_builtin_type_data;
 
 static struct type *
diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
index 2af04433444..59726290011 100644
--- a/gdb/symfile-debug.c
+++ b/gdb/symfile-debug.c
@@ -47,7 +47,7 @@ struct debug_sym_fns_data
 
 /* We need to record a pointer to the real set of functions for each
    objfile.  */
-static const struct objfile_key<debug_sym_fns_data>
+static const registry<objfile>::key<debug_sym_fns_data>
   symfile_debug_objfile_data_key;
 
 /* If true all calls to the symfile functions are logged.  */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 6f546f5b059..ec3244269b1 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -2500,7 +2500,7 @@ reread_symbols (int from_tty)
 	      (*objfile->sf->sym_finish) (objfile);
 	    }
 
-	  clear_objfile_data (objfile);
+	  objfile->registry_fields.clear_registry ();
 
 	  /* Clean up any state BFD has sitting around.  */
 	  {
@@ -2638,7 +2638,7 @@ reread_symbols (int from_tty)
     {
       clear_symtab_users (0);
 
-      /* clear_objfile_data for each objfile was called before freeing it and
+      /* The registry for each objfile was cleared and
 	 gdb::observers::new_objfile.notify (NULL) has been called by
 	 clear_symtab_users above.  Notify the new files now.  */
       for (auto iter : new_objfiles)
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 03aa2a96b87..40887f59d1f 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -121,7 +121,7 @@ struct main_info
 
 /* Program space key for finding name and language of "main".  */
 
-static const program_space_key<main_info> main_progspace_key;
+static const registry<program_space>::key<main_info> main_progspace_key;
 
 /* The default symbol cache size.
    There is no extra cpu cost for large N (except when flushing the cache,
@@ -251,7 +251,7 @@ struct symbol_cache
 
 /* Program space key for finding its symbol cache.  */
 
-static const program_space_key<symbol_cache> symbol_cache_key;
+static const registry<program_space>::key<symbol_cache> symbol_cache_key;
 
 /* When non-zero, print debugging messages related to symtab creation.  */
 unsigned int symtab_create_debug = 0;
diff --git a/gdb/target-dcache.c b/gdb/target-dcache.c
index 0aa53302cea..3e3c0c6ee4d 100644
--- a/gdb/target-dcache.c
+++ b/gdb/target-dcache.c
@@ -24,7 +24,7 @@
 /* The target dcache is kept per-address-space.  This key lets us
    associate the cache with the address space.  */
 
-static const struct address_space_key<DCACHE, dcache_deleter>
+static const registry<address_space>::key<DCACHE, dcache_deleter>
   target_dcache_aspace_key;
 
 /* Target dcache is initialized or not.  */
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 9e571d0419c..bcb667b29e7 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -147,7 +147,7 @@ struct xcoff_symfile_info
 
 /* Key for XCOFF-associated data.  */
 
-static const struct objfile_key<xcoff_symfile_info> xcoff_objfile_data_key;
+static const registry<objfile>::key<xcoff_symfile_info> xcoff_objfile_data_key;
 
 /* Convenience macro to access the per-objfile XCOFF data.  */


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-07-28 20:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-28 20:44 [binutils-gdb] Rewrite registry.h Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).