diff options
author | Guido van Rossum <guido@python.org> | 2023-10-04 15:08:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-04 15:08:02 (GMT) |
commit | 7c149a76b2bf4c66bb7c8650ffb71acce12f5ea2 (patch) | |
tree | 2dde159c7c323f1ce5e4535f3ca011992541d73d /Python/bytecodes.c | |
parent | d8c00d2a607242932359b995e4637c222fcb2284 (diff) | |
download | cpython-7c149a76b2bf4c66bb7c8650ffb71acce12f5ea2.zip cpython-7c149a76b2bf4c66bb7c8650ffb71acce12f5ea2.tar.gz cpython-7c149a76b2bf4c66bb7c8650ffb71acce12f5ea2.tar.bz2 |
gh-104909: Split more LOAD_ATTR specializations (GH-110317)
* Split LOAD_ATTR_MODULE
* Split LOAD_ATTR_WITH_HINT
* Split _GUARD_TYPE_VERSION out of the latter
* Split LOAD_ATTR_CLASS
* Split LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES
* Fix indent of DEOPT_IF in macros
* Split LOAD_ATTR_METHOD_LAZY_DICT
* Split LOAD_ATTR_NONDESCRIPTOR_NO_DICT
* Fix omission of _CHECK_ATTR_METHOD_LAZY_DICT
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r-- | Python/bytecodes.c | 101 |
1 files changed, 68 insertions, 33 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 08f8081..a96c5dd 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1887,11 +1887,15 @@ dummy_func( _LOAD_ATTR_INSTANCE_VALUE + unused/5; // Skip over rest of cache - inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) { + op(_CHECK_ATTR_MODULE, (type_version/2, owner -- owner)) { DEOPT_IF(!PyModule_CheckExact(owner)); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); DEOPT_IF(dict->ma_keys->dk_version != type_version); + } + + op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) { + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); assert(index < dict->ma_keys->dk_nentries); PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index; @@ -1903,19 +1907,26 @@ dummy_func( DECREF_INPUTS(); } - inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) { - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + macro(LOAD_ATTR_MODULE) = + unused/1 + + _CHECK_ATTR_MODULE + + _LOAD_ATTR_MODULE + + unused/5; + + op(_CHECK_ATTR_WITH_HINT, (owner -- owner)) { + assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(_PyDictOrValues_IsValues(dorv)); PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); - uint16_t hint = index; + } + + op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, null if (oparg & 1))) { + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries); + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name); @@ -1933,6 +1944,13 @@ dummy_func( DECREF_INPUTS(); } + macro(LOAD_ATTR_WITH_HINT) = + unused/1 + + _GUARD_TYPE_VERSION + + _CHECK_ATTR_WITH_HINT + + _LOAD_ATTR_WITH_HINT + + unused/5; + op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) { char *addr = (char *)owner + index; attr = *(PyObject **)addr; @@ -1949,20 +1967,27 @@ dummy_func( _LOAD_ATTR_SLOT + // NOTE: This action may also deopt unused/5; - inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, null if (oparg & 1))) { - + op(_CHECK_ATTR_CLASS, (type_version/2, owner -- owner)) { DEOPT_IF(!PyType_Check(owner)); - DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version); assert(type_version != 0); + DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version); + + } + op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr, null if (oparg & 1))) { STAT_INC(LOAD_ATTR, hit); + assert(descr != NULL); + attr = Py_NewRef(descr); null = NULL; - attr = descr; - assert(attr != NULL); - Py_INCREF(attr); DECREF_INPUTS(); } + macro(LOAD_ATTR_CLASS) = + unused/1 + + _CHECK_ATTR_CLASS + + unused/2 + + _LOAD_ATTR_CLASS; + inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused, unused if (0))) { assert((oparg & 1) == 0); DEOPT_IF(tstate->interp->eval_frame); @@ -2819,43 +2844,46 @@ dummy_func( unused/2 + _LOAD_ATTR_METHOD_NO_DICT; - inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, unused if (0))) { + op(_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (descr/4, owner -- attr, unused if (0))) { assert((oparg & 1) == 0); - PyTypeObject *owner_cls = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(owner_cls->tp_version_tag != type_version); - assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)); - PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; - DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); DECREF_INPUTS(); attr = Py_NewRef(descr); } - inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, unused if (0))) { + macro(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) = + unused/1 + + _GUARD_TYPE_VERSION + + _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + + _GUARD_KEYS_VERSION + + _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES; + + op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr, unused if (0))) { assert((oparg & 1) == 0); - PyTypeObject *owner_cls = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(owner_cls->tp_version_tag != type_version); - assert(owner_cls->tp_dictoffset == 0); + assert(Py_TYPE(owner)->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); DECREF_INPUTS(); attr = Py_NewRef(descr); } - inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) { - assert(oparg & 1); - PyTypeObject *owner_cls = Py_TYPE(owner); - DEOPT_IF(owner_cls->tp_version_tag != type_version); - Py_ssize_t dictoffset = owner_cls->tp_dictoffset; + macro(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) = + unused/1 + + _GUARD_TYPE_VERSION + + unused/2 + + _LOAD_ATTR_NONDESCRIPTOR_NO_DICT; + + op(_CHECK_ATTR_METHOD_LAZY_DICT, (owner -- owner)) { + Py_ssize_t dictoffset = Py_TYPE(owner)->tp_dictoffset; assert(dictoffset > 0); PyObject *dict = *(PyObject **)((char *)owner + dictoffset); /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL); + } + + op(_LOAD_ATTR_METHOD_LAZY_DICT, (descr/4, owner -- attr, self if (1))) { + assert(oparg & 1); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); @@ -2863,6 +2891,13 @@ dummy_func( self = owner; } + macro(LOAD_ATTR_METHOD_LAZY_DICT) = + unused/1 + + _GUARD_TYPE_VERSION + + _CHECK_ATTR_METHOD_LAZY_DICT + + unused/2 + + _LOAD_ATTR_METHOD_LAZY_DICT; + inst(INSTRUMENTED_CALL, ( -- )) { int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; |