3#ifndef __NUITKA_ALLOCATOR_H__
4#define __NUITKA_ALLOCATOR_H__
8#include "nuitka/prelude.h"
12#if PYTHON_VERSION < 0x270 && !defined(_PyObject_GC_IS_TRACKED)
13#define _PyObject_GC_IS_TRACKED(obj) (1)
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);
24extern void (*python_mem_free)(
void *ctx,
void *ptr);
28extern void *python_obj_ctx;
29extern void *python_mem_ctx;
31#define python_obj_ctx (NULL)
32#define python_mem_ctx (NULL)
35extern void initNuitkaAllocators(
void);
38NUITKA_MAY_BE_UNUSED
static void *NuitkaObject_Malloc(
size_t size) {
return python_obj_malloc(python_obj_ctx, size); }
41NUITKA_MAY_BE_UNUSED
static void *NuitkaMem_Malloc(
size_t size) {
return python_mem_malloc(python_mem_ctx, size); }
44NUITKA_MAY_BE_UNUSED
static void *NuitkaMem_Calloc(
size_t nelem,
size_t elsize) {
45 return python_mem_calloc(python_mem_ctx, nelem, elsize);
48#ifndef Py_GIL_DISABLED
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);
54NUITKA_MAY_BE_UNUSED
static void NuitkaMem_Free(
void *ptr) { python_mem_free(python_mem_ctx, ptr); }
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
66#define NuitkaMem_Realloc(ptr, new_size) PyMem_Realloc(ptr, new_size)
68#define NuitkaMem_Realloc(ptr, new_size) PyMem_REALLOC(ptr, new_size)
71#define NuitkaMem_Free(ptr) PyMem_Free(ptr)
76static inline void Nuitka_Py_IncRefTotal(PyThreadState *tstate) {
77#if PYTHON_VERSION < 0x3c0
79#elif _NUITKA_MODULE_MODE && PYTHON_VERSION >= 0x3e0 && PYTHON_VERSION < 0x3f0
80 _Py_IncRefTotal(tstate);
83 tstate->interp->object_state.reftotal++;
87static inline void Nuitka_Py_DecRefTotal(PyThreadState *tstate) {
88#if PYTHON_VERSION < 0x3c0
90#elif _NUITKA_MODULE_MODE && PYTHON_VERSION >= 0x3e0 && PYTHON_VERSION < 0x3f0
91 _Py_DecRefTotal(tstate);
94 tstate->interp->object_state.reftotal--;
98#define Nuitka_Py_IncRefTotal(tstate)
99#define Nuitka_Py_DecRefTotal(tstate)
102#if PYTHON_VERSION >= 0x380 && PYTHON_VERSION < 0x3c0
104static inline void _Nuitka_Py_DECREF(PyObject *ob) {
105 assert(ob != NULL && ob->ob_refcnt >= 0);
109 Nuitka_Py_DecRefTotal(_PyThreadState_GET());
110 if (--ob->ob_refcnt == 0) {
111 destructor dealloc = Py_TYPE(ob)->tp_dealloc;
113 _Py_ForgetReference(ob);
120#define Py_DECREF(ob) _Nuitka_Py_DECREF((PyObject *)(ob))
123static inline void _Nuitka_Py_XDECREF(PyObject *ob) {
125 assert(ob->ob_refcnt >= 0);
129 Nuitka_Py_DecRefTotal(_PyThreadState_GET());
130 if (--ob->ob_refcnt == 0) {
131 destructor dealloc = Py_TYPE(ob)->tp_dealloc;
133 _Py_ForgetReference(ob);
141#define Py_XDECREF(ob) _Nuitka_Py_XDECREF((PyObject *)(ob))
145#define Py_CLEAR(op) \
147 PyObject *_py_tmp = (PyObject *)(op); \
148 if (_py_tmp != NULL) { \
150 Py_DECREF(_py_tmp); \
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)
158#define Py_DECREF(arg) \
160 PyObject *op = _PyObject_CAST(arg); \
161 if (_Py_IsImmortal(op)) { \
164 _Py_DECREF_STAT_INC(); \
165 if (--op->ob_refcnt == 0) { \
166 destructor dealloc = Py_TYPE(op)->tp_dealloc; \
172#define Py_XDECREF(arg) \
174 PyObject *xop = _PyObject_CAST(arg); \
181#define Py_IS_TYPE(ob, type) (_PyObject_CAST(ob)->ob_type == (type))
183#undef _Py_DECREF_SPECIALIZED
184#define _Py_DECREF_SPECIALIZED(arg, dealloc) \
186 PyObject *op = _PyObject_CAST(arg); \
187 if (_Py_IsImmortal(op)) { \
190 _Py_DECREF_STAT_INC(); \
191 if (--op->ob_refcnt == 0) { \
192 destructor d = (destructor)(dealloc); \
199#if PYTHON_VERSION < 0x3e0
200#define _Py_IMMORTAL_INITIAL_REFCNT _Py_IMMORTAL_REFCNT
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)
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)
213#define Py_INCREF_IMMORTAL(value)
214#define Py_DECREF_IMMORTAL(value)
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)
225#if PYTHON_VERSION >= 0x390
226static inline void Nuitka_Py_NewReferenceNoTotal(PyObject *op) {
227 Py_SET_REFCNT(op, 1);
229#if PYTHON_VERSION >= 0x3e0 && defined(Py_REF_DEBUG)
230 _PyReftracerTrack(op, PyRefTracer_CREATE);
233static inline void Nuitka_Py_NewReference(PyObject *op) {
234 Nuitka_Py_IncRefTotal(_PyThreadState_GET());
235#if !defined(Py_GIL_DISABLED)
237#if PYTHON_VERSION < 0x3e0
241 op->ob_refcnt_full = 1;
242 assert(op->ob_refcnt == 1);
243 assert(op->ob_flags == 0);
249 op->ob_tid = _Py_ThreadId();
250#if PYTHON_VERSION >= 0x3e0
255 op->ob_mutex = (PyMutex){0};
257 op->ob_ref_local = 1;
258 op->ob_ref_shared = 0;
261 Nuitka_Py_NewReferenceNoTotal(op);
264#define Nuitka_Py_NewReferenceNoTotal(op) _Py_NewReferenceNoTotal(op)
265#define Nuitka_Py_NewReference(op) _Py_NewReference(op)
268static inline int Nuitka_PyType_HasFeature(PyTypeObject *type,
unsigned long feature) {
269 return ((type->tp_flags & feature) != 0);
272#if PYTHON_VERSION >= 0x3d0
274static inline bool Nuitka_PyType_HasInlineValues(PyTypeObject *tp) {
276 return Nuitka_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && Nuitka_PyType_HasFeature(tp, Py_TPFLAGS_INLINE_VALUES);
279static inline size_t Nuitka_PyType_InlineValuesSize(PyTypeObject *tp) {
280 if (!Nuitka_PyType_HasInlineValues(tp)) {
287#if defined(__GNUC__) && __GNUC__ >= 11
288#pragma GCC diagnostic push
289#pragma GCC diagnostic ignored "-Warray-bounds"
291 size_t result = _PyInlineValuesSize(tp);
292#if defined(__GNUC__) && __GNUC__ >= 11
293#pragma GCC diagnostic pop
298static inline void Nuitka_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp) {
299 if (!Nuitka_PyType_HasInlineValues(tp)) {
306#if defined(__GNUC__) && __GNUC__ >= 11
307#pragma GCC diagnostic push
308#pragma GCC diagnostic ignored "-Warray-bounds"
310 PyDictKeysObject *keys = ((PyHeapTypeObject *)tp)->ht_cached_keys;
311#if defined(__GNUC__) && __GNUC__ >= 11
312#pragma GCC diagnostic pop
314 assert(keys != NULL);
316#ifdef Py_GIL_DISABLED
317 Py_ssize_t usable = _Py_atomic_load_ssize_relaxed(&keys->dk_usable);
320 if (keys->dk_usable > 1) {
321 _Py_atomic_store_ssize(&keys->dk_usable, keys->dk_usable - 1);
326 if (keys->dk_usable > 1) {
331 size_t size = shared_keys_usable_size(keys);
332 PyDictValues *values = _PyObject_InlineValues(obj);
335 values->capacity = (uint8_t)size;
337 values->embedded = 1;
339 for (
size_t i = 0; i < size; i++) {
340 values->values[i] = NULL;
343 _PyObject_ManagedDictPointer(obj)->dict = NULL;
347#if PYTHON_VERSION >= 0x3b0
349extern void Nuitka_PyObject_GC_Link(PyObject *op);
351static PyObject *Nuitka_PyType_AllocNoTrackVar(PyTypeObject *type, Py_ssize_t nitems) {
353 const size_t size = _PyObject_VAR_SIZE(type, nitems + 1);
356 size_t pre_size = _PyType_PreHeaderSize(type);
357 size_t inline_values_size = 0;
359#if PYTHON_VERSION >= 0x3d0
360 inline_values_size = Nuitka_PyType_InlineValuesSize(type);
363 char *alloc = (
char *)NuitkaObject_Malloc(size + pre_size + inline_values_size);
365 PyObject *obj = (PyObject *)(alloc + pre_size);
367#ifdef Py_GIL_DISABLED
369 ((PyObject **)alloc)[0] = NULL;
370 ((PyObject **)alloc)[1] = NULL;
372 Nuitka_PyObject_GC_Link(obj);
375 assert(pre_size != 0);
376 ((PyObject **)alloc)[0] = NULL;
377 ((PyObject **)alloc)[1] = NULL;
379 Nuitka_PyObject_GC_Link(obj);
384 memset(obj, 0, size);
387 assert(type->tp_itemsize != 0);
388#if PYTHON_VERSION >= 0x3e0
389 _PyObject_InitVar((PyVarObject *)obj, type, nitems);
391 Py_SET_SIZE((PyVarObject *)obj, nitems);
394 Py_SET_TYPE(obj, type);
395 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
400#if PYTHON_VERSION >= 0x3d0
401 Nuitka_PyObject_InitInlineValues(obj, type);
404#if PYTHON_VERSION < 0x3e0
405 Nuitka_Py_NewReference(obj);
411static PyObject *Nuitka_PyType_AllocNoTrack(PyTypeObject *type) {
413 size_t pre_size = _PyType_PreHeaderSize(type);
414 size_t size = _PyObject_SIZE(type);
416#if PYTHON_VERSION >= 0x3d0
417 size += Nuitka_PyType_InlineValuesSize(type);
420 char *alloc = (
char *)NuitkaObject_Malloc(size + pre_size);
422 PyObject *obj = (PyObject *)(alloc + pre_size);
424#ifdef Py_GIL_DISABLED
426 ((PyObject **)alloc)[0] = NULL;
427 ((PyObject **)alloc)[1] = NULL;
429 Nuitka_PyObject_GC_Link(obj);
432 assert(pre_size != 0);
433 ((PyObject **)alloc)[0] = NULL;
434 ((PyObject **)alloc)[1] = NULL;
436 Nuitka_PyObject_GC_Link(obj);
440#if PYTHON_VERSION >= 0x3e0
441 _PyObject_Init(obj, type);
443 Py_SET_TYPE(obj, type);
444 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
448#if PYTHON_VERSION >= 0x3d0
449 Nuitka_PyObject_InitInlineValues(obj, type);
452#if PYTHON_VERSION < 0x3e0
453 Nuitka_Py_NewReference(obj);
462NUITKA_MAY_BE_UNUSED
static void *Nuitka_GC_NewVar(PyTypeObject *type, Py_ssize_t nitems) {
465#if PYTHON_VERSION < 0x3b0
466 size_t size = _PyObject_VAR_SIZE(type, nitems);
467 PyVarObject *op = (PyVarObject *)_PyObject_GC_Malloc(size);
470 Py_SIZE(op) = nitems;
471 Py_SET_TYPE(op, type);
473#if PYTHON_VERSION >= 0x380
476 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
481 Nuitka_Py_NewReference((PyObject *)op);
486 PyObject *op = Nuitka_PyType_AllocNoTrackVar(type, nitems);
488 assert(Py_SIZE(op) == nitems);
492NUITKA_MAY_BE_UNUSED
static void *Nuitka_GC_New(PyTypeObject *type) {
493#if PYTHON_VERSION < 0x3b0
494 size_t size = _PyObject_SIZE(type);
496 PyVarObject *op = (PyVarObject *)_PyObject_GC_Malloc(size);
499 Py_SET_TYPE(op, type);
501#if PYTHON_VERSION >= 0x380
504 if (Nuitka_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
509 Nuitka_Py_NewReference((PyObject *)op);
512 PyObject *op = Nuitka_PyType_AllocNoTrack(type);
517static bool inline Nuitka_GC_IS_TRACKED_X(PyObject *
object) {
518 return object == NULL || _PyObject_GC_IS_TRACKED(
object);
522#if PYTHON_VERSION >= 0x3c0
523static void inline Py_SET_REFCNT_IMMORTAL(PyObject *
object) {
524 assert(
object != NULL);
527 if (_PyObject_IS_GC(
object) && _PyObject_GC_IS_TRACKED(
object)) {
528 Nuitka_GC_UnTrack(
object);
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);
541#if (PYTHON_VERSION >= 0x3e0) && (SIZEOF_VOID_P > 4)
542 object->ob_flags = _Py_IMMORTAL_FLAGS;
543 object->ob_refcnt = _Py_IMMORTAL_INITIAL_REFCNT;
545 object->ob_refcnt = _Py_IMMORTAL_INITIAL_REFCNT;
551#define Py_SET_REFCNT_IMMORTAL(object)
556#define _Py_CAST(type, expr) ((type)(expr))
559#ifndef _PyObject_CAST
560#define _PyObject_CAST(op) _Py_CAST(PyObject *, (op))
565#define Py_SETREF(dst, src) \
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); \
573#define Py_SETREF(dst, src) \
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); \
589#define Py_XSETREF(dst, src) \
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); \
597#define Py_XSETREF(dst, src) \
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); \