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