Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 6ab0ae3

Browse files
Anselm KruisAnselm Kruis
Anselm Kruis
authored and
Anselm Kruis
committed
Stackless issue #188: stackless calls of generator.send() related methods
Enable stackless calls of the following methods: - generator.send() (generator.__next__() was already stackless); - coroutine.send(); - coroutine_wrapper.__next__() and coroutine_wrapper.send(); - async_generator_asend.__next__() and async_generator_asend.send(). This change needs more tests.
1 parent 533b9e8 commit 6ab0ae3

File tree

2 files changed

+69
-9
lines changed

2 files changed

+69
-9
lines changed

Objects/genobject.c

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,30 @@ gen_dealloc(PyGenObject *gen)
159159
* was not faster, but considerably slower than this solution.
160160
*/
161161

162-
static PyObject* gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result);
162+
/* Like gen_send_ex, additionally pass ob3 into the callback function. */
163+
static PyObject *
164+
gen_send_ex2(PyGenObject *gen, PyObject *arg, int exc, int closing, PyObject* ob3);
165+
166+
/* callback for (async) generators and coroutines. */
167+
static PyObject *
168+
gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result);
169+
170+
/* Additional callback-code for async generators. */
171+
static PyObject *
172+
async_gen_asend_send_end(PyAsyncGenObject *gen, PyObject *asend, PyObject *result);
163173
#endif
164174

175+
165176
static PyObject *
166177
gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
167178
{
168179
#ifdef STACKLESS
180+
return gen_send_ex2(gen, arg, exc, closing, NULL);
181+
}
182+
183+
static PyObject *
184+
gen_send_ex2(PyGenObject *gen, PyObject *arg, int exc, int closing, PyObject * ob3)
185+
{
169186
STACKLESS_GETARG();
170187
PyFrameObject *stopframe;
171188
#endif
@@ -249,6 +266,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
249266
assert(f->f_back->f_back == NULL);
250267
assert(((PyCFrameObject *)f->f_back)->ob1 == NULL);
251268
assert(((PyCFrameObject *)f->f_back)->ob2 == NULL);
269+
assert(((PyCFrameObject *)f->f_back)->ob3 == NULL);
252270

253271
if (f->f_lasti != -1)
254272
#else
@@ -295,8 +313,10 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
295313

296314
Py_INCREF(gen);
297315
Py_XINCREF(arg);
316+
Py_XINCREF(ob3);
298317
((PyCFrameObject *) f->f_back)->ob1 = (PyObject *) gen;
299318
((PyCFrameObject *) f->f_back)->ob2 = arg;
319+
((PyCFrameObject *) f->f_back)->ob3 = ob3;
300320

301321
if (exc)
302322
result = NULL;
@@ -326,12 +346,14 @@ gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result)
326346
PyCFrameObject *cf = (PyCFrameObject *) f;
327347
PyGenObject *gen = (PyGenObject *) cf->ob1;
328348
PyObject *arg = cf->ob2;
349+
PyObject *ob3 = cf->ob3;
329350

330351
/* We hold references to things in the cframe, if we release it
331352
before we clear the references, they get incorrectly and
332353
prematurely freed. */
333354
cf->ob1 = NULL;
334355
cf->ob2 = NULL;
356+
cf->ob3 = NULL;
335357

336358
f = gen->gi_frame;
337359
/* Check, that this cframe belongs to gen */
@@ -400,8 +422,13 @@ gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result)
400422
Py_DECREF(f);
401423
}
402424
#ifdef STACKLESS
425+
if (ob3 && PyAsyncGen_CheckExact(gen)) {
426+
result = async_gen_asend_send_end((PyAsyncGenObject *)gen, ob3, result);
427+
}
428+
403429
Py_DECREF(gen);
404430
Py_XDECREF(arg);
431+
Py_XDECREF(ob3);
405432
#endif
406433
return result;
407434
}
@@ -839,7 +866,7 @@ static PyMemberDef gen_memberlist[] = {
839866
};
840867

