Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0c90e75

Browse files
authored
GH-100288: Specialize LOAD_ATTR for simple class attributes. (#105990)
* Add two more specializations of LOAD_ATTR.
1 parent 34c1414 commit 0c90e75

File tree

10 files changed

+405
-290
lines changed

10 files changed

+405
-290
lines changed

Include/internal/pycore_opcode.h

Lines changed: 20 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode.h

Lines changed: 27 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/_opcode_metadata.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
"LOAD_ATTR_METHOD_WITH_VALUES",
6464
"LOAD_ATTR_METHOD_NO_DICT",
6565
"LOAD_ATTR_METHOD_LAZY_DICT",
66+
"LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
67+
"LOAD_ATTR_NONDESCRIPTOR_NO_DICT",
6668
],
6769
"COMPARE_OP": [
6870
"COMPARE_OP_FLOAT",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Specialize :opcode:`LOAD_ATTR` for non-descriptors on the class. Adds
2+
:opcode:`LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES` and :opcode
3+
`LOAD_ATTR_NONDESCRIPTOR_NO_DICT`.

Python/bytecodes.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,8 @@ dummy_func(
18091809
LOAD_ATTR_METHOD_WITH_VALUES,
18101810
LOAD_ATTR_METHOD_NO_DICT,
18111811
LOAD_ATTR_METHOD_LAZY_DICT,
1812+
LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES,
1813+
LOAD_ATTR_NONDESCRIPTOR_NO_DICT,
18121814
};
18131815

18141816
inst(LOAD_ATTR, (unused/9, owner -- res2 if (oparg & 1), res)) {
@@ -2657,7 +2659,8 @@ dummy_func(
26572659
exc_info->exc_value = Py_NewRef(new_exc);
26582660
}
26592661

2660-
inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) {
2662+
inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (1), res)) {
2663+
assert(oparg & 1);
26612664
/* Cached method object */
26622665
PyTypeObject *self_cls = Py_TYPE(self);
26632666
assert(type_version != 0);
@@ -2673,10 +2676,10 @@ dummy_func(
26732676
res2 = Py_NewRef(descr);
26742677
assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR));
26752678
res = self;
2676-
assert(oparg & 1);
26772679
}
26782680

2679-
inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) {
2681+
inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) {
2682+
assert(oparg & 1);
26802683
PyTypeObject *self_cls = Py_TYPE(self);
26812684
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
26822685
assert(self_cls->tp_dictoffset == 0);
@@ -2685,10 +2688,39 @@ dummy_func(
26852688
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
26862689
res2 = Py_NewRef(descr);
26872690
res = self;
2688-
assert(oparg & 1);
26892691
}
26902692

2691-
inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) {
2693+
inst(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (0), res)) {
2694+
assert((oparg & 1) == 0);
2695+
PyTypeObject *self_cls = Py_TYPE(self);
2696+
assert(type_version != 0);
2697+
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
2698+
assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
2699+
PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
2700+
DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR);
2701+
PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
2702+
DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
2703+
keys_version, LOAD_ATTR);
2704+
STAT_INC(LOAD_ATTR, hit);
2705+
assert(descr != NULL);
2706+
DECREF_INPUTS();
2707+
res = Py_NewRef(descr);
2708+
}
2709+
2710+
inst(LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (0), res)) {
2711+
assert((oparg & 1) == 0);
2712+
PyTypeObject *self_cls = Py_TYPE(self);
2713+
assert(type_version != 0);
2714+
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
2715+
assert(self_cls->tp_dictoffset == 0);
2716+
STAT_INC(LOAD_ATTR, hit);
2717+
assert(descr != NULL);
2718+
DECREF_INPUTS();
2719+
res = Py_NewRef(descr);
2720+
}
2721+
2722+
inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (1), res)) {
2723+
assert(oparg & 1);
26922724
PyTypeObject *self_cls = Py_TYPE(self);
26932725
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
26942726
Py_ssize_t dictoffset = self_cls->tp_dictoffset;
@@ -2701,7 +2733,6 @@ dummy_func(
27012733
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
27022734
res2 = Py_NewRef(descr);
27032735
res = self;
2704-
assert(oparg & 1);
27052736
}
27062737

27072738
inst(KW_NAMES, (--)) {

0 commit comments

Comments
 (0)