int co_nlocalsplus; /* number of local + cell + free variables */ \
int co_framesize; /* Size of frame in words */ \
int co_nlocals; /* number of local variables */ \
- int co_nplaincellvars; /* number of non-arg cell variables */ \
int co_ncellvars; /* total number of cell variables */ \
int co_nfreevars; /* number of free variables */ \
uint32_t co_version; /* version number */ \
return op->co_nfreevars;
}
+static inline int PyCode_GetFirstFree(PyCodeObject *op) {
+ assert(PyCode_Check(op));
+ return op->co_nlocalsplus - op->co_nfreevars;
+}
+
#define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive)
#define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT))
--- /dev/null
+Removed the co_nplaincellvars field from the code object, as it is
+redundant.
static void
get_localsplus_counts(PyObject *names, PyObject *kinds,
- int *pnlocals, int *pnplaincellvars, int *pncellvars,
+ int *pnlocals, int *pncellvars,
int *pnfreevars)
{
int nlocals = 0;
- int nplaincellvars = 0;
int ncellvars = 0;
int nfreevars = 0;
Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(names);
}
else if (kind & CO_FAST_CELL) {
ncellvars += 1;
- nplaincellvars += 1;
}
else if (kind & CO_FAST_FREE) {
nfreevars += 1;
if (pnlocals != NULL) {
*pnlocals = nlocals;
}
- if (pnplaincellvars != NULL) {
- *pnplaincellvars = nplaincellvars;
- }
if (pncellvars != NULL) {
*pncellvars = ncellvars;
}
* here to avoid the possibility of overflow (however remote). */
int nlocals;
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
- &nlocals, NULL, NULL, NULL);
+ &nlocals, NULL, NULL);
int nplainlocals = nlocals -
con->argcount -
con->kwonlyargcount -
init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
{
int nlocalsplus = (int)PyTuple_GET_SIZE(con->localsplusnames);
- int nlocals, nplaincellvars, ncellvars, nfreevars;
+ int nlocals, ncellvars, nfreevars;
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
- &nlocals, &nplaincellvars, &ncellvars, &nfreevars);
+ &nlocals, &ncellvars, &nfreevars);
co->co_filename = Py_NewRef(con->filename);
co->co_name = Py_NewRef(con->name);
co->co_nlocalsplus = nlocalsplus;
co->co_nlocals = nlocals;
co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE;
- co->co_nplaincellvars = nplaincellvars;
co->co_ncellvars = ncellvars;
co->co_nfreevars = nfreevars;
co->co_version = _Py_next_func_version;
/* Free vars have not been initialized -- Do that */
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
- int offset = co->co_nlocals + co->co_nplaincellvars;
+ int offset = PyCode_GetFirstFree(co);
for (int i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
frame->localsplus[offset + i] = Py_NewRef(o);
// Look for __class__ in the free vars.
PyTypeObject *type = NULL;
- int i = co->co_nlocals + co->co_nplaincellvars;
+ int i = PyCode_GetFirstFree(co);
for (; i < co->co_nlocalsplus; i++) {
assert((_PyLocals_GetKind(co->co_localspluskinds, i) & CO_FAST_FREE) != 0);
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
PyCodeObject *co = frame->f_code;
assert(PyFunction_Check(frame->f_funcobj));
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
- int offset = co->co_nlocals + co->co_nplaincellvars;
assert(oparg == co->co_nfreevars);
+ int offset = co->co_nlocalsplus - oparg;
for (int i = 0; i < oparg; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
frame->localsplus[offset + i] = Py_NewRef(o);
if (_PyErr_Occurred(tstate))
return;
name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg);
- if (oparg < co->co_nplaincellvars + co->co_nlocals) {
+ if (oparg < PyCode_GetFirstFree(co)) {
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG, name);
} else {
qualname = co->co_name;
if (co->co_nfreevars) {
- int i = co->co_nlocals + co->co_nplaincellvars;
+ int i = PyCode_GetFirstFree(co);
for (; i < co->co_nlocalsplus; ++i) {
/* Bypass com_addop_varname because it will generate
LOAD_DEREF but LOAD_CLOSURE is needed.
PyCodeObject *co = frame->f_code;
assert(PyFunction_Check(frame->f_funcobj));
PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure;
- int offset = co->co_nlocals + co->co_nplaincellvars;
assert(oparg == co->co_nfreevars);
+ int offset = co->co_nlocalsplus - oparg;
for (int i = 0; i < oparg; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
frame->localsplus[offset + i] = Py_NewRef(o);
names: Tuple[str, ...],
kinds: bytes) -> Tuple[int, int, int, int]:
nlocals = 0
- nplaincellvars = 0
ncellvars = 0
nfreevars = 0
assert len(names) == len(kinds)
ncellvars += 1
elif kind & CO_FAST_CELL:
ncellvars += 1
- nplaincellvars += 1
elif kind & CO_FAST_FREE:
nfreevars += 1
assert nlocals == len(code.co_varnames) == code.co_nlocals, \
(nlocals, len(code.co_varnames), code.co_nlocals)
assert ncellvars == len(code.co_cellvars)
assert nfreevars == len(code.co_freevars)
- assert len(names) == nlocals + nplaincellvars + nfreevars
- return nlocals, nplaincellvars, ncellvars, nfreevars
+ return nlocals, ncellvars, nfreevars
PyUnicode_1BYTE_KIND = 1
co_localsplusnames = self.generate(name + "_localsplusnames", localsplusnames)
co_localspluskinds = self.generate(name + "_localspluskinds", localspluskinds)
# Derived values
- nlocals, nplaincellvars, ncellvars, nfreevars = \
+ nlocals, ncellvars, nfreevars = \
get_localsplus_counts(code, localsplusnames, localspluskinds)
co_code_adaptive = make_string_literal(code.co_code)
self.write("static")
self.field(code, "co_firstlineno")
self.write(f".co_nlocalsplus = {len(localsplusnames)},")
self.field(code, "co_nlocals")
- self.write(f".co_nplaincellvars = {nplaincellvars},")
self.write(f".co_ncellvars = {ncellvars},")
self.write(f".co_nfreevars = {nfreevars},")
self.write(f".co_version = {next_code_version},")