diff options
author | Brandt Bucher <brandtbucher@microsoft.com> | 2023-08-09 18:19:39 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-09 18:19:39 (GMT) |
commit | a9caf9cf9041d6d0b69f8be0fd778dd1f9b50e74 (patch) | |
tree | 5e325bac9eda1b264d3e5fd32991eed91d243f16 /Python | |
parent | 0a7f48b9a8d54809f1e9272337aefe2444158e64 (diff) | |
download | cpython-a9caf9cf9041d6d0b69f8be0fd778dd1f9b50e74.zip cpython-a9caf9cf9041d6d0b69f8be0fd778dd1f9b50e74.tar.gz cpython-a9caf9cf9041d6d0b69f8be0fd778dd1f9b50e74.tar.bz2 |
GH-105848: Simplify the arrangement of CALL's stack (GH-107788)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bytecodes.c | 372 | ||||
-rw-r--r-- | Python/compile.c | 19 | ||||
-rw-r--r-- | Python/executor_cases.c.h | 231 | ||||
-rw-r--r-- | Python/flowgraph.c | 8 | ||||
-rw-r--r-- | Python/generated_cases.c.h | 555 | ||||
-rw-r--r-- | Python/specialize.c | 8 |
6 files changed, 567 insertions, 626 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index d6bfb62..b2281ab 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1315,7 +1315,7 @@ dummy_func( LOAD_GLOBAL_BUILTIN, }; - inst(LOAD_GLOBAL, (unused/1, unused/1, unused/1, unused/1 -- null if (oparg & 1), v)) { + inst(LOAD_GLOBAL, (unused/1, unused/1, unused/1, unused/1 -- res, null if (oparg & 1))) { #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1331,10 +1331,10 @@ dummy_func( if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { - v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); - if (v == NULL) { + res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (res == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ @@ -1343,17 +1343,17 @@ dummy_func( } ERROR_IF(true, error); } - Py_INCREF(v); + Py_INCREF(res); } else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0, error); - if (v == NULL) { + ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0, error); + if (res == NULL) { /* namespace 2: builtins */ - ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0, error); - if (v == NULL) { + ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0, error); + if (res == NULL) { _PyEval_FormatExcCheckArg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); @@ -1378,7 +1378,7 @@ dummy_func( assert(DK_IS_UNICODE(dict->ma_keys)); } - op(_LOAD_GLOBAL_MODULE, (index/1 -- null if (oparg & 1), res)) { + op(_LOAD_GLOBAL_MODULE, (index/1 -- res, null if (oparg & 1))) { PyDictObject *dict = (PyDictObject *)GLOBALS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); res = entries[index].me_value; @@ -1388,7 +1388,7 @@ dummy_func( null = NULL; } - op(_LOAD_GLOBAL_BUILTINS, (index/1 -- null if (oparg & 1), res)) { + op(_LOAD_GLOBAL_BUILTINS, (index/1 -- res, null if (oparg & 1))) { PyDictObject *bdict = (PyDictObject *)BUILTINS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); res = entries[index].me_value; @@ -1614,8 +1614,7 @@ dummy_func( ERROR_IF(map == NULL, error); } - inst(DICT_UPDATE, (update --)) { - PyObject *dict = PEEK(oparg + 1); // update is still on the stack + inst(DICT_UPDATE, (dict, unused[oparg - 1], update -- dict, unused[oparg - 1])) { if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Format(tstate, PyExc_TypeError, @@ -1628,26 +1627,23 @@ dummy_func( DECREF_INPUTS(); } - inst(DICT_MERGE, (update --)) { - PyObject *dict = PEEK(oparg + 1); // update is still on the stack - + inst(DICT_MERGE, (callable, unused, unused, dict, unused[oparg - 1], update -- callable, unused, unused, dict, unused[oparg - 1])) { if (_PyDict_MergeEx(dict, update, 2) < 0) { - _PyEval_FormatKwargsError(tstate, PEEK(3 + oparg), update); + _PyEval_FormatKwargsError(tstate, callable, update); DECREF_INPUTS(); ERROR_IF(true, error); } DECREF_INPUTS(); } - inst(MAP_ADD, (key, value --)) { - PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack + inst(MAP_ADD, (dict, unused[oparg - 1], key, value -- dict, unused[oparg - 1])) { assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references ERROR_IF(_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0, error); } - inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused if (oparg & 1), unused)) { + inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/9, unused, unused, unused -- unused, unused if (oparg & 1))) { _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr; // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we // don't want to specialize instrumented instructions @@ -1660,7 +1656,7 @@ dummy_func( LOAD_SUPER_ATTR_METHOD, }; - inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { + inst(LOAD_SUPER_ATTR, (unused/1, global_super, class, self -- attr, null if (oparg & 1))) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); int load_method = oparg & 1; #if ENABLE_SPECIALIZATION @@ -1704,9 +1700,10 @@ dummy_func( } DECREF_INPUTS(); ERROR_IF(super == NULL, error); - res = PyObject_GetAttr(super, name); + attr = PyObject_GetAttr(super, name); Py_DECREF(super); - ERROR_IF(res == NULL, error); + ERROR_IF(attr == NULL, error); + null = NULL; } pseudo(LOAD_SUPER_METHOD) = { @@ -1721,18 +1718,18 @@ dummy_func( LOAD_SUPER_ATTR, }; - inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- res2 if (oparg & 1), res)) { + inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super, class, self -- attr, unused if (0))) { assert(!(oparg & 1)); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); DECREF_INPUTS(); - ERROR_IF(res == NULL, error); + ERROR_IF(attr == NULL, error); } - inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- res2, res)) { + inst(LOAD_SUPER_ATTR_METHOD, (unused/1, global_super, class, self -- attr, self_or_null)) { assert(oparg & 1); DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR); DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); @@ -1740,20 +1737,19 @@ dummy_func( PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; - res2 = _PySuper_Lookup(cls, self, name, + attr = _PySuper_Lookup(cls, self, name, Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); - if (res2 == NULL) { + if (attr == NULL) { Py_DECREF(self); ERROR_IF(true, error); } if (method_found) { - res = self; // transfer ownership + self_or_null = self; // transfer ownership } else { Py_DECREF(self); - res = res2; - res2 = NULL; + self_or_null = NULL; } } @@ -1772,7 +1768,7 @@ dummy_func( LOAD_ATTR_NONDESCRIPTOR_NO_DICT, }; - inst(LOAD_ATTR, (unused/9, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR, (unused/9, owner -- attr, self_or_null if (oparg & 1))) { #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1787,16 +1783,15 @@ dummy_func( PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ - PyObject* meth = NULL; - if (_PyObject_GetMethod(owner, name, &meth)) { + attr = NULL; + if (_PyObject_GetMethod(owner, name, &attr)) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. meth | self | arg1 | ... | argN */ - assert(meth != NULL); // No errors on this branch - res2 = meth; - res = owner; // Transfer ownership + assert(attr != NULL); // No errors on this branch + self_or_null = owner; // Transfer ownership } else { /* meth is not an unbound method (but a regular attr, or @@ -1807,16 +1802,15 @@ dummy_func( NULL | meth | arg1 | ... | argN */ DECREF_INPUTS(); - ERROR_IF(meth == NULL, error); - res2 = NULL; - res = meth; + ERROR_IF(attr == NULL, error); + self_or_null = NULL; } } else { /* Classic, pushes one value. */ - res = PyObject_GetAttr(owner, name); + attr = PyObject_GetAttr(owner, name); DECREF_INPUTS(); - ERROR_IF(res == NULL, error); + ERROR_IF(attr == NULL, error); } } @@ -1837,13 +1831,13 @@ dummy_func( DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); } - op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- res2 if (oparg & 1), res)) { + op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, owner -- attr, null if (oparg & 1))) { PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - res = _PyDictOrValues_GetValues(dorv)->values[index]; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = _PyDictOrValues_GetValues(dorv)->values[index]; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; DECREF_INPUTS(); } @@ -1854,7 +1848,7 @@ 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 -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- attr, null if (oparg & 1))) { DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -1862,15 +1856,15 @@ dummy_func( 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; - res = ep->me_value; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = ep->me_value; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; DECREF_INPUTS(); } - inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + 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, LOAD_ATTR); @@ -1886,49 +1880,50 @@ dummy_func( if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); - res = ep->me_value; + attr = ep->me_value; } else { PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); - res = ep->me_value; + attr = ep->me_value; } - DEOPT_IF(res == NULL, LOAD_ATTR); + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; DECREF_INPUTS(); } - inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_SLOT, (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, LOAD_ATTR); char *addr = (char *)owner + index; - res = *(PyObject **)addr; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = *(PyObject **)addr; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; DECREF_INPUTS(); } - inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) { + inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, null if (oparg & 1))) { - DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); - DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, + DEOPT_IF(!PyType_Check(owner), LOAD_ATTR); + DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); STAT_INC(LOAD_ATTR, hit); - res2 = NULL; - res = descr; - assert(res != NULL); - Py_INCREF(res); + null = NULL; + attr = descr; + assert(attr != NULL); + Py_INCREF(attr); DECREF_INPUTS(); } - inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) { + 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, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -1945,16 +1940,15 @@ dummy_func( Py_INCREF(fget); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1); // Manipulate stack directly because we exit with DISPATCH_INLINED(). - SET_TOP(NULL); - int shrink_stack = !(oparg & 1); - STACK_SHRINK(shrink_stack); + STACK_SHRINK(1); new_frame->localsplus[0] = owner; SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); } - inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused if (oparg & 1), unused)) { + inst(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, (unused/1, type_version/2, func_version/2, getattribute/4, owner -- unused, unused if (0))) { + assert((oparg & 1) == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -1972,9 +1966,7 @@ dummy_func( Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). - SET_TOP(NULL); - int shrink_stack = !(oparg & 1); - STACK_SHRINK(shrink_stack); + STACK_SHRINK(1); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); @@ -2728,80 +2720,80 @@ dummy_func( exc_info->exc_value = Py_NewRef(new_exc); } - inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (1), res)) { + inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, self if (1))) { assert(oparg & 1); /* Cached method object */ - PyTypeObject *self_cls = Py_TYPE(self); + PyTypeObject *owner_cls = Py_TYPE(owner); assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; - DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - res2 = Py_NewRef(descr); - assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); - res = self; + attr = Py_NewRef(descr); + assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + self = owner; } - inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) { + inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) { assert(oparg & 1); - PyTypeObject *self_cls = Py_TYPE(self); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_dictoffset == 0); + PyTypeObject *owner_cls = Py_TYPE(owner); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); - res2 = Py_NewRef(descr); - res = self; + attr = Py_NewRef(descr); + self = owner; } - inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (0), res)) { + inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, unused if (0))) { assert((oparg & 1) == 0); - PyTypeObject *self_cls = Py_TYPE(self); + PyTypeObject *owner_cls = Py_TYPE(owner); assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; - DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); DECREF_INPUTS(); - res = Py_NewRef(descr); + attr = Py_NewRef(descr); } - inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (0), res)) { + inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, unused if (0))) { assert((oparg & 1) == 0); - PyTypeObject *self_cls = Py_TYPE(self); + PyTypeObject *owner_cls = Py_TYPE(owner); assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_dictoffset == 0); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); DECREF_INPUTS(); - res = Py_NewRef(descr); + attr = Py_NewRef(descr); } - inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) { + inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) { assert(oparg & 1); - PyTypeObject *self_cls = Py_TYPE(self); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - Py_ssize_t dictoffset = self_cls->tp_dictoffset; + PyTypeObject *owner_cls = Py_TYPE(owner); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + Py_ssize_t dictoffset = owner_cls->tp_dictoffset; assert(dictoffset > 0); - PyObject *dict = *(PyObject **)((char *)self + dictoffset); + PyObject *dict = *(PyObject **)((char *)owner + dictoffset); /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); - res2 = Py_NewRef(descr); - res = self; + attr = Py_NewRef(descr); + self = owner; } inst(KW_NAMES, (--)) { @@ -2811,9 +2803,9 @@ dummy_func( } inst(INSTRUMENTED_CALL, ( -- )) { - int is_meth = PEEK(oparg+2) != NULL; + int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; - PyObject *function = PEEK(total_args + 1); + PyObject *function = PEEK(oparg + 2); PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PEEK(total_args); int err = _Py_call_instrumentation_2args( @@ -2855,11 +2847,9 @@ dummy_func( // (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.) // On exit, the stack is [result]. // When calling Python, inline the call using DISPATCH_INLINED(). - inst(CALL, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - int is_meth = method != NULL; + inst(CALL, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -2873,13 +2863,12 @@ dummy_func( STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - if (!is_meth && Py_TYPE(callable) == &PyMethod_Type) { - is_meth = 1; // For consistenct; it's dead, though + if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) { args--; total_args++; PyObject *self = ((PyMethodObject *)callable)->im_self; args[0] = Py_NewRef(self); - method = ((PyMethodObject *)callable)->im_func; + PyObject *method = ((PyMethodObject *)callable)->im_func; args[-1] = Py_NewRef(method); Py_DECREF(callable); callable = method; @@ -2915,7 +2904,7 @@ dummy_func( kwnames); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? - &_PyInstrumentation_MISSING : PEEK(total_args); + &_PyInstrumentation_MISSING : args[0]; if (res == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, @@ -2943,25 +2932,23 @@ dummy_func( // Start out with [NULL, bound_method, arg1, arg2, ...] // Transform to [callable, self, arg1, arg2, ...] // Then fall through to CALL_PY_EXACT_ARGS - inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, method, callable, unused[oparg] -- unused)) { - DEOPT_IF(method != NULL, CALL); + inst(CALL_BOUND_METHOD_EXACT_ARGS, (unused/1, unused/2, callable, null, unused[oparg] -- unused)) { + DEOPT_IF(null != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); PyObject *self = ((PyMethodObject *)callable)->im_self; - PEEK(oparg + 1) = Py_NewRef(self); // callable + PEEK(oparg + 1) = Py_NewRef(self); // self_or_null PyObject *meth = ((PyMethodObject *)callable)->im_func; - PEEK(oparg + 2) = Py_NewRef(meth); // method + PEEK(oparg + 2) = Py_NewRef(meth); // callable Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); } - inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { + inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) { ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); - int is_meth = method != NULL; int argcount = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; argcount++; } @@ -2983,13 +2970,11 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) { + inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) { ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); - int is_meth = method != NULL; int argcount = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; argcount++; } @@ -3021,7 +3006,7 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3033,7 +3018,7 @@ dummy_func( Py_DECREF(&PyType_Type); // I.e., callable } - inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_STR_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3047,7 +3032,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3061,7 +3046,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, null, callable, args[oparg] -- unused)) { + inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) { /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -3124,11 +3109,9 @@ dummy_func( } } - inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { - int is_meth = method != NULL; + inst(CALL_BUILTIN_CLASS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3149,13 +3132,11 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_O functions */ ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3180,13 +3161,11 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3215,12 +3194,10 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) { + inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3250,13 +3227,11 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); /* len(o) */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3277,13 +3252,11 @@ dummy_func( ERROR_IF(res == NULL, error); } - inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) { + inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3307,19 +3280,19 @@ dummy_func( } // This is secretly a super-instruction - inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) { + inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) { ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); - assert(method != NULL); + assert(self != NULL); PyInterpreterState *interp = tstate->interp; - DEOPT_IF(method != interp->callable_cache.list_append, CALL); + DEOPT_IF(callable != interp->callable_cache.list_append, CALL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) { goto pop_1_error; // Since arg is DECREF'ed already } Py_DECREF(self); - Py_DECREF(method); + Py_DECREF(callable); STACK_SHRINK(3); // CALL + POP_TOP SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); @@ -3327,23 +3300,21 @@ dummy_func( DISPATCH(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) { + inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; DEOPT_IF(total_args != 2, CALL); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_O, CALL); PyObject *arg = args[1]; PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall @@ -3361,19 +3332,17 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { - int is_meth = method != NULL; + inst(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); - PyTypeObject *d_type = callable->d_common.d_type; + PyTypeObject *d_type = method->d_common.d_type; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); STAT_INC(CALL, hit); @@ -3393,21 +3362,20 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) { + inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } DEOPT_IF(total_args != 1, CALL); - PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; @@ -3425,22 +3393,20 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) { + inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; /* Builtin METH_FASTCALL methods, without keywords */ - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; @@ -3460,7 +3426,7 @@ dummy_func( GO_TO_INSTRUCTION(CALL_FUNCTION_EX); } - inst(CALL_FUNCTION_EX, (unused, func, callargs, kwargs if (oparg & 1) -- result)) { + inst(CALL_FUNCTION_EX, (func, unused, callargs, kwargs if (oparg & 1) -- result)) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -3523,7 +3489,7 @@ dummy_func( result = PyObject_Call(func, callargs, kwargs); } DECREF_INPUTS(); - assert(PEEK(3 + (oparg & 1)) == NULL); + assert(PEEK(2 + (oparg & 1)) == NULL); ERROR_IF(result == NULL, error); CHECK_EVAL_BREAKER(); } diff --git a/Python/compile.c b/Python/compile.c index b673e3a..68af5d6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2361,11 +2361,6 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) int is_generic = asdl_seq_LEN(type_params) > 0; - if (is_generic) { - // Used by the CALL to the type parameters function. - ADDOP(c, loc, PUSH_NULL); - } - funcflags = compiler_default_arguments(c, loc, args); if (funcflags == -1) { return ERROR; @@ -2436,8 +2431,12 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) Py_DECREF(co); if (num_typeparam_args > 0) { ADDOP_I(c, loc, SWAP, num_typeparam_args + 1); + ADDOP_I(c, loc, CALL, num_typeparam_args - 1); + } + else { + ADDOP(c, loc, PUSH_NULL); + ADDOP_I(c, loc, CALL, 0); } - ADDOP_I(c, loc, CALL, num_typeparam_args); } RETURN_IF_ERROR(compiler_apply_decorators(c, decos)); @@ -2565,8 +2564,8 @@ compiler_class_body(struct compiler *c, stmt_ty s, int firstlineno) // these instructions should be attributed to the class line, // not a decorator line loc = LOC(s); - ADDOP(c, loc, PUSH_NULL); ADDOP(c, loc, LOAD_BUILD_CLASS); + ADDOP(c, loc, PUSH_NULL); /* 3. load a function (or closure) made from the code object */ if (compiler_make_closure(c, loc, co, 0) < 0) { @@ -2598,7 +2597,6 @@ compiler_class(struct compiler *c, stmt_ty s) int is_generic = asdl_seq_LEN(type_params) > 0; if (is_generic) { Py_XSETREF(c->u->u_private, Py_NewRef(s->v.ClassDef.name)); - ADDOP(c, loc, PUSH_NULL); PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", s->v.ClassDef.name); if (!type_params_name) { @@ -2666,6 +2664,7 @@ compiler_class(struct compiler *c, stmt_ty s) return ERROR; } Py_DECREF(co); + ADDOP(c, loc, PUSH_NULL); ADDOP_I(c, loc, CALL, 0); } else { RETURN_IF_ERROR(compiler_call_helper(c, loc, 2, @@ -2716,7 +2715,6 @@ compiler_typealias(struct compiler *c, stmt_ty s) int is_generic = asdl_seq_LEN(type_params) > 0; PyObject *name = s->v.TypeAlias.name->v.Name.id; if (is_generic) { - ADDOP(c, loc, PUSH_NULL); PyObject *type_params_name = PyUnicode_FromFormat("<generic parameters of %U>", name); if (!type_params_name) { @@ -2756,6 +2754,7 @@ compiler_typealias(struct compiler *c, stmt_ty s) return ERROR; } Py_DECREF(co); + ADDOP(c, loc, PUSH_NULL); ADDOP_I(c, loc, CALL, 0); } RETURN_IF_ERROR(compiler_nameop(c, loc, name, Store)); @@ -4994,9 +4993,9 @@ compiler_call(struct compiler *c, expr_ty e) return SUCCESS; } RETURN_IF_ERROR(check_caller(c, e->v.Call.func)); + VISIT(c, expr, e->v.Call.func); location loc = LOC(e->v.Call.func); ADDOP(c, loc, PUSH_NULL); - VISIT(c, expr, e->v.Call.func); loc = LOC(e); return compiler_call_helper(c, loc, 0, e->v.Call.args, diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 27be8a3..d6d541a 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1062,8 +1062,8 @@ case LOAD_GLOBAL: { static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); + PyObject *res; PyObject *null = NULL; - PyObject *v; #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1079,10 +1079,10 @@ if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { - v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); - if (v == NULL) { + res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (res == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ @@ -1091,17 +1091,17 @@ } if (true) goto error; } - Py_INCREF(v); + Py_INCREF(res); } else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto error; - if (v == NULL) { + if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error; + if (res == NULL) { /* namespace 2: builtins */ - if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto error; - if (v == NULL) { + if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error; + if (res == NULL) { _PyEval_FormatExcCheckArg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); @@ -1112,8 +1112,8 @@ null = NULL; STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; } - stack_pointer[-1] = v; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } break; } @@ -1136,8 +1136,8 @@ } case _LOAD_GLOBAL_MODULE: { - PyObject *null = NULL; PyObject *res; + PyObject *null = NULL; uint16_t index = (uint16_t)operand; PyDictObject *dict = (PyDictObject *)GLOBALS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); @@ -1148,14 +1148,14 @@ null = NULL; STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } break; } case _LOAD_GLOBAL_BUILTINS: { - PyObject *null = NULL; PyObject *res; + PyObject *null = NULL; uint16_t index = (uint16_t)operand; PyDictObject *bdict = (PyDictObject *)BUILTINS(); PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); @@ -1166,8 +1166,8 @@ null = NULL; STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } break; } @@ -1445,8 +1445,9 @@ case DICT_UPDATE: { PyObject *update; + PyObject *dict; update = stack_pointer[-1]; - PyObject *dict = PEEK(oparg + 1); // update is still on the stack + dict = stack_pointer[-2 - (oparg - 1)]; if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Format(tstate, PyExc_TypeError, @@ -1463,11 +1464,13 @@ case DICT_MERGE: { PyObject *update; + PyObject *dict; + PyObject *callable; update = stack_pointer[-1]; - PyObject *dict = PEEK(oparg + 1); // update is still on the stack - + dict = stack_pointer[-2 - (oparg - 1)]; + callable = stack_pointer[-5 - (oparg - 1)]; if (_PyDict_MergeEx(dict, update, 2) < 0) { - _PyEval_FormatKwargsError(tstate, PEEK(3 + oparg), update); + _PyEval_FormatKwargsError(tstate, callable, update); Py_DECREF(update); if (true) goto pop_1_error; } @@ -1479,9 +1482,10 @@ case MAP_ADD: { PyObject *value; PyObject *key; + PyObject *dict; value = stack_pointer[-1]; key = stack_pointer[-2]; - PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack + dict = stack_pointer[-3 - (oparg - 1)]; assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references @@ -1494,8 +1498,7 @@ PyObject *self; PyObject *class; PyObject *global_super; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; self = stack_pointer[-1]; class = stack_pointer[-2]; global_super = stack_pointer[-3]; @@ -1504,15 +1507,13 @@ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - if (res == NULL) goto pop_3_error; + if (attr == NULL) goto pop_3_error; STACK_SHRINK(2); - STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (0 ? 1 : 0)] = attr; break; } @@ -1520,8 +1521,8 @@ PyObject *self; PyObject *class; PyObject *global_super; - PyObject *res2; - PyObject *res; + PyObject *attr; + PyObject *self_or_null; self = stack_pointer[-1]; class = stack_pointer[-2]; global_super = stack_pointer[-3]; @@ -1532,32 +1533,31 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; - res2 = _PySuper_Lookup(cls, self, name, + attr = _PySuper_Lookup(cls, self, name, Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); - if (res2 == NULL) { + if (attr == NULL) { Py_DECREF(self); if (true) goto pop_3_error; } if (method_found) { - res = self; // transfer ownership + self_or_null = self; // transfer ownership } else { Py_DECREF(self); - res = res2; - res2 = NULL; + self_or_null = NULL; } STACK_SHRINK(1); - stack_pointer[-2] = res2; - stack_pointer[-1] = res; + stack_pointer[-2] = attr; + stack_pointer[-1] = self_or_null; break; } case LOAD_ATTR: { static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *self_or_null = NULL; owner = stack_pointer[-1]; #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; @@ -1573,16 +1573,15 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ - PyObject* meth = NULL; - if (_PyObject_GetMethod(owner, name, &meth)) { + attr = NULL; + if (_PyObject_GetMethod(owner, name, &attr)) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. meth | self | arg1 | ... | argN */ - assert(meth != NULL); // No errors on this branch - res2 = meth; - res = owner; // Transfer ownership + assert(attr != NULL); // No errors on this branch + self_or_null = owner; // Transfer ownership } else { /* meth is not an unbound method (but a regular attr, or @@ -1593,20 +1592,19 @@ NULL | meth | arg1 | ... | argN */ Py_DECREF(owner); - if (meth == NULL) goto pop_1_error; - res2 = NULL; - res = meth; + if (attr == NULL) goto pop_1_error; + self_or_null = NULL; } } else { /* Classic, pushes one value. */ - res = PyObject_GetAttr(owner, name); + attr = PyObject_GetAttr(owner, name); Py_DECREF(owner); - if (res == NULL) goto pop_1_error; + if (attr == NULL) goto pop_1_error; } STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = self_or_null; } break; } @@ -1632,20 +1630,20 @@ case _LOAD_ATTR_INSTANCE_VALUE: { PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *null = NULL; owner = stack_pointer[-1]; uint16_t index = (uint16_t)operand; PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - res = _PyDictOrValues_GetValues(dorv)->values[index]; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = _PyDictOrValues_GetValues(dorv)->values[index]; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } break; } @@ -2157,12 +2155,12 @@ case CALL_NO_KW_TYPE_1: { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -2180,12 +2178,12 @@ case CALL_NO_KW_STR_1: { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -2205,12 +2203,12 @@ case CALL_NO_KW_TUPLE_1: { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -2244,18 +2242,16 @@ case CALL_NO_KW_BUILTIN_O: { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -2286,18 +2282,16 @@ case CALL_NO_KW_BUILTIN_FAST: { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -2332,18 +2326,16 @@ case CALL_NO_KW_LEN: { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); /* len(o) */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -2370,18 +2362,16 @@ case CALL_NO_KW_ISINSTANCE: { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -2410,26 +2400,26 @@ case CALL_NO_KW_METHOD_DESCRIPTOR_O: { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; DEOPT_IF(total_args != 2, CALL); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_O, CALL); PyObject *arg = args[1]; PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall @@ -2453,24 +2443,25 @@ case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } DEOPT_IF(total_args != 1, CALL); - PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; @@ -2494,25 +2485,25 @@ case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; /* Builtin METH_FASTCALL methods, without keywords */ - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index a72b85d..5b6b3f3 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1536,10 +1536,10 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) break; case KW_NAMES: break; - case PUSH_NULL: - if (nextop == LOAD_GLOBAL && (inst[1].i_opcode & 1) == 0) { - INSTR_SET_OP0(inst, NOP); - inst[1].i_oparg |= 1; + case LOAD_GLOBAL: + if (nextop == PUSH_NULL && (oparg & 1) == 0) { + INSTR_SET_OP1(inst, LOAD_GLOBAL, oparg | 1); + INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); } break; case COMPARE_OP: diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d7db8b0..cf20b86 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1695,8 +1695,8 @@ TARGET(LOAD_GLOBAL) { PREDICTED(LOAD_GLOBAL); static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); + PyObject *res; PyObject *null = NULL; - PyObject *v; #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1712,10 +1712,10 @@ if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { - v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); - if (v == NULL) { + res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (res == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ @@ -1724,17 +1724,17 @@ } if (true) goto error; } - Py_INCREF(v); + Py_INCREF(res); } else { /* Slow-path if globals or builtins is not a dict */ /* namespace 1: globals */ - if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto error; - if (v == NULL) { + if (PyMapping_GetOptionalItem(GLOBALS(), name, &res) < 0) goto error; + if (res == NULL) { /* namespace 2: builtins */ - if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto error; - if (v == NULL) { + if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error; + if (res == NULL) { _PyEval_FormatExcCheckArg( tstate, PyExc_NameError, NAME_ERROR_MSG, name); @@ -1745,15 +1745,15 @@ null = NULL; STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; } - stack_pointer[-1] = v; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 4; DISPATCH(); } TARGET(LOAD_GLOBAL_MODULE) { - PyObject *null = NULL; PyObject *res; + PyObject *null = NULL; // _GUARD_GLOBALS_VERSION { uint16_t version = read_u16(&next_instr[1].cache); @@ -1775,15 +1775,15 @@ } STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 4; DISPATCH(); } TARGET(LOAD_GLOBAL_BUILTIN) { - PyObject *null = NULL; PyObject *res; + PyObject *null = NULL; // _GUARD_GLOBALS_VERSION { uint16_t version = read_u16(&next_instr[1].cache); @@ -1813,8 +1813,8 @@ } STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = null; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 4; DISPATCH(); } @@ -2105,8 +2105,9 @@ TARGET(DICT_UPDATE) { PyObject *update; + PyObject *dict; update = stack_pointer[-1]; - PyObject *dict = PEEK(oparg + 1); // update is still on the stack + dict = stack_pointer[-2 - (oparg - 1)]; if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Format(tstate, PyExc_TypeError, @@ -2123,11 +2124,13 @@ TARGET(DICT_MERGE) { PyObject *update; + PyObject *dict; + PyObject *callable; update = stack_pointer[-1]; - PyObject *dict = PEEK(oparg + 1); // update is still on the stack - + dict = stack_pointer[-2 - (oparg - 1)]; + callable = stack_pointer[-5 - (oparg - 1)]; if (_PyDict_MergeEx(dict, update, 2) < 0) { - _PyEval_FormatKwargsError(tstate, PEEK(3 + oparg), update); + _PyEval_FormatKwargsError(tstate, callable, update); Py_DECREF(update); if (true) goto pop_1_error; } @@ -2139,9 +2142,10 @@ TARGET(MAP_ADD) { PyObject *value; PyObject *key; + PyObject *dict; value = stack_pointer[-1]; key = stack_pointer[-2]; - PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack + dict = stack_pointer[-3 - (oparg - 1)]; assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references @@ -2166,8 +2170,8 @@ PyObject *self; PyObject *class; PyObject *global_super; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *null = NULL; self = stack_pointer[-1]; class = stack_pointer[-2]; global_super = stack_pointer[-3]; @@ -2216,13 +2220,14 @@ Py_DECREF(class); Py_DECREF(self); if (super == NULL) goto pop_3_error; - res = PyObject_GetAttr(super, name); + attr = PyObject_GetAttr(super, name); Py_DECREF(super); - if (res == NULL) goto pop_3_error; + if (attr == NULL) goto pop_3_error; + null = NULL; STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 1; DISPATCH(); } @@ -2231,8 +2236,7 @@ PyObject *self; PyObject *class; PyObject *global_super; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; self = stack_pointer[-1]; class = stack_pointer[-2]; global_super = stack_pointer[-3]; @@ -2241,15 +2245,13 @@ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR); STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); - res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); + attr = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); - if (res == NULL) goto pop_3_error; + if (attr == NULL) goto pop_3_error; STACK_SHRINK(2); - STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (0 ? 1 : 0)] = attr; next_instr += 1; DISPATCH(); } @@ -2258,8 +2260,8 @@ PyObject *self; PyObject *class; PyObject *global_super; - PyObject *res2; - PyObject *res; + PyObject *attr; + PyObject *self_or_null; self = stack_pointer[-1]; class = stack_pointer[-2]; global_super = stack_pointer[-3]; @@ -2270,24 +2272,23 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); PyTypeObject *cls = (PyTypeObject *)class; int method_found = 0; - res2 = _PySuper_Lookup(cls, self, name, + attr = _PySuper_Lookup(cls, self, name, Py_TYPE(self)->tp_getattro == PyObject_GenericGetAttr ? &method_found : NULL); Py_DECREF(global_super); Py_DECREF(class); - if (res2 == NULL) { + if (attr == NULL) { Py_DECREF(self); if (true) goto pop_3_error; } if (method_found) { - res = self; // transfer ownership + self_or_null = self; // transfer ownership } else { Py_DECREF(self); - res = res2; - res2 = NULL; + self_or_null = NULL; } STACK_SHRINK(1); - stack_pointer[-2] = res2; - stack_pointer[-1] = res; + stack_pointer[-2] = attr; + stack_pointer[-1] = self_or_null; next_instr += 1; DISPATCH(); } @@ -2296,8 +2297,8 @@ PREDICTED(LOAD_ATTR); static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *self_or_null = NULL; owner = stack_pointer[-1]; #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; @@ -2313,16 +2314,15 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ - PyObject* meth = NULL; - if (_PyObject_GetMethod(owner, name, &meth)) { + attr = NULL; + if (_PyObject_GetMethod(owner, name, &attr)) { /* We can bypass temporary bound method object. meth is unbound method and obj is self. meth | self | arg1 | ... | argN */ - assert(meth != NULL); // No errors on this branch - res2 = meth; - res = owner; // Transfer ownership + assert(attr != NULL); // No errors on this branch + self_or_null = owner; // Transfer ownership } else { /* meth is not an unbound method (but a regular attr, or @@ -2333,28 +2333,27 @@ NULL | meth | arg1 | ... | argN */ Py_DECREF(owner); - if (meth == NULL) goto pop_1_error; - res2 = NULL; - res = meth; + if (attr == NULL) goto pop_1_error; + self_or_null = NULL; } } else { /* Classic, pushes one value. */ - res = PyObject_GetAttr(owner, name); + attr = PyObject_GetAttr(owner, name); Py_DECREF(owner); - if (res == NULL) goto pop_1_error; + if (attr == NULL) goto pop_1_error; } STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = self_or_null; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_INSTANCE_VALUE) { PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *null = NULL; // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -2374,24 +2373,24 @@ { uint16_t index = read_u16(&next_instr[3].cache); PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - res = _PyDictOrValues_GetValues(dorv)->values[index]; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = _PyDictOrValues_GetValues(dorv)->values[index]; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; Py_DECREF(owner); } STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_MODULE) { PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *null = NULL; owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); @@ -2402,23 +2401,23 @@ 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; - res = ep->me_value; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = ep->me_value; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_WITH_HINT) { PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *null = NULL; owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); @@ -2437,29 +2436,29 @@ if (DK_IS_UNICODE(dict->ma_keys)) { PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); - res = ep->me_value; + attr = ep->me_value; } else { PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; DEOPT_IF(ep->me_key != name, LOAD_ATTR); - res = ep->me_value; + attr = ep->me_value; } - DEOPT_IF(res == NULL, LOAD_ATTR); + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_SLOT) { PyObject *owner; - PyObject *res2 = NULL; - PyObject *res; + PyObject *attr; + PyObject *null = NULL; owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); @@ -2467,41 +2466,41 @@ assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); char *addr = (char *)owner + index; - res = *(PyObject **)addr; - DEOPT_IF(res == NULL, LOAD_ATTR); + attr = *(PyObject **)addr; + DEOPT_IF(attr == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - res2 = NULL; + Py_INCREF(attr); + null = NULL; Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_CLASS) { - PyObject *cls; - PyObject *res2 = NULL; - PyObject *res; - cls = stack_pointer[-1]; + PyObject *owner; + PyObject *attr; + PyObject *null = NULL; + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); - DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, + DEOPT_IF(!PyType_Check(owner), LOAD_ATTR); + DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version, LOAD_ATTR); assert(type_version != 0); STAT_INC(LOAD_ATTR, hit); - res2 = NULL; - res = descr; - assert(res != NULL); - Py_INCREF(res); - Py_DECREF(cls); + null = NULL; + attr = descr; + assert(attr != NULL); + Py_INCREF(attr); + Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); - if (oparg & 1) { stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res2; } - stack_pointer[-1] = res; + stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; + if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } next_instr += 9; DISPATCH(); } @@ -2512,6 +2511,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); + assert((oparg & 1) == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2528,14 +2528,11 @@ Py_INCREF(fget); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1); // Manipulate stack directly because we exit with DISPATCH_INLINED(). - SET_TOP(NULL); - int shrink_stack = !(oparg & 1); - STACK_SHRINK(shrink_stack); + STACK_SHRINK(1); new_frame->localsplus[0] = owner; SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - STACK_GROW(((oparg & 1) ? 1 : 0)); } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2544,6 +2541,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); + assert((oparg & 1) == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2561,15 +2559,12 @@ Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). - SET_TOP(NULL); - int shrink_stack = !(oparg & 1); - STACK_SHRINK(shrink_stack); + STACK_SHRINK(1); new_frame->localsplus[0] = owner; new_frame->localsplus[1] = Py_NewRef(name); SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - STACK_GROW(((oparg & 1) ? 1 : 0)); } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -3499,128 +3494,128 @@ } TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { + PyObject *owner; + PyObject *attr; PyObject *self; - PyObject *res2; - PyObject *res; - self = stack_pointer[-1]; + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); assert(oparg & 1); /* Cached method object */ - PyTypeObject *self_cls = Py_TYPE(self); + PyTypeObject *owner_cls = Py_TYPE(owner); assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; - DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - res2 = Py_NewRef(descr); - assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); - res = self; + attr = Py_NewRef(descr); + assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); + self = owner; STACK_GROW(1); - stack_pointer[-2] = res2; - stack_pointer[-1] = res; + stack_pointer[-2] = attr; + stack_pointer[-1] = self; next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_METHOD_NO_DICT) { + PyObject *owner; + PyObject *attr; PyObject *self; - PyObject *res2; - PyObject *res; - self = stack_pointer[-1]; + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); assert(oparg & 1); - PyTypeObject *self_cls = Py_TYPE(self); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_dictoffset == 0); + PyTypeObject *owner_cls = Py_TYPE(owner); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); - res2 = Py_NewRef(descr); - res = self; + attr = Py_NewRef(descr); + self = owner; STACK_GROW(1); - stack_pointer[-2] = res2; - stack_pointer[-1] = res; + stack_pointer[-2] = attr; + stack_pointer[-1] = self; next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) { - PyObject *self; - PyObject *res; - self = stack_pointer[-1]; + PyObject *owner; + PyObject *attr; + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); assert((oparg & 1) == 0); - PyTypeObject *self_cls = Py_TYPE(self); + PyTypeObject *owner_cls = Py_TYPE(owner); assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; - DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls; + DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - Py_DECREF(self); - res = Py_NewRef(descr); - stack_pointer[-1] = res; + Py_DECREF(owner); + attr = Py_NewRef(descr); + stack_pointer[-1 - (0 ? 1 : 0)] = attr; next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) { - PyObject *self; - PyObject *res; - self = stack_pointer[-1]; + PyObject *owner; + PyObject *attr; + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); assert((oparg & 1) == 0); - PyTypeObject *self_cls = Py_TYPE(self); + PyTypeObject *owner_cls = Py_TYPE(owner); assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_dictoffset == 0); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(owner_cls->tp_dictoffset == 0); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); - Py_DECREF(self); - res = Py_NewRef(descr); - stack_pointer[-1] = res; + Py_DECREF(owner); + attr = Py_NewRef(descr); + stack_pointer[-1 - (0 ? 1 : 0)] = attr; next_instr += 9; DISPATCH(); } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { + PyObject *owner; + PyObject *attr; PyObject *self; - PyObject *res2; - PyObject *res; - self = stack_pointer[-1]; + owner = stack_pointer[-1]; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); assert(oparg & 1); - PyTypeObject *self_cls = Py_TYPE(self); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - Py_ssize_t dictoffset = self_cls->tp_dictoffset; + PyTypeObject *owner_cls = Py_TYPE(owner); + DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR); + Py_ssize_t dictoffset = owner_cls->tp_dictoffset; assert(dictoffset > 0); - PyObject *dict = *(PyObject **)((char *)self + dictoffset); + PyObject *dict = *(PyObject **)((char *)owner + dictoffset); /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); assert(descr != NULL); assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)); - res2 = Py_NewRef(descr); - res = self; + attr = Py_NewRef(descr); + self = owner; STACK_GROW(1); - stack_pointer[-2] = res2; - stack_pointer[-1] = res; + stack_pointer[-2] = attr; + stack_pointer[-1] = self; next_instr += 9; DISPATCH(); } @@ -3633,9 +3628,9 @@ } TARGET(INSTRUMENTED_CALL) { - int is_meth = PEEK(oparg+2) != NULL; + int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; - PyObject *function = PEEK(total_args + 1); + PyObject *function = PEEK(oparg + 2); PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : PEEK(total_args); int err = _Py_call_instrumentation_2args( @@ -3651,16 +3646,14 @@ PREDICTED(CALL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; - int is_meth = method != NULL; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -3674,13 +3667,12 @@ STAT_INC(CALL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - if (!is_meth && Py_TYPE(callable) == &PyMethod_Type) { - is_meth = 1; // For consistenct; it's dead, though + if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) { args--; total_args++; PyObject *self = ((PyMethodObject *)callable)->im_self; args[0] = Py_NewRef(self); - method = ((PyMethodObject *)callable)->im_func; + PyObject *method = ((PyMethodObject *)callable)->im_func; args[-1] = Py_NewRef(method); Py_DECREF(callable); callable = method; @@ -3716,7 +3708,7 @@ kwnames); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? - &_PyInstrumentation_MISSING : PEEK(total_args); + &_PyInstrumentation_MISSING : args[0]; if (res == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, @@ -3747,17 +3739,17 @@ } TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { + PyObject *null; PyObject *callable; - PyObject *method; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; - DEOPT_IF(method != NULL, CALL); + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + DEOPT_IF(null != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); PyObject *self = ((PyMethodObject *)callable)->im_self; - PEEK(oparg + 1) = Py_NewRef(self); // callable + PEEK(oparg + 1) = Py_NewRef(self); // self_or_null PyObject *meth = ((PyMethodObject *)callable)->im_func; - PEEK(oparg + 2) = Py_NewRef(meth); // method + PEEK(oparg + 2) = Py_NewRef(meth); // callable Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); STACK_SHRINK(oparg); @@ -3767,18 +3759,16 @@ TARGET(CALL_PY_EXACT_ARGS) { PREDICTED(CALL_PY_EXACT_ARGS); PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&next_instr[1].cache); ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); - int is_meth = method != NULL; int argcount = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; argcount++; } @@ -3804,18 +3794,16 @@ TARGET(CALL_PY_WITH_DEFAULTS) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&next_instr[1].cache); ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); - int is_meth = method != NULL; int argcount = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; argcount++; } @@ -3851,12 +3839,12 @@ TARGET(CALL_NO_KW_TYPE_1) { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3875,12 +3863,12 @@ TARGET(CALL_NO_KW_STR_1) { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3901,12 +3889,12 @@ TARGET(CALL_NO_KW_TUPLE_1) { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3927,11 +3915,11 @@ TARGET(CALL_NO_KW_ALLOC_AND_ENTER_INIT) { PyObject **args; - PyObject *callable; PyObject *null; + PyObject *callable; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - null = stack_pointer[-2 - oparg]; + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4002,16 +3990,14 @@ TARGET(CALL_BUILTIN_CLASS) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; - int is_meth = method != NULL; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -4039,18 +4025,16 @@ TARGET(CALL_NO_KW_BUILTIN_O) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -4082,18 +4066,16 @@ TARGET(CALL_NO_KW_BUILTIN_FAST) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -4129,17 +4111,15 @@ TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -4176,18 +4156,16 @@ TARGET(CALL_NO_KW_LEN) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); /* len(o) */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -4215,18 +4193,16 @@ TARGET(CALL_NO_KW_ISINSTANCE) { PyObject **args; + PyObject *self_or_null; PyObject *callable; - PyObject *method; PyObject *res; args = stack_pointer - oparg; - callable = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { - callable = method; + if (self_or_null != NULL) { args--; total_args++; } @@ -4257,22 +4233,22 @@ TARGET(CALL_NO_KW_LIST_APPEND) { PyObject **args; PyObject *self; - PyObject *method; + PyObject *callable; args = stack_pointer - oparg; self = stack_pointer[-1 - oparg]; - method = stack_pointer[-2 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); - assert(method != NULL); + assert(self != NULL); PyInterpreterState *interp = tstate->interp; - DEOPT_IF(method != interp->callable_cache.list_append, CALL); + DEOPT_IF(callable != interp->callable_cache.list_append, CALL); DEOPT_IF(!PyList_Check(self), CALL); STAT_INC(CALL, hit); if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) { goto pop_1_error; // Since arg is DECREF'ed already } Py_DECREF(self); - Py_DECREF(method); + Py_DECREF(callable); STACK_SHRINK(3); // CALL + POP_TOP SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); @@ -4284,26 +4260,26 @@ TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; DEOPT_IF(total_args != 2, CALL); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_O, CALL); PyObject *arg = args[1]; PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; // This is slower but CPython promises to check all non-vectorcall @@ -4328,22 +4304,22 @@ TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; - int is_meth = method != NULL; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); - PyTypeObject *d_type = callable->d_common.d_type; + PyTypeObject *d_type = method->d_common.d_type; PyObject *self = args[0]; DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); STAT_INC(CALL, hit); @@ -4370,24 +4346,25 @@ TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } DEOPT_IF(total_args != 1, CALL); - PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); STAT_INC(CALL, hit); PyCFunction cfunc = meth->ml_meth; @@ -4412,25 +4389,25 @@ TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { PyObject **args; - PyObject *method; + PyObject *self_or_null; + PyObject *callable; PyObject *res; args = stack_pointer - oparg; - method = stack_pointer[-2 - oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; ASSERT_KWNAMES_IS_NULL(); - int is_meth = method != NULL; int total_args = oparg; - if (is_meth) { + if (self_or_null != NULL) { args--; total_args++; } - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; /* Builtin METH_FASTCALL methods, without keywords */ - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); PyObject *self = args[0]; - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; @@ -4463,7 +4440,7 @@ PyObject *result; if (oparg & 1) { kwargs = stack_pointer[-(oparg & 1 ? 1 : 0)]; } callargs = stack_pointer[-1 - (oparg & 1 ? 1 : 0)]; - func = stack_pointer[-2 - (oparg & 1 ? 1 : 0)]; + func = stack_pointer[-3 - (oparg & 1 ? 1 : 0)]; // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4528,7 +4505,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - assert(PEEK(3 + (oparg & 1)) == NULL); + assert(PEEK(2 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); diff --git a/Python/specialize.c b/Python/specialize.c index 855252e..98455ae 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -793,6 +793,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) if (!function_check_args(fget, 1, LOAD_ATTR)) { goto fail; } + if (instr->op.arg & 1) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); + goto fail; + } uint32_t version = function_get_version(fget, LOAD_ATTR); if (version == 0) { goto fail; @@ -859,6 +863,10 @@ _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name) if (!function_check_args(descr, 2, LOAD_ATTR)) { goto fail; } + if (instr->op.arg & 1) { + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD); + goto fail; + } uint32_t version = function_get_version(descr, LOAD_ATTR); if (version == 0) { goto fail; |