Nuitka
The Python compiler
Loading...
Searching...
No Matches
compiled_asyncgen.h
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3#ifndef __NUITKA_COMPILED_ASYNCGEN_H__
4#define __NUITKA_COMPILED_ASYNCGEN_H__
5
6// Compiled async generator type, asyncgen in short.
7
8// Another cornerstone of the integration into CPython. Try to behave as well as
9// normal asyncgen objects do or even better.
10
11#if PYTHON_VERSION >= 0x360
12
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#endif
17
18// The Nuitka_AsyncgenObject is the storage associated with a compiled
19// async generator object instance of which there can be many for each code.
20struct Nuitka_AsyncgenObject {
21 /* Python object folklore: */
22 PyObject_VAR_HEAD
23
24 PyObject *m_name;
25
26 // TODO: Only to make traceback for non-started throw
27 PyObject *m_module;
28
29 PyObject *m_qualname;
30 PyObject *m_yield_from;
31
32 // Weak references are supported for asyncgen objects in CPython.
33 PyObject *m_weakrefs;
34
35 int m_running;
36
37 // When an asyncgen is awaiting, this flag is set.
38 int m_awaiting;
39
40#if PYTHON_VERSION >= 0x380
41 // When an asyncgen is running, this is set
42 int m_running_async;
43#endif
44
45 void *m_code;
46
47 // The parent frame of the asyncgen, if created.
48 struct Nuitka_FrameObject *m_frame;
49
50 PyCodeObject *m_code_object;
51
52 // While yielding, this was the frame currently active, restore when
53 // resuming.
54 Nuitka_ThreadStateFrameType *m_resume_frame;
55
56 // Was it ever used, is it still running, or already finished.
57 Generator_Status m_status;
58
59#if PYTHON_VERSION >= 0x370
60 struct Nuitka_ExceptionStackItem m_exc_state;
61#endif
62
63 // The label index to resume after yield.
64 int m_yield_return_index;
65
66 // The finalizer associated through a hook
67 PyObject *m_finalizer;
68
69 // The hooks were initialized
70 bool m_hooks_init_done;
71
72 // It is closed, and cannot be closed again.
73 bool m_closed;
74
75 // A kind of uuid for the generator object, used in comparisons.
76 long m_counter;
77
78 /* The heap of generator objects at run time. */
79 void *m_heap_storage;
80
81 /* Closure variables given, if any, we reference cells here. The last
82 * part is dynamically allocated, the array size differs per asyncgen
83 * and includes the heap storage.
84 */
85 Py_ssize_t m_closure_given;
86 struct Nuitka_CellObject *m_closure[1];
87};
88
89extern PyTypeObject Nuitka_Asyncgen_Type;
90
91typedef PyObject *(*asyncgen_code)(PyThreadState *tstate, struct Nuitka_AsyncgenObject *, PyObject *);
92
93extern PyObject *Nuitka_Asyncgen_New(asyncgen_code code, PyObject *module, PyObject *name, PyObject *qualname,
94 PyCodeObject *code_object, struct Nuitka_CellObject **closure,
95 Py_ssize_t closure_given, Py_ssize_t heap_storage_size);
96
97static inline bool Nuitka_Asyncgen_Check(PyObject *object) { return Py_TYPE(object) == &Nuitka_Asyncgen_Type; }
98
99static inline void SAVE_ASYNCGEN_EXCEPTION(PyThreadState *tstate, struct Nuitka_AsyncgenObject *asyncgen) {
100 /* Before Python3.7: When yielding from an exception handler in Python3,
101 * the exception preserved to the frame is restored, while the current one
102 * is put as there.
103 *
104 * Python3.7: The exception is preserved in the asyncgen object itself
105 * which has a new "m_exc_state" structure just for that.
106 */
107#if _DEBUG_EXCEPTIONS
108 PRINT_STRING("SAVE_ASYNCGEN_EXCEPTION: Enter\n");
109 PRINT_PUBLISHED_EXCEPTION();
110#endif
111
112#if PYTHON_VERSION < 0x3b0
113 PyObject *saved_exception_type = EXC_TYPE(tstate);
114#endif
115 PyObject *saved_exception_value = EXC_VALUE(tstate);
116#if PYTHON_VERSION < 0x3b0
117 PyTracebackObject *saved_exception_traceback = EXC_TRACEBACK(tstate);
118#endif
119
120#if PYTHON_VERSION < 0x370
121 EXC_TYPE(tstate) = tstate->frame->f_exc_type;
122 EXC_VALUE(tstate) = tstate->frame->f_exc_value;
123 SET_EXC_TRACEBACK(tstate, tstate->frame->f_exc_traceback);
124#else
125#if PYTHON_VERSION < 0x3b0
126 EXC_TYPE(tstate) = asyncgen->m_exc_state.exception_type;
127#endif
128 EXC_VALUE(tstate) = asyncgen->m_exc_state.exception_value;
129#if PYTHON_VERSION < 0x3b0
130 SET_EXC_TRACEBACK(tstate, asyncgen->m_exc_state.exception_tb);
131#endif
132#endif
133
134#if _DEBUG_EXCEPTIONS
135 PRINT_STRING("SAVE_ASYNCGEN_EXCEPTION: Leave\n");
136 PRINT_PUBLISHED_EXCEPTION();
137#endif
138
139#if PYTHON_VERSION < 0x370
140 tstate->frame->f_exc_type = saved_exception_type;
141 tstate->frame->f_exc_value = saved_exception_value;
142 tstate->frame->f_exc_traceback = (PyObject *)saved_exception_traceback;
143#else
144#if PYTHON_VERSION < 0x3b0
145 asyncgen->m_exc_state.exception_type = saved_exception_type;
146#endif
147 asyncgen->m_exc_state.exception_value = saved_exception_value;
148#if PYTHON_VERSION < 0x3b0
149 asyncgen->m_exc_state.exception_tb = (PyTracebackObject *)saved_exception_traceback;
150#endif
151#endif
152}
153
154static inline void RESTORE_ASYNCGEN_EXCEPTION(PyThreadState *tstate, struct Nuitka_AsyncgenObject *asyncgen) {
155 // When returning from yield, the exception of the frame is preserved, and
156 // the one that enters should be there.
157
158#if PYTHON_VERSION < 0x3b0
159 PyObject *saved_exception_type = EXC_TYPE(tstate);
160#endif
161 PyObject *saved_exception_value = EXC_VALUE(tstate);
162#if PYTHON_VERSION < 0x3b0
163 PyTracebackObject *saved_exception_traceback = EXC_TRACEBACK(tstate);
164#endif
165
166#if _DEBUG_EXCEPTIONS
167 PRINT_STRING("RESTORE_ASYNCGEN_EXCEPTION: Enter\n");
168#if PYTHON_VERSION < 0x3b0
169 PRINT_EXCEPTION(saved_exception_type, saved_exception_value, saved_exception_traceback);
170#else
171 _PRINT_EXCEPTION1(saved_exception_value);
172#endif
173#endif
174
175#if PYTHON_VERSION < 0x370
176 EXC_TYPE(tstate) = tstate->frame->f_exc_type;
177 EXC_VALUE(tstate) = tstate->frame->f_exc_value;
178 SET_EXC_TRACEBACK(tstate, tstate->frame->f_exc_traceback);
179
180 tstate->frame->f_exc_type = saved_exception_type;
181 tstate->frame->f_exc_value = saved_exception_value;
182 tstate->frame->f_exc_traceback = (PyObject *)saved_exception_traceback;
183#else
184#if PYTHON_VERSION < 0x3b0
185 EXC_TYPE(tstate) = asyncgen->m_exc_state.exception_type;
186#endif
187 EXC_VALUE(tstate) = asyncgen->m_exc_state.exception_value;
188#if PYTHON_VERSION < 0x3b0
189 SET_EXC_TRACEBACK(tstate, asyncgen->m_exc_state.exception_tb);
190#endif
191
192#if PYTHON_VERSION < 0x3b0
193 asyncgen->m_exc_state.exception_type = saved_exception_type;
194#endif
195 asyncgen->m_exc_state.exception_value = saved_exception_value;
196#if PYTHON_VERSION < 0x3b0
197 asyncgen->m_exc_state.exception_tb = (PyTracebackObject *)saved_exception_traceback;
198#endif
199#endif
200
201#if _DEBUG_EXCEPTIONS
202 PRINT_STRING("RESTORE_ASYNCGEN_EXCEPTION: Leave\n");
203 PRINT_PUBLISHED_EXCEPTION();
204#endif
205
206#if PYTHON_VERSION < 0x3b0
207 CHECK_OBJECT_X(EXC_TYPE(tstate));
208#endif
209 CHECK_OBJECT_X(EXC_VALUE(tstate));
210#if PYTHON_VERSION < 0x3b0
211 CHECK_OBJECT_X(EXC_TRACEBACK(tstate));
212#endif
213}
214
215NUITKA_MAY_BE_UNUSED static void STORE_ASYNCGEN_EXCEPTION(PyThreadState *tstate,
216 struct Nuitka_AsyncgenObject *asyncgen) {
217
218#if PYTHON_VERSION < 0x3b0
219 EXC_TYPE_F(asyncgen) = EXC_TYPE(tstate);
220 if (EXC_TYPE_F(asyncgen) == Py_None) {
221 EXC_TYPE_F(asyncgen) = NULL;
222 }
223 Py_XINCREF(EXC_TYPE_F(asyncgen));
224 assert(EXC_TYPE_F(asyncgen) == NULL);
225#endif
226 EXC_VALUE_F(asyncgen) = EXC_VALUE(tstate);
227 Py_XINCREF(EXC_VALUE_F(asyncgen));
228#if PYTHON_VERSION < 0x3b0
229 ASSIGN_EXC_TRACEBACK_F(asyncgen, EXC_TRACEBACK(tstate));
230 Py_XINCREF(EXC_TRACEBACK_F(asyncgen));
231#endif
232}
233
234NUITKA_MAY_BE_UNUSED static void DROP_ASYNCGEN_EXCEPTION(struct Nuitka_AsyncgenObject *asyncgen) {
235#if PYTHON_VERSION < 0x3b0
236 Py_CLEAR(EXC_TYPE_F(asyncgen));
237#endif
238 Py_CLEAR(EXC_VALUE_F(asyncgen));
239#if PYTHON_VERSION < 0x3b0
240 Py_CLEAR(EXC_TRACEBACK_F(asyncgen));
241#endif
242}
243
244// For reference count debugging.
245#if _DEBUG_REFCOUNTS
246extern int count_active_Nuitka_Asyncgen_Type;
247extern int count_allocated_Nuitka_Asyncgen_Type;
248extern int count_released_Nuitka_Asyncgen_Type;
249
250extern int count_active_Nuitka_AsyncgenValueWrapper_Type;
251extern int count_allocated_Nuitka_AsyncgenValueWrapper_Type;
252extern int count_released_Nuitka_AsyncgenValueWrapper_Type;
253
254extern int count_active_Nuitka_AsyncgenAsend_Type;
255extern int count_allocated_Nuitka_AsyncgenAsend_Type;
256extern int count_released_Nuitka_AsyncgenAsend_Type;
257
258extern int count_active_Nuitka_AsyncgenAthrow_Type;
259extern int count_allocated_Nuitka_AsyncgenAthrow_Type;
260extern int count_released_Nuitka_AsyncgenAthrow_Type;
261
262#endif
263
264#endif
265
266#endif
267
268// Part of "Nuitka", an optimizing Python compiler that is compatible and
269// integrates with CPython, but also works on its own.
270//
271// Licensed under the Apache License, Version 2.0 (the "License");
272// you may not use this file except in compliance with the License.
273// You may obtain a copy of the License at
274//
275// http://www.apache.org/licenses/LICENSE-2.0
276//
277// Unless required by applicable law or agreed to in writing, software
278// distributed under the License is distributed on an "AS IS" BASIS,
279// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
280// See the License for the specific language governing permissions and
281// limitations under the License.
Definition compiled_cell.h:14
Definition exceptions.h:222
Definition compiled_frame.h:117