summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2023-09-27 22:27:44 (GMT)
committerGitHub <noreply@github.com>2023-09-27 22:27:44 (GMT)
commit5bb6f0fcba663e1006f9063d1027ce8bd9f8effb (patch)
tree79cfb95b0d8d6582cfeca4f53b0a69ce2d24565f /Python
parent45cf5b0c69bb5c51f33fc681d90c45147e311ddf (diff)
downloadcpython-5bb6f0fcba663e1006f9063d1027ce8bd9f8effb.zip
cpython-5bb6f0fcba663e1006f9063d1027ce8bd9f8effb.tar.gz
cpython-5bb6f0fcba663e1006f9063d1027ce8bd9f8effb.tar.bz2
gh-104909: Split some more insts into ops (#109943)
These are the most popular specializations of `LOAD_ATTR` and `STORE_ATTR` that weren't already viable uops: * Split LOAD_ATTR_METHOD_WITH_VALUES * Split LOAD_ATTR_METHOD_NO_DICT * Split LOAD_ATTR_SLOT * Split STORE_ATTR_SLOT * Split STORE_ATTR_INSTANCE_VALUE Also: * Add `-v` flag to code generator which prints a list of non-viable uops (easter-egg: it can print execution counts -- see source) * Double _Py_UOP_MAX_TRACE_LENGTH to 128 I had dropped one of the DEOPT_IF() calls! :-(
Diffstat (limited to 'Python')
-rw-r--r--Python/abstract_interp_cases.c.h47
-rw-r--r--Python/bytecodes.c66
-rw-r--r--Python/executor_cases.c.h139
-rw-r--r--Python/generated_cases.c.h191
4 files changed, 355 insertions, 88 deletions
diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h
index 5a3848c..61b1db9 100644
--- a/Python/abstract_interp_cases.c.h
+++ b/Python/abstract_interp_cases.c.h
@@ -474,6 +474,31 @@
break;
}
+ case _LOAD_ATTR_SLOT: {
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1 - (oparg & 1 ? 1 : 0))), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-(oparg & 1 ? 1 : 0))), true);
+ break;
+ }
+
+ case _GUARD_DORV_VALUES: {
+ break;
+ }
+
+ case _STORE_ATTR_INSTANCE_VALUE: {
+ STACK_SHRINK(2);
+ break;
+ }
+
+ case _GUARD_TYPE_VERSION_STORE: {
+ break;
+ }
+
+ case _STORE_ATTR_SLOT: {
+ STACK_SHRINK(2);
+ break;
+ }
+
case COMPARE_OP: {
STACK_SHRINK(1);
PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
@@ -627,6 +652,28 @@
break;
}
+ case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: {
+ break;
+ }
+
+ case _GUARD_KEYS_VERSION: {
+ break;
+ }
+
+ case _LOAD_ATTR_METHOD_WITH_VALUES: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
+ case _LOAD_ATTR_METHOD_NO_DICT: {
+ STACK_GROW(1);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-2)), true);
+ PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true);
+ break;
+ }
+
case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
break;
}
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 402b271..0f89779 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1939,10 +1939,7 @@ dummy_func(
DECREF_INPUTS();
}
- 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);
+ op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) {
char *addr = (char *)owner + index;
attr = *(PyObject **)addr;
DEOPT_IF(attr == NULL, LOAD_ATTR);
@@ -1952,6 +1949,12 @@ dummy_func(
DECREF_INPUTS();
}
+ macro(LOAD_ATTR_SLOT) =
+ unused/1 +
+ _GUARD_TYPE_VERSION +
+ _LOAD_ATTR_SLOT + // NOTE: This action may also deopt
+ unused/5;
+
inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, null if (oparg & 1))) {
DEOPT_IF(!PyType_Check(owner), LOAD_ATTR);
@@ -2019,13 +2022,15 @@ dummy_func(
DISPATCH_INLINED(new_frame);
}
- inst(STORE_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, value, owner --)) {
+ op(_GUARD_DORV_VALUES, (owner -- owner)) {
PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
+ }
+
+ op(_STORE_ATTR_INSTANCE_VALUE, (index/1, value, owner --)) {
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
STAT_INC(STORE_ATTR, hit);
PyDictValues *values = _PyDictOrValues_GetValues(dorv);
PyObject *old_value = values->values[index];
@@ -2039,6 +2044,12 @@ dummy_func(
Py_DECREF(owner);
}
+ macro(STORE_ATTR_INSTANCE_VALUE) =
+ unused/1 +
+ _GUARD_TYPE_VERSION_STORE +
+ _GUARD_DORV_VALUES +
+ _STORE_ATTR_INSTANCE_VALUE;
+
inst(STORE_ATTR_WITH_HINT, (unused/1, type_version/2, hint/1, value, owner --)) {
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
@@ -2080,10 +2091,13 @@ dummy_func(
Py_DECREF(owner);
}
- inst(STORE_ATTR_SLOT, (unused/1, type_version/2, index/1, value, owner --)) {
+ op(_GUARD_TYPE_VERSION_STORE, (type_version/2, owner -- owner)) {
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
+ }
+
+ op(_STORE_ATTR_SLOT, (index/1, value, owner --)) {
char *addr = (char *)owner + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
@@ -2092,6 +2106,11 @@ dummy_func(
Py_DECREF(owner);
}
+ macro(STORE_ATTR_SLOT) =
+ unused/1 +
+ _GUARD_TYPE_VERSION_STORE +
+ _STORE_ATTR_SLOT;
+
family(COMPARE_OP, INLINE_CACHE_ENTRIES_COMPARE_OP) = {
COMPARE_OP_FLOAT,
COMPARE_OP_INT,
@@ -2769,20 +2788,25 @@ 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, owner -- attr, self if (1))) {
- assert(oparg & 1);
- /* Cached method object */
+ op(_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, (owner -- owner)) {
PyTypeObject *owner_cls = Py_TYPE(owner);
- assert(type_version != 0);
- 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) &&
!_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
LOAD_ATTR);
+ }
+
+ op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) {
+ PyTypeObject *owner_cls = Py_TYPE(owner);
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
keys_version, LOAD_ATTR);
+ }
+
+ op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self if (1))) {
+ assert(oparg & 1);
+ /* Cached method object */
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
attr = Py_NewRef(descr);
@@ -2790,10 +2814,16 @@ dummy_func(
self = owner;
}
- inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, owner -- attr, self if (1))) {
+ macro(LOAD_ATTR_METHOD_WITH_VALUES) =
+ unused/1 +
+ _GUARD_TYPE_VERSION +
+ _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT +
+ _GUARD_KEYS_VERSION +
+ _LOAD_ATTR_METHOD_WITH_VALUES;
+
+ op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self if (1))) {
assert(oparg & 1);
PyTypeObject *owner_cls = Py_TYPE(owner);
- DEOPT_IF(owner_cls->tp_version_tag != type_version, LOAD_ATTR);
assert(owner_cls->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
@@ -2802,6 +2832,12 @@ dummy_func(
self = owner;
}
+ macro(LOAD_ATTR_METHOD_NO_DICT) =
+ unused/1 +
+ _GUARD_TYPE_VERSION +
+ unused/2 +
+ _LOAD_ATTR_METHOD_NO_DICT;
+
inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, owner -- attr, unused if (0))) {
assert((oparg & 1) == 0);
PyTypeObject *owner_cls = Py_TYPE(owner);
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index befb972..981db69 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -1714,6 +1714,83 @@
break;
}
+ case _LOAD_ATTR_SLOT: {
+ PyObject *owner;
+ PyObject *attr;
+ PyObject *null = NULL;
+ owner = stack_pointer[-1];
+ uint16_t index = (uint16_t)operand;
+ char *addr = (char *)owner + index;
+ attr = *(PyObject **)addr;
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
+ STAT_INC(LOAD_ATTR, hit);
+ Py_INCREF(attr);
+ null = NULL;
+ Py_DECREF(owner);
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
+ if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
+ break;
+ }
+
+ case _GUARD_DORV_VALUES: {
+ PyObject *owner;
+ owner = stack_pointer[-1];
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
+ break;
+ }
+
+ case _STORE_ATTR_INSTANCE_VALUE: {
+ PyObject *owner;
+ PyObject *value;
+ owner = stack_pointer[-1];
+ value = stack_pointer[-2];
+ uint16_t index = (uint16_t)operand;
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ STAT_INC(STORE_ATTR, hit);
+ PyDictValues *values = _PyDictOrValues_GetValues(dorv);
+ PyObject *old_value = values->values[index];
+ values->values[index] = value;
+ if (old_value == NULL) {
+ _PyDictValues_AddToInsertionOrder(values, index);
+ }
+ else {
+ Py_DECREF(old_value);
+ }
+ Py_DECREF(owner);
+ STACK_SHRINK(2);
+ break;
+ }
+
+ case _GUARD_TYPE_VERSION_STORE: {
+ PyObject *owner;
+ owner = stack_pointer[-1];
+ uint32_t type_version = (uint32_t)operand;
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
+ break;
+ }
+
+ case _STORE_ATTR_SLOT: {
+ PyObject *owner;
+ PyObject *value;
+ owner = stack_pointer[-1];
+ value = stack_pointer[-2];
+ uint16_t index = (uint16_t)operand;
+ char *addr = (char *)owner + index;
+ STAT_INC(STORE_ATTR, hit);
+ PyObject *old_value = *(PyObject **)addr;
+ *(PyObject **)addr = value;
+ Py_XDECREF(old_value);
+ Py_DECREF(owner);
+ STACK_SHRINK(2);
+ break;
+ }
+
case COMPARE_OP: {
PyObject *right;
PyObject *left;
@@ -2219,6 +2296,68 @@
break;
}
+ case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT: {
+ PyObject *owner;
+ owner = stack_pointer[-1];
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
+ break;
+ }
+
+ case _GUARD_KEYS_VERSION: {
+ PyObject *owner;
+ owner = stack_pointer[-1];
+ uint32_t keys_version = (uint32_t)operand;
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
+ DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
+ keys_version, LOAD_ATTR);
+ break;
+ }
+
+ case _LOAD_ATTR_METHOD_WITH_VALUES: {
+ PyObject *owner;
+ PyObject *attr;
+ PyObject *self;
+ owner = stack_pointer[-1];
+ PyObject *descr = (PyObject *)operand;
+ assert(oparg & 1);
+ /* Cached method object */
+ STAT_INC(LOAD_ATTR, hit);
+ assert(descr != NULL);
+ attr = Py_NewRef(descr);
+ assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
+ self = owner;
+ STACK_GROW(1);
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self;
+ break;
+ }
+
+ case _LOAD_ATTR_METHOD_NO_DICT: {
+ PyObject *owner;
+ PyObject *attr;
+ PyObject *self;
+ owner = stack_pointer[-1];
+ PyObject *descr = (PyObject *)operand;
+ assert(oparg & 1);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ assert(owner_cls->tp_dictoffset == 0);
+ STAT_INC(LOAD_ATTR, hit);
+ assert(descr != NULL);
+ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
+ attr = Py_NewRef(descr);
+ self = owner;
+ STACK_GROW(1);
+ stack_pointer[-2] = attr;
+ stack_pointer[-1] = self;
+ break;
+ }
+
case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: {
PyObject *null;
PyObject *callable;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index ebb87a8..17df440 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2504,19 +2504,25 @@
PyObject *owner;
PyObject *attr;
PyObject *null = NULL;
+ // _GUARD_TYPE_VERSION
owner = stack_pointer[-1];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint16_t index = read_u16(&next_instr[3].cache);
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
- char *addr = (char *)owner + index;
- attr = *(PyObject **)addr;
- DEOPT_IF(attr == NULL, LOAD_ATTR);
- STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(attr);
- null = NULL;
- Py_DECREF(owner);
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ }
+ // _LOAD_ATTR_SLOT
+ {
+ uint16_t index = read_u16(&next_instr[3].cache);
+ char *addr = (char *)owner + index;
+ attr = *(PyObject **)addr;
+ DEOPT_IF(attr == NULL, LOAD_ATTR);
+ STAT_INC(LOAD_ATTR, hit);
+ Py_INCREF(attr);
+ null = NULL;
+ Py_DECREF(owner);
+ }
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr;
if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; }
@@ -2615,27 +2621,38 @@
TARGET(STORE_ATTR_INSTANCE_VALUE) {
PyObject *owner;
PyObject *value;
+ // _GUARD_TYPE_VERSION_STORE
owner = stack_pointer[-1];
- value = stack_pointer[-2];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint16_t index = read_u16(&next_instr[3].cache);
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
- DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
- STAT_INC(STORE_ATTR, hit);
- PyDictValues *values = _PyDictOrValues_GetValues(dorv);
- PyObject *old_value = values->values[index];
- values->values[index] = value;
- if (old_value == NULL) {
- _PyDictValues_AddToInsertionOrder(values, index);
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
}
- else {
- Py_DECREF(old_value);
+ // _GUARD_DORV_VALUES
+ {
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR);
+ }
+ // _STORE_ATTR_INSTANCE_VALUE
+ value = stack_pointer[-2];
+ {
+ uint16_t index = read_u16(&next_instr[3].cache);
+ PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner);
+ STAT_INC(STORE_ATTR, hit);
+ PyDictValues *values = _PyDictOrValues_GetValues(dorv);
+ PyObject *old_value = values->values[index];
+ values->values[index] = value;
+ if (old_value == NULL) {
+ _PyDictValues_AddToInsertionOrder(values, index);
+ }
+ else {
+ Py_DECREF(old_value);
+ }
+ Py_DECREF(owner);
}
- Py_DECREF(owner);
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -2694,19 +2711,25 @@
TARGET(STORE_ATTR_SLOT) {
PyObject *owner;
PyObject *value;
+ // _GUARD_TYPE_VERSION_STORE
owner = stack_pointer[-1];
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
+ }
+ // _STORE_ATTR_SLOT
value = stack_pointer[-2];
- uint32_t type_version = read_u32(&next_instr[1].cache);
- uint16_t index = read_u16(&next_instr[3].cache);
- PyTypeObject *tp = Py_TYPE(owner);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- char *addr = (char *)owner + index;
- STAT_INC(STORE_ATTR, hit);
- PyObject *old_value = *(PyObject **)addr;
- *(PyObject **)addr = value;
- Py_XDECREF(old_value);
- Py_DECREF(owner);
+ {
+ uint16_t index = read_u16(&next_instr[3].cache);
+ char *addr = (char *)owner + index;
+ STAT_INC(STORE_ATTR, hit);
+ PyObject *old_value = *(PyObject **)addr;
+ *(PyObject **)addr = value;
+ Py_XDECREF(old_value);
+ Py_DECREF(owner);
+ }
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -3557,28 +3580,42 @@
PyObject *owner;
PyObject *attr;
PyObject *self;
+ // _GUARD_TYPE_VERSION
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 *owner_cls = Py_TYPE(owner);
- assert(type_version != 0);
- 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) &&
- !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
- LOAD_ATTR);
- 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);
- attr = Py_NewRef(descr);
- assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
- self = owner;
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ }
+ // _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT
+ {
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ assert(owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
+ PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner);
+ DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) &&
+ !_PyObject_MakeInstanceAttributesFromDict(owner, dorv),
+ LOAD_ATTR);
+ }
+ // _GUARD_KEYS_VERSION
+ {
+ uint32_t keys_version = read_u32(&next_instr[3].cache);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
+ DEOPT_IF(owner_heap_type->ht_cached_keys->dk_version !=
+ keys_version, LOAD_ATTR);
+ }
+ // _LOAD_ATTR_METHOD_WITH_VALUES
+ {
+ PyObject *descr = read_obj(&next_instr[5].cache);
+ assert(oparg & 1);
+ /* Cached method object */
+ STAT_INC(LOAD_ATTR, hit);
+ assert(descr != NULL);
+ attr = Py_NewRef(descr);
+ assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR));
+ self = owner;
+ }
STACK_GROW(1);
stack_pointer[-2] = attr;
stack_pointer[-1] = self;
@@ -3590,18 +3627,26 @@
PyObject *owner;
PyObject *attr;
PyObject *self;
+ // _GUARD_TYPE_VERSION
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 *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));
- attr = Py_NewRef(descr);
- self = owner;
+ {
+ uint32_t type_version = read_u32(&next_instr[1].cache);
+ PyTypeObject *tp = Py_TYPE(owner);
+ assert(type_version != 0);
+ DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
+ }
+ // _LOAD_ATTR_METHOD_NO_DICT
+ {
+ PyObject *descr = read_obj(&next_instr[5].cache);
+ assert(oparg & 1);
+ PyTypeObject *owner_cls = Py_TYPE(owner);
+ assert(owner_cls->tp_dictoffset == 0);
+ STAT_INC(LOAD_ATTR, hit);
+ assert(descr != NULL);
+ assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
+ attr = Py_NewRef(descr);
+ self = owner;
+ }
STACK_GROW(1);
stack_pointer[-2] = attr;
stack_pointer[-1] = self;