From: Andrew Burgess Date: Tue, 7 Jul 2020 14:26:42 +0000 (+0100) Subject: gdb/python: Reuse gdb.RegisterGroup objects where possible X-Git-Tag: gdb-10.1-release~718 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=baf8791efb4b5cb41348b11ad9f63e6c2a004c5f;p=thirdparty%2Fbinutils-gdb.git gdb/python: Reuse gdb.RegisterGroup objects where possible Only create one gdb.RegisterGroup Python object for each of GDB's reggroup objects. I could have added a field into the reggroup object to hold the Python object pointer for each reggroup, however, as reggroups are never deleted within GDB, and are global (not per-architecture) a simpler solution seemed to be just to hold a single global map from reggroup pointer to a Python object representing the reggroup. Then we can reuse the objects out of this map. After this commit it is possible for a user to tell that two gdb.RegisterGroup objects are now identical when previously they were unique, however, as both these objects are read-only I don't think this should be a problem. There should be no other user visible changes after this commit. gdb/ChangeLog: * python/py-registers.c : Add 'unordered_map' include. (gdbpy_new_reggroup): Renamed to... (gdbpy_get_reggroup): ...this. Update to only create register group descriptors when needed. (gdbpy_reggroup_iter_next): Update. gdb/testsuite/ChangeLog: * gdb.python/py-arch-reg-groups.exp: Additional tests. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e2d2e15b653..31307e6ff2b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2020-07-21 Andrew Burgess + + * python/py-registers.c : Add 'unordered_map' include. + (gdbpy_new_reggroup): Renamed to... + (gdbpy_get_reggroup): ...this. Update to only create register + group descriptors when needed. + (gdbpy_reggroup_iter_next): Update. + 2020-07-21 Andrew Burgess * python/py-registers.c (gdbpy_register_object_data): New static diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c index 8e22a919d87..9396498cc34 100644 --- a/gdb/python/py-registers.c +++ b/gdb/python/py-registers.c @@ -23,6 +23,7 @@ #include "disasm.h" #include "reggroups.h" #include "python-internal.h" +#include /* Token to access per-gdbarch data related to register descriptors. */ static struct gdbarch_data *gdbpy_register_object_data = NULL; @@ -95,18 +96,36 @@ gdbpy_register_object_data_init (struct gdbarch *gdbarch) return (void *) vec; } -/* Create a new gdb.RegisterGroup object wrapping REGGROUP. */ +/* Return a gdb.RegisterGroup object wrapping REGGROUP. The register + group objects are cached, and the same Python object will always be + returned for the same REGGROUP pointer. */ -static PyObject * -gdbpy_new_reggroup (struct reggroup *reggroup) +static gdbpy_ref<> +gdbpy_get_reggroup (struct reggroup *reggroup) { - /* Create a new object and fill in its details. */ - reggroup_object *group - = PyObject_New (reggroup_object, ®group_object_type); - if (group == NULL) - return NULL; - group->reggroup = reggroup; - return (PyObject *) group; + /* Map from GDB's internal reggroup objects to the Python representation. + GDB's reggroups are global, and are never deleted, so using a map like + this is safe. */ + static std::unordered_map> + gdbpy_reggroup_object_map; + + /* If there is not already a suitable Python object in the map then + create a new one, and add it to the map. */ + if (gdbpy_reggroup_object_map[reggroup] == nullptr) + { + /* Create a new object and fill in its details. */ + gdbpy_ref group + (PyObject_New (reggroup_object, ®group_object_type)); + if (group == NULL) + return NULL; + group->reggroup = reggroup; + gdbpy_reggroup_object_map[reggroup] + = gdbpy_ref<> ((PyObject *) group.release ()); + } + + /* Fetch the Python object wrapping REGGROUP from the map, increasing + the reference count is handled by the gdbpy_ref class. */ + return gdbpy_reggroup_object_map[reggroup]; } /* Convert a gdb.RegisterGroup to a string, it just returns the name of @@ -215,7 +234,7 @@ gdbpy_reggroup_iter_next (PyObject *self) } iter_obj->reggroup = next_group; - return gdbpy_new_reggroup (iter_obj->reggroup); + return gdbpy_get_reggroup (iter_obj->reggroup).release (); } /* Return a new gdb.RegisterGroupsIterator over all the register groups in diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 6b13e928497..1f0861e706a 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2020-07-21 Andrew Burgess + + * gdb.python/py-arch-reg-groups.exp: Additional tests. + 2020-07-21 Andrew Burgess * gdb.python/py-arch-reg-names.exp: Additional tests. diff --git a/gdb/testsuite/gdb.python/py-arch-reg-groups.exp b/gdb/testsuite/gdb.python/py-arch-reg-groups.exp index ea9aa77b0fa..093de2e7390 100644 --- a/gdb/testsuite/gdb.python/py-arch-reg-groups.exp +++ b/gdb/testsuite/gdb.python/py-arch-reg-groups.exp @@ -85,3 +85,22 @@ for { set i 0 } { $i < [llength $groups] } { incr i } { } } gdb_assert { $found_non_match == 0 } "all register groups match" + +# Check that we get the same register group descriptors from two +# different iterators. +gdb_py_test_silent_cmd \ + "python iter1 = arch.register_groups ()" \ + "get first all register group iterator" 0 +gdb_py_test_silent_cmd \ + "python iter2 = arch.register_groups ()" \ + "get second all register group 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