summaryrefslogtreecommitdiffstats
path: root/Objects/codeobject.c
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2021-06-07 18:22:26 (GMT)
committerGitHub <noreply@github.com>2021-06-07 18:22:26 (GMT)
commit2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6 (patch)
treed3983e5282f575560cb7449fae4785447fdfff14 /Objects/codeobject.c
parent001eb520b5757294dc455c900d94b7b153de6cdd (diff)
downloadcpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.zip
cpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.tar.gz
cpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.tar.bz2
bpo-43693: Un-revert commits 2c1e258 and b2bf2bc. (gh-26577)
These were reverted in gh-26530 (commit 17c4edc) due to refleaks. * 2c1e258 - Compute deref offsets in compiler (gh-25152) * b2bf2bc - Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (gh-26388) This change fixes the refleaks. https://bugs.python.org/issue43693
Diffstat (limited to 'Objects/codeobject.c')
-rw-r--r--Objects/codeobject.c419
1 files changed, 348 insertions, 71 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 768f5d1..1a99ec3 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -154,6 +154,93 @@ validate_and_copy_tuple(PyObject *tup)
* _PyCode_New()
******************/
+// This is also used in compile.c.
+void
+_Py_set_localsplus_info(int offset, PyObject *name, _PyLocalsPlusKind kind,
+ PyObject *names, _PyLocalsPlusKinds kinds)
+{
+ Py_INCREF(name);
+ PyTuple_SET_ITEM(names, offset, name);
+ kinds[offset] = kind;
+
+ if (kind == CO_FAST_CELL) {
+ // Cells can overlap with args, so mark those cases.
+ int nlocalsplus = (int)PyTuple_GET_SIZE(names);
+ for (int i = 0; i < nlocalsplus; i++) {
+ _PyLocalsPlusKind kind = kinds[i];
+ if (kind && !(kind & CO_FAST_LOCAL)) {
+ // We've moved past the locals.
+ break;
+ }
+ PyObject *varname = PyTuple_GET_ITEM(names, i);
+ int cmp = PyUnicode_Compare(name, varname);
+ if (cmp == 0) {
+ kinds[i] |= CO_FAST_CELL;
+ break;
+ }
+ assert(cmp > 0 || !PyErr_Occurred());
+ }
+ }
+}
+
+static void
+get_localsplus_counts(PyObject *names, _PyLocalsPlusKinds kinds,
+ int *pnlocals, int *pncellvars,
+ int *pnfreevars)
+{
+ int nlocals = 0;
+ int ncellvars = 0;
+ int nfreevars = 0;
+ int nlocalsplus = Py_SAFE_DOWNCAST(PyTuple_GET_SIZE(names),
+ Py_ssize_t, int);
+ for (int i = 0; i < nlocalsplus; i++) {
+ if (kinds[i] & CO_FAST_LOCAL) {
+ nlocals += 1;
+ }
+ else if (kinds[i] & CO_FAST_CELL) {
+ ncellvars += 1;
+ }
+ else if (kinds[i] & CO_FAST_FREE) {
+ nfreevars += 1;
+ }
+ }
+ if (pnlocals != NULL) {
+ *pnlocals = nlocals;
+ }
+ if (pncellvars != NULL) {
+ *pncellvars = ncellvars;
+ }
+ if (pnfreevars != NULL) {
+ *pnfreevars = nfreevars;
+ }
+}
+
+static PyObject *
+get_localsplus_names(PyCodeObject *co, _PyLocalsPlusKind kind, int num)
+{
+ PyObject *names = PyTuple_New(num);
+ if (names == NULL) {
+ return NULL;
+ }
+ int index = 0;
+ for (int offset = 0; offset < co->co_nlocalsplus; offset++) {
+ if ((co->co_localspluskinds[offset] & kind) == 0) {
+ continue;
+ }
+ // For now there may be duplicates, which we ignore.
+ if (kind == CO_FAST_CELL && co->co_localspluskinds[offset] != kind) {
+ continue;
+ }
+ assert(index < num);
+ PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, offset);
+ Py_INCREF(name);
+ PyTuple_SET_ITEM(names, index, name);
+ index += 1;
+ }
+ assert(index == num);
+ return names;
+}
+
int
_PyCode_Validate(struct _PyCodeConstructor *con)
{
@@ -164,9 +251,9 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
con->code == NULL || !PyBytes_Check(con->code) ||
con->consts == NULL || !PyTuple_Check(con->consts) ||
con->names == NULL || !PyTuple_Check(con->names) ||
- con->varnames == NULL || !PyTuple_Check(con->varnames) ||
- con->freevars == NULL || !PyTuple_Check(con->freevars) ||
- con->cellvars == NULL || !PyTuple_Check(con->cellvars) ||
+ con->localsplusnames == NULL || !PyTuple_Check(con->localsplusnames) ||
+ (PyTuple_GET_SIZE(con->localsplusnames) && con->localspluskinds == NULL) ||
+ (!PyTuple_GET_SIZE(con->localsplusnames) && con->localspluskinds != NULL) ||
con->name == NULL || !PyUnicode_Check(con->name) ||
con->filename == NULL || !PyUnicode_Check(con->filename) ||
con->linetable == NULL || !PyBytes_Check(con->linetable) ||
@@ -180,20 +267,30 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
a long running assumption in ceval.c and many parts of
the interpreter. */
if (PyBytes_GET_SIZE(con->code) > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError, "co_code larger than INT_MAX");
+ PyErr_SetString(PyExc_OverflowError,
+ "code: co_code larger than INT_MAX");
+ return -1;
+ }
+ if (PyBytes_GET_SIZE(con->code) % sizeof(_Py_CODEUNIT) != 0 ||
+ !_Py_IS_ALIGNED(PyBytes_AS_STRING(con->code), sizeof(_Py_CODEUNIT))
+ ) {
+ PyErr_SetString(PyExc_ValueError, "code: co_code is malformed");
return -1;
}
/* Ensure that the co_varnames has enough names to cover the arg counts.
* Note that totalargs = nlocals - nplainlocals. We check nplainlocals
* here to avoid the possibility of overflow (however remote). */
- int nplainlocals = (int)PyTuple_GET_SIZE(con->varnames) -
+ int nlocals;
+ get_localsplus_counts(con->localsplusnames, con->localspluskinds,
+ &nlocals, NULL, NULL);
+ int nplainlocals = nlocals -
con->argcount -
con->kwonlyargcount -
((con->flags & CO_VARARGS) != 0) -
((con->flags & CO_VARKEYWORDS) != 0);
if (nplainlocals < 0) {
- PyErr_SetString(PyExc_ValueError, "code: varnames is too small");
+ PyErr_SetString(PyExc_ValueError, "code: co_varnames is too small");
return -1;
}
@@ -203,6 +300,11 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
static void
init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
{
+ int nlocalsplus = (int)PyTuple_GET_SIZE(con->localsplusnames);
+ int nlocals, ncellvars, nfreevars;
+ get_localsplus_counts(con->localsplusnames, con->localspluskinds,
+ &nlocals, &ncellvars, &nfreevars);
+
Py_INCREF(con->filename);
co->co_filename = con->filename;
Py_INCREF(con->name);
@@ -221,12 +323,10 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
Py_INCREF(con->names);
co->co_names = con->names;
- Py_INCREF(con->varnames);
- co->co_varnames = con->varnames;
- Py_INCREF(con->cellvars);
- co->co_cellvars = con->cellvars;
- Py_INCREF(con->freevars);
- co->co_freevars = con->freevars;
+ Py_INCREF(con->localsplusnames);
+ co->co_localsplusnames = con->localsplusnames;
+ // We take ownership of the kinds array.
+ co->co_localspluskinds = con->localspluskinds;
co->co_argcount = con->argcount;
co->co_posonlyargcount = con->posonlyargcount;
@@ -239,10 +339,13 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
/* derived values */
co->co_cell2arg = NULL; // This will be set soon.
- co->co_nlocals = (int)PyTuple_GET_SIZE(con->varnames);
- co->co_ncellvars = (int)PyTuple_GET_SIZE(con->cellvars);
- co->co_nfreevars = (int)PyTuple_GET_SIZE(con->freevars);
- co->co_nlocalsplus = co->co_nlocals + co->co_ncellvars + co->co_nfreevars;
+ co->co_nlocalsplus = nlocalsplus;
+ co->co_nlocals = nlocals;
+ co->co_ncellvars = ncellvars;
+ co->co_nfreevars = nfreevars;
+ co->co_varnames = NULL;
+ co->co_cellvars = NULL;
+ co->co_freevars = NULL;
/* not set */
co->co_weakreflist = NULL;
@@ -274,24 +377,10 @@ _PyCode_New(struct _PyCodeConstructor *con)
if (intern_string_constants(con->consts, NULL) < 0) {
return NULL;
}
- if (intern_strings(con->varnames) < 0) {
- return NULL;
- }
- if (intern_strings(con->freevars) < 0) {
- return NULL;
- }
- if (intern_strings(con->cellvars) < 0) {
+ if (intern_strings(con->localsplusnames) < 0) {
return NULL;
}
- /* Check for any inner or outer closure references */
- int ncellvars = (int)PyTuple_GET_SIZE(con->cellvars);
- if (!ncellvars && !PyTuple_GET_SIZE(con->freevars)) {
- con->flags |= CO_NOFREE;
- } else {
- con->flags &= ~CO_NOFREE;
- }
-
PyCodeObject *co = PyObject_New(PyCodeObject, &PyCode_Type);
if (co == NULL) {
PyErr_NoMemory();
@@ -299,18 +388,26 @@ _PyCode_New(struct _PyCodeConstructor *con)
}
init_code(co, con);
+ /* Check for any inner or outer closure references */
+ if (!co->co_ncellvars && !co->co_nfreevars) {
+ co->co_flags |= CO_NOFREE;
+ } else {
+ co->co_flags &= ~CO_NOFREE;
+ }
+
/* Create mapping between cells and arguments if needed. */
- if (ncellvars) {
+ if (co->co_ncellvars) {
int totalargs = co->co_argcount +
co->co_kwonlyargcount +
((co->co_flags & CO_VARARGS) != 0) +
((co->co_flags & CO_VARKEYWORDS) != 0);
assert(totalargs <= co->co_nlocals);
/* Find cells which are also arguments. */
- for (int i = 0; i < ncellvars; i++) {
- PyObject *cellname = PyTuple_GET_ITEM(co->co_cellvars, i);
+ for (int i = 0; i < co->co_ncellvars; i++) {
+ PyObject *cellname = PyTuple_GET_ITEM(co->co_localsplusnames,
+ i + co->co_nlocals);
for (int j = 0; j < totalargs; j++) {
- PyObject *argname = PyTuple_GET_ITEM(co->co_varnames, j);
+ PyObject *argname = PyTuple_GET_ITEM(co->co_localsplusnames, j);
int cmp = PyUnicode_Compare(cellname, argname);
if (cmp == -1 && PyErr_Occurred()) {
Py_DECREF(co);
@@ -318,13 +415,13 @@ _PyCode_New(struct _PyCodeConstructor *con)
}
if (cmp == 0) {
if (co->co_cell2arg == NULL) {
- co->co_cell2arg = PyMem_NEW(int, ncellvars);
+ co->co_cell2arg = PyMem_NEW(int, co->co_ncellvars);
if (co->co_cell2arg == NULL) {
Py_DECREF(co);
PyErr_NoMemory();
return NULL;
}
- for (int k = 0; k < ncellvars; k++) {
+ for (int k = 0; k < co->co_ncellvars; k++) {
co->co_cell2arg[k] = CO_CELL_NOT_AN_ARG;
}
}
@@ -352,6 +449,47 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
PyObject *filename, PyObject *name, int firstlineno,
PyObject *linetable, PyObject *exceptiontable)
{
+ PyCodeObject *co = NULL;
+ PyObject *localsplusnames = NULL;
+ _PyLocalsPlusKinds localspluskinds = NULL;
+
+ if (varnames == NULL || !PyTuple_Check(varnames) ||
+ cellvars == NULL || !PyTuple_Check(cellvars) ||
+ freevars == NULL || !PyTuple_Check(freevars)
+ ) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ // Set the "fast locals plus" info.
+ int nvarnames = (int)PyTuple_GET_SIZE(varnames);
+ int ncellvars = (int)PyTuple_GET_SIZE(cellvars);
+ int nfreevars = (int)PyTuple_GET_SIZE(freevars);
+ int nlocalsplus = nvarnames + ncellvars + nfreevars;
+ localsplusnames = PyTuple_New(nlocalsplus);
+ if (localsplusnames == NULL) {
+ goto error;
+ }
+ if (_PyCode_InitLocalsPlusKinds(nlocalsplus, &localspluskinds) < 0) {
+ goto error;
+ }
+ int offset = 0;
+ for (int i = 0; i < nvarnames; i++, offset++) {
+ PyObject *name = PyTuple_GET_ITEM(varnames, i);
+ _Py_set_localsplus_info(offset, name, CO_FAST_LOCAL,
+ localsplusnames, localspluskinds);
+ }
+ for (int i = 0; i < ncellvars; i++, offset++) {
+ PyObject *name = PyTuple_GET_ITEM(cellvars, i);
+ _Py_set_localsplus_info(offset, name, CO_FAST_CELL,
+ localsplusnames, localspluskinds);
+ }
+ for (int i = 0; i < nfreevars; i++, offset++) {
+ PyObject *name = PyTuple_GET_ITEM(freevars, i);
+ _Py_set_localsplus_info(offset, name, CO_FAST_FREE,
+ localsplusnames, localspluskinds);
+ }
+
struct _PyCodeConstructor con = {
.filename = filename,
.name = name,
@@ -364,9 +502,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
.consts = consts,
.names = names,
- .varnames = varnames,
- .cellvars = cellvars,
- .freevars = freevars,
+ .localsplusnames = localsplusnames,
+ .localspluskinds = localspluskinds,
.argcount = argcount,
.posonlyargcount = posonlyargcount,
@@ -376,18 +513,35 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
.exceptiontable = exceptiontable,
};
+
if (_PyCode_Validate(&con) < 0) {
- return NULL;
+ goto error;
}
assert(PyBytes_GET_SIZE(code) % sizeof(_Py_CODEUNIT) == 0);
assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(code), sizeof(_Py_CODEUNIT)));
if (nlocals != PyTuple_GET_SIZE(varnames)) {
PyErr_SetString(PyExc_ValueError,
"code: co_nlocals != len(co_varnames)");
- return NULL;
+ goto error;
}
- return _PyCode_New(&con);
+ co = _PyCode_New(&con);
+ if (co == NULL) {
+ goto error;
+ }
+
+ localspluskinds = NULL; // This keeps it from getting freed below.
+ Py_INCREF(varnames);
+ co->co_varnames = varnames;
+ Py_INCREF(cellvars);
+ co->co_cellvars = cellvars;
+ Py_INCREF(freevars);
+ co->co_freevars = freevars;
+
+error:
+ Py_XDECREF(localsplusnames);
+ _PyCode_ClearLocalsPlusKinds(localspluskinds);
+ return co;
}
PyCodeObject *
@@ -438,9 +592,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
.linetable = emptystring,
.consts = nulltuple,
.names = nulltuple,
- .varnames = nulltuple,
- .cellvars = nulltuple,
- .freevars = nulltuple,
+ .localsplusnames = nulltuple,
.exceptiontable = emptystring,
};
result = _PyCode_New(&con);
@@ -884,6 +1036,56 @@ _PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
/******************
+ * other PyCodeObject accessor functions
+ ******************/
+
+PyObject *
+_PyCode_GetVarnames(PyCodeObject *co)
+{
+ if (co->co_varnames == NULL) {
+ // PyCodeObject owns this reference.
+ co->co_varnames = get_localsplus_names(co, CO_FAST_LOCAL,
+ co->co_nlocals);
+ if (co->co_varnames == NULL) {
+ return NULL;
+ }
+ }
+ Py_INCREF(co->co_varnames);
+ return co->co_varnames;
+}
+
+PyObject *
+_PyCode_GetCellvars(PyCodeObject *co)
+{
+ if (co->co_cellvars == NULL) {
+ // PyCodeObject owns this reference.
+ co->co_cellvars = get_localsplus_names(co, CO_FAST_CELL,
+ co->co_ncellvars);
+ if (co->co_cellvars == NULL) {
+ return NULL;
+ }
+ }
+ Py_INCREF(co->co_cellvars);
+ return co->co_cellvars;
+}
+
+PyObject *
+_PyCode_GetFreevars(PyCodeObject *co)
+{
+ if (co->co_freevars == NULL) {
+ // PyCodeObject owns this reference.
+ co->co_freevars = get_localsplus_names(co, CO_FAST_FREE,
+ co->co_nfreevars);
+ if (co->co_freevars == NULL) {
+ return NULL;
+ }
+ }
+ Py_INCREF(co->co_freevars);
+ return co->co_freevars;
+}
+
+
+/******************
* PyCode_Type
******************/
@@ -1032,6 +1234,8 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_code);
Py_XDECREF(co->co_consts);
Py_XDECREF(co->co_names);
+ Py_XDECREF(co->co_localsplusnames);
+ _PyCode_ClearLocalsPlusKinds(co->co_localspluskinds);
Py_XDECREF(co->co_varnames);
Py_XDECREF(co->co_freevars);
Py_XDECREF(co->co_cellvars);
@@ -1094,8 +1298,6 @@ code_richcompare(PyObject *self, PyObject *other, int op)
if (!eq) goto unequal;
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
if (!eq) goto unequal;
- eq = co->co_nlocals == cp->co_nlocals;
- if (!eq) goto unequal;
eq = co->co_flags == cp->co_flags;
if (!eq) goto unequal;
eq = co->co_firstlineno == cp->co_firstlineno;
@@ -1119,11 +1321,8 @@ code_richcompare(PyObject *self, PyObject *other, int op)
eq = PyObject_RichCompareBool(co->co_names, cp->co_names, Py_EQ);
if (eq <= 0) goto unequal;
- eq = PyObject_RichCompareBool(co->co_varnames, cp->co_varnames, Py_EQ);
- if (eq <= 0) goto unequal;
- eq = PyObject_RichCompareBool(co->co_freevars, cp->co_freevars, Py_EQ);
- if (eq <= 0) goto unequal;
- eq = PyObject_RichCompareBool(co->co_cellvars, cp->co_cellvars, Py_EQ);
+ eq = PyObject_RichCompareBool(co->co_localsplusnames,
+ cp->co_localsplusnames, Py_EQ);
if (eq <= 0) goto unequal;
if (op == Py_EQ)
@@ -1148,7 +1347,7 @@ code_richcompare(PyObject *self, PyObject *other, int op)
static Py_hash_t
code_hash(PyCodeObject *co)
{
- Py_hash_t h, h0, h1, h2, h3, h4, h5, h6;
+ Py_hash_t h, h0, h1, h2, h3, h4;
h0 = PyObject_Hash(co->co_name);
if (h0 == -1) return -1;
h1 = PyObject_Hash(co->co_code);
@@ -1157,15 +1356,11 @@ code_hash(PyCodeObject *co)
if (h2 == -1) return -1;
h3 = PyObject_Hash(co->co_names);
if (h3 == -1) return -1;
- h4 = PyObject_Hash(co->co_varnames);
+ h4 = PyObject_Hash(co->co_localsplusnames);
if (h4 == -1) return -1;
- h5 = PyObject_Hash(co->co_freevars);
- if (h5 == -1) return -1;
- h6 = PyObject_Hash(co->co_cellvars);
- if (h6 == -1) return -1;
- h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
+ h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^
co->co_argcount ^ co->co_posonlyargcount ^ co->co_kwonlyargcount ^
- co->co_nlocals ^ co->co_flags;
+ co->co_flags;
if (h == -1) h = -2;
return h;
}
@@ -1177,15 +1372,11 @@ static PyMemberDef code_memberlist[] = {
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
{"co_posonlyargcount", T_INT, OFF(co_posonlyargcount), READONLY},
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
- {"co_nlocals", T_INT, OFF(co_nlocals), READONLY},
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
{"co_flags", T_INT, OFF(co_flags), READONLY},
{"co_code", T_OBJECT, OFF(co_code), READONLY},
{"co_consts", T_OBJECT, OFF(co_consts), READONLY},
{"co_names", T_OBJECT, OFF(co_names), READONLY},
- {"co_varnames", T_OBJECT, OFF(co_varnames), READONLY},
- {"co_freevars", T_OBJECT, OFF(co_freevars), READONLY},
- {"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY},
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
{"co_name", T_OBJECT, OFF(co_name), READONLY},
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
@@ -1195,15 +1386,43 @@ static PyMemberDef code_memberlist[] = {
};
-
static PyObject *
code_getlnotab(PyCodeObject *code, void *closure)
{
return decode_linetable(code);
}
+static PyObject *
+code_getnlocals(PyCodeObject *code, void *closure)
+{
+ return PyLong_FromLong(code->co_nlocals);
+}
+
+static PyObject *
+code_getvarnames(PyCodeObject *code, void *closure)
+{
+ return _PyCode_GetVarnames(code);
+}
+
+static PyObject *
+code_getcellvars(PyCodeObject *code, void *closure)
+{
+ return _PyCode_GetCellvars(code);
+}
+
+static PyObject *
+code_getfreevars(PyCodeObject *code, void *closure)
+{
+ return _PyCode_GetFreevars(code);
+}
+
static PyGetSetDef code_getsetlist[] = {
{"co_lnotab", (getter)code_getlnotab, NULL, NULL},
+ // The following old names are kept for backward compatibility.
+ {"co_nlocals", (getter)code_getnlocals, NULL, NULL},
+ {"co_varnames", (getter)code_getvarnames, NULL, NULL},
+ {"co_cellvars", (getter)code_getcellvars, NULL, NULL},
+ {"co_freevars", (getter)code_getfreevars, NULL, NULL},
{0}
};
@@ -1212,15 +1431,17 @@ static PyObject *
code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
{
Py_ssize_t res = _PyObject_SIZE(Py_TYPE(co));
- _PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra;
- if (co->co_cell2arg != NULL && co->co_cellvars != NULL) {
- res += co->co_ncellvars * sizeof(Py_ssize_t);
- }
+ _PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra;
if (co_extra != NULL) {
res += sizeof(_PyCodeObjectExtra) +
(co_extra->ce_size-1) * sizeof(co_extra->ce_extras[0]);
}
+
+ if (co->co_cell2arg != NULL && co->co_cellvars != NULL) {
+ res += co->co_ncellvars * sizeof(Py_ssize_t);
+ }
+
if (co->co_opcache != NULL) {
assert(co->co_opcache_map != NULL);
// co_opcache_map
@@ -1228,6 +1449,7 @@ code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
// co_opcache
res += co->co_opcache_size * sizeof(_PyOpcache);
}
+
return PyLong_FromSsize_t(res);
}
@@ -1298,11 +1520,65 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
return NULL;
}
- return (PyObject *)PyCode_NewWithPosOnlyArgs(
+ PyCodeObject *co = NULL;
+ PyObject *varnames = NULL;
+ PyObject *cellvars = NULL;
+ PyObject *freevars = NULL;
+ if (co_varnames == NULL) {
+ varnames = get_localsplus_names(self, CO_FAST_LOCAL, self->co_nlocals);
+ if (varnames == NULL) {
+ goto error;
+ }
+ co_varnames = varnames;
+ }
+ if (co_cellvars == NULL) {
+ cellvars = get_localsplus_names(self, CO_FAST_CELL, self->co_ncellvars);
+ if (cellvars == NULL) {
+ goto error;
+ }
+ co_cellvars = cellvars;
+ }
+ if (co_freevars == NULL) {
+ freevars = get_localsplus_names(self, CO_FAST_FREE, self->co_nfreevars);
+ if (freevars == NULL) {
+ goto error;
+ }
+ co_freevars = freevars;
+ }
+
+ co = PyCode_NewWithPosOnlyArgs(
co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals,
co_stacksize, co_flags, (PyObject*)co_code, co_consts, co_names,
co_varnames, co_freevars, co_cellvars, co_filename, co_name,
co_firstlineno, (PyObject*)co_linetable, (PyObject*)co_exceptiontable);
+
+error:
+ Py_XDECREF(varnames);
+ Py_XDECREF(cellvars);
+ Py_XDECREF(freevars);
+ return (PyObject *)co;
+}
+
+/*[clinic input]
+code._varname_from_oparg
+
+ oparg: int
+
+(internal-only) Return the local variable name for the given oparg.
+
+WARNING: this method is for internal use only and may change or go away.
+[clinic start generated code]*/
+
+static PyObject *
+code__varname_from_oparg_impl(PyCodeObject *self, int oparg)
+/*[clinic end generated code: output=1fd1130413184206 input=c5fa3ee9bac7d4ca]*/
+{
+ PyObject *name = PyTuple_GetItem(self->co_localsplusnames, oparg);
+ if (name == NULL) {
+ return NULL;
+ }
+ Py_INCREF(name);
+ return name;
}
/* XXX code objects need to participate in GC? */
@@ -1311,6 +1587,7 @@ static struct PyMethodDef code_methods[] = {
{"__sizeof__", (PyCFunction)code_sizeof, METH_NOARGS},
{"co_lines", (PyCFunction)code_linesiterator, METH_NOARGS},
CODE_REPLACE_METHODDEF
+ CODE__VARNAME_FROM_OPARG_METHODDEF
{NULL, NULL} /* sentinel */
};