mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
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:
parent
55087f0c35
commit
2b724da8d9
3 changed files with 33 additions and 28 deletions
|
@ -20,7 +20,6 @@ typedef struct _frame {
|
||||||
PyObject *f_builtins; /* builtin symbol table (PyDictObject) */
|
PyObject *f_builtins; /* builtin symbol table (PyDictObject) */
|
||||||
PyObject *f_globals; /* global symbol table (PyDictObject) */
|
PyObject *f_globals; /* global symbol table (PyDictObject) */
|
||||||
PyObject *f_locals; /* local 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_valuestack; /* points after the last local */
|
||||||
PyObject *f_trace; /* Trace function */
|
PyObject *f_trace; /* Trace function */
|
||||||
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
|
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
|
||||||
|
@ -31,7 +30,10 @@ typedef struct _frame {
|
||||||
in this scope */
|
in this scope */
|
||||||
int f_iblock; /* index in f_blockstack */
|
int f_iblock; /* index in f_blockstack */
|
||||||
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
|
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
|
||||||
|
int f_size; /* size of localsplus */
|
||||||
int f_nlocals; /* number of locals */
|
int f_nlocals; /* number of locals */
|
||||||
|
int f_ncells;
|
||||||
|
int f_nfreevars;
|
||||||
int f_stacksize; /* size of value stack */
|
int f_stacksize; /* size of value stack */
|
||||||
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
|
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
|
||||||
} PyFrameObject;
|
} PyFrameObject;
|
||||||
|
|
|
@ -49,6 +49,7 @@ frame_setattr(PyFrameObject *f, char *name, PyObject *value)
|
||||||
f_back next item on free list, or NULL
|
f_back next item on free list, or NULL
|
||||||
f_nlocals number of locals
|
f_nlocals number of locals
|
||||||
f_stacksize size of value stack
|
f_stacksize size of value stack
|
||||||
|
f_size size of localsplus
|
||||||
Note that the value and block stacks are preserved -- this can save
|
Note that the value and block stacks are preserved -- this can save
|
||||||
another malloc() call or two (and two free() calls as well!).
|
another malloc() call or two (and two free() calls as well!).
|
||||||
Also note that, unlike for integers, each frame object is a
|
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_builtins);
|
||||||
Py_XDECREF(f->f_globals);
|
Py_XDECREF(f->f_globals);
|
||||||
Py_XDECREF(f->f_locals);
|
Py_XDECREF(f->f_locals);
|
||||||
Py_XDECREF(f->f_closure);
|
|
||||||
Py_XDECREF(f->f_trace);
|
Py_XDECREF(f->f_trace);
|
||||||
Py_XDECREF(f->f_exc_type);
|
Py_XDECREF(f->f_exc_type);
|
||||||
Py_XDECREF(f->f_exc_value);
|
Py_XDECREF(f->f_exc_value);
|
||||||
|
@ -114,7 +114,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
|
||||||
static PyObject *builtin_object;
|
static PyObject *builtin_object;
|
||||||
PyFrameObject *f;
|
PyFrameObject *f;
|
||||||
PyObject *builtins;
|
PyObject *builtins;
|
||||||
int extras, ncells;
|
int extras, ncells, nfrees;
|
||||||
|
|
||||||
if (builtin_object == NULL) {
|
if (builtin_object == NULL) {
|
||||||
builtin_object = PyString_InternFromString("__builtins__");
|
builtin_object = PyString_InternFromString("__builtins__");
|
||||||
|
@ -128,8 +128,9 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
extras = code->co_stacksize + code->co_nlocals;
|
|
||||||
ncells = PyTuple_GET_SIZE(code->co_cellvars);
|
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) {
|
if (back == NULL || back->f_globals != globals) {
|
||||||
builtins = PyDict_GetItem(globals, builtin_object);
|
builtins = PyDict_GetItem(globals, builtin_object);
|
||||||
if (builtins != NULL && PyModule_Check(builtins))
|
if (builtins != NULL && PyModule_Check(builtins))
|
||||||
|
@ -150,19 +151,21 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return (PyFrameObject *)PyErr_NoMemory();
|
return (PyFrameObject *)PyErr_NoMemory();
|
||||||
PyObject_INIT(f, &PyFrame_Type);
|
PyObject_INIT(f, &PyFrame_Type);
|
||||||
|
f->f_size = extras;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
f = free_list;
|
f = free_list;
|
||||||
free_list = free_list->f_back;
|
free_list = free_list->f_back;
|
||||||
if (f->f_nlocals + f->f_stacksize < extras) {
|
if (f->f_size < extras) {
|
||||||
f = (PyFrameObject *)
|
f = (PyFrameObject *)
|
||||||
PyObject_REALLOC(f, sizeof(PyFrameObject) +
|
PyObject_REALLOC(f, sizeof(PyFrameObject) +
|
||||||
extras*sizeof(PyObject *));
|
extras*sizeof(PyObject *));
|
||||||
if (f == NULL)
|
if (f == NULL)
|
||||||
return (PyFrameObject *)PyErr_NoMemory();
|
return (PyFrameObject *)PyErr_NoMemory();
|
||||||
|
f->f_size = extras;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
extras = f->f_nlocals + f->f_stacksize;
|
extras = f->f_size;
|
||||||
PyObject_INIT(f, &PyFrame_Type);
|
PyObject_INIT(f, &PyFrame_Type);
|
||||||
}
|
}
|
||||||
if (builtins == NULL) {
|
if (builtins == NULL) {
|
||||||
|
@ -199,22 +202,6 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
|
||||||
locals = globals;
|
locals = globals;
|
||||||
Py_INCREF(locals);
|
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_locals = locals;
|
||||||
f->f_trace = NULL;
|
f->f_trace = NULL;
|
||||||
f->f_exc_type = f->f_exc_value = f->f_exc_traceback = 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_restricted = (builtins != tstate->interp->builtins);
|
||||||
f->f_iblock = 0;
|
f->f_iblock = 0;
|
||||||
f->f_nlocals = code->co_nlocals;
|
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)
|
while (--extras >= 0)
|
||||||
f->f_localsplus[extras] = NULL;
|
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;
|
return f;
|
||||||
}
|
}
|
||||||
|
@ -261,6 +250,8 @@ 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
|
void
|
||||||
PyFrame_FastToLocals(PyFrameObject *f)
|
PyFrame_FastToLocals(PyFrameObject *f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -368,7 +368,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
register PyObject *t;
|
register PyObject *t;
|
||||||
register PyObject *stream = NULL; /* for PRINT opcodes */
|
register PyObject *stream = NULL; /* for PRINT opcodes */
|
||||||
register PyFrameObject *f; /* Current frame */
|
register PyFrameObject *f; /* Current frame */
|
||||||
register PyObject **fastlocals;
|
register PyObject **fastlocals, **freevars;
|
||||||
PyObject *retval = NULL; /* Return value */
|
PyObject *retval = NULL; /* Return value */
|
||||||
PyThreadState *tstate = PyThreadState_GET();
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
unsigned char *first_instr;
|
unsigned char *first_instr;
|
||||||
|
@ -439,6 +439,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
|
|
||||||
tstate->frame = f;
|
tstate->frame = f;
|
||||||
fastlocals = f->f_localsplus;
|
fastlocals = f->f_localsplus;
|
||||||
|
freevars = f->f_localsplus + f->f_nlocals;
|
||||||
|
|
||||||
if (co->co_argcount > 0 ||
|
if (co->co_argcount > 0 ||
|
||||||
co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
|
co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
|
||||||
|
@ -572,6 +573,17 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
goto fail;
|
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) {
|
if (tstate->sys_tracefunc != NULL) {
|
||||||
/* tstate->sys_tracefunc, if defined, is a function that
|
/* tstate->sys_tracefunc, if defined, is a function that
|
||||||
|
@ -1623,13 +1635,13 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case LOAD_CLOSURE:
|
case LOAD_CLOSURE:
|
||||||
x = PyTuple_GET_ITEM(f->f_closure, oparg);
|
x = freevars[oparg];
|
||||||
Py_INCREF(x);
|
Py_INCREF(x);
|
||||||
PUSH(x);
|
PUSH(x);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOAD_DEREF:
|
case LOAD_DEREF:
|
||||||
x = PyTuple_GET_ITEM(f->f_closure, oparg);
|
x = freevars[oparg];
|
||||||
w = PyCell_Get(x);
|
w = PyCell_Get(x);
|
||||||
Py_INCREF(w);
|
Py_INCREF(w);
|
||||||
PUSH(w);
|
PUSH(w);
|
||||||
|
@ -1637,7 +1649,7 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
|
||||||
|
|
||||||
case STORE_DEREF:
|
case STORE_DEREF:
|
||||||
w = POP();
|
w = POP();
|
||||||
x = PyTuple_GET_ITEM(f->f_closure, oparg);
|
x = freevars[oparg];
|
||||||
PyCell_Set(x, w);
|
PyCell_Set(x, w);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue