Skip to content

Commit 09804cd

Browse files
committed
specialize LOAD_SUPER_ATTR for methods
1 parent 92c943b commit 09804cd

File tree

9 files changed

+433
-278
lines changed

9 files changed

+433
-278
lines changed

Include/internal/pycore_code.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ typedef struct {
5151

5252
#define INLINE_CACHE_ENTRIES_BINARY_SUBSCR CACHE_ENTRIES(_PyBinarySubscrCache)
5353

54+
typedef struct {
55+
uint16_t counter;
56+
uint16_t class_version[2];
57+
uint16_t self_type_version[2];
58+
uint16_t method[4];
59+
} _PySuperAttrCache;
60+
61+
#define INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR CACHE_ENTRIES(_PySuperAttrCache)
62+
5463
typedef struct {
5564
uint16_t counter;
5665
uint16_t version[2];
@@ -217,6 +226,8 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);
217226

218227
/* Specialization functions */
219228

229+
extern void _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *class, PyObject *self,
230+
_Py_CODEUNIT *instr, PyObject *name, int load_method);
220231
extern void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr,
221232
PyObject *name);
222233
extern void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr,

Include/internal/pycore_opcode.h

Lines changed: 13 additions & 12 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 & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ def pseudo_op(name, op, real_ops):
353353
"FOR_ITER_RANGE",
354354
"FOR_ITER_GEN",
355355
],
356+
"LOAD_SUPER_ATTR": [
357+
"LOAD_SUPER_ATTR_METHOD",
358+
],
356359
"LOAD_ATTR": [
357360
# These potentially push [NULL, bound method] onto the stack.
358361
"LOAD_ATTR_CLASS",
@@ -426,6 +429,12 @@ def pseudo_op(name, op, real_ops):
426429
"FOR_ITER": {
427430
"counter": 1,
428431
},
432+
"LOAD_SUPER_ATTR": {
433+
"counter": 1,
434+
"class_version": 2,
435+
"self_type_version": 2,
436+
"method": 4,
437+
},
429438
"LOAD_ATTR": {
430439
"counter": 1,
431440
"version": 2,

Python/bytecodes.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,12 +1554,28 @@ dummy_func(
15541554
PREDICT(JUMP_BACKWARD);
15551555
}
15561556

1557-
inst(LOAD_SUPER_ATTR, (global_super, class, self -- res2 if (oparg & 1), res)) {
1557+
family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = {
1558+
LOAD_SUPER_ATTR,
1559+
LOAD_SUPER_ATTR_METHOD,
1560+
};
1561+
1562+
inst(LOAD_SUPER_ATTR, (unused/9, global_super, class, self -- res2 if (oparg & 1), res)) {
15581563
PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2);
1564+
int load_method = oparg & 1;
1565+
#if ENABLE_SPECIALIZATION
1566+
_PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr;
1567+
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
1568+
next_instr--;
1569+
_Py_Specialize_LoadSuperAttr(global_super, class, self, next_instr, name, load_method);
1570+
DISPATCH_SAME_OPARG();
1571+
}
1572+
STAT_INC(LOAD_SUPER_ATTR, deferred);
1573+
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
1574+
#endif /* ENABLE_SPECIALIZATION */
15591575
if (global_super == (PyObject *)&PySuper_Type && PyType_Check(class)) {
15601576
int meth_found = 0;
15611577
Py_DECREF(global_super);
1562-
res = _PySuper_Lookup((PyTypeObject *)class, self, name, oparg & 1 ? &meth_found : NULL);
1578+
res = _PySuper_Lookup((PyTypeObject *)class, self, name, load_method ? &meth_found : NULL);
15631579
Py_DECREF(class);
15641580
if (res == NULL) {
15651581
Py_DECREF(self);
@@ -1588,6 +1604,19 @@ dummy_func(
15881604
}
15891605
}
15901606

1607+
inst(LOAD_SUPER_ATTR_METHOD, (unused/1, class_version/2, self_type_version/2, method/4, global_super, class, self -- res2, res)) {
1608+
DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
1609+
DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
1610+
DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR);
1611+
PyTypeObject *self_type = Py_TYPE(self);
1612+
DEOPT_IF(self_type->tp_version_tag != self_type_version, LOAD_SUPER_ATTR);
1613+
res2 = method;
1614+
res = self; // transfer ownership
1615+
Py_INCREF(res2);
1616+
Py_DECREF(global_super);
1617+
Py_DECREF(class);
1618+
}
1619+
15911620
family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = {
15921621
LOAD_ATTR,
15931622
LOAD_ATTR_INSTANCE_VALUE,

0 commit comments

Comments
 (0)