Nuitka
The Python compiler
Loading...
Searching...
No Matches
allocator.h
1// Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
2
3#ifndef __NUITKA_ALLOCATOR_H__
4#define __NUITKA_ALLOCATOR_H__
5
6/* This file is included from another C file, help IDEs to still parse it on its own. */
7#ifdef __IDE_ONLY__
8#include "nuitka/prelude.h"
9#endif
10
11// For Python2.6, these assertions cannot be done easily, just disable them with dummy code.
12#if PYTHON_VERSION < 0x270 && !defined(_PyObject_GC_IS_TRACKED)
13#define _PyObject_GC_IS_TRACKED(obj) (1)
14#endif
15
16// The full API is available for Python 3.5 only
17#if PYTHON_VERSION >= 0x350 && !defined(_NUITKA_EXPERIMENTAL_DISABLE_ALLOCATORS)
18extern void *(*python_obj_malloc)(void *ctx, size_t size);
19extern void *(*python_mem_malloc)(void *ctx, size_t size);
20extern void *(*python_mem_calloc)(void *ctx, size_t nelem, size_t elsize);
21#ifndef Py_GIL_DISABLED
22extern void *(*python_mem_realloc)(void *ctx, void *ptr, size_t new_size);
23#else
24extern void (*python_mem_free)(void *ctx, void *ptr);
25#endif
26
27#if defined(Py_DEBUG)
28extern void *python_obj_ctx;
29extern void *python_mem_ctx;
30#else
31#define python_obj_ctx (NULL)
32#define python_mem_ctx (NULL)
33#endif
34
35extern void initNuitkaAllocators(void);
36
37// Our version of "PyObject_Malloc".
38NUITKA_MAY_BE_UNUSED static void *NuitkaObject_Malloc(size_t size) { return python_obj_malloc(python_obj_ctx, size); }
39
40// Our version of "PyMem_Malloc".
41NUITKA_MAY_BE_UNUSED static void *NuitkaMem_Malloc(size_t size) { return python_mem_malloc(python_mem_ctx, size); }
42
43// Our version of "PyMem_Calloc".
44NUITKA_MAY_BE_UNUSED static void *NuitkaMem_Calloc(size_t nelem, size_t elsize) {
45 return python_mem_calloc(python_mem_ctx, nelem, elsize);
46}
47
48#ifndef Py_GIL_DISABLED
49// Our version of "PyMem_Realloc".
50NUITKA_MAY_BE_UNUSED static void *NuitkaMem_Realloc(void *ptr, size_t new_size) {
51 return python_mem_realloc(python_mem_ctx, ptr, new_size);
52}
53#else
54NUITKA_MAY_BE_UNUSED static void NuitkaMem_Free(void *ptr) { python_mem_free(python_mem_ctx, ptr); }
55#endif
56
57#else
58#define NuitkaObject_Malloc(size) PyObject_MALLOC(size)
59#define NuitkaMem_Malloc(size) PyMem_MALLOC(size)
60#define NuitkaMem_Calloc(elem, elsize) PyMem_Calloc(elem, elsize)
61#ifndef Py_GIL_DISABLED
62#if defined(_WIN32)
63// On Windows, mixing different runtime DLLs can cause issues at
64// release, so we need to go through the API to get the proper
65// DLL runtime.
66#define NuitkaMem_Realloc(ptr, new_size) PyMem_Realloc(ptr, new_size)
67#else
68#define NuitkaMem_Realloc(ptr, new_size) PyMem_REALLOC(ptr, new_size)
69#endif
70#else
71#define NuitkaMem_Free(ptr) PyMem_Free(ptr)
72#endif
73#endif
74
75#ifdef Py_REF_DEBUG
76static inline void Nuitka_Py_IncRefTotal(PyThreadState *tstate) {
77#if PYTHON_VERSION < 0x3c0
78 _Py_RefTotal++;
79#elif _NUITKA_MODULE_MODE && PYTHON_VERSION >= 0x3e0 && PYTHON_VERSION < 0x3f0
80 _Py_IncRefTotal(tstate);
81#else
82 // Refcounts are now in the interpreter state, spell-checker: ignore reftotal
83 tstate->interp->object_state.reftotal++;
84#endif
85}
86
87static inline void Nuitka_Py_DecRefTotal(PyThreadState *tstate) {
88#if PYTHON_VERSION < 0x3c0
89 _Py_RefTotal--;
90#elif _NUITKA_MODULE_MODE && PYTHON_VERSION >= 0x3e0 && PYTHON_VERSION < 0x3f0
91 _Py_DecRefTotal(tstate);
92#else
93 // Refcounts are now in the interpreter state, spell-checker: ignore reftotal
94 tstate->interp->object_state.reftotal--;
95#endif
96}
97#else
98#define Nuitka_Py_IncRefTotal(tstate)
99#define Nuitka_Py_DecRefTotal(tstate)
100#endif
101
102#if PYTHON_VERSION >= 0x380 && PYTHON_VERSION < 0x3c0
103// Need to make Py_DECREF a macro again that doesn't call an API
104static inline void _Nuitka_Py_DECREF(PyObject *ob) {
105 assert(ob != NULL && ob->ob_refcnt >= 0);
106
107 // Non-limited C API and limited C API for Python 3.9 and older access
108 // directly PyObject.ob_refcnt.
109 Nuitka_Py_DecRefTotal(_PyThreadState_GET());
110 if (--ob->ob_refcnt == 0) {
111 destructor dealloc = Py_TYPE(ob)->tp_dealloc;
112#ifdef Py_TRACE_REFS
113 _Py_ForgetReference(ob);
114#endif
115 (*dealloc)(ob);
116 }
117}
118
119#undef Py_DECREF
120#define Py_DECREF(ob) _Nuitka_Py_DECREF((PyObject *)(ob))
121
122// Need to make Py_XDECREF a macro again that doesn't call an API
123static inline void _Nuitka_Py_XDECREF(PyObject *ob) {
124 if (ob != NULL) {
125 assert(ob->ob_refcnt >= 0);
126
127 // Non-limited C API and limited C API for Python 3.9 and older access
128 // directly PyObject.ob_refcnt.
129 Nuitka_Py_DecRefTotal(_PyThreadState_GET());
130 if (--ob->ob_refcnt == 0) {
131 destructor dealloc = Py_TYPE(ob)->tp_dealloc;
132#ifdef Py_TRACE_REFS
133 _Py_ForgetReference(ob);
134#endif
135 (*dealloc)(ob);
136 }
137 }
138}
139
140#undef Py_XDECREF
141#define Py_XDECREF(ob) _Nuitka_Py_XDECREF((PyObject *)(ob))
142
143// Need to make Py_XDECREF a macro again that uses our Py_DECREF
144#undef Py_CLEAR
145#define Py_CLEAR(op) \
146 do { \
147 PyObject *_py_tmp = (PyObject *)(op); \
148 if (_py_tmp != NULL) { \
149 (op) = NULL; \
150 Py_DECREF(_py_tmp); \
151 } \
152 } while (0)
153
154#elif PYTHON_VERSION >= 0x3c0 && defined(_WIN32) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && \
155 !defined(Py_GIL_DISABLED) && !defined(_NUITKA_EXPERIMENTAL_DISABLE_PY_DECREF_OVERRIDE)
156
157#undef Py_DECREF
158#define Py_DECREF(arg) \
159 do { \
160 PyObject *op = _PyObject_CAST(arg); \
161 if (_Py_IsImmortal(op)) { \
162 break; \
163 } \
164 _Py_DECREF_STAT_INC(); \
165 if (--op->ob_refcnt == 0) { \
166 destructor dealloc = Py_TYPE(op)->tp_dealloc; \
167 (*dealloc)(op); \
168 } \
169 } while (0)
170
171#undef Py_XDECREF
172#define Py_XDECREF(arg) \
173 do { \
174 PyObject *xop = _PyObject_CAST(arg); \
175 if (xop != NULL) { \
176 Py_DECREF(xop); \
177 } \
178 } while (0)
179
180#undef Py_IS_TYPE
181#define Py_IS_TYPE(ob, type) (_PyObject_CAST(ob)->ob_type == (type))
182
183#undef _Py_DECREF_SPECIALIZED
184#define _Py_DECREF_SPECIALIZED(arg, dealloc) \
185 do { \
186 PyObject *op = _PyObject_CAST(arg); \
187 if (_Py_IsImmortal(op)) { \
188 break; \
189 } \
190 _Py_DECREF_STAT_INC(); \
191 if (--op->ob_refcnt == 0) { \
192 destructor d = (destructor)(dealloc); \
193 d(op); \
194 } \
195 } while (0)
196#endif
197
198// Note: The value should be used >= for checking immortality.
199#if PYTHON_VERSION < 0x3e0
200#define _Py_IMMORTAL_INITIAL_REFCNT _Py_IMMORTAL_REFCNT
201#endif
202
203// For Python3.12, avoid reference management if value is known to be immortal.
204#if PYTHON_VERSION < 0x3c0
205#define Py_INCREF_IMMORTAL(value) Py_INCREF(value)
206#define Py_DECREF_IMMORTAL(value) Py_DECREF(value)
207#elif defined(_NUITKA_DEBUG_DEBUG_IMMORTAL)
208// We strive for Nuitka to never harm these, the assertion is going to fail with
209// third party extension modules.
210#define Py_INCREF_IMMORTAL(value) assert(Py_REFCNT(value) == _Py_IMMORTAL_INITIAL_REFCNT)
211#define Py_DECREF_IMMORTAL(value) assert(Py_REFCNT(value) == _Py_IMMORTAL_INITIAL_REFCNT)
212#else
213#define Py_INCREF_IMMORTAL(value)
214#define Py_DECREF_IMMORTAL(value)
215#endif
216
217// Macro introduced with Python3.9 or higher, make it generally available.
218#ifndef Py_SET_TYPE
219static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { ob->ob_type = type; }
220#define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject *)(ob), type)
221#endif
222
223// After Python 3.9 this was moved into the DLL potentially, making
224// it expensive to call.
225#if PYTHON_VERSION >= 0x390
226static inline void Nuitka_Py_NewReferenceNoTotal(PyObject *op) {
227 Py_SET_REFCNT(op, 1);
228
229#if PYTHON_VERSION >= 0x3e0 && defined(Py_REF_DEBUG)
230 _PyReftracerTrack(op, PyRefTracer_CREATE);
231#endif
232}
233static inline void Nuitka_Py_NewReference(PyObject *op) {
234 Nuitka_Py_IncRefTotal(_PyThreadState_GET());
235#if !defined(Py_GIL_DISABLED)
236
237#if PYTHON_VERSION < 0x3e0
238 op->ob_refcnt = 1;
239#else
240#if SIZEOF_VOID_P > 4
241 op->ob_refcnt_full = 1;
242 assert(op->ob_refcnt == 1);
243 assert(op->ob_flags == 0);
244#else
245 op->ob_refcnt = 1;
246#endif
247#endif
248#else
249 op->ob_tid = _Py_ThreadId();
250#if PYTHON_VERSION >= 0x3e0
251 op->ob_flags = 0;
252#else
253 op->_padding = 0;
254#endif
255 op->ob_mutex = (PyMutex){0};
256 op->ob_gc_bits = 0;
257 op->ob_ref_local = 1;
258 op->ob_ref_shared = 0;
259#endif
260
261 Nuitka_Py_NewReferenceNoTotal(op);
262}
263#else
264#define Nuitka_Py_NewReferenceNoTotal(op) _Py_NewReferenceNoTotal(op)
265#define Nuitka_Py_NewReference(op) _Py_NewReference(op)
266#endif
267
268static inline int Nuitka_PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
269 return ((type->tp_flags & feature) != 0);
270}
271
272#if PYTHON_VERSION >= 0x3d0
273
274static inline bool Nuitka_PyType_HasInlineValues(PyTypeObject *tp) {
275 // Inline values are stored via heap type cached keys.
276 return Nuitka_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && Nuitka_PyType_HasFeature(tp, Py_TPFLAGS_INLINE_VALUES);
277}
278
279static inline size_t Nuitka_PyType_InlineValuesSize(PyTypeObject *tp) {
280 if (!Nuitka_PyType_HasInlineValues(tp)) {
281 return 0;
282 }
283
284 // GCC 11+ can still emit a false-positive "-Warray-bounds" for the
285 // PyHeapTypeObject cast in '_PyInlineValuesSize' after the heap type
286 // check above. CPython applies the same workaround elsewhere.
287#if defined(__GNUC__) && __GNUC__ >= 11
288#pragma GCC diagnostic push
289#pragma GCC diagnostic ignored "-Warray-bounds"
290#endif
291 size_t result = _PyInlineValuesSize(tp);
292#if defined(__GNUC__) && __GNUC__ >= 11
293#pragma GCC diagnostic pop
294#endif
295 return result;
296}
297
298static inline void Nuitka_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp) {
299 if (!Nuitka_PyType_HasInlineValues(tp)) {
300 return;
301 }
302
303 // GCC 11+ can still emit a false-positive "-Warray-bounds" for the
304 // PyHeapTypeObject cast after the heap type check above. CPython applies
305 // the same workaround elsewhere.
306#if defined(__GNUC__) && __GNUC__ >= 11
307#pragma GCC diagnostic push
308#pragma GCC diagnostic ignored "-Warray-bounds"
309#endif
310 PyDictKeysObject *keys = ((PyHeapTypeObject *)tp)->ht_cached_keys;
311#if defined(__GNUC__) && __GNUC__ >= 11
312#pragma GCC diagnostic pop
313#endif
314 assert(keys != NULL);
315
316#ifdef Py_GIL_DISABLED
317 Py_ssize_t usable = _Py_atomic_load_ssize_relaxed(&keys->dk_usable);
318 if (usable > 1) {
319 LOCK_KEYS(keys);
320 if (keys->dk_usable > 1) {
321 _Py_atomic_store_ssize(&keys->dk_usable, keys->dk_usable - 1);
322 }
323 UNLOCK_KEYS(keys);
324 }
325#else
326 if (keys->dk_usable > 1) {
327 keys->dk_usable--;
328 }
329#endif
330
331 size_t size = shared_keys_usable_size(keys);
332 PyDictValues *values = _PyObject_InlineValues(obj);
333
334 assert(size < 256);
335 values->capacity = (uint8_t)size;
336 values->size = 0;
337 values->embedded = 1;
338 values->valid = 1;
339 for (size_t i = 0; i < size; i++) {
340 values->values[i] = NULL;
341 }
342
343 _PyObject_ManagedDictPointer(obj)->dict = NULL;
344}
345#endif
346
347#if PYTHON_VERSION >= 0x3b0
348
349extern void Nuitka_PyObject_GC_Link(PyObject *op);
350
351static PyObject *Nuitka_PyType_AllocNoTrackVar(PyTypeObject *type, Py_ssize_t nitems) {
352 // There is always a sentinel now, therefore add one
353 const size_t size = _PyObject_VAR_SIZE(type, nitems + 1);
354
355 // TODO: This ought to be static for all our types, so remove it as a call.
356 size_t pre_size = _PyType_PreHeaderSize(type);
357 size_t inline_values_size = 0;
358
359#if PYTHON_VERSION >= 0x3d0
360 inline_values_size = Nuitka_PyType_InlineValuesSize(type);
361#endif
362
363 char *alloc = (char *)NuitkaObject_Malloc(size + pre_size + inline_values_size);
364 assert(alloc);
365 PyObject *obj = (PyObject *)(alloc + pre_size);
366
367#ifdef Py_GIL_DISABLED
368 if (pre_size) {
369 ((PyObject **)alloc)[0] = NULL;
370 ((PyObject **)alloc)[1] = NULL;
371
372 Nuitka_PyObject_GC_Link(obj);
373 }
374#else
375 assert(pre_size != 0);
376 ((PyObject **)alloc)[0] = NULL;
377 ((PyObject **)alloc)[1] = NULL;
378
379 Nuitka_PyObject_GC_Link(obj);
380#endif
381
382 // We might be able to avoid this, but it's unclear what e.g. the sentinel
383 // is supposed to be.
384 memset(obj, 0, size);
385
386 // This is the "var" branch, we already know we are variable size here.
387 assert(type->tp_itemsize != 0);
388#if PYTHON_VERSION >= 0x3e0
389 _PyObject_InitVar((PyVarObject *)obj, type, nitems);
390#else
391 Py_SET_SIZE((PyVarObject *)obj, nitems);
392
393 // Initialize the object references.
394 Py_SET_TYPE(obj, type);
395 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
396 Py_INCREF(type);
397 }
398#endif
399
400#if PYTHON_VERSION >= 0x3d0
401 Nuitka_PyObject_InitInlineValues(obj, type);
402#endif
403
404#if PYTHON_VERSION < 0x3e0
405 Nuitka_Py_NewReference(obj);
406#endif
407
408 return obj;
409}
410
411static PyObject *Nuitka_PyType_AllocNoTrack(PyTypeObject *type) {
412 // TODO: This ought to be static for all our types, so remove it as a call.
413 size_t pre_size = _PyType_PreHeaderSize(type);
414 size_t size = _PyObject_SIZE(type);
415
416#if PYTHON_VERSION >= 0x3d0
417 size += Nuitka_PyType_InlineValuesSize(type);
418#endif
419
420 char *alloc = (char *)NuitkaObject_Malloc(size + pre_size);
421 assert(alloc);
422 PyObject *obj = (PyObject *)(alloc + pre_size);
423
424#ifdef Py_GIL_DISABLED
425 if (pre_size) {
426 ((PyObject **)alloc)[0] = NULL;
427 ((PyObject **)alloc)[1] = NULL;
428
429 Nuitka_PyObject_GC_Link(obj);
430 }
431#else
432 assert(pre_size != 0);
433 ((PyObject **)alloc)[0] = NULL;
434 ((PyObject **)alloc)[1] = NULL;
435
436 Nuitka_PyObject_GC_Link(obj);
437#endif
438
439 // Initialize the object references.
440#if PYTHON_VERSION >= 0x3e0
441 _PyObject_Init(obj, type);
442#else
443 Py_SET_TYPE(obj, type);
444 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
445 Py_INCREF(type);
446 }
447#endif
448#if PYTHON_VERSION >= 0x3d0
449 Nuitka_PyObject_InitInlineValues(obj, type);
450#endif
451
452#if PYTHON_VERSION < 0x3e0
453 Nuitka_Py_NewReference(obj);
454#endif
455
456 return obj;
457}
458#endif
459
460#endif
461
462NUITKA_MAY_BE_UNUSED static void *Nuitka_GC_NewVar(PyTypeObject *type, Py_ssize_t nitems) {
463 assert(nitems >= 0);
464
465#if PYTHON_VERSION < 0x3b0
466 size_t size = _PyObject_VAR_SIZE(type, nitems);
467 PyVarObject *op = (PyVarObject *)_PyObject_GC_Malloc(size);
468 assert(op != NULL);
469
470 Py_SIZE(op) = nitems;
471 Py_SET_TYPE(op, type);
472
473#if PYTHON_VERSION >= 0x380
474 // TODO: Might have two variants, or more sure this is also false for all of our types,
475 // we are just wasting time for compiled times here.
476 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
477 Py_INCREF(type);
478 }
479#endif
480
481 Nuitka_Py_NewReference((PyObject *)op);
482
483 return op;
484#else
485 // TODO: We ought to inline this probably too, no point as a separate function.
486 PyObject *op = Nuitka_PyType_AllocNoTrackVar(type, nitems);
487#endif
488 assert(Py_SIZE(op) == nitems);
489 return op;
490}
491
492NUITKA_MAY_BE_UNUSED static void *Nuitka_GC_New(PyTypeObject *type) {
493#if PYTHON_VERSION < 0x3b0
494 size_t size = _PyObject_SIZE(type);
495
496 PyVarObject *op = (PyVarObject *)_PyObject_GC_Malloc(size);
497 assert(op != NULL);
498
499 Py_SET_TYPE(op, type);
500
501#if PYTHON_VERSION >= 0x380
502 // TODO: Might have two variants, or more sure this is also false for all of our types,
503 // we are just wasting time for compiled times here.
504 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
505 Py_INCREF(type);
506 }
507#endif
508
509 Nuitka_Py_NewReference((PyObject *)op);
510#else
511 // TODO: We ought to inline this probably too, no point as a separate function.
512 PyObject *op = Nuitka_PyType_AllocNoTrack(type);
513#endif
514 return op;
515}
516
517static bool inline Nuitka_GC_IS_TRACKED_X(PyObject *object) {
518 return object == NULL || _PyObject_GC_IS_TRACKED(object);
519}
520
521// To allow us marking some of our own values as immortal.
522#if PYTHON_VERSION >= 0x3c0
523static void inline Py_SET_REFCNT_IMMORTAL(PyObject *object) {
524 assert(object != NULL);
525
526 // Normally done only with 3.13, but it makes sense to do this.
527 if (_PyObject_IS_GC(object) && _PyObject_GC_IS_TRACKED(object)) {
528 Nuitka_GC_UnTrack(object);
529 }
530
531#ifdef Py_GIL_DISABLED
532 object->ob_tid = _Py_UNOWNED_TID;
533 object->ob_ref_local = _Py_IMMORTAL_INITIAL_REFCNT;
534 object->ob_ref_shared = 0;
535#if PYTHON_VERSION >= 0x3e0
536 _Py_atomic_or_uint8(&op->ob_gc_bits, _PyGC_BITS_DEFERRED);
537#endif
538
539#else
540
541#if (PYTHON_VERSION >= 0x3e0) && (SIZEOF_VOID_P > 4)
542 object->ob_flags = _Py_IMMORTAL_FLAGS;
543 object->ob_refcnt = _Py_IMMORTAL_INITIAL_REFCNT;
544#else
545 object->ob_refcnt = _Py_IMMORTAL_INITIAL_REFCNT;
546#endif
547
548#endif
549}
550#else
551#define Py_SET_REFCNT_IMMORTAL(object)
552#endif
553
554// Have these defines from newer Python for all Python versions available
555#ifndef _Py_CAST
556#define _Py_CAST(type, expr) ((type)(expr))
557#endif
558
559#ifndef _PyObject_CAST
560#define _PyObject_CAST(op) _Py_CAST(PyObject *, (op))
561#endif
562
563#ifndef Py_SETREF
564#ifdef _Py_TYPEOF
565#define Py_SETREF(dst, src) \
566 do { \
567 _Py_TYPEOF(dst) *_tmp_dst_ptr = &(dst); \
568 _Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
569 *_tmp_dst_ptr = (src); \
570 Py_DECREF(_tmp_old_dst); \
571 } while (0)
572#else
573#define Py_SETREF(dst, src) \
574 do { \
575 PyObject **_tmp_dst_ptr = _Py_CAST(PyObject **, &(dst)); \
576 PyObject *_tmp_old_dst = (*_tmp_dst_ptr); \
577 PyObject *_tmp_src = _PyObject_CAST(src); \
578 memcpy(_tmp_dst_ptr, &_tmp_src, sizeof(PyObject *)); \
579 Py_DECREF(_tmp_old_dst); \
580 } while (0)
581#endif
582#endif
583
584#ifndef Py_XSETREF
585/* Py_XSETREF() is a variant of Py_SETREF() that uses Py_XDECREF() instead of
586 * Py_DECREF().
587 */
588#ifdef _Py_TYPEOF
589#define Py_XSETREF(dst, src) \
590 do { \
591 _Py_TYPEOF(dst) *_tmp_dst_ptr = &(dst); \
592 _Py_TYPEOF(dst) _tmp_old_dst = (*_tmp_dst_ptr); \
593 *_tmp_dst_ptr = (src); \
594 Py_XDECREF(_tmp_old_dst); \
595 } while (0)
596#else
597#define Py_XSETREF(dst, src) \
598 do { \
599 PyObject **_tmp_dst_ptr = _Py_CAST(PyObject **, &(dst)); \
600 PyObject *_tmp_old_dst = (*_tmp_dst_ptr); \
601 PyObject *_tmp_src = _PyObject_CAST(src); \
602 memcpy(_tmp_dst_ptr, &_tmp_src, sizeof(PyObject *)); \
603 Py_XDECREF(_tmp_old_dst); \
604 } while (0)
605#endif
606#endif
607
608// Part of "Nuitka", an optimizing Python compiler that is compatible and
609// integrates with CPython, but also works on its own.
610//
611// Licensed under the GNU Affero General Public License, Version 3 (the "License");
612// you may not use this file except in compliance with the License.
613// You may obtain a copy of the License at
614//
615// http://www.gnu.org/licenses/agpl.txt
616//
617// Unless required by applicable law or agreed to in writing, software
618// distributed under the License is distributed on an "AS IS" BASIS,
619// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
620// See the License for the specific language governing permissions and
621// limitations under the License.