Remove f_closure slot of frameobject and use f_localsplus instead.

This change eliminates an extra malloc/free when a frame with free
variables is created.  Any cell vars or free vars are stored in
f_localsplus after the locals and before the stack.

eval_code2() fills in the appropriate values after handling
initialization of locals.

To track the size the frame has an f_size member that tracks the total
size of f_localsplus. It used to be implicitly f_nlocals + f_stacksize.
This commit is contained in:
Jeremy Hylton 2001-01-29 22:51:52 +00:00
parent 55087f0c35
commit 2b724da8d9
3 changed files with 33 additions and 28 deletions

View File

@ -20,7 +20,6 @@ typedef struct _frame {
PyObject *f_builtins; /* builtin symbol table (PyDictObject) */
PyObject *f_globals; /* global symbol table (PyDictObject) */
PyObject *f_locals; /* local symbol table (PyDictObject) */
PyObject *f_closure; /* environment for free variables */
PyObject **f_valuestack; /* points after the last local */
PyObject *f_trace; /* Trace function */
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
@ -31,7 +30,10 @@ typedef struct _frame {
in this scope */
int f_iblock; /* index in f_blockstack */
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
int f_size; /* size of localsplus */
int f_nlocals; /* number of locals */
int f_ncells;
int f_nfreevars;
int f_stacksize; /* size of value stack */
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
} PyFrameObject;

View File

@ -49,6 +49,7 @@ frame_setattr(PyFrameObject *f, char *name, PyObject *value)
f_back next item on free list, or NULL
f_nlocals number of locals
f_stacksize size of value stack
f_size size of localsplus
Note that the value and block stacks are preserved -- this can save
another malloc() call or two (and two free() calls as well!).
Also note that, unlike for integers, each frame object is a
@ -79,7 +80,6 @@ frame_dealloc(PyFrameObject *f)
Py_XDECREF(f->f_builtins);
Py_XDECREF(f->f_globals);
Py_XDECREF(f->f_locals);
Py_XDECREF(f->f_closure);
Py_XDECREF(f->f_trace);
Py_XDECREF(f->f_exc_type);
Py_XDECREF(f->f_exc_value);
@ -114,7 +114,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
static PyObject *builtin_object;
PyFrameObject *f;
PyObject *builtins;
int extras, ncells;
int extras, ncells, nfrees;
if (builtin_object == NULL) {
builtin_object = PyString_InternFromString("__builtins__");
@ -128,8 +128,9 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyErr_BadInternalCall();
return NULL;
}
extras = code->co_stacksize + code->co_nlocals;
ncells = PyTuple_GET_SIZE(code->co_cellvars);
nfrees = PyTuple_GET_SIZE(code->co_freevars);
extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
if (back == NULL || back->f_globals != globals) {
builtins = PyDict_GetItem(globals, builtin_object);
if (builtins != NULL && PyModule_Check(builtins))
@ -150,19 +151,21 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
if (f == NULL)
return (PyFrameObject *)PyErr_NoMemory();
PyObject_INIT(f, &PyFrame_Type);
f->f_size = extras;
}
else {
f = free_list;
free_list = free_list->f_back;
if (f->f_nlocals + f->f_stacksize < extras) {
if (f->f_size < extras) {
f = (PyFrameObject *)
PyObject_REALLOC(f, sizeof(PyFrameObject) +
extras*sizeof(PyObject *));
if (f == NULL)
return (PyFrameObject *)PyErr_NoMemory();
f->f_size = extras;
}
else
extras = f->f_nlocals + f->f_stacksize;
extras = f->f_size;
PyObject_INIT(f, &PyFrame_Type);
}
if (builtins == NULL) {
@ -199,22 +202,6 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
locals = globals;
Py_INCREF(locals);
}
if (closure || ncells) {
int i, size;
size = ncells;
if (closure)
size += PyTuple_GET_SIZE(closure);
f->f_closure = PyTuple_New(size);
for (i = 0; i < ncells; ++i)
PyTuple_SET_ITEM(f->f_closure, i, PyCell_New(NULL));
for (i = ncells; i < size; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i - ncells);
Py_INCREF(o);
PyTuple_SET_ITEM(f->f_closure, i, o);
}
}
else
f->f_closure = NULL;
f->f_locals = locals;
f->f_trace = NULL;
f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
@ -225,12 +212,14 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
f->f_restricted = (builtins != tstate->interp->builtins);
f->f_iblock = 0;
f->f_nlocals = code->co_nlocals;
f->f_stacksize = extras - code->co_nlocals;
f->f_stacksize = code->co_stacksize;
f->f_ncells = ncells;
f->f_nfreevars = nfrees;
while (--extras >= 0)
f->f_localsplus[extras] = NULL;
f->f_valuestack = f->f_localsplus + f->f_nlocals;
f->f_valuestack = f->f_localsplus + (f->f_nlocals + ncells + nfrees);
return f;
}
@ -261,6 +250,8 @@ PyFrame_BlockPop(PyFrameObject *f)
/* Convert between "fast" version of locals and dictionary version */
/* XXX should also copy free variables and cell variables */
void
PyFrame_FastToLocals(PyFrameObject *f)
{

View File

@ -368,7 +368,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
register PyObject *t;
register PyObject *stream = NULL; /* for PRINT opcodes */
register PyFrameObject *f; /* Current frame */
register PyObject **fastlocals;
register PyObject **fastlocals, **freevars;
PyObject *retval = NULL; /* Return value */
PyThreadState *tstate = PyThreadState_GET();
unsigned char *first_instr;
@ -439,6 +439,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
tstate->frame = f;
fastlocals = f->f_localsplus;
freevars = f->f_localsplus + f->f_nlocals;
if (co->co_argcount > 0 ||
co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
@ -572,6 +573,17 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
goto fail;
}
}
/* Allocate storage for cell vars and copy free vars into frame */
if (f->f_ncells) {
int i;
for (i = 0; i < f->f_ncells; ++i)
freevars[i] = PyCell_New(NULL);
}
if (f->f_nfreevars) {
int i;
for (i = 0; i < f->f_nfreevars; ++i)
freevars[f->f_ncells + i] = PyTuple_GET_ITEM(closure, i);
}
if (tstate->sys_tracefunc != NULL) {
/* tstate->sys_tracefunc, if defined, is a function that
@ -1623,13 +1635,13 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
continue;
case LOAD_CLOSURE:
x = PyTuple_GET_ITEM(f->f_closure, oparg);
x = freevars[oparg];
Py_INCREF(x);
PUSH(x);
break;
case LOAD_DEREF:
x = PyTuple_GET_ITEM(f->f_closure, oparg);
x = freevars[oparg];
w = PyCell_Get(x);
Py_INCREF(w);
PUSH(w);
@ -1637,7 +1649,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
case STORE_DEREF:
w = POP();
x = PyTuple_GET_ITEM(f->f_closure, oparg);
x = freevars[oparg];
PyCell_Set(x, w);
continue;