+2020-07-21 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * 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.
+
2020-07-21 Simon Marchi <simon.marchi@efficios.com>
* linux-nat.c (stopped_pids): Make static.
#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
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 *
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,
- ®ister_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,
+ ®ister_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. */
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);
}
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 (®ister_descriptor_object_type) < 0)
return -1;
}
}
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