Nuitka
The Python compiler
Loading...
Searching...
No Matches
compiled_coroutine.h
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3#ifndef __NUITKA_COMPILED_COROUTINE_H__
4#define __NUITKA_COMPILED_COROUTINE_H__
5
6// Compiled coroutine type.
7
8// Another cornerstone of the integration into CPython. Try to behave as well as
9// normal coroutine objects do or even better.
10
11#if PYTHON_VERSION >= 0x350
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_CoroutineObject is the storage associated with a compiled
19// coroutine object instance of which there can be many for each code.
20struct Nuitka_CoroutineObject {
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 coroutine objects in CPython.
33 PyObject *m_weakrefs;
34
35 int m_running;
36
37 // When a coroutine is awaiting, this flag is set.
38 int m_awaiting;
39
40 void *m_code;
41
42 // The parent frame of the coroutine, if created.
43 struct Nuitka_FrameObject *m_frame;
44
45 PyCodeObject *m_code_object;
46
47 // While yielding, this was the frame currently active, restore when
48 // resuming.
49 Nuitka_ThreadStateFrameType *m_resume_frame;
50
51 // Was it ever used, is it still running, or already finished.
52 Generator_Status m_status;
53
54#if PYTHON_VERSION >= 0x370
55 struct Nuitka_ExceptionStackItem m_exc_state;
56
57 // The cr_origin attribute.
58 PyObject *m_origin;
59#endif
60
61 // The label index to resume after yield.
62 int m_yield_return_index;
63
64 // Returned value if yielded value is NULL, is
65 // NULL if not a return
66 PyObject *m_returned;
67
68 // A kind of uuid for the coroutine object, used in comparisons.
69 long m_counter;
70
71 /* The heap of coroutine objects at run time. */
72 void *m_heap_storage;
73
74 /* Closure variables given, if any, we reference cells here. The last
75 * part is dynamically allocated, the array size differs per coroutine
76 * and includes the heap storage.
77 */
78 Py_ssize_t m_closure_given;
79 struct Nuitka_CellObject *m_closure[1];
80};
81
82extern PyTypeObject Nuitka_Coroutine_Type;
83
84typedef PyObject *(*coroutine_code)(PyThreadState *tstate, struct Nuitka_CoroutineObject *, PyObject *);
85
86extern PyObject *Nuitka_Coroutine_New(PyThreadState *tstate, coroutine_code code, PyObject *module, PyObject *name,
87 PyObject *qualname, PyCodeObject *code_object, struct Nuitka_CellObject **closure,
88 Py_ssize_t closure_given, Py_ssize_t heap_storage_size);
89
90static inline bool Nuitka_Coroutine_Check(PyObject *object) { return Py_TYPE(object) == &Nuitka_Coroutine_Type; }
91
92struct Nuitka_CoroutineWrapperObject {
93 /* Python object folklore: */
94 PyObject_HEAD
95
96 struct Nuitka_CoroutineObject *m_coroutine;
97};
98
99extern PyTypeObject Nuitka_CoroutineWrapper_Type;
100
101static inline bool Nuitka_CoroutineWrapper_Check(PyObject *object) {
102 return Py_TYPE(object) == &Nuitka_CoroutineWrapper_Type;
103}
104
105static inline void SAVE_COROUTINE_EXCEPTION(PyThreadState *tstate, struct Nuitka_CoroutineObject *coroutine) {
106 /* Before Python3.7: When yielding from an exception handler in Python3,
107 * the exception preserved to the frame is restored, while the current one
108 * is put as there.
109 *
110 * Python3.7: The exception is preserved in the coroutine object itself
111 * which has a new "m_exc_state" structure just for that.
112 */
113
114#if PYTHON_VERSION < 0x3b0
115 PyObject *saved_exception_type = EXC_TYPE(tstate);
116#endif
117 PyObject *saved_exception_value = EXC_VALUE(tstate);
118#if PYTHON_VERSION < 0x3b0
119 PyTracebackObject *saved_exception_traceback = EXC_TRACEBACK(tstate);
120#endif
121
122#if PYTHON_VERSION < 0x370
123 EXC_TYPE(tstate) = tstate->frame->f_exc_type;
124 EXC_VALUE(tstate) = tstate->frame->f_exc_value;
125 SET_EXC_TRACEBACK(tstate, tstate->frame->f_exc_traceback);
126#else
127#if PYTHON_VERSION < 0x3b0
128 EXC_TYPE(tstate) = coroutine->m_exc_state.exception_type;
129#endif
130 EXC_VALUE(tstate) = coroutine->m_exc_state.exception_value;
131#if PYTHON_VERSION < 0x3b0
132 SET_EXC_TRACEBACK(tstate, coroutine->m_exc_state.exception_tb);
133#endif
134#endif
135
136#if PYTHON_VERSION < 0x370
137 tstate->frame->f_exc_type = saved_exception_type;
138 tstate->frame->f_exc_value = saved_exception_value;
139 tstate->frame->f_exc_traceback = (PyObject *)saved_exception_traceback;
140#else
141#if PYTHON_VERSION < 0x3b0
142 coroutine->m_exc_state.exception_type = saved_exception_type;
143#endif
144 coroutine->m_exc_state.exception_value = saved_exception_value;
145#if PYTHON_VERSION < 0x3b0
146 coroutine->m_exc_state.exception_tb = (PyTracebackObject *)saved_exception_traceback;
147#endif
148#endif
149}
150
151static inline void RESTORE_COROUTINE_EXCEPTION(PyThreadState *tstate, struct Nuitka_CoroutineObject *coroutine) {
152 // When returning from yield, the exception of the frame is preserved, and
153 // the one that enters should be there.
154
155#if PYTHON_VERSION < 0x3b0
156 PyObject *saved_exception_type = EXC_TYPE(tstate);
157#endif
158 PyObject *saved_exception_value = EXC_VALUE(tstate);
159#if PYTHON_VERSION < 0x3b0
160 PyTracebackObject *saved_exception_traceback = EXC_TRACEBACK(tstate);
161#endif
162
163#if PYTHON_VERSION < 0x370
164 EXC_TYPE(tstate) = tstate->frame->f_exc_type;
165 EXC_VALUE(tstate) = tstate->frame->f_exc_value;
166 SET_EXC_TRACEBACK(tstate, tstate->frame->f_exc_traceback);
167
168 tstate->frame->f_exc_type = saved_exception_type;
169 tstate->frame->f_exc_value = saved_exception_value;
170 tstate->frame->f_exc_traceback = (PyObject *)saved_exception_traceback;
171#else
172#if PYTHON_VERSION < 0x3b0
173 EXC_TYPE(tstate) = coroutine->m_exc_state.exception_type;
174#endif
175 EXC_VALUE(tstate) = coroutine->m_exc_state.exception_value;
176#if PYTHON_VERSION < 0x3b0
177 SET_EXC_TRACEBACK(tstate, coroutine->m_exc_state.exception_tb);
178#endif
179
180#if PYTHON_VERSION < 0x3b0
181 coroutine->m_exc_state.exception_type = saved_exception_type;
182#endif
183 coroutine->m_exc_state.exception_value = saved_exception_value;
184#if PYTHON_VERSION < 0x3b0
185 coroutine->m_exc_state.exception_tb = (PyTracebackObject *)saved_exception_traceback;
186#endif
187#endif
188}
189
190#ifdef __cplusplus
191enum Await_Kind {
192 await_normal, // user provided "await"
193 await_enter, // async with statement "__enter__"
194 await_exit // async with statement "__enter__"
195};
196#else
197typedef int Generator_Status;
198static const int await_normal = 0;
199static const int await_enter = 1;
200static const int await_exit = 2;
201#endif
202
203// Create the object to await for async for "iter".
204extern PyObject *ASYNC_MAKE_ITERATOR(PyThreadState *tstate, PyObject *value);
205
206// Create the object to await for async for "next".
207extern PyObject *ASYNC_ITERATOR_NEXT(PyThreadState *tstate, PyObject *value);
208
209// Create the object for plain "await".
210extern PyObject *ASYNC_AWAIT(PyThreadState *tstate, PyObject *awaitable, int await_kind);
211
212NUITKA_MAY_BE_UNUSED static void STORE_COROUTINE_EXCEPTION(PyThreadState *tstate,
213 struct Nuitka_CoroutineObject *coroutine) {
214#if PYTHON_VERSION < 0x3b0
215 EXC_TYPE_F(coroutine) = EXC_TYPE(tstate);
216 if (EXC_TYPE_F(coroutine) == Py_None) {
217 EXC_TYPE_F(coroutine) = NULL;
218 }
219 Py_XINCREF(EXC_TYPE_F(coroutine));
220#endif
221 EXC_VALUE_F(coroutine) = EXC_VALUE(tstate);
222 Py_XINCREF(EXC_VALUE_F(coroutine));
223#if PYTHON_VERSION < 0x3b0
224 ASSIGN_EXC_TRACEBACK_F(coroutine, EXC_TRACEBACK(tstate));
225 Py_XINCREF(EXC_TRACEBACK_F(coroutine));
226#endif
227}
228
229NUITKA_MAY_BE_UNUSED static void DROP_COROUTINE_EXCEPTION(struct Nuitka_CoroutineObject *coroutine) {
230#if PYTHON_VERSION < 0x3b0
231 Py_CLEAR(EXC_TYPE_F(coroutine));
232#endif
233 Py_CLEAR(EXC_VALUE_F(coroutine));
234#if PYTHON_VERSION < 0x3b0
235 Py_CLEAR(EXC_TRACEBACK_F(coroutine));
236#endif
237}
238
239// For reference count debugging.
240#if _DEBUG_REFCOUNTS
241extern int count_active_Nuitka_Coroutine_Type;
242extern int count_allocated_Nuitka_Coroutine_Type;
243extern int count_released_Nuitka_Coroutine_Type;
244
245extern int count_active_Nuitka_CoroutineWrapper_Type;
246extern int count_allocated_Nuitka_CoroutineWrapper_Type;
247extern int count_released_Nuitka_CoroutineWrapper_Type;
248
249extern int count_active_Nuitka_AIterWrapper_Type;
250extern int count_allocated_Nuitka_AIterWrapper_Type;
251extern int count_released_Nuitka_AIterWrapper_Type;
252#endif
253
254#endif
255
256#endif
257
258// Part of "Nuitka", an optimizing Python compiler that is compatible and
259// integrates with CPython, but also works on its own.
260//
261// Licensed under the Apache License, Version 2.0 (the "License");
262// you may not use this file except in compliance with the License.
263// You may obtain a copy of the License at
264//
265// http://www.apache.org/licenses/LICENSE-2.0
266//
267// Unless required by applicable law or agreed to in writing, software
268// distributed under the License is distributed on an "AS IS" BASIS,
269// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
270// See the License for the specific language governing permissions and
271// limitations under the License.
Definition compiled_cell.h:14
Definition exceptions.h:222
Definition compiled_frame.h:117