diff options
author | Carl Meyer <carl@oddbird.net> | 2023-04-24 22:22:14 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-24 22:22:14 (GMT) |
commit | 0dc8b50d33208e9ca4fc3d959c6798529731f020 (patch) | |
tree | 822102a5177183fc6ad7075bd74a02a5633edc52 /Python/bytecodes.c | |
parent | 22bed58e531ce780d91f3364c5ace98fad28c2e8 (diff) | |
download | cpython-0dc8b50d33208e9ca4fc3d959c6798529731f020.zip cpython-0dc8b50d33208e9ca4fc3d959c6798529731f020.tar.gz cpython-0dc8b50d33208e9ca4fc3d959c6798529731f020.tar.bz2 |
gh-87729: add LOAD_SUPER_ATTR instruction for faster super() (#103497)
This speeds up `super()` (by around 85%, for a simple one-level
`super().meth()` microbenchmark) by avoiding allocation of a new
single-use `super()` object on each use.
Diffstat (limited to 'Python/bytecodes.c')
-rw-r--r-- | Python/bytecodes.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7af96b4..dc66059 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -25,6 +25,7 @@ #include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "pycore_typeobject.h" // _PySuper_Lookup() #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS #include "pycore_dict.h" @@ -1553,6 +1554,36 @@ dummy_func( PREDICT(JUMP_BACKWARD); } + inst(LOAD_SUPER_ATTR, (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); + } + } + family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = { LOAD_ATTR, LOAD_ATTR_INSTANCE_VALUE, |