]> granicus.if.org Git - python/commitdiff
Fix PyFrame_FastToLocals() and counterpart to deal with cells and
authorJeremy Hylton <jeremy@alum.mit.edu>
Wed, 21 Mar 2001 16:43:47 +0000 (16:43 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Wed, 21 Mar 2001 16:43:47 +0000 (16:43 +0000)
frees.  Note there doesn't seem to be any way to test LocalsToFast(),
because the instructions that trigger it are illegal in nested scopes
with free variables.

Fix allocation strategy for cells that are also formal parameters.
Instead of emitting LOAD_FAST / STORE_DEREF pairs for each parameter,
have the argument handling code in eval_code2() do the right thing.

A side-effect of this change is that cell variables that are also
arguments are listed at the front of co_cellvars in the order they
appear in the argument list.

Objects/frameobject.c
Python/ceval.c
Python/compile.c

index a5300d1de3e3c0fe286f69627332aa80d403c00c..74e701223218d5c2dbf343b835e22dfe2c2339ce 100644 (file)
@@ -251,7 +251,51 @@ PyFrame_BlockPop(PyFrameObject *f)
 
 /* Convert between "fast" version of locals and dictionary version */
 
-/* XXX should also copy free variables and cell variables */
+void
+map_to_dict(PyObject *map, int nmap, PyObject *dict, PyObject **values,
+           int deref)
+{
+       int j;
+       for (j = nmap; --j >= 0; ) {
+               PyObject *key = PyTuple_GetItem(map, j);
+               PyObject *value = values[j];
+               if (deref)
+                       value = PyCell_GET(value);
+               if (value == NULL) {
+                       PyErr_Clear();
+                       if (PyDict_DelItem(dict, key) != 0)
+                               PyErr_Clear();
+               }
+               else {
+                       if (PyDict_SetItem(dict, key, value) != 0)
+                               PyErr_Clear();
+               }
+       }
+}
+
+void
+dict_to_map(PyObject *map, int nmap, PyObject *dict, PyObject **values,
+           int deref, int clear)
+{
+       int j;
+       for (j = nmap; --j >= 0; ) {
+               PyObject *key = PyTuple_GetItem(map, j);
+               PyObject *value = PyDict_GetItem(dict, key);
+               Py_XINCREF(value);
+               if (deref) {
+                       if (value) {
+                               if (PyCell_Set(values[j], value) < 0)
+                                       PyErr_Clear();
+                       } else if (clear) {
+                               Py_XDECREF(values[j]);
+                               values[j] = value;
+                       }
+               } else if (value != NULL || clear) {
+                       Py_XDECREF(values[j]);
+                       values[j] = value;
+               }
+       }
+}
 
 void
 PyFrame_FastToLocals(PyFrameObject *f)
@@ -281,18 +325,19 @@ PyFrame_FastToLocals(PyFrameObject *f)
        j = PyTuple_Size(map);
        if (j > f->f_nlocals)
                j = f->f_nlocals;
-       for (; --j >= 0; ) {
-               PyObject *key = PyTuple_GetItem(map, j);
-               PyObject *value = fast[j];
-               if (value == NULL) {
-                       PyErr_Clear();
-                       if (PyDict_DelItem(locals, key) != 0)
-                               PyErr_Clear();
-               }
-               else {
-                       if (PyDict_SetItem(locals, key, value) != 0)
-                               PyErr_Clear();
+       map_to_dict(map, j, locals, fast, 0);
+       if (f->f_ncells || f->f_nfreevars) {
+               if (!(PyTuple_Check(f->f_code->co_cellvars)
+                     && PyTuple_Check(f->f_code->co_freevars))) {
+                       Py_DECREF(locals);
+                       return;
                }
+               map_to_dict(f->f_code->co_cellvars, 
+                           PyTuple_GET_SIZE(f->f_code->co_cellvars),
+                           locals, fast + f->f_nlocals, 1);
+               map_to_dict(f->f_code->co_freevars, 
+                           PyTuple_GET_SIZE(f->f_code->co_freevars),
+                           locals, fast + f->f_nlocals + f->f_ncells, 1);
        }
        PyErr_Restore(error_type, error_value, error_traceback);
 }
@@ -318,14 +363,17 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
        j = PyTuple_Size(map);
        if (j > f->f_nlocals)
                j = f->f_nlocals;
-       for (; --j >= 0; ) {
-               PyObject *key = PyTuple_GetItem(map, j);
-               PyObject *value = PyDict_GetItem(locals, key);
-               Py_XINCREF(value);
-               if (value != NULL || clear) {
-                       Py_XDECREF(fast[j]);
-                       fast[j] = value;
-               }
+       dict_to_map(f->f_code->co_varnames, j, locals, fast, 0, clear);
+       if (f->f_ncells || f->f_nfreevars) {
+               if (!(PyTuple_Check(f->f_code->co_cellvars)
+                     && PyTuple_Check(f->f_code->co_freevars)))
+                       return;
+               dict_to_map(f->f_code->co_cellvars, 
+                           PyTuple_GET_SIZE(f->f_code->co_cellvars),
+                           locals, fast, 1, clear);
+               dict_to_map(f->f_code->co_freevars, 
+                           PyTuple_GET_SIZE(f->f_code->co_freevars),
+                           locals, fast, 1, clear);
        }
        PyErr_Restore(error_type, error_value, error_traceback);
 }
index cb5936de6160e1a451d0be24752da346f4e60a80..22b3ea0e0ae72b88b6496a98809e0e51a95f4dba 100644 (file)
@@ -570,11 +570,52 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                        goto fail;
                }
        }
