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