diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2013-08-05 21:26:40 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2013-08-05 21:26:40 (GMT) |
commit | 58720d6145eca69b9aa45b720cb3c1376b1ddaea (patch) | |
tree | 56a90729aff1127491b8f895b40b4159ca3dce56 /Objects | |
parent | c53204b9477a2e28b6b366fd271f61c73b805cee (diff) | |
download | cpython-58720d6145eca69b9aa45b720cb3c1376b1ddaea.zip cpython-58720d6145eca69b9aa45b720cb3c1376b1ddaea.tar.gz cpython-58720d6145eca69b9aa45b720cb3c1376b1ddaea.tar.bz2 |
Issue #17934: Add a clear() method to frame objects, to help clean up expensive details (local variables) and break reference cycles.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/frameobject.c | 28 | ||||
-rw-r--r-- | Objects/genobject.c | 8 |
2 files changed, 31 insertions, 5 deletions
diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d3b59f1..a62a45e 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -488,7 +488,7 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg) } static void -frame_clear(PyFrameObject *f) +frame_tp_clear(PyFrameObject *f) { PyObject **fastlocals, **p, **oldtop; Py_ssize_t i, slots; @@ -500,6 +500,7 @@ frame_clear(PyFrameObject *f) */ oldtop = f->f_stacktop; f->f_stacktop = NULL; + f->f_executing = 0; Py_CLEAR(f->f_exc_type); Py_CLEAR(f->f_exc_value); @@ -520,6 +521,25 @@ frame_clear(PyFrameObject *f) } static PyObject * +frame_clear(PyFrameObject *f) +{ + if (f->f_executing) { + PyErr_SetString(PyExc_RuntimeError, + "cannot clear an executing frame"); + return NULL; + } + if (f->f_gen) { + _PyGen_Finalize(f->f_gen); + assert(f->f_gen == NULL); + } + frame_tp_clear(f); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(clear__doc__, +"F.clear(): clear most references held by the frame"); + +static PyObject * frame_sizeof(PyFrameObject *f) { Py_ssize_t res, extras, ncells, nfrees; @@ -538,6 +558,8 @@ PyDoc_STRVAR(sizeof__doc__, "F.__sizeof__() -> size of F in memory, in bytes"); static PyMethodDef frame_methods[] = { + {"clear", (PyCFunction)frame_clear, METH_NOARGS, + clear__doc__}, {"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS, sizeof__doc__}, {NULL, NULL} /* sentinel */ @@ -566,7 +588,7 @@ PyTypeObject PyFrame_Type = { Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ 0, /* tp_doc */ (traverseproc)frame_traverse, /* tp_traverse */ - (inquiry)frame_clear, /* tp_clear */ + (inquiry)frame_tp_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ @@ -708,6 +730,8 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, f->f_lasti = -1; f->f_lineno = code->co_firstlineno; f->f_iblock = 0; + f->f_executing = 0; + f->f_gen = NULL; _PyObject_GC_TRACK(f); return f; diff --git a/Objects/genobject.c b/Objects/genobject.c index dfd90aa..08d30bf 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -15,8 +15,8 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg) return 0; } -static void -gen_finalize(PyObject *self) +void +_PyGen_Finalize(PyObject *self) { PyGenObject *gen = (PyGenObject *)self; PyObject *res; @@ -140,6 +140,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) Py_XDECREF(t); Py_XDECREF(v); Py_XDECREF(tb); + gen->gi_frame->f_gen = NULL; gen->gi_frame = NULL; Py_DECREF(f); } @@ -505,7 +506,7 @@ PyTypeObject PyGen_Type = { 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ - gen_finalize, /* tp_finalize */ + _PyGen_Finalize, /* tp_finalize */ }; PyObject * @@ -517,6 +518,7 @@ PyGen_New(PyFrameObject *f) return NULL; } gen->gi_frame = f; + f->f_gen = (PyObject *) gen; Py_INCREF(f->f_code); gen->gi_code = (PyObject *)(f->f_code); gen->gi_running = 0; |