-       /* Allocate storage for cell vars and copy free vars into frame */ 
+       /* Allocate and initialize storage for cell vars, and copy free
+          vars into frame.  This isn't too efficient right now. */
        if (f->f_ncells) {
-               int i;
-               for (i = 0; i < f->f_ncells; ++i)
-                       freevars[i] = PyCell_New(NULL);
+               int i = 0, j = 0, nargs, found;
+               char *cellname, *argname;
+               PyObject *c;
+
+               nargs = co->co_argcount;
+               if (co->co_flags & CO_VARARGS)
+                       nargs++;
+               if (co->co_flags & CO_VARKEYWORDS)
+                       nargs++;
+
+               /* Check for cells that shadow args */
+               for (i = 0; i < f->f_ncells && j < nargs; ++i) {
+                       cellname = PyString_AS_STRING(
+                               PyTuple_GET_ITEM(co->co_cellvars, i));
+                       found = 0;
+                       while (j < nargs) {
+                               argname = PyString_AS_STRING(
+                                       PyTuple_GET_ITEM(co->co_varnames, j));
+                               if (strcmp(cellname, argname) == 0) {
+                                       c = PyCell_New(GETLOCAL(j));
+                                       if (c == NULL)
+                                               goto fail;
+                                       GETLOCAL(f->f_nlocals + i) = c;
+                                       found = 1;
+                                       break;
+                               }
+                               j++;
+                       }
+                       if (found == 0) {
+                               c = PyCell_New(NULL);
+                               if (c == NULL)
+                                       goto fail;
+                               SETLOCAL(f->f_nlocals + i, c);
+                       }
+               }
+               /* Initialize any that are left */
+               while (i < f->f_ncells) {
+                       c = PyCell_New(NULL);
+                       if (c == NULL)
+                               goto fail;
+                       SETLOCAL(f->f_nlocals + i, c);
+                       i++;
+               }
        }
        if (f->f_nfreevars) {
                int i;
index 07729b1b3c27a93b7a90981a9e8d663b551d97e6..ed50f7ef41b5a0804a4dfb27a0b0c14c9ce9d8cb 100644 (file)
@@ -3552,16 +3552,7 @@ com_arglist(struct compiling *c, node *n)
                        break;
                REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
                fp = CHILD(ch, 0);
-               if (TYPE(fp) == NAME) {
-                       PyObject *v;
-                       name = STR(fp); 
-                       v = PyDict_GetItemString(c->c_cellvars, name);
-                       if (v) {
-                               com_addoparg(c, LOAD_FAST, narg);
-                               com_addoparg(c, STORE_DEREF, 
-                                            PyInt_AS_LONG(v));
-                       }
-               } else {
+               if (TYPE(fp) != NAME) {
                        name = nbuf;
                        sprintf(nbuf, ".%d", i);
                        complex = 1;
@@ -3576,47 +3567,6 @@ com_arglist(struct compiling *c, node *n)
                else
                        REQ(ch, COMMA);
        }
-       /* Handle *arguments */
-       if (i < nch) {
-               node *ch;
-               ch = CHILD(n, i);
-               if (TYPE(ch) != DOUBLESTAR) {
-                       REQ(ch, STAR);
-                       ch = CHILD(n, i+1);
-                       if (TYPE(ch) == NAME) {
-                               PyObject *v;
-                               i += 3;
-                               v = PyDict_GetItemString(c->c_cellvars,
-                                                        STR(ch));
-                               if (v) {
-                                       com_addoparg(c, LOAD_FAST, narg);
-                                       com_addoparg(c, STORE_DEREF, 
-                                                    PyInt_AS_LONG(v));
-                       }
-                               narg++;
-               }
-       }
-       }
-       /* Handle **keywords */
-       if (i < nch) {
-               PyObject *v;
-               node *ch;
-               ch = CHILD(n, i);
-               if (TYPE(ch) != DOUBLESTAR) {
-                       REQ(ch, STAR);
-                       ch = CHILD(n, i+1);
-                       REQ(ch, STAR);
-                       ch = CHILD(n, i+2);
-               }
-               else
-                       ch = CHILD(n, i+1);
-               REQ(ch, NAME);
-               v = PyDict_GetItemString(c->c_cellvars, STR(ch));
-               if (v) {
-                       com_addoparg(c, LOAD_FAST, narg);
-                       com_addoparg(c, STORE_DEREF, PyInt_AS_LONG(v));
-               }                       
-       }
        if (complex) {
                /* Generate code for complex arguments only after
                   having counted the simple arguments */
@@ -4137,6 +4087,69 @@ symtable_resolve_free(struct compiling *c, PyObject *name,
        return 0;
 }
 
+/* If a variable is a cell and an argument, make sure that appears in
+   co_cellvars before any variable to its right in varnames. 
+*/
+
+
+static int
+symtable_cellvar_offsets(PyObject **cellvars, int argcount, 
+                        PyObject *varnames, int flags) 
+{
+       PyObject *v, *w, *d, *list = NULL;
+       int i, pos;
+
+       if (flags & CO_VARARGS)
+               argcount++;
+       if (flags & CO_VARKEYWORDS)
+               argcount++;
+       for (i = argcount; --i >= 0; ) {
+               v = PyList_GET_ITEM(varnames, i);
+               if (PyDict_GetItem(*cellvars, v)) {
+                       if (list == NULL) {
+                               list = PyList_New(1);
+                               if (list == NULL)
+                                       return -1;
+                               PyList_SET_ITEM(list, 0, v);
+                               Py_INCREF(v);
+                       } else
+                               PyList_Insert(list, 0, v);
+               }
+       }
+       if (list == NULL || PyList_GET_SIZE(list) == 0)
+               return 0;
+       /* There are cellvars that are also arguments.  Create a dict
+          to replace cellvars and put the args at the front.
+       */
+       d = PyDict_New();
+       for (i = PyList_GET_SIZE(list); --i >= 0; ) {
+               v = PyInt_FromLong(i);
+               if (v == NULL) 
+                       goto fail;
+               if (PyDict_SetItem(d, PyList_GET_ITEM(list, i), v) < 0)
+                       goto fail;
+               if (PyDict_DelItem(*cellvars, PyList_GET_ITEM(list, i)) < 0)
+                       goto fail;
+       }
+       pos = 0;
+       i = PyList_GET_SIZE(list);
+       Py_DECREF(list);
+       while (PyDict_Next(*cellvars, &pos, &v, &w)) {
+               w = PyInt_FromLong(i++);  /* don't care about the old key */
+               if (PyDict_SetItem(d, v, w) < 0) {
+                       Py_DECREF(w);
+                       goto fail;
+               }
+               Py_DECREF(w);
+       }
+       Py_DECREF(*cellvars);
+       *cellvars = d;
+       return 1;
+ fail:
+       Py_DECREF(d);
+       return -1;
+}
+
 static int
 symtable_freevar_offsets(PyObject *freevars, int offset)
 {
@@ -4386,6 +4399,11 @@ symtable_load_symbols(struct compiling *c)
                }
        }
 
+       if (si.si_ncells > 1) { /* one cell is always in order */
+               if (symtable_cellvar_offsets(&c->c_cellvars, c->c_argcount,
+                                            c->c_varnames, c->c_flags) < 0)
+                       return -1;
+       }
        if (symtable_freevar_offsets(c->c_freevars, si.si_ncells) < 0)
                return -1;
        return symtable_update_flags(c, ste, &si);