Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Jan Vrany <jan.vrany@labware.com>
To: gdb-patches@sourceware.org
Cc: Jan Vrany <jan.vrany@labware.com>
Subject: [RFC 4/9] gdb/python: preserve identity for gdb.Type objects
Date: Mon, 27 Jan 2025 10:44:30 +0000	[thread overview]
Message-ID: <20250127104435.823519-5-jan.vrany@labware.com> (raw)
In-Reply-To: <20250127104435.823519-1-jan.vrany@labware.com>

This commit changes type_to_type_object() so that each it is called
with a particular struct type * it returns the very same gdb.Type
object.

This is done in the same way as for gdb.Symtab objects in earlier commit
("gdb/python: preserve identity for gdb.Symtab objects") except that
types may be either objfile-owned or arch-owned.

Prior this commit, arch-owned objects we not put into any list (like
objfile-owned ones) so they could not be easily looked up. This commit
changes the code so arch-owned list are put into per-architecture list
which is then used (solely) for looking up arch-owned gdb.Type.

Another complication comes from the fact that when objfile is about to
be freed, associated gdb.Type instances are not merely invalidated
(like it is done with gdb.Symtab or gdb.Symbol objects) but instead the
type is copied and the copy is arch-owned. So we need two different
"deleters", one for objfile-owned types that copies the type (as before)
and then insert the object to per-architecture list and another one
for arch-owned types.
---
 gdb/python/py-type.c                 | 104 ++++++++++++++++++++++-----
 gdb/testsuite/gdb.python/py-arch.exp |   5 ++
 gdb/testsuite/gdb.python/py-type.exp |  15 ++++
 3 files changed, 105 insertions(+), 19 deletions(-)

diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 11a96d52c2e..c9fa6a37250 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -1162,8 +1162,12 @@ typy_richcompare (PyObject *self, PyObject *other, int op)
 
 \f
 
+/* Forward declaration, see below.  */
+static void
+set_type (type_object *obj, struct type *type);
+
 /* Deleter that saves types when an objfile is being destroyed.  */
-struct typy_deleter
+struct typy_deleter_for_objfile_owned
 {
   void operator() (type_object *obj)
   {
@@ -1181,35 +1185,74 @@ struct typy_deleter
 	type_object *next = obj->next;
 
 	copied_types.clear ();
-	obj->type = copy_type_recursive (obj->type, copied_types);
 
-	obj->next = NULL;
-	obj->prev = NULL;
+	/* Set a copied (now arch-owned) type.  As a side-effect this
+	   adds OBJ to per-arch list.  We do not need to remove it from
+	   per-objfile list since the objfile is going to go completely
+	   anyway.  */
+	set_type (obj, copy_type_recursive (obj->type, copied_types));
 
 	obj = next;
       }
   }
 };
 
-static const registry<objfile>::key<type_object, typy_deleter>
+/* Deleter that is used when an arch is is about to be freed.  */
+struct typy_deleter_for_arch_owned
+{
+  void operator() (type_object *obj)
+  {
+    while (obj)
+      {
+	type_object *next = obj->next;
+
+	obj->type = nullptr;
+
+	obj->next = nullptr;
+	obj->prev = nullptr;
+
+	obj = next;
+      }
+  }
+};
+
+
+
+static const registry<objfile>::key<type_object, typy_deleter_for_objfile_owned>
      typy_objfile_data_key;
+static const registry<gdbarch>::key<type_object, typy_deleter_for_arch_owned>
+     typy_gdbarch_data_key;
 
 static void
 set_type (type_object *obj, struct type *type)
 {
   obj->type = type;
-  obj->prev = NULL;
-  if (type != nullptr && type->objfile_owner () != nullptr)
+  obj->prev = nullptr;
+
+  /* Can it really happen that type is NULL?  */
+  if (type != nullptr)
     {
-      struct objfile *objfile = type->objfile_owner ();
+      if (type->objfile_owner () != nullptr)
+	{
+	  struct objfile *objfile = type->objfile_owner ();
+
+	  obj->next = typy_objfile_data_key.get (objfile);
+	  if (obj->next)
+	    obj->next->prev = obj;
+	  typy_objfile_data_key.set (objfile, obj);
+	}
+      else
+	{
+	  struct gdbarch *arch = type->arch_owner ();
 
-      obj->next = typy_objfile_data_key.get (objfile);
-      if (obj->next)
-	obj->next->prev = obj;
-      typy_objfile_data_key.set (objfile, obj);
+	  obj->next = typy_gdbarch_data_key.get (arch);
+	  if (obj->next)
+	    obj->next->prev = obj;
+	  typy_gdbarch_data_key.set (arch, obj);
+	}
     }
   else
-    obj->next = NULL;
+    obj->next = nullptr;
 }
 
 static void
@@ -1219,13 +1262,19 @@ typy_dealloc (PyObject *obj)
 
   if (type->prev)
     type->prev->next = type->next;
