mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
Revert "GH-128914: Remove conditional stack effects from bytecodes.c
and the code generators (GH-128918)" (GH-129202)
The commit introduced a ~2.5-3% regression in the free threading build.
This reverts commit ab61d3f430
.
This commit is contained in:
parent
d7d066c3ab
commit
a10f99375e
44 changed files with 1679 additions and 1460 deletions
|
@ -804,7 +804,7 @@ _Py_Specialize_LoadSuperAttr(_PyStackRef global_super_st, _PyStackRef cls_st, _P
|
|||
SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_BAD_CLASS);
|
||||
goto fail;
|
||||
}
|
||||
uint8_t load_code = load_method ? LOAD_SUPER_METHOD_METHOD : LOAD_SUPER_ATTR_ATTR;
|
||||
uint8_t load_code = load_method ? LOAD_SUPER_ATTR_METHOD : LOAD_SUPER_ATTR_ATTR;
|
||||
specialize(instr, load_code);
|
||||
return;
|
||||
fail:
|
||||
|
@ -1109,7 +1109,7 @@ instance_has_key(PyObject *obj, PyObject *name, uint32_t *shared_keys_version)
|
|||
static int
|
||||
do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name,
|
||||
bool shadow, uint32_t shared_keys_version,
|
||||
DescriptorClassification kind, PyObject *descr, unsigned int tp_version, bool load_method)
|
||||
DescriptorClassification kind, PyObject *descr, unsigned int tp_version)
|
||||
{
|
||||
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
||||
PyTypeObject *type = Py_TYPE(owner);
|
||||
|
@ -1117,16 +1117,17 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
|
||||
return -1;
|
||||
}
|
||||
uint8_t oparg = FT_ATOMIC_LOAD_UINT8_RELAXED(instr->op.arg);
|
||||
switch(kind) {
|
||||
case OVERRIDING:
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
|
||||
return -1;
|
||||
case METHOD:
|
||||
{
|
||||
if (shadow) {
|
||||
goto try_instance;
|
||||
}
|
||||
if (load_method) {
|
||||
if (oparg & 1) {
|
||||
if (specialize_attr_loadclassattr(owner, instr, name, descr,
|
||||
tp_version, kind, true,
|
||||
shared_keys_version)) {
|
||||
|
@ -1136,7 +1137,7 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
return -1;
|
||||
}
|
||||
case PROPERTY:
|
||||
|
@ -1145,28 +1146,28 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
assert(Py_TYPE(descr) == &PyProperty_Type);
|
||||
PyObject *fget = ((_PyPropertyObject *)descr)->prop_get;
|
||||
if (fget == NULL) {
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_EXPECTED_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if (!Py_IS_TYPE(fget, &PyFunction_Type)) {
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
|
||||
return -1;
|
||||
}
|
||||
if (load_method) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_ATTR_METHOD);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_PROPERTY_NOT_PY_FUNCTION);
|
||||
return -1;
|
||||
}
|
||||
if (!function_check_args(fget, 1, LOAD_ATTR)) {
|
||||
return -1;
|
||||
}
|
||||
if (oparg & 1) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
return -1;
|
||||
}
|
||||
/* Don't specialize if PEP 523 is active */
|
||||
if (_PyInterpreterState_GET()->eval_frame) {
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_OTHER);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER);
|
||||
return -1;
|
||||
}
|
||||
#ifdef Py_GIL_DISABLED
|
||||
if (!_PyObject_HasDeferredRefcount(fget)) {
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -1179,10 +1180,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
}
|
||||
case OBJECT_SLOT:
|
||||
{
|
||||
if (load_method) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
return -1;
|
||||
}
|
||||
PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
|
||||
struct PyMemberDef *dmem = member->d_member;
|
||||
Py_ssize_t offset = dmem->offset;
|
||||
|
@ -1207,10 +1204,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
}
|
||||
case DUNDER_CLASS:
|
||||
{
|
||||
if (load_method) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
return -1;
|
||||
}
|
||||
Py_ssize_t offset = offsetof(PyObject, ob_type);
|
||||
assert(offset == (uint16_t)offset);
|
||||
cache->index = (uint16_t)offset;
|
||||
|
@ -1219,20 +1212,16 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
return 0;
|
||||
}
|
||||
case OTHER_SLOT:
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NON_OBJECT_SLOT);
|
||||
return -1;
|
||||
case MUTABLE:
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
|
||||
return -1;
|
||||
case GETSET_OVERRIDDEN:
|
||||
SPECIALIZATION_FAIL(load_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_OVERRIDDEN);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN);
|
||||
return -1;
|
||||
case GETATTRIBUTE_IS_PYTHON_FUNCTION:
|
||||
{
|
||||
if (load_method) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
return -1;
|
||||
}
|
||||
#ifndef Py_GIL_DISABLED
|
||||
// In free-threaded builds it's possible for tp_getattro to change
|
||||
// after the call to analyze_descriptor. That is fine: the version
|
||||
|
@ -1244,6 +1233,10 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
if (!function_check_args(descr, 2, LOAD_ATTR)) {
|
||||
return -1;
|
||||
}
|
||||
if (oparg & 1) {
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_METHOD);
|
||||
return -1;
|
||||
}
|
||||
uint32_t version = function_get_version(descr, LOAD_ATTR);
|
||||
if (version == 0) {
|
||||
return -1;
|
||||
|
@ -1277,7 +1270,7 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
if (shadow) {
|
||||
goto try_instance;
|
||||
}
|
||||
if (!load_method) {
|
||||
if ((oparg & 1) == 0) {
|
||||
if (specialize_attr_loadclassattr(owner, instr, name, descr,
|
||||
tp_version, kind, false,
|
||||
shared_keys_version)) {
|
||||
|
@ -1294,10 +1287,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
|
|||
}
|
||||
Py_UNREACHABLE();
|
||||
try_instance:
|
||||
if (load_method) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
return -1;
|
||||
}
|
||||
if (specialize_dict_access(owner, instr, type, kind, name, tp_version,
|
||||
LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, LOAD_ATTR_WITH_HINT))
|
||||
{
|
||||
|
@ -1307,7 +1296,7 @@ try_instance:
|
|||
}
|
||||
|
||||
static int
|
||||
specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name, bool load_method)
|
||||
specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name)
|
||||
{
|
||||
// 0 is not a valid version
|
||||
uint32_t shared_keys_version = 0;
|
||||
|
@ -1316,7 +1305,7 @@ specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* na
|
|||
unsigned int tp_version = 0;
|
||||
PyTypeObject *type = Py_TYPE(owner);
|
||||
DescriptorClassification kind = analyze_descriptor_load(type, name, &descr, &tp_version);
|
||||
int result = do_specialize_instance_load_attr(owner, instr, name, shadow, shared_keys_version, kind, descr, tp_version, load_method);
|
||||
int result = do_specialize_instance_load_attr(owner, instr, name, shadow, shared_keys_version, kind, descr, tp_version);
|
||||
Py_XDECREF(descr);
|
||||
return result;
|
||||
}
|
||||
|
@ -1344,40 +1333,7 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam
|
|||
fail = specialize_class_load_attr(owner, instr, name);
|
||||
}
|
||||
else {
|
||||
fail = specialize_instance_load_attr(owner, instr, name, false);
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
unspecialize(instr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_Py_Specialize_LoadMethod(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *name)
|
||||
{
|
||||
PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st);
|
||||
|
||||
assert(ENABLE_SPECIALIZATION_FT);
|
||||
assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR);
|
||||
PyTypeObject *type = Py_TYPE(owner);
|
||||
bool fail;
|
||||
if (!_PyType_IsReady(type)) {
|
||||
// We *might* not really need this check, but we inherited it from
|
||||
// PyObject_GenericGetAttr and friends... and this way we still do the
|
||||
// right thing if someone forgets to call PyType_Ready(type):
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
fail = true;
|
||||
}
|
||||
else if (Py_TYPE(owner)->tp_getattro == PyModule_Type.tp_getattro) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
fail = true;
|
||||
}
|
||||
else if (PyType_Check(owner)) {
|
||||
SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OTHER);
|
||||
fail = true;
|
||||
}
|
||||
else {
|
||||
fail = specialize_instance_load_attr(owner, instr, name, true);
|
||||
fail = specialize_instance_load_attr(owner, instr, name);
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
|
@ -1619,7 +1575,7 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr,
|
|||
|
||||
#ifdef Py_GIL_DISABLED
|
||||
if (!_PyObject_HasDeferredRefcount(descr)) {
|
||||
SPECIALIZATION_FAIL(is_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1631,11 +1587,11 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr,
|
|||
((PyHeapTypeObject *)owner_cls)->ht_cached_keys, name) < 0);
|
||||
#endif
|
||||
if (shared_keys_version == 0) {
|
||||
SPECIALIZATION_FAIL(is_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
|
||||
return 0;
|
||||
}
|
||||
write_u32(cache->keys_version, shared_keys_version);
|
||||
specialize(instr, is_method ? LOAD_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES);
|
||||
specialize(instr, is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES);
|
||||
}
|
||||
else {
|
||||
Py_ssize_t dictoffset;
|
||||
|
@ -1645,17 +1601,17 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr,
|
|||
else {
|
||||
dictoffset = owner_cls->tp_dictoffset;
|
||||
if (dictoffset < 0 || dictoffset > INT16_MAX + MANAGED_DICT_OFFSET) {
|
||||
SPECIALIZATION_FAIL(is_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_RANGE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (dictoffset == 0) {
|
||||
specialize(instr, is_method ? LOAD_METHOD_NO_DICT : LOAD_ATTR_NONDESCRIPTOR_NO_DICT);
|
||||
specialize(instr, is_method ? LOAD_ATTR_METHOD_NO_DICT : LOAD_ATTR_NONDESCRIPTOR_NO_DICT);
|
||||
}
|
||||
else if (is_method) {
|
||||
PyObject *dict = *(PyObject **) ((char *)owner + dictoffset);
|
||||
if (dict) {
|
||||
SPECIALIZATION_FAIL(is_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_NOT_MANAGED_DICT);
|
||||
return 0;
|
||||
}
|
||||
/* Cache entries must be unsigned values, so we offset the
|
||||
|
@ -1664,10 +1620,10 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr,
|
|||
dictoffset -= MANAGED_DICT_OFFSET;
|
||||
assert(((uint16_t)dictoffset) == dictoffset);
|
||||
cache->dict_offset = (uint16_t)dictoffset;
|
||||
specialize(instr, LOAD_METHOD_LAZY_DICT);
|
||||
specialize(instr, LOAD_ATTR_METHOD_LAZY_DICT);
|
||||
}
|
||||
else {
|
||||
SPECIALIZATION_FAIL(is_method ? LOAD_METHOD : LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE);
|
||||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_CLASS_ATTR_SIMPLE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue