1 // Copyright 2021, Kay Hayen, mailto:kay.hayen@gmail.com
2 //
3 // Part of "Nuitka", an optimizing Python compiler that is compatible and
4 // integrates with CPython, but also works on its own.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 /** Compiled Asyncgen.
19 *
20 * Unlike in CPython, we have one type for just asyncgen, this doesn't do generators
21 * nor coroutines.
22 *
23 * It strives to be full replacement for normal asyncgen.
24 *
25 */
26
27 // This file is included from another C file, help IDEs to still parse it on
28 // its own.
29 #ifdef __IDE_ONLY__
30 #include "nuitka/freelists.h"
31 #include "nuitka/prelude.h"
32 #include <structmember.h>
33 #endif
34
35 // For reporting about reference counts per type.
36 #if _DEBUG_REFCOUNTS
37 int count_active_Nuitka_Asyncgen_Type = 0;
38 int count_allocated_Nuitka_Asyncgen_Type = 0;
39 int count_released_Nuitka_Asyncgen_Type = 0;
40 int count_active_Nuitka_AsyncgenValueWrapper_Type = 0;
41 int count_allocated_Nuitka_AsyncgenValueWrapper_Type = 0;
42 int count_released_Nuitka_AsyncgenValueWrapper_Type = 0;
43 int count_active_Nuitka_AsyncgenAsend_Type = 0;
44 int count_allocated_Nuitka_AsyncgenAsend_Type = 0;
45 int count_released_Nuitka_AsyncgenAsend_Type = 0;
46 int count_active_Nuitka_AsyncgenAthrow_Type = 0;
47 int count_allocated_Nuitka_AsyncgenAthrow_Type = 0;
48 int count_released_Nuitka_AsyncgenAthrow_Type = 0;
49 #endif
50
Nuitka_Asyncgen_get_name(struct Nuitka_AsyncgenObject * asyncgen)51 static PyObject *Nuitka_Asyncgen_get_name(struct Nuitka_AsyncgenObject *asyncgen) {
52 CHECK_OBJECT(asyncgen);
53
54 Py_INCREF(asyncgen->m_name);
55 return asyncgen->m_name;
56 }
57
Nuitka_Asyncgen_set_name(struct Nuitka_AsyncgenObject * asyncgen,PyObject * value)58 static int Nuitka_Asyncgen_set_name(struct Nuitka_AsyncgenObject *asyncgen, PyObject *value) {
59 CHECK_OBJECT(asyncgen);
60 CHECK_OBJECT_X(value);
61
62 // Cannot be deleted, not be non-unicode value.
63 if (unlikely((value == NULL) || !PyUnicode_Check(value))) {
64 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "__name__ must be set to a string object");
65
66 return -1;
67 }
68
69 PyObject *tmp = asyncgen->m_name;
70 Py_INCREF(value);
71 asyncgen->m_name = value;
72 Py_DECREF(tmp);
73
74 return 0;
75 }
76
Nuitka_Asyncgen_get_qualname(struct Nuitka_AsyncgenObject * asyncgen)77 static PyObject *Nuitka_Asyncgen_get_qualname(struct Nuitka_AsyncgenObject *asyncgen) {
78 CHECK_OBJECT(asyncgen);
79
80 Py_INCREF(asyncgen->m_qualname);
81 return asyncgen->m_qualname;
82 }
83
Nuitka_Asyncgen_set_qualname(struct Nuitka_AsyncgenObject * asyncgen,PyObject * value)84 static int Nuitka_Asyncgen_set_qualname(struct Nuitka_AsyncgenObject *asyncgen, PyObject *value) {
85 CHECK_OBJECT(asyncgen);
86 CHECK_OBJECT_X(value);
87
88 // Cannot be deleted, not be non-unicode value.
89 if (unlikely((value == NULL) || !PyUnicode_Check(value))) {
90 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "__qualname__ must be set to a string object");
91
92 return -1;
93 }
94
95 PyObject *tmp = asyncgen->m_qualname;
96 Py_INCREF(value);
97 asyncgen->m_qualname = value;
98 Py_DECREF(tmp);
99
100 return 0;
101 }
102
Nuitka_Asyncgen_get_ag_await(struct Nuitka_AsyncgenObject * asyncgen)103 static PyObject *Nuitka_Asyncgen_get_ag_await(struct Nuitka_AsyncgenObject *asyncgen) {
104 CHECK_OBJECT(asyncgen);
105
106 if (asyncgen->m_yieldfrom) {
107 Py_INCREF(asyncgen->m_yieldfrom);
108 return asyncgen->m_yieldfrom;
109 } else {
110 Py_INCREF(Py_None);
111 return Py_None;
112 }
113 }
114
Nuitka_Asyncgen_get_code(struct Nuitka_AsyncgenObject * asyncgen)115 static PyObject *Nuitka_Asyncgen_get_code(struct Nuitka_AsyncgenObject *asyncgen) {
116 CHECK_OBJECT(asyncgen);
117 CHECK_OBJECT(asyncgen->m_code_object);
118
119 Py_INCREF(asyncgen->m_code_object);
120 return (PyObject *)asyncgen->m_code_object;
121 }
122
Nuitka_Asyncgen_set_code(struct Nuitka_AsyncgenObject * asyncgen,PyObject * value)123 static int Nuitka_Asyncgen_set_code(struct Nuitka_AsyncgenObject *asyncgen, PyObject *value) {
124 CHECK_OBJECT(asyncgen);
125
126 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "ag_code is not writable in Nuitka");
127 return -1;
128 }
129
Nuitka_Asyncgen_get_frame(struct Nuitka_AsyncgenObject * asyncgen)130 static PyObject *Nuitka_Asyncgen_get_frame(struct Nuitka_AsyncgenObject *asyncgen) {
131 CHECK_OBJECT(asyncgen);
132 CHECK_OBJECT_X(asyncgen->m_frame);
133
134 if (asyncgen->m_frame) {
135 Py_INCREF(asyncgen->m_frame);
136 return (PyObject *)asyncgen->m_frame;
137 } else {
138 Py_INCREF(Py_None);
139 return Py_None;
140 }
141 }
142
Nuitka_Asyncgen_set_frame(struct Nuitka_AsyncgenObject * asyncgen,PyObject * value)143 static int Nuitka_Asyncgen_set_frame(struct Nuitka_AsyncgenObject *asyncgen, PyObject *value) {
144 CHECK_OBJECT(asyncgen);
145 CHECK_OBJECT_X(value);
146
147 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "ag_frame is not writable in Nuitka");
148 return -1;
149 }
150
Nuitka_Asyncgen_release_closure(struct Nuitka_AsyncgenObject * asyncgen)151 static void Nuitka_Asyncgen_release_closure(struct Nuitka_AsyncgenObject *asyncgen) {
152 CHECK_OBJECT(asyncgen);
153
154 for (Py_ssize_t i = 0; i < asyncgen->m_closure_given; i++) {
155 CHECK_OBJECT(asyncgen->m_closure[i]);
156 Py_DECREF(asyncgen->m_closure[i]);
157 }
158
159 asyncgen->m_closure_given = 0;
160 }
161
Nuitka_YieldFromAsyncgenCore(struct Nuitka_AsyncgenObject * asyncgen,PyObject * send_value,bool mode)162 static PyObject *Nuitka_YieldFromAsyncgenCore(struct Nuitka_AsyncgenObject *asyncgen, PyObject *send_value, bool mode) {
163 CHECK_OBJECT(asyncgen);
164 CHECK_OBJECT_X(send_value);
165
166 PyObject *yieldfrom = asyncgen->m_yieldfrom;
167 CHECK_OBJECT(yieldfrom);
168
169 // Need to make it unaccessible while using it.
170 asyncgen->m_yieldfrom = NULL;
171
172 PyObject *returned_value;
173 PyObject *yielded = _Nuitka_YieldFromCore(yieldfrom, send_value, &returned_value, mode);
174
175 if (yielded == NULL) {
176 assert(asyncgen->m_yieldfrom == NULL);
177 Py_DECREF(yieldfrom);
178
179 yielded = ((asyncgen_code)asyncgen->m_code)(asyncgen, returned_value);
180 } else {
181 assert(asyncgen->m_yieldfrom == NULL);
182 asyncgen->m_yieldfrom = yieldfrom;
183 }
184
185 return yielded;
186 }
187
188 #if _DEBUG_ASYNCGEN
_PRINT_ASYNCGEN_STATUS(char const * descriptor,char const * context,struct Nuitka_AsyncgenObject * asyncgen)189 NUITKA_MAY_BE_UNUSED static void _PRINT_ASYNCGEN_STATUS(char const *descriptor, char const *context,
190 struct Nuitka_AsyncgenObject *asyncgen) {
191 char const *status;
192
193 switch (asyncgen->m_status) {
194 case status_Finished:
195 status = "(finished)";
196 break;
197 case status_Running:
198 status = "(running)";
199 break;
200 case status_Unused:
201 status = "(unused)";
202 break;
203 default:
204 status = "(ILLEGAL)";
205 break;
206 }
207
208 PRINT_STRING(descriptor);
209 PRINT_STRING(" : ");
210 PRINT_STRING(context);
211 PRINT_STRING(" ");
212 PRINT_ITEM((PyObject *)asyncgen);
213 PRINT_STRING(" ");
214 PRINT_STRING(status);
215 PRINT_NEW_LINE();
216 }
217
218 #define PRINT_ASYNCGEN_STATUS(context, asyncgen) _PRINT_ASYNCGEN_STATUS(__FUNCTION__, context, asyncgen)
219
220 #endif
221
Nuitka_YieldFromAsyncgenNext(struct Nuitka_AsyncgenObject * asyncgen)222 static PyObject *Nuitka_YieldFromAsyncgenNext(struct Nuitka_AsyncgenObject *asyncgen) {
223 CHECK_OBJECT(asyncgen);
224
225 #if _DEBUG_ASYNCGEN
226 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
227 PRINT_NEW_LINE();
228 #endif
229 PyObject *result = Nuitka_YieldFromAsyncgenCore(asyncgen, Py_None, true);
230 #if _DEBUG_ASYNCGEN
231 PRINT_ASYNCGEN_STATUS("Leave", asyncgen);
232 PRINT_CURRENT_EXCEPTION();
233 PRINT_NEW_LINE();
234 #endif
235
236 return result;
237 }
238
Nuitka_YieldFromAsyncgenInitial(struct Nuitka_AsyncgenObject * asyncgen,PyObject * send_value)239 static PyObject *Nuitka_YieldFromAsyncgenInitial(struct Nuitka_AsyncgenObject *asyncgen, PyObject *send_value) {
240 CHECK_OBJECT(asyncgen);
241 CHECK_OBJECT_X(send_value);
242
243 #if _DEBUG_ASYNCGEN
244 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
245 PRINT_NEW_LINE();
246 #endif
247 PyObject *result = Nuitka_YieldFromAsyncgenCore(asyncgen, send_value, false);
248 #if _DEBUG_ASYNCGEN
249 PRINT_ASYNCGEN_STATUS("Leave", asyncgen);
250 PRINT_CURRENT_EXCEPTION();
251 PRINT_NEW_LINE();
252 #endif
253
254 return result;
255 }
256
257 static PyObject *Nuitka_AsyncgenValueWrapper_New(PyObject *value);
258
_Nuitka_Asyncgen_send(struct Nuitka_AsyncgenObject * asyncgen,PyObject * value,bool closing,PyObject * exception_type,PyObject * exception_value,PyTracebackObject * exception_tb)259 static PyObject *_Nuitka_Asyncgen_send(struct Nuitka_AsyncgenObject *asyncgen, PyObject *value, bool closing,
260 PyObject *exception_type, PyObject *exception_value,
261 PyTracebackObject *exception_tb) {
262 CHECK_OBJECT(asyncgen);
263 assert(Nuitka_Asyncgen_Check((PyObject *)asyncgen));
264 CHECK_OBJECT_X(value);
265 CHECK_OBJECT_X(exception_type);
266 CHECK_OBJECT_X(exception_value);
267 CHECK_OBJECT_X(exception_tb);
268
269 #if _DEBUG_ASYNCGEN
270 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
271 PRINT_COROUTINE_VALUE("value", value);
272 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
273 PRINT_CURRENT_EXCEPTION();
274 PRINT_NEW_LINE();
275 #endif
276
277 if (value != NULL) {
278 assert(exception_type == NULL);
279 assert(exception_value == NULL);
280 assert(exception_tb == NULL);
281 }
282
283 if (asyncgen->m_status == status_Unused && value != NULL && value != Py_None) {
284 // No exception if value is given.
285
286 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "can't send non-None value to a just-started async generator");
287 return NULL;
288 }
289
290 if (asyncgen->m_status != status_Finished) {
291 if (asyncgen->m_running) {
292 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_ValueError, "async generator already executing");
293 return NULL;
294 }
295
296 PyThreadState *thread_state = PyThreadState_GET();
297
298 // Put the asyncgen back on the frame stack.
299
300 // First take of running frame from the stack, owning a reference.
301 PyFrameObject *return_frame = thread_state->frame;
302
303 #ifndef __NUITKA_NO_ASSERT__
304 if (return_frame) {
305 assertFrameObject((struct Nuitka_FrameObject *)return_frame);
306 }
307 #endif
308
309 if (asyncgen->m_resume_frame) {
310 // It would be nice if our frame were still alive. Nobody had the
311 // right to release it.
312 assertFrameObject(asyncgen->m_resume_frame);
313
314 // It's not supposed to be on the top right now.
315 assert(return_frame != &asyncgen->m_resume_frame->m_frame);
316
317 thread_state->frame = &asyncgen->m_frame->m_frame;
318 asyncgen->m_resume_frame = NULL;
319 }
320
321 // Consider it as running.
322 if (asyncgen->m_status == status_Unused) {
323 asyncgen->m_status = status_Running;
324 }
325
326 // Continue the yielder function while preventing recursion.
327 asyncgen->m_running = true;
328
329 // Check for thrown exception, and publish it.
330 if (unlikely(exception_type != NULL)) {
331 assert(value == NULL);
332
333 // Transfer exception ownership to published.
334 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
335 }
336
337 if (asyncgen->m_frame) {
338 Nuitka_Frame_MarkAsExecuting(asyncgen->m_frame);
339 }
340
341 #if _DEBUG_ASYNCGEN
342 PRINT_ASYNCGEN_STATUS("Switching to asyncgen", asyncgen);
343 PRINT_COROUTINE_VALUE("value", value);
344 PRINT_CURRENT_EXCEPTION();
345 PRINT_NEW_LINE();
346 // dumpFrameStack();
347 #endif
348
349 PyObject *yielded;
350
351 if (asyncgen->m_yieldfrom == NULL) {
352 yielded = ((asyncgen_code)asyncgen->m_code)(asyncgen, value);
353 } else {
354 yielded = Nuitka_YieldFromAsyncgenInitial(asyncgen, value);
355 }
356
357 // If the asyncgen returns with m_yieldfrom set, it wants us to yield
358 // from that value from now on.
359 while (yielded == NULL && asyncgen->m_yieldfrom != NULL) {
360 yielded = Nuitka_YieldFromAsyncgenNext(asyncgen);
361 }
362
363 if (asyncgen->m_frame) {
364 Nuitka_Frame_MarkAsNotExecuting(asyncgen->m_frame);
365 }
366
367 asyncgen->m_running = false;
368
369 thread_state = PyThreadState_GET();
370
371 // Remove the back frame from asyncgen if it's there.
372 if (asyncgen->m_frame) {
373 // assert(thread_state->frame == &asyncgen->m_frame->m_frame);
374 assertFrameObject(asyncgen->m_frame);
375
376 Py_CLEAR(asyncgen->m_frame->m_frame.f_back);
377
378 // Remember where to resume from.
379 asyncgen->m_resume_frame = (struct Nuitka_FrameObject *)thread_state->frame;
380 }
381
382 thread_state->frame = return_frame;
383
384 #if _DEBUG_ASYNCGEN
385 PRINT_ASYNCGEN_STATUS("Returned from coroutine", asyncgen);
386 // dumpFrameStack();
387 #endif
388
389 #ifndef __NUITKA_NO_ASSERT__
390 if (return_frame) {
391 assertFrameObject((struct Nuitka_FrameObject *)return_frame);
392 }
393 #endif
394
395 if (yielded == NULL) {
396 #if _DEBUG_ASYNCGEN
397 PRINT_ASYNCGEN_STATUS("finishing from yield", asyncgen);
398 PRINT_STRING("-> finishing sets status_Finished\n");
399 PRINT_NEW_LINE();
400 #endif
401 asyncgen->m_status = status_Finished;
402
403 if (asyncgen->m_frame != NULL) {
404 asyncgen->m_frame->m_frame.f_gen = NULL;
405 Py_DECREF(asyncgen->m_frame);
406 asyncgen->m_frame = NULL;
407 }
408
409 Nuitka_Asyncgen_release_closure(asyncgen);
410
411 PyObject *error_occurred = GET_ERROR_OCCURRED();
412
413 if (error_occurred == PyExc_StopIteration || error_occurred == PyExc_StopAsyncIteration) {
414 PyObject *saved_exception_type, *saved_exception_value;
415 PyTracebackObject *saved_exception_tb;
416
417 FETCH_ERROR_OCCURRED(&saved_exception_type, &saved_exception_value, &saved_exception_tb);
418 NORMALIZE_EXCEPTION(&saved_exception_type, &saved_exception_value, &saved_exception_tb);
419
420 if (error_occurred == PyExc_StopIteration) {
421 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "async generator raised StopIteration");
422 } else {
423 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "async generator raised StopAsyncIteration");
424 }
425
426 FETCH_ERROR_OCCURRED(&exception_type, &exception_value, &exception_tb);
427
428 RAISE_EXCEPTION_WITH_CAUSE(&exception_type, &exception_value, &exception_tb, saved_exception_value);
429
430 CHECK_OBJECT(exception_value);
431 CHECK_OBJECT(saved_exception_value);
432
433 Py_INCREF(saved_exception_value);
434 PyException_SetContext(exception_value, saved_exception_value);
435
436 Py_DECREF(saved_exception_type);
437 Py_XDECREF(saved_exception_tb);
438
439 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
440 }
441
442 return NULL;
443 } else {
444 // For normal yield, wrap the result value before returning.
445 if (asyncgen->m_yieldfrom == NULL) {
446 // TODO: Why not transfer ownership to constructor.
447 PyObject *wrapped = Nuitka_AsyncgenValueWrapper_New(yielded);
448 yielded = wrapped;
449
450 assert(yielded != NULL);
451 }
452
453 return yielded;
454 }
455 } else {
456 // Release exception if any, we are finished with it and will raise another.
457 Py_XDECREF(exception_type);
458 Py_XDECREF(exception_value);
459 Py_XDECREF(exception_tb);
460
461 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopAsyncIteration);
462
463 return NULL;
464 }
465 }
466
467 // Note: Used by compiled frames.
_Nuitka_Asyncgen_close(struct Nuitka_AsyncgenObject * asyncgen)468 static bool _Nuitka_Asyncgen_close(struct Nuitka_AsyncgenObject *asyncgen) {
469 #if _DEBUG_ASYNCGEN
470 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
471 #endif
472 CHECK_OBJECT(asyncgen);
473
474 if (asyncgen->m_status == status_Running) {
475 Py_INCREF(PyExc_GeneratorExit);
476
477 PyObject *result = _Nuitka_Asyncgen_send(asyncgen, NULL, true, PyExc_GeneratorExit, NULL, NULL);
478
479 if (unlikely(result)) {
480 Py_DECREF(result);
481
482 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "async generator ignored GeneratorExit");
483 return false;
484 } else {
485 PyObject *error = GET_ERROR_OCCURRED();
486 assert(error != NULL);
487
488 if (EXCEPTION_MATCH_GENERATOR(error)) {
489 CLEAR_ERROR_OCCURRED();
490
491 return true;
492 }
493
494 return false;
495 }
496 }
497
498 return true;
499 }
500
501 static bool _Nuitka_Generator_check_throw2(PyObject **exception_type, PyObject **exception_value,
502 PyTracebackObject **exception_tb);
503
504 // This function is called when yielding to a asyncgen through "_Nuitka_YieldFromPassExceptionTo"
505 // and potentially wrapper objects used by generators, or by the throw method itself.
506 // Note:
507 // Exception arguments are passed for ownership and must be released before returning. The
508 // value of exception_type will not be NULL, but the actual exception will not necessarily
509 // be normalized.
_Nuitka_Asyncgen_throw2(struct Nuitka_AsyncgenObject * asyncgen,bool close_on_genexit,PyObject * exception_type,PyObject * exception_value,PyTracebackObject * exception_tb)510 static PyObject *_Nuitka_Asyncgen_throw2(struct Nuitka_AsyncgenObject *asyncgen, bool close_on_genexit,
511 PyObject *exception_type, PyObject *exception_value,
512 PyTracebackObject *exception_tb) {
513 CHECK_OBJECT(asyncgen);
514 assert(Nuitka_Asyncgen_Check((PyObject *)asyncgen));
515 CHECK_OBJECT(exception_type);
516 CHECK_OBJECT_X(exception_value);
517 CHECK_OBJECT_X(exception_tb);
518
519 #if _DEBUG_ASYNCGEN
520 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
521 PRINT_COROUTINE_VALUE("yieldfrom", asyncgen->m_yieldfrom);
522 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
523 PRINT_NEW_LINE();
524 #endif
525
526 if (asyncgen->m_yieldfrom != NULL) {
527 // TODO: This check is not done for coroutines, correct?
528 if (close_on_genexit) {
529 if (EXCEPTION_MATCH_BOOL_SINGLE(exception_type, PyExc_GeneratorExit)) {
530 // Asynchronous generators need to close the yield_from.
531 asyncgen->m_running = 1;
532 bool res = Nuitka_gen_close_iter(asyncgen->m_yieldfrom);
533 asyncgen->m_running = 0;
534
535 if (res == false) {
536 // Release exception, we are done with it now and pick up the new one.
537 Py_DECREF(exception_type);
538 Py_XDECREF(exception_value);
539 Py_XDECREF(exception_tb);
540
541 FETCH_ERROR_OCCURRED(&exception_type, &exception_value, &exception_tb);
542 }
543
544 return _Nuitka_Asyncgen_send(asyncgen, NULL, false, exception_type, exception_value, exception_tb);
545 }
546 }
547
548 PyObject *ret;
549
550 #if _DEBUG_ASYNCGEN
551 PRINT_ASYNCGEN_STATUS("Passing to yielded from", asyncgen);
552 PRINT_COROUTINE_VALUE("m_yieldfrom", asyncgen->m_yieldfrom);
553 PRINT_NEW_LINE();
554 #endif
555
556 if (PyGen_CheckExact(asyncgen->m_yieldfrom) || PyCoro_CheckExact(asyncgen->m_yieldfrom)) {
557 PyGenObject *gen = (PyGenObject *)asyncgen->m_yieldfrom;
558
559 // Transferred exception ownership to "Nuitka_UncompiledGenerator_throw".
560 asyncgen->m_running = 1;
561 ret = Nuitka_UncompiledGenerator_throw(gen, 1, exception_type, exception_value, exception_tb);
562 asyncgen->m_running = 0;
563 } else if (Nuitka_Generator_Check(asyncgen->m_yieldfrom)) {
564 struct Nuitka_GeneratorObject *gen = ((struct Nuitka_GeneratorObject *)asyncgen->m_yieldfrom);
565 // Transferred exception ownership to "_Nuitka_Generator_throw2".
566 asyncgen->m_running = 1;
567 ret = _Nuitka_Generator_throw2(gen, exception_type, exception_value, exception_tb);
568 asyncgen->m_running = 0;
569 } else if (Nuitka_Coroutine_Check(asyncgen->m_yieldfrom)) {
570 struct Nuitka_CoroutineObject *coro = ((struct Nuitka_CoroutineObject *)asyncgen->m_yieldfrom);
571 // Transferred exception ownership to "_Nuitka_Coroutine_throw2".
572 asyncgen->m_running = 1;
573 ret = _Nuitka_Coroutine_throw2(coro, true, exception_type, exception_value, exception_tb);
574 asyncgen->m_running = 0;
575 } else if (Nuitka_CoroutineWrapper_Check(asyncgen->m_yieldfrom)) {
576 struct Nuitka_CoroutineObject *coro =
577 ((struct Nuitka_CoroutineWrapperObject *)asyncgen->m_yieldfrom)->m_coroutine;
578
579 // Transferred exception ownership to "_Nuitka_Coroutine_throw2".
580 asyncgen->m_running = 1;
581 ret = _Nuitka_Coroutine_throw2(coro, true, exception_type, exception_value, exception_tb);
582 asyncgen->m_running = 0;
583 } else if (Nuitka_AsyncgenAsend_Check(asyncgen->m_yieldfrom)) {
584 struct Nuitka_AsyncgenAsendObject *asyncgen_asend =
585 ((struct Nuitka_AsyncgenAsendObject *)asyncgen->m_yieldfrom);
586
587 // Transferred exception ownership to "_Nuitka_AsyncgenAsend_throw2".
588 asyncgen->m_running = 1;
589 ret = _Nuitka_AsyncgenAsend_throw2(asyncgen_asend, exception_type, exception_value, exception_tb);
590 asyncgen->m_running = 0;
591 } else {
592 PyObject *meth = PyObject_GetAttr(asyncgen->m_yieldfrom, const_str_plain_throw);
593 if (unlikely(meth == NULL)) {
594 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
595 // Release exception, we are done with it now.
596 Py_DECREF(exception_type);
597 Py_XDECREF(exception_value);
598 Py_XDECREF(exception_tb);
599
600 return NULL;
601 }
602
603 CLEAR_ERROR_OCCURRED();
604
605 // Passing exception ownership to that code.
606 goto throw_here;
607 }
608
609 CHECK_OBJECT(exception_type);
610
611 #if 0
612 // TODO: Add slow mode traces.
613 PRINT_ITEM(coroutine->m_yieldfrom);
614 PRINT_NEW_LINE();
615 #endif
616
617 asyncgen->m_running = 1;
618 ret = PyObject_CallFunctionObjArgs(meth, exception_type, exception_value, exception_tb, NULL);
619 asyncgen->m_running = 0;
620
621 Py_DECREF(meth);
622
623 // Release exception, we are done with it now.
624 Py_DECREF(exception_type);
625 Py_XDECREF(exception_value);
626 Py_XDECREF(exception_tb);
627 }
628
629 if (unlikely(ret == NULL)) {
630 PyObject *val;
631
632 if (_PyGen_FetchStopIterationValue(&val) == 0) {
633 CHECK_OBJECT(val);
634
635 asyncgen->m_yieldfrom = NULL;
636
637 // Return value, not to continue with yielding from.
638 if (asyncgen->m_yieldfrom != NULL) {
639 CHECK_OBJECT(asyncgen->m_yieldfrom);
640 #if _DEBUG_ASYNCGEN
641 PRINT_ASYNCGEN_STATUS("Yield from removal:", asyncgen);
642 PRINT_COROUTINE_VALUE("yieldfrom", asyncgen->m_yieldfrom);
643 #endif
644 Py_DECREF(asyncgen->m_yieldfrom);
645 asyncgen->m_yieldfrom = NULL;
646 }
647
648 #if _DEBUG_ASYNCGEN
649 PRINT_ASYNCGEN_STATUS("Sending return value into ourselves", asyncgen);
650 PRINT_COROUTINE_VALUE("value", val);
651 PRINT_NEW_LINE();
652 #endif
653
654 ret = _Nuitka_Asyncgen_send(asyncgen, val, false, NULL, NULL, NULL);
655 } else {
656 #if _DEBUG_ASYNCGEN
657 PRINT_ASYNCGEN_STATUS("Sending exception value into ourselves", asyncgen);
658 PRINT_COROUTINE_VALUE("yieldfrom", asyncgen->m_yieldfrom);
659 PRINT_CURRENT_EXCEPTION();
660 PRINT_NEW_LINE();
661 #endif
662 ret = _Nuitka_Asyncgen_send(asyncgen, NULL, false, NULL, NULL, NULL);
663 }
664
665 #if _DEBUG_ASYNCGEN
666 PRINT_ASYNCGEN_STATUS("Leave with value/exception from sending into ourselves:", asyncgen);
667 PRINT_COROUTINE_VALUE("return_value", ret);
668 PRINT_CURRENT_EXCEPTION();
669 PRINT_NEW_LINE();
670 #endif
671 } else {
672 #if _DEBUG_ASYNCGEN
673 PRINT_ASYNCGEN_STATUS("Leave with return value:", asyncgen);
674 PRINT_COROUTINE_VALUE("return_value", ret);
675 PRINT_CURRENT_EXCEPTION();
676 PRINT_NEW_LINE();
677 #endif
678 }
679
680 return ret;
681 }
682
683 throw_here:
684 // We continue to have exception ownership here.
685
686 if (unlikely(_Nuitka_Generator_check_throw2(&exception_type, &exception_value, &exception_tb) == false)) {
687 // Exception was released by _Nuitka_Generator_check_throw2 already.
688 return NULL;
689 }
690
691 if (asyncgen->m_status == status_Running) {
692 PyObject *result = _Nuitka_Asyncgen_send(asyncgen, NULL, false, exception_type, exception_value, exception_tb);
693 return result;
694 } else if (asyncgen->m_status == status_Finished) {
695 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
696 return NULL;
697 } else {
698 if (exception_tb == NULL) {
699 // TODO: Our compiled objects really need a way to store common
700 // stuff in a "shared" part across all instances, and outside of
701 // run time, so we could reuse this.
702 struct Nuitka_FrameObject *frame = MAKE_FUNCTION_FRAME(asyncgen->m_code_object, asyncgen->m_module, 0);
703 exception_tb = MAKE_TRACEBACK(frame, asyncgen->m_code_object->co_firstlineno);
704 Py_DECREF(frame);
705 }
706
707 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
708
709 #if _DEBUG_ASYNCGEN
710 PRINT_ASYNCGEN_STATUS("Finishing from exception", asyncgen);
711 PRINT_NEW_LINE();
712 #endif
713
714 asyncgen->m_status = status_Finished;
715
716 return NULL;
717 }
718 }
719
Nuitka_Asyncgen_throw(struct Nuitka_AsyncgenObject * asyncgen,PyObject * args)720 static PyObject *Nuitka_Asyncgen_throw(struct Nuitka_AsyncgenObject *asyncgen, PyObject *args) {
721 CHECK_OBJECT(asyncgen);
722 CHECK_OBJECT_DEEP(args);
723
724 PyObject *exception_type;
725 PyObject *exception_value = NULL;
726 PyTracebackObject *exception_tb = NULL;
727
728 // This takes no references, that is for us to do.
729 int res = PyArg_UnpackTuple(args, "throw", 1, 3, &exception_type, &exception_value, &exception_tb);
730
731 if (unlikely(res == 0)) {
732 return NULL;
733 }
734
735 #if _DEBUG_ASYNCGEN
736 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
737 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
738 PRINT_NEW_LINE();
739 #endif
740
741 // Handing ownership of exception over, we need not release it ourselves
742 Py_INCREF(exception_type);
743 Py_XINCREF(exception_value);
744 Py_XINCREF(exception_tb);
745
746 PyObject *result = _Nuitka_Asyncgen_throw2(asyncgen, false, exception_type, exception_value, exception_tb);
747
748 if (result == NULL) {
749 if (GET_ERROR_OCCURRED() == NULL) {
750 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
751 }
752 }
753
754 #if _DEBUG_ASYNCGEN
755 PRINT_ASYNCGEN_STATUS("Leave", asyncgen);
756 PRINT_COROUTINE_VALUE("return value", result);
757 PRINT_CURRENT_EXCEPTION();
758 #endif
759
760 CHECK_OBJECT(exception_type);
761 CHECK_OBJECT_X(exception_value);
762 CHECK_OBJECT_X(exception_tb);
763
764 return result;
765 }
766
Nuitka_Asyncgen_init_hooks(struct Nuitka_AsyncgenObject * asyncgen)767 static int Nuitka_Asyncgen_init_hooks(struct Nuitka_AsyncgenObject *asyncgen) {
768 /* Just do this once per async generator object. */
769 if (asyncgen->m_hooks_init_done) {
770 return 0;
771 }
772 asyncgen->m_hooks_init_done = 1;
773
774 PyThreadState *tstate = PyThreadState_GET();
775
776 /* Attach the finalizer if any. */
777 PyObject *finalizer = tstate->async_gen_finalizer;
778 if (finalizer != NULL) {
779 Py_INCREF(finalizer);
780 asyncgen->m_finalizer = finalizer;
781 }
782
783 /* Call the "firstiter" hook for async generator. */
784 PyObject *firstiter = tstate->async_gen_firstiter;
785 if (firstiter != NULL) {
786 Py_INCREF(firstiter);
787
788 PyObject *res = CALL_FUNCTION_WITH_SINGLE_ARG(firstiter, (PyObject *)asyncgen);
789
790 Py_DECREF(firstiter);
791
792 if (unlikely(res == NULL)) {
793 return 1;
794 }
795
796 Py_DECREF(res);
797 }
798
799 return 0;
800 }
801
802 static PyObject *Nuitka_AsyncgenAsend_New(struct Nuitka_AsyncgenObject *asyncgen, PyObject *sendval);
803 static PyObject *Nuitka_AsyncgenAthrow_New(struct Nuitka_AsyncgenObject *asyncgen, PyObject *args);
804
Nuitka_Asyncgen_anext(struct Nuitka_AsyncgenObject * asyncgen)805 static PyObject *Nuitka_Asyncgen_anext(struct Nuitka_AsyncgenObject *asyncgen) {
806 CHECK_OBJECT(asyncgen);
807
808 if (Nuitka_Asyncgen_init_hooks(asyncgen)) {
809 return NULL;
810 }
811
812 #if _DEBUG_ASYNCGEN
813 PRINT_ASYNCGEN_STATUS("Enter", asyncgen);
814 PRINT_NEW_LINE();
815 #endif
816
817 PyObject *result = Nuitka_AsyncgenAsend_New(asyncgen, Py_None);
818
819 #if _DEBUG_ASYNCGEN
820 PRINT_ASYNCGEN_STATUS("Leave", asyncgen);
821 PRINT_COROUTINE_VALUE("result", result);
822 PRINT_NEW_LINE();
823 #endif
824
825 return result;
826 }
827
Nuitka_Asyncgen_asend(struct Nuitka_AsyncgenObject * asyncgen,PyObject * value)828 static PyObject *Nuitka_Asyncgen_asend(struct Nuitka_AsyncgenObject *asyncgen, PyObject *value) {
829 CHECK_OBJECT(asyncgen);
830
831 if (Nuitka_Asyncgen_init_hooks(asyncgen)) {
832 return NULL;
833 }
834
835 return Nuitka_AsyncgenAsend_New(asyncgen, value);
836 }
837
Nuitka_Asyncgen_aclose(struct Nuitka_AsyncgenObject * asyncgen)838 static PyObject *Nuitka_Asyncgen_aclose(struct Nuitka_AsyncgenObject *asyncgen) {
839 CHECK_OBJECT(asyncgen);
840
841 if (Nuitka_Asyncgen_init_hooks(asyncgen)) {
842 return NULL;
843 }
844
845 return Nuitka_AsyncgenAthrow_New(asyncgen, NULL);
846 }
847
Nuitka_Asyncgen_athrow(struct Nuitka_AsyncgenObject * asyncgen,PyObject * args)848 static PyObject *Nuitka_Asyncgen_athrow(struct Nuitka_AsyncgenObject *asyncgen, PyObject *args) {
849 CHECK_OBJECT(asyncgen);
850
851 if (Nuitka_Asyncgen_init_hooks(asyncgen)) {
852 return NULL;
853 }
854
855 return Nuitka_AsyncgenAthrow_New(asyncgen, args);
856 }
857
Nuitka_Asyncgen_tp_finalize(struct Nuitka_AsyncgenObject * asyncgen)858 static void Nuitka_Asyncgen_tp_finalize(struct Nuitka_AsyncgenObject *asyncgen) {
859 if (asyncgen->m_status != status_Running) {
860 return;
861 }
862
863 PyObject *save_exception_type, *save_exception_value;
864 PyTracebackObject *save_exception_tb;
865 FETCH_ERROR_OCCURRED(&save_exception_type, &save_exception_value, &save_exception_tb);
866
867 bool close_result = _Nuitka_Asyncgen_close(asyncgen);
868
869 if (unlikely(close_result == false)) {
870 PyErr_WriteUnraisable((PyObject *)asyncgen);
871 }
872
873 /* Restore the saved exception if any. */
874 RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
875 }
876
877 #define MAX_ASYNCGEN_FREE_LIST_COUNT 100
878 static struct Nuitka_AsyncgenObject *free_list_asyncgens = NULL;
879 static int free_list_asyncgens_count = 0;
880
881 // TODO: This might have to be finalize actually.
Nuitka_Asyncgen_tp_dealloc(struct Nuitka_AsyncgenObject * asyncgen)882 static void Nuitka_Asyncgen_tp_dealloc(struct Nuitka_AsyncgenObject *asyncgen) {
883 #if _DEBUG_REFCOUNTS
884 count_active_Nuitka_Asyncgen_Type -= 1;
885 count_released_Nuitka_Asyncgen_Type += 1;
886 #endif
887
888 // Revive temporarily.
889 assert(Py_REFCNT(asyncgen) == 0);
890 Py_REFCNT(asyncgen) = 1;
891
892 // Save the current exception, if any, we must preserve it.
893 PyObject *save_exception_type, *save_exception_value;
894 PyTracebackObject *save_exception_tb;
895
896 PyObject *finalizer = asyncgen->m_finalizer;
897 if (finalizer != NULL && asyncgen->m_closed == false) {
898 /* Save the current exception, if any. */
899 FETCH_ERROR_OCCURRED(&save_exception_type, &save_exception_value, &save_exception_tb);
900
901 PyObject *res = CALL_FUNCTION_WITH_SINGLE_ARG(finalizer, (PyObject *)asyncgen);
902
903 if (unlikely(res == NULL)) {
904 PyErr_WriteUnraisable((PyObject *)asyncgen);
905 } else {
906 Py_DECREF(res);
907 }
908
909 RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
910 return;
911 }
912
913 FETCH_ERROR_OCCURRED(&save_exception_type, &save_exception_value, &save_exception_tb);
914
915 bool close_result = _Nuitka_Asyncgen_close(asyncgen);
916
917 if (unlikely(close_result == false)) {
918 PyErr_WriteUnraisable((PyObject *)asyncgen);
919 }
920
921 Nuitka_Asyncgen_release_closure(asyncgen);
922
923 // Allow for above code to resurrect the coroutine.
924 Py_REFCNT(asyncgen) -= 1;
925 if (Py_REFCNT(asyncgen) >= 1) {
926 return;
927 }
928
929 if (asyncgen->m_frame) {
930 asyncgen->m_frame->m_frame.f_gen = NULL;
931 Py_DECREF(asyncgen->m_frame);
932 asyncgen->m_frame = NULL;
933 }
934
935 // Now it is safe to release references and memory for it.
936 Nuitka_GC_UnTrack(asyncgen);
937
938 Py_XDECREF(asyncgen->m_finalizer);
939
940 if (asyncgen->m_weakrefs != NULL) {
941 PyObject_ClearWeakRefs((PyObject *)asyncgen);
942 assert(!ERROR_OCCURRED());
943 }
944
945 Py_DECREF(asyncgen->m_name);
946 Py_DECREF(asyncgen->m_qualname);
947
948 /* Put the object into freelist or release to GC */
949 releaseToFreeList(free_list_asyncgens, asyncgen, MAX_ASYNCGEN_FREE_LIST_COUNT);
950
951 RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
952 }
953
Nuitka_Asyncgen_tp_repr(struct Nuitka_AsyncgenObject * asyncgen)954 static PyObject *Nuitka_Asyncgen_tp_repr(struct Nuitka_AsyncgenObject *asyncgen) {
955 CHECK_OBJECT(asyncgen);
956
957 return PyUnicode_FromFormat("<compiled_async_generator object %s at %p>",
958 Nuitka_String_AsString(asyncgen->m_qualname), asyncgen);
959 }
960
Nuitka_Asyncgen_tp_traverse(struct Nuitka_AsyncgenObject * asyncgen,visitproc visit,void * arg)961 static int Nuitka_Asyncgen_tp_traverse(struct Nuitka_AsyncgenObject *asyncgen, visitproc visit, void *arg) {
962 CHECK_OBJECT(asyncgen);
963
964 Py_VISIT(asyncgen->m_yieldfrom);
965
966 for (Py_ssize_t i = 0; i < asyncgen->m_closure_given; i++) {
967 Py_VISIT(asyncgen->m_closure[i]);
968 }
969
970 Py_VISIT(asyncgen->m_finalizer);
971
972 return 0;
973 }
974
975 // TODO: Set "__doc__" automatically for method clones of compiled types from
976 // the documentation of built-in original type.
977 static PyMethodDef Nuitka_Asyncgen_methods[] = {{"asend", (PyCFunction)Nuitka_Asyncgen_asend, METH_O, NULL},
978 {"athrow", (PyCFunction)Nuitka_Asyncgen_athrow, METH_VARARGS, NULL},
979 {"aclose", (PyCFunction)Nuitka_Asyncgen_aclose, METH_NOARGS, NULL},
980 {NULL}};
981
982 static PyAsyncMethods Nuitka_Asyncgen_as_async = {
983 0, /* am_await */
984 PyObject_SelfIter, /* am_aiter */
985 (unaryfunc)Nuitka_Asyncgen_anext /* am_anext */
986 };
987
988 // TODO: Set "__doc__" automatically for method clones of compiled types from
989 // the documentation of built-in original type.
990 static PyGetSetDef Nuitka_Asyncgen_getsetlist[] = {
991 {(char *)"__name__", (getter)Nuitka_Asyncgen_get_name, (setter)Nuitka_Asyncgen_set_name, NULL},
992 {(char *)"__qualname__", (getter)Nuitka_Asyncgen_get_qualname, (setter)Nuitka_Asyncgen_set_qualname, NULL},
993 {(char *)"ag_await", (getter)Nuitka_Asyncgen_get_ag_await, (setter)NULL, NULL},
994 {(char *)"ag_code", (getter)Nuitka_Asyncgen_get_code, (setter)Nuitka_Asyncgen_set_code, NULL},
995 {(char *)"ag_frame", (getter)Nuitka_Asyncgen_get_frame, (setter)Nuitka_Asyncgen_set_frame, NULL},
996
997 {NULL}};
998
999 static PyMemberDef Nuitka_Asyncgen_members[] = {
1000 {(char *)"ag_running", T_BOOL, offsetof(struct Nuitka_AsyncgenObject, m_running), READONLY},
1001 #if PYTHON_VERSION >= 0x380
1002 {(char *)"ag_running", T_BOOL, offsetof(struct Nuitka_AsyncgenObject, m_running_async), READONLY},
1003 #endif
1004 {NULL}};
1005
1006 PyTypeObject Nuitka_Asyncgen_Type = {
1007 PyVarObject_HEAD_INIT(NULL, 0) "compiled_async_generator", /* tp_name */
1008 sizeof(struct Nuitka_AsyncgenObject), /* tp_basicsize */
1009 sizeof(struct Nuitka_CellObject *), /* tp_itemsize */
1010 (destructor)Nuitka_Asyncgen_tp_dealloc, /* tp_dealloc */
1011 0, /* tp_print */
1012 0, /* tp_getattr */
1013 0, /* tp_setattr */
1014 &Nuitka_Asyncgen_as_async, /* tp_as_async */
1015 (reprfunc)Nuitka_Asyncgen_tp_repr, /* tp_repr */
1016 0, /* tp_as_number */
1017 0, /* tp_as_sequence */
1018 0, /* tp_as_mapping */
1019 0, /* tp_hash */
1020 0, /* tp_call */
1021 0, /* tp_str */
1022 PyObject_GenericGetAttr, /* tp_getattro */
1023 0, /* tp_setattro */
1024 0, /* tp_as_buffer */
1025 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
1026 0, /* tp_doc */
1027 (traverseproc)Nuitka_Asyncgen_tp_traverse, /* tp_traverse */
1028 0, /* tp_clear */
1029 0, /* tp_richcompare */
1030 offsetof(struct Nuitka_AsyncgenObject, m_weakrefs), /* tp_weaklistoffset */
1031 0, /* tp_iter */
1032 0, /* tp_iternext */
1033 Nuitka_Asyncgen_methods, /* tp_methods */
1034 Nuitka_Asyncgen_members, /* tp_members */
1035 Nuitka_Asyncgen_getsetlist, /* tp_getset */
1036 0, /* tp_base */
1037 0, /* tp_dict */
1038 0, /* tp_descr_get */
1039 0, /* tp_descr_set */
1040 0, /* tp_dictoffset */
1041 0, /* tp_init */
1042 0, /* tp_alloc */
1043 0, /* tp_new */
1044 0, /* tp_free */
1045 };
1046
Nuitka_Asyncgen_New(asyncgen_code code,PyObject * module,PyObject * name,PyObject * qualname,PyCodeObject * code_object,struct Nuitka_CellObject ** closure,Py_ssize_t closure_given,Py_ssize_t heap_storage_size)1047 PyObject *Nuitka_Asyncgen_New(asyncgen_code code, PyObject *module, PyObject *name, PyObject *qualname,
1048 PyCodeObject *code_object, struct Nuitka_CellObject **closure, Py_ssize_t closure_given,
1049 Py_ssize_t heap_storage_size) {
1050 #if _DEBUG_REFCOUNTS
1051 count_active_Nuitka_Asyncgen_Type += 1;
1052 count_allocated_Nuitka_Asyncgen_Type += 1;
1053 #endif
1054
1055 struct Nuitka_AsyncgenObject *result;
1056
1057 // TODO: Change the var part of the type to 1 maybe
1058 Py_ssize_t full_size = closure_given + (heap_storage_size + sizeof(void *) - 1) / sizeof(void *);
1059
1060 // Macro to assign result memory from GC or free list.
1061 allocateFromFreeList(free_list_asyncgens, struct Nuitka_AsyncgenObject, Nuitka_Asyncgen_Type, full_size);
1062
1063 // For quicker access of generator heap.
1064 result->m_heap_storage = &result->m_closure[closure_given];
1065
1066 result->m_code = (void *)code;
1067
1068 CHECK_OBJECT(module);
1069 result->m_module = module;
1070
1071 CHECK_OBJECT(name);
1072 result->m_name = name;
1073 Py_INCREF(name);
1074
1075 // The "qualname" defaults to NULL for most compact C code.
1076 if (qualname == NULL) {
1077 qualname = name;
1078 }
1079 CHECK_OBJECT(qualname);
1080
1081 result->m_qualname = qualname;
1082 Py_INCREF(qualname);
1083
1084 result->m_yieldfrom = NULL;
1085
1086 memcpy(&result->m_closure[0], closure, closure_given * sizeof(struct Nuitka_CellObject *));
1087 result->m_closure_given = closure_given;
1088
1089 result->m_weakrefs = NULL;
1090
1091 result->m_status = status_Unused;
1092 result->m_running = false;
1093 result->m_awaiting = false;
1094 #if PYTHON_VERSION >= 0x380
1095 result->m_running_async = false;
1096 #endif
1097
1098 result->m_yield_return_index = 0;
1099
1100 result->m_frame = NULL;
1101 result->m_code_object = code_object;
1102
1103 result->m_resume_frame = NULL;
1104
1105 result->m_finalizer = NULL;
1106 result->m_hooks_init_done = false;
1107 result->m_closed = false;
1108
1109 #if PYTHON_VERSION >= 0x370
1110 result->m_exc_state.exc_type = NULL;
1111 result->m_exc_state.exc_value = NULL;
1112 result->m_exc_state.exc_traceback = NULL;
1113 #endif
1114
1115 Nuitka_GC_Track(result);
1116 return (PyObject *)result;
1117 }
1118
1119 struct Nuitka_AsyncgenWrappedValueObject {
1120 /* Python object folklore: */
1121 PyObject_HEAD;
1122
1123 PyObject *m_value;
1124 };
1125
1126 static struct Nuitka_AsyncgenWrappedValueObject *free_list_asyncgen_value_wrappers = NULL;
1127 static int free_list_asyncgen_value_wrappers_count = 0;
1128
Nuitka_AsyncgenValueWrapper_tp_dealloc(struct Nuitka_AsyncgenWrappedValueObject * asyncgen_value_wrapper)1129 static void Nuitka_AsyncgenValueWrapper_tp_dealloc(struct Nuitka_AsyncgenWrappedValueObject *asyncgen_value_wrapper) {
1130 #if _DEBUG_REFCOUNTS
1131 count_active_Nuitka_AsyncgenValueWrapper_Type -= 1;
1132 count_released_Nuitka_AsyncgenValueWrapper_Type += 1;
1133 #endif
1134
1135 Nuitka_GC_UnTrack((PyObject *)asyncgen_value_wrapper);
1136
1137 CHECK_OBJECT(asyncgen_value_wrapper->m_value);
1138 Py_DECREF(asyncgen_value_wrapper->m_value);
1139
1140 /* Put the object into freelist or release to GC */
1141 releaseToFreeList(free_list_asyncgen_value_wrappers, asyncgen_value_wrapper, MAX_ASYNCGEN_FREE_LIST_COUNT);
1142 }
1143
Nuitka_AsyncgenValueWrapper_tp_traverse(struct Nuitka_AsyncgenWrappedValueObject * asyncgen_value_wrapper,visitproc visit,void * arg)1144 static int Nuitka_AsyncgenValueWrapper_tp_traverse(struct Nuitka_AsyncgenWrappedValueObject *asyncgen_value_wrapper,
1145 visitproc visit, void *arg) {
1146 CHECK_OBJECT(asyncgen_value_wrapper);
1147
1148 Py_VISIT(asyncgen_value_wrapper->m_value);
1149
1150 return 0;
1151 }
1152
1153 static PyTypeObject Nuitka_AsyncgenValueWrapper_Type = {
1154 PyVarObject_HEAD_INIT(NULL, 0) "compiled_async_generator_wrapped_value", /* tp_name */
1155 sizeof(struct Nuitka_AsyncgenWrappedValueObject), /* tp_basicsize */
1156 0, /* tp_itemsize */
1157 (destructor)Nuitka_AsyncgenValueWrapper_tp_dealloc, /* tp_dealloc */
1158 0, /* tp_print */
1159 0, /* tp_getattr */
1160 0, /* tp_setattr */
1161 0, /* tp_as_async */
1162 0, /* tp_repr */
1163 0, /* tp_as_number */
1164 0, /* tp_as_sequence */
1165 0, /* tp_as_mapping */
1166 0, /* tp_hash */
1167 0, /* tp_call */
1168 0, /* tp_str */
1169 PyObject_GenericGetAttr, /* tp_getattro */
1170 0, /* tp_setattro */
1171 0, /* tp_as_buffer */
1172 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1173 0, /* tp_doc */
1174 (traverseproc)Nuitka_AsyncgenValueWrapper_tp_traverse, /* tp_traverse */
1175 0, /* tp_clear */
1176 0, /* tp_richcompare */
1177 0, /* tp_weaklistoffset */
1178 0, /* tp_iter */
1179 0, /* tp_iternext */
1180 0, /* tp_methods */
1181 0, /* tp_members */
1182 0, /* tp_getset */
1183 0, /* tp_base */
1184 0, /* tp_dict */
1185 0, /* tp_descr_get */
1186 0, /* tp_descr_set */
1187 0, /* tp_dictoffset */
1188 0, /* tp_init */
1189 0, /* tp_alloc */
1190 0, /* tp_new */
1191 };
1192
1193 // Note: This expects a reference given in value, because that is the
1194 // only way we use it.
Nuitka_AsyncgenValueWrapper_New(PyObject * value)1195 static PyObject *Nuitka_AsyncgenValueWrapper_New(PyObject *value) {
1196 CHECK_OBJECT(value);
1197
1198 #if _DEBUG_REFCOUNTS
1199 count_active_Nuitka_AsyncgenValueWrapper_Type -= 1;
1200 count_released_Nuitka_AsyncgenValueWrapper_Type += 1;
1201 #endif
1202
1203 struct Nuitka_AsyncgenWrappedValueObject *result;
1204
1205 allocateFromFreeListFixed(free_list_asyncgen_value_wrappers, struct Nuitka_AsyncgenWrappedValueObject,
1206 Nuitka_AsyncgenValueWrapper_Type);
1207
1208 result->m_value = value;
1209
1210 Nuitka_GC_Track(result);
1211
1212 return (PyObject *)result;
1213 }
1214
1215 #define Nuitka_AsyncgenWrappedValue_CheckExact(o) (Py_TYPE(o) == &Nuitka_AsyncgenValueWrapper_Type)
1216
1217 typedef enum {
1218 AWAITABLE_STATE_INIT = 0, /* Has not yet been iterated. */
1219 AWAITABLE_STATE_ITER = 1, /* Being iterated currently. */
1220 AWAITABLE_STATE_CLOSED = 2, /* Closed, no more. */
1221 } AwaitableState;
1222
1223 struct Nuitka_AsyncgenAsendObject {
1224 /* Python object folklore: */
1225 PyObject_HEAD;
1226
1227 struct Nuitka_AsyncgenObject *m_gen;
1228 PyObject *m_sendval;
1229
1230 AwaitableState m_state;
1231 };
1232
1233 #if _DEBUG_ASYNCGEN
1234
_PRINT_ASYNCGENASEND_STATUS(char const * descriptor,char const * context,struct Nuitka_AsyncgenAsendObject * asyncgen_asend)1235 NUITKA_MAY_BE_UNUSED static void _PRINT_ASYNCGENASEND_STATUS(char const *descriptor, char const *context,
1236 struct Nuitka_AsyncgenAsendObject *asyncgen_asend) {
1237 char const *status;
1238
1239 switch (asyncgen_asend->m_state) {
1240 case AWAITABLE_STATE_INIT:
1241 status = "(init)";
1242 break;
1243 case AWAITABLE_STATE_ITER:
1244 status = "(iter)";
1245 break;
1246 case AWAITABLE_STATE_CLOSED:
1247 status = "(closed)";
1248 break;
1249 default:
1250 status = "(ILLEGAL)";
1251 break;
1252 }
1253
1254 PRINT_STRING(descriptor);
1255 PRINT_STRING(" : ");
1256 PRINT_STRING(context);
1257 PRINT_STRING(" ");
1258 PRINT_ITEM((PyObject *)asyncgen_asend);
1259 PRINT_STRING(" ");
1260 PRINT_STRING(status);
1261 PRINT_NEW_LINE();
1262 }
1263
1264 #define PRINT_ASYNCGENASEND_STATUS(context, asyncgen_asend) \
1265 _PRINT_ASYNCGENASEND_STATUS(__FUNCTION__, context, asyncgen_asend)
1266
1267 #endif
1268
1269 /**
1270 * These can be created by byte code loop, and we don't now its internals,
1271 * yet we have to unwrap ourselves too. These could break in future updates,
1272 * and ideally we would have checks to cover those.
1273 */
1274
1275 struct _PyAsyncGenWrappedValue {
1276 /* Python object folklore: */
1277 PyObject_HEAD;
1278
1279 PyObject *agw_val;
1280 };
1281
1282 #define _PyAsyncGenWrappedValue_CheckExact(o) (Py_TYPE(o) == &_PyAsyncGenWrappedValue_Type)
1283
Nuitka_Asyncgen_unwrap_value(struct Nuitka_AsyncgenObject * asyncgen,PyObject * result)1284 static PyObject *Nuitka_Asyncgen_unwrap_value(struct Nuitka_AsyncgenObject *asyncgen, PyObject *result) {
1285 CHECK_OBJECT(asyncgen);
1286 CHECK_OBJECT_X(result);
1287
1288 if (result == NULL) {
1289 if (!ERROR_OCCURRED()) {
1290 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopAsyncIteration);
1291 asyncgen->m_closed = true;
1292 } else if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
1293 asyncgen->m_closed = true;
1294 }
1295
1296 #if PYTHON_VERSION >= 0x380
1297 asyncgen->m_running_async = false;
1298 #endif
1299 return NULL;
1300 }
1301
1302 if (_PyAsyncGenWrappedValue_CheckExact(result)) {
1303 /* async yield */
1304 _PyGen_SetStopIterationValue(((struct _PyAsyncGenWrappedValue *)result)->agw_val);
1305
1306 Py_DECREF(result);
1307
1308 #if PYTHON_VERSION >= 0x380
1309 asyncgen->m_running_async = false;
1310 #endif
1311 return NULL;
1312 } else if (Nuitka_AsyncgenWrappedValue_CheckExact(result)) {
1313 /* async yield */
1314 _PyGen_SetStopIterationValue(((struct Nuitka_AsyncgenWrappedValueObject *)result)->m_value);
1315
1316 Py_DECREF(result);
1317
1318 #if PYTHON_VERSION >= 0x380
1319 asyncgen->m_running_async = false;
1320 #endif
1321 return NULL;
1322 }
1323
1324 return result;
1325 }
1326
1327 static struct Nuitka_AsyncgenAsendObject *free_list_asyncgen_asends = NULL;
1328 static int free_list_asyncgen_asends_count = 0;
1329
Nuitka_AsyncgenAsend_tp_dealloc(struct Nuitka_AsyncgenAsendObject * asyncgen_asend)1330 static void Nuitka_AsyncgenAsend_tp_dealloc(struct Nuitka_AsyncgenAsendObject *asyncgen_asend) {
1331 #if _DEBUG_REFCOUNTS
1332 count_active_Nuitka_AsyncgenAsend_Type -= 1;
1333 count_released_Nuitka_AsyncgenAsend_Type += 1;
1334 #endif
1335
1336 Nuitka_GC_UnTrack(asyncgen_asend);
1337
1338 CHECK_OBJECT(asyncgen_asend->m_gen);
1339 Py_DECREF(asyncgen_asend->m_gen);
1340
1341 CHECK_OBJECT(asyncgen_asend->m_sendval);
1342 Py_DECREF(asyncgen_asend->m_sendval);
1343
1344 releaseToFreeList(free_list_asyncgen_asends, asyncgen_asend, MAX_ASYNCGEN_FREE_LIST_COUNT);
1345 }
1346
Nuitka_AsyncgenAsend_tp_traverse(struct Nuitka_AsyncgenAsendObject * asyncgen_asend,visitproc visit,void * arg)1347 static int Nuitka_AsyncgenAsend_tp_traverse(struct Nuitka_AsyncgenAsendObject *asyncgen_asend, visitproc visit,
1348 void *arg) {
1349 CHECK_OBJECT(asyncgen_asend);
1350
1351 CHECK_OBJECT(asyncgen_asend->m_gen);
1352 CHECK_OBJECT(asyncgen_asend->m_sendval);
1353
1354 Py_VISIT(asyncgen_asend->m_gen);
1355 Py_VISIT(asyncgen_asend->m_sendval);
1356
1357 return 0;
1358 }
1359
Nuitka_AsyncgenAsend_send(struct Nuitka_AsyncgenAsendObject * asyncgen_asend,PyObject * arg)1360 static PyObject *Nuitka_AsyncgenAsend_send(struct Nuitka_AsyncgenAsendObject *asyncgen_asend, PyObject *arg) {
1361 #if _DEBUG_ASYNCGEN
1362 PRINT_ASYNCGENASEND_STATUS("Enter", asyncgen_asend);
1363 PRINT_COROUTINE_VALUE("arg", arg);
1364 PRINT_NEW_LINE();
1365 #endif
1366
1367 if (asyncgen_asend->m_state == AWAITABLE_STATE_CLOSED) {
1368 #if PYTHON_VERSION < 0x390
1369 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1370 #else
1371 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "cannot reuse already awaited __anext__()/asend()");
1372 #endif
1373
1374 #if _DEBUG_ASYNCGEN
1375 PRINT_ASYNCGENASEND_STATUS("Leave", asyncgen_asend);
1376 PRINT_STRING("Closed -> StopIteration\n");
1377 PRINT_CURRENT_EXCEPTION();
1378 PRINT_NEW_LINE();
1379 #endif
1380
1381 return NULL;
1382 } else if (asyncgen_asend->m_state == AWAITABLE_STATE_INIT) {
1383 #if PYTHON_VERSION >= 0x380
1384 if (asyncgen_asend->m_gen->m_running_async) {
1385 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "anext(): asynchronous generator is already running");
1386 return NULL;
1387 }
1388 #endif
1389 if (arg == NULL || arg == Py_None) {
1390 arg = asyncgen_asend->m_sendval;
1391 }
1392
1393 asyncgen_asend->m_state = AWAITABLE_STATE_ITER;
1394
1395 #if _DEBUG_ASYNCGEN
1396 PRINT_STRING("Init -> begin iteration\n");
1397 PRINT_COROUTINE_VALUE("computed arg from sendval", arg);
1398 PRINT_NEW_LINE();
1399 #endif
1400 }
1401
1402 #if PYTHON_VERSION >= 0x380
1403 asyncgen_asend->m_gen->m_running_async = true;
1404 #endif
1405 // TODO: Who releases arg.
1406 // Py_INCREF(arg);
1407
1408 PyObject *result = _Nuitka_Asyncgen_send(asyncgen_asend->m_gen, arg, false, NULL, NULL, NULL);
1409 result = Nuitka_Asyncgen_unwrap_value(asyncgen_asend->m_gen, result);
1410
1411 if (result == NULL) {
1412 asyncgen_asend->m_state = AWAITABLE_STATE_CLOSED;
1413 }
1414
1415 #if _DEBUG_ASYNCGEN
1416 PRINT_ASYNCGENASEND_STATUS("Leave", asyncgen_asend);
1417 PRINT_COROUTINE_VALUE("result", result);
1418 PRINT_NEW_LINE();
1419 #endif
1420
1421 return result;
1422 }
1423
Nuitka_AsyncgenAsend_tp_iternext(struct Nuitka_AsyncgenAsendObject * asyncgen_asend)1424 static PyObject *Nuitka_AsyncgenAsend_tp_iternext(struct Nuitka_AsyncgenAsendObject *asyncgen_asend) {
1425 #if _DEBUG_ASYNCGEN
1426 PRINT_ASYNCGENASEND_STATUS("Enter", asyncgen_asend);
1427 PRINT_STRING("Deferring to Nuitka_AsyncgenAsend_send(Py_None)\n");
1428 PRINT_NEW_LINE();
1429 #endif
1430
1431 PyObject *result = Nuitka_AsyncgenAsend_send(asyncgen_asend, Py_None);
1432
1433 #if _DEBUG_ASYNCGEN
1434 PRINT_ASYNCGENASEND_STATUS("Leave", asyncgen_asend);
1435 PRINT_COROUTINE_VALUE("result", result);
1436 PRINT_NEW_LINE();
1437 #endif
1438
1439 return result;
1440 }
1441
Nuitka_AsyncgenAsend_throw(struct Nuitka_AsyncgenAsendObject * asyncgen_asend,PyObject * args)1442 static PyObject *Nuitka_AsyncgenAsend_throw(struct Nuitka_AsyncgenAsendObject *asyncgen_asend, PyObject *args) {
1443 #if _DEBUG_ASYNCGEN
1444 PRINT_ASYNCGENASEND_STATUS("Enter", asyncgen_asend);
1445 PRINT_STRING("Nuitka_AsyncgenAsend_throw: args:");
1446 PRINT_ITEM(args);
1447 PRINT_NEW_LINE();
1448 PRINT_STRING("Nuitka_AsyncgenAsend_throw: On entry: ");
1449 PRINT_CURRENT_EXCEPTION();
1450 #endif
1451
1452 if (asyncgen_asend->m_state == AWAITABLE_STATE_CLOSED) {
1453 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1454 return NULL;
1455 }
1456
1457 PyObject *result = Nuitka_Asyncgen_throw(asyncgen_asend->m_gen, args);
1458
1459 #if _DEBUG_ASYNCGEN
1460 PRINT_STRING("Nuitka_AsyncgenAsend_throw: Async throw result:");
1461 PRINT_ITEM(result);
1462 PRINT_STRING(" exception: ");
1463 PRINT_CURRENT_EXCEPTION();
1464 #endif
1465
1466 result = Nuitka_Asyncgen_unwrap_value(asyncgen_asend->m_gen, result);
1467
1468 if (result == NULL) {
1469 asyncgen_asend->m_state = AWAITABLE_STATE_CLOSED;
1470 }
1471
1472 #if _DEBUG_ASYNCGEN
1473 PRINT_STRING("Nuitka_AsyncgenAsend_throw: Leave with result: ");
1474 PRINT_ITEM(result);
1475 PRINT_NEW_LINE();
1476 PRINT_STRING("Nuitka_AsyncgenAsend_throw: Leave with exception: ");
1477 PRINT_CURRENT_EXCEPTION();
1478 PRINT_STRING("Nuitka_AsyncgenAsend_throw: Leave with exception: ");
1479 PRINT_PUBLISHED_EXCEPTION();
1480 PRINT_NEW_LINE();
1481 #endif
1482 CHECK_OBJECT_DEEP(args);
1483
1484 return result;
1485 }
1486
_Nuitka_AsyncgenAsend_throw2(struct Nuitka_AsyncgenAsendObject * asyncgen_asend,PyObject * exception_type,PyObject * exception_value,PyTracebackObject * exception_tb)1487 static PyObject *_Nuitka_AsyncgenAsend_throw2(struct Nuitka_AsyncgenAsendObject *asyncgen_asend,
1488 PyObject *exception_type, PyObject *exception_value,
1489 PyTracebackObject *exception_tb) {
1490 #if _DEBUG_ASYNCGEN
1491 PRINT_ASYNCGENASEND_STATUS("Enter", asyncgen_asend);
1492 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
1493 PRINT_CURRENT_EXCEPTION();
1494 PRINT_NEW_LINE();
1495 #endif
1496
1497 if (asyncgen_asend->m_state == AWAITABLE_STATE_CLOSED) {
1498 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1499 return NULL;
1500 }
1501
1502 PyObject *result =
1503 _Nuitka_Asyncgen_throw2(asyncgen_asend->m_gen, false, exception_type, exception_value, exception_tb);
1504
1505 // TODO: This might not be all that necessary as this is not directly outside facing.
1506 if (result == NULL) {
1507 if (GET_ERROR_OCCURRED() == NULL) {
1508 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1509 }
1510 }
1511
1512 #if _DEBUG_ASYNCGEN
1513 PRINT_ASYNCGENASEND_STATUS("Got result", asyncgen_asend);
1514 PRINT_COROUTINE_VALUE("result", result);
1515 PRINT_CURRENT_EXCEPTION();
1516 #endif
1517
1518 result = Nuitka_Asyncgen_unwrap_value(asyncgen_asend->m_gen, result);
1519
1520 #if _DEBUG_ASYNCGEN
1521 PRINT_COROUTINE_VALUE("unwrapped", result);
1522 PRINT_NEW_LINE();
1523 #endif
1524
1525 if (result == NULL) {
1526 asyncgen_asend->m_state = AWAITABLE_STATE_CLOSED;
1527 }
1528
1529 #if _DEBUG_ASYNCGEN
1530 PRINT_ASYNCGENASEND_STATUS("Leave", asyncgen_asend);
1531 PRINT_COROUTINE_VALUE("result", result);
1532 PRINT_CURRENT_EXCEPTION();
1533 PRINT_NEW_LINE();
1534 #endif
1535 return result;
1536 }
1537
Nuitka_AsyncgenAsend_close(struct Nuitka_AsyncgenAsendObject * asyncgen_asend,PyObject * args)1538 static PyObject *Nuitka_AsyncgenAsend_close(struct Nuitka_AsyncgenAsendObject *asyncgen_asend, PyObject *args) {
1539 asyncgen_asend->m_state = AWAITABLE_STATE_CLOSED;
1540
1541 Py_INCREF(Py_None);
1542 return Py_None;
1543 }
1544
Nuitka_AsyncgenAsend_tp_repr(struct Nuitka_AsyncgenAsendObject * asyncgen_asend)1545 static PyObject *Nuitka_AsyncgenAsend_tp_repr(struct Nuitka_AsyncgenAsendObject *asyncgen_asend) {
1546 return PyUnicode_FromFormat("<compiled_async_generator_asend of %s at %p>",
1547 Nuitka_String_AsString(asyncgen_asend->m_gen->m_qualname), asyncgen_asend);
1548 }
1549
1550 static PyMethodDef Nuitka_AsyncgenAsend_methods[] = {
1551 {"send", (PyCFunction)Nuitka_AsyncgenAsend_send, METH_O, NULL},
1552 {"throw", (PyCFunction)Nuitka_AsyncgenAsend_throw, METH_VARARGS, NULL},
1553 {"close", (PyCFunction)Nuitka_AsyncgenAsend_close, METH_NOARGS, NULL},
1554 {NULL}};
1555
1556 static PyAsyncMethods Nuitka_AsyncgenAsend_as_async = {
1557 PyObject_SelfIter, /* am_await */
1558 0, /* am_aiter */
1559 0 /* am_anext */
1560 };
1561
1562 static PyTypeObject Nuitka_AsyncgenAsend_Type = {
1563 PyVarObject_HEAD_INIT(NULL, 0) "compiled_async_generator_asend", /* tp_name */
1564 sizeof(struct Nuitka_AsyncgenAsendObject), /* tp_basicsize */
1565 0, /* tp_itemsize */
1566 (destructor)Nuitka_AsyncgenAsend_tp_dealloc, /* tp_dealloc */
1567 0, /* tp_print */
1568 0, /* tp_getattr */
1569 0, /* tp_setattr */
1570 &Nuitka_AsyncgenAsend_as_async, /* tp_as_async */
1571 (reprfunc)Nuitka_AsyncgenAsend_tp_repr, /* tp_repr */
1572 0, /* tp_as_number */
1573 0, /* tp_as_sequence */
1574 0, /* tp_as_mapping */
1575 0, /* tp_hash */
1576 0, /* tp_call */
1577 0, /* tp_str */
1578 PyObject_GenericGetAttr, /* tp_getattro */
1579 0, /* tp_setattro */
1580 0, /* tp_as_buffer */
1581 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1582 0, /* tp_doc */
1583 (traverseproc)Nuitka_AsyncgenAsend_tp_traverse, /* tp_traverse */
1584 0, /* tp_clear */
1585 0, /* tp_richcompare */
1586 0, /* tp_weaklistoffset */
1587 PyObject_SelfIter, /* tp_iter */
1588 (iternextfunc)Nuitka_AsyncgenAsend_tp_iternext, /* tp_iternext */
1589 Nuitka_AsyncgenAsend_methods, /* tp_methods */
1590 0, /* tp_members */
1591 0, /* tp_getset */
1592 0, /* tp_base */
1593 0, /* tp_dict */
1594 0, /* tp_descr_get */
1595 0, /* tp_descr_set */
1596 0, /* tp_dictoffset */
1597 0, /* tp_init */
1598 0, /* tp_alloc */
1599 0, /* tp_new */
1600 };
1601
Nuitka_AsyncgenAsend_Check(PyObject * object)1602 static bool Nuitka_AsyncgenAsend_Check(PyObject *object) { return Py_TYPE(object) == &Nuitka_AsyncgenAsend_Type; }
1603
Nuitka_AsyncgenAsend_New(struct Nuitka_AsyncgenObject * asyncgen,PyObject * send_value)1604 static PyObject *Nuitka_AsyncgenAsend_New(struct Nuitka_AsyncgenObject *asyncgen, PyObject *send_value) {
1605 CHECK_OBJECT(asyncgen);
1606 CHECK_OBJECT(send_value);
1607
1608 #if _DEBUG_REFCOUNTS
1609 count_active_Nuitka_AsyncgenAsend_Type += 1;
1610 count_allocated_Nuitka_AsyncgenAsend_Type += 1;
1611 #endif
1612
1613 struct Nuitka_AsyncgenAsendObject *result;
1614
1615 allocateFromFreeListFixed(free_list_asyncgen_asends, struct Nuitka_AsyncgenAsendObject, Nuitka_AsyncgenAsend_Type);
1616
1617 Py_INCREF(asyncgen);
1618 result->m_gen = asyncgen;
1619
1620 Py_INCREF(send_value);
1621 result->m_sendval = send_value;
1622
1623 result->m_state = AWAITABLE_STATE_INIT;
1624
1625 Nuitka_GC_Track(result);
1626 return (PyObject *)result;
1627 }
1628
1629 struct Nuitka_AsyncgenAthrowObject {
1630 /* Python object folklore: */
1631 PyObject_HEAD;
1632
1633 // The asyncgen we are working for.
1634 struct Nuitka_AsyncgenObject *m_gen;
1635 // Arguments, NULL in case of close, otherwise throw arguments.
1636 PyObject *m_args;
1637
1638 AwaitableState m_state;
1639 };
1640
1641 #if _DEBUG_ASYNCGEN
1642
_PRINT_ASYNCGENATHROW_STATUS(char const * descriptor,char const * context,struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow)1643 NUITKA_MAY_BE_UNUSED static void _PRINT_ASYNCGENATHROW_STATUS(char const *descriptor, char const *context,
1644 struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow) {
1645 char const *status;
1646
1647 switch (asyncgen_athrow->m_state) {
1648 case AWAITABLE_STATE_INIT:
1649 status = "(init)";
1650 break;
1651 case AWAITABLE_STATE_ITER:
1652 status = "(iter)";
1653 break;
1654 case AWAITABLE_STATE_CLOSED:
1655 status = "(closed)";
1656 break;
1657 default:
1658 status = "(ILLEGAL)";
1659 break;
1660 }
1661
1662 PRINT_STRING(descriptor);
1663 PRINT_STRING(" : ");
1664 PRINT_STRING(context);
1665 PRINT_STRING(" ");
1666 PRINT_ITEM((PyObject *)asyncgen_athrow);
1667 PRINT_STRING(" ");
1668 PRINT_STRING(status);
1669 PRINT_NEW_LINE();
1670 }
1671
1672 #define PRINT_ASYNCGENATHROW_STATUS(context, coroutine) \
1673 _PRINT_ASYNCGENATHROW_STATUS(__FUNCTION__, context, asyncgen_athrow)
1674
1675 #endif
1676
1677 static struct Nuitka_AsyncgenAthrowObject *free_list_asyncgen_athrows = NULL;
1678 static int free_list_asyncgen_athrows_count = 0;
1679
Nuitka_AsyncgenAthrow_dealloc(struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow)1680 static void Nuitka_AsyncgenAthrow_dealloc(struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow) {
1681 #if _DEBUG_REFCOUNTS
1682 count_active_Nuitka_AIterWrapper_Type -= 1;
1683 count_released_Nuitka_AIterWrapper_Type += 1;
1684 #endif
1685
1686 Nuitka_GC_UnTrack(asyncgen_athrow);
1687
1688 CHECK_OBJECT(asyncgen_athrow->m_gen);
1689 Py_DECREF(asyncgen_athrow->m_gen);
1690
1691 CHECK_OBJECT_X(asyncgen_athrow->m_args);
1692 Py_XDECREF(asyncgen_athrow->m_args);
1693
1694 /* Put the object into freelist or release to GC */
1695 releaseToFreeList(free_list_asyncgen_athrows, asyncgen_athrow, MAX_ASYNCGEN_FREE_LIST_COUNT);
1696 }
1697
Nuitka_AsyncgenAthrow_traverse(struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow,visitproc visit,void * arg)1698 static int Nuitka_AsyncgenAthrow_traverse(struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow, visitproc visit,
1699 void *arg) {
1700 Py_VISIT(asyncgen_athrow->m_gen);
1701 Py_VISIT(asyncgen_athrow->m_args);
1702
1703 return 0;
1704 }
1705
Nuitka_AsyncgenAthrow_send(struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow,PyObject * arg)1706 static PyObject *Nuitka_AsyncgenAthrow_send(struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow, PyObject *arg) {
1707 #if _DEBUG_ASYNCGEN
1708 PRINT_ASYNCGENATHROW_STATUS("Enter", asyncgen_athrow);
1709 PRINT_COROUTINE_VALUE("arg", arg);
1710 PRINT_NEW_LINE();
1711 #endif
1712
1713 struct Nuitka_AsyncgenObject *asyncgen = asyncgen_athrow->m_gen;
1714
1715 // Closing twice is not allowed with 3.9 or higher.
1716 if (asyncgen_athrow->m_state == AWAITABLE_STATE_CLOSED) {
1717 #if PYTHON_VERSION < 0x390
1718 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1719 #else
1720 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "cannot reuse already awaited aclose()/athrow()");
1721 #endif
1722
1723 return NULL;
1724 }
1725
1726 // If finished, just report StopIteration.
1727 if (asyncgen->m_status == status_Finished) {
1728 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1729 return NULL;
1730 }
1731
1732 PyObject *retval;
1733
1734 if (asyncgen_athrow->m_state == AWAITABLE_STATE_INIT) {
1735 #if PYTHON_VERSION >= 0x380
1736 if (asyncgen_athrow->m_gen->m_running_async) {
1737 if (asyncgen_athrow->m_args == NULL) {
1738 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError,
1739 "aclose(): asynchronous generator is already running");
1740 } else {
1741 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError,
1742 "athrow(): asynchronous generator is already running");
1743 }
1744 return NULL;
1745 }
1746 #endif
1747
1748 // Can also close only once.
1749 if (asyncgen->m_closed) {
1750 #if PYTHON_VERSION >= 0x380
1751 asyncgen_athrow->m_state = AWAITABLE_STATE_CLOSED;
1752 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopAsyncIteration);
1753 #else
1754 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1755 #endif
1756 return NULL;
1757 }
1758
1759 // Starting accepts only "None" as input value.
1760 if (arg != Py_None) {
1761 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError,
1762 "can't send non-None value to a just-started coroutine");
1763
1764 return NULL;
1765 }
1766
1767 #if PYTHON_VERSION >= 0x380
1768 asyncgen_athrow->m_gen->m_running_async = true;
1769 #endif
1770 asyncgen_athrow->m_state = AWAITABLE_STATE_ITER;
1771
1772 if (asyncgen_athrow->m_args == NULL) {
1773 asyncgen->m_closed = true;
1774
1775 Py_INCREF(PyExc_GeneratorExit);
1776 retval =
1777 _Nuitka_Asyncgen_throw2(asyncgen, 1, /* Do not close generator when PyExc_GeneratorExit is passed */
1778 PyExc_GeneratorExit, NULL, NULL);
1779
1780 if (retval) {
1781 if (_PyAsyncGenWrappedValue_CheckExact(retval) || Nuitka_AsyncgenWrappedValue_CheckExact(retval)) {
1782 #if PYTHON_VERSION >= 0x380
1783 asyncgen_athrow->m_gen->m_running_async = false;
1784 #endif
1785
1786 Py_DECREF(retval);
1787
1788 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "async generator ignored GeneratorExit");
1789
1790 return NULL;
1791 }
1792 }
1793 } else {
1794 PyObject *exception_type;
1795 PyObject *exception_value = NULL;
1796 PyTracebackObject *exception_tb = NULL;
1797
1798 if (unlikely(!PyArg_UnpackTuple(asyncgen_athrow->m_args, "athrow", 1, 3, &exception_type, &exception_value,
1799 &exception_tb))) {
1800 return NULL;
1801 }
1802
1803 // Handing ownership of exception over, we need not release it ourselves
1804 Py_INCREF(exception_type);
1805 Py_XINCREF(exception_value);
1806 Py_XINCREF(exception_tb);
1807
1808 retval =
1809 _Nuitka_Asyncgen_throw2(asyncgen, 0, /* Do not close generator when PyExc_GeneratorExit is passed */
1810 exception_type, exception_value, exception_tb);
1811
1812 retval = Nuitka_Asyncgen_unwrap_value(asyncgen, retval);
1813 }
1814
1815 if (retval == NULL) {
1816 goto check_error;
1817 }
1818
1819 return retval;
1820 }
1821
1822 assert(asyncgen_athrow->m_state == AWAITABLE_STATE_ITER);
1823
1824 retval = _Nuitka_Asyncgen_send(asyncgen, arg, false, NULL, NULL, NULL);
1825
1826 if (asyncgen_athrow->m_args) {
1827 return Nuitka_Asyncgen_unwrap_value(asyncgen, retval);
1828 } else {
1829 /* We are here to close if no args. */
1830 if (retval) {
1831 if (_PyAsyncGenWrappedValue_CheckExact(retval) || Nuitka_AsyncgenWrappedValue_CheckExact(retval)) {
1832 #if PYTHON_VERSION >= 0x380
1833 asyncgen_athrow->m_gen->m_running_async = false;
1834 #endif
1835 Py_DECREF(retval);
1836
1837 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "async generator ignored GeneratorExit");
1838
1839 return NULL;
1840 }
1841
1842 return retval;
1843 }
1844 }
1845
1846 check_error:
1847 #if PYTHON_VERSION >= 0x380
1848 asyncgen_athrow->m_gen->m_running_async = false;
1849 #endif
1850
1851 if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
1852 asyncgen_athrow->m_state = AWAITABLE_STATE_CLOSED;
1853
1854 if (asyncgen_athrow->m_args == NULL) {
1855 CLEAR_ERROR_OCCURRED();
1856 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1857 }
1858 } else if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
1859 asyncgen_athrow->m_state = AWAITABLE_STATE_CLOSED;
1860
1861 #if PYTHON_VERSION >= 0x380
1862 if (asyncgen_athrow->m_args == NULL) {
1863 #endif
1864 CLEAR_ERROR_OCCURRED();
1865 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1866 #if PYTHON_VERSION >= 0x380
1867 }
1868 #endif
1869 }
1870
1871 return NULL;
1872 }
1873
Nuitka_AsyncgenAthrow_throw(struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow,PyObject * args)1874 static PyObject *Nuitka_AsyncgenAthrow_throw(struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow, PyObject *args) {
1875 #if _DEBUG_ASYNCGEN
1876 PRINT_ASYNCGENATHROW_STATUS("Enter", asyncgen_athrow);
1877 PRINT_COROUTINE_VALUE("args", args);
1878 PRINT_NEW_LINE();
1879 #endif
1880
1881 PyObject *retval;
1882
1883 #if PYTHON_VERSION < 0x375
1884 if (asyncgen_athrow->m_state == AWAITABLE_STATE_INIT) {
1885 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "can't send non-None value to a just-started coroutine");
1886
1887 return NULL;
1888 }
1889 #endif
1890
1891 if (asyncgen_athrow->m_state == AWAITABLE_STATE_CLOSED) {
1892 #if PYTHON_VERSION < 0x390
1893 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1894 #else
1895 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "cannot reuse already awaited aclose()/athrow()");
1896 #endif
1897
1898 return NULL;
1899 }
1900
1901 retval = Nuitka_Asyncgen_throw(asyncgen_athrow->m_gen, args);
1902
1903 if (asyncgen_athrow->m_args) {
1904 return Nuitka_Asyncgen_unwrap_value(asyncgen_athrow->m_gen, retval);
1905 } else {
1906 if (retval != NULL) {
1907 if (_PyAsyncGenWrappedValue_CheckExact(retval) || Nuitka_AsyncgenWrappedValue_CheckExact(retval)) {
1908 #if PYTHON_VERSION >= 0x380
1909 asyncgen_athrow->m_gen->m_running_async = false;
1910 #endif
1911 Py_DECREF(retval);
1912
1913 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "async generator ignored GeneratorExit");
1914
1915 return NULL;
1916 }
1917 }
1918
1919 #if PYTHON_VERSION >= 0x390
1920 if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration) || PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
1921 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
1922 }
1923 #endif
1924
1925 return retval;
1926 }
1927 }
1928
Nuitka_AsyncgenAthrow_tp_iternext(struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow)1929 static PyObject *Nuitka_AsyncgenAthrow_tp_iternext(struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow) {
1930 return Nuitka_AsyncgenAthrow_send(asyncgen_athrow, Py_None);
1931 }
1932
Nuitka_AsyncgenAthrow_close(struct Nuitka_AsyncgenAthrowObject * asyncgen_athrow)1933 static PyObject *Nuitka_AsyncgenAthrow_close(struct Nuitka_AsyncgenAthrowObject *asyncgen_athrow) {
1934 asyncgen_athrow->m_state = AWAITABLE_STATE_CLOSED;
1935
1936 Py_INCREF(Py_None);
1937 return Py_None;
1938 }
1939
1940 static PyMethodDef Nuitka_AsyncgenAthrow_methods[] = {
1941 {"send", (PyCFunction)Nuitka_AsyncgenAthrow_send, METH_O, NULL},
1942 {"throw", (PyCFunction)Nuitka_AsyncgenAthrow_throw, METH_VARARGS, NULL},
1943 {"close", (PyCFunction)Nuitka_AsyncgenAthrow_close, METH_NOARGS, NULL},
1944 {NULL}};
1945
1946 static PyAsyncMethods Nuitka_AsyncgenAthrow_as_async = {
1947 PyObject_SelfIter, /* am_await */
1948 0, /* am_aiter */
1949 0 /* am_anext */
1950 };
1951
1952 static PyTypeObject Nuitka_AsyncgenAthrow_Type = {
1953 PyVarObject_HEAD_INIT(NULL, 0) "compiled_async_generator_athrow", /* tp_name */
1954 sizeof(struct Nuitka_AsyncgenAthrowObject), /* tp_basicsize */
1955 0, /* tp_itemsize */
1956 (destructor)Nuitka_AsyncgenAthrow_dealloc, /* tp_dealloc */
1957 0, /* tp_print */
1958 0, /* tp_getattr */
1959 0, /* tp_setattr */
1960 &Nuitka_AsyncgenAthrow_as_async, /* tp_as_async */
1961 0, /* tp_repr */
1962 0, /* tp_as_number */
1963 0, /* tp_as_sequence */
1964 0, /* tp_as_mapping */
1965 0, /* tp_hash */
1966 0, /* tp_call */
1967 0, /* tp_str */
1968 PyObject_GenericGetAttr, /* tp_getattro */
1969 0, /* tp_setattro */
1970 0, /* tp_as_buffer */
1971 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1972 0, /* tp_doc */
1973 (traverseproc)Nuitka_AsyncgenAthrow_traverse, /* tp_traverse */
1974 0, /* tp_clear */
1975 0, /* tp_richcompare */
1976 0, /* tp_weaklistoffset */
1977 PyObject_SelfIter, /* tp_iter */
1978 (iternextfunc)Nuitka_AsyncgenAthrow_tp_iternext, /* tp_iternext */
1979 Nuitka_AsyncgenAthrow_methods, /* tp_methods */
1980 0, /* tp_members */
1981 0, /* tp_getset */
1982 0, /* tp_base */
1983 0, /* tp_dict */
1984 0, /* tp_descr_get */
1985 0, /* tp_descr_set */
1986 0, /* tp_dictoffset */
1987 0, /* tp_init */
1988 0, /* tp_alloc */
1989 0, /* tp_new */
1990 0, /* tp_free */
1991 0, /* tp_is_gc */
1992 0, /* tp_bases */
1993 0, /* tp_mro */
1994 0, /* tp_cache */
1995 0, /* tp_subclasses */
1996 0, /* tp_weaklist */
1997 0, /* tp_del */
1998 0, /* tp_version_tag */
1999 (destructor)Nuitka_Asyncgen_tp_finalize, /* tp_finalize */
2000 };
2001
Nuitka_AsyncgenAthrow_New(struct Nuitka_AsyncgenObject * asyncgen,PyObject * args)2002 static PyObject *Nuitka_AsyncgenAthrow_New(struct Nuitka_AsyncgenObject *asyncgen, PyObject *args) {
2003 CHECK_OBJECT(asyncgen);
2004 CHECK_OBJECT_X(args);
2005
2006 #if _DEBUG_REFCOUNTS
2007 count_active_Nuitka_AsyncgenAthrow_Type += 1;
2008 count_allocated_Nuitka_AsyncgenAthrow_Type += 1;
2009 #endif
2010
2011 struct Nuitka_AsyncgenAthrowObject *result;
2012
2013 allocateFromFreeListFixed(free_list_asyncgen_athrows, struct Nuitka_AsyncgenAthrowObject,
2014 Nuitka_AsyncgenAthrow_Type);
2015
2016 Py_INCREF(asyncgen);
2017 result->m_gen = asyncgen;
2018
2019 Py_XINCREF(args);
2020 result->m_args = args;
2021
2022 result->m_state = AWAITABLE_STATE_INIT;
2023
2024 Nuitka_GC_Track(result);
2025 return (PyObject *)result;
2026 }
2027
_initCompiledAsyncgenTypes(void)2028 static void _initCompiledAsyncgenTypes(void) {
2029 PyType_Ready(&Nuitka_Asyncgen_Type);
2030 PyType_Ready(&Nuitka_AsyncgenAsend_Type);
2031 PyType_Ready(&Nuitka_AsyncgenAthrow_Type);
2032 PyType_Ready(&Nuitka_AsyncgenValueWrapper_Type);
2033 }
2034