mirror of https://github.com/python/cpython
GH-123040: Specialize shadowed `LOAD_ATTR`. (GH-123219)
This commit is contained in:
parent
90b6d0e0f8
commit
5d3201fe3f
|
@ -279,6 +279,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) {
|
|||
return 1;
|
||||
case LOAD_ATTR_CLASS:
|
||||
return 1;
|
||||
case LOAD_ATTR_CLASS_WITH_METACLASS_CHECK:
|
||||
return 1;
|
||||
case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN:
|
||||
return 1;
|
||||
case LOAD_ATTR_INSTANCE_VALUE:
|
||||
|
@ -734,6 +736,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
|
|||
return 1 + (oparg & 1);
|
||||
case LOAD_ATTR_CLASS:
|
||||
return 1 + (oparg & 1);
|
||||
case LOAD_ATTR_CLASS_WITH_METACLASS_CHECK:
|
||||
return 1 + (oparg & 1);
|
||||
case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN:
|
||||
return 1;
|
||||
case LOAD_ATTR_INSTANCE_VALUE:
|
||||
|
@ -1125,6 +1129,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[264] = {
|
|||
[LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
|
@ -1329,6 +1334,7 @@ _PyOpcode_macro_expansion[256] = {
|
|||
[LIST_EXTEND] = { .nuops = 1, .uops = { { _LIST_EXTEND, 0, 0 } } },
|
||||
[LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, 0, 0 } } },
|
||||
[LOAD_ATTR_CLASS] = { .nuops = 2, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 } } },
|
||||
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 } } },
|
||||
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, 0, 0 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 } } },
|
||||
[LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } },
|
||||
[LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } },
|
||||
|
@ -1542,6 +1548,7 @@ const char *_PyOpcode_OpName[264] = {
|
|||
[LIST_EXTEND] = "LIST_EXTEND",
|
||||
[LOAD_ATTR] = "LOAD_ATTR",
|
||||
[LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS",
|
||||
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = "LOAD_ATTR_CLASS_WITH_METACLASS_CHECK",
|
||||
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
|
||||
[LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE",
|
||||
[LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT",
|
||||
|
@ -1794,6 +1801,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
|
|||
[LIST_EXTEND] = LIST_EXTEND,
|
||||
[LOAD_ATTR] = LOAD_ATTR,
|
||||
[LOAD_ATTR_CLASS] = LOAD_ATTR,
|
||||
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = LOAD_ATTR,
|
||||
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = LOAD_ATTR,
|
||||
[LOAD_ATTR_INSTANCE_VALUE] = LOAD_ATTR,
|
||||
[LOAD_ATTR_METHOD_LAZY_DICT] = LOAD_ATTR,
|
||||
|
@ -1924,7 +1932,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
|
|||
case 146: \
|
||||
case 147: \
|
||||
case 148: \
|
||||
case 226: \
|
||||
case 227: \
|
||||
case 228: \
|
||||
case 229: \
|
||||
|
|
|
@ -173,37 +173,38 @@ extern "C" {
|
|||
#define FOR_ITER_RANGE 192
|
||||
#define FOR_ITER_TUPLE 193
|
||||
#define LOAD_ATTR_CLASS 194
|
||||
#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 195
|
||||
#define LOAD_ATTR_INSTANCE_VALUE 196
|
||||
#define LOAD_ATTR_METHOD_LAZY_DICT 197
|
||||
#define LOAD_ATTR_METHOD_NO_DICT 198
|
||||
#define LOAD_ATTR_METHOD_WITH_VALUES 199
|
||||
#define LOAD_ATTR_MODULE 200
|
||||
#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 201
|
||||
#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 202
|
||||
#define LOAD_ATTR_PROPERTY 203
|
||||
#define LOAD_ATTR_SLOT 204
|
||||
#define LOAD_ATTR_WITH_HINT 205
|
||||
#define LOAD_GLOBAL_BUILTIN 206
|
||||
#define LOAD_GLOBAL_MODULE 207
|
||||
#define LOAD_SUPER_ATTR_ATTR 208
|
||||
#define LOAD_SUPER_ATTR_METHOD 209
|
||||
#define RESUME_CHECK 210
|
||||
#define SEND_GEN 211
|
||||
#define STORE_ATTR_INSTANCE_VALUE 212
|
||||
#define STORE_ATTR_SLOT 213
|
||||
#define STORE_ATTR_WITH_HINT 214
|
||||
#define STORE_SUBSCR_DICT 215
|
||||
#define STORE_SUBSCR_LIST_INT 216
|
||||
#define TO_BOOL_ALWAYS_TRUE 217
|
||||
#define TO_BOOL_BOOL 218
|
||||
#define TO_BOOL_INT 219
|
||||
#define TO_BOOL_LIST 220
|
||||
#define TO_BOOL_NONE 221
|
||||
#define TO_BOOL_STR 222
|
||||
#define UNPACK_SEQUENCE_LIST 223
|
||||
#define UNPACK_SEQUENCE_TUPLE 224
|
||||
#define UNPACK_SEQUENCE_TWO_TUPLE 225
|
||||
#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 195
|
||||
#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 196
|
||||
#define LOAD_ATTR_INSTANCE_VALUE 197
|
||||
#define LOAD_ATTR_METHOD_LAZY_DICT 198
|
||||
#define LOAD_ATTR_METHOD_NO_DICT 199
|
||||
#define LOAD_ATTR_METHOD_WITH_VALUES 200
|
||||
#define LOAD_ATTR_MODULE 201
|
||||
#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 202
|
||||
#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 203
|
||||
#define LOAD_ATTR_PROPERTY 204
|
||||
#define LOAD_ATTR_SLOT 205
|
||||
#define LOAD_ATTR_WITH_HINT 206
|
||||
#define LOAD_GLOBAL_BUILTIN 207
|
||||
#define LOAD_GLOBAL_MODULE 208
|
||||
#define LOAD_SUPER_ATTR_ATTR 209
|
||||
#define LOAD_SUPER_ATTR_METHOD 210
|
||||
#define RESUME_CHECK 211
|
||||
#define SEND_GEN 212
|
||||
#define STORE_ATTR_INSTANCE_VALUE 213
|
||||
#define STORE_ATTR_SLOT 214
|
||||
#define STORE_ATTR_WITH_HINT 215
|
||||
#define STORE_SUBSCR_DICT 216
|
||||
#define STORE_SUBSCR_LIST_INT 217
|
||||
#define TO_BOOL_ALWAYS_TRUE 218
|
||||
#define TO_BOOL_BOOL 219
|
||||
#define TO_BOOL_INT 220
|
||||
#define TO_BOOL_LIST 221
|
||||
#define TO_BOOL_NONE 222
|
||||
#define TO_BOOL_STR 223
|
||||
#define UNPACK_SEQUENCE_LIST 224
|
||||
#define UNPACK_SEQUENCE_TUPLE 225
|
||||
#define UNPACK_SEQUENCE_TWO_TUPLE 226
|
||||
#define INSTRUMENTED_END_FOR 236
|
||||
#define INSTRUMENTED_END_SEND 237
|
||||
#define INSTRUMENTED_LOAD_SUPER_ATTR 238
|
||||
|
|
|
@ -62,6 +62,7 @@ _specializations = {
|
|||
"LOAD_ATTR_WITH_HINT",
|
||||
"LOAD_ATTR_SLOT",
|
||||
"LOAD_ATTR_CLASS",
|
||||
"LOAD_ATTR_CLASS_WITH_METACLASS_CHECK",
|
||||
"LOAD_ATTR_PROPERTY",
|
||||
"LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
|
||||
"LOAD_ATTR_METHOD_WITH_VALUES",
|
||||
|
@ -161,37 +162,38 @@ _specialized_opmap = {
|
|||
'FOR_ITER_RANGE': 192,
|
||||
'FOR_ITER_TUPLE': 193,
|
||||
'LOAD_ATTR_CLASS': 194,
|
||||
'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 195,
|
||||
'LOAD_ATTR_INSTANCE_VALUE': 196,
|
||||
'LOAD_ATTR_METHOD_LAZY_DICT': 197,
|
||||
'LOAD_ATTR_METHOD_NO_DICT': 198,
|
||||
'LOAD_ATTR_METHOD_WITH_VALUES': 199,
|
||||
'LOAD_ATTR_MODULE': 200,
|
||||
'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 201,
|
||||
'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 202,
|
||||
'LOAD_ATTR_PROPERTY': 203,
|
||||
'LOAD_ATTR_SLOT': 204,
|
||||
'LOAD_ATTR_WITH_HINT': 205,
|
||||
'LOAD_GLOBAL_BUILTIN': 206,
|
||||
'LOAD_GLOBAL_MODULE': 207,
|
||||
'LOAD_SUPER_ATTR_ATTR': 208,
|
||||
'LOAD_SUPER_ATTR_METHOD': 209,
|
||||
'RESUME_CHECK': 210,
|
||||
'SEND_GEN': 211,
|
||||
'STORE_ATTR_INSTANCE_VALUE': 212,
|
||||
'STORE_ATTR_SLOT': 213,
|
||||
'STORE_ATTR_WITH_HINT': 214,
|
||||
'STORE_SUBSCR_DICT': 215,
|
||||
'STORE_SUBSCR_LIST_INT': 216,
|
||||
'TO_BOOL_ALWAYS_TRUE': 217,
|
||||
'TO_BOOL_BOOL': 218,
|
||||
'TO_BOOL_INT': 219,
|
||||
'TO_BOOL_LIST': 220,
|
||||
'TO_BOOL_NONE': 221,
|
||||
'TO_BOOL_STR': 222,
|
||||
'UNPACK_SEQUENCE_LIST': 223,
|
||||
'UNPACK_SEQUENCE_TUPLE': 224,
|
||||
'UNPACK_SEQUENCE_TWO_TUPLE': 225,
|
||||
'LOAD_ATTR_CLASS_WITH_METACLASS_CHECK': 195,
|
||||
'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 196,
|
||||
'LOAD_ATTR_INSTANCE_VALUE': 197,
|
||||
'LOAD_ATTR_METHOD_LAZY_DICT': 198,
|
||||
'LOAD_ATTR_METHOD_NO_DICT': 199,
|
||||
'LOAD_ATTR_METHOD_WITH_VALUES': 200,
|
||||
'LOAD_ATTR_MODULE': 201,
|
||||
'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 202,
|
||||
'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 203,
|
||||
'LOAD_ATTR_PROPERTY': 204,
|
||||
'LOAD_ATTR_SLOT': 205,
|
||||
'LOAD_ATTR_WITH_HINT': 206,
|
||||
'LOAD_GLOBAL_BUILTIN': 207,
|
||||
'LOAD_GLOBAL_MODULE': 208,
|
||||
'LOAD_SUPER_ATTR_ATTR': 209,
|
||||
'LOAD_SUPER_ATTR_METHOD': 210,
|
||||
'RESUME_CHECK': 211,
|
||||
'SEND_GEN': 212,
|
||||
'STORE_ATTR_INSTANCE_VALUE': 213,
|
||||
'STORE_ATTR_SLOT': 214,
|
||||
'STORE_ATTR_WITH_HINT': 215,
|
||||
'STORE_SUBSCR_DICT': 216,
|
||||
'STORE_SUBSCR_LIST_INT': 217,
|
||||
'TO_BOOL_ALWAYS_TRUE': 218,
|
||||
'TO_BOOL_BOOL': 219,
|
||||
'TO_BOOL_INT': 220,
|
||||
'TO_BOOL_LIST': 221,
|
||||
'TO_BOOL_NONE': 222,
|
||||
'TO_BOOL_STR': 223,
|
||||
'UNPACK_SEQUENCE_LIST': 224,
|
||||
'UNPACK_SEQUENCE_TUPLE': 225,
|
||||
'UNPACK_SEQUENCE_TWO_TUPLE': 226,
|
||||
}
|
||||
|
||||
opmap = {
|
||||
|
|
|
@ -1936,6 +1936,7 @@ dummy_func(
|
|||
LOAD_ATTR_WITH_HINT,
|
||||
LOAD_ATTR_SLOT,
|
||||
LOAD_ATTR_CLASS,
|
||||
LOAD_ATTR_CLASS_WITH_METACLASS_CHECK,
|
||||
LOAD_ATTR_PROPERTY,
|
||||
LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
|
||||
LOAD_ATTR_METHOD_WITH_VALUES,
|
||||
|
@ -2119,7 +2120,6 @@ dummy_func(
|
|||
EXIT_IF(!PyType_Check(owner_o));
|
||||
assert(type_version != 0);
|
||||
EXIT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version);
|
||||
|
||||
}
|
||||
|
||||
split op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) {
|
||||
|
@ -2136,6 +2136,12 @@ dummy_func(
|
|||
unused/2 +
|
||||
_LOAD_ATTR_CLASS;
|
||||
|
||||
macro(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) =
|
||||
unused/1 +
|
||||
_CHECK_ATTR_CLASS +
|
||||
_GUARD_TYPE_VERSION +
|
||||
_LOAD_ATTR_CLASS;
|
||||
|
||||
op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame: _PyInterpreterFrame *)) {
|
||||
assert((oparg & 1) == 0);
|
||||
assert(Py_IS_TYPE(fget, &PyFunction_Type));
|
||||
|
|
|
@ -4937,6 +4937,47 @@
|
|||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) {
|
||||
_Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;
|
||||
next_instr += 10;
|
||||
INSTRUCTION_STATS(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK);
|
||||
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
|
||||
_PyStackRef owner;
|
||||
_PyStackRef attr;
|
||||
_PyStackRef null = PyStackRef_NULL;
|
||||
/* Skip 1 cache entry */
|
||||
// _CHECK_ATTR_CLASS
|
||||
owner = stack_pointer[-1];
|
||||
{
|
||||
uint32_t type_version = read_u32(&this_instr[2].cache);
|
||||
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
|
||||
DEOPT_IF(!PyType_Check(owner_o), LOAD_ATTR);
|
||||
assert(type_version != 0);
|
||||
DEOPT_IF(((PyTypeObject *)owner_o)->tp_version_tag != type_version, LOAD_ATTR);
|
||||
}
|
||||
// _GUARD_TYPE_VERSION
|
||||
{
|
||||
uint32_t type_version = read_u32(&this_instr[4].cache);
|
||||
PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
assert(type_version != 0);
|
||||
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
|
||||
}
|
||||
// _LOAD_ATTR_CLASS
|
||||
{
|
||||
PyObject *descr = read_obj(&this_instr[6].cache);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
assert(descr != NULL);
|
||||
attr = PyStackRef_FromPyObjectNew(descr);
|
||||
stack_pointer[-1] = attr;
|
||||
null = PyStackRef_NULL;
|
||||
PyStackRef_CLOSE(owner);
|
||||
}
|
||||
if (oparg & 1) stack_pointer[0] = null;
|
||||
stack_pointer += (oparg & 1);
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) {
|
||||
_Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;
|
||||
next_instr += 10;
|
||||
|
|
|
@ -194,6 +194,7 @@ static void *opcode_targets[256] = {
|
|||
&&TARGET_FOR_ITER_RANGE,
|
||||
&&TARGET_FOR_ITER_TUPLE,
|
||||
&&TARGET_LOAD_ATTR_CLASS,
|
||||
&&TARGET_LOAD_ATTR_CLASS_WITH_METACLASS_CHECK,
|
||||
&&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
|
||||
&&TARGET_LOAD_ATTR_INSTANCE_VALUE,
|
||||
&&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
|
||||
|
@ -234,7 +235,6 @@ static void *opcode_targets[256] = {
|
|||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&_unknown_opcode,
|
||||
&&TARGET_INSTRUMENTED_END_FOR,
|
||||
&&TARGET_INSTRUMENTED_END_SEND,
|
||||
&&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR,
|
||||
|
|
|
@ -490,7 +490,7 @@ _PyCode_Quicken(PyCodeObject *code)
|
|||
#define SPEC_FAIL_ATTR_READ_ONLY 16
|
||||
#define SPEC_FAIL_ATTR_AUDITED_SLOT 17
|
||||
#define SPEC_FAIL_ATTR_NOT_MANAGED_DICT 18
|
||||
#define SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT 19
|
||||
#define SPEC_FAIL_ATTR_NON_STRING 19
|
||||
#define SPEC_FAIL_ATTR_MODULE_ATTR_NOT_FOUND 20
|
||||
#define SPEC_FAIL_ATTR_SHADOWED 21
|
||||
#define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD 22
|
||||
|
@ -505,6 +505,8 @@ _PyCode_Quicken(PyCodeObject *code)
|
|||
#define SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE 31
|
||||
#define SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR 32
|
||||
#define SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ 33
|
||||
#define SPEC_FAIL_ATTR_METACLASS_OVERRIDDEN 34
|
||||
#define SPEC_FAIL_ATTR_SPLIT_DICT 35
|
||||
|
||||
/* Binary subscr and store subscr */
|
||||
|
||||
|
@ -647,7 +649,7 @@ specialize_module_load_attr(
|
|||
return -1;
|
||||
}
|
||||
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_STRING);
|
||||
return -1;
|
||||
}
|
||||
Py_ssize_t index = _PyDict_LookupIndex(dict, &_Py_ID(__getattr__));
|
||||
|
@ -730,6 +732,48 @@ typedef enum {
|
|||
} DescriptorClassification;
|
||||
|
||||
|
||||
static DescriptorClassification
|
||||
classify_descriptor(PyObject *descriptor, bool has_getattr)
|
||||
{
|
||||
if (descriptor == NULL) {
|
||||
return ABSENT;
|
||||
}
|
||||
PyTypeObject *desc_cls = Py_TYPE(descriptor);
|
||||
if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) {
|
||||
return MUTABLE;
|
||||
}
|
||||
if (desc_cls->tp_descr_set) {
|
||||
if (desc_cls == &PyMemberDescr_Type) {
|
||||
PyMemberDescrObject *member = (PyMemberDescrObject *)descriptor;
|
||||
struct PyMemberDef *dmem = member->d_member;
|
||||
if (dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT) {
|
||||
return OBJECT_SLOT;
|
||||
}
|
||||
return OTHER_SLOT;
|
||||
}
|
||||
if (desc_cls == &PyProperty_Type) {
|
||||
/* We can't detect at runtime whether an attribute exists
|
||||
with property. So that means we may have to call
|
||||
__getattr__. */
|
||||
return has_getattr ? GETSET_OVERRIDDEN : PROPERTY;
|
||||
}
|
||||
return OVERRIDING;
|
||||
}
|
||||
if (desc_cls->tp_descr_get) {
|
||||
if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) {
|
||||
return METHOD;
|
||||
}
|
||||
if (Py_IS_TYPE(descriptor, &PyClassMethodDescr_Type)) {
|
||||
return BUILTIN_CLASSMETHOD;
|
||||
}
|
||||
if (Py_IS_TYPE(descriptor, &PyClassMethod_Type)) {
|
||||
return PYTHON_CLASSMETHOD;
|
||||
}
|
||||
return NON_OVERRIDING;
|
||||
}
|
||||
return NON_DESCRIPTOR;
|
||||
}
|
||||
|
||||
static DescriptorClassification
|
||||
analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int store)
|
||||
{
|
||||
|
@ -783,50 +827,12 @@ analyze_descriptor(PyTypeObject *type, PyObject *name, PyObject **descr, int sto
|
|||
}
|
||||
PyObject *descriptor = _PyType_Lookup(type, name);
|
||||
*descr = descriptor;
|
||||
if (descriptor == NULL) {
|
||||
return ABSENT;
|
||||
}
|
||||
PyTypeObject *desc_cls = Py_TYPE(descriptor);
|
||||
if (!(desc_cls->tp_flags & Py_TPFLAGS_IMMUTABLETYPE)) {
|
||||
return MUTABLE;
|
||||
}
|
||||
if (desc_cls->tp_descr_set) {
|
||||
if (desc_cls == &PyMemberDescr_Type) {
|
||||
PyMemberDescrObject *member = (PyMemberDescrObject *)descriptor;
|
||||
struct PyMemberDef *dmem = member->d_member;
|
||||
if (dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT) {
|
||||
return OBJECT_SLOT;
|
||||
}
|
||||
return OTHER_SLOT;
|
||||
}
|
||||
if (desc_cls == &PyProperty_Type) {
|
||||
/* We can't detect at runtime whether an attribute exists
|
||||
with property. So that means we may have to call
|
||||
__getattr__. */
|
||||
return has_getattr ? GETSET_OVERRIDDEN : PROPERTY;
|
||||
}
|
||||
if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) {
|
||||
if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) {
|
||||
return DUNDER_CLASS;
|
||||
}
|
||||
}
|
||||
if (store) {
|
||||
return OVERRIDING;
|
||||
if (PyUnicode_CompareWithASCIIString(name, "__class__") == 0) {
|
||||
if (descriptor == _PyType_Lookup(&PyBaseObject_Type, name)) {
|
||||
return DUNDER_CLASS;
|
||||
}
|
||||
}
|
||||
if (desc_cls->tp_descr_get) {
|
||||
if (desc_cls->tp_flags & Py_TPFLAGS_METHOD_DESCRIPTOR) {
|
||||
return METHOD;
|
||||
}
|
||||
if (Py_IS_TYPE(descriptor, &PyClassMethodDescr_Type)) {
|
||||
return BUILTIN_CLASSMETHOD;
|
||||
}
|
||||
if (Py_IS_TYPE(descriptor, &PyClassMethod_Type)) {
|
||||
return PYTHON_CLASSMETHOD;
|
||||
}
|
||||
return NON_OVERRIDING;
|
||||
}
|
||||
return NON_DESCRIPTOR;
|
||||
return classify_descriptor(descriptor, has_getattr);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -836,7 +842,8 @@ specialize_dict_access(
|
|||
int base_op, int values_op, int hint_op)
|
||||
{
|
||||
assert(kind == NON_OVERRIDING || kind == NON_DESCRIPTOR || kind == ABSENT ||
|
||||
kind == BUILTIN_CLASSMETHOD || kind == PYTHON_CLASSMETHOD);
|
||||
kind == BUILTIN_CLASSMETHOD || kind == PYTHON_CLASSMETHOD ||
|
||||
kind == METHOD);
|
||||
// No descriptor, or non overriding.
|
||||
if ((type->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
|
||||
|
@ -871,7 +878,7 @@ specialize_dict_access(
|
|||
}
|
||||
// We found an instance with a __dict__.
|
||||
if (dict->ma_values) {
|
||||
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT);
|
||||
SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_SPLIT_DICT);
|
||||
return 0;
|
||||
}
|
||||
Py_ssize_t index =
|
||||
|
@ -894,57 +901,69 @@ static int specialize_attr_loadclassattr(PyObject* owner, _Py_CODEUNIT* instr, P
|
|||
PyObject* descr, DescriptorClassification kind, bool is_method);
|
||||
static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name);
|
||||
|
||||
void
|
||||
_Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *name)
|
||||
/* Returns true if instances of obj's class are
|
||||
* likely to have `name` in their __dict__.
|
||||
* For objects with inline values, we check in the shared keys.
|
||||
* For other objects, we check their actual dictionary.
|
||||
*/
|
||||
static bool
|
||||
instance_has_key(PyObject *obj, PyObject* name)
|
||||
{
|
||||
PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st);
|
||||
PyTypeObject *cls = Py_TYPE(obj);
|
||||
if ((cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
|
||||
PyDictKeysObject *keys = ((PyHeapTypeObject *)cls)->ht_cached_keys;
|
||||
Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
|
||||
return index >= 0;
|
||||
}
|
||||
PyDictObject *dict = _PyObject_GetManagedDict(obj);
|
||||
if (dict == NULL || !PyDict_CheckExact(dict)) {
|
||||
return false;
|
||||
}
|
||||
if (dict->ma_values) {
|
||||
return false;
|
||||
}
|
||||
Py_ssize_t index = _PyDict_LookupIndex(dict, name);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(ENABLE_SPECIALIZATION);
|
||||
assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
|
||||
static int
|
||||
specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name)
|
||||
{
|
||||
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
||||
PyTypeObject *type = Py_TYPE(owner);
|
||||
if (!_PyType_IsReady(type)) {
|
||||
// We *might* not really need this check, but we inherited it from
|
||||
// PyObject_GenericGetAttr and friends... and this way we still do the
|
||||
// right thing if someone forgets to call PyType_Ready(type):
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
|
||||
goto fail;
|
||||
}
|
||||
if (PyModule_CheckExact(owner)) {
|
||||
if (specialize_module_load_attr(owner, instr, name))
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
if (PyType_Check(owner)) {
|
||||
if (specialize_class_load_attr(owner, instr, name)) {
|
||||
goto fail;
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
bool shadow = instance_has_key(owner, name);
|
||||
PyObject *descr = NULL;
|
||||
DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0);
|
||||
assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN);
|
||||
if (type_get_version(type, LOAD_ATTR) == 0) {
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
switch(kind) {
|
||||
case OVERRIDING:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
|
||||
goto fail;
|
||||
return -1;
|
||||
case METHOD:
|
||||
{
|
||||
if (shadow) {
|
||||
goto try_instance;
|
||||
}
|
||||
int oparg = instr->op.arg;
|
||||
if (oparg & 1) {
|
||||
if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, true)) {
|
||||
goto success;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
}
|
||||
goto fail;
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
return -1;
|
||||
}
|
||||
case PROPERTY:
|
||||
{
|
||||
|
@ -953,29 +972,29 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam
|
|||
PyObject *fget = ((_PyPropertyObject *)descr)->prop_get;
|
||||
if (fget == NULL) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (!Py_IS_TYPE(fget, &PyFunction_Type)) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (!function_check_args(fget, 1, LOAD_ATTR)) {
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (instr->op.arg & 1) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (_PyInterpreterState_GET()->eval_frame) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
assert(type->tp_version_tag != 0);
|
||||
write_u32(lm_cache->type_version, type->tp_version_tag);
|
||||
/* borrowed */
|
||||
write_obj(lm_cache->descr, fget);
|
||||
instr->op.code = LOAD_ATTR_PROPERTY;
|
||||
goto success;
|
||||
return 0;
|
||||
}
|
||||
case OBJECT_SLOT:
|
||||
{
|
||||
|
@ -984,22 +1003,22 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam
|
|||
Py_ssize_t offset = dmem->offset;
|
||||
if (!PyObject_TypeCheck(owner, member->d_common.d_type)) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (dmem->flags & Py_AUDIT_READ) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_AUDITED_SLOT);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (offset != (uint16_t)offset) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
assert(dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT);
|
||||
assert(offset > 0);
|
||||
cache->index = (uint16_t)offset;
|
||||
write_u32(cache->version, type->tp_version_tag);
|
||||
instr->op.code = LOAD_ATTR_SLOT;
|
||||
goto success;
|
||||
return 0;
|
||||
}
|
||||
case DUNDER_CLASS:
|
||||
{
|
||||
|
@ -1008,83 +1027,115 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam
|
|||
cache->index = (uint16_t)offset;
|
||||
write_u32(cache->version, type->tp_version_tag);
|
||||
instr->op.code = LOAD_ATTR_SLOT;
|
||||
goto success;
|
||||
return 0;
|
||||
}
|
||||
case OTHER_SLOT:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
|
||||
goto fail;
|
||||
return -1;
|
||||
case MUTABLE:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
|
||||
goto fail;
|
||||
return -1;
|
||||
case GETSET_OVERRIDDEN:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN);
|
||||
goto fail;
|
||||
return -1;
|
||||
case GETATTRIBUTE_IS_PYTHON_FUNCTION:
|
||||
{
|
||||
assert(type->tp_getattro == _Py_slot_tp_getattro);
|
||||
assert(Py_IS_TYPE(descr, &PyFunction_Type));
|
||||
_PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
|
||||
if (!function_check_args(descr, 2, LOAD_ATTR)) {
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (instr->op.arg & 1) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
uint32_t version = function_get_version(descr, LOAD_ATTR);
|
||||
if (version == 0) {
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
if (_PyInterpreterState_GET()->eval_frame) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
|
||||
goto fail;
|
||||
return -1;
|
||||
}
|
||||
write_u32(lm_cache->keys_version, version);
|
||||
/* borrowed */
|
||||
write_obj(lm_cache->descr, descr);
|
||||
write_u32(lm_cache->type_version, type->tp_version_tag);
|
||||
instr->op.code = LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN;
|
||||
goto success;
|
||||
return 0;
|
||||
}
|
||||
case BUILTIN_CLASSMETHOD:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_BUILTIN_CLASS_METHOD_OBJ);
|
||||
goto fail;
|
||||
case PYTHON_CLASSMETHOD:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_METHOD_OBJ);
|
||||
goto fail;
|
||||
case NON_OVERRIDING:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR,
|
||||
(type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ?
|
||||
SPEC_FAIL_ATTR_CLASS_ATTR_DESCRIPTOR :
|
||||
SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
|
||||
goto fail;
|
||||
if (shadow) {
|
||||
goto try_instance;
|
||||
}
|
||||
return -1;
|
||||
case NON_DESCRIPTOR:
|
||||
if (shadow) {
|
||||
goto try_instance;
|
||||
}
|
||||
if ((instr->op.arg & 1) == 0) {
|
||||
if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, false)) {
|
||||
goto success;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE);
|
||||
}
|
||||
goto fail;
|
||||
return -1;
|
||||
case ABSENT:
|
||||
if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR,
|
||||
LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
|
||||
{
|
||||
goto success;
|
||||
if (shadow) {
|
||||
goto try_instance;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Py_UNREACHABLE();
|
||||
try_instance:
|
||||
if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR,
|
||||
LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
_Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *name)
|
||||
{
|
||||
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
||||
PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st);
|
||||
|
||||
assert(ENABLE_SPECIALIZATION);
|
||||
assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
|
||||
PyTypeObject *type = Py_TYPE(owner);
|
||||
bool fail;
|
||||
if (!_PyType_IsReady(type)) {
|
||||
// We *might* not really need this check, but we inherited it from
|
||||
// PyObject_GenericGetAttr and friends... and this way we still do the
|
||||
// right thing if someone forgets to call PyType_Ready(type):
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
|
||||
fail = true;
|
||||
}
|
||||
else if (PyModule_CheckExact(owner)) {
|
||||
fail = specialize_module_load_attr(owner, instr, name);
|
||||
}
|
||||
else if (PyType_Check(owner)) {
|
||||
fail = specialize_class_load_attr(owner, instr, name);
|
||||
}
|
||||
else {
|
||||
fail = specialize_instance_load_attr(owner, instr, name);
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
STAT_INC(LOAD_ATTR, failure);
|
||||
assert(!PyErr_Occurred());
|
||||
instr->op.code = LOAD_ATTR;
|
||||
cache->counter = adaptive_counter_backoff(cache->counter);
|
||||
}
|
||||
else {
|
||||
STAT_INC(LOAD_ATTR, success);
|
||||
assert(!PyErr_Occurred());
|
||||
cache->counter = adaptive_counter_cooldown();
|
||||
}
|
||||
fail:
|
||||
STAT_INC(LOAD_ATTR, failure);
|
||||
assert(!PyErr_Occurred());
|
||||
instr->op.code = LOAD_ATTR;
|
||||
cache->counter = adaptive_counter_backoff(cache->counter);
|
||||
return;
|
||||
success:
|
||||
STAT_INC(LOAD_ATTR, success);
|
||||
assert(!PyErr_Occurred());
|
||||
cache->counter = adaptive_counter_cooldown();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1230,23 +1281,52 @@ static int
|
|||
specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
|
||||
PyObject *name)
|
||||
{
|
||||
assert(PyType_Check(owner));
|
||||
PyTypeObject *cls = (PyTypeObject *)owner;
|
||||
_PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1);
|
||||
if (!PyType_CheckExact(owner) || _PyType_Lookup(Py_TYPE(owner), name)) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE);
|
||||
if (Py_TYPE(cls)->tp_getattro != _Py_type_getattro) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_OVERRIDDEN);
|
||||
return -1;
|
||||
}
|
||||
PyObject *metadescriptor = _PyType_Lookup(Py_TYPE(cls), name);
|
||||
DescriptorClassification metakind = classify_descriptor(metadescriptor, false);
|
||||
switch (metakind) {
|
||||
case METHOD:
|
||||
case NON_DESCRIPTOR:
|
||||
case NON_OVERRIDING:
|
||||
case BUILTIN_CLASSMETHOD:
|
||||
case PYTHON_CLASSMETHOD:
|
||||
case ABSENT:
|
||||
break;
|
||||
default:
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METACLASS_ATTRIBUTE);
|
||||
return -1;
|
||||
}
|
||||
PyObject *descr = NULL;
|
||||
DescriptorClassification kind = 0;
|
||||
kind = analyze_descriptor((PyTypeObject *)owner, name, &descr, 0);
|
||||
if (type_get_version((PyTypeObject *)owner, LOAD_ATTR) == 0) {
|
||||
kind = analyze_descriptor(cls, name, &descr, 0);
|
||||
if (type_get_version(cls, LOAD_ATTR) == 0) {
|
||||
return -1;
|
||||
}
|
||||
bool metaclass_check = false;
|
||||
if ((Py_TYPE(cls)->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) == 0) {
|
||||
metaclass_check = true;
|
||||
if (type_get_version(Py_TYPE(cls), LOAD_ATTR) == 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
switch (kind) {
|
||||
case METHOD:
|
||||
case NON_DESCRIPTOR:
|
||||
write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag);
|
||||
write_u32(cache->type_version, cls->tp_version_tag);
|
||||
write_obj(cache->descr, descr);
|
||||
instr->op.code = LOAD_ATTR_CLASS;
|
||||
if (metaclass_check) {
|
||||
write_u32(cache->keys_version, Py_TYPE(cls)->tp_version_tag);
|
||||
instr->op.code = LOAD_ATTR_CLASS_WITH_METACLASS_CHECK;
|
||||
}
|
||||
else {
|
||||
instr->op.code = LOAD_ATTR_CLASS;
|
||||
}
|
||||
return 0;
|
||||
#ifdef Py_STATS
|
||||
case ABSENT:
|
||||
|
@ -1273,11 +1353,7 @@ PyObject *descr, DescriptorClassification kind, bool is_method)
|
|||
assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR));
|
||||
if (owner_cls->tp_flags & Py_TPFLAGS_INLINE_VALUES) {
|
||||
PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys;
|
||||
Py_ssize_t index = _PyDictKeys_StringLookup(keys, name);
|
||||
if (index != DKIX_EMPTY) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED);
|
||||
return 0;
|
||||
}
|
||||
assert(_PyDictKeys_StringLookup(keys, name) < 0);
|
||||
uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(
|
||||
_PyInterpreterState_GET(), keys);
|
||||
if (keys_version == 0) {
|
||||
|
|
Loading…
Reference in New Issue