diff options
author | Carl Meyer <carl@oddbird.net> | 2023-04-25 11:45:51 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-25 17:45:51 +0000 |
commit | ef25febcf2ede92a03c5ea00a13e167e0b5cb274 (patch) | |
tree | 6ce38cd3aa3d653d931df5250b02b5cb6b46bb69 /Python/bytecodes.c | |
parent | cef542ca572fdd402ff0e10093a0c1b459e5dcd6 (diff) | |
download | cpython-git-ef25febcf2ede92a03c5ea00a13e167e0b5cb274.tar.gz |
gh-87729: specialize LOAD_SUPER_ATTR_METHOD (#103809)
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r-- | Python/bytecodes.c | 65 |
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) = { |