diff options
author | Mark Shannon <mark@hotpy.org> | 2023-07-10 10:40:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-10 10:40:35 (GMT) |
commit | 0c90e7561046a2deb358e6695148060a1c199b49 (patch) | |
tree | 981359878b814a308c6fe977dd0c552e99bdd653 /Python/specialize.c | |
parent | 34c14147a2c52930b8b471905074509639e82d5b (diff) | |
download | cpython-0c90e7561046a2deb358e6695148060a1c199b49.zip cpython-0c90e7561046a2deb358e6695148060a1c199b49.tar.gz cpython-0c90e7561046a2deb358e6695148060a1c199b49.tar.bz2 |
GH-100288: Specialize LOAD_ATTR for simple class attributes. (#105990)
* Add two more specializations of LOAD_ATTR.
Diffstat (limited to 'Python/specialize.c')
-rw-r--r-- | Python/specialize.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/Python/specialize.c b/Python/specialize.c index a3fce2e..dcf4be7 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -711,8 +711,8 @@ specialize_dict_access( return 1; } -static int specialize_attr_loadmethod(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, - PyObject* descr, DescriptorClassification kind); +static int specialize_attr_loadclassattr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, + PyObject* descr, DescriptorClassification kind, bool is_method); static int specialize_class_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name); void @@ -753,7 +753,7 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) { int oparg = instr->op.arg; if (oparg & 1) { - if (specialize_attr_loadmethod(owner, instr, name, descr, kind)) { + if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, true)) { goto success; } } @@ -872,10 +872,14 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) SPEC_FAIL_ATTR_NOT_MANAGED_DICT); goto fail; case NON_DESCRIPTOR: - SPECIALIZATION_FAIL(LOAD_ATTR, - (type->tp_flags & Py_TPFLAGS_MANAGED_DICT) ? - SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE : - SPEC_FAIL_ATTR_NOT_MANAGED_DICT); + if ((instr->op.arg & 1) == 0) { + if (specialize_attr_loadclassattr(owner, instr, name, descr, kind, false)) { + goto success; + } + } + else { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); + } goto fail; case ABSENT: if (specialize_dict_access(owner, instr, type, kind, name, LOAD_ATTR, @@ -1064,13 +1068,14 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr, // can cause a significant drop in cache hits. A possible test is // python.exe -m test_typing test_re test_dis test_zlib. static int -specialize_attr_loadmethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, -PyObject *descr, DescriptorClassification kind) +specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, +PyObject *descr, DescriptorClassification kind, bool is_method) { _PyLoadMethodCache *cache = (_PyLoadMethodCache *)(instr + 1); PyTypeObject *owner_cls = Py_TYPE(owner); - assert(kind == METHOD && descr != NULL); + assert(descr != NULL); + assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR)); if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys; @@ -1090,7 +1095,7 @@ PyObject *descr, DescriptorClassification kind) return 0; } write_u32(cache->keys_version, keys_version); - instr->op.code = LOAD_ATTR_METHOD_WITH_VALUES; + instr->op.code = is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; } else { Py_ssize_t dictoffset = owner_cls->tp_dictoffset; @@ -1099,9 +1104,9 @@ PyObject *descr, DescriptorClassification kind) return 0; } if (dictoffset == 0) { - instr->op.code = LOAD_ATTR_METHOD_NO_DICT; + instr->op.code = is_method ? LOAD_ATTR_METHOD_NO_DICT : LOAD_ATTR_NONDESCRIPTOR_NO_DICT; } - else { + else if (is_method) { PyObject *dict = *(PyObject **) ((char *)owner + dictoffset); if (dict) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT); @@ -1111,6 +1116,10 @@ PyObject *descr, DescriptorClassification kind) assert(owner_cls->tp_dictoffset <= INT16_MAX); instr->op.code = LOAD_ATTR_METHOD_LAZY_DICT; } + else { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE); + return 0; + } } /* `descr` is borrowed. This is safe for methods (even inherited ones from * super classes!) as long as tp_version_tag is validated for two main reasons: |