Nuitka
The Python compiler
Loading...
Searching...
No Matches
HelpersCalling.c
1// Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3// This file is included from another C file, help IDEs to still parse it on
4// its own.
5#ifdef __IDE_ONLY__
6#include "nuitka/prelude.h"
7#endif
8
9#if PYTHON_VERSION < 0x3b0
10PyObject *callPythonFunction(PyObject *func, PyObject *const *args, int count) {
11 PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
12 PyObject *globals = PyFunction_GET_GLOBALS(func);
13 PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
14
15#if PYTHON_VERSION >= 0x300
16 PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func);
17
18 // TODO: Verify this actually matches current Python versions.
19 if (kwdefs == NULL && argdefs == NULL && co->co_argcount == count &&
20 co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
21#else
22 if (argdefs == NULL && co->co_argcount == count && co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
23#endif
24 {
25 PyThreadState *tstate = PyThreadState_GET();
26 CHECK_OBJECT(globals);
27
28 PyFrameObject *frame = PyFrame_New(tstate, co, globals, NULL);
29
30 if (unlikely(frame == NULL)) {
31 return NULL;
32 };
33
34 for (int i = 0; i < count; i++) {
35 frame->f_localsplus[i] = args[i];
36 Py_INCREF(frame->f_localsplus[i]);
37 }
38
39#if PYTHON_VERSION < 0x390
40 PyObject *result = PyEval_EvalFrameEx(frame, 0);
41#else
42 PyObject *result = _PyEval_EvalFrame(tstate, frame, 0);
43#endif
44 // Frame release protects against recursion as it may lead to variable
45 // destruction.
46 tstate->recursion_depth++;
47 Py_DECREF(frame);
48 tstate->recursion_depth--;
49
50 return result;
51 }
52
53 PyObject **defaults = NULL;
54 int num_defaults = 0;
55
56 if (argdefs != NULL) {
57 defaults = &PyTuple_GET_ITEM(argdefs, 0);
58 num_defaults = (int)(Py_SIZE(argdefs));
59 }
60
61 PyObject *result = PyEval_EvalCodeEx(
62#if PYTHON_VERSION >= 0x300
63 (PyObject *)co,
64#else
65 co, // code object
66#endif
67 globals, // globals
68 NULL, // no locals
69 (PyObject **)args, // args
70 count, // argcount
71 NULL, // kwds
72 0, // kwcount
73 defaults, // defaults
74 num_defaults, // defcount
75#if PYTHON_VERSION >= 0x300
76 kwdefs,
77#endif
78 PyFunction_GET_CLOSURE(func));
79
80 return result;
81}
82
83#if PYTHON_VERSION < 0x380 && !defined(_NUITKA_EXPERIMENTAL_DISABLE_UNCOMPILED_FUNCTION_CALL_OPT)
84static PyObject *callPythonFunctionNoArgs(PyObject *func) {
85 PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
86 PyObject *globals = PyFunction_GET_GLOBALS(func);
87 PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
88
89#if PYTHON_VERSION >= 0x300
90 PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func);
91
92 if (kwdefs == NULL && argdefs == NULL && co->co_argcount == 0 &&
93 co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
94#else
95 if (argdefs == NULL && co->co_argcount == 0 && co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
96#endif
97 {
98 PyThreadState *tstate = PyThreadState_GET();
99 CHECK_OBJECT(globals);
100
101 PyFrameObject *frame = PyFrame_New(tstate, co, globals, NULL);
102
103 if (unlikely(frame == NULL)) {
104 return NULL;
105 };
106
107 PyObject *result = PyEval_EvalFrameEx(frame, 0);
108
109 // Frame release protects against recursion as it may lead to variable
110 // destruction.
111 tstate->recursion_depth++;
112 Py_DECREF(frame);
113 tstate->recursion_depth--;
114
115 return result;
116 }
117
118 PyObject **defaults = NULL;
119 int num_defaults = 0;
120
121 if (argdefs != NULL) {
122 defaults = &PyTuple_GET_ITEM(argdefs, 0);
123 num_defaults = (int)(Py_SIZE(argdefs));
124 }
125
126 PyObject *result = PyEval_EvalCodeEx(
127#if PYTHON_VERSION >= 0x300
128 (PyObject *)co,
129#else
130 co, // code object
131#endif
132 globals, // globals
133 NULL, // no locals
134 NULL, // args
135 0, // argcount
136 NULL, // kwds
137 0, // kwcount
138 defaults, // defaults
139 num_defaults, // defcount
140#if PYTHON_VERSION >= 0x300
141 kwdefs,
142#endif
143 PyFunction_GET_CLOSURE(func));
144
145 return result;
146}
147#endif
148
149#endif
150
151PyObject *CALL_METHOD_WITH_POS_ARGS(PyThreadState *tstate, PyObject *source, PyObject *attr_name,
152 PyObject *positional_args) {
153 CHECK_OBJECT(source);
154 CHECK_OBJECT(attr_name);
155 CHECK_OBJECT(positional_args);
156
157#if PYTHON_VERSION < 0x300
158 if (PyInstance_Check(source)) {
159 PyInstanceObject *source_instance = (PyInstanceObject *)source;
160
161 // The special cases have their own variant on the code generation level
162 // as we are called with constants only.
163 assert(attr_name != const_str_plain___dict__);
164 assert(attr_name != const_str_plain___class__);
165
166 // Try the instance dict first.
167 PyObject *called_object =
168 GET_STRING_DICT_VALUE((PyDictObject *)source_instance->in_dict, (PyStringObject *)attr_name);
169
170 // Note: The "called_object" was found without taking a reference,
171 // so we need not release it in this branch.
172 if (called_object != NULL) {
173 return CALL_FUNCTION_WITH_POS_ARGS(tstate, called_object, positional_args);
174 }
175 // Then check the class dictionaries.
176 called_object = FIND_ATTRIBUTE_IN_CLASS(source_instance->in_class, attr_name);
177
178 // Note: The "called_object" was found without taking a reference,
179 // so we need not release it in this branch.
180 if (called_object != NULL) {
181 descrgetfunc descr_get = Py_TYPE(called_object)->tp_descr_get;
182
183 if (descr_get == Nuitka_Function_Type.tp_descr_get) {
184 return Nuitka_CallMethodFunctionPosArgs(tstate, (struct Nuitka_FunctionObject const *)called_object,
185 source, &PyTuple_GET_ITEM(positional_args, 0),
186 PyTuple_GET_SIZE(positional_args));
187 } else if (descr_get != NULL) {
188 PyObject *method = descr_get(called_object, source, (PyObject *)source_instance->in_class);
189
190 if (unlikely(method == NULL)) {
191 return NULL;
192 }
193
194 PyObject *result = CALL_FUNCTION_WITH_POS_ARGS(tstate, method, positional_args);
195 Py_DECREF(method);
196 return result;
197 } else {
198 return CALL_FUNCTION_WITH_POS_ARGS(tstate, called_object, positional_args);
199 }
200 } else if (unlikely(source_instance->in_class->cl_getattr == NULL)) {
201 PyErr_Format(PyExc_AttributeError, "%s instance has no attribute '%s'",
202 PyString_AS_STRING(source_instance->in_class->cl_name), PyString_AS_STRING(attr_name));
203
204 return NULL;
205 } else {
206 // Finally allow the "__getattr__" override to provide it or else
207 // it's an error.
208
209 PyObject *args[] = {source, attr_name};
210
211 called_object = CALL_FUNCTION_WITH_ARGS2(tstate, source_instance->in_class->cl_getattr, args);
212
213 if (unlikely(called_object == NULL)) {
214 return NULL;
215 }
216
217 PyObject *result = CALL_FUNCTION_WITH_POS_ARGS(tstate, called_object, positional_args);
218 Py_DECREF(called_object);
219 return result;
220 }
221 } else
222#endif
223 {
224 PyObject *called_object;
225
226 PyTypeObject *type = Py_TYPE(source);
227
228 if (type->tp_getattro != NULL) {
229 called_object = (*type->tp_getattro)(source, attr_name);
230 } else if (type->tp_getattr != NULL) {
231 called_object = (*type->tp_getattr)(source, (char *)Nuitka_String_AsString_Unchecked(attr_name));
232 } else {
233 SET_CURRENT_EXCEPTION_TYPE0_FORMAT2(PyExc_AttributeError, "'%s' object has no attribute '%s'",
234 type->tp_name, Nuitka_String_AsString_Unchecked(attr_name));
235
236 return NULL;
237 }
238
239 if (unlikely(called_object == NULL)) {
240 return NULL;
241 }
242
243 PyObject *result = CALL_FUNCTION_WITH_POS_ARGS(tstate, called_object, positional_args);
244 Py_DECREF(called_object);
245 return result;
246 }
247}
248
249char const *GET_CALLABLE_NAME(PyObject *object) {
250 if (Nuitka_Function_Check(object)) {
251 return Nuitka_String_AsString(Nuitka_Function_GetName(object));
252 } else if (Nuitka_Generator_Check(object)) {
253 return Nuitka_String_AsString(Nuitka_Generator_GetName(object));
254 } else if (PyMethod_Check(object)) {
255 return PyEval_GetFuncName(PyMethod_GET_FUNCTION(object));
256 } else if (PyFunction_Check(object)) {
257 return Nuitka_String_AsString(((PyFunctionObject *)object)->func_name);
258 }
259#if PYTHON_VERSION < 0x300
260 else if (PyInstance_Check(object)) {
261 return Nuitka_String_AsString(((PyInstanceObject *)object)->in_class->cl_name);
262 } else if (PyClass_Check(object)) {
263 return Nuitka_String_AsString(((PyClassObject *)object)->cl_name);
264 }
265#endif
266 else if (PyCFunction_Check(object)) {
267 return ((PyCFunctionObject *)object)->m_ml->ml_name;
268 } else {
269 return Py_TYPE(object)->tp_name;
270 }
271}
272
273char const *GET_CALLABLE_DESC(PyObject *object) {
274 if (Nuitka_Function_Check(object) || Nuitka_Generator_Check(object) || PyMethod_Check(object) ||
275 PyFunction_Check(object) || PyCFunction_Check(object)) {
276 return "()";
277 }
278#if PYTHON_VERSION < 0x300
279 else if (PyClass_Check(object)) {
280 return " constructor";
281 } else if (PyInstance_Check(object)) {
282 return " instance";
283 }
284#endif
285 else {
286 return " object";
287 }
288}
289
290char const *GET_CLASS_NAME(PyObject *class_object) {
291 if (class_object == NULL) {
292 return "?";
293 } else {
294#if PYTHON_VERSION < 0x300
295 if (PyClass_Check(class_object)) {
296 return Nuitka_String_AsString(((PyClassObject *)class_object)->cl_name);
297 }
298#endif
299
300 if (!PyType_Check(class_object)) {
301 class_object = (PyObject *)Py_TYPE(class_object);
302 }
303
304 return ((PyTypeObject *)class_object)->tp_name;
305 }
306}
307
308char const *GET_INSTANCE_CLASS_NAME(PyThreadState *tstate, PyObject *instance) {
309 // TODO: Why not use our own attribute lookup here.
310 PyObject *class_object = PyObject_GetAttr(instance, const_str_plain___class__);
311
312 // Fallback to type as this cannot fail.
313 if (class_object == NULL) {
314 CLEAR_ERROR_OCCURRED(tstate);
315
316 class_object = (PyObject *)Py_TYPE(instance);
317 Py_INCREF(class_object);
318 }
319
320 char const *result = GET_CLASS_NAME(class_object);
321
322 Py_DECREF(class_object);
323
324 return result;
325}
326
327static PyObject *_getTypeAbstractMethods(PyThreadState *tstate, PyTypeObject *type, void *context) {
328 PyObject *result = DICT_GET_ITEM_WITH_ERROR(tstate, type->tp_dict, const_str_plain___abstractmethods__);
329
330 if (unlikely(result == NULL)) {
331 if (!HAS_ERROR_OCCURRED(tstate)) {
332 SET_CURRENT_EXCEPTION_TYPE0_VALUE0(tstate, PyExc_AttributeError, const_str_plain___abstractmethods__);
333 }
334 return NULL;
335 }
336
337 return result;
338}
339
340void formatCannotInstantiateAbstractClass(PyThreadState *tstate, PyTypeObject *type) {
341 PyObject *abstract_methods = _getTypeAbstractMethods(tstate, type, NULL);
342 if (unlikely(abstract_methods == NULL)) {
343 return;
344 }
345
346 PyObject *sorted_methods = PySequence_List(abstract_methods);
347 Py_DECREF(abstract_methods);
348 if (unlikely(sorted_methods == NULL)) {
349 return;
350 }
351 if (unlikely(PyList_Sort(sorted_methods))) {
352 Py_DECREF(sorted_methods);
353 return;
354 }
355 PyObject *comma = Nuitka_String_FromString(", ");
356 CHECK_OBJECT(comma);
357#if PYTHON_VERSION < 0x300
358 PyObject *joined = CALL_METHOD_WITH_SINGLE_ARG(tstate, comma, const_str_plain_join, sorted_methods);
359
360 char const *joined_str = Nuitka_String_AsString(joined);
361 if (unlikely(joined_str == NULL)) {
362 Py_DECREF(joined);
363 return;
364 }
365#else
366 PyObject *joined = PyUnicode_Join(comma, sorted_methods);
367#endif
368 Py_DECREF(sorted_methods);
369 if (unlikely(joined == NULL)) {
370 return;
371 }
372
373 Py_ssize_t method_count = PyList_GET_SIZE(sorted_methods);
374
375 SET_CURRENT_EXCEPTION_TYPE0_FORMAT3(PyExc_TypeError,
376 "Can't instantiate abstract class %s with abstract method%s %s", type->tp_name,
377 method_count > 1 ? "s" : "", Nuitka_String_AsString(joined));
378
379 Py_DECREF(joined);
380}
381
382#include "HelpersCallingGenerated.c"
383
384// Part of "Nuitka", an optimizing Python compiler that is compatible and
385// integrates with CPython, but also works on its own.
386//
387// Licensed under the Apache License, Version 2.0 (the "License");
388// you may not use this file except in compliance with the License.
389// You may obtain a copy of the License at
390//
391// http://www.apache.org/licenses/LICENSE-2.0
392//
393// Unless required by applicable law or agreed to in writing, software
394// distributed under the License is distributed on an "AS IS" BASIS,
395// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
396// See the License for the specific language governing permissions and
397// limitations under the License.
Definition compiled_function.h:22