mirror of
https://github.com/python/cpython.git
synced 2025-07-19 17:25:54 +00:00
GH-105848: Simplify the arrangement of CALL's stack (GH-107788)
This commit is contained in:
parent
0a7f48b9a8
commit
a9caf9cf90
16 changed files with 627 additions and 682 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
231
Python/executor_cases.c.h
generated
231
Python/executor_cases.c.h
generated
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
555
Python/generated_cases.c.h
generated
555
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue