diff options
author | Ken Jin <kenjin4096@gmail.com> | 2022-06-14 10:36:22 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-14 10:36:22 (GMT) |
commit | b083450f8896bb4a29ac522e4474d91c056b9f32 (patch) | |
tree | 74d923609496e622ec1e99e9381ee3f6c42b829b /Python/specialize.c | |
parent | cd543d0bc9aacca1dee02dea7ff4aec8966dcaf8 (diff) | |
download | cpython-b083450f8896bb4a29ac522e4474d91c056b9f32.zip cpython-b083450f8896bb4a29ac522e4474d91c056b9f32.tar.gz cpython-b083450f8896bb4a29ac522e4474d91c056b9f32.tar.bz2 |
GH-93429: Merge `LOAD_METHOD` back into `LOAD_ATTR` (GH-93430)
Diffstat (limited to 'Python/specialize.c')
-rw-r--r-- | Python/specialize.c | 136 |
1 files changed, 55 insertions, 81 deletions
diff --git a/Python/specialize.c b/Python/specialize.c index b187784..11bd838 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -20,7 +20,6 @@ uint8_t _PyOpcode_Adaptive[256] = { [LOAD_ATTR] = LOAD_ATTR_ADAPTIVE, [LOAD_GLOBAL] = LOAD_GLOBAL_ADAPTIVE, - [LOAD_METHOD] = LOAD_METHOD_ADAPTIVE, [BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE, [STORE_SUBSCR] = STORE_SUBSCR_ADAPTIVE, [CALL] = CALL_ADAPTIVE, @@ -362,22 +361,14 @@ miss_counter_start(void) { /* Methods */ -#define SPEC_FAIL_LOAD_METHOD_OVERRIDING_DESCRIPTOR 8 -#define SPEC_FAIL_LOAD_METHOD_NON_OVERRIDING_DESCRIPTOR 9 -#define SPEC_FAIL_LOAD_METHOD_NOT_DESCRIPTOR 10 -#define SPEC_FAIL_LOAD_METHOD_METHOD 11 -#define SPEC_FAIL_LOAD_METHOD_MUTABLE_CLASS 12 -#define SPEC_FAIL_LOAD_METHOD_PROPERTY 13 -#define SPEC_FAIL_LOAD_METHOD_NON_OBJECT_SLOT 14 -#define SPEC_FAIL_LOAD_METHOD_IS_ATTR 15 -#define SPEC_FAIL_LOAD_METHOD_DICT_SUBCLASS 16 -#define SPEC_FAIL_LOAD_METHOD_BUILTIN_CLASS_METHOD 17 -#define SPEC_FAIL_LOAD_METHOD_CLASS_METHOD_OBJ 18 -#define SPEC_FAIL_LOAD_METHOD_OBJECT_SLOT 19 -#define SPEC_FAIL_LOAD_METHOD_HAS_DICT 20 -#define SPEC_FAIL_LOAD_METHOD_HAS_MANAGED_DICT 21 -#define SPEC_FAIL_LOAD_METHOD_INSTANCE_ATTRIBUTE 22 -#define SPEC_FAIL_LOAD_METHOD_METACLASS_ATTRIBUTE 23 +#define SPEC_FAIL_LOAD_METHOD_METHOD 20 +#define SPEC_FAIL_LOAD_METHOD_IS_ATTR 21 +#define SPEC_FAIL_LOAD_METHOD_BUILTIN_CLASS_METHOD 22 +#define SPEC_FAIL_LOAD_METHOD_CLASS_METHOD_OBJ 23 +#define SPEC_FAIL_LOAD_METHOD_OBJECT_SLOT 24 +#define SPEC_FAIL_LOAD_METHOD_HAS_MANAGED_DICT 25 +#define SPEC_FAIL_LOAD_METHOD_INSTANCE_ATTRIBUTE 26 +#define SPEC_FAIL_LOAD_METHOD_METACLASS_ATTRIBUTE 27 /* Binary subscr and store subscr */ @@ -660,6 +651,10 @@ specialize_dict_access( return 1; } +static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, + PyObject* descr, DescriptorClassification kind); +static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); + int _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { @@ -673,21 +668,37 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) } goto success; } + if (PyType_Check(owner)) { + int err = specialize_class_load_attr(owner, instr, name); + if (err) { + goto fail; + } + goto success; + } PyTypeObject *type = Py_TYPE(owner); if (type->tp_dict == NULL) { if (PyType_Ready(type) < 0) { return -1; } } - PyObject *descr; + PyObject *descr = NULL; DescriptorClassification kind = analyze_descriptor(type, name, &descr, 0); + assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); switch(kind) { case OVERRIDING: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR); goto fail; case METHOD: + { + int oparg = _Py_OPARG(*instr); + if (oparg & 1) { + if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) { + goto success; + } + } SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); goto fail; + } case PROPERTY: SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY); goto fail; @@ -843,23 +854,23 @@ success: #ifdef Py_STATS static int -load_method_fail_kind(DescriptorClassification kind) +load_attr_fail_kind(DescriptorClassification kind) { switch (kind) { case OVERRIDING: - return SPEC_FAIL_LOAD_METHOD_OVERRIDING_DESCRIPTOR; + return SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR; case METHOD: - return SPEC_FAIL_LOAD_METHOD_METHOD; + return SPEC_FAIL_ATTR_METHOD; case PROPERTY: - return SPEC_FAIL_LOAD_METHOD_PROPERTY; + return SPEC_FAIL_ATTR_PROPERTY; case OBJECT_SLOT: return SPEC_FAIL_LOAD_METHOD_OBJECT_SLOT; case OTHER_SLOT: - return SPEC_FAIL_LOAD_METHOD_NON_OBJECT_SLOT; + return SPEC_FAIL_ATTR_NON_OBJECT_SLOT; case DUNDER_CLASS: return SPEC_FAIL_OTHER; case MUTABLE: - return SPEC_FAIL_LOAD_METHOD_MUTABLE_CLASS; + return SPEC_FAIL_ATTR_MUTABLE_CLASS; case GETSET_OVERRIDDEN: return SPEC_FAIL_OVERRIDDEN; case BUILTIN_CLASSMETHOD: @@ -867,9 +878,9 @@ load_method_fail_kind(DescriptorClassification kind) case PYTHON_CLASSMETHOD: return SPEC_FAIL_LOAD_METHOD_CLASS_METHOD_OBJ; case NON_OVERRIDING: - return SPEC_FAIL_LOAD_METHOD_NON_OVERRIDING_DESCRIPTOR; + return SPEC_FAIL_ATTR_NON_OVERRIDING_DESCRIPTOR; case NON_DESCRIPTOR: - return SPEC_FAIL_LOAD_METHOD_NOT_DESCRIPTOR; + return SPEC_FAIL_ATTR_NOT_DESCRIPTOR; case ABSENT: return SPEC_FAIL_LOAD_METHOD_INSTANCE_ATTRIBUTE; } @@ -878,7 +889,7 @@ load_method_fail_kind(DescriptorClassification kind) #endif static int -specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr, +specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); @@ -890,20 +901,20 @@ specialize_class_load_method(PyObject *owner, _Py_CODEUNIT *instr, case NON_DESCRIPTOR: write_u32(cache->type_version, ((PyTypeObject *)owner)->tp_version_tag); write_obj(cache->descr, descr); - _Py_SET_OPCODE(*instr, LOAD_METHOD_CLASS); + _Py_SET_OPCODE(*instr, LOAD_ATTR_CLASS); return 0; #ifdef Py_STATS case ABSENT: if (_PyType_Lookup(Py_TYPE(owner), name) != NULL) { - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_LOAD_METHOD_METACLASS_ATTRIBUTE); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_LOAD_METHOD_METACLASS_ATTRIBUTE); } else { - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_EXPECTED_ERROR); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR); } return -1; #endif default: - SPECIALIZATION_FAIL(LOAD_METHOD, load_method_fail_kind(kind)); + SPECIALIZATION_FAIL(LOAD_ATTR, load_attr_fail_kind(kind)); return -1; } } @@ -919,44 +930,14 @@ typedef enum { // Please collect stats carefully before and after modifying. A subtle change // can cause a significant drop in cache hits. A possible test is // python.exe -m test_typing test_re test_dis test_zlib. -int -_Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) +static int +specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, +PyObject *descr, DescriptorClassification kind) { - assert(_PyOpcode_Caches[LOAD_METHOD] == INLINE_CACHE_ENTRIES_LOAD_METHOD); _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); PyTypeObject *owner_cls = Py_TYPE(owner); - if (PyModule_CheckExact(owner)) { - assert(INLINE_CACHE_ENTRIES_LOAD_ATTR <= - INLINE_CACHE_ENTRIES_LOAD_METHOD); - int err = specialize_module_load_attr(owner, instr, name, LOAD_METHOD, - LOAD_METHOD_MODULE); - if (err) { - goto fail; - } - goto success; - } - if (owner_cls->tp_dict == NULL) { - if (PyType_Ready(owner_cls) < 0) { - return -1; - } - } - if (PyType_Check(owner)) { - int err = specialize_class_load_method(owner, instr, name); - if (err) { - goto fail; - } - goto success; - } - - PyObject *descr = NULL; - DescriptorClassification kind = 0; - kind = analyze_descriptor(owner_cls, name, &descr, 0); - assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); - if (kind != METHOD) { - SPECIALIZATION_FAIL(LOAD_METHOD, load_method_fail_kind(kind)); - goto fail; - } + assert(kind == METHOD && descr != NULL); ObjectDictKind dictkind; PyDictKeysObject *keys; if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { @@ -972,7 +953,7 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) else { Py_ssize_t dictoffset = owner_cls->tp_dictoffset; if (dictoffset < 0 || dictoffset > INT16_MAX) { - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OUT_OF_RANGE); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE); goto fail; } if (dictoffset == 0) { @@ -995,33 +976,33 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) if (dictkind == MANAGED_VALUES || dictkind == OFFSET_DICT) { Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); if (index != DKIX_EMPTY) { - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_LOAD_METHOD_IS_ATTR); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_LOAD_METHOD_IS_ATTR); goto fail; } uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(keys); if (keys_version == 0) { - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OUT_OF_VERSIONS); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } write_u32(cache->keys_version, keys_version); } switch(dictkind) { case NO_DICT: - _Py_SET_OPCODE(*instr, LOAD_METHOD_NO_DICT); + _Py_SET_OPCODE(*instr, LOAD_ATTR_METHOD_NO_DICT); break; case MANAGED_VALUES: - _Py_SET_OPCODE(*instr, LOAD_METHOD_WITH_VALUES); + _Py_SET_OPCODE(*instr, LOAD_ATTR_METHOD_WITH_VALUES); break; case MANAGED_DICT: - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_LOAD_METHOD_HAS_MANAGED_DICT); + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_LOAD_METHOD_HAS_MANAGED_DICT); goto fail; case OFFSET_DICT: assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX); - _Py_SET_OPCODE(*instr, LOAD_METHOD_WITH_DICT); + _Py_SET_OPCODE(*instr, LOAD_ATTR_METHOD_WITH_DICT); break; case LAZY_DICT: assert(owner_cls->tp_dictoffset > 0 && owner_cls->tp_dictoffset <= INT16_MAX); - _Py_SET_OPCODE(*instr, LOAD_METHOD_LAZY_DICT); + _Py_SET_OPCODE(*instr, LOAD_ATTR_METHOD_LAZY_DICT); break; } /* `descr` is borrowed. This is safe for methods (even inherited ones from @@ -1041,15 +1022,8 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) write_u32(cache->type_version, owner_cls->tp_version_tag); write_obj(cache->descr, descr); // Fall through. -success: - STAT_INC(LOAD_METHOD, success); - assert(!PyErr_Occurred()); - cache->counter = miss_counter_start(); - return 0; + return 1; fail: - STAT_INC(LOAD_METHOD, failure); - assert(!PyErr_Occurred()); - cache->counter = adaptive_counter_backoff(cache->counter); return 0; } |