bpo-30156: Remove property_descr_get() optimization (GH-9541)
property_descr_get() uses a "cached" tuple to optimize function calls. But this tuple can be discovered in debug mode with sys.getobjects(). Remove the optimization, it's not really worth it and it causes 3 different crashes last years. Microbenchmark: ./python -m perf timeit -v \ -s "from collections import namedtuple; P = namedtuple('P', 'x y'); p = P(1, 2)" \ --duplicate 1024 "p.x" Result: Mean +- std dev: [ref] 32.8 ns +- 0.8 ns -> [patch] 40.4 ns +- 1.3 ns: 1.23x slower (+23%)
This commit is contained in:
parent
9df100286b
commit
e972c13624
|
@ -0,0 +1,4 @@
|
|||
The C function ``property_descr_get()`` uses a "cached" tuple to optimize
|
||||
function calls. But this tuple can be discovered in debug mode with
|
||||
:func:`sys.getobjects()`. Remove the optimization, it's not really worth it
|
||||
and it causes 3 different crashes last years.
|
|
@ -1331,42 +1331,19 @@ property_dealloc(PyObject *self)
|
|||
static PyObject *
|
||||
property_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||
{
|
||||
static PyObject * volatile cached_args = NULL;
|
||||
PyObject *args;
|
||||
PyObject *ret;
|
||||
propertyobject *gs = (propertyobject *)self;
|
||||
|
||||
if (obj == NULL || obj == Py_None) {
|
||||
Py_INCREF(self);
|
||||
return self;
|
||||
}
|
||||
|
||||
propertyobject *gs = (propertyobject *)self;
|
||||
if (gs->prop_get == NULL) {
|
||||
PyErr_SetString(PyExc_AttributeError, "unreadable attribute");
|
||||
return NULL;
|
||||
}
|
||||
args = cached_args;
|
||||
cached_args = NULL;
|
||||
if (!args) {
|
||||
args = PyTuple_New(1);
|
||||
if (!args)
|
||||
return NULL;
|
||||
_PyObject_GC_UNTRACK(args);
|
||||
}
|
||||
Py_INCREF(obj);
|
||||
PyTuple_SET_ITEM(args, 0, obj);
|
||||
ret = PyObject_Call(gs->prop_get, args, NULL);
|
||||
if (cached_args == NULL && Py_REFCNT(args) == 1) {
|
||||
assert(PyTuple_GET_SIZE(args) == 1);
|
||||
assert(PyTuple_GET_ITEM(args, 0) == obj);
|
||||
cached_args = args;
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
else {
|
||||
assert(Py_REFCNT(args) >= 1);
|
||||
_PyObject_GC_TRACK(args);
|
||||
Py_DECREF(args);
|
||||
}
|
||||
return ret;
|
||||
|
||||
PyObject *args[1] = {obj};
|
||||
return _PyObject_FastCall(gs->prop_get, args, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
Loading…
Reference in New Issue