aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/compile.c
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2021-06-07 12:22:26 -0600
committerGitHub <noreply@github.com>2021-06-07 12:22:26 -0600
commit2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6 (patch)
treed3983e5282f575560cb7449fae4785447fdfff14 /Python/compile.c
parent001eb520b5757294dc455c900d94b7b153de6cdd (diff)
downloadcpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.tar.gz
cpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.zip
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 'Python/compile.c')
-rw-r--r--Python/compile.c160
1 files changed, 123 insertions, 37 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 03d522b34f1..d5a0234c0fe 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2047,16 +2047,16 @@ static int
compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags,
PyObject *qualname)
{
- Py_ssize_t i, free = PyCode_GetNumFree(co);
if (qualname == NULL)
qualname = co->co_name;
- if (free) {
- for (i = 0; i < free; ++i) {
+ if (co->co_nfreevars) {
+ int i = co->co_nlocals + co->co_ncellvars;
+ for (; i < co->co_nlocalsplus; ++i) {
/* Bypass com_addop_varname because it will generate
LOAD_DEREF but LOAD_CLOSURE is needed.
*/
- PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
+ PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
/* Special case: If a class contains a method with a
free variable that has the same name as a method,
@@ -2076,6 +2076,10 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags,
arg = compiler_lookup_arg(c->u->u_freevars, name);
}
if (arg == -1) {
+ PyObject *freevars = _PyCode_GetFreevars(co);
+ if (freevars == NULL) {
+ PyErr_Clear();
+ }
PyErr_Format(PyExc_SystemError,
"compiler_lookup_arg(name=%R) with reftype=%d failed in %S; "
"freevars of code %S: %R",
@@ -2083,13 +2087,14 @@ compiler_make_closure(struct compiler *c, PyCodeObject *co, Py_ssize_t flags,
reftype,
c->u->u_name,
co->co_name,
- co->co_freevars);
+ freevars);
+ Py_DECREF(freevars);
return 0;
}
ADDOP_I(c, LOAD_CLOSURE, arg);
}
flags |= 0x08;
- ADDOP_I(c, BUILD_TUPLE, free);
+ ADDOP_I(c, BUILD_TUPLE, co->co_nfreevars);
}
ADDOP_LOAD_CONST(c, (PyObject*)co);
ADDOP_LOAD_CONST(c, qualname);
@@ -7176,6 +7181,46 @@ merge_const_one(struct compiler *c, PyObject **obj)
return 1;
}
+// This is in codeobject.c.
+extern void _Py_set_localsplus_info(int, PyObject *, _PyLocalsPlusKind,
+ PyObject *, _PyLocalsPlusKinds);
+
+static void
+compute_localsplus_info(struct compiler *c,
+ PyObject *names, _PyLocalsPlusKinds kinds)
+{
+ int nlocalsplus = (int)PyTuple_GET_SIZE(names);
+
+ PyObject *k, *v;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(c->u->u_varnames, &pos, &k, &v)) {
+ int offset = (int)PyLong_AS_LONG(v);
+ assert(offset >= 0);
+ assert(offset < nlocalsplus);
+ // For now we do not distinguish arg kinds.
+ _Py_set_localsplus_info(offset, k, CO_FAST_LOCAL, names, kinds);
+ }
+ int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames);
+
+ pos = 0;
+ while (PyDict_Next(c->u->u_cellvars, &pos, &k, &v)) {
+ int offset = (int)PyLong_AS_LONG(v);
+ assert(offset >= 0);
+ offset += nlocals;
+ assert(offset < nlocalsplus);
+ _Py_set_localsplus_info(offset, k, CO_FAST_CELL, names, kinds);
+ }
+
+ pos = 0;
+ while (PyDict_Next(c->u->u_freevars, &pos, &k, &v)) {
+ int offset = (int)PyLong_AS_LONG(v);
+ assert(offset >= 0);
+ offset += nlocals;
+ assert(offset < nlocalsplus);
+ _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds);
+ }
+}
+
static PyCodeObject *
makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
int maxdepth)
@@ -7183,36 +7228,22 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
PyCodeObject *co = NULL;
PyObject *names = NULL;
PyObject *consts = NULL;
- PyObject *varnames = NULL;
+ PyObject *localsplusnames = NULL;
+ _PyLocalsPlusKinds localspluskinds = NULL;
PyObject *name = NULL;
- PyObject *freevars = NULL;
- PyObject *cellvars = NULL;
- int flags;
- int posorkeywordargcount, posonlyargcount, kwonlyargcount;
names = dict_keys_inorder(c->u->u_names, 0);
- varnames = dict_keys_inorder(c->u->u_varnames, 0);
- if (!names || !varnames) {
+ if (!names) {
goto error;
}
- cellvars = dict_keys_inorder(c->u->u_cellvars, 0);
- if (!cellvars)
- goto error;
- freevars = dict_keys_inorder(c->u->u_freevars, PyTuple_GET_SIZE(cellvars));
- if (!freevars)
- goto error;
-
- if (!merge_const_one(c, &names) ||
- !merge_const_one(c, &varnames) ||
- !merge_const_one(c, &cellvars) ||
- !merge_const_one(c, &freevars))
- {
+ if (!merge_const_one(c, &names)) {
goto error;
}
- flags = compute_code_flags(c);
- if (flags < 0)
+ int flags = compute_code_flags(c);
+ if (flags < 0) {
goto error;
+ }
consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */
if (consts == NULL) {
@@ -7222,9 +7253,32 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
goto error;
}
- posonlyargcount = Py_SAFE_DOWNCAST(c->u->u_posonlyargcount, Py_ssize_t, int);
- posorkeywordargcount = Py_SAFE_DOWNCAST(c->u->u_argcount, Py_ssize_t, int);
- kwonlyargcount = Py_SAFE_DOWNCAST(c->u->u_kwonlyargcount, Py_ssize_t, int);
+ assert(c->u->u_posonlyargcount < INT_MAX);
+ assert(c->u->u_argcount < INT_MAX);
+ assert(c->u->u_kwonlyargcount < INT_MAX);
+ int posonlyargcount = (int)c->u->u_posonlyargcount;
+ int posorkwargcount = (int)c->u->u_argcount;
+ assert(INT_MAX - posonlyargcount - posorkwargcount > 0);
+ int kwonlyargcount = (int)c->u->u_kwonlyargcount;
+
+ Py_ssize_t nlocals = PyDict_GET_SIZE(c->u->u_varnames);
+ Py_ssize_t ncellvars = PyDict_GET_SIZE(c->u->u_cellvars);
+ Py_ssize_t nfreevars = PyDict_GET_SIZE(c->u->u_freevars);
+ assert(nlocals < INT_MAX);
+ assert(ncellvars < INT_MAX);
+ assert(nfreevars < INT_MAX);
+ assert(INT_MAX - nlocals - ncellvars - nfreevars > 0);
+ int nlocalsplus = (int)nlocals + (int)ncellvars + (int)nfreevars;
+
+ localsplusnames = PyTuple_New(nlocalsplus);
+ if (localsplusnames == NULL) {
+ goto error;
+ }
+ if (_PyCode_InitLocalsPlusKinds(nlocalsplus, &localspluskinds) < 0) {
+ goto error;
+ }
+ compute_localsplus_info(c, localsplusnames, localspluskinds);
+
struct _PyCodeConstructor con = {
.filename = c->c_filename,
.name = c->u->u_name,
@@ -7237,11 +7291,10 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
.consts = consts,
.names = names,
- .varnames = varnames,
- .cellvars = cellvars,
- .freevars = freevars,
+ .localsplusnames = localsplusnames,
+ .localspluskinds = localspluskinds,
- .argcount = posonlyargcount + posorkeywordargcount,
+ .argcount = posonlyargcount + posorkwargcount,
.posonlyargcount = posonlyargcount,
.kwonlyargcount = kwonlyargcount,
@@ -7249,18 +7302,30 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
.exceptiontable = a->a_except_table,
};
+
if (_PyCode_Validate(&con) < 0) {
goto error;
}
+
+ if (!merge_const_one(c, &localsplusnames)) {
+ _PyCode_ClearLocalsPlusKinds(con.localspluskinds);
+ goto error;
+ }
+ con.localsplusnames = localsplusnames;
+
co = _PyCode_New(&con);
+ if (co == NULL) {
+ goto error;
+ }
+
+ localspluskinds = NULL; // This keeps it from getting freed below.
error:
Py_XDECREF(names);
Py_XDECREF(consts);
- Py_XDECREF(varnames);
+ Py_XDECREF(localsplusnames);
+ _PyCode_ClearLocalsPlusKinds(localspluskinds);
Py_XDECREF(name);
- Py_XDECREF(freevars);
- Py_XDECREF(cellvars);
return co;
}
@@ -7371,6 +7436,24 @@ guarantee_lineno_for_exits(struct assembler *a, int firstlineno) {
}
}
+static void
+offset_derefs(basicblock *entryblock, int nlocals)
+{
+ for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
+ for (int i = 0; i < b->b_iused; i++) {
+ struct instr *inst = &b->b_instr[i];
+ switch(inst->i_opcode) {
+ case LOAD_CLOSURE:
+ case LOAD_DEREF:
+ case STORE_DEREF:
+ case DELETE_DEREF:
+ case LOAD_CLASSDEREF:
+ inst->i_oparg += nlocals;
+ }
+ }
+ }
+}
+
static PyCodeObject *
assemble(struct compiler *c, int addNone)
{
@@ -7426,6 +7509,9 @@ assemble(struct compiler *c, int addNone)
a.a_entry = entryblock;
a.a_nblocks = nblocks;
+ assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX);
+ offset_derefs(entryblock, (int)PyDict_GET_SIZE(c->u->u_varnames));
+
consts = consts_dict_keys_inorder(c->u->u_consts);
if (consts == NULL) {
goto error;