diff options
Diffstat (limited to 'Objects/frameobject.c')
-rw-r--r-- | Objects/frameobject.c | 220 |
1 files changed, 124 insertions, 96 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 9aabc7a..fcb5e4e 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -350,13 +350,32 @@ static PyGetSetDef frame_getsetlist[] = { }; /* Stack frames are allocated and deallocated at a considerable rate. - In an attempt to improve the speed of function calls, we maintain a - separate free list of stack frames (just like integers are - allocated in a special way -- see intobject.c). When a stack frame - is on the free list, only the following members have a meaning: + In an attempt to improve the speed of function calls, we: + + 1. Hold a single "zombie" frame on each code object. This retains + the allocated and initialised frame object from an invocation of + the code object. The zombie is reanimated the next time we need a + frame object for that code object. Doing this saves the malloc/ + realloc required when using a free_list frame that isn't the + correct size. It also saves some field initialisation. + + In zombie mode, no field of PyFrameObject holds a reference, but + the following fields are still valid: + + * ob_type, ob_size, f_code, f_valuestack; + + * f_locals, f_trace, + f_exc_type, f_exc_value, f_exc_traceback are NULL; + + * f_localsplus does not require re-allocation and + the local variables in f_localsplus are NULL. + + 2. We also maintain a separate free list of stack frames (just like + integers are allocated in a special way -- see intobject.c). When + a stack frame is on the free list, only the following members have + a meaning: ob_type == &Frametype f_back next item on free list, or NULL - f_nlocals number of locals f_stacksize size of value stack ob_size size of localsplus Note that the value and block stacks are preserved -- this can save @@ -380,41 +399,43 @@ static int numfree = 0; /* number of frames currently in free_list */ static void frame_dealloc(PyFrameObject *f) { - int i, slots; - PyObject **fastlocals; - PyObject **p; + PyObject **p, **valuestack; + PyCodeObject *co; PyObject_GC_UnTrack(f); Py_TRASHCAN_SAFE_BEGIN(f) /* Kill all local variables */ - slots = f->f_nlocals + f->f_ncells + f->f_nfreevars; - fastlocals = f->f_localsplus; - for (i = slots; --i >= 0; ++fastlocals) { - Py_XDECREF(*fastlocals); - } + valuestack = f->f_valuestack; + for (p = f->f_localsplus; p < valuestack; p++) + Py_CLEAR(*p); /* Free stack */ if (f->f_stacktop != NULL) { - for (p = f->f_valuestack; p < f->f_stacktop; p++) + for (p = valuestack; p < f->f_stacktop; p++) Py_XDECREF(*p); } Py_XDECREF(f->f_back); - Py_DECREF(f->f_code); Py_DECREF(f->f_builtins); Py_DECREF(f->f_globals); - Py_XDECREF(f->f_locals); - Py_XDECREF(f->f_trace); - Py_XDECREF(f->f_exc_type); - Py_XDECREF(f->f_exc_value); - Py_XDECREF(f->f_exc_traceback); - if (numfree < MAXFREELIST) { + Py_CLEAR(f->f_locals); + Py_CLEAR(f->f_trace); + Py_CLEAR(f->f_exc_type); + Py_CLEAR(f->f_exc_value); + Py_CLEAR(f->f_exc_traceback); + + co = f->f_code; + if (co != NULL && co->co_zombieframe == NULL) + co->co_zombieframe = f; + else if (numfree < MAXFREELIST) { ++numfree; f->f_back = free_list; free_list = f; - } - else + } + else PyObject_GC_Del(f); + + Py_XDECREF(co); Py_TRASHCAN_SAFE_END(f) } @@ -435,7 +456,7 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg) Py_VISIT(f->f_exc_traceback); /* locals */ - slots = f->f_nlocals + f->f_ncells + f->f_nfreevars; + slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); fastlocals = f->f_localsplus; for (i = slots; --i >= 0; ++fastlocals) Py_VISIT(*fastlocals); @@ -468,7 +489,7 @@ frame_clear(PyFrameObject *f) Py_CLEAR(f->f_trace); /* locals */ - slots = f->f_nlocals + f->f_ncells + f->f_nfreevars; + slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); fastlocals = f->f_localsplus; for (i = slots; --i >= 0; ++fastlocals) Py_CLEAR(*fastlocals); @@ -532,7 +553,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, PyFrameObject *back = tstate->frame; PyFrameObject *f; PyObject *builtins; - Py_ssize_t extras, ncells, nfrees, i; + Py_ssize_t i; #ifdef Py_DEBUG if (code == NULL || globals == NULL || !PyDict_Check(globals) || @@ -541,9 +562,6 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, return NULL; } #endif - 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) { @@ -574,71 +592,82 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, assert(builtins != NULL && PyDict_Check(builtins)); Py_INCREF(builtins); } - if (free_list == NULL) { - f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras); - if (f == NULL) { - Py_DECREF(builtins); - return NULL; - } + if (code->co_zombieframe != NULL) { + f = code->co_zombieframe; + code->co_zombieframe = NULL; + _Py_NewReference((PyObject *)f); + assert(f->f_code == code); } - else { - assert(numfree > 0); - --numfree; - f = free_list; - free_list = free_list->f_back; - if (f->ob_size < extras) { - f = PyObject_GC_Resize(PyFrameObject, f, extras); - if (f == NULL) { - Py_DECREF(builtins); - return NULL; - } - } - _Py_NewReference((PyObject *)f); + else { + Py_ssize_t extras, ncells, nfrees; + ncells = PyTuple_GET_SIZE(code->co_cellvars); + nfrees = PyTuple_GET_SIZE(code->co_freevars); + extras = code->co_stacksize + code->co_nlocals + ncells + + nfrees; + if (free_list == NULL) { + f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, + extras); + if (f == NULL) { + Py_DECREF(builtins); + return NULL; + } + } + else { + assert(numfree > 0); + --numfree; + f = free_list; + free_list = free_list->f_back; + if (f->ob_size < extras) { + f = PyObject_GC_Resize(PyFrameObject, f, extras); + if (f == NULL) { + Py_DECREF(builtins); + return NULL; + } + } + _Py_NewReference((PyObject *)f); + } + + f->f_code = code; + extras = code->co_nlocals + ncells + nfrees; + f->f_valuestack = f->f_localsplus + extras; + for (i=0; i<extras; i++) + f->f_localsplus[i] = NULL; + f->f_locals = NULL; + f->f_trace = NULL; + f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; } f->f_builtins = builtins; Py_XINCREF(back); f->f_back = back; Py_INCREF(code); - f->f_code = code; Py_INCREF(globals); f->f_globals = globals; /* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */ if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == (CO_NEWLOCALS | CO_OPTIMIZED)) - locals = NULL; /* PyFrame_FastToLocals() will set. */ + ; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */ else if (code->co_flags & CO_NEWLOCALS) { locals = PyDict_New(); if (locals == NULL) { Py_DECREF(f); return NULL; } + f->f_locals = locals; } else { if (locals == NULL) locals = globals; Py_INCREF(locals); + f->f_locals = locals; } - f->f_locals = locals; - f->f_trace = NULL; - f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; f->f_tstate = tstate; f->f_lasti = -1; f->f_lineno = code->co_firstlineno; f->f_restricted = (builtins != tstate->interp->builtins); f->f_iblock = 0; - f->f_nlocals = code->co_nlocals; - f->f_stacksize = code->co_stacksize; - f->f_ncells = ncells; - f->f_nfreevars = nfrees; - - extras = f->f_nlocals + ncells + nfrees; - /* Tim said it's ok to replace memset */ - for (i=0; i<extras; i++) - f->f_localsplus[i] = NULL; - - f->f_valuestack = f->f_localsplus + extras; - f->f_stacktop = f->f_valuestack; + + f->f_stacktop = f->f_valuestack; _PyObject_GC_TRACK(f); return f; } @@ -725,7 +754,9 @@ PyFrame_FastToLocals(PyFrameObject *f) PyObject *locals, *map; PyObject **fast; PyObject *error_type, *error_value, *error_traceback; + PyCodeObject *co; Py_ssize_t j; + int ncells, nfreevars; if (f == NULL) return; locals = f->f_locals; @@ -736,27 +767,24 @@ PyFrame_FastToLocals(PyFrameObject *f) return; } } - map = f->f_code->co_varnames; + co = f->f_code; + map = co->co_varnames; if (!PyTuple_Check(map)) return; PyErr_Fetch(&error_type, &error_value, &error_traceback); fast = f->f_localsplus; j = PyTuple_GET_SIZE(map); - if (j > f->f_nlocals) - j = f->f_nlocals; - if (f->f_nlocals) + if (j > co->co_nlocals) + j = co->co_nlocals; + if (co->co_nlocals) 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))) { - 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); + ncells = PyTuple_GET_SIZE(co->co_cellvars); + nfreevars = PyTuple_GET_SIZE(co->co_freevars); + if (ncells || nfreevars) { + map_to_dict(co->co_cellvars, ncells, + locals, fast + co->co_nlocals, 1); + map_to_dict(co->co_freevars, nfreevars, + locals, fast + co->co_nlocals + ncells, 1); } PyErr_Restore(error_type, error_value, error_traceback); } @@ -768,11 +796,14 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) PyObject *locals, *map; PyObject **fast; PyObject *error_type, *error_value, *error_traceback; + PyCodeObject *co; Py_ssize_t j; + int ncells, nfreevars; if (f == NULL) return; locals = f->f_locals; - map = f->f_code->co_varnames; + co = f->f_code; + map = co->co_varnames; if (locals == NULL) return; if (!PyTuple_Check(map)) @@ -780,21 +811,18 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) PyErr_Fetch(&error_type, &error_value, &error_traceback); fast = f->f_localsplus; j = PyTuple_GET_SIZE(map); - if (j > f->f_nlocals) - j = f->f_nlocals; - if (f->f_nlocals) - 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 + f->f_nlocals, 1, clear); - dict_to_map(f->f_code->co_freevars, - PyTuple_GET_SIZE(f->f_code->co_freevars), - locals, fast + f->f_nlocals + f->f_ncells, 1, - clear); + if (j > co->co_nlocals) + j = co->co_nlocals; + if (co->co_nlocals) + dict_to_map(co->co_varnames, j, locals, fast, 0, clear); + ncells = PyTuple_GET_SIZE(co->co_cellvars); + nfreevars = PyTuple_GET_SIZE(co->co_freevars); + if (ncells || nfreevars) { + dict_to_map(co->co_cellvars, ncells, + locals, fast + co->co_nlocals, 1, clear); + dict_to_map(co->co_freevars, nfreevars, + locals, fast + co->co_nlocals + ncells, 1, + clear); } PyErr_Restore(error_type, error_value, error_traceback); } |