mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
bpo-36012: Avoid linear slot search for non-dunder methods (GH-11907)
This commit is contained in:
parent
b5409dacc4
commit
d8b9e1fc2e
3 changed files with 45 additions and 13 deletions
|
@ -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…
Add table
Add a link
Reference in a new issue