diff -r 52744a5a9260 Include/code.h --- a/Include/code.h Fri Jun 24 09:37:26 2011 -0500 +++ b/Include/code.h Fri Jun 24 11:03:40 2011 -0500 @@ -17,16 +17,17 @@ typedef struct { int co_flags; /* CO_..., see below */ PyObject *co_code; /* instruction opcodes */ PyObject *co_consts; /* list (constants used) */ PyObject *co_names; /* list of strings (names used) */ 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) */ /* 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_name; /* unicode (name, for reference) */ int co_firstlineno; /* first source line number */ PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See Objects/lnotab_notes.txt for details. */ void *co_zombieframe; /* for optimization only (see frameobject.c) */ PyObject *co_weakreflist; /* to support weakrefs to code objects */ } PyCodeObject; diff -r 52744a5a9260 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Fri Jun 24 09:37:26 2011 -0500 +++ b/Lib/test/test_sys.py Fri Jun 24 11:03:40 2011 -0500 @@ -660,17 +660,17 @@ class SizeofTest(unittest.TestCase): # cell def get_cell(): x = 42 def inner(): return x return inner check(get_cell().__closure__[0], size(h + 'P')) # code - check(get_cell().__code__, size(h + '5i8Pi3P')) + check(get_cell().__code__, size(h + '5i9Pi3P')) # complex check(complex(0,1), size(h + '2d')) # method_descriptor (descriptor object) check(str.lower, size(h + '2PP')) # classmethod_descriptor (descriptor object) # XXX # member_descriptor (descriptor object) import datetime diff -r 52744a5a9260 Objects/codeobject.c --- a/Objects/codeobject.c Fri Jun 24 09:37:26 2011 -0500 +++ b/Objects/codeobject.c Fri Jun 24 11:03:40 2011 -0500 @@ -46,75 +46,111 @@ PyCodeObject * PyCode_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab) { PyCodeObject *co; - Py_ssize_t i; + unsigned char *cell2arg = NULL; + Py_ssize_t i, n_cellvars; /* Check argument types */ if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 || code == NULL || consts == NULL || !PyTuple_Check(consts) || names == NULL || !PyTuple_Check(names) || varnames == NULL || !PyTuple_Check(varnames) || freevars == NULL || !PyTuple_Check(freevars) || cellvars == NULL || !PyTuple_Check(cellvars) || name == NULL || !PyUnicode_Check(name) || filename == NULL || !PyUnicode_Check(filename) || lnotab == NULL || !PyBytes_Check(lnotab) || !PyObject_CheckReadBuffer(code)) { PyErr_BadInternalCall(); return NULL; } + n_cellvars = PyTuple_GET_SIZE(cellvars); intern_strings(names); intern_strings(varnames); intern_strings(freevars); intern_strings(cellvars); /* 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); if (!PyUnicode_Check(v)) continue; if (!all_name_chars(PyUnicode_AS_UNICODE(v))) continue; PyUnicode_InternInPlace(&PyTuple_GET_ITEM(consts, i)); } + /* Create mapping between cells and arguments. */ + if (n_cellvars) { + Py_ssize_t total_args = argcount + kwonlyargcount + + ((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0); + Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars; + int used_cell2arg = 0; + cell2arg = PyMem_MALLOC(alloc_size); + if (cell2arg == NULL) + return NULL; + /* The maximum number of arguments is 255, so use 255 as a value + indicating the cell is not an argument. */ + assert(total_args <= 255); + memset(cell2arg, 255, alloc_size); + for (i = 0; i < n_cellvars; i++) { + Py_ssize_t j; + PyObject *cell = PyTuple_GET_ITEM(cellvars, i); + for (j = 0; j < total_args; j++) { + PyObject *arg = PyTuple_GET_ITEM(varnames, j); + if (!PyUnicode_Compare(cell, arg)) { + cell2arg[i] = j; + used_cell2arg = 1; + break; + } + } + } + if (!used_cell2arg) { + PyMem_FREE(cell2arg); + cell2arg = NULL; + } + } co = PyObject_NEW(PyCodeObject, &PyCode_Type); - if (co != 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; - 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; + 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; } PyCodeObject * PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) { static PyObject *emptystring = NULL; static PyObject *nulltuple = NULL; @@ -325,16 +361,18 @@ code_dealloc(PyCodeObject *co) Py_XDECREF(co->co_consts); Py_XDECREF(co->co_names); Py_XDECREF(co->co_varnames); Py_XDECREF(co->co_freevars); Py_XDECREF(co->co_cellvars); Py_XDECREF(co->co_filename); Py_XDECREF(co->co_name); Py_XDECREF(co->co_lnotab); + if (co->co_cell2arg != NULL) + PyMem_FREE(co->co_cell2arg); if (co->co_zombieframe != NULL) PyObject_GC_Del(co->co_zombieframe); if (co->co_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject*)co); PyObject_DEL(co); } static PyObject * diff -r 52744a5a9260 Python/ceval.c --- a/Python/ceval.c Fri Jun 24 09:37:26 2011 -0500 +++ b/Python/ceval.c Fri Jun 24 11:03:40 2011 -0500 @@ -3352,61 +3352,34 @@ PyEval_EvalCodeEx(PyObject *_co, PyObjec } if (missing) { missing_arguments(co, missing, -1, fastlocals); goto fail; } } /* 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)) { - int i, j, nargs, found; - Py_UNICODE *cellname, *argname; - PyObject *c; - - nargs = total_args; - if (co->co_flags & CO_VARARGS) - nargs++; - if (co->co_flags & CO_VARKEYWORDS) - nargs++; - /* Initialize each cell var, taking into account cell vars that are initialized from arguments. - - 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) { + PyObject *c; + int arg; + if (co->co_cell2arg != NULL && (arg = co->co_cell2arg[i]) != 255) + c = PyCell_New(GETLOCAL(arg)); + else c = PyCell_New(NULL); - if (c == NULL) - goto fail; - SETLOCAL(co->co_nlocals + i, c); - } + if (c == NULL) + goto fail; + SETLOCAL(co->co_nlocals + i, c); } } if (PyTuple_GET_SIZE(co->co_freevars)) { - int i; for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) { PyObject *o = PyTuple_GET_ITEM(closure, i); Py_INCREF(o); freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; } } if (co->co_flags & CO_GENERATOR) {