-  else if (type->type != nullptr && type->type->objfile_owner () != nullptr)
+  else if (type->type != nullptr)
     {
-      /* Must reset head of list.  */
-      struct objfile *objfile = type->type->objfile_owner ();
-
-      if (objfile)
-	typy_objfile_data_key.set (objfile, type->next);
+      if (type->type->is_objfile_owned ())
+	{
+	  /* Must reset head of list.  */
+	  struct objfile *objfile = type->type->objfile_owner ();
+	  typy_objfile_data_key.set (objfile, type->next);
+	}
+      else
+	{
+	  struct gdbarch *arch = type->type->arch_owner ();
+	  typy_gdbarch_data_key.set (arch, type->next);
+	}
     }
   if (type->next)
     type->next->prev = type->prev;
@@ -1473,6 +1522,23 @@ type_to_type_object (struct type *type)
       return gdbpy_handle_gdb_exception (nullptr, except);
     }
 
+  /* Look if there's already a gdb.Type object for given TYPE
+     and if so, return it.  */
+  if (type->is_objfile_owned ())
+    type_obj = typy_objfile_data_key.get (type->objfile_owner ());
+  else
+    type_obj = typy_gdbarch_data_key.get (type->arch_owner ());
+
+  while (type_obj != nullptr)
+    {
+      if (type_obj->type == type)
+	{
+	  Py_INCREF (type_obj);
+	  return (PyObject*)type_obj;
+	}
+      type_obj = type_obj->next;
+    }
+
   type_obj = PyObject_New (type_object, &type_object_type);
   if (type_obj)
     set_type (type_obj, type);
diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp
index 14802ec80a3..aefb9e90eac 100644
--- a/gdb/testsuite/gdb.python/py-arch.exp
+++ b/gdb/testsuite/gdb.python/py-arch.exp
@@ -104,6 +104,11 @@ foreach_with_prefix test_data { {None None} \
 	"check 'signed' argument can handle non-bool type $bad_type"
 }
 
+# Test type identity
+gdb_test "python print(arch.integer_type(32) is arch.integer_type(32))" \
+    "True" \
+    "arch.integer_type(32) always return the same Python object"
+
 # Test for gdb.architecture_names().  First we're going to grab the
 # complete list of architecture names using the 'complete' command.
 set arch_names []
diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp
index 7e469c93c35..c9d4353e488 100644
--- a/gdb/testsuite/gdb.python/py-type.exp
+++ b/gdb/testsuite/gdb.python/py-type.exp
@@ -324,6 +324,19 @@ proc test_type_equality {} {
     }
 }
 
+# Test type identity
+proc test_type_identity {} {
+    gdb_test_no_output "python v1 = gdb.parse_and_eval('global_unsigned_int')"
+    gdb_test_no_output "python v2 = gdb.parse_and_eval('global_unsigned_int')"
+
+    gdb_test "python print(v1.type is v2.type)" "True"
+
+    gdb_test_no_output "python t1 = gdb.lookup_type ('char')"
+    gdb_test_no_output "python t2 = gdb.lookup_type ('char')"
+
+    gdb_test "python print(t1 is t2)" "True"
+}
+
 # Test the gdb.Type.is_scalar property.
 proc test_is_scalar { lang } {
     if {$lang == "c++"} {
@@ -376,6 +389,7 @@ if { [build_inferior "${binfile}" "c"] == 0 } {
       test_is_scalar "c"
       test_is_signed "c"
       test_type_equality
+      test_type_identity
   }
 }
 
@@ -392,6 +406,7 @@ if { [build_inferior "${binfile}-cxx" "c++"] == 0 } {
       test_is_scalar "c++"
       test_is_signed "c++"
       test_type_equality
+      test_type_identity
   }
 }
 
-- 
2.45.2


  parent reply	other threads:[~2025-01-27 10:47 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-27 10:44 [RFC 0/9] Attempt to unify Python object's lifecycle Jan Vrany
2025-01-27 10:44 ` [RFC 1/9] gdb/python: preserve identity for gdb.Symtab objects Jan Vrany
2025-01-27 10:44 ` [RFC 2/9] gdb/python: preserve identity for gdb.Symbol objects Jan Vrany
2025-02-20 19:22   ` Tom Tromey
2025-01-27 10:44 ` [RFC 3/9] gdb/python: do not hold on gdb.Symtab object from gdb.Symtab_and_line Jan Vrany
2025-01-27 10:44 ` Jan Vrany [this message]
2025-01-27 10:44 ` [RFC 5/9] gdb/python: introduce gdbpy_registry Jan Vrany
2025-02-20 19:28   ` Tom Tromey
2025-01-27 10:44 ` [RFC 6/9] gdb/python: convert gdb.Symbol to use gdbpy_registry Jan Vrany
2025-01-27 10:44 ` [RFC 7/9] gdb/python: convert gdb.Type " Jan Vrany
2025-01-27 10:44 ` [RFC 8/9] gdb/python: convert gdb.Symtab " Jan Vrany
2025-01-27 10:44 ` [RFC 9/9] gdb/python: convert gdb.Symtab_and_line " Jan Vrany
2025-02-18 11:15 ` [PING] Re: [RFC 0/9] Attempt to unify Python object's lifecycle Jan Vraný
2025-02-19 21:00 ` Simon Marchi
2025-02-20 17:50   ` Jan Vraný
2025-02-20 19:18 ` Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250127104435.823519-5-jan.vrany@labware.com \
    --to=jan.vrany@labware.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox