aboutsummaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2020-07-07 15:00:30 +0100
committerAndrew Burgess <andrew.burgess@embecosm.com>2020-07-21 21:57:08 +0100
commitf7306dac19c502232f766c3881313857915f330d (patch)
treebbad3df7c454ff4eecb1064dfdb00d8e7fb3a778 /gdb/python
parent05c309a8aeb8060fdcb9a05bbcdca2f5f1be61d7 (diff)
downloadfsf-binutils-gdb-f7306dac19c502232f766c3881313857915f330d.zip
fsf-binutils-gdb-f7306dac19c502232f766c3881313857915f330d.tar.gz
fsf-binutils-gdb-f7306dac19c502232f766c3881313857915f330d.tar.bz2
gdb/python: Reuse gdb.RegisterDescriptor objects where possible
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.
Diffstat (limited to 'gdb/python')
-rw-r--r--gdb/python/py-registers.c61
1 files changed, 48 insertions, 13 deletions
diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c
index db0fe37..8e22a919 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,17 @@ typedef struct {
extern PyTypeObject reggroup_object_type
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("reggroup_object");
+/* Associates a vector of gdb.RegisterDescriptor objects 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<gdbpy_ref<>> *vec = new (std::vector<gdbpy_ref<>>);
+ return (void *) vec;
+}
+
/* Create a new gdb.RegisterGroup object wrapping REGGROUP. */
static PyObject *
@@ -117,20 +131,38 @@ gdbpy_reggroup_name (PyObject *self, void *closure)
return gdbpy_reggroup_to_string (self);
}
-/* Create an return a new gdb.RegisterDescriptor object. */
-static PyObject *
-gdbpy_new_register_descriptor (struct gdbarch *gdbarch,
+/* 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 gdbpy_ref<>
+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;
+ auto vec = (std::vector<gdbpy_ref<>> *) 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)
+ {
+ gdbpy_ref <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) = gdbpy_ref<> ((PyObject *) reg.release ());
+ }
+
+ /* Grab the register descriptor from the vector, the reference count is
+ automatically incremented thanks to gdbpy_ref. */
+ return vec->at (regnum);
}
/* Convert the register descriptor to a string. */
@@ -281,7 +313,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).release ();
}
while (true);
}
@@ -291,6 +323,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;