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 Coroutines.
19 *
20 * Unlike in CPython, we have one type for just coroutines, this doesn't do generators
21 * nor asyncgen.
22 *
23 * It strives to be full replacement for normal coroutines.
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_Coroutine_Type = 0;
38 int count_allocated_Nuitka_Coroutine_Type = 0;
39 int count_released_Nuitka_Coroutine_Type = 0;
40 int count_active_Nuitka_CoroutineWrapper_Type = 0;
41 int count_allocated_Nuitka_CoroutineWrapper_Type = 0;
42 int count_released_Nuitka_CoroutineWrapper_Type = 0;
43 int count_active_Nuitka_AIterWrapper_Type = 0;
44 int count_allocated_Nuitka_AIterWrapper_Type = 0;
45 int count_released_Nuitka_AIterWrapper_Type = 0;
46 #endif
47
48 static PyObject *_Nuitka_Coroutine_send(struct Nuitka_CoroutineObject *coroutine, PyObject *value, bool closing,
49 PyObject *exception_type, PyObject *exception_value,
50 PyTracebackObject *exception_tb);
51
Nuitka_Coroutine_get_name(struct Nuitka_CoroutineObject * coroutine)52 static PyObject *Nuitka_Coroutine_get_name(struct Nuitka_CoroutineObject *coroutine) {
53 CHECK_OBJECT(coroutine);
54
55 Py_INCREF(coroutine->m_name);
56 return coroutine->m_name;
57 }
58
Nuitka_Coroutine_set_name(struct Nuitka_CoroutineObject * coroutine,PyObject * value)59 static int Nuitka_Coroutine_set_name(struct Nuitka_CoroutineObject *coroutine, PyObject *value) {
60 CHECK_OBJECT(coroutine);
61 CHECK_OBJECT_X(value);
62
63 // Cannot be deleted, not be non-unicode value.
64 if (unlikely((value == NULL) || !PyUnicode_Check(value))) {
65 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "__name__ must be set to a string object");
66
67 return -1;
68 }
69
70 PyObject *tmp = coroutine->m_name;
71 Py_INCREF(value);
72 coroutine->m_name = value;
73 Py_DECREF(tmp);
74
75 return 0;
76 }
77
Nuitka_Coroutine_get_qualname(struct Nuitka_CoroutineObject * coroutine)78 static PyObject *Nuitka_Coroutine_get_qualname(struct Nuitka_CoroutineObject *coroutine) {
79 CHECK_OBJECT(coroutine);
80
81 Py_INCREF(coroutine->m_qualname);
82 return coroutine->m_qualname;
83 }
84
Nuitka_Coroutine_set_qualname(struct Nuitka_CoroutineObject * coroutine,PyObject * value)85 static int Nuitka_Coroutine_set_qualname(struct Nuitka_CoroutineObject *coroutine, PyObject *value) {
86 CHECK_OBJECT(coroutine);
87 CHECK_OBJECT_X(value);
88
89 // Cannot be deleted, not be non-unicode value.
90 if (unlikely((value == NULL) || !PyUnicode_Check(value))) {
91 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "__qualname__ must be set to a string object");
92
93 return -1;
94 }
95
96 PyObject *tmp = coroutine->m_qualname;
97 Py_INCREF(value);
98 coroutine->m_qualname = value;
99 Py_DECREF(tmp);
100
101 return 0;
102 }
103
Nuitka_Coroutine_get_cr_await(struct Nuitka_CoroutineObject * coroutine)104 static PyObject *Nuitka_Coroutine_get_cr_await(struct Nuitka_CoroutineObject *coroutine) {
105 CHECK_OBJECT(coroutine);
106 CHECK_OBJECT_X(coroutine->m_yieldfrom);
107
108 if (coroutine->m_yieldfrom) {
109 Py_INCREF(coroutine->m_yieldfrom);
110 return coroutine->m_yieldfrom;
111 } else {
112 Py_INCREF(Py_None);
113 return Py_None;
114 }
115 }
116
Nuitka_Coroutine_get_code(struct Nuitka_CoroutineObject * coroutine)117 static PyObject *Nuitka_Coroutine_get_code(struct Nuitka_CoroutineObject *coroutine) {
118 CHECK_OBJECT(coroutine);
119 CHECK_OBJECT(coroutine->m_code_object);
120
121 Py_INCREF(coroutine->m_code_object);
122 return (PyObject *)coroutine->m_code_object;
123 }
124
Nuitka_Coroutine_set_code(struct Nuitka_CoroutineObject * coroutine,PyObject * value)125 static int Nuitka_Coroutine_set_code(struct Nuitka_CoroutineObject *coroutine, PyObject *value) {
126 CHECK_OBJECT(coroutine);
127
128 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "cr_code is not writable in Nuitka");
129 return -1;
130 }
131
Nuitka_Coroutine_get_frame(struct Nuitka_CoroutineObject * coroutine)132 static PyObject *Nuitka_Coroutine_get_frame(struct Nuitka_CoroutineObject *coroutine) {
133 CHECK_OBJECT(coroutine);
134 CHECK_OBJECT_X(coroutine->m_frame);
135
136 if (coroutine->m_frame) {
137 Py_INCREF(coroutine->m_frame);
138 return (PyObject *)coroutine->m_frame;
139 } else {
140 Py_INCREF(Py_None);
141 return Py_None;
142 }
143 }
144
Nuitka_Coroutine_set_frame(struct Nuitka_CoroutineObject * coroutine,PyObject * value)145 static int Nuitka_Coroutine_set_frame(struct Nuitka_CoroutineObject *coroutine, PyObject *value) {
146 CHECK_OBJECT(coroutine);
147 CHECK_OBJECT_X(value);
148
149 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "gi_frame is not writable in Nuitka");
150 return -1;
151 }
152
Nuitka_Coroutine_release_closure(struct Nuitka_CoroutineObject * coroutine)153 static void Nuitka_Coroutine_release_closure(struct Nuitka_CoroutineObject *coroutine) {
154 CHECK_OBJECT(coroutine);
155
156 for (Py_ssize_t i = 0; i < coroutine->m_closure_given; i++) {
157 CHECK_OBJECT(coroutine->m_closure[i]);
158 Py_DECREF(coroutine->m_closure[i]);
159 }
160
161 coroutine->m_closure_given = 0;
162 }
163
164 // Note: Shared with asyncgen.
_Nuitka_YieldFromCore(PyObject * yieldfrom,PyObject * send_value,PyObject ** returned_value,bool mode)165 static PyObject *_Nuitka_YieldFromCore(PyObject *yieldfrom, PyObject *send_value, PyObject **returned_value,
166 bool mode) {
167 // Send iteration value to the sub-generator, which may be a CPython
168 // generator object, something with an iterator next, or a send method,
169 // where the later is only required if values other than "None" need to
170 // be passed in.
171 CHECK_OBJECT(yieldfrom);
172 CHECK_OBJECT_X(send_value);
173
174 assert(send_value != NULL || ERROR_OCCURRED());
175
176 PyObject *retval;
177
178 PyObject *exception_type, *exception_value;
179 PyTracebackObject *exception_tb;
180
181 FETCH_ERROR_OCCURRED(&exception_type, &exception_value, &exception_tb);
182
183 if (exception_type != NULL) {
184 // Exception, was thrown into us, need to send that to sub-generator.
185 // We acquired ownership of the published exception and need to release it potentially.
186
187 // Transfer exception owner this.
188 retval = _Nuitka_YieldFromPassExceptionTo(yieldfrom, exception_type, exception_value, exception_tb);
189
190 if (unlikely(send_value == NULL)) {
191 PyObject *error = GET_ERROR_OCCURRED();
192
193 if (error != NULL && EXCEPTION_MATCH_BOOL_SINGLE(error, PyExc_StopIteration)) {
194 *returned_value = ERROR_GET_STOP_ITERATION_VALUE();
195
196 assert(!ERROR_OCCURRED());
197 return NULL;
198 }
199 }
200 } else if (PyGen_CheckExact(yieldfrom) || PyCoro_CheckExact(yieldfrom)) {
201 retval = Nuitka_PyGen_Send((PyGenObject *)yieldfrom, Py_None);
202 } else if (send_value == Py_None && Nuitka_CoroutineWrapper_Check(yieldfrom)) {
203 struct Nuitka_CoroutineObject *yieldfrom_coroutine =
204 ((struct Nuitka_CoroutineWrapperObject *)yieldfrom)->m_coroutine;
205
206 retval = _Nuitka_Coroutine_send(yieldfrom_coroutine, Py_None, mode ? false : true, NULL, NULL, NULL);
207 } else if (send_value == Py_None && Py_TYPE(yieldfrom)->tp_iternext != NULL) {
208 retval = Py_TYPE(yieldfrom)->tp_iternext(yieldfrom);
209 } else {
210 #if 0
211 // TODO: Add slow mode traces.
212 PRINT_ITEM(yieldfrom);
213 PRINT_NEW_LINE();
214 #endif
215
216 retval = PyObject_CallMethodObjArgs(yieldfrom, const_str_plain_send, send_value, NULL);
217 }
218
219 // Check the sub-generator result
220 if (retval == NULL) {
221 PyObject *error = GET_ERROR_OCCURRED();
222
223 if (error == NULL) {
224 Py_INCREF(Py_None);
225 *returned_value = Py_None;
226 } else if (likely(EXCEPTION_MATCH_BOOL_SINGLE(error, PyExc_StopIteration))) {
227 // The sub-generator has given an exception. In case of
228 // StopIteration, we need to check the value, as it is going to be
229 // the expression value of this "yield from", and we are done. All
230 // other errors, we need to raise.
231 *returned_value = ERROR_GET_STOP_ITERATION_VALUE();
232 assert(*returned_value != NULL);
233 assert(!ERROR_OCCURRED());
234 } else {
235 *returned_value = NULL;
236 }
237
238 return NULL;
239 } else {
240 assert(!ERROR_OCCURRED());
241 return retval;
242 }
243 }
244
_Nuitka_YieldFromCoroutineCore(struct Nuitka_CoroutineObject * coroutine,PyObject * send_value,bool mode)245 static PyObject *_Nuitka_YieldFromCoroutineCore(struct Nuitka_CoroutineObject *coroutine, PyObject *send_value,
246 bool mode) {
247 CHECK_OBJECT(coroutine);
248 CHECK_OBJECT_X(send_value);
249
250 PyObject *yieldfrom = coroutine->m_yieldfrom;
251 CHECK_OBJECT(yieldfrom);
252
253 // Need to make it unaccessible while using it.
254 coroutine->m_yieldfrom = NULL;
255
256 PyObject *returned_value;
257 PyObject *yielded = _Nuitka_YieldFromCore(yieldfrom, send_value, &returned_value, mode);
258
259 if (yielded == NULL) {
260 assert(coroutine->m_yieldfrom == NULL);
261 Py_DECREF(yieldfrom);
262
263 yielded = ((coroutine_code)coroutine->m_code)(coroutine, returned_value);
264 } else {
265 assert(coroutine->m_yieldfrom == NULL);
266 coroutine->m_yieldfrom = yieldfrom;
267 }
268
269 return yielded;
270 }
271
272 #if _DEBUG_COROUTINE
_PRINT_COROUTINE_STATUS(char const * descriptor,char const * context,struct Nuitka_CoroutineObject * coroutine)273 NUITKA_MAY_BE_UNUSED static void _PRINT_COROUTINE_STATUS(char const *descriptor, char const *context,
274 struct Nuitka_CoroutineObject *coroutine) {
275 char const *status;
276
277 switch (coroutine->m_status) {
278 case status_Finished:
279 status = "(finished)";
280 break;
281 case status_Running:
282 status = "(running)";
283 break;
284 case status_Unused:
285 status = "(unused)";
286 break;
287 default:
288 status = "(ILLEGAL)";
289 break;
290 }
291
292 PRINT_STRING(descriptor);
293 PRINT_STRING(" : ");
294 PRINT_STRING(context);
295 PRINT_STRING(" ");
296 PRINT_ITEM((PyObject *)coroutine);
297 PRINT_STRING(" ");
298 PRINT_REFCOUNT((PyObject *)coroutine);
299 PRINT_STRING(status);
300 PRINT_NEW_LINE();
301 }
302
303 #define PRINT_COROUTINE_STATUS(context, coroutine) _PRINT_COROUTINE_STATUS(__FUNCTION__, context, coroutine)
304
305 #endif
306
Nuitka_YieldFromCoroutineNext(struct Nuitka_CoroutineObject * coroutine)307 static PyObject *Nuitka_YieldFromCoroutineNext(struct Nuitka_CoroutineObject *coroutine) {
308 CHECK_OBJECT(coroutine);
309
310 #if _DEBUG_COROUTINE
311 PRINT_COROUTINE_STATUS("Enter", coroutine);
312 PRINT_NEW_LINE();
313 #endif
314 PyObject *result = _Nuitka_YieldFromCoroutineCore(coroutine, Py_None, true);
315 #if _DEBUG_COROUTINE
316 PRINT_COROUTINE_STATUS("Leave", coroutine);
317 PRINT_CURRENT_EXCEPTION();
318 PRINT_NEW_LINE();
319 #endif
320 return result;
321 }
322
Nuitka_YieldFromCoroutineInitial(struct Nuitka_CoroutineObject * coroutine,PyObject * send_value)323 static PyObject *Nuitka_YieldFromCoroutineInitial(struct Nuitka_CoroutineObject *coroutine, PyObject *send_value) {
324 CHECK_OBJECT(coroutine);
325 CHECK_OBJECT_X(send_value);
326
327 #if _DEBUG_COROUTINE
328 PRINT_COROUTINE_STATUS("Enter", coroutine);
329 PRINT_NEW_LINE();
330 #endif
331 PyObject *result = _Nuitka_YieldFromCoroutineCore(coroutine, send_value, false);
332 #if _DEBUG_COROUTINE
333 PRINT_COROUTINE_STATUS("Leave", coroutine);
334 PRINT_CURRENT_EXCEPTION();
335 PRINT_NEW_LINE();
336 #endif
337 return result;
338 }
339
340 static void Nuitka_SetStopIterationValue(PyObject *value);
341
342 // This function is called when sending a value or exception to be handled in the coroutine
343 // Note:
344 // Exception arguments are passed for ownership and must be released before returning. The
345 // value of exception_type may be NULL, and the actual exception will not necessarily
346 // be normalized.
347
_Nuitka_Coroutine_send(struct Nuitka_CoroutineObject * coroutine,PyObject * value,bool closing,PyObject * exception_type,PyObject * exception_value,PyTracebackObject * exception_tb)348 static PyObject *_Nuitka_Coroutine_send(struct Nuitka_CoroutineObject *coroutine, PyObject *value, bool closing,
349 PyObject *exception_type, PyObject *exception_value,
350 PyTracebackObject *exception_tb) {
351 CHECK_OBJECT(coroutine);
352 assert(Nuitka_Coroutine_Check((PyObject *)coroutine));
353 CHECK_OBJECT_X(exception_type);
354 CHECK_OBJECT_X(exception_value);
355 CHECK_OBJECT_X(exception_tb);
356 CHECK_OBJECT_X(value);
357
358 #if _DEBUG_COROUTINE
359 PRINT_COROUTINE_STATUS("Enter", coroutine);
360 PRINT_COROUTINE_STRING("closing", closing ? "(closing) " : "(not closing) ");
361 PRINT_COROUTINE_VALUE("value", value);
362 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
363 PRINT_CURRENT_EXCEPTION();
364 PRINT_NEW_LINE();
365 #endif
366
367 if (value != NULL) {
368 assert(exception_type == NULL);
369 assert(exception_value == NULL);
370 assert(exception_tb == NULL);
371 }
372
373 if (coroutine->m_status == status_Unused && value != NULL && value != Py_None) {
374 // No exception if value is given.
375
376 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "can't send non-None value to a just-started coroutine");
377 return NULL;
378 }
379
380 if (coroutine->m_status != status_Finished) {
381 if (coroutine->m_running) {
382 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_ValueError, "coroutine already executing");
383 return NULL;
384 }
385
386 PyThreadState *thread_state = PyThreadState_GET();
387
388 // Put the coroutine back on the frame stack.
389
390 // First take of running frame from the stack, owning a reference.
391 PyFrameObject *return_frame = thread_state->frame;
392 #ifndef __NUITKA_NO_ASSERT__
393 if (return_frame) {
394 assertFrameObject((struct Nuitka_FrameObject *)return_frame);
395 }
396 #endif
397
398 if (coroutine->m_resume_frame) {
399 // It would be nice if our frame were still alive. Nobody had the
400 // right to release it.
401 assertFrameObject(coroutine->m_resume_frame);
402
403 // It's not supposed to be on the top right now.
404 assert(return_frame != &coroutine->m_resume_frame->m_frame);
405
406 thread_state->frame = &coroutine->m_resume_frame->m_frame;
407 coroutine->m_resume_frame = NULL;
408 }
409
410 // Consider it as running.
411 if (coroutine->m_status == status_Unused) {
412 coroutine->m_status = status_Running;
413 }
414
415 // Continue the yielder function while preventing recursion.
416 coroutine->m_running = true;
417
418 // Check for thrown exception, publish it to the coroutine code.
419 if (unlikely(exception_type)) {
420 assert(value == NULL);
421
422 // Transfer exception ownership to published.
423 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
424 }
425
426 if (coroutine->m_frame) {
427 Nuitka_Frame_MarkAsExecuting(coroutine->m_frame);
428 }
429
430 #if _DEBUG_COROUTINE
431 PRINT_COROUTINE_STATUS("Switching to coroutine", coroutine);
432 PRINT_COROUTINE_VALUE("value", value);
433 PRINT_CURRENT_EXCEPTION();
434 PRINT_NEW_LINE();
435 // dumpFrameStack();
436 #endif
437
438 PyObject *yielded;
439
440 if (coroutine->m_yieldfrom == NULL) {
441 yielded = ((coroutine_code)coroutine->m_code)(coroutine, value);
442 } else {
443 yielded = Nuitka_YieldFromCoroutineInitial(coroutine, value);
444 }
445
446 // If the coroutine returns with m_yieldfrom set, it wants us to yield
447 // from that value from now on.
448 while (yielded == NULL && coroutine->m_yieldfrom != NULL) {
449 yielded = Nuitka_YieldFromCoroutineNext(coroutine);
450 }
451
452 if (coroutine->m_frame) {
453 Nuitka_Frame_MarkAsNotExecuting(coroutine->m_frame);
454 }
455
456 coroutine->m_running = false;
457
458 thread_state = PyThreadState_GET();
459
460 // Remove the back frame from coroutine if it's there.
461 if (coroutine->m_frame) {
462 // assert(thread_state->frame == &coroutine->m_frame->m_frame);
463 assertFrameObject(coroutine->m_frame);
464
465 Py_CLEAR(coroutine->m_frame->m_frame.f_back);
466
467 // Remember where to resume from.
468 coroutine->m_resume_frame = (struct Nuitka_FrameObject *)thread_state->frame;
469 }
470
471 // Return back to the frame that called us.
472 thread_state->frame = return_frame;
473
474 #if _DEBUG_COROUTINE
475 PRINT_COROUTINE_STATUS("Returned from coroutine", coroutine);
476 // dumpFrameStack();
477 #endif
478
479 #ifndef __NUITKA_NO_ASSERT__
480 if (return_frame) {
481 assertFrameObject((struct Nuitka_FrameObject *)return_frame);
482 }
483 #endif
484
485 if (yielded == NULL) {
486 #if _DEBUG_COROUTINE
487 PRINT_COROUTINE_STATUS("finishing from yield", coroutine);
488 PRINT_COROUTINE_STRING("closing", closing ? "(closing) " : "(not closing) ");
489 PRINT_STRING("-> finishing sets status_Finished\n");
490 PRINT_COROUTINE_VALUE("return_value", coroutine->m_returned);
491 PRINT_CURRENT_EXCEPTION();
492 PRINT_NEW_LINE();
493 #endif
494 coroutine->m_status = status_Finished;
495
496 if (coroutine->m_frame != NULL) {
497 coroutine->m_frame->m_frame.f_gen = NULL;
498 Py_DECREF(coroutine->m_frame);
499 coroutine->m_frame = NULL;
500 }
501
502 Nuitka_Coroutine_release_closure(coroutine);
503
504 // Create StopIteration if necessary, i.e. return value that is not "None" was
505 // given. TODO: Push this further down the user line, we might be able to avoid
506 // it for some uses, e.g. quick iteration entirely.
507 if (coroutine->m_returned) {
508 if (coroutine->m_returned != Py_None) {
509 Nuitka_SetStopIterationValue(coroutine->m_returned);
510 }
511
512 Py_DECREF(coroutine->m_returned);
513 coroutine->m_returned = NULL;
514
515 #if _DEBUG_COROUTINE
516 PRINT_COROUTINE_STATUS("Return value to exception set", coroutine);
517 PRINT_CURRENT_EXCEPTION();
518 PRINT_NEW_LINE();
519 #endif
520 } else {
521 PyObject *error = GET_ERROR_OCCURRED();
522
523 if (error == NULL) {
524 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
525 } else if (error == PyExc_StopIteration) {
526 PyObject *saved_exception_type, *saved_exception_value;
527 PyTracebackObject *saved_exception_tb;
528
529 FETCH_ERROR_OCCURRED(&saved_exception_type, &saved_exception_value, &saved_exception_tb);
530 NORMALIZE_EXCEPTION(&saved_exception_type, &saved_exception_value, &saved_exception_tb);
531
532 PyErr_Format(PyExc_RuntimeError, "coroutine raised StopIteration");
533
534 FETCH_ERROR_OCCURRED(&exception_type, &exception_value, &exception_tb);
535
536 RAISE_EXCEPTION_WITH_CAUSE(&exception_type, &exception_value, &exception_tb, saved_exception_value);
537
538 CHECK_OBJECT(exception_value);
539 CHECK_OBJECT(saved_exception_value);
540
541 Py_INCREF(saved_exception_value);
542 PyException_SetContext(exception_value, saved_exception_value);
543
544 Py_DECREF(saved_exception_type);
545 Py_XDECREF(saved_exception_tb);
546
547 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
548
549 #if _DEBUG_COROUTINE
550 PRINT_COROUTINE_STATUS("Leave with exception set", coroutine);
551 PRINT_CURRENT_EXCEPTION();
552 PRINT_NEW_LINE();
553 #endif
554 }
555 }
556
557 return NULL;
558 } else {
559 return yielded;
560 }
561 } else {
562 // Release exception if any, we are finished with it and will raise another.
563 Py_XDECREF(exception_type);
564 Py_XDECREF(exception_value);
565 Py_XDECREF(exception_tb);
566
567 /* This is for status_Finished */
568 assert(coroutine->m_status == status_Finished);
569 /* This check got added in Python 3.5.2 only. It's good to do it, but
570 * not fully compatible, therefore guard it.
571 */
572 #if PYTHON_VERSION >= 0x352 || !defined(_NUITKA_FULL_COMPAT)
573 if (closing == false) {
574 #if _DEBUG_COROUTINE
575 PRINT_COROUTINE_STATUS("Finished coroutine sent into -> RuntimeError", coroutine);
576 PRINT_NEW_LINE();
577 #endif
578 PyErr_Format(PyExc_RuntimeError,
579 #if !defined(_NUITKA_FULL_COMPAT)
580 "cannot reuse already awaited compiled_coroutine %S", coroutine->m_qualname
581 #else
582 "cannot reuse already awaited coroutine"
583 #endif
584 );
585 } else
586 #endif
587 {
588 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
589 }
590
591 return NULL;
592 }
593 }
594
Nuitka_Coroutine_send(struct Nuitka_CoroutineObject * coroutine,PyObject * value)595 static PyObject *Nuitka_Coroutine_send(struct Nuitka_CoroutineObject *coroutine, PyObject *value) {
596 CHECK_OBJECT(coroutine);
597 CHECK_OBJECT(value);
598
599 // TODO: Does it release value ?
600 // Py_INCREF(value);
601 PyObject *result = _Nuitka_Coroutine_send(coroutine, value, false, NULL, NULL, NULL);
602
603 if (result == NULL) {
604 if (GET_ERROR_OCCURRED() == NULL) {
605 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
606 }
607 }
608
609 return result;
610 }
611
612 // Note: Used by compiled frames.
_Nuitka_Coroutine_close(struct Nuitka_CoroutineObject * coroutine)613 static bool _Nuitka_Coroutine_close(struct Nuitka_CoroutineObject *coroutine) {
614 #if _DEBUG_COROUTINE
615 PRINT_COROUTINE_STATUS("Enter", coroutine);
616 #endif
617 CHECK_OBJECT(coroutine);
618
619 if (coroutine->m_status == status_Running) {
620 Py_INCREF(PyExc_GeneratorExit);
621
622 PyObject *result = _Nuitka_Coroutine_send(coroutine, NULL, true, PyExc_GeneratorExit, NULL, NULL);
623
624 if (unlikely(result)) {
625 Py_DECREF(result);
626
627 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "coroutine ignored GeneratorExit");
628 return false;
629 } else {
630 PyObject *error = GET_ERROR_OCCURRED();
631 assert(error != NULL);
632
633 if (EXCEPTION_MATCH_GENERATOR(error)) {
634 CLEAR_ERROR_OCCURRED();
635
636 return true;
637 }
638
639 return false;
640 }
641 }
642
643 return true;
644 }
645
Nuitka_Coroutine_close(struct Nuitka_CoroutineObject * coroutine)646 static PyObject *Nuitka_Coroutine_close(struct Nuitka_CoroutineObject *coroutine) {
647 bool r = _Nuitka_Coroutine_close(coroutine);
648
649 if (unlikely(r == false)) {
650 return NULL;
651 } else {
652 Py_INCREF(Py_None);
653 return Py_None;
654 }
655 }
656
657 #if PYTHON_VERSION >= 0x360
658 static bool Nuitka_AsyncgenAsend_Check(PyObject *object);
659 struct Nuitka_AsyncgenAsendObject;
660 static PyObject *_Nuitka_AsyncgenAsend_throw2(struct Nuitka_AsyncgenAsendObject *asyncgen_asend,
661 PyObject *exception_type, PyObject *exception_value,
662 PyTracebackObject *exception_tb);
663 #endif
664
665 static bool _Nuitka_Generator_check_throw2(PyObject **exception_type, PyObject **exception_value,
666 PyTracebackObject **exception_tb);
667
668 // This function is called when yielding to a coroutine through "_Nuitka_YieldFromPassExceptionTo"
669 // and potentially wrapper objects used by generators, or by the throw method itself.
670 // Note:
671 // Exception arguments are passed for ownership and must be released before returning. The
672 // value of exception_type will not be NULL, but the actual exception will not necessarily
673 // be normalized.
_Nuitka_Coroutine_throw2(struct Nuitka_CoroutineObject * coroutine,bool closing,PyObject * exception_type,PyObject * exception_value,PyTracebackObject * exception_tb)674 static PyObject *_Nuitka_Coroutine_throw2(struct Nuitka_CoroutineObject *coroutine, bool closing,
675 PyObject *exception_type, PyObject *exception_value,
676 PyTracebackObject *exception_tb) {
677 CHECK_OBJECT(coroutine);
678 assert(Nuitka_Coroutine_Check((PyObject *)coroutine));
679 CHECK_OBJECT(exception_type);
680 CHECK_OBJECT_X(exception_value);
681 CHECK_OBJECT_X(exception_tb);
682
683 #if _DEBUG_COROUTINE
684 PRINT_COROUTINE_STATUS("Enter", coroutine);
685 PRINT_COROUTINE_STRING("closing", closing ? "(closing) " : "(not closing) ");
686 PRINT_COROUTINE_VALUE("yieldfrom", coroutine->m_yieldfrom);
687 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
688 PRINT_NEW_LINE();
689 #endif
690
691 if (coroutine->m_yieldfrom != NULL) {
692 if (EXCEPTION_MATCH_BOOL_SINGLE(exception_type, PyExc_GeneratorExit)) {
693 // Coroutines need to close the yield_from.
694 coroutine->m_running = 1;
695 bool res = Nuitka_gen_close_iter(coroutine->m_yieldfrom);
696 coroutine->m_running = 0;
697
698 if (res == false) {
699 // Release exception, we are done with it now and pick up the new one.
700 Py_DECREF(exception_type);
701 Py_XDECREF(exception_value);
702 Py_XDECREF(exception_tb);
703
704 FETCH_ERROR_OCCURRED(&exception_type, &exception_value, &exception_tb);
705 }
706
707 // Transferred exception ownership to "_Nuitka_Coroutine_send".
708 return _Nuitka_Coroutine_send(coroutine, NULL, false, exception_type, exception_value, exception_tb);
709 }
710
711 PyObject *ret;
712
713 #if _DEBUG_COROUTINE
714 PRINT_COROUTINE_STATUS("Passing to yielded from", coroutine);
715 PRINT_COROUTINE_VALUE("m_yieldfrom", coroutine->m_yieldfrom);
716 PRINT_NEW_LINE();
717 #endif
718
719 if (PyGen_CheckExact(coroutine->m_yieldfrom) || PyCoro_CheckExact(coroutine->m_yieldfrom)) {
720 PyGenObject *gen = (PyGenObject *)coroutine->m_yieldfrom;
721
722 // Transferred exception ownership to "Nuitka_UncompiledGenerator_throw".
723 coroutine->m_running = 1;
724 ret = Nuitka_UncompiledGenerator_throw(gen, 1, exception_type, exception_value, exception_tb);
725 coroutine->m_running = 0;
726 } else if (Nuitka_Generator_Check(coroutine->m_yieldfrom)) {
727 struct Nuitka_GeneratorObject *gen = ((struct Nuitka_GeneratorObject *)coroutine->m_yieldfrom);
728 // Transferred exception ownership to "_Nuitka_Generator_throw2".
729 coroutine->m_running = 1;
730 ret = _Nuitka_Generator_throw2(gen, exception_type, exception_value, exception_tb);
731 coroutine->m_running = 0;
732 } else if (Nuitka_Coroutine_Check(coroutine->m_yieldfrom)) {
733 struct Nuitka_CoroutineObject *coro = ((struct Nuitka_CoroutineObject *)coroutine->m_yieldfrom);
734 // Transferred exception ownership to "_Nuitka_Coroutine_throw2".
735 coroutine->m_running = 1;
736 ret = _Nuitka_Coroutine_throw2(coro, true, exception_type, exception_value, exception_tb);
737 coroutine->m_running = 0;
738 } else if (Nuitka_CoroutineWrapper_Check(coroutine->m_yieldfrom)) {
739 struct Nuitka_CoroutineObject *coro =
740 ((struct Nuitka_CoroutineWrapperObject *)coroutine->m_yieldfrom)->m_coroutine;
741
742 // Transferred exception ownership to "_Nuitka_Coroutine_throw2".
743 coroutine->m_running = 1;
744 ret = _Nuitka_Coroutine_throw2(coro, true, exception_type, exception_value, exception_tb);
745 coroutine->m_running = 0;
746 #if PYTHON_VERSION >= 0x360
747 } else if (Nuitka_AsyncgenAsend_Check(coroutine->m_yieldfrom)) {
748 struct Nuitka_AsyncgenAsendObject *asyncgen_asend =
749 ((struct Nuitka_AsyncgenAsendObject *)coroutine->m_yieldfrom);
750
751 // Transferred exception ownership to "_Nuitka_AsyncgenAsend_throw2".
752 coroutine->m_running = 1;
753 ret = _Nuitka_AsyncgenAsend_throw2(asyncgen_asend, exception_type, exception_value, exception_tb);
754 coroutine->m_running = 0;
755 #endif
756 } else {
757 PyObject *meth = PyObject_GetAttr(coroutine->m_yieldfrom, const_str_plain_throw);
758 if (unlikely(meth == NULL)) {
759 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
760 // Release exception, we are done with it now.
761 Py_DECREF(exception_type);
762 Py_XDECREF(exception_value);
763 Py_XDECREF(exception_tb);
764
765 return NULL;
766 }
767
768 CLEAR_ERROR_OCCURRED();
769
770 // Passing exception ownership to that code.
771 goto throw_here;
772 }
773
774 CHECK_OBJECT(exception_type);
775
776 #if 0
777 // TODO: Add slow mode traces.
778 PRINT_ITEM(coroutine->m_yieldfrom);
779 PRINT_NEW_LINE();
780 #endif
781 coroutine->m_running = 1;
782 ret = PyObject_CallFunctionObjArgs(meth, exception_type, exception_value, exception_tb, NULL);
783 coroutine->m_running = 0;
784
785 Py_DECREF(meth);
786
787 // Release exception, we are done with it now.
788 Py_DECREF(exception_type);
789 Py_XDECREF(exception_value);
790 Py_XDECREF(exception_tb);
791 }
792
793 if (unlikely(ret == NULL)) {
794 // Return value or exception, not to continue with yielding from.
795 if (coroutine->m_yieldfrom != NULL) {
796 CHECK_OBJECT(coroutine->m_yieldfrom);
797 #if _DEBUG_COROUTINE
798 PRINT_COROUTINE_STATUS("Null return, yield from removal:", coroutine);
799 PRINT_COROUTINE_VALUE("yieldfrom", coroutine->m_yieldfrom);
800 #endif
801 Py_DECREF(coroutine->m_yieldfrom);
802 coroutine->m_yieldfrom = NULL;
803 }
804
805 PyObject *val;
806 if (_PyGen_FetchStopIterationValue(&val) == 0) {
807 CHECK_OBJECT(val);
808
809 #if _DEBUG_COROUTINE
810 PRINT_COROUTINE_STATUS("Sending return value into ourselves", coroutine);
811 PRINT_COROUTINE_VALUE("value", val);
812 PRINT_NEW_LINE();
813 #endif
814
815 ret = _Nuitka_Coroutine_send(coroutine, val, false, NULL, NULL, NULL);
816 } else {
817 #if _DEBUG_COROUTINE
818 PRINT_COROUTINE_STATUS("Sending exception value into ourselves", coroutine);
819 PRINT_CURRENT_EXCEPTION();
820 PRINT_NEW_LINE();
821 #endif
822 ret = _Nuitka_Coroutine_send(coroutine, NULL, false, NULL, NULL, NULL);
823 }
824
825 #if _DEBUG_COROUTINE
826 PRINT_COROUTINE_STATUS("Leave with value/exception from sending into ourselves:", coroutine);
827 PRINT_COROUTINE_STRING("closing", closing ? "(closing) " : "(not closing) ");
828 PRINT_COROUTINE_VALUE("return_value", ret);
829 PRINT_CURRENT_EXCEPTION();
830 PRINT_NEW_LINE();
831 #endif
832 } else {
833 #if _DEBUG_COROUTINE
834 PRINT_COROUTINE_STATUS("Leave with return value:", coroutine);
835 PRINT_COROUTINE_STRING("closing", closing ? "(closing) " : "(not closing) ");
836 PRINT_COROUTINE_VALUE("return_value", ret);
837 PRINT_CURRENT_EXCEPTION();
838 PRINT_NEW_LINE();
839 #endif
840 }
841
842 return ret;
843 }
844
845 throw_here:
846 // We continue to have exception ownership here.
847
848 if (unlikely(_Nuitka_Generator_check_throw2(&exception_type, &exception_value, &exception_tb) == false)) {
849 // Exception was released by _Nuitka_Generator_check_throw2 already.
850 return NULL;
851 }
852
853 if (coroutine->m_status == status_Running) {
854 // Transferred exception ownership to "_Nuitka_Coroutine_send".
855 PyObject *result =
856 _Nuitka_Coroutine_send(coroutine, NULL, false, exception_type, exception_value, exception_tb);
857 return result;
858 } else if (coroutine->m_status == status_Finished) {
859
860 /* This check got added in Python 3.5.2 only. It's good to do it, but
861 * not fully compatible, therefore guard it.
862 */
863 #if PYTHON_VERSION >= 0x352 || !defined(_NUITKA_FULL_COMPAT)
864 if (closing == false) {
865 #if _DEBUG_COROUTINE
866 PRINT_STRING("Finished coroutine thrown into -> RuntimeError\n");
867 PRINT_ITEM(coroutine->m_qualname);
868 PRINT_NEW_LINE();
869 #endif
870 PyErr_Format(PyExc_RuntimeError,
871 #if !defined(_NUITKA_FULL_COMPAT)
872 "cannot reuse already awaited compiled_coroutine %S", coroutine->m_qualname
873 #else
874 "cannot reuse already awaited coroutine"
875 #endif
876 );
877
878 Py_DECREF(exception_type);
879 Py_XDECREF(exception_value);
880 Py_XDECREF(exception_tb);
881
882 return NULL;
883 }
884 #endif
885 // Passing exception to publication.
886 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
887
888 return NULL;
889 } else {
890 if (exception_tb == NULL) {
891 // TODO: Our compiled objects really need a way to store common
892 // stuff in a "shared" part across all instances, and outside of
893 // run time, so we could reuse this.
894 struct Nuitka_FrameObject *frame = MAKE_FUNCTION_FRAME(coroutine->m_code_object, coroutine->m_module, 0);
895 exception_tb = MAKE_TRACEBACK(frame, coroutine->m_code_object->co_firstlineno);
896 Py_DECREF(frame);
897 }
898
899 // Passing exception to publication.
900 RESTORE_ERROR_OCCURRED(exception_type, exception_value, exception_tb);
901
902 #if _DEBUG_COROUTINE
903 PRINT_COROUTINE_STATUS("Finishing from exception", coroutine);
904 PRINT_NEW_LINE();
905 #endif
906
907 coroutine->m_status = status_Finished;
908
909 return NULL;
910 }
911 }
912
Nuitka_Coroutine_throw(struct Nuitka_CoroutineObject * coroutine,PyObject * args)913 static PyObject *Nuitka_Coroutine_throw(struct Nuitka_CoroutineObject *coroutine, PyObject *args) {
914 CHECK_OBJECT(coroutine);
915 CHECK_OBJECT_DEEP(args);
916
917 PyObject *exception_type;
918 PyObject *exception_value = NULL;
919 PyTracebackObject *exception_tb = NULL;
920
921 // This takes no references, that is for us to do.
922 int res = PyArg_UnpackTuple(args, "throw", 1, 3, &exception_type, &exception_value, &exception_tb);
923
924 if (unlikely(res == 0)) {
925 return NULL;
926 }
927
928 #if _DEBUG_COROUTINE
929 PRINT_COROUTINE_STATUS("Enter", coroutine);
930 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
931 PRINT_NEW_LINE();
932 #endif
933
934 // Handing ownership of exception over, we need not release it ourselves
935 Py_INCREF(exception_type);
936 Py_XINCREF(exception_value);
937 Py_XINCREF(exception_tb);
938
939 PyObject *result = _Nuitka_Coroutine_throw2(coroutine, false, exception_type, exception_value, exception_tb);
940
941 if (result == NULL) {
942 if (GET_ERROR_OCCURRED() == NULL) {
943 SET_CURRENT_EXCEPTION_TYPE0(PyExc_StopIteration);
944 }
945 }
946
947 #if _DEBUG_COROUTINE
948 PRINT_COROUTINE_STATUS("Leave", coroutine);
949 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
950 PRINT_COROUTINE_VALUE("return value", result);
951 PRINT_CURRENT_EXCEPTION();
952 #endif
953
954 return result;
955 }
956
Nuitka_Coroutine_tp_repr(struct Nuitka_CoroutineObject * coroutine)957 static PyObject *Nuitka_Coroutine_tp_repr(struct Nuitka_CoroutineObject *coroutine) {
958 CHECK_OBJECT(coroutine);
959 CHECK_OBJECT(coroutine->m_qualname);
960
961 return PyUnicode_FromFormat("<compiled_coroutine object %s at %p>", Nuitka_String_AsString(coroutine->m_qualname),
962 coroutine);
963 }
964
Nuitka_Coroutine_tp_traverse(struct Nuitka_CoroutineObject * coroutine,visitproc visit,void * arg)965 static long Nuitka_Coroutine_tp_traverse(struct Nuitka_CoroutineObject *coroutine, visitproc visit, void *arg) {
966 CHECK_OBJECT(coroutine);
967
968 // TODO: Identify the impact of not visiting owned objects like module and
969 // frame.
970 Py_VISIT(coroutine->m_yieldfrom);
971
972 for (Py_ssize_t i = 0; i < coroutine->m_closure_given; i++) {
973 Py_VISIT(coroutine->m_closure[i]);
974 }
975
976 return 0;
977 }
978
979 static struct Nuitka_CoroutineWrapperObject *free_list_coro_wrappers = NULL;
980 static int free_list_coro_wrappers_count = 0;
981
Nuitka_Coroutine_await(struct Nuitka_CoroutineObject * coroutine)982 static PyObject *Nuitka_Coroutine_await(struct Nuitka_CoroutineObject *coroutine) {
983 CHECK_OBJECT(coroutine);
984
985 #if _DEBUG_COROUTINE
986 PRINT_COROUTINE_STATUS("Enter", coroutine);
987 PRINT_NEW_LINE();
988 #endif
989
990 #if _DEBUG_REFCOUNTS
991 count_active_Nuitka_CoroutineWrapper_Type += 1;
992 count_allocated_Nuitka_CoroutineWrapper_Type += 1;
993 #endif
994
995 struct Nuitka_CoroutineWrapperObject *result;
996
997 allocateFromFreeListFixed(free_list_coro_wrappers, struct Nuitka_CoroutineWrapperObject,
998 Nuitka_CoroutineWrapper_Type);
999
1000 if (unlikely(result == NULL)) {
1001 return NULL;
1002 }
1003
1004 result->m_coroutine = coroutine;
1005 Py_INCREF(result->m_coroutine);
1006
1007 Nuitka_GC_Track(result);
1008
1009 return (PyObject *)result;
1010 }
1011
Nuitka_Coroutine_tp_finalize(struct Nuitka_CoroutineObject * coroutine)1012 static void Nuitka_Coroutine_tp_finalize(struct Nuitka_CoroutineObject *coroutine) {
1013 if (coroutine->m_status != status_Running) {
1014 return;
1015 }
1016
1017 PyObject *save_exception_type, *save_exception_value;
1018 PyTracebackObject *save_exception_tb;
1019 FETCH_ERROR_OCCURRED(&save_exception_type, &save_exception_value, &save_exception_tb);
1020
1021 bool close_result = _Nuitka_Coroutine_close(coroutine);
1022
1023 if (unlikely(close_result == false)) {
1024 PyErr_WriteUnraisable((PyObject *)coroutine);
1025 }
1026
1027 /* Restore the saved exception if any. */
1028 RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
1029 }
1030
1031 #define MAX_COROUTINE_FREE_LIST_COUNT 100
1032 static struct Nuitka_CoroutineObject *free_list_coros = NULL;
1033 static int free_list_coros_count = 0;
1034
Nuitka_Coroutine_tp_dealloc(struct Nuitka_CoroutineObject * coroutine)1035 static void Nuitka_Coroutine_tp_dealloc(struct Nuitka_CoroutineObject *coroutine) {
1036 #if _DEBUG_REFCOUNTS
1037 count_active_Nuitka_Coroutine_Type -= 1;
1038 count_released_Nuitka_Coroutine_Type += 1;
1039 #endif
1040
1041 // Revive temporarily.
1042 assert(Py_REFCNT(coroutine) == 0);
1043 Py_REFCNT(coroutine) = 1;
1044
1045 // Save the current exception, if any, we must preserve it.
1046 PyObject *save_exception_type, *save_exception_value;
1047 PyTracebackObject *save_exception_tb;
1048 FETCH_ERROR_OCCURRED(&save_exception_type, &save_exception_value, &save_exception_tb);
1049
1050 #if _DEBUG_COROUTINE
1051 PRINT_COROUTINE_STATUS("Enter", coroutine);
1052 PRINT_NEW_LINE();
1053 #endif
1054
1055 bool close_result = _Nuitka_Coroutine_close(coroutine);
1056
1057 if (unlikely(close_result == false)) {
1058 PyErr_WriteUnraisable((PyObject *)coroutine);
1059 }
1060
1061 Nuitka_Coroutine_release_closure(coroutine);
1062
1063 // Allow for above code to resurrect the coroutine.
1064 Py_REFCNT(coroutine) -= 1;
1065 if (Py_REFCNT(coroutine) >= 1) {
1066 RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
1067 return;
1068 }
1069
1070 if (coroutine->m_frame) {
1071 coroutine->m_frame->m_frame.f_gen = NULL;
1072 Py_DECREF(coroutine->m_frame);
1073 coroutine->m_frame = NULL;
1074 }
1075
1076 // Now it is safe to release references and memory for it.
1077 Nuitka_GC_UnTrack(coroutine);
1078
1079 if (coroutine->m_weakrefs != NULL) {
1080 PyObject_ClearWeakRefs((PyObject *)coroutine);
1081 assert(!ERROR_OCCURRED());
1082 }
1083
1084 Py_DECREF(coroutine->m_name);
1085 Py_DECREF(coroutine->m_qualname);
1086
1087 /* Put the object into freelist or release to GC */
1088 releaseToFreeList(free_list_coros, coroutine, MAX_COROUTINE_FREE_LIST_COUNT);
1089
1090 RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
1091 }
1092
1093 // TODO: Set "__doc__" automatically for method clones of compiled types from
1094 // the documentation of built-in original type.
1095 static PyMethodDef Nuitka_Coroutine_methods[] = {{"send", (PyCFunction)Nuitka_Coroutine_send, METH_O, NULL},
1096 {"throw", (PyCFunction)Nuitka_Coroutine_throw, METH_VARARGS, NULL},
1097 {"close", (PyCFunction)Nuitka_Coroutine_close, METH_NOARGS, NULL},
1098 {NULL}};
1099
1100 // TODO: Set "__doc__" automatically for method clones of compiled types from
1101 // the documentation of built-in original type.
1102 static PyGetSetDef Nuitka_Coroutine_getsetlist[] = {
1103 {(char *)"__name__", (getter)Nuitka_Coroutine_get_name, (setter)Nuitka_Coroutine_set_name, NULL},
1104 {(char *)"__qualname__", (getter)Nuitka_Coroutine_get_qualname, (setter)Nuitka_Coroutine_set_qualname, NULL},
1105 {(char *)"cr_await", (getter)Nuitka_Coroutine_get_cr_await, (setter)NULL, NULL},
1106 {(char *)"cr_code", (getter)Nuitka_Coroutine_get_code, (setter)Nuitka_Coroutine_set_code, NULL},
1107 {(char *)"cr_frame", (getter)Nuitka_Coroutine_get_frame, (setter)Nuitka_Coroutine_set_frame, NULL},
1108
1109 {NULL}};
1110
1111 static PyMemberDef Nuitka_Coroutine_members[] = {
1112 {(char *)"cr_running", T_BOOL, offsetof(struct Nuitka_CoroutineObject, m_running), READONLY},
1113 #if PYTHON_VERSION >= 0x370
1114 {(char *)"cr_origin", T_OBJECT, offsetof(struct Nuitka_CoroutineObject, m_origin), READONLY},
1115
1116 #endif
1117 {NULL}};
1118
1119 static PyAsyncMethods Nuitka_Coroutine_as_async = {
1120 (unaryfunc)Nuitka_Coroutine_await, /* am_await */
1121 0, /* am_aiter */
1122 0 /* am_anext */
1123 };
1124
1125 PyTypeObject Nuitka_Coroutine_Type = {
1126 PyVarObject_HEAD_INIT(NULL, 0) "compiled_coroutine", /* tp_name */
1127 sizeof(struct Nuitka_CoroutineObject), /* tp_basicsize */
1128 sizeof(struct Nuitka_CellObject *), /* tp_itemsize */
1129 (destructor)Nuitka_Coroutine_tp_dealloc, /* tp_dealloc */
1130 0, /* tp_print */
1131 0, /* tp_getattr */
1132 0, /* tp_setattr */
1133 &Nuitka_Coroutine_as_async, /* tp_as_async */
1134 (reprfunc)Nuitka_Coroutine_tp_repr, /* tp_repr */
1135 0, /* tp_as_number */
1136 0, /* tp_as_sequence */
1137 0, /* tp_as_mapping */
1138 0, /* tp_hash */
1139 0, /* tp_call */
1140 0, /* tp_str */
1141 PyObject_GenericGetAttr, /* tp_getattro */
1142 0, /* tp_setattro */
1143 0, /* tp_as_buffer */
1144 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */
1145 0, /* tp_doc */
1146 (traverseproc)Nuitka_Coroutine_tp_traverse, /* tp_traverse */
1147 0, /* tp_clear */
1148 0, /* tp_richcompare */
1149 offsetof(struct Nuitka_CoroutineObject, m_weakrefs), /* tp_weaklistoffset */
1150 0, /* tp_iter */
1151 0, /* tp_iternext */
1152 Nuitka_Coroutine_methods, /* tp_methods */
1153 Nuitka_Coroutine_members, /* tp_members */
1154 Nuitka_Coroutine_getsetlist, /* tp_getset */
1155 0, /* tp_base */
1156 0, /* tp_dict */
1157 0, /* tp_descr_get */
1158 0, /* tp_descr_set */
1159 0, /* tp_dictoffset */
1160 0, /* tp_init */
1161 0, /* tp_alloc */
1162 0, /* tp_new */
1163 0, /* tp_free */
1164 0, /* tp_is_gc */
1165 0, /* tp_bases */
1166 0, /* tp_mro */
1167 0, /* tp_cache */
1168 0, /* tp_subclasses */
1169 0, /* tp_weaklist */
1170 0, /* tp_del */
1171 0, /* tp_version_tag */
1172 (destructor)Nuitka_Coroutine_tp_finalize, /* tp_finalize */
1173 };
1174
Nuitka_CoroutineWrapper_tp_dealloc(struct Nuitka_CoroutineWrapperObject * cw)1175 static void Nuitka_CoroutineWrapper_tp_dealloc(struct Nuitka_CoroutineWrapperObject *cw) {
1176 Nuitka_GC_UnTrack((PyObject *)cw);
1177
1178 assert(Py_REFCNT(cw) == 0);
1179 Py_REFCNT(cw) = 1;
1180
1181 #if _DEBUG_REFCOUNTS
1182 count_active_Nuitka_CoroutineWrapper_Type -= 1;
1183 count_released_Nuitka_CoroutineWrapper_Type += 1;
1184 #endif
1185 CHECK_OBJECT(cw->m_coroutine);
1186
1187 Py_DECREF(cw->m_coroutine);
1188 cw->m_coroutine = NULL;
1189
1190 assert(Py_REFCNT(cw) == 1);
1191 Py_REFCNT(cw) = 0;
1192
1193 releaseToFreeList(free_list_coro_wrappers, cw, MAX_COROUTINE_FREE_LIST_COUNT);
1194 }
1195
Nuitka_CoroutineWrapper_tp_iternext(struct Nuitka_CoroutineWrapperObject * cw)1196 static PyObject *Nuitka_CoroutineWrapper_tp_iternext(struct Nuitka_CoroutineWrapperObject *cw) {
1197 CHECK_OBJECT(cw);
1198
1199 return Nuitka_Coroutine_send(cw->m_coroutine, Py_None);
1200 }
1201
Nuitka_CoroutineWrapper_tp_traverse(struct Nuitka_CoroutineWrapperObject * cw,visitproc visit,void * arg)1202 static int Nuitka_CoroutineWrapper_tp_traverse(struct Nuitka_CoroutineWrapperObject *cw, visitproc visit, void *arg) {
1203 CHECK_OBJECT(cw);
1204
1205 Py_VISIT((PyObject *)cw->m_coroutine);
1206 return 0;
1207 }
1208
Nuitka_CoroutineWrapper_send(struct Nuitka_CoroutineWrapperObject * cw,PyObject * arg)1209 static PyObject *Nuitka_CoroutineWrapper_send(struct Nuitka_CoroutineWrapperObject *cw, PyObject *arg) {
1210 CHECK_OBJECT(cw);
1211 CHECK_OBJECT(arg);
1212
1213 return Nuitka_Coroutine_send(cw->m_coroutine, arg);
1214 }
1215
Nuitka_CoroutineWrapper_throw(struct Nuitka_CoroutineWrapperObject * cw,PyObject * args)1216 static PyObject *Nuitka_CoroutineWrapper_throw(struct Nuitka_CoroutineWrapperObject *cw, PyObject *args) {
1217 CHECK_OBJECT(cw);
1218 CHECK_OBJECT_DEEP(args);
1219
1220 return Nuitka_Coroutine_throw(cw->m_coroutine, args);
1221 }
1222
Nuitka_CoroutineWrapper_close(struct Nuitka_CoroutineWrapperObject * cw)1223 static PyObject *Nuitka_CoroutineWrapper_close(struct Nuitka_CoroutineWrapperObject *cw) {
1224 CHECK_OBJECT(cw);
1225
1226 return Nuitka_Coroutine_close(cw->m_coroutine);
1227 }
1228
Nuitka_CoroutineWrapper_tp_repr(struct Nuitka_CoroutineWrapperObject * cw)1229 static PyObject *Nuitka_CoroutineWrapper_tp_repr(struct Nuitka_CoroutineWrapperObject *cw) {
1230 CHECK_OBJECT(cw);
1231 CHECK_OBJECT(cw->m_coroutine);
1232 CHECK_OBJECT(cw->m_coroutine->m_qualname);
1233
1234 return PyUnicode_FromFormat("<compiled_coroutine_wrapper object %s at %p>",
1235 Nuitka_String_AsString(cw->m_coroutine->m_qualname), cw);
1236 }
1237
1238 static PyMethodDef Nuitka_CoroutineWrapper_methods[] = {
1239 {"send", (PyCFunction)Nuitka_CoroutineWrapper_send, METH_O, NULL},
1240 {"throw", (PyCFunction)Nuitka_CoroutineWrapper_throw, METH_VARARGS, NULL},
1241 {"close", (PyCFunction)Nuitka_CoroutineWrapper_close, METH_NOARGS, NULL},
1242 {NULL}};
1243
1244 PyTypeObject Nuitka_CoroutineWrapper_Type = {
1245 PyVarObject_HEAD_INIT(NULL, 0) "compiled_coroutine_wrapper",
1246 sizeof(struct Nuitka_CoroutineWrapperObject), /* tp_basicsize */
1247 0, /* tp_itemsize */
1248 (destructor)Nuitka_CoroutineWrapper_tp_dealloc, /* tp_dealloc */
1249 0, /* tp_print */
1250 0, /* tp_getattr */
1251 0, /* tp_setattr */
1252 0, /* tp_as_async */
1253 (reprfunc)Nuitka_CoroutineWrapper_tp_repr, /* tp_repr */
1254 0, /* tp_as_number */
1255 0, /* tp_as_sequence */
1256 0, /* tp_as_mapping */
1257 0, /* tp_hash */
1258 0, /* tp_call */
1259 0, /* tp_str */
1260 PyObject_GenericGetAttr, /* tp_getattro */
1261 0, /* tp_setattro */
1262 0, /* tp_as_buffer */
1263 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1264 0, /* tp_doc */
1265 (traverseproc)Nuitka_CoroutineWrapper_tp_traverse, /* tp_traverse */
1266 0, /* tp_clear */
1267 0, /* tp_richcompare */
1268 0, /* tp_weaklistoffset */
1269 PyObject_SelfIter, /* tp_iter */
1270 (iternextfunc)Nuitka_CoroutineWrapper_tp_iternext, /* tp_iternext */
1271 Nuitka_CoroutineWrapper_methods, /* tp_methods */
1272 0, /* tp_members */
1273 0, /* tp_getset */
1274 0, /* tp_base */
1275 0, /* tp_dict */
1276 0, /* tp_descr_get */
1277 0, /* tp_descr_set */
1278 0, /* tp_dictoffset */
1279 0, /* tp_init */
1280 0, /* tp_alloc */
1281 0, /* tp_new */
1282 0, /* tp_free */
1283 };
1284
1285 #if PYTHON_VERSION >= 0x370
computeCoroutineOrigin(int origin_depth)1286 static PyObject *computeCoroutineOrigin(int origin_depth) {
1287 PyFrameObject *frame = PyEval_GetFrame();
1288
1289 int frame_count = 0;
1290
1291 while (frame != NULL && frame_count < origin_depth) {
1292 frame = frame->f_back;
1293 frame_count += 1;
1294 }
1295
1296 PyObject *cr_origin = PyTuple_New(frame_count);
1297
1298 frame = PyEval_GetFrame();
1299
1300 for (int i = 0; i < frame_count; i++) {
1301 PyObject *frameinfo =
1302 Py_BuildValue("OiO", frame->f_code->co_filename, PyFrame_GetLineNumber(frame), frame->f_code->co_name);
1303
1304 assert(frameinfo);
1305
1306 PyTuple_SET_ITEM(cr_origin, i, frameinfo);
1307
1308 frame = frame->f_back;
1309 }
1310
1311 return cr_origin;
1312 }
1313 #endif
1314
Nuitka_Coroutine_New(coroutine_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)1315 PyObject *Nuitka_Coroutine_New(coroutine_code code, PyObject *module, PyObject *name, PyObject *qualname,
1316 PyCodeObject *code_object, struct Nuitka_CellObject **closure, Py_ssize_t closure_given,
1317 Py_ssize_t heap_storage_size) {
1318 #if _DEBUG_REFCOUNTS
1319 count_active_Nuitka_Coroutine_Type += 1;
1320 count_allocated_Nuitka_Coroutine_Type += 1;
1321 #endif
1322
1323 struct Nuitka_CoroutineObject *result;
1324
1325 // TODO: Change the var part of the type to 1 maybe
1326 Py_ssize_t full_size = closure_given + (heap_storage_size + sizeof(void *) - 1) / sizeof(void *);
1327
1328 // Macro to assign result memory from GC or free list.
1329 allocateFromFreeList(free_list_coros, struct Nuitka_CoroutineObject, Nuitka_Coroutine_Type, full_size);
1330
1331 // For quicker access of generator heap.
1332 result->m_heap_storage = &result->m_closure[closure_given];
1333
1334 result->m_code = (void *)code;
1335
1336 CHECK_OBJECT(module);
1337 result->m_module = module;
1338
1339 CHECK_OBJECT(name);
1340 result->m_name = name;
1341 Py_INCREF(name);
1342
1343 // The "qualname" defaults to NULL for most compact C code.
1344 if (qualname == NULL) {
1345 qualname = name;
1346 }
1347 CHECK_OBJECT(qualname);
1348
1349 result->m_qualname = qualname;
1350 Py_INCREF(qualname);
1351
1352 result->m_yieldfrom = NULL;
1353
1354 memcpy(&result->m_closure[0], closure, closure_given * sizeof(struct Nuitka_CellObject *));
1355 result->m_closure_given = closure_given;
1356
1357 result->m_weakrefs = NULL;
1358
1359 result->m_status = status_Unused;
1360 result->m_running = false;
1361 result->m_awaiting = false;
1362
1363 result->m_yield_return_index = 0;
1364
1365 result->m_returned = NULL;
1366
1367 result->m_frame = NULL;
1368 result->m_code_object = code_object;
1369
1370 result->m_resume_frame = NULL;
1371
1372 #if PYTHON_VERSION >= 0x370
1373 PyThreadState *tstate = PyThreadState_GET();
1374 int origin_depth = tstate->coroutine_origin_tracking_depth;
1375
1376 if (origin_depth == 0) {
1377 result->m_origin = NULL;
1378 } else {
1379 result->m_origin = computeCoroutineOrigin(origin_depth);
1380 }
1381 #endif
1382
1383 #if PYTHON_VERSION >= 0x370
1384 result->m_exc_state.exc_type = NULL;
1385 result->m_exc_state.exc_value = NULL;
1386 result->m_exc_state.exc_traceback = NULL;
1387 #endif
1388
1389 Nuitka_GC_Track(result);
1390 return (PyObject *)result;
1391 }
1392
gen_is_coroutine(PyObject * object)1393 static int gen_is_coroutine(PyObject *object) {
1394 if (PyGen_CheckExact(object)) {
1395 PyCodeObject *code = (PyCodeObject *)((PyGenObject *)object)->gi_code;
1396
1397 if (code->co_flags & CO_ITERABLE_COROUTINE) {
1398 return 1;
1399 }
1400 }
1401
1402 return 0;
1403 }
1404
Nuitka_GetAwaitableIter(PyObject * value)1405 static PyObject *Nuitka_GetAwaitableIter(PyObject *value) {
1406 CHECK_OBJECT(value);
1407
1408 #if _DEBUG_COROUTINE
1409 PRINT_STRING("Nuitka_GetAwaitableIter: Enter ");
1410 PRINT_ITEM(value);
1411 PRINT_NEW_LINE();
1412 #endif
1413
1414 unaryfunc getter = NULL;
1415
1416 if (PyCoro_CheckExact(value) || gen_is_coroutine(value)) {
1417 Py_INCREF(value);
1418 return value;
1419 }
1420
1421 if (Py_TYPE(value)->tp_as_async != NULL) {
1422 getter = Py_TYPE(value)->tp_as_async->am_await;
1423 }
1424
1425 if (getter != NULL) {
1426 PyObject *result = (*getter)(value);
1427
1428 if (result != NULL) {
1429 if (unlikely(PyCoro_CheckExact(result) || gen_is_coroutine(result) || Nuitka_Coroutine_Check(result))) {
1430 Py_DECREF(result);
1431
1432 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_TypeError, "__await__() returned a coroutine");
1433
1434 return NULL;
1435 }
1436
1437 if (unlikely(!HAS_ITERNEXT(result))) {
1438 PyErr_Format(PyExc_TypeError, "__await__() returned non-iterator of type '%s'",
1439 Py_TYPE(result)->tp_name);
1440
1441 Py_DECREF(result);
1442
1443 return NULL;
1444 }
1445 }
1446
1447 return result;
1448 }
1449
1450 PyErr_Format(PyExc_TypeError, "object %s can't be used in 'await' expression", Py_TYPE(value)->tp_name);
1451
1452 return NULL;
1453 }
1454
1455 #if PYTHON_VERSION >= 0x366
FORMAT_AWAIT_ERROR(PyObject * value,int await_kind)1456 static void FORMAT_AWAIT_ERROR(PyObject *value, int await_kind) {
1457 CHECK_OBJECT(value);
1458
1459 if (await_kind == await_enter) {
1460 PyErr_Format(PyExc_TypeError,
1461 "'async with' received an object from __aenter__ that does not implement __await__: %s",
1462 Py_TYPE(value)->tp_name);
1463 } else if (await_kind == await_exit) {
1464 PyErr_Format(PyExc_TypeError,
1465 "'async with' received an object from __aexit__ that does not implement __await__: %s",
1466 Py_TYPE(value)->tp_name);
1467 }
1468
1469 assert(ERROR_OCCURRED());
1470 }
1471 #endif
1472
ASYNC_AWAIT(PyObject * awaitable,int await_kind)1473 PyObject *ASYNC_AWAIT(PyObject *awaitable, int await_kind) {
1474 CHECK_OBJECT(awaitable);
1475
1476 #if _DEBUG_COROUTINE
1477 PRINT_STRING("ASYNC_AWAIT: Enter for awaitable ");
1478 PRINT_STRING(await_kind == await_enter ? "enter" : "exit");
1479 PRINT_STRING(" ");
1480 PRINT_ITEM(awaitable);
1481 PRINT_NEW_LINE();
1482 #endif
1483
1484 PyObject *awaitable_iter = Nuitka_GetAwaitableIter(awaitable);
1485
1486 if (unlikely(awaitable_iter == NULL)) {
1487 #if PYTHON_VERSION >= 0x366
1488 FORMAT_AWAIT_ERROR(awaitable, await_kind);
1489 #endif
1490 return NULL;
1491 }
1492
1493 #if PYTHON_VERSION >= 0x352 || !defined(_NUITKA_FULL_COMPAT)
1494 /* This check got added in Python 3.5.2 only. It's good to do it, but
1495 * not fully compatible, therefore guard it.
1496 */
1497
1498 if (Nuitka_Coroutine_Check(awaitable)) {
1499 struct Nuitka_CoroutineObject *awaited_coroutine = (struct Nuitka_CoroutineObject *)awaitable;
1500
1501 if (awaited_coroutine->m_awaiting) {
1502 Py_DECREF(awaitable_iter);
1503
1504 SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "coroutine is being awaited already");
1505
1506 return NULL;
1507 }
1508 }
1509 #endif
1510
1511 #if _DEBUG_COROUTINE
1512 PRINT_STRING("ASYNC_AWAIT: Result ");
1513 PRINT_ITEM(awaitable);
1514 PRINT_NEW_LINE();
1515 #endif
1516
1517 return awaitable_iter;
1518 }
1519
1520 #if PYTHON_VERSION >= 0x352
1521
1522 /* Our "aiter" wrapper clone */
1523 struct Nuitka_AIterWrapper {
1524 /* Python object folklore: */
1525 PyObject_HEAD;
1526
1527 PyObject *aw_aiter;
1528 };
1529
Nuitka_AIterWrapper_tp_repr(struct Nuitka_AIterWrapper * aw)1530 static PyObject *Nuitka_AIterWrapper_tp_repr(struct Nuitka_AIterWrapper *aw) {
1531 return PyUnicode_FromFormat("<compiled_aiter_wrapper object of %R at %p>", aw->aw_aiter, aw);
1532 }
1533
Nuitka_AIterWrapper_iternext(struct Nuitka_AIterWrapper * aw)1534 static PyObject *Nuitka_AIterWrapper_iternext(struct Nuitka_AIterWrapper *aw) {
1535 CHECK_OBJECT(aw);
1536
1537 #if PYTHON_VERSION < 0x360
1538 SET_CURRENT_EXCEPTION_TYPE0_VALUE0(PyExc_StopIteration, aw->aw_aiter);
1539 #else
1540 if (!PyTuple_Check(aw->aw_aiter) && !PyExceptionInstance_Check(aw->aw_aiter)) {
1541 SET_CURRENT_EXCEPTION_TYPE0_VALUE0(PyExc_StopIteration, aw->aw_aiter);
1542 } else {
1543 PyObject *result = PyObject_CallFunctionObjArgs(PyExc_StopIteration, aw->aw_aiter, NULL);
1544 if (unlikely(result == NULL)) {
1545 return NULL;
1546 }
1547 SET_CURRENT_EXCEPTION_TYPE0_VALUE1(PyExc_StopIteration, result);
1548 }
1549 #endif
1550
1551 return NULL;
1552 }
1553
Nuitka_AIterWrapper_traverse(struct Nuitka_AIterWrapper * aw,visitproc visit,void * arg)1554 static int Nuitka_AIterWrapper_traverse(struct Nuitka_AIterWrapper *aw, visitproc visit, void *arg) {
1555 CHECK_OBJECT(aw);
1556
1557 Py_VISIT((PyObject *)aw->aw_aiter);
1558 return 0;
1559 }
1560
1561 static struct Nuitka_AIterWrapper *free_list_coroutine_aiter_wrappers = NULL;
1562 static int free_list_coroutine_aiter_wrappers_count = 0;
1563
Nuitka_AIterWrapper_dealloc(struct Nuitka_AIterWrapper * aw)1564 static void Nuitka_AIterWrapper_dealloc(struct Nuitka_AIterWrapper *aw) {
1565 #if _DEBUG_REFCOUNTS
1566 count_active_Nuitka_AIterWrapper_Type -= 1;
1567 count_released_Nuitka_AIterWrapper_Type += 1;
1568 #endif
1569
1570 Nuitka_GC_UnTrack((PyObject *)aw);
1571
1572 CHECK_OBJECT(aw->aw_aiter);
1573 Py_DECREF(aw->aw_aiter);
1574
1575 /* Put the object into freelist or release to GC */
1576 releaseToFreeList(free_list_coroutine_aiter_wrappers, aw, MAX_COROUTINE_FREE_LIST_COUNT);
1577 }
1578
1579 static PyAsyncMethods Nuitka_AIterWrapper_as_async = {
1580 PyObject_SelfIter, /* am_await */
1581 0, /* am_aiter */
1582 0 /* am_anext */
1583 };
1584
1585 PyTypeObject Nuitka_AIterWrapper_Type = {
1586 PyVarObject_HEAD_INIT(NULL, 0) "compiled_aiter_wrapper",
1587 sizeof(struct Nuitka_AIterWrapper), /* tp_basicsize */
1588 0, /* tp_itemsize */
1589 (destructor)Nuitka_AIterWrapper_dealloc, /* destructor tp_dealloc */
1590 0, /* tp_print */
1591 0, /* tp_getattr */
1592 0, /* tp_setattr */
1593 &Nuitka_AIterWrapper_as_async, /* tp_as_async */
1594 (reprfunc)Nuitka_AIterWrapper_tp_repr, /* tp_repr */
1595 0, /* tp_as_number */
1596 0, /* tp_as_sequence */
1597 0, /* tp_as_mapping */
1598 0, /* tp_hash */
1599 0, /* tp_call */
1600 0, /* tp_str */
1601 PyObject_GenericGetAttr, /* tp_getattro */
1602 0, /* tp_setattro */
1603 0, /* tp_as_buffer */
1604 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1605 "A wrapper object for '__aiter__' backwards compatibility.",
1606 (traverseproc)Nuitka_AIterWrapper_traverse, /* tp_traverse */
1607 0, /* tp_clear */
1608 0, /* tp_richcompare */
1609 0, /* tp_weaklistoffset */
1610 PyObject_SelfIter, /* tp_iter */
1611 (iternextfunc)Nuitka_AIterWrapper_iternext, /* tp_iternext */
1612 0, /* tp_methods */
1613 0, /* tp_members */
1614 0, /* tp_getset */
1615 0, /* tp_base */
1616 0, /* tp_dict */
1617 0, /* tp_descr_get */
1618 0, /* tp_descr_set */
1619 0, /* tp_dictoffset */
1620 0, /* tp_init */
1621 0, /* tp_alloc */
1622 0, /* tp_new */
1623 0, /* tp_free */
1624 };
1625
Nuitka_AIterWrapper_New(PyObject * aiter)1626 static PyObject *Nuitka_AIterWrapper_New(PyObject *aiter) {
1627 CHECK_OBJECT(aiter);
1628
1629 #if _DEBUG_REFCOUNTS
1630 count_active_Nuitka_AIterWrapper_Type += 1;
1631 count_allocated_Nuitka_AIterWrapper_Type += 1;
1632 #endif
1633 struct Nuitka_AIterWrapper *result;
1634
1635 allocateFromFreeListFixed(free_list_coroutine_aiter_wrappers, struct Nuitka_AIterWrapper, Nuitka_AIterWrapper_Type);
1636
1637 CHECK_OBJECT(aiter);
1638
1639 Py_INCREF(aiter);
1640 result->aw_aiter = aiter;
1641
1642 Nuitka_GC_Track(result);
1643 return (PyObject *)result;
1644 }
1645
1646 #endif
1647
ASYNC_MAKE_ITERATOR(PyObject * value)1648 PyObject *ASYNC_MAKE_ITERATOR(PyObject *value) {
1649 CHECK_OBJECT(value);
1650
1651 #if _DEBUG_COROUTINE
1652 PRINT_STRING("AITER entry:");
1653 PRINT_ITEM(value);
1654
1655 PRINT_NEW_LINE();
1656 #endif
1657
1658 unaryfunc getter = NULL;
1659
1660 if (Py_TYPE(value)->tp_as_async) {
1661 getter = Py_TYPE(value)->tp_as_async->am_aiter;
1662 }
1663
1664 if (unlikely(getter == NULL)) {
1665 PyErr_Format(PyExc_TypeError, "'async for' requires an object with __aiter__ method, got %s",
1666 Py_TYPE(value)->tp_name);
1667
1668 return NULL;
1669 }
1670
1671 PyObject *iter = (*getter)(value);
1672
1673 if (unlikely(iter == NULL)) {
1674 return NULL;
1675 }
1676
1677 #if PYTHON_VERSION >= 0x370
1678 if (unlikely(Py_TYPE(iter)->tp_as_async == NULL || Py_TYPE(iter)->tp_as_async->am_anext == NULL)) {
1679 PyErr_Format(PyExc_TypeError,
1680 "'async for' received an object from __aiter__ that does not implement __anext__: %s",
1681 Py_TYPE(iter)->tp_name);
1682
1683 Py_DECREF(iter);
1684 return NULL;
1685 }
1686 #endif
1687
1688 #if PYTHON_VERSION >= 0x352
1689 /* Starting with Python 3.5.2 it is acceptable to return an async iterator
1690 * directly, instead of an awaitable.
1691 */
1692 if (Py_TYPE(iter)->tp_as_async != NULL && Py_TYPE(iter)->tp_as_async->am_anext != NULL) {
1693 PyObject *wrapper = Nuitka_AIterWrapper_New(iter);
1694 Py_DECREF(iter);
1695
1696 iter = wrapper;
1697 }
1698 #endif
1699
1700 PyObject *awaitable_iter = Nuitka_GetAwaitableIter(iter);
1701
1702 if (unlikely(awaitable_iter == NULL)) {
1703 #if PYTHON_VERSION >= 0x360
1704 _PyErr_FormatFromCause(
1705 #else
1706 PyErr_Format(
1707 #endif
1708 PyExc_TypeError, "'async for' received an invalid object from __aiter__: %s", Py_TYPE(iter)->tp_name);
1709
1710 Py_DECREF(iter);
1711
1712 return NULL;
1713 }
1714
1715 Py_DECREF(iter);
1716
1717 return awaitable_iter;
1718 }
1719
ASYNC_ITERATOR_NEXT(PyObject * value)1720 PyObject *ASYNC_ITERATOR_NEXT(PyObject *value) {
1721 CHECK_OBJECT(value);
1722
1723 #if _DEBUG_COROUTINE
1724 PRINT_STRING("ANEXT entry:");
1725 PRINT_ITEM(value);
1726
1727 PRINT_NEW_LINE();
1728 #endif
1729
1730 unaryfunc getter = NULL;
1731
1732 if (Py_TYPE(value)->tp_as_async) {
1733 getter = Py_TYPE(value)->tp_as_async->am_anext;
1734 }
1735
1736 if (unlikely(getter == NULL)) {
1737 PyErr_Format(PyExc_TypeError, "'async for' requires an iterator with __anext__ method, got %s",
1738 Py_TYPE(value)->tp_name);
1739
1740 return NULL;
1741 }
1742
1743 PyObject *next_value = (*getter)(value);
1744
1745 if (unlikely(next_value == NULL)) {
1746 return NULL;
1747 }
1748
1749 PyObject *awaitable_iter = Nuitka_GetAwaitableIter(next_value);
1750
1751 if (unlikely(awaitable_iter == NULL)) {
1752 #if PYTHON_VERSION >= 0x360
1753 _PyErr_FormatFromCause(
1754 #else
1755 PyErr_Format(
1756 #endif
1757 PyExc_TypeError, "'async for' received an invalid object from __anext__: %s", Py_TYPE(next_value)->tp_name);
1758
1759 Py_DECREF(next_value);
1760
1761 return NULL;
1762 }
1763
1764 Py_DECREF(next_value);
1765
1766 return awaitable_iter;
1767 }
1768
_initCompiledCoroutineTypes(void)1769 static void _initCompiledCoroutineTypes(void) {
1770 PyType_Ready(&Nuitka_Coroutine_Type);
1771 PyType_Ready(&Nuitka_CoroutineWrapper_Type);
1772
1773 #if PYTHON_VERSION >= 0x352
1774 PyType_Ready(&Nuitka_AIterWrapper_Type);
1775 #endif
1776 }
1777
1778 // Chain asyncgen code to coroutine and generator code, as it uses same functions,
1779 // and then we can have some things static if both are in the same compilation unit.
1780
1781 #if PYTHON_VERSION >= 0x360
1782 #include "CompiledAsyncgenType.c"
1783 #endif
1784