Nuitka
The Python compiler
Loading...
Searching...
No Matches
CompiledGeneratorType.c
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
13/* This file is included from another C file, help IDEs to still parse it on its own. */
14#ifdef __IDE_ONLY__
15#include "nuitka/prelude.h"
16#include <structmember.h>
17#endif
18
19#if _DEBUG_REFCOUNTS
20int count_active_Nuitka_Generator_Type;
21int count_allocated_Nuitka_Generator_Type;
22int count_released_Nuitka_Generator_Type;
23#endif
24
25// In a separate file, code to interact with uncompiled generators, that does
26// all the quirks necessary to get those working.
27#include "CompiledGeneratorTypeUncompiledIntegration.c"
28
29// Debugging output tools
30#if _DEBUG_GENERATOR
31NUITKA_MAY_BE_UNUSED static void _PRINT_GENERATOR_STATUS(char const *descriptor, char const *context,
32 struct Nuitka_GeneratorObject *generator) {
33 char const *status;
34
35 switch (generator->m_status) {
36 case status_Finished:
37 status = "(finished)";
38 break;
39 case status_Running:
40 status = "(running)";
41 break;
42 case status_Unused:
43 status = "(unused)";
44 break;
45 default:
46 status = "(ILLEGAL)";
47 break;
48 }
49
50 PRINT_STRING(descriptor);
51 PRINT_STRING(" : ");
52 PRINT_STRING(context);
53 PRINT_STRING(" ");
54 PRINT_ITEM((PyObject *)generator);
55 PRINT_STRING(" ");
56 PRINT_STRING(status);
57 PRINT_STRING(" ");
58 PRINT_REFCOUNT((PyObject *)generator);
59 PRINT_NEW_LINE();
60}
61
62#define PRINT_GENERATOR_STATUS(context, generator) _PRINT_GENERATOR_STATUS(__FUNCTION__, context, generator)
63
64#endif
65
66#if _DEBUG_GENERATOR || _DEBUG_COROUTINE || _DEBUG_ASYNCGEN
67
68NUITKA_MAY_BE_UNUSED static void PRINT_COROUTINE_VALUE(char const *name, PyObject *value) {
69 PRINT_STRING(name);
70 PRINT_STRING("=");
71 PRINT_ITEM(value);
72 if (value) {
73 PRINT_REFCOUNT(value);
74 }
75 PRINT_NEW_LINE();
76}
77
78NUITKA_MAY_BE_UNUSED static void PRINT_COROUTINE_STRING(char const *name, char const *value) {
79 PRINT_STRING(name);
80 PRINT_STRING("=");
81 PRINT_STRING(value);
82 PRINT_NEW_LINE();
83}
84#endif
85
86static void Nuitka_MarkGeneratorAsFinished(struct Nuitka_GeneratorObject *generator) {
87 generator->m_status = status_Finished;
88
89#if PYTHON_VERSION >= 0x3b0
90 if (generator->m_frame) {
91 generator->m_frame->m_frame_state = FRAME_COMPLETED;
92 }
93#endif
94}
95
96static void Nuitka_MarkGeneratorAsRunning(struct Nuitka_GeneratorObject *generator) {
97 generator->m_running = 1;
98
99 if (generator->m_frame) {
100 Nuitka_Frame_MarkAsExecuting(generator->m_frame);
101 }
102}
103
104static void Nuitka_MarkGeneratorAsNotRunning(struct Nuitka_GeneratorObject *generator) {
105 generator->m_running = 0;
106
107 if (generator->m_frame) {
108 Nuitka_Frame_MarkAsNotExecuting(generator->m_frame);
109 }
110}
111
112static PyObject *Nuitka_Generator_tp_repr(struct Nuitka_GeneratorObject *generator) {
113#if PYTHON_VERSION < 0x300
114 return Nuitka_String_FromFormat("<compiled_generator object %s at %p>", Nuitka_String_AsString(generator->m_name),
115 generator);
116#elif PYTHON_VERSION < 0x350
117 return Nuitka_String_FromFormat("<compiled_generator object %U at %p>", generator->m_name, generator);
118
119#else
120 return Nuitka_String_FromFormat("<compiled_generator object %U at %p>", generator->m_qualname, generator);
121#endif
122}
123
124static long Nuitka_Generator_tp_traverse(struct Nuitka_GeneratorObject *generator, visitproc visit, void *arg) {
125 CHECK_OBJECT(generator);
126
127 // TODO: Identify the impact of not visiting owned objects like module.
128#if PYTHON_VERSION >= 0x300
129 Py_VISIT(generator->m_yield_from);
130#endif
131
132 for (Py_ssize_t i = 0; i < generator->m_closure_given; i++) {
133 Py_VISIT(generator->m_closure[i]);
134 }
135
136 Py_VISIT(generator->m_frame);
137
138 return 0;
139}
140
141static void Nuitka_Generator_release_closure(struct Nuitka_GeneratorObject *generator) {
142 for (Py_ssize_t i = 0; i < generator->m_closure_given; i++) {
143 CHECK_OBJECT(generator->m_closure[i]);
144 Py_DECREF(generator->m_closure[i]);
145 }
146
147 generator->m_closure_given = 0;
148}
149
150static PyObject *_Nuitka_CallGeneratorCodeC(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
151 PyObject *send_value) {
152
153#if PYTHON_VERSION < 0x300
154 return ((generator_code)generator->m_code)(tstate, generator, send_value);
155#else
156 struct Nuitka_ExceptionStackItem enter_exception = GET_CURRENT_EXCEPTION(tstate);
157
158#if PYTHON_VERSION < 0x3b0
159 if (generator->m_resume_exception.exception_type != NULL) {
160 SET_CURRENT_EXCEPTION(tstate, &generator->m_resume_exception);
161 }
162#else
163 if (generator->m_resume_exception.exception_value != NULL) {
164 SET_CURRENT_EXCEPTION(tstate, &generator->m_resume_exception);
165 }
166#endif
167
168 PyObject *result = ((generator_code)generator->m_code)(tstate, generator, send_value);
169
170#if PYTHON_VERSION < 0x3b0
171 if (enter_exception.exception_type != NULL) {
172 if (enter_exception.exception_type != Py_None) {
173 if (EXC_TYPE(tstate) != enter_exception.exception_type ||
174 EXC_VALUE(tstate) != enter_exception.exception_value) {
175 generator->m_resume_exception = GET_CURRENT_EXCEPTION(tstate);
176
177 SET_CURRENT_EXCEPTION(tstate, &enter_exception);
178 } else {
179 Py_DECREF(enter_exception.exception_type);
180 Py_XDECREF(enter_exception.exception_value);
181 Py_XDECREF(enter_exception.exception_tb);
182 }
183 } else {
184 Py_DECREF(enter_exception.exception_type);
185 Py_XDECREF(enter_exception.exception_value);
186 Py_XDECREF(enter_exception.exception_tb);
187 }
188 }
189#else
190 if (enter_exception.exception_value != NULL) {
191 if (enter_exception.exception_value != Py_None) {
192 if (EXC_VALUE(tstate) != enter_exception.exception_value) {
193 generator->m_resume_exception = GET_CURRENT_EXCEPTION(tstate);
194
195 SET_CURRENT_EXCEPTION(tstate, &enter_exception);
196 } else {
197 Py_DECREF(enter_exception.exception_value);
198 }
199 } else {
200 Py_DECREF_IMMORTAL(Py_None);
201 }
202 }
203#endif
204
205 return result;
206#endif
207}
208
209#if PYTHON_VERSION >= 0x300
210
211// Note: Shared with coroutines and asyncgen code.
212static PyObject *ERROR_GET_STOP_ITERATION_VALUE(PyThreadState *tstate) {
213 assert(PyErr_ExceptionMatches(PyExc_StopIteration));
214
215 struct Nuitka_ExceptionPreservationItem saved_exception_state;
216 FETCH_ERROR_OCCURRED_STATE(tstate, &saved_exception_state);
217
218#if PYTHON_VERSION < 0x3c0
219 Py_DECREF(saved_exception_state.exception_type);
220 Py_XDECREF(saved_exception_state.exception_tb);
221#endif
222
223 // We own a reference, and we mean to return it.
224 PyObject *exception_value = saved_exception_state.exception_value;
225
226 PyObject *value = NULL;
227
228 if (exception_value != NULL) {
229 if (EXCEPTION_MATCH_BOOL_SINGLE(tstate, exception_value, PyExc_StopIteration)) {
230 value = ((PyStopIterationObject *)exception_value)->value;
231 Py_XINCREF(value);
232 Py_DECREF(exception_value);
233 } else {
234 value = exception_value;
235 }
236 }
237
238 if (value == NULL) {
239 Py_INCREF_IMMORTAL(Py_None);
240 value = Py_None;
241 }
242
243 return value;
244}
245
246static PyObject *Nuitka_CallGeneratorThrowMethod(PyObject *throw_method,
247 struct Nuitka_ExceptionPreservationItem *exception_state) {
248
249 // TODO: Faster call code should be used.
250
251#if PYTHON_VERSION < 0x3c0
252 PyObject *result =
253 PyObject_CallFunctionObjArgs(throw_method, exception_state->exception_type, exception_state->exception_value,
254 exception_state->exception_tb, NULL);
255
256 return result;
257#else
258 // For Python 3.12 or higher, we don't create the type and tb args, code was
259 // always supposed to handle single argument forms and is now.
260 PyObject *result = PyObject_CallFunctionObjArgs(throw_method, exception_state->exception_value, NULL);
261
262 return result;
263#endif
264}
265
266static PyObject *_Nuitka_Generator_throw2(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
267 struct Nuitka_ExceptionPreservationItem *exception_state);
268#if PYTHON_VERSION >= 0x350
269static PyObject *_Nuitka_Coroutine_throw2(PyThreadState *tstate, struct Nuitka_CoroutineObject *coroutine, bool closing,
270 struct Nuitka_ExceptionPreservationItem *exception_state);
271#endif
272
273static PyObject *_Nuitka_YieldFromPassExceptionTo(PyThreadState *tstate, PyObject *value,
274 struct Nuitka_ExceptionPreservationItem *exception_state) {
275 // The yielding generator is being closed, but we also are tasked to
276 // immediately close the currently running sub-generator.
277 if (EXCEPTION_STATE_MATCH_BOOL_SINGLE(tstate, exception_state, PyExc_GeneratorExit)) {
278 PyObject *close_method = PyObject_GetAttr(value, const_str_plain_close);
279
280 if (close_method) {
281 PyObject *close_value = PyObject_Call(close_method, const_tuple_empty, NULL);
282 Py_DECREF(close_method);
283
284 if (unlikely(close_value == NULL)) {
285 // Release exception, we are done with it, raising the one from close instead.
286 RELEASE_ERROR_OCCURRED_STATE(exception_state);
287
288 return NULL;
289 }
290
291 Py_DECREF(close_value);
292 } else {
293 PyObject *error = GET_ERROR_OCCURRED(tstate);
294
295 if (error != NULL && !EXCEPTION_MATCH_BOOL_SINGLE(tstate, error, PyExc_AttributeError)) {
296 PyErr_WriteUnraisable((PyObject *)value);
297 }
298 }
299
300 // Transfer exception ownership to published.
301 RESTORE_ERROR_OCCURRED_STATE(tstate, exception_state);
302
303 return NULL;
304 }
305
306#if NUITKA_UNCOMPILED_THROW_INTEGRATION
307 if (PyGen_CheckExact(value)
308#if PYTHON_VERSION >= 0x350
309 || PyCoro_CheckExact(value)
310#endif
311 ) {
312 PyGenObject *gen = (PyGenObject *)value;
313
314 // Handing exception ownership over.
315 PyObject *result = Nuitka_UncompiledGenerator_throw(tstate, gen, 1, exception_state);
316
317 return result;
318 }
319#endif
320
321 if (Nuitka_Generator_Check(value)) {
322 struct Nuitka_GeneratorObject *gen = ((struct Nuitka_GeneratorObject *)value);
323
324 return _Nuitka_Generator_throw2(tstate, gen, exception_state);
325 }
326
327#if PYTHON_VERSION >= 0x350
328 if (Nuitka_Coroutine_Check(value)) {
329 struct Nuitka_CoroutineObject *coro = ((struct Nuitka_CoroutineObject *)value);
330 // Handing exception ownership over.
331 return _Nuitka_Coroutine_throw2(tstate, coro, true, exception_state);
332 }
333
334 if (Nuitka_CoroutineWrapper_Check(value)) {
335 struct Nuitka_CoroutineObject *coro = ((struct Nuitka_CoroutineWrapperObject *)value)->m_coroutine;
336 // Handing exception ownership over.
337 return _Nuitka_Coroutine_throw2(tstate, coro, true, exception_state);
338 }
339#endif
340
341 PyObject *throw_method = PyObject_GetAttr(value, const_str_plain_throw);
342
343 if (throw_method != NULL) {
344 PyObject *result = Nuitka_CallGeneratorThrowMethod(throw_method, exception_state);
345 Py_DECREF(throw_method);
346
347 // Releasing exception we own.
348 RELEASE_ERROR_OCCURRED_STATE(exception_state);
349
350 return result;
351 } else {
352 assert(HAS_ERROR_OCCURRED(tstate));
353
354 if (EXCEPTION_MATCH_BOOL_SINGLE(tstate, GET_ERROR_OCCURRED(tstate), PyExc_AttributeError)) {
355 // Restoring the exception we own, to be released when handling it.
356 RESTORE_ERROR_OCCURRED_STATE(tstate, exception_state);
357 } else {
358 // Releasing exception we own.
359 RELEASE_ERROR_OCCURRED_STATE(exception_state);
360 }
361
362 return NULL;
363 }
364}
365
366static PyObject *_Nuitka_YieldFromGeneratorCore(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
367 PyObject *yield_from, PyObject *send_value) {
368 // Send iteration value to the sub-generator, which may be a CPython
369 // generator object, something with an iterator next, or a send method,
370 // where the later is only required if values other than "None" need to
371 // be passed in.
372 CHECK_OBJECT(yield_from);
373 assert(send_value != NULL || HAS_ERROR_OCCURRED(tstate));
374
375 PyObject *retval;
376
377#if 0
378 PRINT_STRING("YIELD CORE:");
379 PRINT_ITEM( value );
380 PRINT_ITEM( send_value );
381
382 PRINT_NEW_LINE();
383#endif
384
385 struct Nuitka_ExceptionPreservationItem exception_state;
386 FETCH_ERROR_OCCURRED_STATE(tstate, &exception_state);
387
388 // Exception, was thrown into us, need to send that to sub-generator.
389 if (HAS_EXCEPTION_STATE(&exception_state)) {
390 // Passing ownership of exception fetch to it.
391 retval = _Nuitka_YieldFromPassExceptionTo(tstate, yield_from, &exception_state);
392
393 // TODO: This wants to look at retval most definitely, send_value is going to be NULL.
394 if (unlikely(send_value == NULL)) {
395 PyObject *error = GET_ERROR_OCCURRED(tstate);
396
397 if (error != NULL && EXCEPTION_MATCH_BOOL_SINGLE(tstate, error, PyExc_StopIteration)) {
398 generator->m_returned = ERROR_GET_STOP_ITERATION_VALUE(tstate);
399 assert(!HAS_ERROR_OCCURRED(tstate));
400
401 return NULL;
402 }
403 }
404 } else if (PyGen_CheckExact(yield_from)) {
405 retval = Nuitka_PyGen_Send(tstate, (PyGenObject *)yield_from, Py_None);
406 }
407#if PYTHON_VERSION >= 0x350
408 else if (PyCoro_CheckExact(yield_from)) {
409 retval = Nuitka_PyGen_Send(tstate, (PyGenObject *)yield_from, Py_None);
410 }
411#endif
412 else if (send_value == Py_None && Py_TYPE(yield_from)->tp_iternext != NULL) {
413 retval = Py_TYPE(yield_from)->tp_iternext(yield_from);
414 } else {
415 // Bug compatibility here, before Python3 tuples were unrolled in calls, which is what
416 // PyObject_CallMethod does.
417#if PYTHON_VERSION >= 0x300
418 retval = PyObject_CallMethodObjArgs(yield_from, const_str_plain_send, send_value, NULL);
419#else
420 retval = PyObject_CallMethod(yield_from, (char *)"send", (char *)"O", send_value);
421#endif
422 }
423
424 // Check the sub-generator result
425 if (retval == NULL) {
426 PyObject *error = GET_ERROR_OCCURRED(tstate);
427
428 if (error == NULL) {
429 Py_INCREF_IMMORTAL(Py_None);
430 generator->m_returned = Py_None;
431 } else if (likely(EXCEPTION_MATCH_BOOL_SINGLE(tstate, error, PyExc_StopIteration))) {
432 // The sub-generator has given an exception. In case of
433 // StopIteration, we need to check the value, as it is going to be
434 // the expression value of this "yield from", and we are done. All
435 // other errors, we need to raise.
436 generator->m_returned = ERROR_GET_STOP_ITERATION_VALUE(tstate);
437 assert(!HAS_ERROR_OCCURRED(tstate));
438 }
439
440 return NULL;
441 } else {
442 return retval;
443 }
444}
445
446static PyObject *Nuitka_YieldFromGeneratorCore(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
447 PyObject *send_value) {
448 CHECK_OBJECT(generator);
449 CHECK_OBJECT_X(send_value);
450
451 PyObject *yield_from = generator->m_yield_from;
452 CHECK_OBJECT(yield_from);
453
454 // Need to make it unaccessible while using it.
455 generator->m_yield_from = NULL;
456 PyObject *yielded = _Nuitka_YieldFromGeneratorCore(tstate, generator, yield_from, send_value);
457
458 if (yielded == NULL) {
459 Py_DECREF(yield_from);
460
461 if (generator->m_returned != NULL) {
462 PyObject *yield_from_result = generator->m_returned;
463 generator->m_returned = NULL;
464
465 yielded = _Nuitka_CallGeneratorCodeC(tstate, generator, yield_from_result);
466 } else {
467 assert(HAS_ERROR_OCCURRED(tstate));
468 yielded = _Nuitka_CallGeneratorCodeC(tstate, generator, NULL);
469 }
470
471 } else {
472 generator->m_yield_from = yield_from;
473 }
474
475 return yielded;
476}
477
478static PyObject *Nuitka_YieldFromGeneratorNext(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator) {
479 CHECK_OBJECT(generator);
480
481 // Coroutines are already perfect for yielding from.
482#if PYTHON_VERSION >= 0x350
483 if (PyCoro_CheckExact(generator->m_yield_from) || Nuitka_Coroutine_Check(generator->m_yield_from)) {
484 if (unlikely((generator->m_code_object->co_flags & CO_ITERABLE_COROUTINE) == 0)) {
485 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError,
486 "cannot 'yield from' a coroutine object in a non-coroutine generator");
487 }
488 } else
489#endif
490 {
491 PyObject *new_iterator = MAKE_ITERATOR(tstate, generator->m_yield_from);
492 if (new_iterator != NULL) {
493 Py_DECREF(generator->m_yield_from);
494 generator->m_yield_from = new_iterator;
495 }
496 }
497
498 return Nuitka_YieldFromGeneratorCore(tstate, generator, Py_None);
499}
500
501static PyObject *Nuitka_YieldFromGeneratorInitial(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
502 PyObject *send_value) {
503 PyObject *result = Nuitka_YieldFromGeneratorCore(tstate, generator, send_value);
504
505#if 0
506 PRINT_STRING("RES:");
507 PRINT_ITEM( result );
508 PRINT_NEW_LINE();
509#endif
510
511 return result;
512}
513
514#endif
515
516static void _Nuitka_GeneratorPopFrame(PyThreadState *tstate, Nuitka_ThreadStateFrameType *return_frame) {
517#if PYTHON_VERSION < 0x3b0
518 tstate->frame = return_frame;
519#else
520 CURRENT_TSTATE_INTERPRETER_FRAME(tstate) = return_frame;
521#endif
522
523 PRINT_TOP_FRAME("Generator pop exit gives top frame:");
524}
525
526#if PYTHON_VERSION >= 0x350
527static void RAISE_RUNTIME_ERROR_RAISED_STOP_ITERATION(PyThreadState *tstate, char const *message) {
528
529 struct Nuitka_ExceptionPreservationItem saved_exception_state;
530 FETCH_ERROR_OCCURRED_STATE(tstate, &saved_exception_state);
531
532#if PYTHON_VERSION < 0x3c0
533 NORMALIZE_EXCEPTION_STATE(tstate, &saved_exception_state);
534#endif
535
536 struct Nuitka_ExceptionPreservationItem new_exception_state;
537 SET_EXCEPTION_PRESERVATION_STATE_FROM_TYPE0_STR(tstate, &new_exception_state, PyExc_RuntimeError, message);
538
539#if PYTHON_VERSION < 0x3c0
540 NORMALIZE_EXCEPTION_STATE(tstate, &new_exception_state);
541#endif
542
543 Py_INCREF(saved_exception_state.exception_value);
544 RAISE_EXCEPTION_WITH_CAUSE(tstate, &new_exception_state, saved_exception_state.exception_value);
545
546 Nuitka_Exception_SetContext(new_exception_state.exception_value, saved_exception_state.exception_value);
547
548 RELEASE_ERROR_OCCURRED_STATE_X(&saved_exception_state);
549 RESTORE_ERROR_OCCURRED_STATE(tstate, &new_exception_state);
550}
551#endif
552
553static PyObject *_Nuitka_Generator_send(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
554 PyObject *value, struct Nuitka_ExceptionPreservationItem *exception_state) {
555 CHECK_OBJECT(generator);
556 assert(Nuitka_Generator_Check((PyObject *)generator));
557 CHECK_EXCEPTION_STATE_X(exception_state);
558 CHECK_OBJECT_X(value);
559
560#if _DEBUG_GENERATOR
561 PRINT_GENERATOR_STATUS("Enter", generator);
562 PRINT_COROUTINE_VALUE("value", value);
563 PRINT_EXCEPTION_STATE(exception_state);
564 PRINT_CURRENT_EXCEPTION();
565 PRINT_NEW_LINE();
566#endif
567
568 if (value != NULL) {
569 ASSERT_EMPTY_EXCEPTION_STATE(exception_state);
570 }
571
572 if (generator->m_status != status_Finished) {
573 if (generator->m_running) {
574 Py_XDECREF(value);
575
576 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_ValueError, "generator already executing");
577 return NULL;
578 }
579
580#if PYTHON_VERSION < 0x300
581 PyObject *saved_exception_type = tstate->exc_type;
582 PyObject *saved_exception_value = NULL;
583 PyTracebackObject *saved_exception_traceback = NULL;
584
585 if (saved_exception_type != Py_None && saved_exception_type != NULL) {
586 saved_exception_value = tstate->exc_value;
587 Py_INCREF(saved_exception_type);
588 Py_XINCREF(saved_exception_value);
589 saved_exception_traceback = (PyTracebackObject *)tstate->exc_traceback;
590 Py_XINCREF(saved_exception_traceback);
591 }
592#endif
593
594 // Put the generator back on the frame stack.
595 Nuitka_ThreadStateFrameType *return_frame = _Nuitka_GetThreadStateFrame(tstate);
596
597 if (generator->m_status == status_Unused) {
598 generator->m_status = status_Running;
599
600 Py_XDECREF(value);
601 value = NULL;
602 } else {
603 // Put the generator back on the frame stack.
604 pushFrameStackGeneratorCompiledFrame(tstate, generator->m_frame);
605 }
606
607 // Continue the yielder function while preventing recursion.
608 Nuitka_MarkGeneratorAsRunning(generator);
609
610 // Check for thrown exception, publish it to the generator code.
611 if (unlikely(HAS_EXCEPTION_STATE(exception_state))) {
612 // TODO: Original value is meant here probably.
613 assert(value == NULL);
614
615 // Transfer exception ownership to published.
616 RESTORE_ERROR_OCCURRED_STATE(tstate, exception_state);
617 }
618
619#if _DEBUG_GENERATOR
620 PRINT_GENERATOR_STATUS("Switching to generator", generator);
621 PRINT_COROUTINE_VALUE("value", value);
622 PRINT_CURRENT_EXCEPTION();
623 PRINT_NEW_LINE();
624 // dumpFrameStack();
625#endif
626
627 PyObject *yielded;
628
629#if PYTHON_VERSION >= 0x300
630 if (generator->m_yield_from == NULL) {
631 yielded = _Nuitka_CallGeneratorCodeC(tstate, generator, value);
632 } else {
633 // This does not release the value if any, so we need to do it afterwards.
634 yielded = Nuitka_YieldFromGeneratorInitial(tstate, generator, value);
635 Py_XDECREF(value);
636 }
637#else
638 yielded = _Nuitka_CallGeneratorCodeC(tstate, generator, value);
639#endif
640
641#if PYTHON_VERSION >= 0x300
642 // If the generator returns with m_yield_from set, it wants us to yield
643 // from that value from now on.
644 while (yielded == NULL && generator->m_yield_from != NULL) {
645 yielded = Nuitka_YieldFromGeneratorNext(tstate, generator);
646 }
647#endif
648 Nuitka_MarkGeneratorAsNotRunning(generator);
649
650 // Remove the generator from the frame stack.
651 if (generator->m_frame) {
652 // assert(tstate->frame == &generator->m_frame->m_frame);
653 assertFrameObject(generator->m_frame);
654
655 if (generator->m_frame->m_frame.f_back) {
656 Py_CLEAR(generator->m_frame->m_frame.f_back);
657 }
658 }
659
660 // Return back to the frame that called us.
661 _Nuitka_GeneratorPopFrame(tstate, return_frame);
662
663#if _DEBUG_GENERATOR
664 PRINT_GENERATOR_STATUS("Returned from generator", generator);
665 // dumpFrameStack();
666#endif
667
668 if (yielded == NULL) {
669#if _DEBUG_GENERATOR
670 PRINT_GENERATOR_STATUS("finishing from yield", generator);
671 PRINT_STRING("-> finishing generator sets status_Finished\n");
672 PRINT_COROUTINE_VALUE("return_value", generator->m_returned);
673 PRINT_CURRENT_EXCEPTION();
674 PRINT_NEW_LINE();
675#endif
676 Nuitka_MarkGeneratorAsFinished(generator);
677
678 if (generator->m_frame != NULL) {
679#if PYTHON_VERSION >= 0x300
680 Nuitka_SetFrameGenerator(generator->m_frame, NULL);
681#endif
682 Py_DECREF(generator->m_frame);
683 generator->m_frame = NULL;
684 }
685
686 Nuitka_Generator_release_closure(generator);
687
688#if PYTHON_VERSION < 0x300
689 if (saved_exception_type != NULL && saved_exception_type != Py_None) {
690 Py_DECREF(saved_exception_type);
691 Py_XDECREF(saved_exception_value);
692 Py_XDECREF(saved_exception_traceback);
693 }
694#endif
695
696#if PYTHON_VERSION >= 0x350
697 if (
698#if PYTHON_VERSION < 0x370
699 generator->m_code_object->co_flags & CO_FUTURE_GENERATOR_STOP &&
700#endif
701 GET_ERROR_OCCURRED(tstate) == PyExc_StopIteration) {
702 RAISE_RUNTIME_ERROR_RAISED_STOP_ITERATION(tstate, "generator raised StopIteration");
703
704 return NULL;
705 }
706#endif
707
708 // Create StopIteration if necessary, i.e. return value that is not "None" was
709 // given. TODO: Push this further down the user line, we might be able to avoid
710 // it for some uses, e.g. quick iteration entirely.
711#if PYTHON_VERSION >= 0x300
712 if (generator->m_returned) {
713 if (generator->m_returned != Py_None) {
714 Nuitka_SetStopIterationValue(tstate, generator->m_returned);
715 }
716
717 Py_DECREF(generator->m_returned);
718 generator->m_returned = NULL;
719
720#if _DEBUG_GENERATOR
721 PRINT_GENERATOR_STATUS("Return value to exception set", generator);
722 PRINT_CURRENT_EXCEPTION();
723 PRINT_NEW_LINE();
724#endif
725 }
726#endif
727
728 return NULL;
729 } else {
730#if _NUITKA_MAINTAIN_SYS_EXC_VARS
731 PyObject *old_type = tstate->exc_type;
732 PyObject *old_value = tstate->exc_value;
733 PyTracebackObject *old_tb = (PyTracebackObject *)tstate->exc_traceback;
734
735 // Set sys attributes in the fastest possible way, spell-checker: ignore sysdict
736 PyObject *sys_dict = tstate->interp->sysdict;
737 CHECK_OBJECT(sys_dict);
738
739 if (saved_exception_type != NULL && saved_exception_type != Py_None) {
740 tstate->exc_type = saved_exception_type;
741 tstate->exc_value = saved_exception_value;
742 tstate->exc_traceback = (PyObject *)saved_exception_traceback;
743
744 Py_XDECREF(old_type);
745 Py_XDECREF(old_value);
746 Py_XDECREF(old_tb);
747
748 if (old_type != saved_exception_type) {
749 DICT_SET_ITEM(sys_dict, const_str_plain_exc_type, saved_exception_type);
750 }
751 if (saved_exception_value != old_value) {
752 DICT_SET_ITEM(sys_dict, const_str_plain_exc_value,
753 saved_exception_value ? saved_exception_value : Py_None);
754 }
755 if (saved_exception_traceback != old_tb) {
756 DICT_SET_ITEM(sys_dict, const_str_plain_exc_traceback,
757 saved_exception_traceback ? (PyObject *)saved_exception_traceback : Py_None);
758 }
759 } else {
760 tstate->exc_type = Py_None;
761 tstate->exc_value = Py_None;
762 tstate->exc_traceback = (PyObject *)Py_None;
763
764 Py_INCREF_IMMORTAL(Py_None);
765 Py_INCREF_IMMORTAL(Py_None);
766 Py_INCREF_IMMORTAL(Py_None);
767
768 Py_XDECREF(old_type);
769 Py_XDECREF(old_value);
770 Py_XDECREF(old_tb);
771
772 if (old_type != Py_None) {
773 DICT_SET_ITEM(sys_dict, const_str_plain_exc_type, Py_None);
774 }
775 if (old_value != Py_None) {
776 DICT_SET_ITEM(sys_dict, const_str_plain_exc_value, Py_None);
777 }
778 if (old_tb != (PyTracebackObject *)Py_None) {
779 DICT_SET_ITEM(sys_dict, const_str_plain_exc_traceback, Py_None);
780 }
781 }
782#endif
783
784 return yielded;
785 }
786 } else {
787 Py_XDECREF(value);
788
789 // Release exception if any, we are finished with it and will raise another.
790 RELEASE_ERROR_OCCURRED_STATE_X(exception_state);
791
792 return NULL;
793 }
794}
795
796static PyObject *Nuitka_Generator_send(struct Nuitka_GeneratorObject *generator, PyObject *value) {
797 CHECK_OBJECT(value);
798
799 PyThreadState *tstate = PyThreadState_GET();
800
801 if (generator->m_status == status_Unused && value != Py_None) {
802 // Buggy CPython 3.10 refuses to allow later usage.
803#if PYTHON_VERSION >= 0x3a0 && PYTHON_VERSION < 0x3a2
804 Nuitka_MarkGeneratorAsFinished(generator);
805#endif
806
807 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError,
808 "can't send non-None value to a just-started generator");
809 return NULL;
810 }
811
812 // We need to transfer ownership of the sent value.
813 Py_INCREF(value);
814
815 struct Nuitka_ExceptionPreservationItem exception_state;
816 INIT_ERROR_OCCURRED_STATE(&exception_state);
817
818 PyObject *result = _Nuitka_Generator_send(tstate, generator, value, &exception_state);
819
820 if (result == NULL) {
821 if (HAS_ERROR_OCCURRED(tstate) == false) {
822 SET_CURRENT_EXCEPTION_STOP_ITERATION_EMPTY(tstate);
823 }
824 }
825
826 return result;
827}
828
829static PyObject *Nuitka_Generator_tp_iternext(struct Nuitka_GeneratorObject *generator) {
830#if _DEBUG_GENERATOR
831 PRINT_GENERATOR_STATUS("Enter", generator);
832 PRINT_CURRENT_EXCEPTION();
833 PRINT_NEW_LINE();
834#endif
835
836 PyThreadState *tstate = PyThreadState_GET();
837
838 Py_INCREF_IMMORTAL(Py_None);
839
840 struct Nuitka_ExceptionPreservationItem exception_state;
841 INIT_ERROR_OCCURRED_STATE(&exception_state);
842
843 return _Nuitka_Generator_send(tstate, generator, Py_None, &exception_state);
844}
845
846/* Our own qiter interface, which is for quicker simple loop style iteration,
847 that does not send anything in. */
848PyObject *Nuitka_Generator_qiter(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator, bool *finished) {
849 Py_INCREF_IMMORTAL(Py_None);
850
851 struct Nuitka_ExceptionPreservationItem exception_state;
852 INIT_ERROR_OCCURRED_STATE(&exception_state);
853
854 PyObject *result = _Nuitka_Generator_send(tstate, generator, Py_None, &exception_state);
855
856 if (result == NULL) {
857 if (unlikely(!CHECK_AND_CLEAR_STOP_ITERATION_OCCURRED(tstate))) {
858 *finished = false;
859 return NULL;
860 }
861
862 *finished = true;
863 return NULL;
864 }
865
866 *finished = false;
867 return result;
868}
869
870static bool DROP_ERROR_OCCURRED_GENERATOR_EXIT_OR_STOP_ITERATION(PyThreadState *tstate) {
871 PyObject *error = GET_ERROR_OCCURRED(tstate);
872
873 if (EXCEPTION_MATCH_GENERATOR(tstate, error)) {
874 CLEAR_ERROR_OCCURRED(tstate);
875
876 return true;
877 }
878
879 return false;
880}
881
882// Note: Used by compiled frames.
883static bool _Nuitka_Generator_close(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator) {
884#if _DEBUG_GENERATOR
885 PRINT_GENERATOR_STATUS("Enter", generator);
886#endif
887 CHECK_OBJECT(generator);
888
889 if (generator->m_status == status_Running) {
890 struct Nuitka_ExceptionPreservationItem exception_state;
891 SET_EXCEPTION_PRESERVATION_STATE_FROM_ARGS(tstate, &exception_state, PyExc_GeneratorExit, NULL, NULL);
892
893 PyObject *result = _Nuitka_Generator_send(tstate, generator, NULL, &exception_state);
894
895 if (unlikely(result)) {
896 Py_DECREF(result);
897
898 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_RuntimeError, "generator ignored GeneratorExit");
899 return false;
900 } else {
901 PyObject *error = GET_ERROR_OCCURRED(tstate);
902
903 // StopIteration as exception.
904 if (error == NULL) {
905 return true;
906 }
907
908 // Maybe another acceptable exception for generator exit.
909 return DROP_ERROR_OCCURRED_GENERATOR_EXIT_OR_STOP_ITERATION(tstate);
910 }
911 }
912
913 return true;
914}
915
916static PyObject *Nuitka_Generator_close(struct Nuitka_GeneratorObject *generator, PyObject *unused) {
917 PyThreadState *tstate = PyThreadState_GET();
918
919 bool r = _Nuitka_Generator_close(tstate, generator);
920
921 if (unlikely(r == false)) {
922 return NULL;
923 } else {
924 Py_INCREF_IMMORTAL(Py_None);
925 return Py_None;
926 }
927}
928
929#if PYTHON_VERSION >= 0x3c0
930static bool _Nuitka_Generator_check_throw_args(PyThreadState *tstate, PyObject **exception_type,
931 PyObject **exception_value, PyTracebackObject **exception_tb) {
932 if (*exception_tb == (PyTracebackObject *)Py_None) {
933 *exception_tb = NULL;
934 } else if (*exception_tb != NULL && !PyTraceBack_Check(*exception_tb)) {
935 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError, "throw() third argument must be a traceback object");
936 goto failed_throw;
937 }
938
939 if (PyExceptionClass_Check(*exception_type)) {
940 NORMALIZE_EXCEPTION(tstate, exception_type, exception_value, exception_tb);
941 } else if (PyExceptionInstance_Check(*exception_type)) {
942 if (*exception_value != NULL && *exception_value != Py_None) {
943 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError,
944 "instance exception may not have a separate value");
945 goto failed_throw;
946 }
947
948 // Release old None value and replace it with the object, then set the exception type
949 // from the class. The "None" is known immortal here and needs no refcount correction.
950 *exception_value = *exception_type;
951 *exception_type = PyExceptionInstance_Class(*exception_type);
952 Py_INCREF(*exception_type);
953 } else {
954#if PYTHON_VERSION < 0x300
955 PyErr_Format(PyExc_TypeError, "exceptions must be classes, or instances, not %s",
956 Py_TYPE(*exception_type)->tp_name);
957#else
958 PyErr_Format(PyExc_TypeError, "exceptions must be classes or instances deriving from BaseException, not %s",
959 Py_TYPE(*exception_type)->tp_name);
960#endif
961
962 goto failed_throw;
963 }
964
965 return true;
966
967failed_throw:
968
969 return false;
970}
971#endif
972
973static bool _Nuitka_Generator_make_throw_exception_state(PyThreadState *tstate,
974 struct Nuitka_ExceptionPreservationItem *exception_state,
975 PyObject *exception_type, PyObject *exception_value,
976 PyTracebackObject *exception_tb) {
977
978#if PYTHON_VERSION >= 0x3c0
979 Py_INCREF(exception_type);
980 Py_XINCREF(exception_value);
981 Py_XINCREF(exception_tb);
982
983 if (_Nuitka_Generator_check_throw_args(tstate, &exception_type, &exception_value, &exception_tb) == false) {
984 Py_DECREF(exception_type);
985 Py_XDECREF(exception_value);
986 Py_XDECREF(exception_tb);
987
988 return false;
989 }
990#endif
991
992 SET_EXCEPTION_PRESERVATION_STATE_FROM_ARGS(tstate, exception_state, exception_type, exception_value, exception_tb);
993
994#if PYTHON_VERSION >= 0x3c0
995 Py_DECREF(exception_type);
996 Py_XDECREF(exception_value);
997 Py_XDECREF(exception_tb);
998#endif
999
1000 return true;
1001}
1002
1003// Shared code for checking a thrown exception, coroutines, asyncgen, uncompiled
1004// ones do this too. For pre-3.12, the checking needs to be done late, for 3.12
1005// early, so it's a separate function.
1006static bool _Nuitka_Generator_check_throw(PyThreadState *tstate,
1007 struct Nuitka_ExceptionPreservationItem *exception_state) {
1008 CHECK_EXCEPTION_STATE(exception_state);
1009
1010#if PYTHON_VERSION < 0x3c0
1011 if (exception_state->exception_tb == (PyTracebackObject *)Py_None) {
1012 Py_DECREF(exception_state->exception_tb);
1013 exception_state->exception_tb = NULL;
1014 } else if (exception_state->exception_tb != NULL && !PyTraceBack_Check(exception_state->exception_tb)) {
1015 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError, "throw() third argument must be a traceback object");
1016 goto failed_throw;
1017 }
1018
1019 if (PyExceptionClass_Check(exception_state->exception_type)) {
1020 // TODO: Must not / need not normalize here?
1021 NORMALIZE_EXCEPTION_STATE(tstate, exception_state);
1022 } else if (PyExceptionInstance_Check(exception_state->exception_type)) {
1023 if (exception_state->exception_value != NULL && exception_state->exception_value != Py_None) {
1024 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError,
1025 "instance exception may not have a separate value");
1026 goto failed_throw;
1027 }
1028
1029 // Release old None value and replace it with the object, then set the exception type
1030 // from the class.
1031 Py_XDECREF(exception_state->exception_value);
1032 exception_state->exception_value = exception_state->exception_type;
1033
1034 exception_state->exception_type = PyExceptionInstance_Class(exception_state->exception_type);
1035 Py_INCREF(exception_state->exception_type);
1036 } else {
1037#if PYTHON_VERSION < 0x300
1038 PyErr_Format(PyExc_TypeError, "exceptions must be classes, or instances, not %s",
1039 Py_TYPE(exception_state->exception_type)->tp_name);
1040#else
1041 PyErr_Format(PyExc_TypeError, "exceptions must be classes or instances deriving from BaseException, not %s",
1042 Py_TYPE(exception_state->exception_type)->tp_name);
1043#endif
1044
1045 goto failed_throw;
1046 }
1047
1048#endif
1049 return true;
1050
1051#if PYTHON_VERSION < 0x3c0
1052failed_throw:
1053#endif
1054 // Release exception, we are done with it now.
1055 RELEASE_ERROR_OCCURRED_STATE(exception_state);
1056
1057 return false;
1058}
1059
1060#if PYTHON_VERSION >= 0x300
1061
1062static bool _Nuitka_Generator_close(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator);
1063#if PYTHON_VERSION >= 0x350
1064static bool _Nuitka_Coroutine_close(PyThreadState *tstate, struct Nuitka_CoroutineObject *coroutine);
1065#if PYTHON_VERSION >= 0x360
1066static bool _Nuitka_Asyncgen_close(PyThreadState *tstate, struct Nuitka_AsyncgenObject *asyncgen);
1067#endif
1068#endif
1069
1070// Note: This is also used for coroutines and asyncgen
1071static bool Nuitka_gen_close_iter(PyThreadState *tstate, PyObject *yield_from) {
1072#if _DEBUG_GENERATOR
1073 PRINT_STRING("Nuitka_gen_close_iter: Enter\n");
1074#endif
1075
1076 CHECK_OBJECT(yield_from);
1077
1078 // TODO: Could specialize depending in yield_from type for performance. Many
1079 // times these will be our own ones, or known ones like uncompiled
1080 // generators.
1081 if (Nuitka_Generator_Check(yield_from)) {
1082#if _DEBUG_GENERATOR
1083 PRINT_STRING("Nuitka_gen_close_iter: Defer to _Nuitka_Generator_close\n");
1084#endif
1085 return _Nuitka_Generator_close(tstate, (struct Nuitka_GeneratorObject *)yield_from);
1086 }
1087
1088#if PYTHON_VERSION >= 0x350
1089 if (Nuitka_Coroutine_Check(yield_from)) {
1090#if _DEBUG_GENERATOR
1091 PRINT_STRING("Nuitka_gen_close_iter: Defer to _Nuitka_Coroutine_close\n");
1092#endif
1093 return _Nuitka_Coroutine_close(tstate, (struct Nuitka_CoroutineObject *)yield_from);
1094 }
1095#endif
1096
1097#if PYTHON_VERSION >= 0x360
1098 if (Nuitka_Asyncgen_Check(yield_from)) {
1099#if _DEBUG_GENERATOR
1100 PRINT_STRING("Nuitka_gen_close_iter: Defer to _Nuitka_Asyncgen_close\n");
1101#endif
1102 return _Nuitka_Asyncgen_close(tstate, (struct Nuitka_AsyncgenObject *)yield_from);
1103 }
1104#endif
1105
1106 PyObject *meth = PyObject_GetAttr(yield_from, const_str_plain_close);
1107
1108 if (unlikely(meth == NULL)) {
1109 if (unlikely(!PyErr_ExceptionMatches(PyExc_AttributeError))) {
1110#if _DEBUG_GENERATOR
1111 PRINT_STRING("Nuitka_gen_close_iter: Strange error while looking up close method.\n");
1112#endif
1113 PyErr_WriteUnraisable(yield_from);
1114 }
1115
1116 CLEAR_ERROR_OCCURRED(tstate);
1117
1118#if _DEBUG_GENERATOR
1119 PRINT_STRING("Nuitka_gen_close_iter: Leave, has no close method.\n");
1120#endif
1121 return true;
1122 }
1123
1124 PyObject *retval = CALL_FUNCTION_NO_ARGS(tstate, meth);
1125 Py_DECREF(meth);
1126
1127 if (unlikely(retval == NULL)) {
1128#if _DEBUG_GENERATOR
1129 PRINT_STRING("Nuitka_gen_close_iter: Leave, exception from close.\n");
1130#endif
1131 return false;
1132 }
1133
1134 CHECK_OBJECT(retval);
1135 Py_DECREF(retval);
1136
1137#if _DEBUG_GENERATOR
1138 PRINT_STRING("Nuitka_gen_close_iter: Leave, closed.\n");
1139#endif
1140
1141 return true;
1142}
1143#endif
1144
1145#if PYTHON_VERSION >= 0x360
1146static bool Nuitka_AsyncgenAsend_Check(PyObject *object);
1148static PyObject *_Nuitka_AsyncgenAsend_throw2(PyThreadState *tstate, struct Nuitka_AsyncgenAsendObject *asyncgen_asend,
1149 struct Nuitka_ExceptionPreservationItem *exception_state);
1150#endif
1151
1152static PyObject *_Nuitka_Generator_throw2(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
1153 struct Nuitka_ExceptionPreservationItem *exception_state) {
1154#if _DEBUG_GENERATOR
1155 PRINT_GENERATOR_STATUS("Enter", generator);
1156 PRINT_COROUTINE_VALUE("yield_from", generator->m_yield_from);
1157 PRINT_EXCEPTION_STATE(exception_state);
1158 PRINT_NEW_LINE();
1159#endif
1160
1161 CHECK_OBJECT(generator);
1162 assert(Nuitka_Generator_Check((PyObject *)generator));
1163 CHECK_EXCEPTION_STATE(exception_state);
1164
1165#if PYTHON_VERSION >= 0x300
1166 if (generator->m_yield_from != NULL) {
1167 if (EXCEPTION_STATE_MATCH_BOOL_SINGLE(tstate, exception_state, PyExc_GeneratorExit)) {
1168 // Generators need to close the yield_from.
1169 Nuitka_MarkGeneratorAsRunning(generator);
1170 bool res = Nuitka_gen_close_iter(tstate, generator->m_yield_from);
1171 Nuitka_MarkGeneratorAsNotRunning(generator);
1172
1173 if (res == false) {
1174 // Release exception, we are done with it now and pick up the new one.
1175 RELEASE_ERROR_OCCURRED_STATE(exception_state);
1176
1177 FETCH_ERROR_OCCURRED_STATE(tstate, exception_state);
1178 }
1179
1180 // Transferred exception ownership to "_Nuitka_Generator_send".
1181 return _Nuitka_Generator_send(tstate, generator, NULL, exception_state);
1182 }
1183
1184 PyObject *ret;
1185
1186#if _DEBUG_GENERATOR
1187 PRINT_GENERATOR_STATUS("Passing to yielded from", generator);
1188 PRINT_COROUTINE_VALUE("m_yield_from", generator->m_yield_from);
1189 PRINT_NEW_LINE();
1190#endif
1191
1192 if (Nuitka_Generator_Check(generator->m_yield_from)) {
1193 struct Nuitka_GeneratorObject *gen = ((struct Nuitka_GeneratorObject *)generator->m_yield_from);
1194 // Transferred exception ownership to "_Nuitka_Generator_throw2".
1195 Nuitka_MarkGeneratorAsRunning(generator);
1196 ret = _Nuitka_Generator_throw2(tstate, gen, exception_state);
1197 Nuitka_MarkGeneratorAsNotRunning(generator);
1198#if NUITKA_UNCOMPILED_THROW_INTEGRATION
1199 } else if (PyGen_CheckExact(generator->m_yield_from)) {
1200 PyGenObject *gen = (PyGenObject *)generator->m_yield_from;
1201
1202 // Transferred exception ownership to "Nuitka_UncompiledGenerator_throw".
1203 Nuitka_MarkGeneratorAsRunning(generator);
1204 ret = Nuitka_UncompiledGenerator_throw(tstate, gen, 1, exception_state);
1205 Nuitka_MarkGeneratorAsNotRunning(generator);
1206#endif
1207#if PYTHON_VERSION >= 0x350
1208 } else if (Nuitka_Coroutine_Check(generator->m_yield_from)) {
1209 struct Nuitka_CoroutineObject *coro = ((struct Nuitka_CoroutineObject *)generator->m_yield_from);
1210 // Transferred exception ownership to "_Nuitka_Coroutine_throw2".
1211 Nuitka_MarkGeneratorAsRunning(generator);
1212 ret = _Nuitka_Coroutine_throw2(tstate, coro, true, exception_state);
1213 Nuitka_MarkGeneratorAsNotRunning(generator);
1214 } else if (Nuitka_CoroutineWrapper_Check(generator->m_yield_from)) {
1215 struct Nuitka_CoroutineObject *coro =
1216 ((struct Nuitka_CoroutineWrapperObject *)generator->m_yield_from)->m_coroutine;
1217
1218 // Transferred exception ownership to "_Nuitka_Coroutine_throw2".
1219 Nuitka_MarkGeneratorAsRunning(generator);
1220 ret = _Nuitka_Coroutine_throw2(tstate, coro, true, exception_state);
1221 Nuitka_MarkGeneratorAsNotRunning(generator);
1222#if NUITKA_UNCOMPILED_THROW_INTEGRATION
1223 } else if (PyCoro_CheckExact(generator->m_yield_from)) {
1224 PyGenObject *gen = (PyGenObject *)generator->m_yield_from;
1225
1226 // Transferred exception ownership to "Nuitka_UncompiledGenerator_throw".
1227 Nuitka_MarkGeneratorAsRunning(generator);
1228 ret = Nuitka_UncompiledGenerator_throw(tstate, gen, 1, exception_state);
1229 Nuitka_MarkGeneratorAsNotRunning(generator);
1230#endif
1231#if PYTHON_VERSION >= 0x360
1232 } else if (Nuitka_AsyncgenAsend_Check(generator->m_yield_from)) {
1233 struct Nuitka_AsyncgenAsendObject *asyncgen_asend =
1234 ((struct Nuitka_AsyncgenAsendObject *)generator->m_yield_from);
1235
1236 // Transferred exception ownership to "_Nuitka_AsyncgenAsend_throw2".
1237 Nuitka_MarkGeneratorAsRunning(generator);
1238 ret = _Nuitka_AsyncgenAsend_throw2(tstate, asyncgen_asend, exception_state);
1239 Nuitka_MarkGeneratorAsNotRunning(generator);
1240#endif
1241#endif
1242 } else {
1243 PyObject *meth = PyObject_GetAttr(generator->m_yield_from, const_str_plain_throw);
1244 if (unlikely(meth == NULL)) {
1245 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
1246 // Release exception, we are done with it now.
1247 RELEASE_ERROR_OCCURRED_STATE(exception_state);
1248
1249 return NULL;
1250 }
1251
1252 CLEAR_ERROR_OCCURRED(tstate);
1253
1254 // Passing exception ownership to that code.
1255 goto throw_here;
1256 }
1257
1258 CHECK_EXCEPTION_STATE(exception_state);
1259
1260#if 0
1261 // TODO: Add slow mode traces.
1262 PRINT_ITEM(coroutine->m_yield_from);
1263 PRINT_NEW_LINE();
1264#endif
1265 Nuitka_MarkGeneratorAsRunning(generator);
1266 ret = Nuitka_CallGeneratorThrowMethod(meth, exception_state);
1267 Nuitka_MarkGeneratorAsNotRunning(generator);
1268
1269 Py_DECREF(meth);
1270
1271 // Release exception, we are done with it now.
1272 RELEASE_ERROR_OCCURRED_STATE(exception_state);
1273 }
1274
1275 if (unlikely(ret == NULL)) {
1276 // Return value or exception, not to continue with yielding from.
1277 if (generator->m_yield_from != NULL) {
1278 CHECK_OBJECT(generator->m_yield_from);
1279#if _DEBUG_GENERATOR
1280 PRINT_GENERATOR_STATUS("Null return, yield from removal:", generator);
1281 PRINT_COROUTINE_VALUE("yield_from", generator->m_yield_from);
1282#endif
1283 Py_DECREF(generator->m_yield_from);
1284 generator->m_yield_from = NULL;
1285 }
1286
1287 PyObject *val;
1288 if (Nuitka_PyGen_FetchStopIterationValue(tstate, &val)) {
1289 CHECK_OBJECT(val);
1290
1291#if _DEBUG_GENERATOR
1292 PRINT_GENERATOR_STATUS("Sending return value into ourselves", generator);
1293 PRINT_COROUTINE_VALUE("value", val);
1294 PRINT_NEW_LINE();
1295#endif
1296
1297 struct Nuitka_ExceptionPreservationItem no_exception_state;
1298 INIT_ERROR_OCCURRED_STATE(&no_exception_state);
1299
1300 ret = _Nuitka_Generator_send(tstate, generator, val, &no_exception_state);
1301 } else {
1302#if _DEBUG_GENERATOR
1303 PRINT_GENERATOR_STATUS("Sending exception value into ourselves", generator);
1304 PRINT_CURRENT_EXCEPTION();
1305 PRINT_NEW_LINE();
1306#endif
1307
1308 struct Nuitka_ExceptionPreservationItem no_exception_state;
1309 INIT_ERROR_OCCURRED_STATE(&no_exception_state);
1310
1311 ret = _Nuitka_Generator_send(tstate, generator, NULL, &no_exception_state);
1312 }
1313
1314#if _DEBUG_GENERATOR
1315 PRINT_GENERATOR_STATUS("Leave with value/exception from sending into ourselves:", generator);
1316 PRINT_COROUTINE_VALUE("return_value", ret);
1317 PRINT_CURRENT_EXCEPTION();
1318 PRINT_NEW_LINE();
1319#endif
1320 } else {
1321#if _DEBUG_GENERATOR
1322 PRINT_GENERATOR_STATUS("Leave with return value:", generator);
1323 PRINT_COROUTINE_VALUE("return_value", ret);
1324 PRINT_CURRENT_EXCEPTION();
1325 PRINT_NEW_LINE();
1326#endif
1327 }
1328
1329 return ret;
1330 }
1331
1332throw_here:
1333#endif
1334
1335 // We continue to have exception ownership here.
1336
1337 if (unlikely(_Nuitka_Generator_check_throw(tstate, exception_state) == false)) {
1338 // Exception was released by _Nuitka_Generator_check_throw already.
1339 return NULL;
1340 }
1341
1342 if (generator->m_status == status_Running) {
1343 // Passing exception ownership to _Nuitka_Generator_send
1344 PyObject *result = _Nuitka_Generator_send(tstate, generator, NULL, exception_state);
1345
1346 if (result == NULL) {
1347 if (HAS_ERROR_OCCURRED(tstate) == false) {
1348 SET_CURRENT_EXCEPTION_STOP_ITERATION_EMPTY(tstate);
1349 }
1350 }
1351
1352 return result;
1353 } else if (generator->m_status == status_Finished) {
1354 RESTORE_ERROR_OCCURRED_STATE(tstate, exception_state);
1355
1356 return NULL;
1357 } else {
1358 PyTracebackObject *exception_tb = GET_EXCEPTION_STATE_TRACEBACK(exception_state);
1359
1360 if (exception_tb == NULL) {
1361 // TODO: Our compiled objects really need a way to store common
1362 // stuff in a "shared" part across all instances, and outside of
1363 // run time, so we could reuse this.
1364 struct Nuitka_FrameObject *frame =
1365 MAKE_FUNCTION_FRAME(tstate, generator->m_code_object, generator->m_module, 0);
1366 SET_EXCEPTION_STATE_TRACEBACK(exception_state,
1367 MAKE_TRACEBACK(frame, generator->m_code_object->co_firstlineno));
1368 Py_DECREF(frame);
1369 }
1370
1371 RESTORE_ERROR_OCCURRED_STATE(tstate, exception_state);
1372
1373 Nuitka_MarkGeneratorAsFinished(generator);
1374
1375 return NULL;
1376 }
1377}
1378
1379static PyObject *Nuitka_Generator_throw(struct Nuitka_GeneratorObject *generator, PyObject *args) {
1380 PyObject *exception_type;
1381 PyObject *exception_value = NULL;
1382 PyTracebackObject *exception_tb = NULL;
1383
1384 // This takes no references, that is for us to do.
1385 int res = PyArg_UnpackTuple(args, "throw", 1, 3, &exception_type, &exception_value, &exception_tb);
1386
1387 if (unlikely(res == 0)) {
1388 return NULL;
1389 }
1390
1391 PyThreadState *tstate = PyThreadState_GET();
1392
1393 // Handing ownership of exception over, we need not release it ourselves
1394 struct Nuitka_ExceptionPreservationItem exception_state;
1395 if (_Nuitka_Generator_make_throw_exception_state(tstate, &exception_state, exception_type, exception_value,
1396 exception_tb) == false) {
1397 return NULL;
1398 }
1399
1400 PyObject *result = _Nuitka_Generator_throw2(tstate, generator, &exception_state);
1401
1402 if (result == NULL) {
1403 if (HAS_ERROR_OCCURRED(tstate) == false) {
1404 SET_CURRENT_EXCEPTION_STOP_ITERATION_EMPTY(tstate);
1405 }
1406 }
1407
1408#if _DEBUG_GENERATOR
1409 PRINT_GENERATOR_STATUS("Leave", generator);
1410 PRINT_EXCEPTION(exception_type, exception_value, exception_tb);
1411 PRINT_COROUTINE_VALUE("return value", result);
1412 PRINT_CURRENT_EXCEPTION();
1413#endif
1414
1415 return result;
1416}
1417
1418#if PYTHON_VERSION >= 0x300
1419
1420// Need to integrate with garbage collector to undo finalization.
1421#if PYTHON_VERSION >= 0x300
1422
1423#if PYTHON_VERSION < 0x380
1424#define _PyGC_CLEAR_FINALIZED(o) _PyGC_SET_FINALIZED(o, 0)
1425#elif PYTHON_VERSION < 0x3d0
1426#define _PyGCHead_SET_UNFINALIZED(g) ((g)->_gc_prev &= (~_PyGC_PREV_MASK_FINALIZED))
1427#define _PyGC_CLEAR_FINALIZED(o) _PyGCHead_SET_UNFINALIZED(_Py_AS_GC(o))
1428#endif
1429#endif
1430
1431#if !defined(_PyGC_FINALIZED) && PYTHON_VERSION < 0x3d0
1432#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o))
1433#endif
1434#if !defined(_PyType_IS_GC) && PYTHON_VERSION < 0x3d0
1435#define _PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
1436#endif
1437
1438// Replacement for PyObject_CallFinalizer
1439static void Nuitka_CallFinalizer(PyObject *self) {
1440 PyTypeObject *type = Py_TYPE(self);
1441
1442 // Do not call this otherwise.
1443 assert(type->tp_finalize != NULL);
1444
1445 assert(_PyType_IS_GC(type));
1446 if (_PyGC_FINALIZED(self)) {
1447 return;
1448 }
1449
1450 type->tp_finalize(self);
1451
1452#if PYTHON_VERSION >= 0x380
1453 _PyGC_SET_FINALIZED(self);
1454#else
1455 _PyGC_SET_FINALIZED(self, 1);
1456#endif
1457}
1458
1459// Replacement for PyObject_CallFinalizerFromDealloc
1460static bool Nuitka_CallFinalizerFromDealloc(PyObject *self) {
1461 assert(Py_REFCNT(self) == 0);
1462
1463 // Temporarily resurrect the object, so it can be worked with.
1464 Py_SET_REFCNT(self, 1);
1465
1466 Nuitka_CallFinalizer(self);
1467
1468 assert(Py_REFCNT(self) > 0);
1469
1470 // Undo the temporary resurrection
1471 Py_SET_REFCNT(self, Py_REFCNT(self) - 1);
1472 if (Py_REFCNT(self) == 0) {
1473 return true;
1474 } else {
1475 assert((!_PyType_IS_GC(Py_TYPE(self)) || _PyObject_GC_IS_TRACKED(self)));
1476
1477 return false;
1478 }
1479}
1480
1481static void Nuitka_Generator_tp_finalizer(struct Nuitka_GeneratorObject *generator) {
1482 if (generator->m_status != status_Running) {
1483 return;
1484 }
1485
1486 PyThreadState *tstate = PyThreadState_GET();
1487
1488 struct Nuitka_ExceptionPreservationItem saved_exception_state;
1489 FETCH_ERROR_OCCURRED_STATE(tstate, &saved_exception_state);
1490
1491 bool close_result = _Nuitka_Generator_close(tstate, generator);
1492
1493 if (unlikely(close_result == false)) {
1494 PyErr_WriteUnraisable((PyObject *)generator);
1495 }
1496
1497 // Restore the saved exception if any.
1498 RESTORE_ERROR_OCCURRED_STATE(tstate, &saved_exception_state);
1499}
1500#endif
1501
1502// Freelist setup
1503#define MAX_GENERATOR_FREE_LIST_COUNT 100
1504static struct Nuitka_GeneratorObject *free_list_generators = NULL;
1505static int free_list_generators_count = 0;
1506
1507static void Nuitka_Generator_tp_dealloc(struct Nuitka_GeneratorObject *generator) {
1508#if _DEBUG_REFCOUNTS
1509 count_active_Nuitka_Generator_Type -= 1;
1510 count_released_Nuitka_Generator_Type += 1;
1511#endif
1512
1513 if (generator->m_weakrefs != NULL) {
1514 Nuitka_GC_UnTrack(generator);
1515
1516 // TODO: Avoid API call and make this our own function to reuse the
1517 // pattern of temporarily untracking the value or maybe even to avoid
1518 // the need to do it. It may also be a lot of work to do that though
1519 // and maybe having weakrefs is uncommon.
1520 PyObject_ClearWeakRefs((PyObject *)generator);
1521
1522 Nuitka_GC_Track(generator);
1523 }
1524
1525#if PYTHON_VERSION >= 0x300
1526 if (Nuitka_CallFinalizerFromDealloc((PyObject *)generator) == false) {
1527 return;
1528 }
1529#else
1530 // Revive temporarily.
1531 assert(Py_REFCNT(generator) == 0);
1532 Py_SET_REFCNT(generator, 1);
1533
1534 PyThreadState *tstate = PyThreadState_GET();
1535
1536 // Save the current exception, if any, we must preserve it.
1537 struct Nuitka_ExceptionPreservationItem saved_exception_state;
1538 FETCH_ERROR_OCCURRED_STATE(tstate, &saved_exception_state);
1539
1540 if (generator->m_status == status_Running) {
1541 bool close_result = _Nuitka_Generator_close(tstate, generator);
1542 CHECK_OBJECT(generator);
1543
1544 if (unlikely(close_result == false)) {
1545 PyErr_WriteUnraisable((PyObject *)generator);
1546 }
1547 }
1548
1549 Nuitka_Generator_release_closure(generator);
1550
1551 // Allow for above code to resurrect the generator.
1552 Py_SET_REFCNT(generator, Py_REFCNT(generator) - 1);
1553 if (Py_REFCNT(generator) >= 1) {
1554 return;
1555 }
1556#endif
1557
1558 // Now it is safe to release references and memory for it.
1559 Nuitka_GC_UnTrack(generator);
1560
1561 Nuitka_Generator_release_closure(generator);
1562
1563 if (generator->m_frame != NULL) {
1564#if PYTHON_VERSION >= 0x300
1565 Nuitka_SetFrameGenerator(generator->m_frame, NULL);
1566#endif
1567 Py_DECREF(generator->m_frame);
1568 }
1569
1570 Py_DECREF(generator->m_name);
1571
1572#if PYTHON_VERSION >= 0x350
1573 Py_DECREF(generator->m_qualname);
1574#endif
1575
1576#if PYTHON_VERSION >= 0x300
1577 // TODO: Maybe push this into the freelist code and do
1578 // it on allocation.
1579 _PyGC_CLEAR_FINALIZED((PyObject *)generator);
1580#endif
1581
1582 /* Put the object into free list or release to GC */
1583 releaseToFreeList(free_list_generators, generator, MAX_GENERATOR_FREE_LIST_COUNT);
1584
1585#if PYTHON_VERSION < 0x300
1586 RESTORE_ERROR_OCCURRED_STATE(tstate, &saved_exception_state);
1587#endif
1588}
1589
1590static long Nuitka_Generator_tp_hash(struct Nuitka_GeneratorObject *generator) { return generator->m_counter; }
1591
1592static PyObject *Nuitka_Generator_get_name(PyObject *self, void *data) {
1593 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1594 PyObject *result = generator->m_name;
1595 Py_INCREF(result);
1596 return result;
1597}
1598
1599#if PYTHON_VERSION >= 0x350
1600static int Nuitka_Generator_set_name(PyObject *self, PyObject *value, void *data) {
1601 // Cannot be deleted, not be non-unicode value.
1602 if (unlikely((value == NULL) || !PyUnicode_Check(value))) {
1603 PyThreadState *tstate = PyThreadState_GET();
1604
1605 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError, "__name__ must be set to a string object");
1606 return -1;
1607 }
1608
1609 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1610 PyObject *tmp = generator->m_name;
1611 Py_INCREF(value);
1612 generator->m_name = value;
1613 Py_DECREF(tmp);
1614
1615 return 0;
1616}
1617
1618static PyObject *Nuitka_Generator_get_qualname(PyObject *self, void *data) {
1619 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1620 PyObject *result = generator->m_qualname;
1621 Py_INCREF(result);
1622 return result;
1623}
1624
1625static int Nuitka_Generator_set_qualname(PyObject *self, PyObject *value, void *data) {
1626 // Cannot be deleted, not be non-unicode value.
1627 if (unlikely((value == NULL) || !PyUnicode_Check(value))) {
1628 PyThreadState *tstate = PyThreadState_GET();
1629
1630 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_TypeError, "__qualname__ must be set to a string object");
1631 return -1;
1632 }
1633
1634 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1635 PyObject *tmp = generator->m_qualname;
1636 Py_INCREF(value);
1637 generator->m_qualname = value;
1638 Py_DECREF(tmp);
1639
1640 return 0;
1641}
1642
1643static PyObject *Nuitka_Generator_get_yield_from(PyObject *self, void *data) {
1644 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1645 if (generator->m_yield_from) {
1646 Py_INCREF(generator->m_yield_from);
1647 return generator->m_yield_from;
1648 } else {
1649 Py_INCREF_IMMORTAL(Py_None);
1650 return Py_None;
1651 }
1652}
1653
1654#endif
1655
1656static PyObject *Nuitka_Generator_get_code(PyObject *self, void *data) {
1657 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1658 PyObject *result = (PyObject *)generator->m_code_object;
1659 Py_INCREF(result);
1660 return result;
1661}
1662
1663static int Nuitka_Generator_set_code(PyObject *self, PyObject *value, void *data) {
1664 PyThreadState *tstate = PyThreadState_GET();
1665
1666 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_RuntimeError, "gi_code is not writable in Nuitka");
1667 return -1;
1668}
1669
1670static PyObject *Nuitka_Generator_get_frame(PyObject *self, void *data) {
1671 PyObject *result;
1672
1673 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1674 if (generator->m_frame) {
1675 result = (PyObject *)generator->m_frame;
1676 } else {
1677 result = Py_None;
1678 }
1679
1680 Py_INCREF(result);
1681 return result;
1682}
1683
1684static int Nuitka_Generator_set_frame(PyObject *self, PyObject *value, void *data) {
1685 PyThreadState *tstate = PyThreadState_GET();
1686
1687 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, PyExc_RuntimeError, "gi_frame is not writable in Nuitka");
1688 return -1;
1689}
1690
1691static PyObject *Nuitka_Generator_get_running(PyObject *self, void *data) {
1692 PyObject *result;
1693
1694 struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)self;
1695/* The type of "gi_running" changed in Python3. */
1696#if PYTHON_VERSION < 0x300
1697 result = Nuitka_PyInt_FromLong(generator->m_running);
1698#else
1699 result = BOOL_FROM(generator->m_running != 0);
1700 Py_INCREF_IMMORTAL(result);
1701#endif
1702 return result;
1703}
1704
1705static int Nuitka_Generator_set_running(PyObject *self, PyObject *value, void *data) {
1706#if PYTHON_VERSION < 0x300
1707 PyObject *exception_type = PyExc_TypeError;
1708#else
1709 PyObject *exception_type = PyExc_AttributeError;
1710#endif
1711
1712 PyThreadState *tstate = PyThreadState_GET();
1713
1714#if !defined(_NUITKA_FULL_COMPAT) || PYTHON_VERSION >= 0x3a0
1715 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, exception_type,
1716 "attribute 'gi_running' of 'generator' objects is not writable");
1717#else
1718 SET_CURRENT_EXCEPTION_TYPE0_STR(tstate, exception_type, "readonly attribute");
1719#endif
1720 return -1;
1721}
1722
1723// spell-checker: ignore gi_yieldfrom
1724
1725static PyGetSetDef Nuitka_Generator_tp_getset[] = {
1726#if PYTHON_VERSION < 0x350
1727 {(char *)"__name__", Nuitka_Generator_get_name, NULL, NULL},
1728#else
1729 {(char *)"__name__", Nuitka_Generator_get_name, Nuitka_Generator_set_name, NULL},
1730 {(char *)"__qualname__", Nuitka_Generator_get_qualname, Nuitka_Generator_set_qualname, NULL},
1731 {(char *)"gi_yieldfrom", Nuitka_Generator_get_yield_from, NULL, NULL},
1732#endif
1733 {(char *)"gi_code", Nuitka_Generator_get_code, Nuitka_Generator_set_code, NULL},
1734 {(char *)"gi_frame", Nuitka_Generator_get_frame, Nuitka_Generator_set_frame, NULL},
1735 {(char *)"gi_running", Nuitka_Generator_get_running, Nuitka_Generator_set_running, NULL},
1736
1737 {NULL}};
1738
1739static PyMethodDef Nuitka_Generator_methods[] = {{"send", (PyCFunction)Nuitka_Generator_send, METH_O, NULL},
1740 {"throw", (PyCFunction)Nuitka_Generator_throw, METH_VARARGS, NULL},
1741 {"close", (PyCFunction)Nuitka_Generator_close, METH_NOARGS, NULL},
1742 {NULL}};
1743
1744// This is only used.
1745#if PYTHON_VERSION >= 0x3a0
1746static PyAsyncMethods Nuitka_Generator_as_async = {
1747 NULL, /* am_await */
1748 NULL, /* am_aiter */
1749 NULL, /* am_anext */
1750 // TODO: have this too, (sendfunc)_Nuitka_Generator_am_send
1751 NULL /* am_send */
1752};
1753#endif
1754
1755PyTypeObject Nuitka_Generator_Type = {
1756 PyVarObject_HEAD_INIT(NULL, 0) "compiled_generator", // tp_name
1757 sizeof(struct Nuitka_GeneratorObject), // tp_basicsize
1758 sizeof(struct Nuitka_CellObject *), // tp_itemsize
1759 (destructor)Nuitka_Generator_tp_dealloc, // tp_dealloc
1760 0, // tp_print
1761 0, // tp_getattr
1762 0, // tp_setattr
1763#if PYTHON_VERSION < 0x3a0
1764 0, // tp_as_async
1765#else
1766 &Nuitka_Generator_as_async, // tp_as_async
1767#endif
1768 (reprfunc)Nuitka_Generator_tp_repr, // tp_repr
1769 0, // tp_as_number
1770 0, // tp_as_sequence
1771 0, // tp_as_mapping
1772 (hashfunc)Nuitka_Generator_tp_hash, // tp_hash
1773 0, // tp_call
1774 0, // tp_str
1775 0, // tp_getattro (PyObject_GenericGetAttr)
1776 0, // tp_setattro
1777 0, // tp_as_buffer
1778#if PYTHON_VERSION < 0x300
1779 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
1780#else
1781 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,
1782#endif
1783 // tp_flags
1784 0, // tp_doc
1785 (traverseproc)Nuitka_Generator_tp_traverse, // tp_traverse
1786 0, // tp_clear
1787 0, // tp_richcompare
1788 offsetof(struct Nuitka_GeneratorObject, m_weakrefs), // tp_weaklistoffset
1789 0, // tp_iter (PyObject_SelfIter)
1790 (iternextfunc)Nuitka_Generator_tp_iternext, // tp_iternext
1791 Nuitka_Generator_methods, // tp_methods
1792 NULL, // tp_members
1793 Nuitka_Generator_tp_getset, // tp_getset
1794 0, // tp_base
1795 0, // tp_dict
1796 0, // tp_descr_get
1797 0, // tp_descr_set
1798 0, // tp_dictoffset
1799 0, // tp_init
1800 0, // tp_alloc
1801 0, // tp_new
1802 0, // tp_free
1803 0, // tp_is_gc
1804 0, // tp_bases
1805 0, // tp_mro
1806 0, // tp_cache
1807 0, // tp_subclasses
1808 0, // tp_weaklist
1809 0, // tp_del
1810 0 // tp_version_tag
1811#if PYTHON_VERSION >= 0x300
1812 ,
1813 (destructor)Nuitka_Generator_tp_finalizer // tp_finalize
1814#endif
1815};
1816
1817#if PYTHON_VERSION >= 0x350
1818static void _initCompiledCoroutineTypes();
1819#endif
1820#if PYTHON_VERSION >= 0x360
1821static void _initCompiledAsyncgenTypes();
1822#endif
1823
1824void _initCompiledGeneratorType(void) {
1825 Nuitka_PyType_Ready(&Nuitka_Generator_Type, &PyGen_Type, true, false, true, false, false);
1826
1827 // Be a paranoid subtype of uncompiled function, we want nothing shared.
1828 assert(Nuitka_Generator_Type.tp_doc != PyGen_Type.tp_doc || PyGen_Type.tp_doc == NULL);
1829 assert(Nuitka_Generator_Type.tp_traverse != PyGen_Type.tp_traverse);
1830 assert(Nuitka_Generator_Type.tp_clear != PyGen_Type.tp_clear || PyGen_Type.tp_clear == NULL);
1831 assert(Nuitka_Generator_Type.tp_richcompare != PyGen_Type.tp_richcompare || PyGen_Type.tp_richcompare == NULL);
1832 assert(Nuitka_Generator_Type.tp_iter != PyGen_Type.tp_iter || PyGen_Type.tp_iter == PyObject_SelfIter);
1833 assert(Nuitka_Generator_Type.tp_iternext != PyGen_Type.tp_iternext || PyGen_Type.tp_iternext == NULL);
1834#if PYTHON_VERSION >= 0x350
1835 assert(Nuitka_Generator_Type.tp_as_async != PyGen_Type.tp_as_async || PyGen_Type.tp_as_async == NULL);
1836#endif
1837 assert(Nuitka_Generator_Type.tp_methods != PyGen_Type.tp_methods);
1838 assert(Nuitka_Generator_Type.tp_members != PyGen_Type.tp_members);
1839 assert(Nuitka_Generator_Type.tp_getset != PyGen_Type.tp_getset);
1840 assert(Nuitka_Generator_Type.tp_base != PyGen_Type.tp_base);
1841 assert(Nuitka_Generator_Type.tp_dict != PyGen_Type.tp_dict);
1842 assert(Nuitka_Generator_Type.tp_descr_get != PyGen_Type.tp_descr_get || PyGen_Type.tp_descr_get == NULL);
1843
1844 assert(Nuitka_Generator_Type.tp_descr_set != PyGen_Type.tp_descr_set || PyGen_Type.tp_descr_set == NULL);
1845 assert(Nuitka_Generator_Type.tp_dictoffset != PyGen_Type.tp_dictoffset || PyGen_Type.tp_dictoffset == 0);
1846 // TODO: These get changed and into the same thing, not sure what to compare against, project something
1847 // assert(Nuitka_Generator_Type.tp_init != PyGen_Type.tp_init || PyGen_Type.tp_init == NULL);
1848 // assert(Nuitka_Generator_Type.tp_alloc != PyGen_Type.tp_alloc || PyGen_Type.tp_alloc == NULL);
1849 // assert(Nuitka_Generator_Type.tp_new != PyGen_Type.tp_new || PyGen_Type.tp_new == NULL);
1850 // assert(Nuitka_Generator_Type.tp_free != PyGen_Type.tp_free || PyGen_Type.tp_free == NULL);
1851 assert(Nuitka_Generator_Type.tp_bases != PyGen_Type.tp_bases);
1852 assert(Nuitka_Generator_Type.tp_mro != PyGen_Type.tp_mro);
1853 assert(Nuitka_Generator_Type.tp_cache != PyGen_Type.tp_cache || PyGen_Type.tp_cache == NULL);
1854 assert(Nuitka_Generator_Type.tp_subclasses != PyGen_Type.tp_subclasses || PyGen_Type.tp_cache == NULL);
1855 assert(Nuitka_Generator_Type.tp_weaklist != PyGen_Type.tp_weaklist);
1856 assert(Nuitka_Generator_Type.tp_del != PyGen_Type.tp_del || PyGen_Type.tp_del == NULL);
1857#if PYTHON_VERSION >= 0x300
1858 assert(Nuitka_Generator_Type.tp_finalize != PyGen_Type.tp_finalize || PyGen_Type.tp_finalize == NULL);
1859#endif
1860
1861#if PYTHON_VERSION >= 0x350
1862 // Also initialize coroutines if necessary
1863 _initCompiledCoroutineTypes();
1864#endif
1865
1866#if PYTHON_VERSION >= 0x360
1867 // Also initialize asyncgen if necessary
1868 _initCompiledAsyncgenTypes();
1869#endif
1870}
1871
1872PyObject *Nuitka_Generator_New(generator_code code, PyObject *module, PyObject *name,
1873#if PYTHON_VERSION >= 0x350
1874 PyObject *qualname,
1875#endif
1876 PyCodeObject *code_object, struct Nuitka_CellObject **closure, Py_ssize_t closure_given,
1877 Py_ssize_t heap_storage_size) {
1878#if _DEBUG_REFCOUNTS
1879 count_active_Nuitka_Generator_Type += 1;
1880 count_allocated_Nuitka_Generator_Type += 1;
1881#endif
1882
1883 struct Nuitka_GeneratorObject *result;
1884
1885 // TODO: Change the var part of the type to 1 maybe
1886 Py_ssize_t full_size = closure_given + (heap_storage_size + sizeof(void *) - 1) / sizeof(void *);
1887
1888 // Macro to assign result memory from GC or free list.
1889 allocateFromFreeList(free_list_generators, struct Nuitka_GeneratorObject, Nuitka_Generator_Type, full_size);
1890
1891 // For quicker access of generator heap.
1892 result->m_heap_storage = &result->m_closure[closure_given];
1893
1894 assert(result != NULL);
1895 CHECK_OBJECT(result);
1896
1897 assert(Py_SIZE(result) >= closure_given);
1898
1899 result->m_code = (void *)code;
1900
1901 CHECK_OBJECT(module);
1902 result->m_module = module;
1903
1904 CHECK_OBJECT(name);
1905 result->m_name = name;
1906 Py_INCREF(name);
1907
1908#if PYTHON_VERSION >= 0x350
1909 // The "qualname" defaults to NULL for most compact C code.
1910 if (qualname == NULL) {
1911 qualname = name;
1912 }
1913 CHECK_OBJECT(qualname);
1914
1915 result->m_qualname = qualname;
1916 Py_INCREF(qualname);
1917#endif
1918
1919#if PYTHON_VERSION >= 0x300
1920 result->m_yield_from = NULL;
1921#endif
1922
1923 memcpy(&result->m_closure[0], closure, closure_given * sizeof(struct Nuitka_CellObject *));
1924 result->m_closure_given = closure_given;
1925
1926 result->m_weakrefs = NULL;
1927
1928 result->m_status = status_Unused;
1929 result->m_running = 0;
1930
1931 result->m_yield_return_index = 0;
1932
1933#if PYTHON_VERSION >= 0x300
1934 result->m_returned = NULL;
1935#endif
1936
1937 result->m_frame = NULL;
1938 result->m_code_object = code_object;
1939
1940#if PYTHON_VERSION >= 0x370
1941 result->m_exc_state = Nuitka_ExceptionStackItem_Empty;
1942#endif
1943
1944#if PYTHON_VERSION >= 0x300
1945 result->m_resume_exception = Nuitka_ExceptionStackItem_Empty;
1946#endif
1947
1948 static long Nuitka_Generator_counter = 0;
1949 result->m_counter = Nuitka_Generator_counter++;
1950
1951 Nuitka_GC_Track(result);
1952 return (PyObject *)result;
1953}
1954
1955static PyObject *_EMPTY_GENERATOR_CONTEXT(PyThreadState *tstate, struct Nuitka_GeneratorObject *generator,
1956 PyObject *yield_return_value) {
1957 return NULL;
1958}
1959
1960PyObject *Nuitka_Generator_NewEmpty(PyObject *module, PyObject *name,
1961#if PYTHON_VERSION >= 0x350
1962 PyObject *qualname,
1963#endif
1964 PyCodeObject *code_object, struct Nuitka_CellObject **closure,
1965 Py_ssize_t closure_given) {
1966 return Nuitka_Generator_New(_EMPTY_GENERATOR_CONTEXT, module, name,
1967#if PYTHON_VERSION >= 0x350
1968 qualname,
1969#endif
1970 code_object, closure, closure_given, 0);
1971}
1972
1973// Chain coroutine code to generator code, as it uses same functions, and then we can
1974// have some things static if both are in the same compilation unit. This also loads
1975// the asyncgen for 3.6 and higher.
1976#if PYTHON_VERSION >= 0x350
1977#include "CompiledCoroutineType.c"
1978#endif
1979
1980// Chain frames to generator and asyncgen code, as they need to close them with access
1981// to best functions.
1982#include "CompiledFrameType.c"
1983
1984// Part of "Nuitka", an optimizing Python compiler that is compatible and
1985// integrates with CPython, but also works on its own.
1986//
1987// Licensed under the Apache License, Version 2.0 (the "License");
1988// you may not use this file except in compliance with the License.
1989// You may obtain a copy of the License at
1990//
1991// http://www.apache.org/licenses/LICENSE-2.0
1992//
1993// Unless required by applicable law or agreed to in writing, software
1994// distributed under the License is distributed on an "AS IS" BASIS,
1995// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1996// See the License for the specific language governing permissions and
1997// limitations under the License.
Definition CompiledAsyncgenType.c:1293
Definition compiled_cell.h:14
Definition exceptions.h:712
Definition exceptions.h:222
Definition compiled_frame.h:117
Definition compiled_generator.h:41