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 #include "nuitka/prelude.h"
19 
20 #include "nuitka/freelists.h"
21 
22 #include "structmember.h"
23 
24 // For reporting about reference counts per type.
25 #if _DEBUG_REFCOUNTS
26 int count_active_Nuitka_Frame_Type = 0;
27 int count_allocated_Nuitka_Frame_Type = 0;
28 int count_released_Nuitka_Frame_Type = 0;
29 #endif
30 
31 // For reporting about frame cache usage
32 #if _DEBUG_REFCOUNTS
33 int count_active_frame_cache_instances = 0;
34 int count_allocated_frame_cache_instances = 0;
35 int count_released_frame_cache_instances = 0;
36 int count_hit_frame_cache_instances = 0;
37 #endif
38 
39 #define OFF(x) offsetof(PyFrameObject, x)
40 
41 static PyMemberDef Nuitka_Frame_memberlist[] = {
42     {(char *)"f_back", T_OBJECT, OFF(f_back), READONLY | RESTRICTED},
43     {(char *)"f_code", T_OBJECT, OFF(f_code), READONLY | RESTRICTED},
44     {(char *)"f_builtins", T_OBJECT, OFF(f_builtins), READONLY | RESTRICTED},
45     {(char *)"f_globals", T_OBJECT, OFF(f_globals), READONLY | RESTRICTED},
46     {(char *)"f_lasti", T_INT, OFF(f_lasti), READONLY | RESTRICTED},
47     {NULL}};
48 
49 #if PYTHON_VERSION < 0x300
50 
Nuitka_Frame_get_exc_traceback(struct Nuitka_FrameObject * frame)51 static PyObject *Nuitka_Frame_get_exc_traceback(struct Nuitka_FrameObject *frame) {
52     PyObject *result = frame->m_frame.f_exc_traceback;
53 
54     if (result == NULL) {
55         result = Py_None;
56     }
57 
58     Py_INCREF(result);
59     return result;
60 }
61 
Nuitka_Frame_set_exc_traceback(struct Nuitka_FrameObject * frame,PyObject * traceback)62 static int Nuitka_Frame_set_exc_traceback(struct Nuitka_FrameObject *frame, PyObject *traceback) {
63     Py_XDECREF(frame->m_frame.f_exc_traceback);
64 
65     if (traceback == Py_None) {
66         traceback = NULL;
67     }
68 
69     frame->m_frame.f_exc_traceback = traceback;
70     Py_XINCREF(traceback);
71 
72     return 0;
73 }
74 
Nuitka_Frame_get_exc_type(struct Nuitka_FrameObject * frame)75 static PyObject *Nuitka_Frame_get_exc_type(struct Nuitka_FrameObject *frame) {
76     PyObject *result;
77 
78     if (frame->m_frame.f_exc_type != NULL) {
79         result = frame->m_frame.f_exc_type;
80     } else {
81         result = Py_None;
82     }
83 
84     Py_INCREF(result);
85     return result;
86 }
87 
Nuitka_Frame_set_exc_type(struct Nuitka_FrameObject * frame,PyObject * exception_type)88 static int Nuitka_Frame_set_exc_type(struct Nuitka_FrameObject *frame, PyObject *exception_type) {
89     PyObject *old = frame->m_frame.f_exc_type;
90 
91     if (exception_type == Py_None) {
92         exception_type = NULL;
93     }
94 
95     frame->m_frame.f_exc_type = exception_type;
96     Py_XINCREF(frame->m_frame.f_exc_type);
97 
98     Py_XDECREF(old);
99 
100     return 0;
101 }
102 
Nuitka_Frame_get_exc_value(struct Nuitka_FrameObject * frame)103 static PyObject *Nuitka_Frame_get_exc_value(struct Nuitka_FrameObject *frame) {
104     PyObject *result;
105 
106     if (frame->m_frame.f_exc_value != NULL) {
107         result = frame->m_frame.f_exc_value;
108     } else {
109         result = Py_None;
110     }
111 
112     Py_INCREF(result);
113     return result;
114 }
115 
Nuitka_Frame_set_exc_value(struct Nuitka_FrameObject * frame,PyObject * exception_value)116 static int Nuitka_Frame_set_exc_value(struct Nuitka_FrameObject *frame, PyObject *exception_value) {
117     PyObject *old = frame->m_frame.f_exc_value;
118 
119     if (exception_value == Py_None) {
120         exception_value = NULL;
121     }
122 
123     frame->m_frame.f_exc_value = exception_value;
124     Py_XINCREF(exception_value);
125     Py_XDECREF(old);
126 
127     return 0;
128 }
129 
Nuitka_Frame_get_restricted(struct Nuitka_FrameObject * frame,void * closure)130 static PyObject *Nuitka_Frame_get_restricted(struct Nuitka_FrameObject *frame, void *closure) {
131     Py_INCREF(Py_False);
132     return Py_False;
133 }
134 
135 #endif
136 
Nuitka_Frame_getlocals(struct Nuitka_FrameObject * frame,void * closure)137 static PyObject *Nuitka_Frame_getlocals(struct Nuitka_FrameObject *frame, void *closure) {
138     if (frame->m_type_description == NULL) {
139         if (frame->m_frame.f_locals == NULL) {
140             frame->m_frame.f_locals = PyDict_New();
141         }
142 
143         Py_INCREF(frame->m_frame.f_locals);
144         return frame->m_frame.f_locals;
145     } else {
146         PyObject *result = PyDict_New();
147         PyObject **varnames = &PyTuple_GET_ITEM(frame->m_frame.f_code->co_varnames, 0);
148 
149         char const *w = frame->m_type_description;
150         char const *t = frame->m_locals_storage;
151 
152         while (*w != 0) {
153             switch (*w) {
154             case NUITKA_TYPE_DESCRIPTION_OBJECT:
155             case NUITKA_TYPE_DESCRIPTION_OBJECT_PTR: {
156                 PyObject *value = *(PyObject **)t;
157                 CHECK_OBJECT_X(value);
158 
159                 if (value != NULL) {
160                     PyDict_SetItem(result, *varnames, value);
161                 }
162 
163                 t += sizeof(PyObject *);
164 
165                 break;
166             }
167             case NUITKA_TYPE_DESCRIPTION_CELL: {
168                 struct Nuitka_CellObject *value = *(struct Nuitka_CellObject **)t;
169                 assert(Nuitka_Cell_Check((PyObject *)value));
170                 CHECK_OBJECT(value);
171 
172                 if (value->ob_ref != NULL) {
173                     PyDict_SetItem(result, *varnames, value->ob_ref);
174                 }
175 
176                 t += sizeof(struct Nuitka_CellObject *);
177 
178                 break;
179             }
180             case NUITKA_TYPE_DESCRIPTION_NULL: {
181                 break;
182             }
183             case NUITKA_TYPE_DESCRIPTION_BOOL: {
184                 int value = *(int *)t;
185                 t += sizeof(int);
186                 switch ((nuitka_bool)value) {
187                 case NUITKA_BOOL_TRUE: {
188                     PyDict_SetItem(result, *varnames, Py_True);
189                     break;
190                 }
191                 case NUITKA_BOOL_FALSE: {
192                     PyDict_SetItem(result, *varnames, Py_False);
193                     break;
194                 }
195                 default:
196                     break;
197                 }
198                 break;
199             }
200             default:
201                 assert(false);
202             }
203 
204             w += 1;
205             varnames += 1;
206         }
207 
208         return result;
209     }
210 }
211 
Nuitka_Frame_getlineno(PyFrameObject * frame,void * closure)212 static PyObject *Nuitka_Frame_getlineno(PyFrameObject *frame, void *closure) { return PyInt_FromLong(frame->f_lineno); }
213 
Nuitka_Frame_gettrace(PyFrameObject * frame,void * closure)214 static PyObject *Nuitka_Frame_gettrace(PyFrameObject *frame, void *closure) {
215     PyObject *result = frame->f_trace;
216     Py_INCREF(result);
217     return result;
218 }
219 
Nuitka_Frame_settrace(PyFrameObject * frame,PyObject * v,void * closure)220 static int Nuitka_Frame_settrace(PyFrameObject *frame, PyObject *v, void *closure) {
221     SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "f_trace is not writable in Nuitka");
222     return -1;
223 }
224 
225 #if PYTHON_VERSION >= 0x370
Nuitka_Frame_gettracelines(PyFrameObject * frame,void * closure)226 static PyObject *Nuitka_Frame_gettracelines(PyFrameObject *frame, void *closure) {
227     PyObject *result = Py_False;
228     Py_INCREF(result);
229     return result;
230 }
231 
Nuitka_Frame_settracelines(PyFrameObject * frame,PyObject * v,void * closure)232 static int Nuitka_Frame_settracelines(PyFrameObject *frame, PyObject *v, void *closure) {
233     SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "f_trace_lines is not writable in Nuitka");
234     return -1;
235 }
236 
Nuitka_Frame_gettraceopcodes(PyFrameObject * frame,void * closure)237 static PyObject *Nuitka_Frame_gettraceopcodes(PyFrameObject *frame, void *closure) {
238     PyObject *result = Py_False;
239     Py_INCREF(result);
240     return result;
241 }
242 
Nuitka_Frame_settraceopcodes(PyFrameObject * frame,PyObject * v,void * closure)243 static int Nuitka_Frame_settraceopcodes(PyFrameObject *frame, PyObject *v, void *closure) {
244     SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "f_trace_opcodes is not writable in Nuitka");
245     return -1;
246 }
247 
248 #endif
249 
250 static PyGetSetDef Nuitka_Frame_getsetlist[] = {
251     {(char *)"f_locals", (getter)Nuitka_Frame_getlocals, NULL, NULL},
252     {(char *)"f_lineno", (getter)Nuitka_Frame_getlineno, NULL, NULL},
253     {(char *)"f_trace", (getter)Nuitka_Frame_gettrace, (setter)Nuitka_Frame_settrace, NULL},
254 #if PYTHON_VERSION < 0x300
255     {(char *)"f_restricted", (getter)Nuitka_Frame_get_restricted, NULL, NULL},
256     {(char *)"f_exc_traceback", (getter)Nuitka_Frame_get_exc_traceback, (setter)Nuitka_Frame_set_exc_traceback, NULL},
257     {(char *)"f_exc_type", (getter)Nuitka_Frame_get_exc_type, (setter)Nuitka_Frame_set_exc_type, NULL},
258     {(char *)"f_exc_value", (getter)Nuitka_Frame_get_exc_value, (setter)Nuitka_Frame_set_exc_value, NULL},
259 #endif
260 #if PYTHON_VERSION >= 0x370
261     {(char *)"f_trace_lines", (getter)Nuitka_Frame_gettracelines, (setter)Nuitka_Frame_settracelines, NULL},
262     {(char *)"f_trace_opcodes", (getter)Nuitka_Frame_gettraceopcodes, (setter)Nuitka_Frame_settraceopcodes, NULL},
263 #endif
264     {NULL}};
265 
266 // tp_repr slot, decide how a function shall be output
Nuitka_Frame_tp_repr(struct Nuitka_FrameObject * nuitka_frame)267 static PyObject *Nuitka_Frame_tp_repr(struct Nuitka_FrameObject *nuitka_frame) {
268 #if PYTHON_VERSION < 0x300
269     return PyString_FromFormat(
270 #else
271     return PyUnicode_FromFormat(
272 #endif
273 #if PYTHON_VERSION >= 0x370
274         "<compiled_frame at %p, file %R, line %d, code %S>", nuitka_frame, nuitka_frame->m_frame.f_code->co_filename,
275         nuitka_frame->m_frame.f_lineno, nuitka_frame->m_frame.f_code->co_name
276 #elif _DEBUG_FRAME || _DEBUG_REFRAME || _DEBUG_EXCEPTIONS
277         "<compiled_frame object for %s at %p>", Nuitka_String_AsString(nuitka_frame->m_frame.f_code->co_name),
278         nuitka_frame
279 #else
280         "<compiled_frame object at %p>",
281         nuitka_frame
282 #endif
283     );
284 }
285 
Nuitka_Frame_tp_clear(struct Nuitka_FrameObject * frame)286 static void Nuitka_Frame_tp_clear(struct Nuitka_FrameObject *frame) {
287     if (frame->m_type_description) {
288         char const *w = frame->m_type_description;
289         char const *t = frame->m_locals_storage;
290 
291         while (*w != 0) {
292             switch (*w) {
293             case NUITKA_TYPE_DESCRIPTION_OBJECT:
294             case NUITKA_TYPE_DESCRIPTION_OBJECT_PTR: {
295                 PyObject *value = *(PyObject **)t;
296                 CHECK_OBJECT_X(value);
297 
298                 Py_XDECREF(value);
299 
300                 t += sizeof(PyObject *);
301 
302                 break;
303             }
304             case NUITKA_TYPE_DESCRIPTION_CELL: {
305                 struct Nuitka_CellObject *value = *(struct Nuitka_CellObject **)t;
306                 assert(Nuitka_Cell_Check((PyObject *)value));
307                 CHECK_OBJECT(value);
308 
309                 Py_DECREF(value);
310 
311                 t += sizeof(struct Nuitka_CellObject *);
312 
313                 break;
314             }
315             case NUITKA_TYPE_DESCRIPTION_NULL: {
316                 break;
317             }
318             case NUITKA_TYPE_DESCRIPTION_BOOL: {
319                 t += sizeof(int);
320 
321                 break;
322             }
323             default:
324                 assert(false);
325             }
326 
327             w += 1;
328         }
329 
330         frame->m_type_description = NULL;
331     }
332 }
333 
334 #define MAX_FRAME_FREE_LIST_COUNT 100
335 static struct Nuitka_FrameObject *free_list_frames = NULL;
336 static int free_list_frames_count = 0;
337 
Nuitka_Frame_tp_dealloc(struct Nuitka_FrameObject * nuitka_frame)338 static void Nuitka_Frame_tp_dealloc(struct Nuitka_FrameObject *nuitka_frame) {
339 #if _DEBUG_REFCOUNTS
340     count_active_Nuitka_Frame_Type -= 1;
341     count_released_Nuitka_Frame_Type += 1;
342 #endif
343 
344 #ifndef __NUITKA_NO_ASSERT__
345     // Save the current exception, if any, we must to not corrupt it.
346     PyObject *save_exception_type, *save_exception_value;
347     PyTracebackObject *save_exception_tb;
348     FETCH_ERROR_OCCURRED(&save_exception_type, &save_exception_value, &save_exception_tb);
349     RESTORE_ERROR_OCCURRED(save_exception_type, save_exception_value, save_exception_tb);
350 #endif
351 
352     Nuitka_GC_UnTrack(nuitka_frame);
353 
354     PyFrameObject *frame = &nuitka_frame->m_frame;
355 
356     Py_XDECREF(frame->f_back);
357     Py_DECREF(frame->f_builtins);
358     Py_DECREF(frame->f_globals);
359     Py_XDECREF(frame->f_locals);
360 
361 #if PYTHON_VERSION < 0x370
362     Py_XDECREF(frame->f_exc_type);
363     Py_XDECREF(frame->f_exc_value);
364     Py_XDECREF(frame->f_exc_traceback);
365 #endif
366 
367     Nuitka_Frame_tp_clear(nuitka_frame);
368 
369     releaseToFreeList(free_list_frames, nuitka_frame, MAX_FRAME_FREE_LIST_COUNT);
370 
371 #ifndef __NUITKA_NO_ASSERT__
372     PyThreadState *tstate = PyThreadState_GET();
373 
374     assert(tstate->curexc_type == save_exception_type);
375     assert(tstate->curexc_value == save_exception_value);
376     assert((PyTracebackObject *)tstate->curexc_traceback == save_exception_tb);
377 #endif
378 }
379 
Nuitka_Frame_tp_traverse(struct Nuitka_FrameObject * frame,visitproc visit,void * arg)380 static int Nuitka_Frame_tp_traverse(struct Nuitka_FrameObject *frame, visitproc visit, void *arg) {
381     Py_VISIT(frame->m_frame.f_back);
382     // Py_VISIT(frame->f_code);
383     Py_VISIT(frame->m_frame.f_builtins);
384     Py_VISIT(frame->m_frame.f_globals);
385     // Py_VISIT(frame->f_locals);
386 
387 #if PYTHON_VERSION < 0x370
388     Py_VISIT(frame->m_frame.f_exc_type);
389     Py_VISIT(frame->m_frame.f_exc_value);
390     Py_VISIT(frame->m_frame.f_exc_traceback);
391 #endif
392 
393     // Traverse attached locals too.
394     char const *w = frame->m_type_description;
395     char const *t = frame->m_locals_storage;
396 
397     while (w != NULL && *w != 0) {
398         switch (*w) {
399         case NUITKA_TYPE_DESCRIPTION_OBJECT:
400         case NUITKA_TYPE_DESCRIPTION_OBJECT_PTR: {
401             PyObject *value = *(PyObject **)t;
402             CHECK_OBJECT_X(value);
403 
404             Py_VISIT(value);
405             t += sizeof(PyObject *);
406 
407             break;
408         }
409         case NUITKA_TYPE_DESCRIPTION_CELL: {
410             struct Nuitka_CellObject *value = *(struct Nuitka_CellObject **)t;
411             assert(Nuitka_Cell_Check((PyObject *)value));
412             CHECK_OBJECT(value);
413 
414             Py_VISIT(value);
415 
416             t += sizeof(struct Nuitka_CellObject *);
417 
418             break;
419         }
420         case NUITKA_TYPE_DESCRIPTION_NULL: {
421             break;
422         }
423         case NUITKA_TYPE_DESCRIPTION_BOOL: {
424             t += sizeof(int);
425 
426             break;
427         }
428         default:
429             assert(false);
430         }
431 
432         w += 1;
433     }
434 
435     return 0;
436 }
437 
438 #if PYTHON_VERSION >= 0x340
439 
Nuitka_Frame_clear(struct Nuitka_FrameObject * frame)440 static PyObject *Nuitka_Frame_clear(struct Nuitka_FrameObject *frame) {
441     if (Nuitka_Frame_IsExecuting(frame)) {
442         SET_CURRENT_EXCEPTION_TYPE0_STR(PyExc_RuntimeError, "cannot clear an executing frame");
443 
444         return NULL;
445     }
446 
447 #if PYTHON_VERSION >= 0x340
448     // For frames that are closed, we also need to close the generator.
449     if (frame->m_frame.f_gen != NULL) {
450         Py_INCREF(frame);
451 
452         CHECK_OBJECT(frame->m_frame.f_gen);
453         PyObject *f_gen = frame->m_frame.f_gen;
454 
455         bool close_exception;
456 
457         if (Nuitka_Generator_Check(frame->m_frame.f_gen)) {
458             struct Nuitka_GeneratorObject *generator = (struct Nuitka_GeneratorObject *)frame->m_frame.f_gen;
459             frame->m_frame.f_gen = NULL;
460 
461             close_exception = !_Nuitka_Generator_close(generator);
462         }
463 #if PYTHON_VERSION >= 0x350
464         else if (Nuitka_Coroutine_Check(frame->m_frame.f_gen)) {
465             struct Nuitka_CoroutineObject *coroutine = (struct Nuitka_CoroutineObject *)frame->m_frame.f_gen;
466             frame->m_frame.f_gen = NULL;
467 
468             close_exception = !_Nuitka_Coroutine_close(coroutine);
469         }
470 #endif
471 #if PYTHON_VERSION >= 0x360
472         else if (Nuitka_Asyncgen_Check(frame->m_frame.f_gen)) {
473             struct Nuitka_AsyncgenObject *asyncgen = (struct Nuitka_AsyncgenObject *)frame->m_frame.f_gen;
474             frame->m_frame.f_gen = NULL;
475 
476             close_exception = !_Nuitka_Asyncgen_close(asyncgen);
477         }
478 #endif
479         else {
480             // Compiled frames should only have our types, so this ought to not happen.
481             assert(false);
482 
483             frame->m_frame.f_gen = NULL;
484             close_exception = false;
485         }
486 
487         if (unlikely(close_exception)) {
488             PyErr_WriteUnraisable(f_gen);
489         }
490 
491         Py_DECREF(frame);
492     }
493 #endif
494 
495     Nuitka_Frame_tp_clear(frame);
496 
497     Py_RETURN_NONE;
498 }
499 
500 #endif
501 
Nuitka_Frame_sizeof(struct Nuitka_FrameObject * frame)502 static PyObject *Nuitka_Frame_sizeof(struct Nuitka_FrameObject *frame) {
503     return PyInt_FromSsize_t(sizeof(struct Nuitka_FrameObject) + Py_SIZE(frame));
504 }
505 
506 static PyMethodDef Nuitka_Frame_methods[] = {
507 #if PYTHON_VERSION >= 0x340
508     {"clear", (PyCFunction)Nuitka_Frame_clear, METH_NOARGS, "F.clear(): clear most references held by the frame"},
509 #endif
510     {"__sizeof__", (PyCFunction)Nuitka_Frame_sizeof, METH_NOARGS, "F.__sizeof__() -> size of F in memory, in bytes"},
511     {NULL, NULL}};
512 
513 PyTypeObject Nuitka_Frame_Type = {
514     PyVarObject_HEAD_INIT(NULL, 0) "compiled_frame",
515     sizeof(struct Nuitka_FrameObject),
516     1,
517     (destructor)Nuitka_Frame_tp_dealloc,     // tp_dealloc
518     0,                                       // tp_print
519     0,                                       // tp_getattr
520     0,                                       // tp_setattr
521     0,                                       // tp_compare
522     (reprfunc)Nuitka_Frame_tp_repr,          // tp_repr
523     0,                                       // tp_as_number
524     0,                                       // tp_as_sequence
525     0,                                       // tp_as_mapping
526     0,                                       // tp_hash
527     0,                                       // tp_call
528     0,                                       // tp_str
529     PyObject_GenericGetAttr,                 // tp_getattro
530     PyObject_GenericSetAttr,                 // tp_setattro
531     0,                                       // tp_as_buffer
532     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags
533     0,                                       // tp_doc
534     (traverseproc)Nuitka_Frame_tp_traverse,  // tp_traverse
535     (inquiry)Nuitka_Frame_tp_clear,          // tp_clear
536     0,                                       // tp_richcompare
537     0,                                       // tp_weaklistoffset
538     0,                                       // tp_iter
539     0,                                       // tp_iternext
540     Nuitka_Frame_methods,                    // tp_methods
541     Nuitka_Frame_memberlist,                 // tp_members
542     Nuitka_Frame_getsetlist,                 // tp_getset
543     0,                                       // tp_base
544     0,                                       // tp_dict
545 };
546 
_initCompiledFrameType(void)547 void _initCompiledFrameType(void) {
548     PyType_Ready(&Nuitka_Frame_Type);
549 
550     // These are to be used interchangeably. Make sure that's true.
551     assert(offsetof(struct Nuitka_FrameObject, m_frame.f_localsplus) == offsetof(PyFrameObject, f_localsplus));
552 }
553 
MAKE_FRAME(PyCodeObject * code,PyObject * module,bool is_module,Py_ssize_t locals_size)554 static struct Nuitka_FrameObject *MAKE_FRAME(PyCodeObject *code, PyObject *module, bool is_module,
555                                              Py_ssize_t locals_size) {
556     assertCodeObject(code);
557 
558 #if _DEBUG_REFCOUNTS
559     count_active_Nuitka_Frame_Type += 1;
560     count_allocated_Nuitka_Frame_Type += 1;
561 #endif
562 
563     PyObject *globals = ((PyModuleObject *)module)->md_dict;
564     assert(PyDict_Check(globals));
565 
566     struct Nuitka_FrameObject *result;
567 
568     // Macro to assign result memory from GC or free list.
569     allocateFromFreeList(free_list_frames, struct Nuitka_FrameObject, Nuitka_Frame_Type, locals_size);
570 
571     result->m_type_description = NULL;
572 
573     PyFrameObject *frame = &result->m_frame;
574 
575     frame->f_code = code;
576 
577     frame->f_trace = Py_None;
578 
579 #if PYTHON_VERSION < 0x370
580     frame->f_exc_type = NULL;
581     frame->f_exc_value = NULL;
582     frame->f_exc_traceback = NULL;
583 #else
584     frame->f_trace_lines = 0;
585     frame->f_trace_opcodes = 0;
586 #endif
587 
588     Py_INCREF(dict_builtin);
589     frame->f_builtins = (PyObject *)dict_builtin;
590 
591     frame->f_back = NULL;
592 
593     Py_INCREF(globals);
594     frame->f_globals = globals;
595 
596     if (likely((code->co_flags & CO_OPTIMIZED) == CO_OPTIMIZED)) {
597         frame->f_locals = NULL;
598     } else if (is_module) {
599         Py_INCREF(globals);
600         frame->f_locals = globals;
601     } else {
602         frame->f_locals = PyDict_New();
603 
604         if (unlikely(frame->f_locals == NULL)) {
605             Py_DECREF(result);
606 
607             return NULL;
608         }
609 
610         PyDict_SetItem(frame->f_locals, const_str_plain___module__, MODULE_NAME0(module));
611     }
612 
613 #if PYTHON_VERSION < 0x340
614     frame->f_tstate = PyThreadState_GET();
615 #endif
616 
617     frame->f_lasti = -1;
618     frame->f_lineno = code->co_firstlineno;
619     frame->f_iblock = 0;
620 
621 #if PYTHON_VERSION >= 0x340
622     frame->f_gen = NULL;
623     Nuitka_Frame_MarkAsNotExecuting(result);
624 #endif
625 
626     Nuitka_GC_Track(result);
627     return result;
628 }
629 
MAKE_MODULE_FRAME(PyCodeObject * code,PyObject * module)630 struct Nuitka_FrameObject *MAKE_MODULE_FRAME(PyCodeObject *code, PyObject *module) {
631     return MAKE_FRAME(code, module, true, 0);
632 }
633 
MAKE_FUNCTION_FRAME(PyCodeObject * code,PyObject * module,Py_ssize_t locals_size)634 struct Nuitka_FrameObject *MAKE_FUNCTION_FRAME(PyCodeObject *code, PyObject *module, Py_ssize_t locals_size) {
635     return MAKE_FRAME(code, module, false, locals_size);
636 }
637 
638 // This is the backend of MAKE_CODEOBJ macro.
makeCodeObject(PyObject * filename,int line,int flags,PyObject * function_name,PyObject * argnames,PyObject * freevars,int arg_count,int kw_only_count,int pos_only_count)639 PyCodeObject *makeCodeObject(PyObject *filename, int line, int flags, PyObject *function_name, PyObject *argnames,
640                              PyObject *freevars, int arg_count
641 #if PYTHON_VERSION >= 0x300
642                              ,
643                              int kw_only_count
644 #endif
645 #if PYTHON_VERSION >= 0x380
646                              ,
647                              int pos_only_count
648 #endif
649 ) {
650     CHECK_OBJECT(filename);
651     assert(Nuitka_String_CheckExact(filename));
652     CHECK_OBJECT(function_name);
653     assert(Nuitka_String_CheckExact(function_name));
654 
655     if (argnames == NULL) {
656         argnames = const_tuple_empty;
657     }
658     CHECK_OBJECT(argnames);
659     assert(PyTuple_Check(argnames));
660 
661     if (freevars == NULL) {
662         freevars = const_tuple_empty;
663     }
664     CHECK_OBJECT(freevars);
665     assert(PyTuple_Check(freevars));
666 
667     // The PyCode_New has funny code that interns, mutating the tuple that owns
668     // it. Really serious non-immutable shit. We have triggered that changes
669     // behind our back in the past.
670 #ifndef __NUITKA_NO_ASSERT__
671     Py_hash_t hash = DEEP_HASH(argnames);
672 #endif
673 
674 #if PYTHON_VERSION < 0x300
675     PyObject *code = const_str_empty;
676     PyObject *lnotab = const_str_empty;
677 #else
678     PyObject *code = const_bytes_empty;
679     PyObject *lnotab = const_bytes_empty;
680 #endif
681 
682     // Not using PyCode_NewEmpty, it doesn't given us much beyond this
683     // and is not available for Python2.
684 #if PYTHON_VERSION >= 0x380
685     PyCodeObject *result = PyCode_NewWithPosOnlyArgs(arg_count, // argcount
686 #else
687     PyCodeObject *result = PyCode_New(arg_count, // argcount
688 #endif
689 #if PYTHON_VERSION >= 0x300
690 #if PYTHON_VERSION >= 0x380
691                                                      pos_only_count, // kw-only count
692 #endif
693                                                      kw_only_count, // kw-only count
694 #endif
695                                                      0,                 // nlocals
696                                                      0,                 // stacksize
697                                                      flags,             // flags
698                                                      code,              // code (bytecode)
699                                                      const_tuple_empty, // consts (we are not going to be compatible)
700                                                      const_tuple_empty, // names (we are not going to be compatible)
701                                                      argnames,          // varnames (we are not going to be compatible)
702                                                      freevars,          // freevars
703                                                      const_tuple_empty, // cellvars (we are not going to be compatible)
704                                                      filename,          // filename
705                                                      function_name,     // name
706                                                      line,              // firstlineno (offset of the code object)
707                                                      lnotab             // lnotab (table to translate code object)
708     );
709 
710     assert(DEEP_HASH(argnames) == hash);
711 
712     CHECK_OBJECT(result);
713     return result;
714 }
715 
Nuitka_Frame_AttachLocals(struct Nuitka_FrameObject * frame,char const * type_description,...)716 void Nuitka_Frame_AttachLocals(struct Nuitka_FrameObject *frame, char const *type_description, ...) {
717     assertFrameObject(frame);
718 
719     assert(frame->m_type_description == NULL);
720 
721     // TODO: Do not call this if there is nothing to do. Instead make all the
722     // places handle NULL pointer and recognize that there is nothing to do.
723     // assert(type_description != NULL && assert(strlen(type_description)>0));
724     if (type_description == NULL) {
725         type_description = "";
726     }
727 
728     frame->m_type_description = type_description;
729 
730     char const *w = type_description;
731     char *t = frame->m_locals_storage;
732 
733     va_list(ap);
734     va_start(ap, type_description);
735 
736     while (*w != 0) {
737         switch (*w) {
738         case NUITKA_TYPE_DESCRIPTION_OBJECT: {
739             PyObject *value = va_arg(ap, PyObject *);
740             memcpy(t, &value, sizeof(PyObject *));
741             Py_XINCREF(value);
742             t += sizeof(PyObject *);
743 
744             break;
745         }
746         case NUITKA_TYPE_DESCRIPTION_OBJECT_PTR: {
747             /* Note: We store the pointed object only, so this is only
748                a shortcut for the calling side. */
749             PyObject **value = va_arg(ap, PyObject **);
750             CHECK_OBJECT_X(*value);
751 
752             memcpy(t, value, sizeof(PyObject *));
753 
754             Py_XINCREF(*value);
755             t += sizeof(PyObject *);
756 
757             break;
758         }
759         case NUITKA_TYPE_DESCRIPTION_CELL: {
760             struct Nuitka_CellObject *value = va_arg(ap, struct Nuitka_CellObject *);
761             assert(Nuitka_Cell_Check((PyObject *)value));
762             CHECK_OBJECT(value);
763             CHECK_OBJECT_X(value->ob_ref);
764 
765             memcpy(t, &value, sizeof(struct Nuitka_CellObject *));
766             Py_INCREF(value);
767 
768             t += sizeof(struct Nuitka_CellObject *);
769 
770             break;
771         }
772         case NUITKA_TYPE_DESCRIPTION_NULL: {
773             NUITKA_MAY_BE_UNUSED void *value = va_arg(ap, struct Nuitka_CellObject *);
774 
775             break;
776         }
777         case NUITKA_TYPE_DESCRIPTION_BOOL: {
778             int value = va_arg(ap, int);
779             memcpy(t, &value, sizeof(int));
780 
781             t += sizeof(value);
782 
783             break;
784         }
785         default:
786             assert(false);
787         }
788 
789         w += 1;
790     }
791 
792     va_end(ap);
793     assert(t - frame->m_locals_storage <= Py_SIZE(frame));
794 }
795 
796 // Make a dump of the active frame stack. For debugging purposes only.
dumpFrameStack(void)797 void dumpFrameStack(void) {
798     PyObject *saved_exception_type, *saved_exception_value;
799     PyTracebackObject *saved_exception_tb;
800 
801     FETCH_ERROR_OCCURRED(&saved_exception_type, &saved_exception_value, &saved_exception_tb);
802 
803     PyFrameObject *current = PyThreadState_GET()->frame;
804     int total = 0;
805 
806     while (current) {
807         total++;
808         current = current->f_back;
809     }
810 
811     current = PyThreadState_GET()->frame;
812 
813     PRINT_STRING(">--------->\n");
814 
815     while (current) {
816         PyObject *current_repr = PyObject_Str((PyObject *)current);
817         PyObject *code_repr = PyObject_Str((PyObject *)current->f_code);
818 
819         PRINT_FORMAT("Frame stack %d: %s %d %s\n", total--, Nuitka_String_AsString(current_repr), Py_REFCNT(current),
820                      Nuitka_String_AsString(code_repr));
821 
822         Py_DECREF(current_repr);
823         Py_DECREF(code_repr);
824 
825         current = current->f_back;
826     }
827 
828     PRINT_STRING(">---------<\n");
829 
830     RESTORE_ERROR_OCCURRED(saved_exception_type, saved_exception_value, saved_exception_tb);
831 }
832