841868
static PyMethodDef gen_methods[] = {
842-
{"send",(PyCFunction)_PyGen_Send, METH_O, send_doc},
869+
{"send",(PyCFunction)_PyGen_Send, METH_O | METH_STACKLESS, send_doc},
843870
{"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc},
844871
{"close",(PyCFunction)gen_close, METH_NOARGS, close_doc},
845872
{NULL, NULL} /* Sentinel */
@@ -1092,7 +1119,7 @@ PyDoc_STRVAR(coro_close_doc,
10921119
"close() -> raise GeneratorExit inside coroutine.");
10931120

10941121
static PyMethodDef coro_methods[] = {
1095-
{"send",(PyCFunction)_PyGen_Send, METH_O, coro_send_doc},
1122+
{"send",(PyCFunction)_PyGen_Send, METH_O | METH_STACKLESS, coro_send_doc},
10961123
{"throw",(PyCFunction)gen_throw, METH_VARARGS, coro_throw_doc},
10971124
{"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc},
10981125
{NULL, NULL} /* Sentinel */
@@ -1197,7 +1224,7 @@ coro_wrapper_traverse(PyCoroWrapper *cw, visitproc visit, void *arg)
11971224
}
11981225

11991226
static PyMethodDef coro_wrapper_methods[] = {
1200-
{"send",(PyCFunction)coro_wrapper_send, METH_O, coro_send_doc},
1227+
{"send",(PyCFunction)coro_wrapper_send, METH_O | METH_STACKLESS, coro_send_doc},
12011228
{"throw",(PyCFunction)coro_wrapper_throw, METH_VARARGS, coro_throw_doc},
12021229
{"close",(PyCFunction)coro_wrapper_close, METH_NOARGS, coro_close_doc},
12031230
{NULL, NULL} /* Sentinel */
@@ -1245,6 +1272,8 @@ PyTypeObject _PyCoroWrapper_Type = {
12451272
0, /* tp_free */
12461273
};
12471274

1275+
STACKLESS_DECLARE_METHOD(&_PyCoroWrapper_Type, tp_iternext);
1276+
12481277
static PyObject *
12491278
compute_cr_origin(int origin_depth)
12501279
{
@@ -1666,6 +1695,7 @@ async_gen_asend_traverse(PyAsyncGenASend *o, visitproc visit, void *arg)
16661695
static PyObject *
16671696
async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
16681697
{
1698+
STACKLESS_GETARG();
16691699
PyObject *result;
16701700

16711701
if (o->ags_state == AWAITABLE_STATE_CLOSED) {
@@ -1680,6 +1710,16 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
16801710
o->ags_state = AWAITABLE_STATE_ITER;
16811711
}
16821712

1713+
#ifdef STACKLESS
1714+
if (stackless) {
1715+
STACKLESS_PROMOTE_ALL();
1716+
result = gen_send_ex2((PyGenObject*)o->ags_gen, arg, 0, 0, (PyObject *)o);
1717+
STACKLESS_ASSERT();
1718+
if (STACKLESS_UNWINDING(result))
1719+
return result;
1720+
}
1721+
else
1722+
#endif
16831723
result = gen_send_ex((PyGenObject*)o->ags_gen, arg, 0, 0);
16841724
result = async_gen_unwrap_value(o->ags_gen, result);
16851725

@@ -1690,6 +1730,22 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg)
16901730
return result;
16911731
}
16921732

1733+
#ifdef STACKLESS
1734+
static PyObject *
1735+
async_gen_asend_send_end(PyAsyncGenObject *gen, PyObject *asend, PyObject *result)
1736+
{
1737+
PyAsyncGenASend *o = (PyAsyncGenASend *) asend;
1738+
assert(o->ags_gen == gen);
1739+
1740+
result = async_gen_unwrap_value(o->ags_gen, result);
1741+
1742+
if (result == NULL) {
1743+
o->ags_state = AWAITABLE_STATE_CLOSED;
1744+
}
1745+
1746+
return result;
1747+
}
1748+
#endif
16931749

16941750
static PyObject *
16951751
async_gen_asend_iternext(PyAsyncGenASend *o)
@@ -1728,7 +1784,7 @@ async_gen_asend_close(PyAsyncGenASend *o, PyObject *args)
17281784

17291785

17301786
static PyMethodDef async_gen_asend_methods[] = {
1731-
{"send", (PyCFunction)async_gen_asend_send, METH_O, send_doc},
1787+
{"send", (PyCFunction)async_gen_asend_send, METH_O | METH_STACKLESS, send_doc},
17321788
{"throw", (PyCFunction)async_gen_asend_throw, METH_VARARGS, throw_doc},
17331789
{"close", (PyCFunction)async_gen_asend_close, METH_NOARGS, close_doc},
17341790
{NULL, NULL} /* Sentinel */
@@ -1784,6 +1840,8 @@ PyTypeObject _PyAsyncGenASend_Type = {
17841840
0, /* tp_new */
17851841
};
17861842

1843+
STACKLESS_DECLARE_METHOD(&_PyAsyncGenASend_Type, tp_iternext);
1844+
17871845

17881846
static PyObject *
17891847
async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)

Stackless/core/stackless_methods.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ typedef struct {
1414
#define MFLAG_OFS_IND(meth) MFLAG_OFS(meth) + MFLAG_IND
1515

1616
static _stackless_method _stackless_methtable[] = {
17-
/* from methodobject.c */
18-
{&PyCFunction_Type, MFLAG_OFS(tp_call)},
17+
/* from classobject.c */
18+
{&PyMethod_Type, MFLAG_OFS(tp_call)},
1919
/* from descrobject.c */
2020
{&PyMethodDescr_Type, MFLAG_OFS(tp_call)},
2121
{&PyClassMethodDescr_Type, MFLAG_OFS(tp_call)},
@@ -24,10 +24,12 @@ static _stackless_method _stackless_methtable[] = {
2424
{&PyFunction_Type, MFLAG_OFS(tp_call)},
2525
/* from genobject.c */
2626
{&PyGen_Type, MFLAG_OFS(tp_iternext)},
27+
{&_PyCoroWrapper_Type, MFLAG_OFS(tp_iternext)},
28+
{&_PyAsyncGenASend_Type, MFLAG_OFS(tp_iternext)},
29+
/* from methodobject.c */
30+
{&PyCFunction_Type, MFLAG_OFS(tp_call)},
2731
/* from typeobject.c */
2832
{&PyType_Type, MFLAG_OFS(tp_call)},
29-
/* from classobject.c */
30-
{&PyMethod_Type, MFLAG_OFS(tp_call)},
3133
/* from channelobject.c */
3234
{&PyChannel_Type, MFLAG_OFS(tp_iternext)},
3335
{0, 0} /* sentinel */

0 commit comments

Comments
 (0)