8000 bpo-43693: Clean up the PyCodeObject fields. by ericsnowcurrently · Pull Request #26364 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-43693: Clean up the PyCodeObject fields. #26364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add co_ncellvars and co_nfreevars.
  • Loading branch information
ericsnowcurrently committed May 25, 2021
commit 9a62e10b67ae5a89c034d3fa92fc38c7d72521d4
8 changes: 5 additions & 3 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ struct PyCodeObject {
int co_stacksize; /* #entries needed for evaluation stack */
int co_firstlineno; /* first source line number */
PyObject *co_varnames; /* tuple of strings (local variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
PyObject *co_linetable; /* string (encoding addr<->lineno mapping) See
Expand All @@ -66,8 +66,10 @@ struct PyCodeObject {

Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
// These are redundant.
int co_nlocalsplus; /* Number of locals + free + cell variables */
int co_nlocals; /* #local variables */
int co_nlocalsplus; /* number of local + cell + free variables */
int co_nlocals; /* number of local variables */
int co_ncellvars; /* number of cell variables */
int co_nfreevars; /* number of free variables */

/* The remaining fields are zeroed out on new code objects. */

Expand Down
23 changes: 14 additions & 9 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
{
PyCodeObject *co;
Py_ssize_t *cell2arg = NULL;
Py_ssize_t i, n_cellvars, n_varnames, total_args;
Py_ssize_t i, n_varnames, total_args;
int ncellvars, nfreevars;

/* Check argument types */
if (argcount < posonlyargcount || posonlyargcount < 0 ||
Expand Down Expand Up @@ -217,8 +218,11 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
}

/* Check for any inner or outer closure references */
n_cellvars = PyTuple_GET_SIZE(cellvars);
if (!n_cellvars && !PyTuple_GET_SIZE(freevars)) {
assert(PyTuple_GET_SIZE(cellvars) < INT_MAX);
ncellvars = (int)PyTuple_GET_SIZE(cellvars);
assert(PyTuple_GET_SIZE(freevars) < INT_MAX);
nfreevars = (int)PyTuple_GET_SIZE(freevars);
if (!ncellvars && !nfreevars) {
flags |= CO_NOFREE;
} else {
flags &= ~CO_NOFREE;
Expand All @@ -239,15 +243,15 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
}

/* Create mapping between cells and arguments if needed. */
if (n_cellvars) {
if (ncellvars) {
bool used_cell2arg = false;
cell2arg = PyMem_NEW(Py_ssize_t, n_cellvars);
cell2arg = PyMem_NEW(Py_ssize_t, ncellvars);
if (cell2arg == NULL) {
PyErr_NoMemory();
return NULL;
}
/* Find cells which are also arguments. */
for (i = 0; i < n_cellvars; i++) {
for (i = 0; i < ncellvars; i++) {
Py_ssize_t j;
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
cell2arg[i] = CO_CELL_NOT_AN_ARG;
Expand Down Expand Up @@ -279,9 +283,10 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
co->co_argcount = argcount;
co->co_posonlyargcount = posonlyargcount;
co->co_kwonlyargcount = kwonlyargcount;
co->co_nlocalsplus = nlocals + ncellvars + nfreevars;
co->co_nlocals = nlocals;
co->co_nlocalsplus = nlocals +
(int)PyTuple_GET_SIZE(freevars) + (int)PyTuple_GET_SIZE(cellvars);
co->co_ncellvars = ncellvars;
co->co_nfreevars = nfreevars;
co->co_stacksize = stacksize;
co->co_flags = flags;
Py_INCREF(code);
Expand Down Expand Up @@ -1139,7 +1144,7 @@ code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra;

if (co->co_cell2arg != NULL && co->co_cellvars != NULL) {
res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(Py_ssize_t);
res += co->co_ncellvars * sizeof(Py_ssize_t);
}
if (co_extra != NULL) {
res += sizeof(_PyCodeObjectExtra) +
Expand Down
24 changes: 9 additions & 15 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,6 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
PyObject **fast;
PyCodeObject *co;
Py_ssize_t j;
Py_ssize_t ncells, nfreevars;

if (f == NULL) {
PyErr_BadInternalCall();
Expand Down Expand Up @@ -1051,10 +1050,8 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
if (map_to_dict(map, j, locals, fast, 0) < 0)
return -1;
}
ncells = PyTuple_GET_SIZE(co->co_cellvars);
nfreevars = PyTuple_GET_SIZE(co->co_freevars);
if (ncells || nfreevars) {
if (map_to_dict(co->co_cellvars, ncells,
if (co->co_ncellvars || co->co_nfreevars) {
if (map_to_dict(co->co_cellvars, co->co_ncellvars,
locals, fast + co->co_nlocals, 1))
return -1;

Expand All @@ -1067,8 +1064,8 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
into the locals dict used by the class.
*/
if (co->co_flags & CO_OPTIMIZED) {
if (map_to_dict(co->co_freevars, nfreevars,
locals, fast + co->co_nlocals + ncells, 1) < 0)
if (map_to_dict(co->co_freevars, co->co_nfreevars, locals,
fast + co->co_nlocals + co->co_ncellvars, 1) < 0)
return -1;
}
}
Expand Down Expand Up @@ -1096,7 +1093,6 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
PyObject *error_type, *error_value, *error_traceback;
PyCodeObject *co;
Py_ssize_t j;
Py_ssize_t ncells, nfreevars;
if (f == NULL)
return;
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
Expand All @@ -1113,16 +1109,14 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
j = co->co_nlocals;
if (co->co_nlocals)
dict_to_map(co->co_varnames, j, locals, fast, 0, clear);
ncells = PyTuple_GET_SIZE(co->co_cellvars);
nfreevars = PyTuple_GET_SIZE(co->co_freevars);
if (ncells || nfreevars) {
dict_to_map(co->co_cellvars, ncells,
if (co->co_ncellvars || co->co_nfreevars) {
dict_to_map(co->co_cellvars, co->co_ncellvars,
locals, fast + co->co_nlocals, 1, clear);
/* Same test as in PyFrame_FastToLocals() above. */
if (co->co_flags & CO_OPTIMIZED) {
dict_to_map(co->co_freevars, nfreevars,
locals, fast + co->co_nlocals + ncells, 1,
clear);
dict_to_map(co->co_freevars, co->co_nfreevars, locals,
fast + co->co_nlocals + co->co_ncellvars, 1,
clear);
}
}
PyErr_Restore(error_type, error_value, error_traceback);
Expand Down
14 changes: 7 additions & 7 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored))
static int
func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
{
Py_ssize_t nfree, nclosure;
Py_ssize_t nclosure;
int nfree;

/* Not legal to del f.func_code or to set it to anything
* other than a code object. */
Expand All @@ -294,7 +295,7 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
return -1;
}

nfree = PyCode_GetNumFree((PyCodeObject *)value);
nfree = ((PyCodeObject *)value)->co_nfreevars;
nclosure = (op->func_closure == NULL ? 0 :
PyTuple_GET_SIZE(op->func_closure));
if (nclosure != nfree) {
Expand Down Expand Up @@ -538,7 +539,7 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
/*[clinic end generated code: output=99c6d9da3a24e3be input=93611752fc2daf11]*/
{
PyFunctionObject *newfunc;
Py_ssize_t nfree, nclosure;
Py_ssize_t nclosure;

if (name != Py_None && !PyUnicode_Check(name)) {
PyErr_SetString(PyExc_TypeError,
Expand All @@ -550,9 +551,8 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
"arg 4 (defaults) must be None or tuple");
return NULL;
}
nfree = PyTuple_GET_SIZE(code->co_freevars);
if (!PyTuple_Check(closure)) {
if (nfree && closure == Py_None) {
if (code->co_nfreevars && closure == Py_None) {
PyErr_SetString(PyExc_TypeError,
"arg 5 (closure) must be tuple");
return NULL;
Expand All @@ -566,10 +566,10 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,

/* check that the closure is well-formed */
nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure);
if (nfree != nclosure)
if (code->co_nfreevars != nclosure)
return PyErr_Format(PyExc_ValueError,
"%U requires closure of length %zd, not %zd",
code->co_name, nfree, nclosure);
code->co_name, code->co_nfreevars, nclosure);
if (nclosure) {
Py_ssize_t i;
for (i = 0; i < nclosure; i++) {
Expand Down
18 changes: 4 additions & 14 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -8837,11 +8837,10 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
}

PyObject *obj = f->f_localsptr[0];
Py_ssize_t i, n;
Py_ssize_t i;
if (obj == NULL && co->co_cell2arg) {
/* The first argument might be a cell. */
n = PyTuple_GET_SIZE(co->co_cellvars);
for (i = 0; i < n; i++) {
for (i = 0; i < co->co_ncellvars; i++) {
if (co->co_cell2arg[i] == 0) {
PyObject *cell = f->f_localsptr[co->co_nlocals + i];
assert(PyCell_Check(cell));
Expand All @@ -8856,21 +8855,12 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
return -1;
}

if (co->co_freevars == NULL) {
n = 0;
}
else {
assert(PyTuple_Check(co->co_freevars));
n = PyTuple_GET_SIZE(co->co_freevars);
}

PyTypeObject *type = NULL;
for (i = 0; i < n; i++) {
for (i = 0; i < co->co_nfreevars; i++) {
PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
assert(PyUnicode_Check(name));
if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
Py_ssize_t index = co->co_nlocals +
PyTuple_GET_SIZE(co->co_cellvars) + i;
Py_ssize_t index = co->co_nlocals + co->co_ncellvars + i;
PyObject *cell = f->f_localsptr[index];
if (cell == NULL || !PyCell_Check(cell)) {
PyErr_SetString(PyExc_RuntimeError,
Expand Down
17 changes: 8 additions & 9 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -3081,9 +3081,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
PyObject *name, *value, *locals = LOCALS();
Py_ssize_t idx;
assert(locals);
assert(oparg >= PyTuple_GET_SIZE(co->co_cellvars));
idx = oparg - PyTuple_GET_SIZE(co->co_cellvars);
assert(idx >= 0 && idx < PyTuple_GET_SIZE(co->co_freevars));
assert(oparg >= co->co_ncellvars);
idx = oparg - co->co_ncellvars;
assert(idx >= 0 && idx < co->co_nfreevars);
name = PyTuple_GET_ITEM(co->co_freevars, idx);
if (PyDict_CheckExact(locals)) {
value = PyDict_GetItemWithError(locals, name);
Expand Down Expand Up @@ -5062,7 +5062,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,

/* Allocate and initialize storage for cell vars, and copy free
vars into frame. */
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
for (i = 0; i < co->co_ncellvars; ++i) {
PyObject *c;
Py_ssize_t arg;
/* Possibly account for the cell variable being an argument. */
Expand All @@ -5081,10 +5081,10 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
}

/* Copy closure variables to free variables */
for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
for (i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i);
Py_INCREF(o);
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
freevars[co->co_ncellvars + i] = o;
}

return 0;
Expand Down Expand Up @@ -6417,16 +6417,15 @@ format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg)
/* Don't stomp existing exception */
if (_PyErr_Occurred(tstate))
return;
if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
if (oparg < co->co_ncellvars) {
name = PyTuple_GET_ITEM(co->co_cellvars,
oparg);
format_exc_check_arg(tstate,
PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG,
name);
} else {
name = PyTuple_GET_ITEM(co->co_freevars, oparg -
PyTuple_GET_SIZE(co->co_cellvars));
name = PyTuple_GET_ITEM(co->co_freevars, oparg - co->co_ncellvars);
format_exc_check_arg(tstate, PyExc_NameError,
UNBOUNDFREE_ERROR_MSG, name);
}
Expand Down
0