/home/mdboom/Work/builds/cpython/Objects/genobject.c
Line | Count | Source (jump to first uncovered line) |
1 | /* Generator object implementation */ |
2 | |
3 | #define _PY_INTERPRETER |
4 | |
5 | #include "Python.h" |
6 | #include "pycore_call.h" // _PyObject_CallNoArgs() |
7 | #include "pycore_ceval.h" // _PyEval_EvalFrame() |
8 | #include "pycore_frame.h" // _PyInterpreterFrame |
9 | #include "pycore_genobject.h" // struct _Py_async_gen_state |
10 | #include "pycore_object.h" // _PyObject_GC_UNTRACK() |
11 | #include "pycore_opcode.h" // _PyOpcode_Deopt |
12 | #include "pycore_pyerrors.h" // _PyErr_ClearExcState() |
13 | #include "pycore_pystate.h" // _PyThreadState_GET() |
14 | #include "structmember.h" // PyMemberDef |
15 | #include "opcode.h" // SEND |
16 | #include "pystats.h" |
17 | |
18 | static PyObject *gen_close(PyGenObject *, PyObject *); |
19 | static PyObject *async_gen_asend_new(PyAsyncGenObject *, PyObject *); |
20 | static PyObject *async_gen_athrow_new(PyAsyncGenObject *, PyObject *); |
21 | |
22 | static const char *NON_INIT_CORO_MSG = "can't send non-None value to a " |
23 | "just-started coroutine"; |
24 | |
25 | static const char *ASYNC_GEN_IGNORED_EXIT_MSG = |
26 | "async generator ignored GeneratorExit"; |
27 | |
28 | static inline int |
29 | exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg) |
30 | { |
31 | Py_VISIT(exc_state->exc_value); |
32 | return 0; |
33 | } |
34 | |
35 | static int |
36 | gen_traverse(PyGenObject *gen, visitproc visit, void *arg) |
37 | { |
38 | Py_VISIT(gen->gi_code); |
39 | Py_VISIT(gen->gi_name); |
40 | Py_VISIT(gen->gi_qualname); |
41 | if (gen->gi_frame_state < FRAME_CLEARED) { Branch (41:9): [True: 411k, False: 3.33k]
|
42 | _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); |
43 | assert(frame->frame_obj == NULL || |
44 | frame->frame_obj->f_frame->owner == FRAME_OWNED_BY_GENERATOR); |
45 | int err = _PyFrame_Traverse(frame, visit, arg); |
46 | if (err) { Branch (46:13): [True: 0, False: 411k]
|
47 | return err; |
48 | } |
49 | } |
50 | /* No need to visit cr_origin, because it's just tuples/str/int, so can't |
51 | participate in a reference cycle. */ |
52 | return exc_state_traverse(&gen->gi_exc_state, visit, arg); |
53 | } |
54 | |
55 | void |
56 | _PyGen_Finalize(PyObject *self) |
57 | { |
58 | PyGenObject *gen = (PyGenObject *)self; |
59 | PyObject *res = NULL; |
60 | PyObject *error_type, *error_value, *error_traceback; |
61 | |
62 | if (gen->gi_frame_state >= FRAME_COMPLETED) { Branch (62:9): [True: 2.97M, False: 594k]
|
63 | /* Generator isn't paused, so no need to close */ |
64 | return; |
65 | } |
66 | |
67 | if (PyAsyncGen_CheckExact(self)) { |
68 | PyAsyncGenObject *agen = (PyAsyncGenObject*)self; |
69 | PyObject *finalizer = agen->ag_origin_or_finalizer; |
70 | if (finalizer && !agen->ag_closed12 ) { Branch (70:13): [True: 12, False: 405]
Branch (70:26): [True: 10, False: 2]
|
71 | /* Save the current exception, if any. */ |
72 | PyErr_Fetch(&error_type, &error_value, &error_traceback); |
73 | |
74 | res = PyObject_CallOneArg(finalizer, self); |
75 | |
76 | if (res == NULL) { Branch (76:17): [True: 0, False: 10]
|
77 | PyErr_WriteUnraisable(self); |
78 | } else { |
79 | Py_DECREF(res); |
80 | } |
81 | /* Restore the saved exception. */ |
82 | PyErr_Restore(error_type, error_value, error_traceback); |
83 | return; |
84 | } |
85 | } |
86 | |
87 | /* Save the current exception, if any. */ |
88 | PyErr_Fetch(&error_type, &error_value, &error_traceback); |
89 | |
90 | /* If `gen` is a coroutine, and if it was never awaited on, |
91 | issue a RuntimeWarning. */ |
92 | if (gen->gi_code != NULL && Branch (92:9): [True: 594k, False: 0]
|
93 | ((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE && Branch (93:9): [True: 57, False: 594k]
|
94 | gen->gi_frame_state == FRAME_CREATED57 ) Branch (94:9): [True: 37, False: 20]
|
95 | { |
96 | _PyErr_WarnUnawaitedCoroutine((PyObject *)gen); |
97 | } |
98 | else { |
99 | res = gen_close(gen, NULL); |
100 | } |
101 | |
102 | if (res == NULL) { Branch (102:9): [True: 38, False: 594k]
|
103 | if (PyErr_Occurred()) { Branch (103:13): [True: 1, False: 37]
|
104 | PyErr_WriteUnraisable(self); |
105 | } |
106 | } |
107 | else { |
108 | Py_DECREF(res); |
109 | } |
110 | |
111 | /* Restore the saved exception. */ |
112 | PyErr_Restore(error_type, error_value, error_traceback); |
113 | } |
114 | |
115 | static void |
116 | gen_dealloc(PyGenObject *gen) |
117 | { |
118 | PyObject *self = (PyObject *) gen; |
119 | |
120 | _PyObject_GC_UNTRACK(gen); |
121 | |
122 | if (gen->gi_weakreflist != NULL) Branch (122:9): [True: 138, False: 3.56M]
|
123 | PyObject_ClearWeakRefs(self); |
124 | |
125 | _PyObject_GC_TRACK(self); |
126 | |
127 | if (PyObject_CallFinalizerFromDealloc(self)) Branch (127:9): [True: 43, False: 3.56M]
|
128 | return; /* resurrected. :( */ |
129 | |
130 | _PyObject_GC_UNTRACK(self); |
131 | if (PyAsyncGen_CheckExact(gen)) { |
132 | /* We have to handle this case for asynchronous generators |
133 | right here, because this code has to be between UNTRACK |
134 | and GC_Del. */ |
135 | Py_CLEAR(((PyAsyncGenObject*)gen)->ag_origin_or_finalizer); |
136 | } |
137 | if (gen->gi_frame_state < FRAME_CLEARED) { Branch (137:9): [True: 37, False: 3.56M]
|
138 | _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; |
139 | gen->gi_frame_state = FRAME_CLEARED; |
140 | frame->previous = NULL; |
141 | _PyFrame_Clear(frame); |
142 | } |
143 | if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) { Branch (143:9): [True: 28.9k, False: 3.53M]
|
144 | Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer); |
145 | } |
146 | Py_CLEAR(gen->gi_code); |
147 | Py_CLEAR(gen->gi_name); |
148 | Py_CLEAR(gen->gi_qualname); |
149 | _PyErr_ClearExcState(&gen->gi_exc_state); |
150 | PyObject_GC_Del(gen); |
151 | } |
152 | |
153 | static PySendResult |
154 | gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, |
155 | int exc, int closing) |
156 | { |
157 | PyThreadState *tstate = _PyThreadState_GET(); |
158 | _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; |
159 | PyObject *result; |
160 | |
161 | *presult = NULL; |
162 | if (gen->gi_frame_state == FRAME_CREATED && arg3.56M && arg != 658k Py_None658k ) { Branch (162:9): [True: 3.56M, False: 26.4M]
Branch (162:49): [True: 658k, False: 2.91M]
Branch (162:56): [True: 4, False: 658k]
|
163 | const char *msg = "can't send non-None value to a " |
164 | "just-started generator"; |
165 | if (PyCoro_CheckExact(gen)) { |
166 | msg = NON_INIT_CORO_MSG; |
167 | } |
168 | else if (PyAsyncGen_CheckExact(gen)) { |
169 | msg = "can't send non-None value to a " |
170 | "just-started async generator"; |
171 | } |
172 | PyErr_SetString(PyExc_TypeError, msg); |
173 | return PYGEN_ERROR; |
174 | } |
175 | if (gen->gi_frame_state == FRAME_EXECUTING) { Branch (175:9): [True: 9, False: 30.0M]
|
176 | const char *msg = "generator already executing"; |
177 | if (PyCoro_CheckExact(gen)) { |
178 | msg = "coroutine already executing"; |
179 | } |
180 | else if (PyAsyncGen_CheckExact(gen)) { |
181 | msg = "async generator already executing"; |
182 | } |
183 | PyErr_SetString(PyExc_ValueError, msg); |
184 | return PYGEN_ERROR; |
185 | } |
186 | if (gen->gi_frame_state >= FRAME_COMPLETED) { Branch (186:9): [True: 9.66k, False: 30.0M]
|
187 | if (PyCoro_CheckExact(gen) && !closing825 ) { Branch (187:39): [True: 11, False: 814]
|
188 | /* `gen` is an exhausted coroutine: raise an error, |
189 | except when called from gen_close(), which should |
190 | always be a silent method. */ |
191 | PyErr_SetString( |
192 | PyExc_RuntimeError, |
193 | "cannot reuse already awaited coroutine"); |
194 | } |
195 | else if (arg && !exc9.41k ) { Branch (195:18): [True: 9.41k, False: 244]
Branch (195:25): [True: 1, False: 9.40k]
|
196 | /* `gen` is an exhausted generator: |
197 | only return value if called from send(). */ |
198 | *presult = Py_None; |
199 | Py_INCREF(*presult); |
200 | return PYGEN_RETURN; |
201 | } |
202 | return PYGEN_ERROR; |
203 | } |
204 | |
205 | assert(gen->gi_frame_state < FRAME_EXECUTING); |
206 | /* Push arg onto the frame's value stack */ |
207 | result = arg ? arg2.11M : Py_None27.9M ; Branch (207:14): [True: 2.11M, False: 27.9M]
|
208 | Py_INCREF(result); |
209 | _PyFrame_StackPush(frame, result); |
210 | |
211 | frame->previous = tstate->cframe->current_frame; |
212 | |
213 | gen->gi_exc_state.previous_item = tstate->exc_info; |
214 | tstate->exc_info = &gen->gi_exc_state; |
215 | |
216 | if (exc) { Branch (216:9): [True: 610k, False: 29.4M]
|
217 | assert(_PyErr_Occurred(tstate)); |
218 | _PyErr_ChainStackItem(NULL); |
219 | } |
220 | |
221 | gen->gi_frame_state = FRAME_EXECUTING; |
222 | EVAL_CALL_STAT_INC(EVAL_CALL_GENERATOR); |
223 | result = _PyEval_EvalFrame(tstate, frame, exc); |
224 | if (gen->gi_frame_state == FRAME_EXECUTING) { Branch (224:9): [True: 3.56M, False: 26.4M]
|
225 | gen->gi_frame_state = FRAME_COMPLETED; |
226 | } |
227 | tstate->exc_info = gen->gi_exc_state.previous_item; |
228 | gen->gi_exc_state.previous_item = NULL; |
229 | |
230 | assert(tstate->cframe->current_frame == frame->previous); |
231 | /* Don't keep the reference to previous any longer than necessary. It |
232 | * may keep a chain of frames alive or it could create a reference |
233 | * cycle. */ |
234 | frame->previous = NULL; |
235 | |
236 | /* If the generator just returned (as opposed to yielding), signal |
237 | * that the generator is exhausted. */ |
238 | if (result) { Branch (238:9): [True: 29.4M, False: 611k]
|
239 | if (gen->gi_frame_state == FRAME_SUSPENDED) { Branch (239:13): [True: 26.4M, False: 2.95M]
|
240 | *presult = result; |
241 | return PYGEN_NEXT; |
242 | } |
243 | assert(result == Py_None || !PyAsyncGen_CheckExact(gen)); |
244 | if (result == Py_None && !2.94M PyAsyncGen_CheckExact(gen) && !arg2.94M ) { Branch (244:13): [True: 2.94M, False: 7.77k]
Branch (244:34): [True: 2.94M, False: 151]
Branch (244:65): [True: 2.69M, False: 255k]
|
245 | /* Return NULL if called by gen_iternext() */ |
246 | Py_CLEAR(result); |
247 | } |
248 | } |
249 | else { |
250 | if (PyErr_ExceptionMatches(PyExc_StopIteration)) { Branch (250:13): [True: 20, False: 611k]
|
251 | const char *msg = "generator raised StopIteration"; |
252 | if (PyCoro_CheckExact(gen)) { |
253 | msg = "coroutine raised StopIteration"; |
254 | } |
255 | else if (PyAsyncGen_CheckExact(gen)) { |
256 | msg = "async generator raised StopIteration"; |
257 | } |
258 | _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); |
259 | } |
260 | else if (PyAsyncGen_CheckExact(gen) && |
261 | PyErr_ExceptionMatches(PyExc_StopAsyncIteration)463 ) Branch (261:17): [True: 5, False: 458]
|
262 | { |
263 | /* code in `gen` raised a StopAsyncIteration error: |
264 | raise a RuntimeError. |
265 | */ |
266 | const char *msg = "async generator raised StopAsyncIteration"; |
267 | _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); |
268 | } |
269 | } |
270 | |
271 | /* generator can't be rerun, so release the frame */ |
272 | /* first clean reference cycle through stored exception traceback */ |
273 | _PyErr_ClearExcState(&gen->gi_exc_state); |
274 | |
275 | gen->gi_frame_state = FRAME_CLEARED; |
276 | _PyFrame_Clear(frame); |
277 | *presult = result; |
278 | return result ? PYGEN_RETURN263k : PYGEN_ERROR3.30M ; Branch (278:12): [True: 263k, False: 3.30M]
|
279 | } |
280 | |
281 | static PySendResult |
282 | PyGen_am_send(PyGenObject *gen, PyObject *arg, PyObject **result) |
283 | { |
284 | return gen_send_ex2(gen, arg, result, 0, 0); |
285 | } |
286 | |
287 | static PyObject * |
288 | gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) |
289 | { |
290 | PyObject *result; |
291 | if (gen_send_ex2(gen, arg, &result, exc, closing) == PYGEN_RETURN) { Branch (291:9): [True: 2.46k, False: 620k]
|
292 | if (PyAsyncGen_CheckExact(gen)) { |
293 | assert(result == Py_None); |
294 | PyErr_SetNone(PyExc_StopAsyncIteration); |
295 | } |
296 | else if (result == Py_None) { Branch (296:18): [True: 1.62k, False: 688]
|
297 | PyErr_SetNone(PyExc_StopIteration); |
298 | } |
299 | else { |
300 | _PyGen_SetStopIterationValue(result); |
301 | } |
302 | Py_CLEAR(result); |
303 | } |
304 | return result; |
305 | } |
306 | |
307 | PyDoc_STRVAR(send_doc, |
308 | "send(arg) -> send 'arg' into generator,\n\ |
309 | return next yielded value or raise StopIteration."); |
310 | |
311 | static PyObject * |
312 | gen_send(PyGenObject *gen, PyObject *arg) |
313 | { |
314 | return gen_send_ex(gen, arg, 0, 0); |
315 | } |
316 | |
317 | PyDoc_STRVAR(close_doc, |
318 | "close() -> raise GeneratorExit inside generator."); |
319 | |
320 | /* |
321 | * This helper function is used by gen_close and gen_throw to |
322 | * close a subiterator being delegated to by yield-from. |
323 | */ |
324 | |
325 | static int |
326 | gen_close_iter(PyObject *yf) |
327 | { |
328 | PyObject *retval = NULL; |
329 | |
330 | if (PyGen_CheckExact(yf) || PyCoro_CheckExact645 (yf)) { |
331 | retval = gen_close((PyGenObject *)yf, NULL); |
332 | if (retval == NULL) Branch (332:13): [True: 11, False: 12.6k]
|
333 | return -1; |
334 | } |
335 | else { |
336 | PyObject *meth; |
337 | if (_PyObject_LookupAttr(yf, &_Py_ID(close), &meth) < 0) { Branch (337:13): [True: 2, False: 639]
|
338 | PyErr_WriteUnraisable(yf); |
339 | } |
340 | if (meth) { Branch (340:13): [True: 13, False: 628]
|
341 | retval = _PyObject_CallNoArgs(meth); |
342 | Py_DECREF(meth); |
343 | if (retval == NULL) Branch (343:17): [True: 0, False: 13]
|
344 | return -1; |
345 | } |
346 | } |
347 | Py_XDECREF(retval); |
348 | return 0; |
349 | } |
350 | |
351 | PyObject * |
352 | _PyGen_yf(PyGenObject *gen) |
353 | { |
354 | PyObject *yf = NULL; |
355 | |
356 | if (gen->gi_frame_state < FRAME_CLEARED) { Branch (356:9): [True: 630k, False: 9.41k]
|
357 | _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; |
358 | |
359 | if (gen->gi_frame_state == FRAME_CREATED) { Branch (359:13): [True: 401k, False: 229k]
|
360 | /* Return immediately if the frame didn't start yet. SEND |
361 | always come after LOAD_CONST: a code object should not start |
362 | with SEND */ |
363 | assert(_Py_OPCODE(_PyCode_CODE(gen->gi_code)[0]) != SEND); |
364 | return NULL; |
365 | } |
366 | _Py_CODEUNIT next = frame->prev_instr[1]; |
367 | if (_PyOpcode_Deopt[_Py_OPCODE(next)] != RESUME || _Py_OPARG228k (next) < 2228k ) Branch (367:13): [True: 10, False: 228k]
Branch (367:60): [True: 214k, False: 14.4k]
|
368 | { |
369 | /* Not in a yield from */ |
370 | return NULL; |
371 | } |
372 | yf = _PyFrame_StackPeek(frame); |
373 | Py_INCREF(yf); |
374 | } |
375 | |
376 | return yf; |
377 | } |
378 | |
379 | static PyObject * |
380 | gen_close(PyGenObject *gen, PyObject *args) |
381 | { |
382 | PyObject *retval; |
383 | PyObject *yf = _PyGen_yf(gen); |
384 | int err = 0; |
385 | |
386 | if (yf) { Branch (386:9): [True: 13.2k, False: 604k]
|
387 | PyFrameState state = gen->gi_frame_state; |
388 | gen->gi_frame_state = FRAME_EXECUTING; |
389 | err = gen_close_iter(yf); |
390 | gen->gi_frame_state = state; |
391 | Py_DECREF(yf); |
392 | } |
393 | if (err == 0) Branch (393:9): [True: 617k, False: 5]
|
394 | PyErr_SetNone(PyExc_GeneratorExit); |
395 | retval = gen_send_ex(gen, Py_None, 1, 1); |
396 | if (retval) { Branch (396:9): [True: 7, False: 617k]
|
397 | const char *msg = "generator ignored GeneratorExit"; |
398 | if (PyCoro_CheckExact(gen)) { |
399 | msg = "coroutine ignored GeneratorExit"; |
400 | } else if (PyAsyncGen_CheckExact(gen)) { |
401 | msg = ASYNC_GEN_IGNORED_EXIT_MSG; |
402 | } |
403 | Py_DECREF(retval); |
404 | PyErr_SetString(PyExc_RuntimeError, msg); |
405 | return NULL; |
406 | } |
407 | if (PyErr_ExceptionMatches(PyExc_StopIteration) Branch (407:9): [True: 6, False: 617k]
|
408 | || PyErr_ExceptionMatches(PyExc_GeneratorExit)617k ) { Branch (408:12): [True: 617k, False: 14]
|
409 | PyErr_Clear(); /* ignore these errors */ |
410 | Py_RETURN_NONE; |
411 | } |
412 | return NULL; |
413 | } |
414 | |
415 | |
416 | PyDoc_STRVAR(throw_doc, |
417 | "throw(value)\n\ |
418 | throw(type[,value[,tb]])\n\ |
419 | \n\ |
420 | Raise exception in generator, return next yielded value or raise\n\ |
421 | StopIteration."); |
422 | |
423 | static PyObject * |
424 | _gen_throw(PyGenObject *gen, int close_on_genexit, |
425 | PyObject *typ, PyObject *val, PyObject *tb) |
426 | { |
427 | PyObject *yf = _PyGen_yf(gen); |
428 | |
429 | if (yf) { Branch (429:9): [True: 1.15k, False: 1.43k]
|
430 | _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; |
431 | PyObject *ret; |
432 | int err; |
433 | if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && Branch (433:13): [True: 10, False: 1.14k]
|
434 | close_on_genexit10 Branch (434:13): [True: 10, False: 0]
|
435 | ) { |
436 | /* Asynchronous generators *should not* be closed right away. |
437 | We have to allow some awaits to work it through, hence the |
438 | `close_on_genexit` parameter here. |
439 | */ |
440 | PyFrameState state = gen->gi_frame_state; |
441 | gen->gi_frame_state = FRAME_EXECUTING; |
442 | err = gen_close_iter(yf); |
443 | gen->gi_frame_state = state; |
444 | Py_DECREF(yf); |
445 | if (err < 0) Branch (445:17): [True: 6, False: 4]
|
446 | return gen_send_ex(gen, Py_None, 1, 0); |
447 | goto throw_here; |
448 | } |
449 | if (PyGen_CheckExact(yf) || PyCoro_CheckExact1.00k (yf)) { |
450 | /* `yf` is a generator or a coroutine. */ |
451 | PyThreadState *tstate = _PyThreadState_GET(); |
452 | /* Since we are fast-tracking things by skipping the eval loop, |
453 | we need to update the current frame so the stack trace |
454 | will be reported correctly to the user. */ |
455 | /* XXX We should probably be updating the current frame |
456 | somewhere in ceval.c. */ |
457 | _PyInterpreterFrame *prev = tstate->cframe->current_frame; |
458 | frame->previous = prev; |
459 | tstate->cframe->current_frame = frame; |
460 | /* Close the generator that we are currently iterating with |
461 | 'yield from' or awaiting on with 'await'. */ |
462 | PyFrameState state = gen->gi_frame_state; |
463 | gen->gi_frame_state = FRAME_EXECUTING; |
464 | ret = _gen_throw((PyGenObject *)yf, close_on_genexit, |
465 | typ, val, tb); |
466 | gen->gi_frame_state = state; |
467 | tstate->cframe->current_frame = prev; |
468 | frame->previous = NULL; |
469 | } else { |
470 | /* `yf` is an iterator or a coroutine-like object. */ |
471 | PyObject *meth; |
472 | if (_PyObject_LookupAttr(yf, &_Py_ID(throw), &meth) < 0) { Branch (472:17): [True: 1, False: 600]
|
473 | Py_DECREF(yf); |
474 | return NULL; |
475 | } |
476 | if (meth == NULL) { Branch (476:17): [True: 1, False: 599]
|
477 | Py_DECREF(yf); |
478 | goto throw_here; |
479 | } |
480 | PyFrameState state = gen->gi_frame_state; |
481 | gen->gi_frame_state = FRAME_EXECUTING; |
482 | ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); |
483 | gen->gi_frame_state = state; |
484 | Py_DECREF(meth); |
485 | } |
486 | Py_DECREF(yf); |
487 | if (!ret) { Branch (487:13): [True: 1.11k, False: 32]
|
488 | PyObject *val; |
489 | /* Pop subiterator from stack */ |
490 | assert(gen->gi_frame_state < FRAME_CLEARED); |
491 | ret = _PyFrame_StackPop((_PyInterpreterFrame *)gen->gi_iframe); |
492 | assert(ret == yf); |
493 | Py_DECREF(ret); |
494 | // XXX: Performing this jump ourselves is awkward and problematic. |
495 | // See https://github.com/python/cpython/pull/31968. |
496 | /* Termination repetition of SEND loop */ |
497 | assert(_PyInterpreterFrame_LASTI(frame) >= 0); |
498 | /* Backup to SEND */ |
499 | assert(_Py_OPCODE(frame->prev_instr[-1]) == SEND); |
500 | int jump = _Py_OPARG(frame->prev_instr[-1]); |
501 | frame->prev_instr += jump - 1; |
502 | if (_PyGen_FetchStopIterationValue(&val) == 0) { Branch (502:17): [True: 12, False: 1.09k]
|
503 | ret = gen_send(gen, val); |
504 | Py_DECREF(val); |
505 | } else { |
506 | ret = gen_send_ex(gen, Py_None, 1, 0); |
507 | } |
508 | } |
509 | return ret; |
510 | } |
511 | |
512 | throw_here: |
513 | /* First, check the traceback argument, replacing None with |
514 | NULL. */ |
515 | if (tb == Py_None) { Branch (515:9): [True: 21, False: 1.42k]
|
516 | tb = NULL; |
517 | } |
518 | else if (tb != NULL && !1.17k PyTraceBack_Check1.17k (tb)) { Branch (518:14): [True: 1.17k, False: 251]
Branch (518:28): [True: 2, False: 1.16k]
|
519 | PyErr_SetString(PyExc_TypeError, |
520 | "throw() third argument must be a traceback object"); |
521 | return NULL; |
522 | } |
523 | |
524 | Py_INCREF(typ); |
525 | Py_XINCREF(val); |
526 | Py_XINCREF(tb); |
527 | |
528 | if (PyExceptionClass_Check(typ)) |
529 | PyErr_NormalizeException(&typ, &val, &tb); |
530 | |
531 | else if (PyExceptionInstance_Check(typ)) { |
532 | /* Raising an instance. The value should be a dummy. */ |
533 | if (val && val != 2 Py_None2 ) { Branch (533:13): [True: 2, False: 188]
Branch (533:20): [True: 2, False: 0]
|
534 | PyErr_SetString(PyExc_TypeError, |
535 | "instance exception may not have a separate value"); |
536 | goto failed_throw; |
537 | } |
538 | else { |
539 | /* Normalize to raise <class>, <instance> */ |
540 | Py_XDECREF(val); |
541 | val = typ; |
542 | typ = PyExceptionInstance_Class(typ); |
543 | Py_INCREF(typ); |
544 | |
545 | if (tb == NULL) Branch (545:17): [True: 188, False: 0]
|
546 | /* Returns NULL if there's no traceback */ |
547 | tb = PyException_GetTraceback(val); |
548 | } |
549 | } |
550 | else { |
551 | /* Not something you can raise. throw() fails. */ |
552 | PyErr_Format(PyExc_TypeError, |
553 | "exceptions must be classes or instances " |
554 | "deriving from BaseException, not %s", |
555 | Py_TYPE(typ)->tp_name); |
556 | goto failed_throw; |
557 | } |
558 | |
559 | PyErr_Restore(typ, val, tb); |
560 | return gen_send_ex(gen, Py_None, 1, 0); |
561 | |
562 | failed_throw: |
563 | /* Didn't use our arguments, so restore their original refcounts */ |
564 | Py_DECREF(typ); |
565 | Py_XDECREF(val); |
566 | Py_XDECREF(tb); |
567 | return NULL; |
568 | } |
569 | |
570 | |
571 | static PyObject * |
572 | gen_throw(PyGenObject *gen, PyObject *const *args, Py_ssize_t nargs) |
573 | { |
574 | PyObject *typ; |
575 | PyObject *tb = NULL; |
576 | PyObject *val = NULL; |
577 | |
578 | if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) { |
579 | return NULL; |
580 | } |
581 | typ = args[0]; |
582 | if (nargs == 3) { Branch (582:9): [True: 1.18k, False: 829]
|
583 | val = args[1]; |
584 | tb = args[2]; |
585 | } |
586 | else if (nargs == 2) { Branch (586:14): [True: 7, False: 822]
|
587 | val = args[1]; |
588 | } |
589 | return _gen_throw(gen, 1, typ, val, tb); |
590 | } |
591 | |
592 | |
593 | static PyObject * |
594 | gen_iternext(PyGenObject *gen) |
595 | { |
596 | PyObject *result; |
597 | assert(PyGen_CheckExact(gen) || PyCoro_CheckExact(gen)); |
598 | if (gen_send_ex2(gen, NULL, &result, 0, 0) == PYGEN_RETURN) { Branch (598:9): [True: 49, False: 27.9M]
|
599 | if (result != Py_None) { Branch (599:13): [True: 49, False: 0]
|
600 | _PyGen_SetStopIterationValue(result); |
601 | } |
602 | Py_CLEAR(result); |
603 | } |
604 | return result; |
605 | } |
606 | |
607 | /* |
608 | * Set StopIteration with specified value. Value can be arbitrary object |
609 | * or NULL. |
610 | * |
611 | * Returns 0 if StopIteration is set and -1 if any other exception is set. |
612 | */ |
613 | int |
614 | _PyGen_SetStopIterationValue(PyObject *value) |
615 | { |
616 | PyObject *e; |
617 | |
618 | if (value == NULL || Branch (618:9): [True: 0, False: 1.18k]
|
619 | (!PyTuple_Check(value) && !1.14k PyExceptionInstance_Check1.14k (value))) Branch (619:10): [True: 1.14k, False: 40]
Branch (619:35): [True: 1.13k, False: 9]
|
620 | { |
621 | /* Delay exception instantiation if we can */ |
622 | PyErr_SetObject(PyExc_StopIteration, value); |
623 | return 0; |
624 | } |
625 | /* Construct an exception instance manually with |
626 | * PyObject_CallOneArg and pass it to PyErr_SetObject. |
627 | * |
628 | * We do this to handle a situation when "value" is a tuple, in which |
629 | * case PyErr_SetObject would set the value of StopIteration to |
630 | * the first element of the tuple. |
631 | * |
632 | * (See PyErr_SetObject/_PyErr_CreateException code for details.) |
633 | */ |
634 | e = PyObject_CallOneArg(PyExc_StopIteration, value); |
635 | if (e == NULL) { Branch (635:9): [True: 0, False: 49]
|
636 | return -1; |
637 | } |
638 | PyErr_SetObject(PyExc_StopIteration, e); |
639 | Py_DECREF(e); |
640 | return 0; |
641 | } |
642 | |
643 | /* |
644 | * If StopIteration exception is set, fetches its 'value' |
645 | * attribute if any, otherwise sets pvalue to None. |
646 | * |
647 | * Returns 0 if no exception or StopIteration is set. |
648 | * If any other exception is set, returns -1 and leaves |
649 | * pvalue unchanged. |
650 | */ |
651 | |
652 | int |
653 | _PyGen_FetchStopIterationValue(PyObject **pvalue) |
654 | { |
655 | PyObject *et, *ev, *tb; |
656 | PyObject *value = NULL; |
657 | |
658 | if (PyErr_ExceptionMatches(PyExc_StopIteration)) { Branch (658:9): [True: 611, False: 6.77k]
|
659 | PyErr_Fetch(&et, &ev, &tb); |
660 | if (ev) { Branch (660:13): [True: 510, False: 101]
|
661 | /* exception will usually be normalised already */ |
662 | if (PyObject_TypeCheck(ev, (PyTypeObject *) et)) { |
663 | value = ((PyStopIterationObject *)ev)->value; |
664 | Py_INCREF(value); |
665 | Py_DECREF(ev); |
666 | } else if (et == PyExc_StopIteration && !PyTuple_Check(ev)) { Branch (666:24): [True: 409, False: 0]
Branch (666:53): [True: 409, False: 0]
|
667 | /* Avoid normalisation and take ev as value. |
668 | * |
669 | * Normalization is required if the value is a tuple, in |
670 | * that case the value of StopIteration would be set to |
671 | * the first element of the tuple. |
672 | * |
673 | * (See _PyErr_CreateException code for details.) |
674 | */ |
675 | value = ev; |
676 | } else { |
677 | /* normalisation required */ |
678 | PyErr_NormalizeException(&et, &ev, &tb); |
679 | if (!PyObject_TypeCheck(ev, (PyTypeObject *)PyExc_StopIteration)) { Branch (679:21): [True: 0, False: 0]
|
680 | PyErr_Restore(et, ev, tb); |
681 | return -1; |
682 | } |
683 | value = ((PyStopIterationObject *)ev)->value; |
684 | Py_INCREF(value); |
685 | Py_DECREF(ev); |
686 | } |
687 | } |
688 | Py_XDECREF(et); |
689 | Py_XDECREF(tb); |
690 | } else if (PyErr_Occurred()) { Branch (690:16): [True: 1.69k, False: 5.08k]
|
691 | return -1; |
692 | } |
693 | if (value == NULL) { Branch (693:9): [True: 5.18k, False: 510]
|
694 | value = Py_None; |
695 | Py_INCREF(value); |
696 | } |
697 | *pvalue = value; |
698 | return 0; |
699 | } |
700 | |
701 | static PyObject * |
702 | gen_repr(PyGenObject *gen) |
703 | { |
704 | return PyUnicode_FromFormat("<generator object %S at %p>", |
705 | gen->gi_qualname, gen); |
706 | } |
707 | |
708 | static PyObject * |
709 | gen_get_name(PyGenObject *op, void *Py_UNUSED(ignored)) |
710 | { |
711 | Py_INCREF(op->gi_name); |
712 | return op->gi_name; |
713 | } |
714 | |
715 | static int |
716 | gen_set_name(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored)) |
717 | { |
718 | /* Not legal to del gen.gi_name or to set it to anything |
719 | * other than a string object. */ |
720 | if (value == NULL || !3 PyUnicode_Check3 (value)) { Branch (720:9): [True: 1, False: 3]
Branch (720:26): [True: 1, False: 2]
|
721 | PyErr_SetString(PyExc_TypeError, |
722 | "__name__ must be set to a string object"); |
723 | return -1; |
724 | } |
725 | Py_INCREF(value); |
726 | Py_XSETREF(op->gi_name, value); |
727 | return 0; |
728 | } |
729 | |
730 | static PyObject * |
731 | gen_get_qualname(PyGenObject *op, void *Py_UNUSED(ignored)) |
732 | { |
733 | Py_INCREF(op->gi_qualname); |
734 | return op->gi_qualname; |
735 | } |
736 | |
737 | static int |
738 | gen_set_qualname(PyGenObject *op, PyObject *value, void *Py_UNUSED(ignored)) |
739 | { |
740 | /* Not legal to del gen.__qualname__ or to set it to anything |
741 | * other than a string object. */ |
742 | if (value == NULL || !3 PyUnicode_Check3 (value)) { Branch (742:9): [True: 1, False: 3]
Branch (742:26): [True: 1, False: 2]
|
743 | PyErr_SetString(PyExc_TypeError, |
744 | "__qualname__ must be set to a string object"); |
745 | return -1; |
746 | } |
747 | Py_INCREF(value); |
748 | Py_XSETREF(op->gi_qualname, value); |
749 | return 0; |
750 | } |
751 | |
752 | static PyObject * |
753 | gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored)) |
754 | { |
755 | PyObject *yf = _PyGen_yf(gen); |
756 | if (yf == NULL) Branch (756:9): [True: 8, False: 1]
|
757 | Py_RETURN_NONE; |
758 | return yf; |
759 | } |
760 | |
761 | |
762 | static PyObject * |
763 | gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) |
764 | { |
765 | if (gen->gi_frame_state == FRAME_EXECUTING) { Branch (765:9): [True: 8, False: 15]
|
766 | Py_RETURN_TRUE; |
767 | } |
768 | Py_RETURN_FALSE15 ; |
769 | } |
770 | |
771 | static PyObject * |
772 | gen_getsuspended(PyGenObject *gen, void *Py_UNUSED(ignored)) |
773 | { |
774 | return PyBool_FromLong(gen->gi_frame_state == FRAME_SUSPENDED); |
775 | } |
776 | |
777 | static PyObject * |
778 | _gen_getframe(PyGenObject *gen, const char *const name) |
779 | { |
780 | if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) { Branch (780:9): [True: 0, False: 3.82k]
|
781 | return NULL; |
782 | } |
783 | if (gen->gi_frame_state == FRAME_CLEARED) { Branch (783:9): [True: 3.40k, False: 415]
|
784 | Py_RETURN_NONE; |
785 | } |
786 | return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((_PyInterpreterFrame *)gen->gi_iframe)); |
787 | } |
788 | |
789 | static PyObject * |
790 | gen_getframe(PyGenObject *gen, void *Py_UNUSED(ignored)) |
791 | { |
792 | return _gen_getframe(gen, "gi_frame"); |
793 | } |
794 | |
795 | static PyGetSetDef gen_getsetlist[] = { |
796 | {"__name__", (getter)gen_get_name, (setter)gen_set_name, |
797 | PyDoc_STR("name of the generator")}, |
798 | {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, |
799 | PyDoc_STR("qualified name of the generator")}, |
800 | {"gi_yieldfrom", (getter)gen_getyieldfrom, NULL, |
801 | PyDoc_STR("object being iterated by yield from, or None")}, |
802 | {"gi_running", (getter)gen_getrunning, NULL, NULL}, |
803 | {"gi_frame", (getter)gen_getframe, NULL, NULL}, |
804 | {"gi_suspended", (getter)gen_getsuspended, NULL, NULL}, |
805 | {NULL} /* Sentinel */ |
806 | }; |
807 | |
808 | static PyMemberDef gen_memberlist[] = { |
809 | {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|PY_AUDIT_READ}, |
810 | {NULL} /* Sentinel */ |
811 | }; |
812 | |
813 | static PyObject * |
814 | gen_sizeof(PyGenObject *gen, PyObject *Py_UNUSED(ignored)) |
815 | { |
816 | Py_ssize_t res; |
817 | res = offsetof(PyGenObject, gi_iframe) + offsetof(_PyInterpreterFrame, localsplus); |
818 | PyCodeObject *code = gen->gi_code; |
819 | res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *); |
820 | return PyLong_FromSsize_t(res); |
821 | } |
822 | |
823 | PyDoc_STRVAR(sizeof__doc__, |
824 | "gen.__sizeof__() -> size of gen in memory, in bytes"); |
825 | |
826 | static PyMethodDef gen_methods[] = { |
827 | {"send",(PyCFunction)gen_send, METH_O, send_doc}, |
828 | {"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, throw_doc}, |
829 | {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, |
830 | {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, |
831 | {NULL, NULL} /* Sentinel */ |
832 | }; |
833 | |
834 | static PyAsyncMethods gen_as_async = { |
835 | 0, /* am_await */ |
836 | 0, /* am_aiter */ |
837 | 0, /* am_anext */ |
838 | (sendfunc)PyGen_am_send, /* am_send */ |
839 | }; |
840 | |
841 | |
842 | PyTypeObject PyGen_Type = { |
843 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
844 | "generator", /* tp_name */ |
845 | offsetof(PyGenObject, gi_iframe) + |
846 | offsetof(_PyInterpreterFrame, localsplus), /* tp_basicsize */ |
847 | sizeof(PyObject *), /* tp_itemsize */ |
848 | /* methods */ |
849 | (destructor)gen_dealloc, /* tp_dealloc */ |
850 | 0, /* tp_vectorcall_offset */ |
851 | 0, /* tp_getattr */ |
852 | 0, /* tp_setattr */ |
853 | &gen_as_async, /* tp_as_async */ |
854 | (reprfunc)gen_repr, /* tp_repr */ |
855 | 0, /* tp_as_number */ |
856 | 0, /* tp_as_sequence */ |
857 | 0, /* tp_as_mapping */ |
858 | 0, /* tp_hash */ |
859 | 0, /* tp_call */ |
860 | 0, /* tp_str */ |
861 | PyObject_GenericGetAttr, /* tp_getattro */ |
862 | 0, /* tp_setattro */ |
863 | 0, /* tp_as_buffer */ |
864 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
865 | 0, /* tp_doc */ |
866 | (traverseproc)gen_traverse, /* tp_traverse */ |
867 | 0, /* tp_clear */ |
868 | 0, /* tp_richcompare */ |
869 | offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */ |
870 | PyObject_SelfIter, /* tp_iter */ |
871 | (iternextfunc)gen_iternext, /* tp_iternext */ |
872 | gen_methods, /* tp_methods */ |
873 | gen_memberlist, /* tp_members */ |
874 | gen_getsetlist, /* tp_getset */ |
875 | 0, /* tp_base */ |
876 | 0, /* tp_dict */ |
877 | |
878 | 0, /* tp_descr_get */ |
879 | 0, /* tp_descr_set */ |
880 | 0, /* tp_dictoffset */ |
881 | 0, /* tp_init */ |
882 | 0, /* tp_alloc */ |
883 | 0, /* tp_new */ |
884 | 0, /* tp_free */ |
885 | 0, /* tp_is_gc */ |
886 | 0, /* tp_bases */ |
887 | 0, /* tp_mro */ |
888 | 0, /* tp_cache */ |
889 | 0, /* tp_subclasses */ |
890 | 0, /* tp_weaklist */ |
891 | 0, /* tp_del */ |
892 | 0, /* tp_version_tag */ |
893 | _PyGen_Finalize, /* tp_finalize */ |
894 | }; |
895 | |
896 | static PyObject * |
897 | make_gen(PyTypeObject *type, PyFunctionObject *func) |
898 | { |
899 | PyCodeObject *code = (PyCodeObject *)func->func_code; |
900 | int slots = code->co_nlocalsplus + code->co_stacksize; |
901 | PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, slots); |
902 | if (gen == NULL) { Branch (902:9): [True: 0, False: 3.56M]
|
903 | return NULL; |
904 | } |
905 | gen->gi_frame_state = FRAME_CLEARED; |
906 | gen->gi_code = (PyCodeObject *)func->func_code; |
907 | Py_INCREF(gen->gi_code); |
908 | gen->gi_weakreflist = NULL; |
909 | gen->gi_exc_state.exc_value = NULL; |
910 | gen->gi_exc_state.previous_item = NULL; |
911 | assert(func->func_name != NULL); |
912 | gen->gi_name = Py_NewRef(func->func_name); |
913 | assert(func->func_qualname != NULL); |
914 | gen->gi_qualname = Py_NewRef(func->func_qualname); |
915 | _PyObject_GC_TRACK(gen); |
916 | return (PyObject *)gen; |
917 | } |
918 | |
919 | static PyObject * |
920 | compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame); |
921 | |
922 | PyObject * |
923 | _Py_MakeCoro(PyFunctionObject *func) |
924 | { |
925 | int coro_flags = ((PyCodeObject *)func->func_code)->co_flags & |
926 | (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); |
927 | assert(coro_flags); |
928 | if (coro_flags == CO_GENERATOR) { Branch (928:9): [True: 3.53M, False: 29.6k]
|
929 | return make_gen(&PyGen_Type, func); |
930 | } |
931 | if (coro_flags == CO_ASYNC_GENERATOR) { Branch (931:9): [True: 617, False: 28.9k]
|
932 | PyAsyncGenObject *o; |
933 | o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, func); |
934 | if (o == NULL) { Branch (934:13): [True: 0, False: 617]
|
935 | return NULL; |
936 | } |
937 | o->ag_origin_or_finalizer = NULL; |
938 | o->ag_closed = 0; |
939 | o->ag_hooks_inited = 0; |
940 | o->ag_running_async = 0; |
941 | return (PyObject*)o; |
942 | } |
943 | assert (coro_flags == CO_COROUTINE); |
944 | PyObject *coro = make_gen(&PyCoro_Type, func); |
945 | if (!coro) { Branch (945:9): [True: 0, False: 28.9k]
|
946 | return NULL; |
947 | } |
948 | PyThreadState *tstate = _PyThreadState_GET(); |
949 | int origin_depth = tstate->coroutine_origin_tracking_depth; |
950 | |
951 | if (origin_depth == 0) { Branch (951:9): [True: 25.8k, False: 3.18k]
|
952 | ((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL; |
953 | } else { |
954 | assert(_PyEval_GetFrame()); |
955 | PyObject *cr_origin = compute_cr_origin(origin_depth, _PyEval_GetFrame()->previous); |
956 | ((PyCoroObject *)coro)->cr_origin_or_finalizer = cr_origin; |
957 | if (!cr_origin) { Branch (957:13): [True: 0, False: 3.18k]
|
958 | Py_DECREF(coro); |
959 | return NULL; |
960 | } |
961 | } |
962 | return coro; |
963 | } |
964 | |
965 | static PyObject * |
966 | gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, |
967 | PyObject *name, PyObject *qualname) |
968 | { |
969 | PyCodeObject *code = f->f_frame->f_code; |
970 | int size = code->co_nlocalsplus + code->co_stacksize; |
971 | PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size); |
972 | if (gen == NULL) { Branch (972:9): [True: 0, False: 0]
|
973 | Py_DECREF(f); |
974 | return NULL; |
975 | } |
976 | /* Copy the frame */ |
977 | assert(f->f_frame->frame_obj == NULL); |
978 | assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); |
979 | _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; |
980 | _PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame); |
981 | gen->gi_frame_state = FRAME_CREATED; |
982 | assert(frame->frame_obj == f); |
983 | f->f_frame = frame; |
984 | frame->owner = FRAME_OWNED_BY_GENERATOR; |
985 | assert(PyObject_GC_IsTracked((PyObject *)f)); |
986 | gen->gi_code = PyFrame_GetCode(f); |
987 | Py_INCREF(gen->gi_code); |
988 | Py_DECREF(f); |
989 | gen->gi_weakreflist = NULL; |
990 | gen->gi_exc_state.exc_value = NULL; |
991 | gen->gi_exc_state.previous_item = NULL; |
992 | if (name != NULL) Branch (992:9): [True: 0, False: 0]
|
993 | gen->gi_name = name; |
994 | else |
995 | gen->gi_name = gen->gi_code->co_name; |
996 | Py_INCREF(gen->gi_name); |
997 | if (qualname != NULL) Branch (997:9): [True: 0, False: 0]
|
998 | gen->gi_qualname = qualname; |
999 | else |
1000 | gen->gi_qualname = gen->gi_code->co_qualname; |
1001 | Py_INCREF(gen->gi_qualname); |
1002 | _PyObject_GC_TRACK(gen); |
1003 | return (PyObject *)gen; |
1004 | } |
1005 | |
1006 | PyObject * |
1007 | PyGen_NewWithQualName(PyFrameObject *f, PyObject *name, PyObject *qualname) |
1008 | { |
1009 | return gen_new_with_qualname(&PyGen_Type, f, name, qualname); |
1010 | } |
1011 | |
1012 | PyObject * |
1013 | PyGen_New(PyFrameObject *f) |
1014 | { |
1015 | return gen_new_with_qualname(&PyGen_Type, f, NULL, NULL); |
1016 | } |
1017 | |
1018 | /* Coroutine Object */ |
1019 | |
1020 | typedef struct { |
1021 | PyObject_HEAD |
1022 | PyCoroObject *cw_coroutine; |
1023 | } PyCoroWrapper; |
1024 | |
1025 | static int |
1026 | gen_is_coroutine(PyObject *o) |
1027 | { |
1028 | if (PyGen_CheckExact(o)) { |
1029 | PyCodeObject *code = (PyCodeObject *)((PyGenObject*)o)->gi_code; |
1030 | if (code->co_flags & CO_ITERABLE_COROUTINE) { Branch (1030:13): [True: 3.31k, False: 213]
|
1031 | return 1; |
1032 | } |
1033 | } |
1034 | return 0; |
1035 | } |
1036 | |
1037 | /* |
1038 | * This helper function returns an awaitable for `o`: |
1039 | * - `o` if `o` is a coroutine-object; |
1040 | * - `type(o)->tp_as_async->am_await(o)` |
1041 | * |
1042 | * Raises a TypeError if it's not possible to return |
1043 | * an awaitable and returns NULL. |
1044 | */ |
1045 | PyObject * |
1046 | _PyCoro_GetAwaitableIter(PyObject *o) |
1047 | { |
1048 | unaryfunc getter = NULL; |
1049 | PyTypeObject *ot; |
1050 | |
1051 | if (PyCoro_CheckExact(o) || gen_is_coroutine(o)16.7k ) { Branch (1051:33): [True: 3.31k, False: 13.4k]
|
1052 | /* 'o' is a coroutine. */ |
1053 | Py_INCREF(o); |
1054 | return o; |
1055 | } |
1056 | |
1057 | ot = Py_TYPE(o); |
1058 | if (ot->tp_as_async != NULL) { Branch (1058:9): [True: 13.4k, False: 11]
|
1059 | getter = ot->tp_as_async->am_await; |
1060 | } |
1061 | if (getter != NULL) { Branch (1061:9): [True: 13.3k, False: 26]
|
1062 | PyObject *res = (*getter)(o); |
1063 | if (res != NULL) { Branch (1063:13): [True: 13.3k, False: 1]
|
1064 | if (PyCoro_CheckExact(res) || gen_is_coroutine(res)13.3k ) { Branch (1064:43): [True: 0, False: 13.3k]
|
1065 | /* __await__ must return an *iterator*, not |
1066 | a coroutine or another awaitable (see PEP 492) */ |
1067 | PyErr_SetString(PyExc_TypeError, |
1068 | "__await__() returned a coroutine"); |
1069 | Py_CLEAR(res); |
1070 | } else if (!PyIter_Check(res)) { Branch (1070:24): [True: 5, False: 13.3k]
|
1071 | PyErr_Format(PyExc_TypeError, |
1072 | "__await__() returned non-iterator " |
1073 | "of type '%.100s'", |
1074 | Py_TYPE(res)->tp_name); |
1075 | Py_CLEAR(res); |
1076 | } |
1077 | } |
1078 | return res; |
1079 | } |
1080 | |
1081 | PyErr_Format(PyExc_TypeError, |
1082 | "object %.100s can't be used in 'await' expression", |
1083 | ot->tp_name); |
1084 | return NULL; |
1085 | } |
1086 | |
1087 | static PyObject * |
1088 | coro_repr(PyCoroObject *coro) |
1089 | { |
1090 | return PyUnicode_FromFormat("<coroutine object %S at %p>", |
1091 | coro->cr_qualname, coro); |
1092 | } |
1093 | |
1094 | static PyObject * |
1095 | coro_await(PyCoroObject *coro) |
1096 | { |
1097 | PyCoroWrapper *cw = PyObject_GC_New(PyCoroWrapper, &_PyCoroWrapper_Type); |
1098 | if (cw == NULL) { Branch (1098:9): [True: 0, False: 38]
|
1099 | return NULL; |
1100 | } |
1101 | Py_INCREF(coro); |
1102 | cw->cw_coroutine = coro; |
1103 | _PyObject_GC_TRACK(cw); |
1104 | return (PyObject *)cw; |
1105 | } |
1106 | |
1107 | static PyObject * |
1108 | coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored)) |
1109 | { |
1110 | PyObject *yf = _PyGen_yf((PyGenObject *) coro); |
1111 | if (yf == NULL) Branch (1111:9): [True: 7, False: 2]
|
1112 | Py_RETURN_NONE; |
1113 | return yf; |
1114 | } |
1115 | |
1116 | static PyObject * |
1117 | cr_getsuspended(PyCoroObject *coro, void *Py_UNUSED(ignored)) |
1118 | { |
1119 | if (coro->cr_frame_state == FRAME_SUSPENDED) { Branch (1119:9): [True: 2, False: 5]
|
1120 | Py_RETURN_TRUE; |
1121 | } |
1122 | Py_RETURN_FALSE5 ; |
1123 | } |
1124 | |
1125 | static PyObject * |
1126 | cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) |
1127 | { |
1128 | if (coro->cr_frame_state == FRAME_EXECUTING) { Branch (1128:9): [True: 2, False: 7]
|
1129 | Py_RETURN_TRUE; |
1130 | } |
1131 | Py_RETURN_FALSE7 ; |
1132 | } |
1133 | |
1134 | static PyObject * |
1135 | cr_getframe(PyCoroObject *coro, void *Py_UNUSED(ignored)) |
1136 | { |
1137 | return _gen_getframe((PyGenObject *)coro, "cr_frame"); |
1138 | } |
1139 | |
1140 | |
1141 | static PyGetSetDef coro_getsetlist[] = { |
1142 | {"__name__", (getter)gen_get_name, (setter)gen_set_name, |
1143 | PyDoc_STR("name of the coroutine")}, |
1144 | {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, |
1145 | PyDoc_STR("qualified name of the coroutine")}, |
1146 | {"cr_await", (getter)coro_get_cr_await, NULL, |
1147 | PyDoc_STR("object being awaited on, or None")}, |
1148 | {"cr_running", (getter)cr_getrunning, NULL, NULL}, |
1149 | {"cr_frame", (getter)cr_getframe, NULL, NULL}, |
1150 | {"cr_suspended", (getter)cr_getsuspended, NULL, NULL}, |
1151 | {NULL} /* Sentinel */ |
1152 | }; |
1153 | |
1154 | static PyMemberDef coro_memberlist[] = { |
1155 | {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|PY_AUDIT_READ}, |
1156 | {"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin_or_finalizer), READONLY}, |
1157 | {NULL} /* Sentinel */ |
1158 | }; |
1159 | |
1160 | PyDoc_STRVAR(coro_send_doc, |
1161 | "send(arg) -> send 'arg' into coroutine,\n\ |
1162 | return next iterated value or raise StopIteration."); |
1163 | |
1164 | PyDoc_STRVAR(coro_throw_doc, |
1165 | "throw(value)\n\ |
1166 | throw(type[,value[,traceback]])\n\ |
1167 | \n\ |
1168 | Raise exception in coroutine, return next iterated value or raise\n\ |
1169 | StopIteration."); |
1170 | |
1171 | PyDoc_STRVAR(coro_close_doc, |
1172 | "close() -> raise GeneratorExit inside coroutine."); |
1173 | |
1174 | static PyMethodDef coro_methods[] = { |
1175 | {"send",(PyCFunction)gen_send, METH_O, coro_send_doc}, |
1176 | {"throw",_PyCFunction_CAST(gen_throw), METH_FASTCALL, coro_throw_doc}, |
1177 | {"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc}, |
1178 | {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, |
1179 | {NULL, NULL} /* Sentinel */ |
1180 | }; |
1181 | |
1182 | static PyAsyncMethods coro_as_async = { |
1183 | (unaryfunc)coro_await, /* am_await */ |
1184 | 0, /* am_aiter */ |
1185 | 0, /* am_anext */ |
1186 | (sendfunc)PyGen_am_send, /* am_send */ |
1187 | }; |
1188 | |
1189 | PyTypeObject PyCoro_Type = { |
1190 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
1191 | "coroutine", /* tp_name */ |
1192 | offsetof(PyCoroObject, cr_iframe) + |
1193 | offsetof(_PyInterpreterFrame, localsplus), /* tp_basicsize */ |
1194 | sizeof(PyObject *), /* tp_itemsize */ |
1195 | /* methods */ |
1196 | (destructor)gen_dealloc, /* tp_dealloc */ |
1197 | 0, /* tp_vectorcall_offset */ |
1198 | 0, /* tp_getattr */ |
1199 | 0, /* tp_setattr */ |
1200 | &coro_as_async, /* tp_as_async */ |
1201 | (reprfunc)coro_repr, /* tp_repr */ |
1202 | 0, /* tp_as_number */ |
1203 | 0, /* tp_as_sequence */ |
1204 | 0, /* tp_as_mapping */ |
1205 | 0, /* tp_hash */ |
1206 | 0, /* tp_call */ |
1207 | 0, /* tp_str */ |
1208 | PyObject_GenericGetAttr, /* tp_getattro */ |
1209 | 0, /* tp_setattro */ |
1210 | 0, /* tp_as_buffer */ |
1211 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
1212 | 0, /* tp_doc */ |
1213 | (traverseproc)gen_traverse, /* tp_traverse */ |
1214 | 0, /* tp_clear */ |
1215 | 0, /* tp_richcompare */ |
1216 | offsetof(PyCoroObject, cr_weakreflist), /* tp_weaklistoffset */ |
1217 | 0, /* tp_iter */ |
1218 | 0, /* tp_iternext */ |
1219 | coro_methods, /* tp_methods */ |
1220 | coro_memberlist, /* tp_members */ |
1221 | coro_getsetlist, /* tp_getset */ |
1222 | 0, /* tp_base */ |
1223 | 0, /* tp_dict */ |
1224 | 0, /* tp_descr_get */ |
1225 | 0, /* tp_descr_set */ |
1226 | 0, /* tp_dictoffset */ |
1227 | 0, /* tp_init */ |
1228 | 0, /* tp_alloc */ |
1229 | 0, /* tp_new */ |
1230 | 0, /* tp_free */ |
1231 | 0, /* tp_is_gc */ |
1232 | 0, /* tp_bases */ |
1233 | 0, /* tp_mro */ |
1234 | 0, /* tp_cache */ |
1235 | 0, /* tp_subclasses */ |
1236 | 0, /* tp_weaklist */ |
1237 | 0, /* tp_del */ |
1238 | 0, /* tp_version_tag */ |
1239 | _PyGen_Finalize, /* tp_finalize */ |
1240 | }; |
1241 | |
1242 | static void |
1243 | coro_wrapper_dealloc(PyCoroWrapper *cw) |
1244 | { |
1245 | _PyObject_GC_UNTRACK((PyObject *)cw); |
1246 | Py_CLEAR(cw->cw_coroutine); |
1247 | PyObject_GC_Del(cw); |
1248 | } |
1249 | |
1250 | static PyObject * |
1251 | coro_wrapper_iternext(PyCoroWrapper *cw) |
1252 | { |
1253 | return gen_iternext((PyGenObject *)cw->cw_coroutine); |
1254 | } |
1255 | |
1256 | static PyObject * |
1257 | coro_wrapper_send(PyCoroWrapper *cw, PyObject *arg) |
1258 | { |
1259 | return gen_send((PyGenObject *)cw->cw_coroutine, arg); |
1260 | } |
1261 | |
1262 | static PyObject * |
1263 | coro_wrapper_throw(PyCoroWrapper *cw, PyObject *const *args, Py_ssize_t nargs) |
1264 | { |
1265 | return gen_throw((PyGenObject *)cw->cw_coroutine, args, nargs); |
1266 | } |
1267 | |
1268 | static PyObject * |
1269 | coro_wrapper_close(PyCoroWrapper *cw, PyObject *args) |
1270 | { |
1271 | return gen_close((PyGenObject *)cw->cw_coroutine, args); |
1272 | } |
1273 | |
1274 | static int |
1275 | coro_wrapper_traverse(PyCoroWrapper *cw, visitproc visit, void *arg) |
1276 | { |
1277 | Py_VISIT((PyObject *)cw->cw_coroutine); |
1278 | return 0; |
1279 | } |
1280 | |
1281 | static PyMethodDef coro_wrapper_methods[] = { |
1282 | {"send",(PyCFunction)coro_wrapper_send, METH_O, coro_send_doc}, |
1283 | {"throw",_PyCFunction_CAST(coro_wrapper_throw), |
1284 | METH_FASTCALL, coro_throw_doc}, |
1285 | {"close",(PyCFunction)coro_wrapper_close, METH_NOARGS, coro_close_doc}, |
1286 | {NULL, NULL} /* Sentinel */ |
1287 | }; |
1288 | |
1289 | PyTypeObject _PyCoroWrapper_Type = { |
1290 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
1291 | "coroutine_wrapper", |
1292 | sizeof(PyCoroWrapper), /* tp_basicsize */ |
1293 | 0, /* tp_itemsize */ |
1294 | (destructor)coro_wrapper_dealloc, /* destructor tp_dealloc */ |
1295 | 0, /* tp_vectorcall_offset */ |
1296 | 0, /* tp_getattr */ |
1297 | 0, /* tp_setattr */ |
1298 | 0, /* tp_as_async */ |
1299 | 0, /* tp_repr */ |
1300 | 0, /* tp_as_number */ |
1301 | 0, /* tp_as_sequence */ |
1302 | 0, /* tp_as_mapping */ |
1303 | 0, /* tp_hash */ |
1304 | 0, /* tp_call */ |
1305 | 0, /* tp_str */ |
1306 | PyObject_GenericGetAttr, /* tp_getattro */ |
1307 | 0, /* tp_setattro */ |
1308 | 0, /* tp_as_buffer */ |
1309 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
1310 | "A wrapper object implementing __await__ for coroutines.", |
1311 | (traverseproc)coro_wrapper_traverse, /* tp_traverse */ |
1312 | 0, /* tp_clear */ |
1313 | 0, /* tp_richcompare */ |
1314 | 0, /* tp_weaklistoffset */ |
1315 | PyObject_SelfIter, /* tp_iter */ |
1316 | (iternextfunc)coro_wrapper_iternext, /* tp_iternext */ |
1317 | coro_wrapper_methods, /* tp_methods */ |
1318 | 0, /* tp_members */ |
1319 | 0, /* tp_getset */ |
1320 | 0, /* tp_base */ |
1321 | 0, /* tp_dict */ |
1322 | 0, /* tp_descr_get */ |
1323 | 0, /* tp_descr_set */ |
1324 | 0, /* tp_dictoffset */ |
1325 | 0, /* tp_init */ |
1326 | 0, /* tp_alloc */ |
1327 | 0, /* tp_new */ |
1328 | 0, /* tp_free */ |
1329 | }; |
1330 | |
1331 | static PyObject * |
1332 | compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame) |
1333 | { |
1334 | _PyInterpreterFrame *frame = current_frame; |
1335 | /* First count how many frames we have */ |
1336 | int frame_count = 0; |
1337 | for (; frame && frame_count < origin_depth35.0k ; ++frame_count31.8k ) { Branch (1337:12): [True: 35.0k, False: 1]
Branch (1337:21): [True: 31.8k, False: 3.18k]
|
1338 | frame = frame->previous; |
1339 | } |
1340 | |
1341 | /* Now collect them */ |
1342 | PyObject *cr_origin = PyTuple_New(frame_count); |
1343 | if (cr_origin == NULL) { Branch (1343:9): [True: 0, False: 3.18k]
|
1344 | return NULL; |
1345 | } |
1346 | frame = current_frame; |
1347 | for (int i = 0; i < frame_count; ++i31.8k ) { Branch (1347:21): [True: 31.8k, False: 3.18k]
|
1348 | PyCodeObject *code = frame->f_code; |
1349 | int line = _PyInterpreterFrame_GetLine(frame); |
1350 | PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line, |
1351 | code->co_name); |
1352 | if (!frameinfo) { Branch (1352:13): [True: 0, False: 31.8k]
|
1353 | Py_DECREF(cr_origin); |
1354 | return NULL; |
1355 | } |
1356 | PyTuple_SET_ITEM(cr_origin, i, frameinfo); |
1357 | frame = frame->previous; |
1358 | } |
1359 | |
1360 | return cr_origin; |
1361 | } |
1362 | |
1363 | PyObject * |
1364 | PyCoro_New(PyFrameObject *f, PyObject *name, PyObject *qualname) |
1365 | { |
1366 | PyObject *coro = gen_new_with_qualname(&PyCoro_Type, f, name, qualname); |
1367 | if (!coro) { Branch (1367:9): [True: 0, False: 0]
|
1368 | return NULL; |
1369 | } |
1370 | |
1371 | PyThreadState *tstate = _PyThreadState_GET(); |
1372 | int origin_depth = tstate->coroutine_origin_tracking_depth; |
1373 |
|
1374 | if (origin_depth == 0) { Branch (1374:9): [True: 0, False: 0]
|
1375 | ((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL; |
1376 | } else { |
1377 | PyObject *cr_origin = compute_cr_origin(origin_depth, _PyEval_GetFrame()); |
1378 | ((PyCoroObject *)coro)->cr_origin_or_finalizer = cr_origin; |
1379 | if (!cr_origin) { Branch (1379:13): [True: 0, False: 0]
|
1380 | Py_DECREF(coro); |
1381 | return NULL; |
1382 | } |
1383 | } |
1384 | |
1385 | return coro; |
1386 | } |
1387 | |
1388 | |
1389 | /* ========= Asynchronous Generators ========= */ |
1390 | |
1391 | |
1392 | typedef enum { |
1393 | AWAITABLE_STATE_INIT, /* new awaitable, has not yet been iterated */ |
1394 | AWAITABLE_STATE_ITER, /* being iterated */ |
1395 | AWAITABLE_STATE_CLOSED, /* closed */ |
1396 | } AwaitableState; |
1397 | |
1398 | |
1399 | typedef struct PyAsyncGenASend { |
1400 | PyObject_HEAD |
1401 | PyAsyncGenObject *ags_gen; |
1402 | |
1403 | /* Can be NULL, when in the __anext__() mode |
1404 | (equivalent of "asend(None)") */ |
1405 | PyObject *ags_sendval; |
1406 | |
1407 | AwaitableState ags_state; |
1408 | } PyAsyncGenASend; |
1409 | |
1410 | |
1411 | typedef struct PyAsyncGenAThrow { |
1412 | PyObject_HEAD |
1413 | PyAsyncGenObject *agt_gen; |
1414 | |
1415 | /* Can be NULL, when in the "aclose()" mode |
1416 | (equivalent of "athrow(GeneratorExit)") */ |
1417 | PyObject *agt_args; |
1418 | |
1419 | AwaitableState agt_state; |
1420 | } PyAsyncGenAThrow; |
1421 | |
1422 | |
1423 | typedef struct _PyAsyncGenWrappedValue { |
1424 | PyObject_HEAD |
1425 | PyObject *agw_val; |
1426 | } _PyAsyncGenWrappedValue; |
1427 | |
1428 | |
1429 | #define _PyAsyncGenWrappedValue_CheckExact(o) \ |
1430 | Py_IS_TYPE(o, &_PyAsyncGenWrappedValue_Type) |
1431 | |
1432 | #define PyAsyncGenASend_CheckExact(o) \ |
1433 | Py_IS_TYPE(o, &_PyAsyncGenASend_Type) |
1434 | |
1435 | |
1436 | static int |
1437 | async_gen_traverse(PyAsyncGenObject *gen, visitproc visit, void *arg) |
1438 | { |
1439 | Py_VISIT(gen->ag_origin_or_finalizer); |
1440 | return gen_traverse((PyGenObject*)gen, visit, arg); |
1441 | } |
1442 | |
1443 | |
1444 | static PyObject * |
1445 | async_gen_repr(PyAsyncGenObject *o) |
1446 | { |
1447 | return PyUnicode_FromFormat("<async_generator object %S at %p>", |
1448 | o->ag_qualname, o); |
1449 | } |
1450 | |
1451 | |
1452 | static int |
1453 | async_gen_init_hooks(PyAsyncGenObject *o) |
1454 | { |
1455 | PyThreadState *tstate; |
1456 | PyObject *finalizer; |
1457 | PyObject *firstiter; |
1458 | |
1459 | if (o->ag_hooks_inited) { Branch (1459:9): [True: 441, False: 224]
|
1460 | return 0; |
1461 | } |
1462 | |
1463 | o->ag_hooks_inited = 1; |
1464 | |
1465 | tstate = _PyThreadState_GET(); |
1466 | |
1467 | finalizer = tstate->async_gen_finalizer; |
1468 | if (finalizer) { Branch (1468:9): [True: 145, False: 79]
|
1469 | Py_INCREF(finalizer); |
1470 | o->ag_origin_or_finalizer = finalizer; |
1471 | } |
1472 | |
1473 | firstiter = tstate->async_gen_firstiter; |
1474 | if (firstiter) { Branch (1474:9): [True: 145, False: 79]
|
1475 | PyObject *res; |
1476 | |
1477 | Py_INCREF(firstiter); |
1478 | res = PyObject_CallOneArg(firstiter, (PyObject *)o); |
1479 | Py_DECREF(firstiter); |
1480 | if (res == NULL) { Branch (1480:13): [True: 0, False: 145]
|
1481 | return 1; |
1482 | } |
1483 | Py_DECREF(res); |
1484 | } |
1485 | |
1486 | return 0; |
1487 | } |
1488 | |
1489 | |
1490 | static PyObject * |
1491 | async_gen_anext(PyAsyncGenObject *o) |
1492 | { |
1493 | if (async_gen_init_hooks(o)) { Branch (1493:9): [True: 0, False: 589]
|
1494 | return NULL; |
1495 | } |
1496 | return async_gen_asend_new(o, NULL); |
1497 | } |
1498 | |
1499 | |
1500 | static PyObject * |
1501 | async_gen_asend(PyAsyncGenObject *o, PyObject *arg) |
1502 | { |
1503 | if (async_gen_init_hooks(o)) { Branch (1503:9): [True: 0, False: 22]
|
1504 | return NULL; |
1505 | } |
1506 | return async_gen_asend_new(o, arg); |
1507 | } |
1508 | |
1509 | |
1510 | static PyObject * |
1511 | async_gen_aclose(PyAsyncGenObject *o, PyObject *arg) |
1512 | { |
1513 | if (async_gen_init_hooks(o)) { Branch (1513:9): [True: 0, False: 31]
|
1514 | return NULL; |
1515 | } |
1516 | return async_gen_athrow_new(o, NULL); |
1517 | } |
1518 | |
1519 | static PyObject * |
1520 | async_gen_athrow(PyAsyncGenObject *o, PyObject *args) |
1521 | { |
1522 | if (async_gen_init_hooks(o)) { Branch (1522:9): [True: 0, False: 23]
|
1523 | return NULL; |
1524 | } |
1525 | return async_gen_athrow_new(o, args); |
1526 | } |
1527 | |
1528 | static PyObject * |
1529 | ag_getframe(PyAsyncGenObject *ag, void *Py_UNUSED(ignored)) |
1530 | { |
1531 | return _gen_getframe((PyGenObject *)ag, "ag_frame"); |
1532 | } |
1533 | |
1534 | static PyGetSetDef async_gen_getsetlist[] = { |
1535 | {"__name__", (getter)gen_get_name, (setter)gen_set_name, |
1536 | PyDoc_STR("name of the async generator")}, |
1537 | {"__qualname__", (getter)gen_get_qualname, (setter)gen_set_qualname, |
1538 | PyDoc_STR("qualified name of the async generator")}, |
1539 | {"ag_await", (getter)coro_get_cr_await, NULL, |
1540 | PyDoc_STR("object being awaited on, or None")}, |
1541 | {"ag_frame", (getter)ag_getframe, NULL, NULL}, |
1542 | {NULL} /* Sentinel */ |
1543 | }; |
1544 | |
1545 | static PyMemberDef async_gen_memberlist[] = { |
1546 | {"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async), |
1547 | READONLY}, |
1548 | {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|PY_AUDIT_READ}, |
1549 | {NULL} /* Sentinel */ |
1550 | }; |
1551 | |
1552 | PyDoc_STRVAR(async_aclose_doc, |
1553 | "aclose() -> raise GeneratorExit inside generator."); |
1554 | |
1555 | PyDoc_STRVAR(async_asend_doc, |
1556 | "asend(v) -> send 'v' in generator."); |
1557 | |
1558 | PyDoc_STRVAR(async_athrow_doc, |
1559 | "athrow(typ[,val[,tb]]) -> raise exception in generator."); |
1560 | |
1561 | static PyMethodDef async_gen_methods[] = { |
1562 | {"asend", (PyCFunction)async_gen_asend, METH_O, async_asend_doc}, |
1563 | {"athrow",(PyCFunction)async_gen_athrow, METH_VARARGS, async_athrow_doc}, |
1564 | {"aclose", (PyCFunction)async_gen_aclose, METH_NOARGS, async_aclose_doc}, |
1565 | {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, |
1566 | {"__class_getitem__", Py_GenericAlias, |
1567 | METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, |
1568 | {NULL, NULL} /* Sentinel */ |
1569 | }; |
1570 | |
1571 | |
1572 | static PyAsyncMethods async_gen_as_async = { |
1573 | 0, /* am_await */ |
1574 | PyObject_SelfIter, /* am_aiter */ |
1575 | (unaryfunc)async_gen_anext, /* am_anext */ |
1576 | (sendfunc)PyGen_am_send, /* am_send */ |
1577 | }; |
1578 | |
1579 | |
1580 | PyTypeObject PyAsyncGen_Type = { |
1581 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
1582 | "async_generator", /* tp_name */ |
1583 | offsetof(PyAsyncGenObject, ag_iframe) + |
1584 | offsetof(_PyInterpreterFrame, localsplus), /* tp_basicsize */ |
1585 | sizeof(PyObject *), /* tp_itemsize */ |
1586 | /* methods */ |
1587 | (destructor)gen_dealloc, /* tp_dealloc */ |
1588 | 0, /* tp_vectorcall_offset */ |
1589 | 0, /* tp_getattr */ |
1590 | 0, /* tp_setattr */ |
1591 | &async_gen_as_async, /* tp_as_async */ |
1592 | (reprfunc)async_gen_repr, /* tp_repr */ |
1593 | 0, /* tp_as_number */ |
1594 | 0, /* tp_as_sequence */ |
1595 | 0, /* tp_as_mapping */ |
1596 | 0, /* tp_hash */ |
1597 | 0, /* tp_call */ |
1598 | 0, /* tp_str */ |
1599 | PyObject_GenericGetAttr, /* tp_getattro */ |
1600 | 0, /* tp_setattro */ |
1601 | 0, /* tp_as_buffer */ |
1602 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
1603 | 0, /* tp_doc */ |
1604 | (traverseproc)async_gen_traverse, /* tp_traverse */ |
1605 | 0, /* tp_clear */ |
1606 | 0, /* tp_richcompare */ |
1607 | offsetof(PyAsyncGenObject, ag_weakreflist), /* tp_weaklistoffset */ |
1608 | 0, /* tp_iter */ |
1609 | 0, /* tp_iternext */ |
1610 | async_gen_methods, /* tp_methods */ |
1611 | async_gen_memberlist, /* tp_members */ |
1612 | async_gen_getsetlist, /* tp_getset */ |
1613 | 0, /* tp_base */ |
1614 | 0, /* tp_dict */ |
1615 | 0, /* tp_descr_get */ |
1616 | 0, /* tp_descr_set */ |
1617 | 0, /* tp_dictoffset */ |
1618 | 0, /* tp_init */ |
1619 | 0, /* tp_alloc */ |
1620 | 0, /* tp_new */ |
1621 | 0, /* tp_free */ |
1622 | 0, /* tp_is_gc */ |
1623 | 0, /* tp_bases */ |
1624 | 0, /* tp_mro */ |
1625 | 0, /* tp_cache */ |
1626 | 0, /* tp_subclasses */ |
1627 | 0, /* tp_weaklist */ |
1628 | 0, /* tp_del */ |
1629 | 0, /* tp_version_tag */ |
1630 | _PyGen_Finalize, /* tp_finalize */ |
1631 | }; |
1632 | |
1633 | |
1634 | #if _PyAsyncGen_MAXFREELIST > 0 |
1635 | static struct _Py_async_gen_state * |
1636 | get_async_gen_state(void) |
1637 | { |
1638 | PyInterpreterState *interp = _PyInterpreterState_GET(); |
1639 | return &interp->async_gen; |
1640 | } |
1641 | #endif |
1642 | |
1643 | |
1644 | PyObject * |
1645 | PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) |
1646 | { |
1647 | PyAsyncGenObject *o; |
1648 | o = (PyAsyncGenObject *)gen_new_with_qualname( |
1649 | &PyAsyncGen_Type, f, name, qualname); |
1650 | if (o == NULL) { Branch (1650:9): [True: 0, False: 0]
|
1651 | return NULL; |
1652 | } |
1653 | o->ag_origin_or_finalizer = NULL; |
1654 | o->ag_closed = 0; |
1655 | o->ag_hooks_inited = 0; |
1656 | o->ag_running_async = 0; |
1657 | return (PyObject*)o; |
1658 | } |
1659 | |
1660 | |
1661 | void |
1662 | _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp) |
1663 | { |
1664 | #if _PyAsyncGen_MAXFREELIST > 0 |
1665 | struct _Py_async_gen_state *state = &interp->async_gen; |
1666 | |
1667 | while (state->value_numfree) { Branch (1667:12): [True: 15, False: 13.5k]
|
1668 | _PyAsyncGenWrappedValue *o; |
1669 | o = state->value_freelist[--state->value_numfree]; |
1670 | assert(_PyAsyncGenWrappedValue_CheckExact(o)); |
1671 | PyObject_GC_Del(o); |
1672 | } |
1673 | |
1674 | while (state->asend_numfree) { Branch (1674:12): [True: 23, False: 13.5k]
|
1675 | PyAsyncGenASend *o; |
1676 | o = state->asend_freelist[--state->asend_numfree]; |
1677 | assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type)); |
1678 | PyObject_GC_Del(o); |
1679 | } |
1680 | #endif |
1681 | } |
1682 | |
1683 | void |
1684 | _PyAsyncGen_Fini(PyInterpreterState *interp) |
1685 | { |
1686 | _PyAsyncGen_ClearFreeLists(interp); |
1687 | #if defined(Py_DEBUG) && _PyAsyncGen_MAXFREELIST > 0 |
1688 | struct _Py_async_gen_state *state = &interp->async_gen; |
1689 | state->value_numfree = -1; |
1690 | state->asend_numfree = -1; |
1691 | #endif |
1692 | } |
1693 | |
1694 | |
1695 | static PyObject * |
1696 | async_gen_unwrap_value(PyAsyncGenObject *gen, PyObject *result) |
1697 | { |
1698 | if (result == NULL) { Branch (1698:9): [True: 200, False: 564]
|
1699 | if (!PyErr_Occurred()) { Branch (1699:13): [True: 10, False: 190]
|
1700 | PyErr_SetNone(PyExc_StopAsyncIteration); |
1701 | } |
1702 | |
1703 | if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) Branch (1703:13): [True: 160, False: 40]
|
1704 | || PyErr_ExceptionMatches(PyExc_GeneratorExit)40 Branch (1704:16): [True: 1, False: 39]
|
1705 | ) { |
1706 | gen->ag_closed = 1; |
1707 | } |
1708 | |
1709 | gen->ag_running_async = 0; |
1710 | return NULL; |
1711 | } |
1712 | |
1713 | if (_PyAsyncGenWrappedValue_CheckExact(result)) { |
1714 | /* async yield */ |
1715 | _PyGen_SetStopIterationValue(((_PyAsyncGenWrappedValue*)result)->agw_val); |
1716 | Py_DECREF(result); |
1717 | gen->ag_running_async = 0; |
1718 | return NULL; |
1719 | } |
1720 | |
1721 | return result; |
1722 | } |
1723 | |
1724 | |
1725 | /* ---------- Async Generator ASend Awaitable ------------ */ |
1726 | |
1727 | |
1728 | static void |
1729 | async_gen_asend_dealloc(PyAsyncGenASend *o) |
1730 | { |
1731 | _PyObject_GC_UNTRACK((PyObject *)o); |
1732 | Py_CLEAR(o->ags_gen); |
1733 | Py_CLEAR(o->ags_sendval); |
1734 | #if _PyAsyncGen_MAXFREELIST > 0 |
1735 | struct _Py_async_gen_state *state = get_async_gen_state(); |
1736 | #ifdef Py_DEBUG |
1737 | // async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini() |
1738 | assert(state->asend_numfree != -1); |
1739 | #endif |
1740 | if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) { Branch (1740:9): [True: 611, False: 0]
|
1741 | assert(PyAsyncGenASend_CheckExact(o)); |
1742 | state->asend_freelist[state->asend_numfree++] = o; |
1743 | } |
1744 | else |
1745 | #endif |
1746 | { |
1747 | PyObject_GC_Del(o); |
1748 | } |
1749 | } |
1750 | |
1751 | static int |
1752 | async_gen_asend_traverse(PyAsyncGenASend *o, visitproc visit, void *arg) |
1753 | { |
1754 | Py_VISIT(o->ags_gen); |
1755 | Py_VISIT(o->ags_sendval); |
1756 | return 0; |
1757 | } |
1758 | |
1759 | |
1760 | static PyObject * |
1761 | async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg) |
1762 | { |
1763 | PyObject *result; |
1764 | |
1765 | if (o->ags_state == AWAITABLE_STATE_CLOSED) { Branch (1765:9): [True: 2, False: 715]
|
1766 | PyErr_SetString( |
1767 | PyExc_RuntimeError, |
1768 | "cannot reuse already awaited __anext__()/asend()"); |
1769 | return NULL; |
1770 | } |
1771 | |
1772 | if (o->ags_state == AWAITABLE_STATE_INIT) { Branch (1772:9): [True: 606, False: 109]
|
1773 | if (o->ags_gen->ag_running_async) { Branch (1773:13): [True: 0, False: 606]
|
1774 | PyErr_SetString( |
1775 | PyExc_RuntimeError, |
1776 | "anext(): asynchronous generator is already running"); |
1777 | return NULL; |
1778 | } |
1779 | |
1780 | if (arg == NULL || arg == 10 Py_None10 ) { Branch (1780:13): [True: 596, False: 10]
Branch (1780:28): [True: 7, False: 3]
|
1781 | arg = o->ags_sendval; |
1782 | } |
1783 | o->ags_state = AWAITABLE_STATE_ITER; |
1784 | } |
1785 | |
1786 | o->ags_gen->ag_running_async = 1; |
1787 | result = gen_send((PyGenObject*)o->ags_gen, arg); |
1788 | result = async_gen_unwrap_value(o->ags_gen, result); |
1789 | |
1790 | if (result == NULL) { Branch (1790:9): [True: 596, False: 119]
|
1791 | o->ags_state = AWAITABLE_STATE_CLOSED; |
1792 | } |
1793 | |
1794 | return result; |
1795 | } |
1796 | |
1797 | |
1798 | static PyObject * |
1799 | async_gen_asend_iternext(PyAsyncGenASend *o) |
1800 | { |
1801 | return async_gen_asend_send(o, NULL); |
1802 | } |
1803 | |
1804 | |
1805 | static PyObject * |
1806 | async_gen_asend_throw(PyAsyncGenASend *o, PyObject *const *args, Py_ssize_t nargs) |
1807 | { |
1808 | PyObject *result; |
1809 | |
1810 | if (o->ags_state == AWAITABLE_STATE_CLOSED) { Branch (1810:9): [True: 0, False: 22]
|
1811 | PyErr_SetString( |
1812 | PyExc_RuntimeError, |
1813 | "cannot reuse already awaited __anext__()/asend()"); |
1814 | return NULL; |
1815 | } |
1816 | |
1817 | result = gen_throw((PyGenObject*)o->ags_gen, args, nargs); |
1818 | result = async_gen_unwrap_value(o->ags_gen, result); |
1819 | |
1820 | if (result == NULL) { Branch (1820:9): [True: 13, False: 9]
|
1821 | o->ags_state = AWAITABLE_STATE_CLOSED; |
1822 | } |
1823 | |
1824 | return result; |
1825 | } |
1826 | |
1827 | |
1828 | static PyObject * |
1829 | async_gen_asend_close(PyAsyncGenASend *o, PyObject *args) |
1830 | { |
1831 | o->ags_state = AWAITABLE_STATE_CLOSED; |
1832 | Py_RETURN_NONE; |
1833 | } |
1834 | |
1835 | |
1836 | static PyMethodDef async_gen_asend_methods[] = { |
1837 | {"send", (PyCFunction)async_gen_asend_send, METH_O, send_doc}, |
1838 | {"throw", _PyCFunction_CAST(async_gen_asend_throw), METH_FASTCALL, throw_doc}, |
1839 | {"close", (PyCFunction)async_gen_asend_close, METH_NOARGS, close_doc}, |
1840 | {NULL, NULL} /* Sentinel */ |
1841 | }; |
1842 | |
1843 | |
1844 | static PyAsyncMethods async_gen_asend_as_async = { |
1845 | PyObject_SelfIter, /* am_await */ |
1846 | 0, /* am_aiter */ |
1847 | 0, /* am_anext */ |
1848 | 0, /* am_send */ |
1849 | }; |
1850 | |
1851 | |
1852 | PyTypeObject _PyAsyncGenASend_Type = { |
1853 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
1854 | "async_generator_asend", /* tp_name */ |
1855 | sizeof(PyAsyncGenASend), /* tp_basicsize */ |
1856 | 0, /* tp_itemsize */ |
1857 | /* methods */ |
1858 | (destructor)async_gen_asend_dealloc, /* tp_dealloc */ |
1859 | 0, /* tp_vectorcall_offset */ |
1860 | 0, /* tp_getattr */ |
1861 | 0, /* tp_setattr */ |
1862 | &async_gen_asend_as_async, /* tp_as_async */ |
1863 | 0, /* tp_repr */ |
1864 | 0, /* tp_as_number */ |
1865 | 0, /* tp_as_sequence */ |
1866 | 0, /* tp_as_mapping */ |
1867 | 0, /* tp_hash */ |
1868 | 0, /* tp_call */ |
1869 | 0, /* tp_str */ |
1870 | PyObject_GenericGetAttr, /* tp_getattro */ |
1871 | 0, /* tp_setattro */ |
1872 | 0, /* tp_as_buffer */ |
1873 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
1874 | 0, /* tp_doc */ |
1875 | (traverseproc)async_gen_asend_traverse, /* tp_traverse */ |
1876 | 0, /* tp_clear */ |
1877 | 0, /* tp_richcompare */ |
1878 | 0, /* tp_weaklistoffset */ |
1879 | PyObject_SelfIter, /* tp_iter */ |
1880 | (iternextfunc)async_gen_asend_iternext, /* tp_iternext */ |
1881 | async_gen_asend_methods, /* tp_methods */ |
1882 | 0, /* tp_members */ |
1883 | 0, /* tp_getset */ |
1884 | 0, /* tp_base */ |
1885 | 0, /* tp_dict */ |
1886 | 0, /* tp_descr_get */ |
1887 | 0, /* tp_descr_set */ |
1888 | 0, /* tp_dictoffset */ |
1889 | 0, /* tp_init */ |
1890 | 0, /* tp_alloc */ |
1891 | 0, /* tp_new */ |
1892 | }; |
1893 | |
1894 | |
1895 | static PyObject * |
1896 | async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval) |
1897 | { |
1898 | PyAsyncGenASend *o; |
1899 | #if _PyAsyncGen_MAXFREELIST > 0 |
1900 | struct _Py_async_gen_state *state = get_async_gen_state(); |
1901 | #ifdef Py_DEBUG |
1902 | // async_gen_asend_new() must not be called after _PyAsyncGen_Fini() |
1903 | assert(state->asend_numfree != -1); |
1904 | #endif |
1905 | if (state->asend_numfree) { Branch (1905:9): [True: 588, False: 23]
|
1906 | state->asend_numfree--; |
1907 | o = state->asend_freelist[state->asend_numfree]; |
1908 | _Py_NewReference((PyObject *)o); |
1909 | } |
1910 | else |
1911 | #endif |
1912 | { |
1913 | o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type); |
1914 | if (o == NULL) { Branch (1914:13): [True: 0, False: 23]
|
1915 | return NULL; |
1916 | } |
1917 | } |
1918 | |
1919 | Py_INCREF(gen); |
1920 | o->ags_gen = gen; |
1921 | |
1922 | Py_XINCREF(sendval); |
1923 | o->ags_sendval = sendval; |
1924 | |
1925 | o->ags_state = AWAITABLE_STATE_INIT; |
1926 | |
1927 | _PyObject_GC_TRACK((PyObject*)o); |
1928 | return (PyObject*)o; |
1929 | } |
1930 | |
1931 | |
1932 | /* ---------- Async Generator Value Wrapper ------------ */ |
1933 | |
1934 | |
1935 | static void |
1936 | async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o) |
1937 | { |
1938 | _PyObject_GC_UNTRACK((PyObject *)o); |
1939 | Py_CLEAR(o->agw_val); |
1940 | #if _PyAsyncGen_MAXFREELIST > 0 |
1941 | struct _Py_async_gen_state *state = get_async_gen_state(); |
1942 | #ifdef Py_DEBUG |
1943 | // async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini() |
1944 | assert(state->value_numfree != -1); |
1945 | #endif |
1946 | if (state->value_numfree < _PyAsyncGen_MAXFREELIST) { Branch (1946:9): [True: 434, False: 0]
|
1947 | assert(_PyAsyncGenWrappedValue_CheckExact(o)); |
1948 | state->value_freelist[state->value_numfree++] = o; |
1949 | OBJECT_STAT_INC(to_freelist); |
1950 | } |
1951 | else |
1952 | #endif |
1953 | { |
1954 | PyObject_GC_Del(o); |
1955 | } |
1956 | } |
1957 | |
1958 | |
1959 | static int |
1960 | async_gen_wrapped_val_traverse(_PyAsyncGenWrappedValue *o, |
1961 | visitproc visit, void *arg) |
1962 | { |
1963 | Py_VISIT(o->agw_val); |
1964 | return 0; |
1965 | } |
1966 | |
1967 | |
1968 | PyTypeObject _PyAsyncGenWrappedValue_Type = { |
1969 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
1970 | "async_generator_wrapped_value", /* tp_name */ |
1971 | sizeof(_PyAsyncGenWrappedValue), /* tp_basicsize */ |
1972 | 0, /* tp_itemsize */ |
1973 | /* methods */ |
1974 | (destructor)async_gen_wrapped_val_dealloc, /* tp_dealloc */ |
1975 | 0, /* tp_vectorcall_offset */ |
1976 | 0, /* tp_getattr */ |
1977 | 0, /* tp_setattr */ |
1978 | 0, /* tp_as_async */ |
1979 | 0, /* tp_repr */ |
1980 | 0, /* tp_as_number */ |
1981 | 0, /* tp_as_sequence */ |
1982 | 0, /* tp_as_mapping */ |
1983 | 0, /* tp_hash */ |
1984 | 0, /* tp_call */ |
1985 | 0, /* tp_str */ |
1986 | PyObject_GenericGetAttr, /* tp_getattro */ |
1987 | 0, /* tp_setattro */ |
1988 | 0, /* tp_as_buffer */ |
1989 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
1990 | 0, /* tp_doc */ |
1991 | (traverseproc)async_gen_wrapped_val_traverse, /* tp_traverse */ |
1992 | 0, /* tp_clear */ |
1993 | 0, /* tp_richcompare */ |
1994 | 0, /* tp_weaklistoffset */ |
1995 | 0, /* tp_iter */ |
1996 | 0, /* tp_iternext */ |
1997 | 0, /* tp_methods */ |
1998 | 0, /* tp_members */ |
1999 | 0, /* tp_getset */ |
2000 | 0, /* tp_base */ |
2001 | 0, /* tp_dict */ |
2002 | 0, /* tp_descr_get */ |
2003 | 0, /* tp_descr_set */ |
2004 | 0, /* tp_dictoffset */ |
2005 | 0, /* tp_init */ |
2006 | 0, /* tp_alloc */ |
2007 | 0, /* tp_new */ |
2008 | }; |
2009 | |
2010 | |
2011 | PyObject * |
2012 | _PyAsyncGenValueWrapperNew(PyObject *val) |
2013 | { |
2014 | _PyAsyncGenWrappedValue *o; |
2015 | assert(val); |
2016 | |
2017 | #if _PyAsyncGen_MAXFREELIST > 0 |
2018 | struct _Py_async_gen_state *state = get_async_gen_state(); |
2019 | #ifdef Py_DEBUG |
2020 | // _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini() |
2021 | assert(state->value_numfree != -1); |
2022 | #endif |
2023 | if (state->value_numfree) { Branch (2023:9): [True: 419, False: 15]
|
2024 | state->value_numfree--; |
2025 | o = state->value_freelist[state->value_numfree]; |
2026 | OBJECT_STAT_INC(from_freelist); |
2027 | assert(_PyAsyncGenWrappedValue_CheckExact(o)); |
2028 | _Py_NewReference((PyObject*)o); |
2029 | } |
2030 | else |
2031 | #endif |
2032 | { |
2033 | o = PyObject_GC_New(_PyAsyncGenWrappedValue, |
2034 | &_PyAsyncGenWrappedValue_Type); |
2035 | if (o == NULL) { Branch (2035:13): [True: 0, False: 15]
|
2036 | return NULL; |
2037 | } |
2038 | } |
2039 | o->agw_val = val; |
2040 | Py_INCREF(val); |
2041 | _PyObject_GC_TRACK((PyObject*)o); |
2042 | return (PyObject*)o; |
2043 | } |
2044 | |
2045 | |
2046 | /* ---------- Async Generator AThrow awaitable ------------ */ |
2047 | |
2048 | |
2049 | static void |
2050 | async_gen_athrow_dealloc(PyAsyncGenAThrow *o) |
2051 | { |
2052 | _PyObject_GC_UNTRACK((PyObject *)o); |
2053 | Py_CLEAR(o->agt_gen); |
2054 | Py_CLEAR(o->agt_args); |
2055 | PyObject_GC_Del(o); |
2056 | } |
2057 | |
2058 | |
2059 | static int |
2060 | async_gen_athrow_traverse(PyAsyncGenAThrow *o, visitproc visit, void *arg) |
2061 | { |
2062 | Py_VISIT(o->agt_gen); |
2063 | Py_VISIT(o->agt_args); |
2064 | return 0; |
2065 | } |
2066 | |
2067 | |
2068 | static PyObject * |
2069 | async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) |
2070 | { |
2071 | PyGenObject *gen = (PyGenObject*)o->agt_gen; |
2072 | PyObject *retval; |
2073 | |
2074 | if (o->agt_state == AWAITABLE_STATE_CLOSED) { Branch (2074:9): [True: 1, False: 56]
|
2075 | PyErr_SetString( |
2076 | PyExc_RuntimeError, |
2077 | "cannot reuse already awaited aclose()/athrow()"); |
2078 | return NULL; |
2079 | } |
2080 | |
2081 | if (gen->gi_frame_state >= FRAME_COMPLETED) { Branch (2081:9): [True: 7, False: 49]
|
2082 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2083 | PyErr_SetNone(PyExc_StopIteration); |
2084 | return NULL; |
2085 | } |
2086 | |
2087 | if (o->agt_state == AWAITABLE_STATE_INIT) { Branch (2087:9): [True: 39, False: 10]
|
2088 | if (o->agt_gen->ag_running_async) { Branch (2088:13): [True: 0, False: 39]
|
2089 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2090 | if (o->agt_args == NULL) { Branch (2090:17): [True: 0, False: 0]
|
2091 | PyErr_SetString( |
2092 | PyExc_RuntimeError, |
2093 | "aclose(): asynchronous generator is already running"); |
2094 | } |
2095 | else { |
2096 | PyErr_SetString( |
2097 | PyExc_RuntimeError, |
2098 | "athrow(): asynchronous generator is already running"); |
2099 | } |
2100 | return NULL; |
2101 | } |
2102 | |
2103 | if (o->agt_gen->ag_closed) { Branch (2103:13): [True: 0, False: 39]
|
2104 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2105 | PyErr_SetNone(PyExc_StopAsyncIteration); |
2106 | return NULL; |
2107 | } |
2108 | |
2109 | if (arg != Py_None) { Branch (2109:13): [True: 0, False: 39]
|
2110 | PyErr_SetString(PyExc_RuntimeError, NON_INIT_CORO_MSG); |
2111 | return NULL; |
2112 | } |
2113 | |
2114 | o->agt_state = AWAITABLE_STATE_ITER; |
2115 | o->agt_gen->ag_running_async = 1; |
2116 | |
2117 | if (o->agt_args == NULL) { Branch (2117:13): [True: 16, False: 23]
|
2118 | /* aclose() mode */ |
2119 | o->agt_gen->ag_closed = 1; |
2120 | |
2121 | retval = _gen_throw((PyGenObject *)gen, |
2122 | 0, /* Do not close generator when |
2123 | PyExc_GeneratorExit is passed */ |
2124 | PyExc_GeneratorExit, NULL, NULL); |
2125 | |
2126 | if (retval && _PyAsyncGenWrappedValue_CheckExact6 (retval)) { Branch (2126:17): [True: 6, False: 10]
|
2127 | Py_DECREF(retval); |
2128 | goto yield_close; |
2129 | } |
2130 | } else { |
2131 | PyObject *typ; |
2132 | PyObject *tb = NULL; |
2133 | PyObject *val = NULL; |
2134 | |
2135 | if (!PyArg_UnpackTuple(o->agt_args, "athrow", 1, 3, Branch (2135:17): [True: 0, False: 23]
|
2136 | &typ, &val, &tb)) { |
2137 | return NULL; |
2138 | } |
2139 | |
2140 | retval = _gen_throw((PyGenObject *)gen, |
2141 | 0, /* Do not close generator when |
2142 | PyExc_GeneratorExit is passed */ |
2143 | typ, val, tb); |
2144 | retval = async_gen_unwrap_value(o->agt_gen, retval); |
2145 | } |
2146 | if (retval == NULL) { Branch (2146:13): [True: 31, False: 7]
|
2147 | goto check_error; |
2148 | } |
2149 | return retval; |
2150 | } |
2151 | |
2152 | assert(o->agt_state == AWAITABLE_STATE_ITER); |
2153 | |
2154 | retval = gen_send((PyGenObject *)gen, arg); |
2155 | if (o->agt_args) { Branch (2155:9): [True: 3, False: 7]
|
2156 | return async_gen_unwrap_value(o->agt_gen, retval); |
2157 | } else { |
2158 | /* aclose() mode */ |
2159 | if (retval) { Branch (2159:13): [True: 4, False: 3]
|
2160 | if (_PyAsyncGenWrappedValue_CheckExact(retval)) { |
2161 | Py_DECREF(retval); |
2162 | goto yield_close; |
2163 | } |
2164 | else { |
2165 | return retval; |
2166 | } |
2167 | } |
2168 | else { |
2169 | goto check_error; |
2170 | } |
2171 | } |
2172 | |
2173 | yield_close: |
2174 | o->agt_gen->ag_running_async = 0; |
2175 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2176 | PyErr_SetString( |
2177 | PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG); |
2178 | return NULL; |
2179 | |
2180 | check_error: |
2181 | o->agt_gen->ag_running_async = 0; |
2182 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2183 | if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || Branch (2183:9): [True: 3, False: 31]
|
2184 | PyErr_ExceptionMatches(PyExc_GeneratorExit)31 ) Branch (2184:13): [True: 12, False: 19]
|
2185 | { |
2186 | if (o->agt_args == NULL) { Branch (2186:13): [True: 12, False: 3]
|
2187 | /* when aclose() is called we don't want to propagate |
2188 | StopAsyncIteration or GeneratorExit; just raise |
2189 | StopIteration, signalling that this 'aclose()' await |
2190 | is done. |
2191 | */ |
2192 | PyErr_Clear(); |
2193 | PyErr_SetNone(PyExc_StopIteration); |
2194 | } |
2195 | } |
2196 | return NULL; |
2197 | } |
2198 | |
2199 | |
2200 | static PyObject * |
2201 | async_gen_athrow_throw(PyAsyncGenAThrow *o, PyObject *const *args, Py_ssize_t nargs) |
2202 | { |
2203 | PyObject *retval; |
2204 | |
2205 | if (o->agt_state == AWAITABLE_STATE_CLOSED) { Branch (2205:9): [True: 0, False: 9]
|
2206 | PyErr_SetString( |
2207 | PyExc_RuntimeError, |
2208 | "cannot reuse already awaited aclose()/athrow()"); |
2209 | return NULL; |
2210 | } |
2211 | |
2212 | retval = gen_throw((PyGenObject*)o->agt_gen, args, nargs); |
2213 | if (o->agt_args) { Branch (2213:9): [True: 1, False: 8]
|
2214 | return async_gen_unwrap_value(o->agt_gen, retval); |
2215 | } else { |
2216 | /* aclose() mode */ |
2217 | if (retval && _PyAsyncGenWrappedValue_CheckExact0 (retval)) { Branch (2217:13): [True: 0, False: 8]
|
2218 | o->agt_gen->ag_running_async = 0; |
2219 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2220 | Py_DECREF(retval); |
2221 | PyErr_SetString(PyExc_RuntimeError, ASYNC_GEN_IGNORED_EXIT_MSG); |
2222 | return NULL; |
2223 | } |
2224 | if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || Branch (2224:13): [True: 0, False: 8]
|
2225 | PyErr_ExceptionMatches(PyExc_GeneratorExit)) Branch (2225:13): [True: 1, False: 7]
|
2226 | { |
2227 | /* when aclose() is called we don't want to propagate |
2228 | StopAsyncIteration or GeneratorExit; just raise |
2229 | StopIteration, signalling that this 'aclose()' await |
2230 | is done. |
2231 | */ |
2232 | PyErr_Clear(); |
2233 | PyErr_SetNone(PyExc_StopIteration); |
2234 | } |
2235 | return retval; |
2236 | } |
2237 | } |
2238 | |
2239 | |
2240 | static PyObject * |
2241 | async_gen_athrow_iternext(PyAsyncGenAThrow *o) |
2242 | { |
2243 | return async_gen_athrow_send(o, Py_None); |
2244 | } |
2245 | |
2246 | |
2247 | static PyObject * |
2248 | async_gen_athrow_close(PyAsyncGenAThrow *o, PyObject *args) |
2249 | { |
2250 | o->agt_state = AWAITABLE_STATE_CLOSED; |
2251 | Py_RETURN_NONE; |
2252 | } |
2253 | |
2254 | |
2255 | static PyMethodDef async_gen_athrow_methods[] = { |
2256 | {"send", (PyCFunction)async_gen_athrow_send, METH_O, send_doc}, |
2257 | {"throw", _PyCFunction_CAST(async_gen_athrow_throw), |
2258 | METH_FASTCALL, throw_doc}, |
2259 | {"close", (PyCFunction)async_gen_athrow_close, METH_NOARGS, close_doc}, |
2260 | {NULL, NULL} /* Sentinel */ |
2261 | }; |
2262 | |
2263 | |
2264 | static PyAsyncMethods async_gen_athrow_as_async = { |
2265 | PyObject_SelfIter, /* am_await */ |
2266 | 0, /* am_aiter */ |
2267 | 0, /* am_anext */ |
2268 | 0, /* am_send */ |
2269 | }; |
2270 | |
2271 | |
2272 | PyTypeObject _PyAsyncGenAThrow_Type = { |
2273 | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
2274 | "async_generator_athrow", /* tp_name */ |
2275 | sizeof(PyAsyncGenAThrow), /* tp_basicsize */ |
2276 | 0, /* tp_itemsize */ |
2277 | /* methods */ |
2278 | (destructor)async_gen_athrow_dealloc, /* tp_dealloc */ |
2279 | 0, /* tp_vectorcall_offset */ |
2280 | 0, /* tp_getattr */ |
2281 | 0, /* tp_setattr */ |
2282 | &async_gen_athrow_as_async, /* tp_as_async */ |
2283 | 0, /* tp_repr */ |
2284 | 0, /* tp_as_number */ |
2285 | 0, /* tp_as_sequence */ |
2286 | 0, /* tp_as_mapping */ |
2287 | 0, /* tp_hash */ |
2288 | 0, /* tp_call */ |
2289 | 0, /* tp_str */ |
2290 | PyObject_GenericGetAttr, /* tp_getattro */ |
2291 | 0, /* tp_setattro */ |
2292 | 0, /* tp_as_buffer */ |
2293 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ |
2294 | 0, /* tp_doc */ |
2295 | (traverseproc)async_gen_athrow_traverse, /* tp_traverse */ |
2296 | 0, /* tp_clear */ |
2297 | 0, /* tp_richcompare */ |
2298 | 0, /* tp_weaklistoffset */ |
2299 | PyObject_SelfIter, /* tp_iter */ |
2300 | (iternextfunc)async_gen_athrow_iternext, /* tp_iternext */ |
2301 | async_gen_athrow_methods, /* tp_methods */ |
2302 | 0, /* tp_members */ |
2303 | 0, /* tp_getset */ |
2304 | 0, /* tp_base */ |
2305 | 0, /* tp_dict */ |
2306 | 0, /* tp_descr_get */ |
2307 | 0, /* tp_descr_set */ |
2308 | 0, /* tp_dictoffset */ |
2309 | 0, /* tp_init */ |
2310 | 0, /* tp_alloc */ |
2311 | 0, /* tp_new */ |
2312 | }; |
2313 | |
2314 | |
2315 | static PyObject * |
2316 | async_gen_athrow_new(PyAsyncGenObject *gen, PyObject *args) |
2317 | { |
2318 | PyAsyncGenAThrow *o; |
2319 | o = PyObject_GC_New(PyAsyncGenAThrow, &_PyAsyncGenAThrow_Type); |
2320 | if (o == NULL) { Branch (2320:9): [True: 0, False: 54]
|
2321 | return NULL; |
2322 | } |
2323 | o->agt_gen = gen; |
2324 | o->agt_args = args; |
2325 | o->agt_state = AWAITABLE_STATE_INIT; |
2326 | Py_INCREF(gen); |
2327 | Py_XINCREF(args); |
2328 | _PyObject_GC_TRACK((PyObject*)o); |
2329 | return (PyObject*)o; |
2330 | } |