mirror of https://github.com/python/cpython
bpo-36012: Avoid linear slot search for non-dunder methods (GH-11907)
This commit is contained in:
parent
b5409dacc4
commit
d8b9e1fc2e
|
@ -375,6 +375,11 @@ Optimizations
|
|||
This makes the created list 12% smaller on average. (Contributed by
|
||||
Raymond Hettinger and Pablo Galindo in :issue:`33234`.)
|
||||
|
||||
* Doubled the speed of class variable writes. When a non-dunder attribute
|
||||
was updated, there was an unnecessary call to update slots.
|
||||
(Contributed by Stefan Behnel, Pablo Galindo Salgado, Raymond Hettinger,
|
||||
Neil Schemenauer, and Serhiy Storchaka in :issue:`36012`.)
|
||||
|
||||
|
||||
Build and C API Changes
|
||||
=======================
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Doubled the speed of class variable writes. When a non-dunder attribute was
|
||||
updated, there was an unnecessary call to update slots.
|
|
@ -3164,6 +3164,24 @@ _PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name)
|
|||
return _PyType_Lookup(type, oname);
|
||||
}
|
||||
|
||||
/* Check if the "readied" PyUnicode name
|
||||
is a double-underscore special name. */
|
||||
static int
|
||||
is_dunder_name(PyObject *name)
|
||||
{
|
||||
Py_ssize_t length = PyUnicode_GET_LENGTH(name);
|
||||
int kind = PyUnicode_KIND(name);
|
||||
/* Special names contain at least "__x__" and are always ASCII. */
|
||||
if (length > 4 && kind == PyUnicode_1BYTE_KIND) {
|
||||
Py_UCS1 *characters = PyUnicode_1BYTE_DATA(name);
|
||||
return (
|
||||
((characters[length-2] == '_') && (characters[length-1] == '_')) &&
|
||||
((characters[0] == '_') && (characters[1] == '_'))
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is similar to PyObject_GenericGetAttr(),
|
||||
but uses _PyType_Lookup() instead of just looking in type->tp_dict. */
|
||||
static PyObject *
|
||||
|
@ -3275,12 +3293,14 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
|
|||
if (name == NULL)
|
||||
return -1;
|
||||
}
|
||||
PyUnicode_InternInPlace(&name);
|
||||
if (!PyUnicode_CHECK_INTERNED(name)) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Out of memory interning an attribute name");
|
||||
Py_DECREF(name);
|
||||
return -1;
|
||||
PyUnicode_InternInPlace(&name);
|
||||
if (!PyUnicode_CHECK_INTERNED(name)) {
|
||||
PyErr_SetString(PyExc_MemoryError,
|
||||
"Out of memory interning an attribute name");
|
||||
Py_DECREF(name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -3289,7 +3309,16 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
|
|||
}
|
||||
res = _PyObject_GenericSetAttrWithDict((PyObject *)type, name, value, NULL);
|
||||
if (res == 0) {
|
||||
res = update_slot(type, name);
|
||||
/* Clear the VALID_VERSION flag of 'type' and all its
|
||||
subclasses. This could possibly be unified with the
|
||||
update_subclasses() recursion in update_slot(), but carefully:
|
||||
they each have their own conditions on which to stop
|
||||
recursing into subclasses. */
|
||||
PyType_Modified(type);
|
||||
|
||||
if (is_dunder_name(name)) {
|
||||
res = update_slot(type, name);
|
||||
}
|
||||
assert(_PyType_CheckConsistency(type));
|
||||
}
|
||||
Py_DECREF(name);
|
||||
|
@ -7236,13 +7265,6 @@ update_slot(PyTypeObject *type, PyObject *name)
|
|||
assert(PyUnicode_CheckExact(name));
|
||||
assert(PyUnicode_CHECK_INTERNED(name));
|
||||
|
||||
/* Clear the VALID_VERSION flag of 'type' and all its
|
||||
subclasses. This could possibly be unified with the
|
||||
update_subclasses() recursion below, but carefully:
|
||||
they each have their own conditions on which to stop
|
||||
recursing into subclasses. */
|
||||
PyType_Modified(type);
|
||||
|
||||
init_slotdefs();
|
||||
pp = ptrs;
|
||||
for (p = slotdefs; p->name; p++) {
|
||||
|
@ -7281,6 +7303,9 @@ update_all_slots(PyTypeObject* type)
|
|||
{
|
||||
slotdef *p;
|
||||
|
||||
/* Clear the VALID_VERSION flag of 'type' and all its subclasses. */
|
||||
PyType_Modified(type);
|
||||
|
||||
init_slotdefs();
|
||||
for (p = slotdefs; p->name; p++) {
|
||||
/* update_slot returns int but can't actually fail */
|
||||
|
|
Loading…
Reference in New Issue