[PATCH 1/2] gdb/python: Reuse gdb.RegisterDescriptor objects where possible

Andrew Burgess andrew.burgess@embecosm.com
Wed Jul 8 08:48:11 GMT 2020


Instead of having the gdb.RegisterDescriptorIterator creating new
gdb.RegisterDescriptor objects for each regnum, instead cache
gdb.RegisterDescriptor objects on the gdbarch object and reuse these.

This means that for every gdbarch/regnum pair there is a single unique
gdb.RegisterDescriptor, this feels like a neater implementation than
the existing one.

It is possible for a user to see (in Python code) that the descriptors
are now identical, but as the descriptors are read-only this should
make no real difference.

There should be no other user visible changes.

gdb/ChangeLog:

	* python/py-registers.c (gdbpy_register_object_data): New static
	global.
	(gdbpy_register_object_data_init): New function.
	(gdbpy_new_register_descriptor): Renamed to...
	(gdbpy_get_register_descriptor): ...this, and update to reuse
	existing register descriptors where possible.
	(gdbpy_register_descriptor_iter_next): Update.
	(gdbpy_initialize_registers): Register new gdbarch data.

gdb/testsuite/ChangeLog:

	* gdb.python/py-arch-reg-names.exp: Additional tests.
---
 gdb/ChangeLog                                 | 11 ++++
 gdb/python/py-registers.c                     | 63 +++++++++++++++----
 gdb/testsuite/ChangeLog                       |  4 ++
 .../gdb.python/py-arch-reg-names.exp          | 19 ++++++
 4 files changed, 85 insertions(+), 12 deletions(-)

diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c
index db0fe37eecb..fec84e5d5d4 100644
--- a/gdb/python/py-registers.c
+++ b/gdb/python/py-registers.c
@@ -24,6 +24,9 @@
 #include "reggroups.h"
 #include "python-internal.h"
 
+/* Token to access per-gdbarch data related to register descriptors.  */
+static struct gdbarch_data *gdbpy_register_object_data = NULL;
+
 /* Structure for iterator over register descriptors.  */
 typedef struct {
   PyObject_HEAD
@@ -81,6 +84,18 @@ typedef struct {
 extern PyTypeObject reggroup_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("reggroup_object");
 
+/* Associates a vector of register_descriptor_object pointers with GDBARCH
+   as gdbarch_data via the gdbarch post init registration mechanism
+   (gdbarch_data_register_post_init).  */
+
+static void *
+gdbpy_register_object_data_init (struct gdbarch *gdbarch)
+{
+  std::vector<const register_descriptor_object *> *vec
+    = new (std::vector<const register_descriptor_object *>);
+  return (void *) vec;
+}
+
 /* Create a new gdb.RegisterGroup object wrapping REGGROUP.  */
 
 static PyObject *
@@ -117,20 +132,41 @@ gdbpy_reggroup_name (PyObject *self, void *closure)
   return gdbpy_reggroup_to_string (self);
 }
 
-/* Create an return a new gdb.RegisterDescriptor object.  */
+/* Return a gdb.RegisterDescriptor object for REGNUM from GDBARCH.  For
+   each REGNUM (in GDBARCH) only one descriptor is ever created, which is
+   then cached on the GDBARCH.  */
+
 static PyObject *
-gdbpy_new_register_descriptor (struct gdbarch *gdbarch,
+gdbpy_get_register_descriptor (struct gdbarch *gdbarch,
 			       int regnum)
 {
-  /* Create a new object and fill in its details.  */
-  register_descriptor_object *reg
-    = PyObject_New (register_descriptor_object,
-		    &register_descriptor_object_type);
-  if (reg == NULL)
-    return NULL;
-  reg->regnum = regnum;
-  reg->gdbarch = gdbarch;
-  return (PyObject *) reg;
+  std::vector<const register_descriptor_object *> *vec
+    = (std::vector<const register_descriptor_object *> *) gdbarch_data
+    (gdbarch, gdbpy_register_object_data);
+
+  /* Ensure that we have enough entries in the vector.  */
+  if (vec->size () <= regnum)
+    vec->resize ((regnum + 1), nullptr);
+
+  /* If we don't already have a descriptor for REGNUM in GDBARCH then
+     create one now.  */
+  if (vec->at (regnum) == nullptr)
+    {
+      register_descriptor_object *reg
+	= PyObject_New (register_descriptor_object,
+			&register_descriptor_object_type);
+      if (reg == NULL)
+	return NULL;
+      reg->regnum = regnum;
+      reg->gdbarch = gdbarch;
+      vec->at (regnum) = reg;
+    }
+
+  /* Grab the register descriptor from the vector and increment its
+     reference count before returning it.  */
+  PyObject *obj = (PyObject *) vec->at (regnum);
+  Py_XINCREF (obj);
+  return obj;
 }
 
 /* Convert the register descriptor to a string.  */
@@ -281,7 +317,7 @@ gdbpy_register_descriptor_iter_next (PyObject *self)
       iter_obj->regnum++;
 
       if (name != nullptr && *name != '\0')
-	return gdbpy_new_register_descriptor (gdbarch, regnum);
+	return gdbpy_get_register_descriptor (gdbarch, regnum);
     }
   while (true);
 }
@@ -291,6 +327,9 @@ gdbpy_register_descriptor_iter_next (PyObject *self)
 int
 gdbpy_initialize_registers ()
 {
+  gdbpy_register_object_data
+    = gdbarch_data_register_post_init (gdbpy_register_object_data_init);
+
   register_descriptor_object_type.tp_new = PyType_GenericNew;
   if (PyType_Ready (&register_descriptor_object_type) < 0)
     return -1;
diff --git a/gdb/testsuite/gdb.python/py-arch-reg-names.exp b/gdb/testsuite/gdb.python/py-arch-reg-names.exp
index 14bc0a822a4..8dd34ef5fd2 100644
--- a/gdb/testsuite/gdb.python/py-arch-reg-names.exp
+++ b/gdb/testsuite/gdb.python/py-arch-reg-names.exp
@@ -85,3 +85,22 @@ for { set i 0 } { $i < [llength $regs] } { incr i } {
     }
 }
 gdb_assert { $found_non_match == 0 } "all registers match"
+
+# Check that we get the same register descriptors from two different
+# iterators.
+gdb_py_test_silent_cmd \
+    "python iter1 = arch.registers ()" \
+    "get first all register iterator" 0
+gdb_py_test_silent_cmd \
+    "python iter2 = arch.registers ()" \
+    "get second all register iterator" 0
+gdb_py_test_silent_cmd \
+    [multi_line_input \
+	 "python" \
+	 "for r1, r2 in zip(iter1, iter2):" \
+	 "  if (r1.name != r2.name):"\
+	 "    raise gdb.GdbError (\"miss-matched names\")" \
+	 "  if (r1 != r2):" \
+	 "    raise gdb.GdbError (\"miss-matched objects\")" \
+	 "\004" ] \
+    "check names and objects match" 1
-- 
2.25.4



More information about the Gdb-patches mailing list