summaryrefslogtreecommitdiff
path: root/Python/bytecodes.c
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2023-04-25 11:45:51 -0600
committerGitHub <noreply@github.com>2023-04-25 17:45:51 +0000
commitef25febcf2ede92a03c5ea00a13e167e0b5cb274 (patch)
tree6ce38cd3aa3d653d931df5250b02b5cb6b46bb69 /Python/bytecodes.c
parentcef542ca572fdd402ff0e10093a0c1b459e5dcd6 (diff)
downloadcpython-git-ef25febcf2ede92a03c5ea00a13e167e0b5cb274.tar.gz
gh-87729: specialize LOAD_SUPER_ATTR_METHOD (#103809)
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r--Python/bytecodes.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index dc66059cc8..9de0d92e38 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1554,34 +1554,47 @@ dummy_func(
PREDICT(JUMP_BACKWARD);
}
- inst(LOAD_SUPER_ATTR, (global_super, class, self -- res2 if (oparg & 1), res)) {
+ family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = {
+ LOAD_SUPER_ATTR,
+ LOAD_SUPER_ATTR_METHOD,
+ };
+
+ inst(LOAD_SUPER_ATTR, (unused/9, global_super, class, self -- res2 if (oparg & 1), res)) {
PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2);
- if (global_super == (PyObject *)&PySuper_Type && PyType_Check(class)) {
- int method = 0;
- Py_DECREF(global_super);
- res = _PySuper_Lookup((PyTypeObject *)class, self, name, oparg & 1 ? &method : NULL);
- Py_DECREF(class);
- if (res == NULL) {
- Py_DECREF(self);
- ERROR_IF(true, error);
- }
- // Works with CALL, pushes two values: either `meth | self` or `NULL | meth`.
- if (method) {
- res2 = res;
- res = self; // transfer ownership
- } else {
- res2 = NULL;
- Py_DECREF(self);
- }
- } else {
- PyObject *stack[] = {class, self};
- PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
- DECREF_INPUTS();
- ERROR_IF(super == NULL, error);
- res = PyObject_GetAttr(super, name);
- Py_DECREF(super);
- ERROR_IF(res == NULL, error);
+ int load_method = oparg & 1;
+ #if ENABLE_SPECIALIZATION
+ _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr;
+ if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
+ next_instr--;
+ _Py_Specialize_LoadSuperAttr(global_super, class, self, next_instr, name, load_method);
+ DISPATCH_SAME_OPARG();
}
+ STAT_INC(LOAD_SUPER_ATTR, deferred);
+ DECREMENT_ADAPTIVE_COUNTER(cache->counter);
+ #endif /* ENABLE_SPECIALIZATION */
+
+ // we make no attempt to optimize here; specializations should
+ // handle any case whose performance we care about
+ PyObject *stack[] = {class, self};
+ PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
+ DECREF_INPUTS();
+ ERROR_IF(super == NULL, error);
+ res = PyObject_GetAttr(super, name);
+ Py_DECREF(super);
+ ERROR_IF(res == NULL, error);
+ }
+
+ inst(LOAD_SUPER_ATTR_METHOD, (unused/1, class_version/2, self_type_version/2, method/4, global_super, class, self -- res2, res)) {
+ DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
+ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
+ DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR);
+ PyTypeObject *self_type = Py_TYPE(self);
+ DEOPT_IF(self_type->tp_version_tag != self_type_version, LOAD_SUPER_ATTR);
+ res2 = method;
+ res = self; // transfer ownership
+ Py_INCREF(res2);
+ Py_DECREF(global_super);
+ Py_DECREF(class);
}
family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = {