diff options
Diffstat (limited to 'Objects/frameobject.c')
-rw-r--r-- | Objects/frameobject.c | 267 |
1 files changed, 137 insertions, 130 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c index ae8cdcfb92d..1781c3cff73 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -6,6 +6,7 @@ #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "frameobject.h" // PyFrameObject +#include "pycore_frame.h" #include "opcode.h" // EXTENDED_ARG #include "structmember.h" // PyMemberDef @@ -13,9 +14,6 @@ static PyMemberDef frame_memberlist[] = { {"f_back", T_OBJECT, OFF(f_back), READONLY}, - {"f_code", T_OBJECT, OFF(f_code), READONLY|PY_AUDIT_READ}, - {"f_builtins", T_OBJECT, OFF(f_builtins), READONLY}, - {"f_globals", T_OBJECT, OFF(f_globals), READONLY}, {"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0}, {"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0}, {NULL} /* Sentinel */ @@ -34,8 +32,9 @@ frame_getlocals(PyFrameObject *f, void *closure) { if (PyFrame_FastToLocalsWithError(f) < 0) return NULL; - Py_INCREF(f->f_locals); - return f->f_locals; + PyObject *locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET]; + Py_INCREF(locals); + return locals; } int @@ -71,6 +70,36 @@ frame_getlasti(PyFrameObject *f, void *closure) return PyLong_FromLong(f->f_lasti*2); } +static PyObject * +frame_getglobals(PyFrameObject *f, void *closure) +{ + PyObject *globals = _PyFrame_GetGlobals(f); + if (globals == NULL) { + globals = Py_None; + } + Py_INCREF(globals); + return globals; +} + +static PyObject * +frame_getbuiltins(PyFrameObject *f, void *closure) +{ + PyObject *builtins = _PyFrame_GetBuiltins(f); + if (builtins == NULL) { + builtins = Py_None; + } + Py_INCREF(builtins); + return builtins; +} + +static PyObject * +frame_getcode(PyFrameObject *f, void *closure) +{ + if (PySys_Audit("object.__getattr__", "Os", f, "f_code") < 0) { + return NULL; + } + return (PyObject *)PyFrame_GetCode(f); +} /* Given the index of the effective opcode, scan back to construct the oparg with EXTENDED_ARG */ @@ -554,50 +583,21 @@ static PyGetSetDef frame_getsetlist[] = { (setter)frame_setlineno, NULL}, {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL}, {"f_lasti", (getter)frame_getlasti, NULL, NULL}, + {"f_globals", (getter)frame_getglobals, NULL, NULL}, + {"f_builtins", (getter)frame_getbuiltins, NULL, NULL}, + {"f_code", (getter)frame_getcode, NULL, NULL}, {0} }; /* Stack frames are allocated and deallocated at a considerable rate. - 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 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 - floats are allocated in a special way -- see floatobject.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 maintain + a separate free list of stack frames (just like floats are + allocated in a special way -- see floatobject.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_stacksize size of value stack - ob_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 - malloc'ed object in its own right -- it is only the actual calls to - malloc() that we are trying to save here, not the administration. - After all, while a typical program may make millions of calls, a - call depth of more than 20 or 30 is probably already exceptional - unless the program contains run-away recursion. I hope. - - Later, PyFrame_MAXFREELIST was added to bound the # of frames saved on - free_list. Else programs creating lots of cyclic trash involving - frames could provoke free_list into growing without bound. */ + /* max value for numfree */ #define PyFrame_MAXFREELIST 200 @@ -609,42 +609,37 @@ frame_dealloc(PyFrameObject *f) } Py_TRASHCAN_SAFE_BEGIN(f) - /* Kill all local variables */ - PyObject **valuestack = f->f_valuestack; - for (PyObject **p = f->f_localsplus; p < valuestack; p++) { - Py_CLEAR(*p); - } + PyCodeObject *co = f->f_code; - /* Free stack */ - for (int i = 0; i < f->f_stackdepth; i++) { - Py_XDECREF(f->f_valuestack[i]); + /* Kill all local variables */ + if (f->f_localsptr) { + for (int i = 0; i < co->co_nlocalsplus+FRAME_SPECIALS_SIZE; i++) { + Py_CLEAR(f->f_localsptr[i]); + } + /* Free items on stack */ + for (int i = 0; i < f->f_stackdepth; i++) { + Py_XDECREF(f->f_valuestack[i]); + } + if (f->f_own_locals_memory) { + PyMem_Free(f->f_localsptr); + f->f_own_locals_memory = 0; + } } f->f_stackdepth = 0; - Py_XDECREF(f->f_back); - Py_DECREF(f->f_builtins); - Py_DECREF(f->f_globals); - Py_CLEAR(f->f_locals); Py_CLEAR(f->f_trace); - - PyCodeObject *co = f->f_code; - if (co->co_zombieframe == NULL) { - co->co_zombieframe = f; - } - else { - struct _Py_frame_state *state = get_frame_state(); + struct _Py_frame_state *state = get_frame_state(); #ifdef Py_DEBUG - // frame_dealloc() must not be called after _PyFrame_Fini() - assert(state->numfree != -1); + // frame_dealloc() must not be called after _PyFrame_Fini() + assert(state->numfree != -1); #endif - if (state->numfree < PyFrame_MAXFREELIST) { - ++state->numfree; - f->f_back = state->free_list; - state->free_list = f; - } - else { - PyObject_GC_Del(f); - } + if (state->numfree < PyFrame_MAXFREELIST) { + ++state->numfree; + f->f_back = state->free_list; + state->free_list = f; + } + else { + PyObject_GC_Del(f); } Py_DECREF(co); @@ -654,24 +649,17 @@ frame_dealloc(PyFrameObject *f) static inline Py_ssize_t frame_nslots(PyFrameObject *frame) { - PyCodeObject *code = frame->f_code; - return (code->co_nlocals - + PyTuple_GET_SIZE(code->co_cellvars) - + PyTuple_GET_SIZE(code->co_freevars)); + return frame->f_valuestack - frame->f_localsptr; } static int frame_traverse(PyFrameObject *f, visitproc visit, void *arg) { Py_VISIT(f->f_back); - Py_VISIT(f->f_code); - Py_VISIT(f->f_builtins); - Py_VISIT(f->f_globals); - Py_VISIT(f->f_locals); Py_VISIT(f->f_trace); /* locals */ - PyObject **fastlocals = f->f_localsplus; + PyObject **fastlocals = f->f_localsptr; for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) { Py_VISIT(*fastlocals); } @@ -696,7 +684,7 @@ frame_tp_clear(PyFrameObject *f) Py_CLEAR(f->f_trace); /* locals */ - PyObject **fastlocals = f->f_localsplus; + PyObject **fastlocals = f->f_localsptr; for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) { Py_CLEAR(*fastlocals); } @@ -731,15 +719,12 @@ PyDoc_STRVAR(clear__doc__, static PyObject * frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) { - Py_ssize_t res, extras, ncells, nfrees; - - PyCodeObject *code = f->f_code; - ncells = PyTuple_GET_SIZE(code->co_cellvars); - nfrees = PyTuple_GET_SIZE(code->co_freevars); - extras = code->co_stacksize + code->co_nlocals + ncells + nfrees; - /* subtract one as it is already included in PyFrameObject */ - res = sizeof(PyFrameObject) + (extras-1) * sizeof(PyObject *); - + Py_ssize_t res; + res = sizeof(PyFrameObject); + if (f->f_own_locals_memory) { + PyCodeObject *code = f->f_code; + res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *); + } return PyLong_FromSsize_t(res); } @@ -802,24 +787,33 @@ PyTypeObject PyFrame_Type = { _Py_IDENTIFIER(__builtins__); static inline PyFrameObject* -frame_alloc(PyCodeObject *code) +frame_alloc(PyCodeObject *code, PyObject **localsarray) { - PyFrameObject *f = code->co_zombieframe; - if (f != NULL) { - code->co_zombieframe = NULL; - _Py_NewReference((PyObject *)f); - assert(f->f_code == code); - return f; + int owns; + PyFrameObject *f; + if (localsarray == NULL) { + int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; + localsarray = PyMem_Malloc(sizeof(PyObject *)*size); + if (localsarray == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) { + localsarray[i] = NULL; + } + owns = 1; + } + else { + owns = 0; } - - Py_ssize_t ncells = PyTuple_GET_SIZE(code->co_cellvars); - Py_ssize_t nfrees = PyTuple_GET_SIZE(code->co_freevars); - Py_ssize_t extras = code->co_stacksize + code->co_nlocals + ncells + nfrees; struct _Py_frame_state *state = get_frame_state(); if (state->free_list == NULL) { - f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras); + f = PyObject_GC_New(PyFrameObject, &PyFrame_Type); if (f == NULL) { + if (owns) { + PyMem_Free(localsarray); + } return NULL; } } @@ -832,46 +826,60 @@ frame_alloc(PyCodeObject *code) --state->numfree; f = state->free_list; state->free_list = state->free_list->f_back; - if (Py_SIZE(f) < extras) { - PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras); - if (new_f == NULL) { - PyObject_GC_Del(f); - return NULL; - } - f = new_f; - } _Py_NewReference((PyObject *)f); } - - extras = code->co_nlocals + ncells + nfrees; - f->f_valuestack = f->f_localsplus + extras; - for (Py_ssize_t i=0; i < extras; i++) { - f->f_localsplus[i] = NULL; - } + f->f_localsptr = localsarray; + f->f_own_locals_memory = owns; return f; } +int +_PyFrame_TakeLocals(PyFrameObject *f) +{ + assert(f->f_own_locals_memory == 0); + assert(f->f_stackdepth == 0); + int size = frame_nslots(f); + PyObject **copy = PyMem_Malloc(sizeof(PyObject *)*size); + if (copy == NULL) { + for (int i = 0; i < size; i++) { + PyObject *o = f->f_localsptr[i]; + Py_XDECREF(o); + } + PyErr_NoMemory(); + return -1; + } + for (int i = 0; i < size; i++) { + PyObject *o = f->f_localsptr[i]; + copy[i] = o; + } + f->f_own_locals_memory = 1; + f->f_localsptr = copy; + f->f_valuestack = copy + size; + return 0; +} PyFrameObject* _Py_HOT_FUNCTION -_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals) +_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals, PyObject **localsarray) { assert(con != NULL); assert(con->fc_globals != NULL); assert(con->fc_builtins != NULL); assert(con->fc_code != NULL); assert(locals == NULL || PyMapping_Check(locals)); + PyCodeObject *code = (PyCodeObject *)con->fc_code; - PyFrameObject *f = frame_alloc((PyCodeObject *)con->fc_code); + PyFrameObject *f = frame_alloc(code, localsarray); if (f == NULL) { return NULL; } + PyObject **specials = f->f_localsptr + code->co_nlocalsplus; + f->f_valuestack = specials + FRAME_SPECIALS_SIZE; f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame); f->f_code = (PyCodeObject *)Py_NewRef(con->fc_code); - f->f_builtins = Py_NewRef(con->fc_builtins); - f->f_globals = Py_NewRef(con->fc_globals); - f->f_locals = Py_XNewRef(locals); - // f_valuestack initialized by frame_alloc() + specials[FRAME_SPECIALS_BUILTINS_OFFSET] = Py_NewRef(con->fc_builtins); + specials[FRAME_SPECIALS_GLOBALS_OFFSET] = Py_NewRef(con->fc_globals); + specials[FRAME_SPECIALS_LOCALS_OFFSET] = Py_XNewRef(locals); f->f_trace = NULL; f->f_stackdepth = 0; f->f_trace_lines = 1; @@ -880,7 +888,6 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *l f->f_lasti = -1; f->f_lineno = 0; f->f_state = FRAME_CREATED; - // f_blockstack and f_localsplus initialized by frame_alloc() return f; } @@ -903,7 +910,7 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, .fc_kwdefaults = NULL, .fc_closure = NULL }; - PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals); + PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals, NULL); if (f) { _PyObject_GC_TRACK(f); } @@ -1022,9 +1029,9 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f) PyErr_BadInternalCall(); return -1; } - locals = f->f_locals; + locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET]; if (locals == NULL) { - locals = f->f_locals = PyDict_New(); + locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET] = PyDict_New(); if (locals == NULL) return -1; } @@ -1036,7 +1043,7 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f) Py_TYPE(map)->tp_name); return -1; } - fast = f->f_localsplus; + fast = f->f_localsptr; j = PyTuple_GET_SIZE(map); if (j > co->co_nlocals) j = co->co_nlocals; @@ -1083,7 +1090,7 @@ PyFrame_FastToLocals(PyFrameObject *f) void PyFrame_LocalsToFast(PyFrameObject *f, int clear) { - /* Merge f->f_locals into fast locals */ + /* Merge locals into fast locals */ PyObject *locals, *map; PyObject **fast; PyObject *error_type, *error_value, *error_traceback; @@ -1092,7 +1099,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) Py_ssize_t ncells, nfreevars; if (f == NULL) return; - locals = f->f_locals; + locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET]; co = f->f_code; map = co->co_varnames; if (locals == NULL) @@ -1100,7 +1107,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) if (!PyTuple_Check(map)) return; PyErr_Fetch(&error_type, &error_value, &error_traceback); - fast = f->f_localsplus; + fast = f->f_localsptr; j = PyTuple_GET_SIZE(map); if (j > co->co_nlocals) j = co->co_nlocals; |