]> granicus.if.org Git - python/commitdiff
Remove f_closure slot of frameobject and use f_localsplus instead.
authorJeremy Hylton <jeremy@alum.mit.edu>
Mon, 29 Jan 2001 22:51:52 +0000 (22:51 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Mon, 29 Jan 2001 22:51:52 +0000 (22:51 +0000)
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.

Include/frameobject.h
Objects/frameobject.c
Python/ceval.c

index c19f1d8c2769c7afc38547e9dc6d9ebffe299a34..d1a310a288d3bbba1c5ecc4868bec178e313b096 100644 (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;
index 0f6372bb194536421e5ce4c7ec617fb21ccc3ee2..18fb0b0adce4a1b8d94dd15e4635222dbf1e56a1 100644 (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)
 {
index c7b5696d042ad2f4d120b399893f14c08b339c68..5d593f28b26e455add70265bc3011ffe30bbcb64 100644 (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;