summaryrefslogtreecommitdiffstats
path: root/Objects/genobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/genobject.c')
-rw-r--r--Objects/genobject.c80
1 files changed, 53 insertions, 27 deletions
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 3f6ef85..15e53dd 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -5,11 +5,13 @@
#include "genobject.h"
#include "ceval.h"
#include "structmember.h"
+#include "opcode.h"
static int
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
- return visit((PyObject *)gen->gi_frame, arg);
+ Py_VISIT((PyObject *)gen->gi_frame);
+ return 0;
}
static void
@@ -20,12 +22,11 @@ gen_dealloc(PyGenObject *gen)
_PyObject_GC_UNTRACK(gen);
if (gen->gi_weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *) gen);
-
+ PyObject_ClearWeakRefs(self);
_PyObject_GC_TRACK(self);
- if (gen->gi_frame->f_stacktop!=NULL) {
+ if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) {
/* Generator is paused, so we need to close */
gen->ob_type->tp_del(self);
if (self->ob_refcnt > 0)
@@ -33,7 +34,7 @@ gen_dealloc(PyGenObject *gen)
}
_PyObject_GC_UNTRACK(self);
- Py_XDECREF(gen->gi_frame);
+ Py_CLEAR(gen->gi_frame);
PyObject_GC_Del(gen);
}
@@ -50,16 +51,18 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
"generator already executing");
return NULL;
}
- if ((PyObject *)f == Py_None || f->f_stacktop == NULL) {
+ if (f==NULL || f->f_stacktop == NULL) {
/* Only set exception if called from send() */
- if (arg && !exc) PyErr_SetNone(PyExc_StopIteration);
+ if (arg && !exc)
+ PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
if (f->f_lasti == -1) {
if (arg && arg != Py_None) {
PyErr_SetString(PyExc_TypeError,
- "can't send non-None value to a just-started generator");
+ "can't send non-None value to a "
+ "just-started generator");
return NULL;
}
} else {
@@ -91,21 +94,22 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
Py_DECREF(result);
result = NULL;
/* Set exception if not called by gen_iternext() */
- if (arg) PyErr_SetNone(PyExc_StopIteration);
+ if (arg)
+ PyErr_SetNone(PyExc_StopIteration);
}
if (!result || f->f_stacktop == NULL) {
/* generator can't be rerun, so release the frame */
Py_DECREF(f);
- gen->gi_frame = (PyFrameObject *)Py_None;
- Py_INCREF(Py_None);
+ gen->gi_frame = NULL;
}
return result;
}
PyDoc_STRVAR(send_doc,
-"send(arg) -> send 'arg' into generator, return next yielded value or raise StopIteration.");
+"send(arg) -> send 'arg' into generator,\n\
+return next yielded value or raise StopIteration.");
static PyObject *
gen_send(PyGenObject *gen, PyObject *arg)
@@ -125,11 +129,11 @@ gen_close(PyGenObject *gen, PyObject *args)
if (retval) {
Py_DECREF(retval);
PyErr_SetString(PyExc_RuntimeError,
- "generator ignored GeneratorExit");
+ "generator ignored GeneratorExit");
return NULL;
}
- if ( PyErr_ExceptionMatches(PyExc_StopIteration)
- || PyErr_ExceptionMatches(PyExc_GeneratorExit) )
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)
+ || PyErr_ExceptionMatches(PyExc_GeneratorExit))
{
PyErr_Clear(); /* ignore these errors */
Py_INCREF(Py_None);
@@ -145,7 +149,7 @@ gen_del(PyObject *self)
PyObject *error_type, *error_value, *error_traceback;
PyGenObject *gen = (PyGenObject *)self;
- if ((PyObject *)gen->gi_frame == Py_None || gen->gi_frame->f_stacktop==NULL)
+ if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL)
/* Generator isn't paused, so no need to close */
return;
@@ -156,10 +160,10 @@ gen_del(PyObject *self)
/* Save the current exception, if any. */
PyErr_Fetch(&error_type, &error_value, &error_traceback);
- res = gen_close((PyGenObject *)self, NULL);
+ res = gen_close(gen, NULL);
if (res == NULL)
- PyErr_WriteUnraisable((PyObject *)self);
+ PyErr_WriteUnraisable(self);
else
Py_DECREF(res);
@@ -181,7 +185,7 @@ gen_del(PyObject *self)
_Py_NewReference(self);
self->ob_refcnt = refcnt;
}
- assert(!PyType_IS_GC(self->ob_type) ||
+ assert(PyType_IS_GC(self->ob_type) &&
_Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
@@ -202,10 +206,11 @@ gen_del(PyObject *self)
PyDoc_STRVAR(throw_doc,
-"throw(typ[,val[,tb]]) -> raise exception in generator, return next yielded value or raise StopIteration.");
+"throw(typ[,val[,tb]]) -> raise exception in generator,\n\
+return next yielded value or raise StopIteration.");
static PyObject *
-gen_throw(PyGenObject *gen, PyObject *args)
+gen_throw(PyGenObject *gen, PyObject *args)
{
PyObject *typ;
PyObject *tb = NULL;
@@ -216,10 +221,8 @@ gen_throw(PyGenObject *gen, PyObject *args)
/* First, check the traceback argument, replacing None with
NULL. */
- if (tb == Py_None) {
- Py_DECREF(tb);
+ if (tb == Py_None)
tb = NULL;
- }
else if (tb != NULL && !PyTraceBack_Check(tb)) {
PyErr_SetString(PyExc_TypeError,
"throw() third argument must be a traceback object");
@@ -249,7 +252,10 @@ gen_throw(PyGenObject *gen, PyObject *args)
Py_INCREF(typ);
}
}
- else {
+
+ /* Allow raising builtin string exceptions */
+
+ else if (!PyString_CheckExact(typ)) {
/* Not something you can raise. throw() fails. */
PyErr_Format(PyExc_TypeError,
"exceptions must be classes, or instances, not %s",
@@ -257,7 +263,7 @@ gen_throw(PyGenObject *gen, PyObject *args)
goto failed_throw;
}
- PyErr_Restore(typ,val,tb);
+ PyErr_Restore(typ, val, tb);
return gen_send_ex(gen, Py_None, 1);
failed_throw:
@@ -324,7 +330,7 @@ PyTypeObject PyGen_Type = {
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
-
+
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
@@ -355,3 +361,23 @@ PyGen_New(PyFrameObject *f)
_PyObject_GC_TRACK(gen);
return (PyObject *)gen;
}
+
+int
+PyGen_NeedsFinalizing(PyGenObject *gen)
+{
+ int i;
+ PyFrameObject *f = gen->gi_frame;
+
+ if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0)
+ return 0; /* no frame or empty blockstack == no finalization */
+
+ /* Any block type besides a loop requires cleanup. */
+ i = f->f_iblock;
+ while (--i >= 0) {
+ if (f->f_blockstack[i].b_type != SETUP_LOOP)
+ return 1;
+ }
+
+ /* No blocks except loops, it's safe to skip finalization. */
+ return 0;
+}