mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
map cells to arg slots at code creation time (closes #12399)
This removes nested loops in PyEval_EvalCodeEx.
This commit is contained in:
parent
935fa016f4
commit
9003760991
4 changed files with 89 additions and 79 deletions
|
@ -22,6 +22,7 @@ typedef struct {
|
||||||
PyObject *co_freevars; /* tuple of strings (free variable names) */
|
PyObject *co_freevars; /* tuple of strings (free variable names) */
|
||||||
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
|
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
|
||||||
/* The rest doesn't count for hash or comparisons */
|
/* The rest doesn't count for hash or comparisons */
|
||||||
|
unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
|
||||||
PyObject *co_filename; /* unicode (where it was loaded from) */
|
PyObject *co_filename; /* unicode (where it was loaded from) */
|
||||||
PyObject *co_name; /* unicode (name, for reference) */
|
PyObject *co_name; /* unicode (name, for reference) */
|
||||||
int co_firstlineno; /* first source line number */
|
int co_firstlineno; /* first source line number */
|
||||||
|
@ -57,6 +58,11 @@ typedef struct {
|
||||||
|
|
||||||
#define CO_FUTURE_BARRY_AS_BDFL 0x40000
|
#define CO_FUTURE_BARRY_AS_BDFL 0x40000
|
||||||
|
|
||||||
|
/* This value is found in the co_cell2arg array when the associated cell
|
||||||
|
variable does not correspond to an argument. The maximum number of
|
||||||
|
arguments is 255 (indexed up to 254), so 255 work as a special flag.*/
|
||||||
|
#define CO_CELL_NOT_AN_ARG 255
|
||||||
|
|
||||||
/* This should be defined if a future statement modifies the syntax.
|
/* This should be defined if a future statement modifies the syntax.
|
||||||
For example, when a keyword is added.
|
For example, when a keyword is added.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -665,7 +665,7 @@ class SizeofTest(unittest.TestCase):
|
||||||
return inner
|
return inner
|
||||||
check(get_cell().__closure__[0], size(h + 'P'))
|
check(get_cell().__closure__[0], size(h + 'P'))
|
||||||
# code
|
# code
|
||||||
check(get_cell().__code__, size(h + '5i8Pi3P'))
|
check(get_cell().__code__, size(h + '5i9Pi3P'))
|
||||||
# complex
|
# complex
|
||||||
check(complex(0,1), size(h + '2d'))
|
check(complex(0,1), size(h + '2d'))
|
||||||
# method_descriptor (descriptor object)
|
# method_descriptor (descriptor object)
|
||||||
|
|
|
@ -51,7 +51,8 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
PyObject *lnotab)
|
PyObject *lnotab)
|
||||||
{
|
{
|
||||||
PyCodeObject *co;
|
PyCodeObject *co;
|
||||||
Py_ssize_t i;
|
unsigned char *cell2arg = NULL;
|
||||||
|
Py_ssize_t i, n_cellvars;
|
||||||
|
|
||||||
/* Check argument types */
|
/* Check argument types */
|
||||||
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
|
if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
|
||||||
|
@ -68,12 +69,13 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
n_cellvars = PyTuple_GET_SIZE(cellvars);
|
||||||
intern_strings(names);
|
intern_strings(names);
|
||||||
intern_strings(varnames);
|
intern_strings(varnames);
|
||||||
intern_strings(freevars);
|
intern_strings(freevars);
|
||||||
intern_strings(cellvars);
|
intern_strings(cellvars);
|
||||||
/* Intern selected string constants */
|
/* Intern selected string constants */
|
||||||
for (i = PyTuple_Size(consts); --i >= 0; ) {
|
for (i = PyTuple_GET_SIZE(consts); --i >= 0; ) {
|
||||||
PyObject *v = PyTuple_GetItem(consts, i);
|
PyObject *v = PyTuple_GetItem(consts, i);
|
||||||
if (!PyUnicode_Check(v))
|
if (!PyUnicode_Check(v))
|
||||||
continue;
|
continue;
|
||||||
|
@ -81,35 +83,67 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
continue;
|
continue;
|
||||||
PyUnicode_InternInPlace(&PyTuple_GET_ITEM(consts, i));
|
PyUnicode_InternInPlace(&PyTuple_GET_ITEM(consts, i));
|
||||||
}
|
}
|
||||||
co = PyObject_NEW(PyCodeObject, &PyCode_Type);
|
/* Create mapping between cells and arguments if needed. */
|
||||||
if (co != NULL) {
|
if (n_cellvars) {
|
||||||
co->co_argcount = argcount;
|
Py_ssize_t total_args = argcount + kwonlyargcount +
|
||||||
co->co_kwonlyargcount = kwonlyargcount;
|
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
||||||
co->co_nlocals = nlocals;
|
Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars;
|
||||||
co->co_stacksize = stacksize;
|
int used_cell2arg = 0;
|
||||||
co->co_flags = flags;
|
cell2arg = PyMem_MALLOC(alloc_size);
|
||||||
Py_INCREF(code);
|
if (cell2arg == NULL)
|
||||||
co->co_code = code;
|
return NULL;
|
||||||
Py_INCREF(consts);
|
memset(cell2arg, CO_CELL_NOT_AN_ARG, alloc_size);
|
||||||
co->co_consts = consts;
|
/* Find cells which are also arguments. */
|
||||||
Py_INCREF(names);
|
for (i = 0; i < n_cellvars; i++) {
|
||||||
co->co_names = names;
|
Py_ssize_t j;
|
||||||
Py_INCREF(varnames);
|
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
|
||||||
co->co_varnames = varnames;
|
for (j = 0; j < total_args; j++) {
|
||||||
Py_INCREF(freevars);
|
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
|
||||||
co->co_freevars = freevars;
|
if (!PyUnicode_Compare(cell, arg)) {
|
||||||
Py_INCREF(cellvars);
|
cell2arg[i] = j;
|
||||||
co->co_cellvars = cellvars;
|
used_cell2arg = 1;
|
||||||
Py_INCREF(filename);
|
break;
|
||||||
co->co_filename = filename;
|
}
|
||||||
Py_INCREF(name);
|
}
|
||||||
co->co_name = name;
|
}
|
||||||
co->co_firstlineno = firstlineno;
|
if (!used_cell2arg) {
|
||||||
Py_INCREF(lnotab);
|
PyMem_FREE(cell2arg);
|
||||||
co->co_lnotab = lnotab;
|
cell2arg = NULL;
|
||||||
co->co_zombieframe = NULL;
|
}
|
||||||
co->co_weakreflist = NULL;
|
|
||||||
}
|
}
|
||||||
|
co = PyObject_NEW(PyCodeObject, &PyCode_Type);
|
||||||
|
if (co == NULL) {
|
||||||
|
if (cell2arg)
|
||||||
|
PyMem_FREE(cell2arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
co->co_argcount = argcount;
|
||||||
|
co->co_kwonlyargcount = kwonlyargcount;
|
||||||
|
co->co_nlocals = nlocals;
|
||||||
|
co->co_stacksize = stacksize;
|
||||||
|
co->co_flags = flags;
|
||||||
|
Py_INCREF(code);
|
||||||
|
co->co_code = code;
|
||||||
|
Py_INCREF(consts);
|
||||||
|
co->co_consts = consts;
|
||||||
|
Py_INCREF(names);
|
||||||
|
co->co_names = names;
|
||||||
|
Py_INCREF(varnames);
|
||||||
|
co->co_varnames = varnames;
|
||||||
|
Py_INCREF(freevars);
|
||||||
|
co->co_freevars = freevars;
|
||||||
|
Py_INCREF(cellvars);
|
||||||
|
co->co_cellvars = cellvars;
|
||||||
|
co->co_cell2arg = cell2arg;
|
||||||
|
Py_INCREF(filename);
|
||||||
|
co->co_filename = filename;
|
||||||
|
Py_INCREF(name);
|
||||||
|
co->co_name = name;
|
||||||
|
co->co_firstlineno = firstlineno;
|
||||||
|
Py_INCREF(lnotab);
|
||||||
|
co->co_lnotab = lnotab;
|
||||||
|
co->co_zombieframe = NULL;
|
||||||
|
co->co_weakreflist = NULL;
|
||||||
return co;
|
return co;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +364,8 @@ code_dealloc(PyCodeObject *co)
|
||||||
Py_XDECREF(co->co_filename);
|
Py_XDECREF(co->co_filename);
|
||||||
Py_XDECREF(co->co_name);
|
Py_XDECREF(co->co_name);
|
||||||
Py_XDECREF(co->co_lnotab);
|
Py_XDECREF(co->co_lnotab);
|
||||||
|
if (co->co_cell2arg != NULL)
|
||||||
|
PyMem_FREE(co->co_cell2arg);
|
||||||
if (co->co_zombieframe != NULL)
|
if (co->co_zombieframe != NULL)
|
||||||
PyObject_GC_Del(co->co_zombieframe);
|
PyObject_GC_Del(co->co_zombieframe);
|
||||||
if (co->co_weakreflist != NULL)
|
if (co->co_weakreflist != NULL)
|
||||||
|
|
|
@ -3357,56 +3357,24 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and initialize storage for cell vars, and copy free
|
/* Allocate and initialize storage for cell vars, and copy free
|
||||||
vars into frame. This isn't too efficient right now. */
|
vars into frame. */
|
||||||
if (PyTuple_GET_SIZE(co->co_cellvars)) {
|
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
|
||||||
int i, j, nargs, found;
|
|
||||||
Py_UNICODE *cellname, *argname;
|
|
||||||
PyObject *c;
|
PyObject *c;
|
||||||
|
int arg;
|
||||||
nargs = total_args;
|
/* Possibly account for the cell variable being an argument. */
|
||||||
if (co->co_flags & CO_VARARGS)
|
if (co->co_cell2arg != NULL &&
|
||||||
nargs++;
|
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG)
|
||||||
if (co->co_flags & CO_VARKEYWORDS)
|
c = PyCell_New(GETLOCAL(arg));
|
||||||
nargs++;
|
else
|
||||||
|
c = PyCell_New(NULL);
|
||||||
/* Initialize each cell var, taking into account
|
if (c == NULL)
|
||||||
cell vars that are initialized from arguments.
|
goto fail;
|
||||||
|
SETLOCAL(co->co_nlocals + i, c);
|
||||||
Should arrange for the compiler to put cellvars
|
|
||||||
that are arguments at the beginning of the cellvars
|
|
||||||
list so that we can march over it more efficiently?
|
|
||||||
*/
|
|
||||||
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
|
|
||||||
cellname = PyUnicode_AS_UNICODE(
|
|
||||||
PyTuple_GET_ITEM(co->co_cellvars, i));
|
|
||||||
found = 0;
|
|
||||||
for (j = 0; j < nargs; j++) {
|
|
||||||
argname = PyUnicode_AS_UNICODE(
|
|
||||||
PyTuple_GET_ITEM(co->co_varnames, j));
|
|
||||||
if (Py_UNICODE_strcmp(cellname, argname) == 0) {
|
|
||||||
c = PyCell_New(GETLOCAL(j));
|
|
||||||
if (c == NULL)
|
|
||||||
goto fail;
|
|
||||||
GETLOCAL(co->co_nlocals + i) = c;
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found == 0) {
|
|
||||||
c = PyCell_New(NULL);
|
|
||||||
if (c == NULL)
|
|
||||||
goto fail;
|
|
||||||
SETLOCAL(co->co_nlocals + i, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (PyTuple_GET_SIZE(co->co_freevars)) {
|
for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
|
||||||
int i;
|
PyObject *o = PyTuple_GET_ITEM(closure, i);
|
||||||
for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
|
Py_INCREF(o);
|
||||||
PyObject *o = PyTuple_GET_ITEM(closure, i);
|
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
|
||||||
Py_INCREF(o);
|
|
||||||
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (co->co_flags & CO_GENERATOR) {
|
if (co->co_flags & CO_GENERATOR) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue