Skip to content

Commit 83193b5

Browse files
fix scaling of descriptors on free-threading
1 parent 29917d5 commit 83193b5

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

Objects/typeobject.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6289,6 +6289,10 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
62896289

62906290
PyObject *res_obj = PyStackRef_AsPyObjectBorrow(*out);
62916291
#if Py_GIL_DISABLED
6292+
// Optimistically enable deferred refcounting for the result if it's not already enabled.
6293+
if (res_obj != NULL && PyType_IS_GC(Py_TYPE(res_obj)) && !_PyObject_HasDeferredRefcount(res_obj)) {
6294+
PyUnstable_Object_EnableDeferredRefcount(res_obj);
6295+
}
62926296
update_cache_gil_disabled(entry, name, version_tag, res_obj);
62936297
#else
62946298
PyObject *old_value = update_cache(entry, name, version_tag, res_obj);
@@ -10995,10 +10999,12 @@ static PyObject *
1099510999
slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1099611000
{
1099711001
PyTypeObject *tp = Py_TYPE(self);
10998-
PyObject *get;
10999-
11000-
get = _PyType_LookupRef(tp, &_Py_ID(__get__));
11001-
if (get == NULL) {
11002+
PyThreadState *tstate = _PyThreadState_GET();
11003+
_PyCStackRef cref;
11004+
_PyThreadState_PushCStackRef(tstate, &cref);
11005+
_PyType_LookupStackRefAndVersion(tp, &_Py_ID(__get__), &cref.ref);
11006+
if (PyStackRef_IsNull(cref.ref)) {
11007+
_PyThreadState_PopCStackRef(tstate, &cref);
1100211008
#ifndef Py_GIL_DISABLED
1100311009
/* Avoid further slowdowns */
1100411010
if (tp->tp_descr_get == slot_tp_descr_get)
@@ -11010,9 +11016,10 @@ slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1101011016
obj = Py_None;
1101111017
if (type == NULL)
1101211018
type = Py_None;
11019+
PyObject *get = PyStackRef_AsPyObjectBorrow(cref.ref);
1101311020
PyObject *stack[3] = {self, obj, type};
1101411021
PyObject *res = PyObject_Vectorcall(get, stack, 3, NULL);
11015-
Py_DECREF(get);
11022+
_PyThreadState_PopCStackRef(tstate, &cref);
1101611023
return res;
1101711024
}
1101811025

Tools/ftscalingbench/ftscalingbench.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,23 @@ def staticmethod_call():
279279
for _ in range(1000 * WORK_SCALE):
280280
obj.my_staticmethod()
281281

282+
283+
class MyDescriptor:
284+
def __get__(self, obj, objtype=None):
285+
return 42
286+
287+
def __set__(self, obj, value):
288+
pass
289+
290+
class MyClassWithDescriptor:
291+
attr = MyDescriptor()
292+
293+
@register_benchmark
294+
def descriptor():
295+
obj = MyClassWithDescriptor()
296+
for _ in range(1000 * WORK_SCALE):
297+
obj.attr
298+
282299
@register_benchmark
283300
def deepcopy():
284301
x = {'list': [1, 2], 'tuple': (1, None)}

0 commit comments

Comments
 (0)