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