diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2021-06-15 16:35:25 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-15 16:35:25 -0600 |
commit | ac38a9f2dfbba95f5d4338eb11a0221d38ef9328 (patch) | |
tree | cbe976854afe2fc55df27e5134abc9cdc727c601 /Objects/typeobject.c | |
parent | 1d10bf0bb9409a406c56b0de8870df998637fd0f (diff) | |
download | cpython-git-ac38a9f2dfbba95f5d4338eb11a0221d38ef9328.tar.gz |
bpo-43693: Eliminate unused "fast locals". (gh-26587)
Currently, if an arg value escapes (into the closure for an inner function) we end up allocating two indices in the fast locals even though only one gets used. Additionally, using the lower index would be better in some cases, such as with no-arg `super()`. To address this, we update the compiler to fix the offsets so each variable only gets one "fast local". As a consequence, now some cell offsets are interspersed with the locals (only when an arg escapes to an inner function).
https://bugs.python.org/issue43693
Diffstat (limited to 'Objects/typeobject.c')
-rw-r--r-- | Objects/typeobject.c | 32 |
1 files changed, 13 insertions, 19 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4c7e5d4567..170929f5d8 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -11,7 +11,6 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_unionobject.h" // _Py_Union(), _Py_union_type_or #include "frameobject.h" -#include "pycore_frame.h" // _PyFrame_OpAlreadyRan #include "opcode.h" // MAKE_CELL #include "structmember.h" // PyMemberDef @@ -8878,23 +8877,18 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co, return -1; } - PyObject *obj = f->f_localsptr[0]; - int i; - if (obj == NULL && co->co_cell2arg) { - /* The first argument might be a cell. */ - for (i = 0; i < co->co_ncellvars; i++) { - if (co->co_cell2arg[i] == 0) { - int celloffset = co->co_nlocals + i; - PyObject *cell = f->f_localsptr[celloffset]; - if (PyCell_Check(cell) && - _PyFrame_OpAlreadyRan(f, MAKE_CELL, celloffset)) { - obj = PyCell_GET(cell); - } - break; - } + PyObject *firstarg = f->f_localsptr[0]; + // The first argument might be a cell. + if (firstarg != NULL && (co->co_localspluskinds[0] & CO_FAST_CELL)) { + // "firstarg" is a cell here unless (very unlikely) super() + // was called from the C-API before the first MAKE_CELL op. + if (f->f_lasti >= 0) { + assert(_Py_OPCODE(*co->co_firstinstr) == MAKE_CELL); + assert(PyCell_Check(firstarg)); + firstarg = PyCell_GET(firstarg); } } - if (obj == NULL) { + if (firstarg == NULL) { PyErr_SetString(PyExc_RuntimeError, "super(): arg[0] deleted"); return -1; @@ -8902,9 +8896,9 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co, // Look for __class__ in the free vars. PyTypeObject *type = NULL; - i = co->co_nlocals + co->co_ncellvars; + int i = co->co_nlocals + co->co_nplaincellvars; for (; i < co->co_nlocalsplus; i++) { - assert(co->co_localspluskinds[i] & CO_FAST_FREE); + assert((co->co_localspluskinds[i] & CO_FAST_FREE) != 0); PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); assert(PyUnicode_Check(name)); if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) { @@ -8936,7 +8930,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co, } *type_p = type; - *obj_p = obj; + *obj_p = firstarg; return 0; } |