diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2021-06-15 22:35:25 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-15 22:35:25 (GMT) |
commit | ac38a9f2dfbba95f5d4338eb11a0221d38ef9328 (patch) | |
tree | cbe976854afe2fc55df27e5134abc9cdc727c601 /Python/ceval.c | |
parent | 1d10bf0bb9409a406c56b0de8870df998637fd0f (diff) | |
download | cpython-ac38a9f2dfbba95f5d4338eb11a0221d38ef9328.zip cpython-ac38a9f2dfbba95f5d4338eb11a0221d38ef9328.tar.gz cpython-ac38a9f2dfbba95f5d4338eb11a0221d38ef9328.tar.bz2 |
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 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 24 |
1 files changed, 4 insertions, 20 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 79ec143..a9b9aca 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2922,29 +2922,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) } case TARGET(MAKE_CELL): { + // "initial" is probably NULL but not if it's an arg (or set + // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); - // Normally initial would be NULL. However, it - // might have been set to an initial value during - // a call to PyFrame_LocalsToFast(). PyObject *cell = PyCell_New(initial); if (cell == NULL) { goto error; } - /* If it is an arg then copy the arg into the cell. */ - if (initial == NULL && co->co_cell2arg != NULL) { - int argoffset = co->co_cell2arg[oparg - co->co_nlocals]; - if (argoffset != CO_CELL_NOT_AN_ARG) { - PyObject *arg = GETLOCAL(argoffset); - // It will have been set in initialize_locals() but - // may have been deleted PyFrame_LocalsToFast(). - if (arg != NULL) {; - Py_INCREF(arg); - PyCell_SET(cell, arg); - /* Clear the local copy. */ - SETLOCAL(argoffset, NULL); - } - } - } SETLOCAL(oparg, cell); DISPATCH(); } @@ -4915,7 +4899,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, for (i = 0; i < co->co_nfreevars; ++i) { PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i); Py_INCREF(o); - localsplus[co->co_nlocals + co->co_ncellvars + i] = o; + localsplus[co->co_nlocals + co->co_nplaincellvars + i] = o; } return 0; @@ -6244,7 +6228,7 @@ format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg) if (_PyErr_Occurred(tstate)) return; name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg); - if (oparg < co->co_ncellvars + co->co_nlocals) { + if (oparg < co->co_nplaincellvars + co->co_nlocals) { format_exc_check_arg(tstate, PyExc_UnboundLocalError, UNBOUNDLOCAL_ERROR_MSG, name); } else { |