From d63f19b6307ff2a8eb88b5eea61fb90f9546696f Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 5 Mar 2026 17:02:31 +0000 Subject: [PATCH 1/2] gh-145566: Skip stop-the-world when reassigning `__class__` on newly created objects --- .../2026-03-05-19-10-56.gh-issue-145566.H4RupyYN.rst | 2 ++ Objects/typeobject.c | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-19-10-56.gh-issue-145566.H4RupyYN.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-19-10-56.gh-issue-145566.H4RupyYN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-19-10-56.gh-issue-145566.H4RupyYN.rst new file mode 100644 index 00000000000000..723b81ddc5f897 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-05-19-10-56.gh-issue-145566.H4RupyYN.rst @@ -0,0 +1,2 @@ +In the free threading build, skip the stop-the-world pause when reassigning +``__class__`` on a newly created object. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1fdd3cbdaaa639..ad389346198be2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7608,10 +7608,15 @@ object_set_class(PyObject *self, PyObject *value, void *closure) return -1; } - types_stop_world(); + int unique = _PyObject_IsUniquelyReferenced(self); + if (!unique) { + types_stop_world(); + } PyTypeObject *oldto = Py_TYPE(self); int res = object_set_class_world_stopped(self, newto); - types_start_world(); + if (!unique) { + types_start_world(); + } if (res == 0) { if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) { Py_DECREF(oldto); From d1012c3c7112c7dfff26b7fdb637130306ef80fd Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 5 Mar 2026 15:01:38 -0500 Subject: [PATCH 2/2] Lock the dict if we're not in a stop-the-world event --- Objects/typeobject.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ad389346198be2..27ec8bb40a929f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7568,7 +7568,11 @@ object_set_class_world_stopped(PyObject *self, PyTypeObject *newto) assert(_PyObject_GetManagedDict(self) == dict); - if (_PyDict_DetachFromObject(dict, self) < 0) { + int err; + Py_BEGIN_CRITICAL_SECTION(dict); + err = _PyDict_DetachFromObject(dict, self); + Py_END_CRITICAL_SECTION(); + if (err < 0) { return -1; }