Kaydet (Commit) 220ae7c0 authored tarafından Jeremy Hylton's avatar Jeremy Hylton

Fix PyFrame_FastToLocals() and counterpart to deal with cells and

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.
üst bec1958d
...@@ -251,7 +251,51 @@ PyFrame_BlockPop(PyFrameObject *f) ...@@ -251,7 +251,51 @@ PyFrame_BlockPop(PyFrameObject *f)
/* Convert between "fast" version of locals and dictionary version */ /* 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 void
PyFrame_FastToLocals(PyFrameObject *f) PyFrame_FastToLocals(PyFrameObject *f)
...@@ -281,18 +325,19 @@ PyFrame_FastToLocals(PyFrameObject *f) ...@@ -281,18 +325,19 @@ PyFrame_FastToLocals(PyFrameObject *f)
j = PyTuple_Size(map); j = PyTuple_Size(map);
if (j > f->f_nlocals) if (j > f->f_nlocals)
j = f->f_nlocals; j = f->f_nlocals;
for (; --j >= 0; ) { map_to_dict(map, j, locals, fast, 0);
PyObject *key = PyTuple_GetItem(map, j); if (f->f_ncells || f->f_nfreevars) {
PyObject *value = fast[j]; if (!(PyTuple_Check(f->f_code->co_cellvars)
if (value == NULL) { && PyTuple_Check(f->f_code->co_freevars))) {
PyErr_Clear(); Py_DECREF(locals);
if (PyDict_DelItem(locals, key) != 0) return;
PyErr_Clear();
}
else {
if (PyDict_SetItem(locals, key, value) != 0)
PyErr_Clear();
} }
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); PyErr_Restore(error_type, error_value, error_traceback);
} }
...@@ -318,14 +363,17 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) ...@@ -318,14 +363,17 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
j = PyTuple_Size(map); j = PyTuple_Size(map);
if (j > f->f_nlocals) if (j > f->f_nlocals)
j = f->f_nlocals; j = f->f_nlocals;
for (; --j >= 0; ) { dict_to_map(f->f_code->co_varnames, j, locals, fast, 0, clear);
PyObject *key = PyTuple_GetItem(map, j); if (f->f_ncells || f->f_nfreevars) {
PyObject *value = PyDict_GetItem(locals, key); if (!(PyTuple_Check(f->f_code->co_cellvars)
Py_XINCREF(value); && PyTuple_Check(f->f_code->co_freevars)))
if (value != NULL || clear) { return;
Py_XDECREF(fast[j]); dict_to_map(f->f_code->co_cellvars,
fast[j] = value; 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); PyErr_Restore(error_type, error_value, error_traceback);
} }
......
...@@ -570,11 +570,52 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -570,11 +570,52 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
goto fail; 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) { if (f->f_ncells) {
int i; int i = 0, j = 0, nargs, found;
for (i = 0; i < f->f_ncells; ++i) char *cellname, *argname;
freevars[i] = PyCell_New(NULL); 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) { if (f->f_nfreevars) {
int i; int i;
......
...@@ -3552,16 +3552,7 @@ com_arglist(struct compiling *c, node *n) ...@@ -3552,16 +3552,7 @@ com_arglist(struct compiling *c, node *n)
break; break;
REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */ REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
fp = CHILD(ch, 0); fp = CHILD(ch, 0);
if (TYPE(fp) == NAME) { 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 {
name = nbuf; name = nbuf;
sprintf(nbuf, ".%d", i); sprintf(nbuf, ".%d", i);
complex = 1; complex = 1;
...@@ -3576,47 +3567,6 @@ com_arglist(struct compiling *c, node *n) ...@@ -3576,47 +3567,6 @@ com_arglist(struct compiling *c, node *n)
else else
REQ(ch, COMMA); 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) { if (complex) {
/* Generate code for complex arguments only after /* Generate code for complex arguments only after
having counted the simple arguments */ having counted the simple arguments */
...@@ -4137,6 +4087,69 @@ symtable_resolve_free(struct compiling *c, PyObject *name, ...@@ -4137,6 +4087,69 @@ symtable_resolve_free(struct compiling *c, PyObject *name,
return 0; 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 static int
symtable_freevar_offsets(PyObject *freevars, int offset) symtable_freevar_offsets(PyObject *freevars, int offset)
{ {
...@@ -4386,6 +4399,11 @@ symtable_load_symbols(struct compiling *c) ...@@ -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) if (symtable_freevar_offsets(c->c_freevars, si.si_ncells) < 0)
return -1; return -1;
return symtable_update_flags(c, ste, &si); return symtable_update_flags(c, ste, &si);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment