17db96d56Sopenharmony_ci#include "Python.h"
27db96d56Sopenharmony_ci#include "pycore_pymem.h"         // _PyTraceMalloc_Config
37db96d56Sopenharmony_ci#include "pycore_code.h"         // stats
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci#include <stdbool.h>
67db96d56Sopenharmony_ci#include <stdlib.h>               // malloc()
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci/* Defined in tracemalloc.c */
107db96d56Sopenharmony_ciextern void _PyMem_DumpTraceback(int fd, const void *ptr);
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci/* Python's malloc wrappers (see pymem.h) */
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci#undef  uint
167db96d56Sopenharmony_ci#define uint    unsigned int    /* assuming >= 16 bits */
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ci/* Forward declaration */
197db96d56Sopenharmony_cistatic void* _PyMem_DebugRawMalloc(void *ctx, size_t size);
207db96d56Sopenharmony_cistatic void* _PyMem_DebugRawCalloc(void *ctx, size_t nelem, size_t elsize);
217db96d56Sopenharmony_cistatic void* _PyMem_DebugRawRealloc(void *ctx, void *ptr, size_t size);
227db96d56Sopenharmony_cistatic void _PyMem_DebugRawFree(void *ctx, void *ptr);
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_cistatic void* _PyMem_DebugMalloc(void *ctx, size_t size);
257db96d56Sopenharmony_cistatic void* _PyMem_DebugCalloc(void *ctx, size_t nelem, size_t elsize);
267db96d56Sopenharmony_cistatic void* _PyMem_DebugRealloc(void *ctx, void *ptr, size_t size);
277db96d56Sopenharmony_cistatic void _PyMem_DebugFree(void *ctx, void *p);
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_cistatic void _PyObject_DebugDumpAddress(const void *p);
307db96d56Sopenharmony_cistatic void _PyMem_DebugCheckAddress(const char *func, char api_id, const void *p);
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_cistatic void _PyMem_SetupDebugHooksDomain(PyMemAllocatorDomain domain);
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci#if defined(__has_feature)  /* Clang */
357db96d56Sopenharmony_ci#  if __has_feature(address_sanitizer) /* is ASAN enabled? */
367db96d56Sopenharmony_ci#    define _Py_NO_SANITIZE_ADDRESS \
377db96d56Sopenharmony_ci        __attribute__((no_sanitize("address")))
387db96d56Sopenharmony_ci#  endif
397db96d56Sopenharmony_ci#  if __has_feature(thread_sanitizer)  /* is TSAN enabled? */
407db96d56Sopenharmony_ci#    define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
417db96d56Sopenharmony_ci#  endif
427db96d56Sopenharmony_ci#  if __has_feature(memory_sanitizer)  /* is MSAN enabled? */
437db96d56Sopenharmony_ci#    define _Py_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
447db96d56Sopenharmony_ci#  endif
457db96d56Sopenharmony_ci#elif defined(__GNUC__)
467db96d56Sopenharmony_ci#  if defined(__SANITIZE_ADDRESS__)    /* GCC 4.8+, is ASAN enabled? */
477db96d56Sopenharmony_ci#    define _Py_NO_SANITIZE_ADDRESS \
487db96d56Sopenharmony_ci        __attribute__((no_sanitize_address))
497db96d56Sopenharmony_ci#  endif
507db96d56Sopenharmony_ci   // TSAN is supported since GCC 5.1, but __SANITIZE_THREAD__ macro
517db96d56Sopenharmony_ci   // is provided only since GCC 7.
527db96d56Sopenharmony_ci#  if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)
537db96d56Sopenharmony_ci#    define _Py_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
547db96d56Sopenharmony_ci#  endif
557db96d56Sopenharmony_ci#endif
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci#ifndef _Py_NO_SANITIZE_ADDRESS
587db96d56Sopenharmony_ci#  define _Py_NO_SANITIZE_ADDRESS
597db96d56Sopenharmony_ci#endif
607db96d56Sopenharmony_ci#ifndef _Py_NO_SANITIZE_THREAD
617db96d56Sopenharmony_ci#  define _Py_NO_SANITIZE_THREAD
627db96d56Sopenharmony_ci#endif
637db96d56Sopenharmony_ci#ifndef _Py_NO_SANITIZE_MEMORY
647db96d56Sopenharmony_ci#  define _Py_NO_SANITIZE_MEMORY
657db96d56Sopenharmony_ci#endif
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci#ifdef MS_WINDOWS
707db96d56Sopenharmony_ci#  include <windows.h>
717db96d56Sopenharmony_ci#elif defined(HAVE_MMAP)
727db96d56Sopenharmony_ci#  include <sys/mman.h>
737db96d56Sopenharmony_ci#  ifdef MAP_ANONYMOUS
747db96d56Sopenharmony_ci#    define ARENAS_USE_MMAP
757db96d56Sopenharmony_ci#  endif
767db96d56Sopenharmony_ci#endif
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci/* Forward declaration */
797db96d56Sopenharmony_cistatic void* _PyObject_Malloc(void *ctx, size_t size);
807db96d56Sopenharmony_cistatic void* _PyObject_Calloc(void *ctx, size_t nelem, size_t elsize);
817db96d56Sopenharmony_cistatic void _PyObject_Free(void *ctx, void *p);
827db96d56Sopenharmony_cistatic void* _PyObject_Realloc(void *ctx, void *ptr, size_t size);
837db96d56Sopenharmony_ci#endif
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci/* bpo-35053: Declare tracemalloc configuration here rather than
877db96d56Sopenharmony_ci   Modules/_tracemalloc.c because _tracemalloc can be compiled as dynamic
887db96d56Sopenharmony_ci   library, whereas _Py_NewReference() requires it. */
897db96d56Sopenharmony_cistruct _PyTraceMalloc_Config _Py_tracemalloc_config = _PyTraceMalloc_Config_INIT;
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_cistatic void *
937db96d56Sopenharmony_ci_PyMem_RawMalloc(void *ctx, size_t size)
947db96d56Sopenharmony_ci{
957db96d56Sopenharmony_ci    /* PyMem_RawMalloc(0) means malloc(1). Some systems would return NULL
967db96d56Sopenharmony_ci       for malloc(0), which would be treated as an error. Some platforms would
977db96d56Sopenharmony_ci       return a pointer with no memory behind it, which would break pymalloc.
987db96d56Sopenharmony_ci       To solve these problems, allocate an extra byte. */
997db96d56Sopenharmony_ci    if (size == 0)
1007db96d56Sopenharmony_ci        size = 1;
1017db96d56Sopenharmony_ci    return malloc(size);
1027db96d56Sopenharmony_ci}
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_cistatic void *
1057db96d56Sopenharmony_ci_PyMem_RawCalloc(void *ctx, size_t nelem, size_t elsize)
1067db96d56Sopenharmony_ci{
1077db96d56Sopenharmony_ci    /* PyMem_RawCalloc(0, 0) means calloc(1, 1). Some systems would return NULL
1087db96d56Sopenharmony_ci       for calloc(0, 0), which would be treated as an error. Some platforms
1097db96d56Sopenharmony_ci       would return a pointer with no memory behind it, which would break
1107db96d56Sopenharmony_ci       pymalloc.  To solve these problems, allocate an extra byte. */
1117db96d56Sopenharmony_ci    if (nelem == 0 || elsize == 0) {
1127db96d56Sopenharmony_ci        nelem = 1;
1137db96d56Sopenharmony_ci        elsize = 1;
1147db96d56Sopenharmony_ci    }
1157db96d56Sopenharmony_ci    return calloc(nelem, elsize);
1167db96d56Sopenharmony_ci}
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_cistatic void *
1197db96d56Sopenharmony_ci_PyMem_RawRealloc(void *ctx, void *ptr, size_t size)
1207db96d56Sopenharmony_ci{
1217db96d56Sopenharmony_ci    if (size == 0)
1227db96d56Sopenharmony_ci        size = 1;
1237db96d56Sopenharmony_ci    return realloc(ptr, size);
1247db96d56Sopenharmony_ci}
1257db96d56Sopenharmony_ci
1267db96d56Sopenharmony_cistatic void
1277db96d56Sopenharmony_ci_PyMem_RawFree(void *ctx, void *ptr)
1287db96d56Sopenharmony_ci{
1297db96d56Sopenharmony_ci    free(ptr);
1307db96d56Sopenharmony_ci}
1317db96d56Sopenharmony_ci
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ci#ifdef MS_WINDOWS
1347db96d56Sopenharmony_cistatic void *
1357db96d56Sopenharmony_ci_PyObject_ArenaVirtualAlloc(void *ctx, size_t size)
1367db96d56Sopenharmony_ci{
1377db96d56Sopenharmony_ci    return VirtualAlloc(NULL, size,
1387db96d56Sopenharmony_ci                        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
1397db96d56Sopenharmony_ci}
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_cistatic void
1427db96d56Sopenharmony_ci_PyObject_ArenaVirtualFree(void *ctx, void *ptr, size_t size)
1437db96d56Sopenharmony_ci{
1447db96d56Sopenharmony_ci    VirtualFree(ptr, 0, MEM_RELEASE);
1457db96d56Sopenharmony_ci}
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ci#elif defined(ARENAS_USE_MMAP)
1487db96d56Sopenharmony_cistatic void *
1497db96d56Sopenharmony_ci_PyObject_ArenaMmap(void *ctx, size_t size)
1507db96d56Sopenharmony_ci{
1517db96d56Sopenharmony_ci    void *ptr;
1527db96d56Sopenharmony_ci    ptr = mmap(NULL, size, PROT_READ|PROT_WRITE,
1537db96d56Sopenharmony_ci               MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
1547db96d56Sopenharmony_ci    if (ptr == MAP_FAILED)
1557db96d56Sopenharmony_ci        return NULL;
1567db96d56Sopenharmony_ci    assert(ptr != NULL);
1577db96d56Sopenharmony_ci    return ptr;
1587db96d56Sopenharmony_ci}
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_cistatic void
1617db96d56Sopenharmony_ci_PyObject_ArenaMunmap(void *ctx, void *ptr, size_t size)
1627db96d56Sopenharmony_ci{
1637db96d56Sopenharmony_ci    munmap(ptr, size);
1647db96d56Sopenharmony_ci}
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci#else
1677db96d56Sopenharmony_cistatic void *
1687db96d56Sopenharmony_ci_PyObject_ArenaMalloc(void *ctx, size_t size)
1697db96d56Sopenharmony_ci{
1707db96d56Sopenharmony_ci    return malloc(size);
1717db96d56Sopenharmony_ci}
1727db96d56Sopenharmony_ci
1737db96d56Sopenharmony_cistatic void
1747db96d56Sopenharmony_ci_PyObject_ArenaFree(void *ctx, void *ptr, size_t size)
1757db96d56Sopenharmony_ci{
1767db96d56Sopenharmony_ci    free(ptr);
1777db96d56Sopenharmony_ci}
1787db96d56Sopenharmony_ci#endif
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_ci#define MALLOC_ALLOC {NULL, _PyMem_RawMalloc, _PyMem_RawCalloc, _PyMem_RawRealloc, _PyMem_RawFree}
1817db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
1827db96d56Sopenharmony_ci#  define PYMALLOC_ALLOC {NULL, _PyObject_Malloc, _PyObject_Calloc, _PyObject_Realloc, _PyObject_Free}
1837db96d56Sopenharmony_ci#endif
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci#define PYRAW_ALLOC MALLOC_ALLOC
1867db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
1877db96d56Sopenharmony_ci#  define PYOBJ_ALLOC PYMALLOC_ALLOC
1887db96d56Sopenharmony_ci#else
1897db96d56Sopenharmony_ci#  define PYOBJ_ALLOC MALLOC_ALLOC
1907db96d56Sopenharmony_ci#endif
1917db96d56Sopenharmony_ci#define PYMEM_ALLOC PYOBJ_ALLOC
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_citypedef struct {
1947db96d56Sopenharmony_ci    /* We tag each block with an API ID in order to tag API violations */
1957db96d56Sopenharmony_ci    char api_id;
1967db96d56Sopenharmony_ci    PyMemAllocatorEx alloc;
1977db96d56Sopenharmony_ci} debug_alloc_api_t;
1987db96d56Sopenharmony_cistatic struct {
1997db96d56Sopenharmony_ci    debug_alloc_api_t raw;
2007db96d56Sopenharmony_ci    debug_alloc_api_t mem;
2017db96d56Sopenharmony_ci    debug_alloc_api_t obj;
2027db96d56Sopenharmony_ci} _PyMem_Debug = {
2037db96d56Sopenharmony_ci    {'r', PYRAW_ALLOC},
2047db96d56Sopenharmony_ci    {'m', PYMEM_ALLOC},
2057db96d56Sopenharmony_ci    {'o', PYOBJ_ALLOC}
2067db96d56Sopenharmony_ci    };
2077db96d56Sopenharmony_ci
2087db96d56Sopenharmony_ci#define PYDBGRAW_ALLOC \
2097db96d56Sopenharmony_ci    {&_PyMem_Debug.raw, _PyMem_DebugRawMalloc, _PyMem_DebugRawCalloc, _PyMem_DebugRawRealloc, _PyMem_DebugRawFree}
2107db96d56Sopenharmony_ci#define PYDBGMEM_ALLOC \
2117db96d56Sopenharmony_ci    {&_PyMem_Debug.mem, _PyMem_DebugMalloc, _PyMem_DebugCalloc, _PyMem_DebugRealloc, _PyMem_DebugFree}
2127db96d56Sopenharmony_ci#define PYDBGOBJ_ALLOC \
2137db96d56Sopenharmony_ci    {&_PyMem_Debug.obj, _PyMem_DebugMalloc, _PyMem_DebugCalloc, _PyMem_DebugRealloc, _PyMem_DebugFree}
2147db96d56Sopenharmony_ci
2157db96d56Sopenharmony_ci#ifdef Py_DEBUG
2167db96d56Sopenharmony_cistatic PyMemAllocatorEx _PyMem_Raw = PYDBGRAW_ALLOC;
2177db96d56Sopenharmony_cistatic PyMemAllocatorEx _PyMem = PYDBGMEM_ALLOC;
2187db96d56Sopenharmony_cistatic PyMemAllocatorEx _PyObject = PYDBGOBJ_ALLOC;
2197db96d56Sopenharmony_ci#else
2207db96d56Sopenharmony_cistatic PyMemAllocatorEx _PyMem_Raw = PYRAW_ALLOC;
2217db96d56Sopenharmony_cistatic PyMemAllocatorEx _PyMem = PYMEM_ALLOC;
2227db96d56Sopenharmony_cistatic PyMemAllocatorEx _PyObject = PYOBJ_ALLOC;
2237db96d56Sopenharmony_ci#endif
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_cistatic int
2277db96d56Sopenharmony_cipymem_set_default_allocator(PyMemAllocatorDomain domain, int debug,
2287db96d56Sopenharmony_ci                            PyMemAllocatorEx *old_alloc)
2297db96d56Sopenharmony_ci{
2307db96d56Sopenharmony_ci    if (old_alloc != NULL) {
2317db96d56Sopenharmony_ci        PyMem_GetAllocator(domain, old_alloc);
2327db96d56Sopenharmony_ci    }
2337db96d56Sopenharmony_ci
2347db96d56Sopenharmony_ci
2357db96d56Sopenharmony_ci    PyMemAllocatorEx new_alloc;
2367db96d56Sopenharmony_ci    switch(domain)
2377db96d56Sopenharmony_ci    {
2387db96d56Sopenharmony_ci    case PYMEM_DOMAIN_RAW:
2397db96d56Sopenharmony_ci        new_alloc = (PyMemAllocatorEx)PYRAW_ALLOC;
2407db96d56Sopenharmony_ci        break;
2417db96d56Sopenharmony_ci    case PYMEM_DOMAIN_MEM:
2427db96d56Sopenharmony_ci        new_alloc = (PyMemAllocatorEx)PYMEM_ALLOC;
2437db96d56Sopenharmony_ci        break;
2447db96d56Sopenharmony_ci    case PYMEM_DOMAIN_OBJ:
2457db96d56Sopenharmony_ci        new_alloc = (PyMemAllocatorEx)PYOBJ_ALLOC;
2467db96d56Sopenharmony_ci        break;
2477db96d56Sopenharmony_ci    default:
2487db96d56Sopenharmony_ci        /* unknown domain */
2497db96d56Sopenharmony_ci        return -1;
2507db96d56Sopenharmony_ci    }
2517db96d56Sopenharmony_ci    PyMem_SetAllocator(domain, &new_alloc);
2527db96d56Sopenharmony_ci    if (debug) {
2537db96d56Sopenharmony_ci        _PyMem_SetupDebugHooksDomain(domain);
2547db96d56Sopenharmony_ci    }
2557db96d56Sopenharmony_ci    return 0;
2567db96d56Sopenharmony_ci}
2577db96d56Sopenharmony_ci
2587db96d56Sopenharmony_ci
2597db96d56Sopenharmony_ciint
2607db96d56Sopenharmony_ci_PyMem_SetDefaultAllocator(PyMemAllocatorDomain domain,
2617db96d56Sopenharmony_ci                           PyMemAllocatorEx *old_alloc)
2627db96d56Sopenharmony_ci{
2637db96d56Sopenharmony_ci#ifdef Py_DEBUG
2647db96d56Sopenharmony_ci    const int debug = 1;
2657db96d56Sopenharmony_ci#else
2667db96d56Sopenharmony_ci    const int debug = 0;
2677db96d56Sopenharmony_ci#endif
2687db96d56Sopenharmony_ci    return pymem_set_default_allocator(domain, debug, old_alloc);
2697db96d56Sopenharmony_ci}
2707db96d56Sopenharmony_ci
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_ciint
2737db96d56Sopenharmony_ci_PyMem_GetAllocatorName(const char *name, PyMemAllocatorName *allocator)
2747db96d56Sopenharmony_ci{
2757db96d56Sopenharmony_ci    if (name == NULL || *name == '\0') {
2767db96d56Sopenharmony_ci        /* PYTHONMALLOC is empty or is not set or ignored (-E/-I command line
2777db96d56Sopenharmony_ci           nameions): use default memory allocators */
2787db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_DEFAULT;
2797db96d56Sopenharmony_ci    }
2807db96d56Sopenharmony_ci    else if (strcmp(name, "default") == 0) {
2817db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_DEFAULT;
2827db96d56Sopenharmony_ci    }
2837db96d56Sopenharmony_ci    else if (strcmp(name, "debug") == 0) {
2847db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_DEBUG;
2857db96d56Sopenharmony_ci    }
2867db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
2877db96d56Sopenharmony_ci    else if (strcmp(name, "pymalloc") == 0) {
2887db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_PYMALLOC;
2897db96d56Sopenharmony_ci    }
2907db96d56Sopenharmony_ci    else if (strcmp(name, "pymalloc_debug") == 0) {
2917db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_PYMALLOC_DEBUG;
2927db96d56Sopenharmony_ci    }
2937db96d56Sopenharmony_ci#endif
2947db96d56Sopenharmony_ci    else if (strcmp(name, "malloc") == 0) {
2957db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_MALLOC;
2967db96d56Sopenharmony_ci    }
2977db96d56Sopenharmony_ci    else if (strcmp(name, "malloc_debug") == 0) {
2987db96d56Sopenharmony_ci        *allocator = PYMEM_ALLOCATOR_MALLOC_DEBUG;
2997db96d56Sopenharmony_ci    }
3007db96d56Sopenharmony_ci    else {
3017db96d56Sopenharmony_ci        /* unknown allocator */
3027db96d56Sopenharmony_ci        return -1;
3037db96d56Sopenharmony_ci    }
3047db96d56Sopenharmony_ci    return 0;
3057db96d56Sopenharmony_ci}
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci
3087db96d56Sopenharmony_ciint
3097db96d56Sopenharmony_ci_PyMem_SetupAllocators(PyMemAllocatorName allocator)
3107db96d56Sopenharmony_ci{
3117db96d56Sopenharmony_ci    switch (allocator) {
3127db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_NOT_SET:
3137db96d56Sopenharmony_ci        /* do nothing */
3147db96d56Sopenharmony_ci        break;
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_DEFAULT:
3177db96d56Sopenharmony_ci        (void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, NULL);
3187db96d56Sopenharmony_ci        (void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_MEM, NULL);
3197db96d56Sopenharmony_ci        (void)_PyMem_SetDefaultAllocator(PYMEM_DOMAIN_OBJ, NULL);
3207db96d56Sopenharmony_ci        break;
3217db96d56Sopenharmony_ci
3227db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_DEBUG:
3237db96d56Sopenharmony_ci        (void)pymem_set_default_allocator(PYMEM_DOMAIN_RAW, 1, NULL);
3247db96d56Sopenharmony_ci        (void)pymem_set_default_allocator(PYMEM_DOMAIN_MEM, 1, NULL);
3257db96d56Sopenharmony_ci        (void)pymem_set_default_allocator(PYMEM_DOMAIN_OBJ, 1, NULL);
3267db96d56Sopenharmony_ci        break;
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
3297db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_PYMALLOC:
3307db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_PYMALLOC_DEBUG:
3317db96d56Sopenharmony_ci    {
3327db96d56Sopenharmony_ci        PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
3337db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc);
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci        PyMemAllocatorEx pymalloc = PYMALLOC_ALLOC;
3367db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &pymalloc);
3377db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &pymalloc);
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_ci        if (allocator == PYMEM_ALLOCATOR_PYMALLOC_DEBUG) {
3407db96d56Sopenharmony_ci            PyMem_SetupDebugHooks();
3417db96d56Sopenharmony_ci        }
3427db96d56Sopenharmony_ci        break;
3437db96d56Sopenharmony_ci    }
3447db96d56Sopenharmony_ci#endif
3457db96d56Sopenharmony_ci
3467db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_MALLOC:
3477db96d56Sopenharmony_ci    case PYMEM_ALLOCATOR_MALLOC_DEBUG:
3487db96d56Sopenharmony_ci    {
3497db96d56Sopenharmony_ci        PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
3507db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &malloc_alloc);
3517db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &malloc_alloc);
3527db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &malloc_alloc);
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci        if (allocator == PYMEM_ALLOCATOR_MALLOC_DEBUG) {
3557db96d56Sopenharmony_ci            PyMem_SetupDebugHooks();
3567db96d56Sopenharmony_ci        }
3577db96d56Sopenharmony_ci        break;
3587db96d56Sopenharmony_ci    }
3597db96d56Sopenharmony_ci
3607db96d56Sopenharmony_ci    default:
3617db96d56Sopenharmony_ci        /* unknown allocator */
3627db96d56Sopenharmony_ci        return -1;
3637db96d56Sopenharmony_ci    }
3647db96d56Sopenharmony_ci    return 0;
3657db96d56Sopenharmony_ci}
3667db96d56Sopenharmony_ci
3677db96d56Sopenharmony_ci
3687db96d56Sopenharmony_cistatic int
3697db96d56Sopenharmony_cipymemallocator_eq(PyMemAllocatorEx *a, PyMemAllocatorEx *b)
3707db96d56Sopenharmony_ci{
3717db96d56Sopenharmony_ci    return (memcmp(a, b, sizeof(PyMemAllocatorEx)) == 0);
3727db96d56Sopenharmony_ci}
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci
3757db96d56Sopenharmony_ciconst char*
3767db96d56Sopenharmony_ci_PyMem_GetCurrentAllocatorName(void)
3777db96d56Sopenharmony_ci{
3787db96d56Sopenharmony_ci    PyMemAllocatorEx malloc_alloc = MALLOC_ALLOC;
3797db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
3807db96d56Sopenharmony_ci    PyMemAllocatorEx pymalloc = PYMALLOC_ALLOC;
3817db96d56Sopenharmony_ci#endif
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    if (pymemallocator_eq(&_PyMem_Raw, &malloc_alloc) &&
3847db96d56Sopenharmony_ci        pymemallocator_eq(&_PyMem, &malloc_alloc) &&
3857db96d56Sopenharmony_ci        pymemallocator_eq(&_PyObject, &malloc_alloc))
3867db96d56Sopenharmony_ci    {
3877db96d56Sopenharmony_ci        return "malloc";
3887db96d56Sopenharmony_ci    }
3897db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
3907db96d56Sopenharmony_ci    if (pymemallocator_eq(&_PyMem_Raw, &malloc_alloc) &&
3917db96d56Sopenharmony_ci        pymemallocator_eq(&_PyMem, &pymalloc) &&
3927db96d56Sopenharmony_ci        pymemallocator_eq(&_PyObject, &pymalloc))
3937db96d56Sopenharmony_ci    {
3947db96d56Sopenharmony_ci        return "pymalloc";
3957db96d56Sopenharmony_ci    }
3967db96d56Sopenharmony_ci#endif
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci    PyMemAllocatorEx dbg_raw = PYDBGRAW_ALLOC;
3997db96d56Sopenharmony_ci    PyMemAllocatorEx dbg_mem = PYDBGMEM_ALLOC;
4007db96d56Sopenharmony_ci    PyMemAllocatorEx dbg_obj = PYDBGOBJ_ALLOC;
4017db96d56Sopenharmony_ci
4027db96d56Sopenharmony_ci    if (pymemallocator_eq(&_PyMem_Raw, &dbg_raw) &&
4037db96d56Sopenharmony_ci        pymemallocator_eq(&_PyMem, &dbg_mem) &&
4047db96d56Sopenharmony_ci        pymemallocator_eq(&_PyObject, &dbg_obj))
4057db96d56Sopenharmony_ci    {
4067db96d56Sopenharmony_ci        /* Debug hooks installed */
4077db96d56Sopenharmony_ci        if (pymemallocator_eq(&_PyMem_Debug.raw.alloc, &malloc_alloc) &&
4087db96d56Sopenharmony_ci            pymemallocator_eq(&_PyMem_Debug.mem.alloc, &malloc_alloc) &&
4097db96d56Sopenharmony_ci            pymemallocator_eq(&_PyMem_Debug.obj.alloc, &malloc_alloc))
4107db96d56Sopenharmony_ci        {
4117db96d56Sopenharmony_ci            return "malloc_debug";
4127db96d56Sopenharmony_ci        }
4137db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
4147db96d56Sopenharmony_ci        if (pymemallocator_eq(&_PyMem_Debug.raw.alloc, &malloc_alloc) &&
4157db96d56Sopenharmony_ci            pymemallocator_eq(&_PyMem_Debug.mem.alloc, &pymalloc) &&
4167db96d56Sopenharmony_ci            pymemallocator_eq(&_PyMem_Debug.obj.alloc, &pymalloc))
4177db96d56Sopenharmony_ci        {
4187db96d56Sopenharmony_ci            return "pymalloc_debug";
4197db96d56Sopenharmony_ci        }
4207db96d56Sopenharmony_ci#endif
4217db96d56Sopenharmony_ci    }
4227db96d56Sopenharmony_ci    return NULL;
4237db96d56Sopenharmony_ci}
4247db96d56Sopenharmony_ci
4257db96d56Sopenharmony_ci
4267db96d56Sopenharmony_ci#undef MALLOC_ALLOC
4277db96d56Sopenharmony_ci#undef PYMALLOC_ALLOC
4287db96d56Sopenharmony_ci#undef PYRAW_ALLOC
4297db96d56Sopenharmony_ci#undef PYMEM_ALLOC
4307db96d56Sopenharmony_ci#undef PYOBJ_ALLOC
4317db96d56Sopenharmony_ci#undef PYDBGRAW_ALLOC
4327db96d56Sopenharmony_ci#undef PYDBGMEM_ALLOC
4337db96d56Sopenharmony_ci#undef PYDBGOBJ_ALLOC
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci
4367db96d56Sopenharmony_cistatic PyObjectArenaAllocator _PyObject_Arena = {NULL,
4377db96d56Sopenharmony_ci#ifdef MS_WINDOWS
4387db96d56Sopenharmony_ci    _PyObject_ArenaVirtualAlloc, _PyObject_ArenaVirtualFree
4397db96d56Sopenharmony_ci#elif defined(ARENAS_USE_MMAP)
4407db96d56Sopenharmony_ci    _PyObject_ArenaMmap, _PyObject_ArenaMunmap
4417db96d56Sopenharmony_ci#else
4427db96d56Sopenharmony_ci    _PyObject_ArenaMalloc, _PyObject_ArenaFree
4437db96d56Sopenharmony_ci#endif
4447db96d56Sopenharmony_ci    };
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
4477db96d56Sopenharmony_cistatic int
4487db96d56Sopenharmony_ci_PyMem_DebugEnabled(void)
4497db96d56Sopenharmony_ci{
4507db96d56Sopenharmony_ci    return (_PyObject.malloc == _PyMem_DebugMalloc);
4517db96d56Sopenharmony_ci}
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_cistatic int
4547db96d56Sopenharmony_ci_PyMem_PymallocEnabled(void)
4557db96d56Sopenharmony_ci{
4567db96d56Sopenharmony_ci    if (_PyMem_DebugEnabled()) {
4577db96d56Sopenharmony_ci        return (_PyMem_Debug.obj.alloc.malloc == _PyObject_Malloc);
4587db96d56Sopenharmony_ci    }
4597db96d56Sopenharmony_ci    else {
4607db96d56Sopenharmony_ci        return (_PyObject.malloc == _PyObject_Malloc);
4617db96d56Sopenharmony_ci    }
4627db96d56Sopenharmony_ci}
4637db96d56Sopenharmony_ci#endif
4647db96d56Sopenharmony_ci
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_cistatic void
4677db96d56Sopenharmony_ci_PyMem_SetupDebugHooksDomain(PyMemAllocatorDomain domain)
4687db96d56Sopenharmony_ci{
4697db96d56Sopenharmony_ci    PyMemAllocatorEx alloc;
4707db96d56Sopenharmony_ci
4717db96d56Sopenharmony_ci    if (domain == PYMEM_DOMAIN_RAW) {
4727db96d56Sopenharmony_ci        if (_PyMem_Raw.malloc == _PyMem_DebugRawMalloc) {
4737db96d56Sopenharmony_ci            return;
4747db96d56Sopenharmony_ci        }
4757db96d56Sopenharmony_ci
4767db96d56Sopenharmony_ci        PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &_PyMem_Debug.raw.alloc);
4777db96d56Sopenharmony_ci        alloc.ctx = &_PyMem_Debug.raw;
4787db96d56Sopenharmony_ci        alloc.malloc = _PyMem_DebugRawMalloc;
4797db96d56Sopenharmony_ci        alloc.calloc = _PyMem_DebugRawCalloc;
4807db96d56Sopenharmony_ci        alloc.realloc = _PyMem_DebugRawRealloc;
4817db96d56Sopenharmony_ci        alloc.free = _PyMem_DebugRawFree;
4827db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
4837db96d56Sopenharmony_ci    }
4847db96d56Sopenharmony_ci    else if (domain == PYMEM_DOMAIN_MEM) {
4857db96d56Sopenharmony_ci        if (_PyMem.malloc == _PyMem_DebugMalloc) {
4867db96d56Sopenharmony_ci            return;
4877db96d56Sopenharmony_ci        }
4887db96d56Sopenharmony_ci
4897db96d56Sopenharmony_ci        PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &_PyMem_Debug.mem.alloc);
4907db96d56Sopenharmony_ci        alloc.ctx = &_PyMem_Debug.mem;
4917db96d56Sopenharmony_ci        alloc.malloc = _PyMem_DebugMalloc;
4927db96d56Sopenharmony_ci        alloc.calloc = _PyMem_DebugCalloc;
4937db96d56Sopenharmony_ci        alloc.realloc = _PyMem_DebugRealloc;
4947db96d56Sopenharmony_ci        alloc.free = _PyMem_DebugFree;
4957db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
4967db96d56Sopenharmony_ci    }
4977db96d56Sopenharmony_ci    else if (domain == PYMEM_DOMAIN_OBJ)  {
4987db96d56Sopenharmony_ci        if (_PyObject.malloc == _PyMem_DebugMalloc) {
4997db96d56Sopenharmony_ci            return;
5007db96d56Sopenharmony_ci        }
5017db96d56Sopenharmony_ci
5027db96d56Sopenharmony_ci        PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &_PyMem_Debug.obj.alloc);
5037db96d56Sopenharmony_ci        alloc.ctx = &_PyMem_Debug.obj;
5047db96d56Sopenharmony_ci        alloc.malloc = _PyMem_DebugMalloc;
5057db96d56Sopenharmony_ci        alloc.calloc = _PyMem_DebugCalloc;
5067db96d56Sopenharmony_ci        alloc.realloc = _PyMem_DebugRealloc;
5077db96d56Sopenharmony_ci        alloc.free = _PyMem_DebugFree;
5087db96d56Sopenharmony_ci        PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
5097db96d56Sopenharmony_ci    }
5107db96d56Sopenharmony_ci}
5117db96d56Sopenharmony_ci
5127db96d56Sopenharmony_ci
5137db96d56Sopenharmony_civoid
5147db96d56Sopenharmony_ciPyMem_SetupDebugHooks(void)
5157db96d56Sopenharmony_ci{
5167db96d56Sopenharmony_ci    _PyMem_SetupDebugHooksDomain(PYMEM_DOMAIN_RAW);
5177db96d56Sopenharmony_ci    _PyMem_SetupDebugHooksDomain(PYMEM_DOMAIN_MEM);
5187db96d56Sopenharmony_ci    _PyMem_SetupDebugHooksDomain(PYMEM_DOMAIN_OBJ);
5197db96d56Sopenharmony_ci}
5207db96d56Sopenharmony_ci
5217db96d56Sopenharmony_civoid
5227db96d56Sopenharmony_ciPyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
5237db96d56Sopenharmony_ci{
5247db96d56Sopenharmony_ci    switch(domain)
5257db96d56Sopenharmony_ci    {
5267db96d56Sopenharmony_ci    case PYMEM_DOMAIN_RAW: *allocator = _PyMem_Raw; break;
5277db96d56Sopenharmony_ci    case PYMEM_DOMAIN_MEM: *allocator = _PyMem; break;
5287db96d56Sopenharmony_ci    case PYMEM_DOMAIN_OBJ: *allocator = _PyObject; break;
5297db96d56Sopenharmony_ci    default:
5307db96d56Sopenharmony_ci        /* unknown domain: set all attributes to NULL */
5317db96d56Sopenharmony_ci        allocator->ctx = NULL;
5327db96d56Sopenharmony_ci        allocator->malloc = NULL;
5337db96d56Sopenharmony_ci        allocator->calloc = NULL;
5347db96d56Sopenharmony_ci        allocator->realloc = NULL;
5357db96d56Sopenharmony_ci        allocator->free = NULL;
5367db96d56Sopenharmony_ci    }
5377db96d56Sopenharmony_ci}
5387db96d56Sopenharmony_ci
5397db96d56Sopenharmony_civoid
5407db96d56Sopenharmony_ciPyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)
5417db96d56Sopenharmony_ci{
5427db96d56Sopenharmony_ci    switch(domain)
5437db96d56Sopenharmony_ci    {
5447db96d56Sopenharmony_ci    case PYMEM_DOMAIN_RAW: _PyMem_Raw = *allocator; break;
5457db96d56Sopenharmony_ci    case PYMEM_DOMAIN_MEM: _PyMem = *allocator; break;
5467db96d56Sopenharmony_ci    case PYMEM_DOMAIN_OBJ: _PyObject = *allocator; break;
5477db96d56Sopenharmony_ci    /* ignore unknown domain */
5487db96d56Sopenharmony_ci    }
5497db96d56Sopenharmony_ci}
5507db96d56Sopenharmony_ci
5517db96d56Sopenharmony_civoid
5527db96d56Sopenharmony_ciPyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)
5537db96d56Sopenharmony_ci{
5547db96d56Sopenharmony_ci    *allocator = _PyObject_Arena;
5557db96d56Sopenharmony_ci}
5567db96d56Sopenharmony_ci
5577db96d56Sopenharmony_civoid *
5587db96d56Sopenharmony_ci_PyObject_VirtualAlloc(size_t size)
5597db96d56Sopenharmony_ci{
5607db96d56Sopenharmony_ci    return _PyObject_Arena.alloc(_PyObject_Arena.ctx, size);
5617db96d56Sopenharmony_ci}
5627db96d56Sopenharmony_ci
5637db96d56Sopenharmony_civoid
5647db96d56Sopenharmony_ci_PyObject_VirtualFree(void *obj, size_t size)
5657db96d56Sopenharmony_ci{
5667db96d56Sopenharmony_ci    _PyObject_Arena.free(_PyObject_Arena.ctx, obj, size);
5677db96d56Sopenharmony_ci}
5687db96d56Sopenharmony_ci
5697db96d56Sopenharmony_civoid
5707db96d56Sopenharmony_ciPyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)
5717db96d56Sopenharmony_ci{
5727db96d56Sopenharmony_ci    _PyObject_Arena = *allocator;
5737db96d56Sopenharmony_ci}
5747db96d56Sopenharmony_ci
5757db96d56Sopenharmony_civoid *
5767db96d56Sopenharmony_ciPyMem_RawMalloc(size_t size)
5777db96d56Sopenharmony_ci{
5787db96d56Sopenharmony_ci    /*
5797db96d56Sopenharmony_ci     * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
5807db96d56Sopenharmony_ci     * Most python internals blindly use a signed Py_ssize_t to track
5817db96d56Sopenharmony_ci     * things without checking for overflows or negatives.
5827db96d56Sopenharmony_ci     * As size_t is unsigned, checking for size < 0 is not required.
5837db96d56Sopenharmony_ci     */
5847db96d56Sopenharmony_ci    if (size > (size_t)PY_SSIZE_T_MAX)
5857db96d56Sopenharmony_ci        return NULL;
5867db96d56Sopenharmony_ci    return _PyMem_Raw.malloc(_PyMem_Raw.ctx, size);
5877db96d56Sopenharmony_ci}
5887db96d56Sopenharmony_ci
5897db96d56Sopenharmony_civoid *
5907db96d56Sopenharmony_ciPyMem_RawCalloc(size_t nelem, size_t elsize)
5917db96d56Sopenharmony_ci{
5927db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
5937db96d56Sopenharmony_ci    if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
5947db96d56Sopenharmony_ci        return NULL;
5957db96d56Sopenharmony_ci    return _PyMem_Raw.calloc(_PyMem_Raw.ctx, nelem, elsize);
5967db96d56Sopenharmony_ci}
5977db96d56Sopenharmony_ci
5987db96d56Sopenharmony_civoid*
5997db96d56Sopenharmony_ciPyMem_RawRealloc(void *ptr, size_t new_size)
6007db96d56Sopenharmony_ci{
6017db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
6027db96d56Sopenharmony_ci    if (new_size > (size_t)PY_SSIZE_T_MAX)
6037db96d56Sopenharmony_ci        return NULL;
6047db96d56Sopenharmony_ci    return _PyMem_Raw.realloc(_PyMem_Raw.ctx, ptr, new_size);
6057db96d56Sopenharmony_ci}
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_civoid PyMem_RawFree(void *ptr)
6087db96d56Sopenharmony_ci{
6097db96d56Sopenharmony_ci    _PyMem_Raw.free(_PyMem_Raw.ctx, ptr);
6107db96d56Sopenharmony_ci}
6117db96d56Sopenharmony_ci
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_civoid *
6147db96d56Sopenharmony_ciPyMem_Malloc(size_t size)
6157db96d56Sopenharmony_ci{
6167db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
6177db96d56Sopenharmony_ci    if (size > (size_t)PY_SSIZE_T_MAX)
6187db96d56Sopenharmony_ci        return NULL;
6197db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations512, size < 512);
6207db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations4k, size >= 512 && size < 4094);
6217db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations_big, size >= 4094);
6227db96d56Sopenharmony_ci    OBJECT_STAT_INC(allocations);
6237db96d56Sopenharmony_ci    return _PyMem.malloc(_PyMem.ctx, size);
6247db96d56Sopenharmony_ci}
6257db96d56Sopenharmony_ci
6267db96d56Sopenharmony_civoid *
6277db96d56Sopenharmony_ciPyMem_Calloc(size_t nelem, size_t elsize)
6287db96d56Sopenharmony_ci{
6297db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
6307db96d56Sopenharmony_ci    if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
6317db96d56Sopenharmony_ci        return NULL;
6327db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations512, elsize < 512);
6337db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations4k, elsize >= 512 && elsize < 4094);
6347db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations_big, elsize >= 4094);
6357db96d56Sopenharmony_ci    OBJECT_STAT_INC(allocations);
6367db96d56Sopenharmony_ci    return _PyMem.calloc(_PyMem.ctx, nelem, elsize);
6377db96d56Sopenharmony_ci}
6387db96d56Sopenharmony_ci
6397db96d56Sopenharmony_civoid *
6407db96d56Sopenharmony_ciPyMem_Realloc(void *ptr, size_t new_size)
6417db96d56Sopenharmony_ci{
6427db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
6437db96d56Sopenharmony_ci    if (new_size > (size_t)PY_SSIZE_T_MAX)
6447db96d56Sopenharmony_ci        return NULL;
6457db96d56Sopenharmony_ci    return _PyMem.realloc(_PyMem.ctx, ptr, new_size);
6467db96d56Sopenharmony_ci}
6477db96d56Sopenharmony_ci
6487db96d56Sopenharmony_civoid
6497db96d56Sopenharmony_ciPyMem_Free(void *ptr)
6507db96d56Sopenharmony_ci{
6517db96d56Sopenharmony_ci    OBJECT_STAT_INC(frees);
6527db96d56Sopenharmony_ci    _PyMem.free(_PyMem.ctx, ptr);
6537db96d56Sopenharmony_ci}
6547db96d56Sopenharmony_ci
6557db96d56Sopenharmony_ci
6567db96d56Sopenharmony_ciwchar_t*
6577db96d56Sopenharmony_ci_PyMem_RawWcsdup(const wchar_t *str)
6587db96d56Sopenharmony_ci{
6597db96d56Sopenharmony_ci    assert(str != NULL);
6607db96d56Sopenharmony_ci
6617db96d56Sopenharmony_ci    size_t len = wcslen(str);
6627db96d56Sopenharmony_ci    if (len > (size_t)PY_SSIZE_T_MAX / sizeof(wchar_t) - 1) {
6637db96d56Sopenharmony_ci        return NULL;
6647db96d56Sopenharmony_ci    }
6657db96d56Sopenharmony_ci
6667db96d56Sopenharmony_ci    size_t size = (len + 1) * sizeof(wchar_t);
6677db96d56Sopenharmony_ci    wchar_t *str2 = PyMem_RawMalloc(size);
6687db96d56Sopenharmony_ci    if (str2 == NULL) {
6697db96d56Sopenharmony_ci        return NULL;
6707db96d56Sopenharmony_ci    }
6717db96d56Sopenharmony_ci
6727db96d56Sopenharmony_ci    memcpy(str2, str, size);
6737db96d56Sopenharmony_ci    return str2;
6747db96d56Sopenharmony_ci}
6757db96d56Sopenharmony_ci
6767db96d56Sopenharmony_cichar *
6777db96d56Sopenharmony_ci_PyMem_RawStrdup(const char *str)
6787db96d56Sopenharmony_ci{
6797db96d56Sopenharmony_ci    assert(str != NULL);
6807db96d56Sopenharmony_ci    size_t size = strlen(str) + 1;
6817db96d56Sopenharmony_ci    char *copy = PyMem_RawMalloc(size);
6827db96d56Sopenharmony_ci    if (copy == NULL) {
6837db96d56Sopenharmony_ci        return NULL;
6847db96d56Sopenharmony_ci    }
6857db96d56Sopenharmony_ci    memcpy(copy, str, size);
6867db96d56Sopenharmony_ci    return copy;
6877db96d56Sopenharmony_ci}
6887db96d56Sopenharmony_ci
6897db96d56Sopenharmony_cichar *
6907db96d56Sopenharmony_ci_PyMem_Strdup(const char *str)
6917db96d56Sopenharmony_ci{
6927db96d56Sopenharmony_ci    assert(str != NULL);
6937db96d56Sopenharmony_ci    size_t size = strlen(str) + 1;
6947db96d56Sopenharmony_ci    char *copy = PyMem_Malloc(size);
6957db96d56Sopenharmony_ci    if (copy == NULL) {
6967db96d56Sopenharmony_ci        return NULL;
6977db96d56Sopenharmony_ci    }
6987db96d56Sopenharmony_ci    memcpy(copy, str, size);
6997db96d56Sopenharmony_ci    return copy;
7007db96d56Sopenharmony_ci}
7017db96d56Sopenharmony_ci
7027db96d56Sopenharmony_civoid *
7037db96d56Sopenharmony_ciPyObject_Malloc(size_t size)
7047db96d56Sopenharmony_ci{
7057db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
7067db96d56Sopenharmony_ci    if (size > (size_t)PY_SSIZE_T_MAX)
7077db96d56Sopenharmony_ci        return NULL;
7087db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations512, size < 512);
7097db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations4k, size >= 512 && size < 4094);
7107db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations_big, size >= 4094);
7117db96d56Sopenharmony_ci    OBJECT_STAT_INC(allocations);
7127db96d56Sopenharmony_ci    return _PyObject.malloc(_PyObject.ctx, size);
7137db96d56Sopenharmony_ci}
7147db96d56Sopenharmony_ci
7157db96d56Sopenharmony_civoid *
7167db96d56Sopenharmony_ciPyObject_Calloc(size_t nelem, size_t elsize)
7177db96d56Sopenharmony_ci{
7187db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
7197db96d56Sopenharmony_ci    if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
7207db96d56Sopenharmony_ci        return NULL;
7217db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations512, elsize < 512);
7227db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations4k, elsize >= 512 && elsize < 4094);
7237db96d56Sopenharmony_ci    OBJECT_STAT_INC_COND(allocations_big, elsize >= 4094);
7247db96d56Sopenharmony_ci    OBJECT_STAT_INC(allocations);
7257db96d56Sopenharmony_ci    return _PyObject.calloc(_PyObject.ctx, nelem, elsize);
7267db96d56Sopenharmony_ci}
7277db96d56Sopenharmony_ci
7287db96d56Sopenharmony_civoid *
7297db96d56Sopenharmony_ciPyObject_Realloc(void *ptr, size_t new_size)
7307db96d56Sopenharmony_ci{
7317db96d56Sopenharmony_ci    /* see PyMem_RawMalloc() */
7327db96d56Sopenharmony_ci    if (new_size > (size_t)PY_SSIZE_T_MAX)
7337db96d56Sopenharmony_ci        return NULL;
7347db96d56Sopenharmony_ci    return _PyObject.realloc(_PyObject.ctx, ptr, new_size);
7357db96d56Sopenharmony_ci}
7367db96d56Sopenharmony_ci
7377db96d56Sopenharmony_civoid
7387db96d56Sopenharmony_ciPyObject_Free(void *ptr)
7397db96d56Sopenharmony_ci{
7407db96d56Sopenharmony_ci    OBJECT_STAT_INC(frees);
7417db96d56Sopenharmony_ci    _PyObject.free(_PyObject.ctx, ptr);
7427db96d56Sopenharmony_ci}
7437db96d56Sopenharmony_ci
7447db96d56Sopenharmony_ci
7457db96d56Sopenharmony_ci/* If we're using GCC, use __builtin_expect() to reduce overhead of
7467db96d56Sopenharmony_ci   the valgrind checks */
7477db96d56Sopenharmony_ci#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
7487db96d56Sopenharmony_ci#  define UNLIKELY(value) __builtin_expect((value), 0)
7497db96d56Sopenharmony_ci#  define LIKELY(value) __builtin_expect((value), 1)
7507db96d56Sopenharmony_ci#else
7517db96d56Sopenharmony_ci#  define UNLIKELY(value) (value)
7527db96d56Sopenharmony_ci#  define LIKELY(value) (value)
7537db96d56Sopenharmony_ci#endif
7547db96d56Sopenharmony_ci
7557db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
7567db96d56Sopenharmony_ci
7577db96d56Sopenharmony_ci#ifdef WITH_VALGRIND
7587db96d56Sopenharmony_ci#include <valgrind/valgrind.h>
7597db96d56Sopenharmony_ci
7607db96d56Sopenharmony_ci/* -1 indicates that we haven't checked that we're running on valgrind yet. */
7617db96d56Sopenharmony_cistatic int running_on_valgrind = -1;
7627db96d56Sopenharmony_ci#endif
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_ci
7657db96d56Sopenharmony_ci/* An object allocator for Python.
7667db96d56Sopenharmony_ci
7677db96d56Sopenharmony_ci   Here is an introduction to the layers of the Python memory architecture,
7687db96d56Sopenharmony_ci   showing where the object allocator is actually used (layer +2), It is
7697db96d56Sopenharmony_ci   called for every object allocation and deallocation (PyObject_New/Del),
7707db96d56Sopenharmony_ci   unless the object-specific allocators implement a proprietary allocation
7717db96d56Sopenharmony_ci   scheme (ex.: ints use a simple free list). This is also the place where
7727db96d56Sopenharmony_ci   the cyclic garbage collector operates selectively on container objects.
7737db96d56Sopenharmony_ci
7747db96d56Sopenharmony_ci
7757db96d56Sopenharmony_ci    Object-specific allocators
7767db96d56Sopenharmony_ci    _____   ______   ______       ________
7777db96d56Sopenharmony_ci   [ int ] [ dict ] [ list ] ... [ string ]       Python core         |
7787db96d56Sopenharmony_ci+3 | <----- Object-specific memory -----> | <-- Non-object memory --> |
7797db96d56Sopenharmony_ci    _______________________________       |                           |
7807db96d56Sopenharmony_ci   [   Python's object allocator   ]      |                           |
7817db96d56Sopenharmony_ci+2 | ####### Object memory ####### | <------ Internal buffers ------> |
7827db96d56Sopenharmony_ci    ______________________________________________________________    |
7837db96d56Sopenharmony_ci   [          Python's raw memory allocator (PyMem_ API)          ]   |
7847db96d56Sopenharmony_ci+1 | <----- Python memory (under PyMem manager's control) ------> |   |
7857db96d56Sopenharmony_ci    __________________________________________________________________
7867db96d56Sopenharmony_ci   [    Underlying general-purpose allocator (ex: C library malloc)   ]
7877db96d56Sopenharmony_ci 0 | <------ Virtual memory allocated for the python process -------> |
7887db96d56Sopenharmony_ci
7897db96d56Sopenharmony_ci   =========================================================================
7907db96d56Sopenharmony_ci    _______________________________________________________________________
7917db96d56Sopenharmony_ci   [                OS-specific Virtual Memory Manager (VMM)               ]
7927db96d56Sopenharmony_ci-1 | <--- Kernel dynamic storage allocation & management (page-based) ---> |
7937db96d56Sopenharmony_ci    __________________________________   __________________________________
7947db96d56Sopenharmony_ci   [                                  ] [                                  ]
7957db96d56Sopenharmony_ci-2 | <-- Physical memory: ROM/RAM --> | | <-- Secondary storage (swap) --> |
7967db96d56Sopenharmony_ci
7977db96d56Sopenharmony_ci*/
7987db96d56Sopenharmony_ci/*==========================================================================*/
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_ci/* A fast, special-purpose memory allocator for small blocks, to be used
8017db96d56Sopenharmony_ci   on top of a general-purpose malloc -- heavily based on previous art. */
8027db96d56Sopenharmony_ci
8037db96d56Sopenharmony_ci/* Vladimir Marangozov -- August 2000 */
8047db96d56Sopenharmony_ci
8057db96d56Sopenharmony_ci/*
8067db96d56Sopenharmony_ci * "Memory management is where the rubber meets the road -- if we do the wrong
8077db96d56Sopenharmony_ci * thing at any level, the results will not be good. And if we don't make the
8087db96d56Sopenharmony_ci * levels work well together, we are in serious trouble." (1)
8097db96d56Sopenharmony_ci *
8107db96d56Sopenharmony_ci * (1) Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles,
8117db96d56Sopenharmony_ci *    "Dynamic Storage Allocation: A Survey and Critical Review",
8127db96d56Sopenharmony_ci *    in Proc. 1995 Int'l. Workshop on Memory Management, September 1995.
8137db96d56Sopenharmony_ci */
8147db96d56Sopenharmony_ci
8157db96d56Sopenharmony_ci/* #undef WITH_MEMORY_LIMITS */         /* disable mem limit checks  */
8167db96d56Sopenharmony_ci
8177db96d56Sopenharmony_ci/*==========================================================================*/
8187db96d56Sopenharmony_ci
8197db96d56Sopenharmony_ci/*
8207db96d56Sopenharmony_ci * Allocation strategy abstract:
8217db96d56Sopenharmony_ci *
8227db96d56Sopenharmony_ci * For small requests, the allocator sub-allocates <Big> blocks of memory.
8237db96d56Sopenharmony_ci * Requests greater than SMALL_REQUEST_THRESHOLD bytes are routed to the
8247db96d56Sopenharmony_ci * system's allocator.
8257db96d56Sopenharmony_ci *
8267db96d56Sopenharmony_ci * Small requests are grouped in size classes spaced 8 bytes apart, due
8277db96d56Sopenharmony_ci * to the required valid alignment of the returned address. Requests of
8287db96d56Sopenharmony_ci * a particular size are serviced from memory pools of 4K (one VMM page).
8297db96d56Sopenharmony_ci * Pools are fragmented on demand and contain free lists of blocks of one
8307db96d56Sopenharmony_ci * particular size class. In other words, there is a fixed-size allocator
8317db96d56Sopenharmony_ci * for each size class. Free pools are shared by the different allocators
8327db96d56Sopenharmony_ci * thus minimizing the space reserved for a particular size class.
8337db96d56Sopenharmony_ci *
8347db96d56Sopenharmony_ci * This allocation strategy is a variant of what is known as "simple
8357db96d56Sopenharmony_ci * segregated storage based on array of free lists". The main drawback of
8367db96d56Sopenharmony_ci * simple segregated storage is that we might end up with lot of reserved
8377db96d56Sopenharmony_ci * memory for the different free lists, which degenerate in time. To avoid
8387db96d56Sopenharmony_ci * this, we partition each free list in pools and we share dynamically the
8397db96d56Sopenharmony_ci * reserved space between all free lists. This technique is quite efficient
8407db96d56Sopenharmony_ci * for memory intensive programs which allocate mainly small-sized blocks.
8417db96d56Sopenharmony_ci *
8427db96d56Sopenharmony_ci * For small requests we have the following table:
8437db96d56Sopenharmony_ci *
8447db96d56Sopenharmony_ci * Request in bytes     Size of allocated block      Size class idx
8457db96d56Sopenharmony_ci * ----------------------------------------------------------------
8467db96d56Sopenharmony_ci *        1-8                     8                       0
8477db96d56Sopenharmony_ci *        9-16                   16                       1
8487db96d56Sopenharmony_ci *       17-24                   24                       2
8497db96d56Sopenharmony_ci *       25-32                   32                       3
8507db96d56Sopenharmony_ci *       33-40                   40                       4
8517db96d56Sopenharmony_ci *       41-48                   48                       5
8527db96d56Sopenharmony_ci *       49-56                   56                       6
8537db96d56Sopenharmony_ci *       57-64                   64                       7
8547db96d56Sopenharmony_ci *       65-72                   72                       8
8557db96d56Sopenharmony_ci *        ...                   ...                     ...
8567db96d56Sopenharmony_ci *      497-504                 504                      62
8577db96d56Sopenharmony_ci *      505-512                 512                      63
8587db96d56Sopenharmony_ci *
8597db96d56Sopenharmony_ci *      0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying
8607db96d56Sopenharmony_ci *      allocator.
8617db96d56Sopenharmony_ci */
8627db96d56Sopenharmony_ci
8637db96d56Sopenharmony_ci/*==========================================================================*/
8647db96d56Sopenharmony_ci
8657db96d56Sopenharmony_ci/*
8667db96d56Sopenharmony_ci * -- Main tunable settings section --
8677db96d56Sopenharmony_ci */
8687db96d56Sopenharmony_ci
8697db96d56Sopenharmony_ci/*
8707db96d56Sopenharmony_ci * Alignment of addresses returned to the user. 8-bytes alignment works
8717db96d56Sopenharmony_ci * on most current architectures (with 32-bit or 64-bit address buses).
8727db96d56Sopenharmony_ci * The alignment value is also used for grouping small requests in size
8737db96d56Sopenharmony_ci * classes spaced ALIGNMENT bytes apart.
8747db96d56Sopenharmony_ci *
8757db96d56Sopenharmony_ci * You shouldn't change this unless you know what you are doing.
8767db96d56Sopenharmony_ci */
8777db96d56Sopenharmony_ci
8787db96d56Sopenharmony_ci#if SIZEOF_VOID_P > 4
8797db96d56Sopenharmony_ci#define ALIGNMENT              16               /* must be 2^N */
8807db96d56Sopenharmony_ci#define ALIGNMENT_SHIFT         4
8817db96d56Sopenharmony_ci#else
8827db96d56Sopenharmony_ci#define ALIGNMENT               8               /* must be 2^N */
8837db96d56Sopenharmony_ci#define ALIGNMENT_SHIFT         3
8847db96d56Sopenharmony_ci#endif
8857db96d56Sopenharmony_ci
8867db96d56Sopenharmony_ci/* Return the number of bytes in size class I, as a uint. */
8877db96d56Sopenharmony_ci#define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT)
8887db96d56Sopenharmony_ci
8897db96d56Sopenharmony_ci/*
8907db96d56Sopenharmony_ci * Max size threshold below which malloc requests are considered to be
8917db96d56Sopenharmony_ci * small enough in order to use preallocated memory pools. You can tune
8927db96d56Sopenharmony_ci * this value according to your application behaviour and memory needs.
8937db96d56Sopenharmony_ci *
8947db96d56Sopenharmony_ci * Note: a size threshold of 512 guarantees that newly created dictionaries
8957db96d56Sopenharmony_ci * will be allocated from preallocated memory pools on 64-bit.
8967db96d56Sopenharmony_ci *
8977db96d56Sopenharmony_ci * The following invariants must hold:
8987db96d56Sopenharmony_ci *      1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 512
8997db96d56Sopenharmony_ci *      2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT
9007db96d56Sopenharmony_ci *
9017db96d56Sopenharmony_ci * Although not required, for better performance and space efficiency,
9027db96d56Sopenharmony_ci * it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2.
9037db96d56Sopenharmony_ci */
9047db96d56Sopenharmony_ci#define SMALL_REQUEST_THRESHOLD 512
9057db96d56Sopenharmony_ci#define NB_SMALL_SIZE_CLASSES   (SMALL_REQUEST_THRESHOLD / ALIGNMENT)
9067db96d56Sopenharmony_ci
9077db96d56Sopenharmony_ci/*
9087db96d56Sopenharmony_ci * The system's VMM page size can be obtained on most unices with a
9097db96d56Sopenharmony_ci * getpagesize() call or deduced from various header files. To make
9107db96d56Sopenharmony_ci * things simpler, we assume that it is 4K, which is OK for most systems.
9117db96d56Sopenharmony_ci * It is probably better if this is the native page size, but it doesn't
9127db96d56Sopenharmony_ci * have to be.  In theory, if SYSTEM_PAGE_SIZE is larger than the native page
9137db96d56Sopenharmony_ci * size, then `POOL_ADDR(p)->arenaindex' could rarely cause a segmentation
9147db96d56Sopenharmony_ci * violation fault.  4K is apparently OK for all the platforms that python
9157db96d56Sopenharmony_ci * currently targets.
9167db96d56Sopenharmony_ci */
9177db96d56Sopenharmony_ci#define SYSTEM_PAGE_SIZE        (4 * 1024)
9187db96d56Sopenharmony_ci
9197db96d56Sopenharmony_ci/*
9207db96d56Sopenharmony_ci * Maximum amount of memory managed by the allocator for small requests.
9217db96d56Sopenharmony_ci */
9227db96d56Sopenharmony_ci#ifdef WITH_MEMORY_LIMITS
9237db96d56Sopenharmony_ci#ifndef SMALL_MEMORY_LIMIT
9247db96d56Sopenharmony_ci#define SMALL_MEMORY_LIMIT      (64 * 1024 * 1024)      /* 64 MB -- more? */
9257db96d56Sopenharmony_ci#endif
9267db96d56Sopenharmony_ci#endif
9277db96d56Sopenharmony_ci
9287db96d56Sopenharmony_ci#if !defined(WITH_PYMALLOC_RADIX_TREE)
9297db96d56Sopenharmony_ci/* Use radix-tree to track arena memory regions, for address_in_range().
9307db96d56Sopenharmony_ci * Enable by default since it allows larger pool sizes.  Can be disabled
9317db96d56Sopenharmony_ci * using -DWITH_PYMALLOC_RADIX_TREE=0 */
9327db96d56Sopenharmony_ci#define WITH_PYMALLOC_RADIX_TREE 1
9337db96d56Sopenharmony_ci#endif
9347db96d56Sopenharmony_ci
9357db96d56Sopenharmony_ci#if SIZEOF_VOID_P > 4
9367db96d56Sopenharmony_ci/* on 64-bit platforms use larger pools and arenas if we can */
9377db96d56Sopenharmony_ci#define USE_LARGE_ARENAS
9387db96d56Sopenharmony_ci#if WITH_PYMALLOC_RADIX_TREE
9397db96d56Sopenharmony_ci/* large pools only supported if radix-tree is enabled */
9407db96d56Sopenharmony_ci#define USE_LARGE_POOLS
9417db96d56Sopenharmony_ci#endif
9427db96d56Sopenharmony_ci#endif
9437db96d56Sopenharmony_ci
9447db96d56Sopenharmony_ci/*
9457db96d56Sopenharmony_ci * The allocator sub-allocates <Big> blocks of memory (called arenas) aligned
9467db96d56Sopenharmony_ci * on a page boundary. This is a reserved virtual address space for the
9477db96d56Sopenharmony_ci * current process (obtained through a malloc()/mmap() call). In no way this
9487db96d56Sopenharmony_ci * means that the memory arenas will be used entirely. A malloc(<Big>) is
9497db96d56Sopenharmony_ci * usually an address range reservation for <Big> bytes, unless all pages within
9507db96d56Sopenharmony_ci * this space are referenced subsequently. So malloc'ing big blocks and not
9517db96d56Sopenharmony_ci * using them does not mean "wasting memory". It's an addressable range
9527db96d56Sopenharmony_ci * wastage...
9537db96d56Sopenharmony_ci *
9547db96d56Sopenharmony_ci * Arenas are allocated with mmap() on systems supporting anonymous memory
9557db96d56Sopenharmony_ci * mappings to reduce heap fragmentation.
9567db96d56Sopenharmony_ci */
9577db96d56Sopenharmony_ci#ifdef USE_LARGE_ARENAS
9587db96d56Sopenharmony_ci#define ARENA_BITS              20                    /* 1 MiB */
9597db96d56Sopenharmony_ci#else
9607db96d56Sopenharmony_ci#define ARENA_BITS              18                    /* 256 KiB */
9617db96d56Sopenharmony_ci#endif
9627db96d56Sopenharmony_ci#define ARENA_SIZE              (1 << ARENA_BITS)
9637db96d56Sopenharmony_ci#define ARENA_SIZE_MASK         (ARENA_SIZE - 1)
9647db96d56Sopenharmony_ci
9657db96d56Sopenharmony_ci#ifdef WITH_MEMORY_LIMITS
9667db96d56Sopenharmony_ci#define MAX_ARENAS              (SMALL_MEMORY_LIMIT / ARENA_SIZE)
9677db96d56Sopenharmony_ci#endif
9687db96d56Sopenharmony_ci
9697db96d56Sopenharmony_ci/*
9707db96d56Sopenharmony_ci * Size of the pools used for small blocks.  Must be a power of 2.
9717db96d56Sopenharmony_ci */
9727db96d56Sopenharmony_ci#ifdef USE_LARGE_POOLS
9737db96d56Sopenharmony_ci#define POOL_BITS               14                  /* 16 KiB */
9747db96d56Sopenharmony_ci#else
9757db96d56Sopenharmony_ci#define POOL_BITS               12                  /* 4 KiB */
9767db96d56Sopenharmony_ci#endif
9777db96d56Sopenharmony_ci#define POOL_SIZE               (1 << POOL_BITS)
9787db96d56Sopenharmony_ci#define POOL_SIZE_MASK          (POOL_SIZE - 1)
9797db96d56Sopenharmony_ci
9807db96d56Sopenharmony_ci#if !WITH_PYMALLOC_RADIX_TREE
9817db96d56Sopenharmony_ci#if POOL_SIZE != SYSTEM_PAGE_SIZE
9827db96d56Sopenharmony_ci#   error "pool size must be equal to system page size"
9837db96d56Sopenharmony_ci#endif
9847db96d56Sopenharmony_ci#endif
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci#define MAX_POOLS_IN_ARENA  (ARENA_SIZE / POOL_SIZE)
9877db96d56Sopenharmony_ci#if MAX_POOLS_IN_ARENA * POOL_SIZE != ARENA_SIZE
9887db96d56Sopenharmony_ci#   error "arena size not an exact multiple of pool size"
9897db96d56Sopenharmony_ci#endif
9907db96d56Sopenharmony_ci
9917db96d56Sopenharmony_ci/*
9927db96d56Sopenharmony_ci * -- End of tunable settings section --
9937db96d56Sopenharmony_ci */
9947db96d56Sopenharmony_ci
9957db96d56Sopenharmony_ci/*==========================================================================*/
9967db96d56Sopenharmony_ci
9977db96d56Sopenharmony_ci/* When you say memory, my mind reasons in terms of (pointers to) blocks */
9987db96d56Sopenharmony_citypedef uint8_t block;
9997db96d56Sopenharmony_ci
10007db96d56Sopenharmony_ci/* Pool for small blocks. */
10017db96d56Sopenharmony_cistruct pool_header {
10027db96d56Sopenharmony_ci    union { block *_padding;
10037db96d56Sopenharmony_ci            uint count; } ref;          /* number of allocated blocks    */
10047db96d56Sopenharmony_ci    block *freeblock;                   /* pool's free list head         */
10057db96d56Sopenharmony_ci    struct pool_header *nextpool;       /* next pool of this size class  */
10067db96d56Sopenharmony_ci    struct pool_header *prevpool;       /* previous pool       ""        */
10077db96d56Sopenharmony_ci    uint arenaindex;                    /* index into arenas of base adr */
10087db96d56Sopenharmony_ci    uint szidx;                         /* block size class index        */
10097db96d56Sopenharmony_ci    uint nextoffset;                    /* bytes to virgin block         */
10107db96d56Sopenharmony_ci    uint maxnextoffset;                 /* largest valid nextoffset      */
10117db96d56Sopenharmony_ci};
10127db96d56Sopenharmony_ci
10137db96d56Sopenharmony_citypedef struct pool_header *poolp;
10147db96d56Sopenharmony_ci
10157db96d56Sopenharmony_ci/* Record keeping for arenas. */
10167db96d56Sopenharmony_cistruct arena_object {
10177db96d56Sopenharmony_ci    /* The address of the arena, as returned by malloc.  Note that 0
10187db96d56Sopenharmony_ci     * will never be returned by a successful malloc, and is used
10197db96d56Sopenharmony_ci     * here to mark an arena_object that doesn't correspond to an
10207db96d56Sopenharmony_ci     * allocated arena.
10217db96d56Sopenharmony_ci     */
10227db96d56Sopenharmony_ci    uintptr_t address;
10237db96d56Sopenharmony_ci
10247db96d56Sopenharmony_ci    /* Pool-aligned pointer to the next pool to be carved off. */
10257db96d56Sopenharmony_ci    block* pool_address;
10267db96d56Sopenharmony_ci
10277db96d56Sopenharmony_ci    /* The number of available pools in the arena:  free pools + never-
10287db96d56Sopenharmony_ci     * allocated pools.
10297db96d56Sopenharmony_ci     */
10307db96d56Sopenharmony_ci    uint nfreepools;
10317db96d56Sopenharmony_ci
10327db96d56Sopenharmony_ci    /* The total number of pools in the arena, whether or not available. */
10337db96d56Sopenharmony_ci    uint ntotalpools;
10347db96d56Sopenharmony_ci
10357db96d56Sopenharmony_ci    /* Singly-linked list of available pools. */
10367db96d56Sopenharmony_ci    struct pool_header* freepools;
10377db96d56Sopenharmony_ci
10387db96d56Sopenharmony_ci    /* Whenever this arena_object is not associated with an allocated
10397db96d56Sopenharmony_ci     * arena, the nextarena member is used to link all unassociated
10407db96d56Sopenharmony_ci     * arena_objects in the singly-linked `unused_arena_objects` list.
10417db96d56Sopenharmony_ci     * The prevarena member is unused in this case.
10427db96d56Sopenharmony_ci     *
10437db96d56Sopenharmony_ci     * When this arena_object is associated with an allocated arena
10447db96d56Sopenharmony_ci     * with at least one available pool, both members are used in the
10457db96d56Sopenharmony_ci     * doubly-linked `usable_arenas` list, which is maintained in
10467db96d56Sopenharmony_ci     * increasing order of `nfreepools` values.
10477db96d56Sopenharmony_ci     *
10487db96d56Sopenharmony_ci     * Else this arena_object is associated with an allocated arena
10497db96d56Sopenharmony_ci     * all of whose pools are in use.  `nextarena` and `prevarena`
10507db96d56Sopenharmony_ci     * are both meaningless in this case.
10517db96d56Sopenharmony_ci     */
10527db96d56Sopenharmony_ci    struct arena_object* nextarena;
10537db96d56Sopenharmony_ci    struct arena_object* prevarena;
10547db96d56Sopenharmony_ci};
10557db96d56Sopenharmony_ci
10567db96d56Sopenharmony_ci#define POOL_OVERHEAD   _Py_SIZE_ROUND_UP(sizeof(struct pool_header), ALIGNMENT)
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci#define DUMMY_SIZE_IDX          0xffff  /* size class of newly cached pools */
10597db96d56Sopenharmony_ci
10607db96d56Sopenharmony_ci/* Round pointer P down to the closest pool-aligned address <= P, as a poolp */
10617db96d56Sopenharmony_ci#define POOL_ADDR(P) ((poolp)_Py_ALIGN_DOWN((P), POOL_SIZE))
10627db96d56Sopenharmony_ci
10637db96d56Sopenharmony_ci/* Return total number of blocks in pool of size index I, as a uint. */
10647db96d56Sopenharmony_ci#define NUMBLOCKS(I) ((uint)(POOL_SIZE - POOL_OVERHEAD) / INDEX2SIZE(I))
10657db96d56Sopenharmony_ci
10667db96d56Sopenharmony_ci/*==========================================================================*/
10677db96d56Sopenharmony_ci
10687db96d56Sopenharmony_ci/*
10697db96d56Sopenharmony_ci * Pool table -- headed, circular, doubly-linked lists of partially used pools.
10707db96d56Sopenharmony_ci
10717db96d56Sopenharmony_ciThis is involved.  For an index i, usedpools[i+i] is the header for a list of
10727db96d56Sopenharmony_ciall partially used pools holding small blocks with "size class idx" i. So
10737db96d56Sopenharmony_ciusedpools[0] corresponds to blocks of size 8, usedpools[2] to blocks of size
10747db96d56Sopenharmony_ci16, and so on:  index 2*i <-> blocks of size (i+1)<<ALIGNMENT_SHIFT.
10757db96d56Sopenharmony_ci
10767db96d56Sopenharmony_ciPools are carved off an arena's highwater mark (an arena_object's pool_address
10777db96d56Sopenharmony_cimember) as needed.  Once carved off, a pool is in one of three states forever
10787db96d56Sopenharmony_ciafter:
10797db96d56Sopenharmony_ci
10807db96d56Sopenharmony_ciused == partially used, neither empty nor full
10817db96d56Sopenharmony_ci    At least one block in the pool is currently allocated, and at least one
10827db96d56Sopenharmony_ci    block in the pool is not currently allocated (note this implies a pool
10837db96d56Sopenharmony_ci    has room for at least two blocks).
10847db96d56Sopenharmony_ci    This is a pool's initial state, as a pool is created only when malloc
10857db96d56Sopenharmony_ci    needs space.
10867db96d56Sopenharmony_ci    The pool holds blocks of a fixed size, and is in the circular list headed
10877db96d56Sopenharmony_ci    at usedpools[i] (see above).  It's linked to the other used pools of the
10887db96d56Sopenharmony_ci    same size class via the pool_header's nextpool and prevpool members.
10897db96d56Sopenharmony_ci    If all but one block is currently allocated, a malloc can cause a
10907db96d56Sopenharmony_ci    transition to the full state.  If all but one block is not currently
10917db96d56Sopenharmony_ci    allocated, a free can cause a transition to the empty state.
10927db96d56Sopenharmony_ci
10937db96d56Sopenharmony_cifull == all the pool's blocks are currently allocated
10947db96d56Sopenharmony_ci    On transition to full, a pool is unlinked from its usedpools[] list.
10957db96d56Sopenharmony_ci    It's not linked to from anything then anymore, and its nextpool and
10967db96d56Sopenharmony_ci    prevpool members are meaningless until it transitions back to used.
10977db96d56Sopenharmony_ci    A free of a block in a full pool puts the pool back in the used state.
10987db96d56Sopenharmony_ci    Then it's linked in at the front of the appropriate usedpools[] list, so
10997db96d56Sopenharmony_ci    that the next allocation for its size class will reuse the freed block.
11007db96d56Sopenharmony_ci
11017db96d56Sopenharmony_ciempty == all the pool's blocks are currently available for allocation
11027db96d56Sopenharmony_ci    On transition to empty, a pool is unlinked from its usedpools[] list,
11037db96d56Sopenharmony_ci    and linked to the front of its arena_object's singly-linked freepools list,
11047db96d56Sopenharmony_ci    via its nextpool member.  The prevpool member has no meaning in this case.
11057db96d56Sopenharmony_ci    Empty pools have no inherent size class:  the next time a malloc finds
11067db96d56Sopenharmony_ci    an empty list in usedpools[], it takes the first pool off of freepools.
11077db96d56Sopenharmony_ci    If the size class needed happens to be the same as the size class the pool
11087db96d56Sopenharmony_ci    last had, some pool initialization can be skipped.
11097db96d56Sopenharmony_ci
11107db96d56Sopenharmony_ci
11117db96d56Sopenharmony_ciBlock Management
11127db96d56Sopenharmony_ci
11137db96d56Sopenharmony_ciBlocks within pools are again carved out as needed.  pool->freeblock points to
11147db96d56Sopenharmony_cithe start of a singly-linked list of free blocks within the pool.  When a
11157db96d56Sopenharmony_ciblock is freed, it's inserted at the front of its pool's freeblock list.  Note
11167db96d56Sopenharmony_cithat the available blocks in a pool are *not* linked all together when a pool
11177db96d56Sopenharmony_ciis initialized.  Instead only "the first two" (lowest addresses) blocks are
11187db96d56Sopenharmony_ciset up, returning the first such block, and setting pool->freeblock to a
11197db96d56Sopenharmony_cione-block list holding the second such block.  This is consistent with that
11207db96d56Sopenharmony_cipymalloc strives at all levels (arena, pool, and block) never to touch a piece
11217db96d56Sopenharmony_ciof memory until it's actually needed.
11227db96d56Sopenharmony_ci
11237db96d56Sopenharmony_ciSo long as a pool is in the used state, we're certain there *is* a block
11247db96d56Sopenharmony_ciavailable for allocating, and pool->freeblock is not NULL.  If pool->freeblock
11257db96d56Sopenharmony_cipoints to the end of the free list before we've carved the entire pool into
11267db96d56Sopenharmony_ciblocks, that means we simply haven't yet gotten to one of the higher-address
11277db96d56Sopenharmony_ciblocks.  The offset from the pool_header to the start of "the next" virgin
11287db96d56Sopenharmony_ciblock is stored in the pool_header nextoffset member, and the largest value
11297db96d56Sopenharmony_ciof nextoffset that makes sense is stored in the maxnextoffset member when a
11307db96d56Sopenharmony_cipool is initialized.  All the blocks in a pool have been passed out at least
11317db96d56Sopenharmony_cionce when and only when nextoffset > maxnextoffset.
11327db96d56Sopenharmony_ci
11337db96d56Sopenharmony_ci
11347db96d56Sopenharmony_ciMajor obscurity:  While the usedpools vector is declared to have poolp
11357db96d56Sopenharmony_cientries, it doesn't really.  It really contains two pointers per (conceptual)
11367db96d56Sopenharmony_cipoolp entry, the nextpool and prevpool members of a pool_header.  The
11377db96d56Sopenharmony_ciexcruciating initialization code below fools C so that
11387db96d56Sopenharmony_ci
11397db96d56Sopenharmony_ci    usedpool[i+i]
11407db96d56Sopenharmony_ci
11417db96d56Sopenharmony_ci"acts like" a genuine poolp, but only so long as you only reference its
11427db96d56Sopenharmony_cinextpool and prevpool members.  The "- 2*sizeof(block *)" gibberish is
11437db96d56Sopenharmony_cicompensating for that a pool_header's nextpool and prevpool members
11447db96d56Sopenharmony_ciimmediately follow a pool_header's first two members:
11457db96d56Sopenharmony_ci
11467db96d56Sopenharmony_ci    union { block *_padding;
11477db96d56Sopenharmony_ci            uint count; } ref;
11487db96d56Sopenharmony_ci    block *freeblock;
11497db96d56Sopenharmony_ci
11507db96d56Sopenharmony_cieach of which consume sizeof(block *) bytes.  So what usedpools[i+i] really
11517db96d56Sopenharmony_cicontains is a fudged-up pointer p such that *if* C believes it's a poolp
11527db96d56Sopenharmony_cipointer, then p->nextpool and p->prevpool are both p (meaning that the headed
11537db96d56Sopenharmony_cicircular list is empty).
11547db96d56Sopenharmony_ci
11557db96d56Sopenharmony_ciIt's unclear why the usedpools setup is so convoluted.  It could be to
11567db96d56Sopenharmony_ciminimize the amount of cache required to hold this heavily-referenced table
11577db96d56Sopenharmony_ci(which only *needs* the two interpool pointer members of a pool_header). OTOH,
11587db96d56Sopenharmony_cireferencing code has to remember to "double the index" and doing so isn't
11597db96d56Sopenharmony_cifree, usedpools[0] isn't a strictly legal pointer, and we're crucially relying
11607db96d56Sopenharmony_cion that C doesn't insert any padding anywhere in a pool_header at or before
11617db96d56Sopenharmony_cithe prevpool member.
11627db96d56Sopenharmony_ci**************************************************************************** */
11637db96d56Sopenharmony_ci
11647db96d56Sopenharmony_ci#define PTA(x)  ((poolp )((uint8_t *)&(usedpools[2*(x)]) - 2*sizeof(block *)))
11657db96d56Sopenharmony_ci#define PT(x)   PTA(x), PTA(x)
11667db96d56Sopenharmony_ci
11677db96d56Sopenharmony_cistatic poolp usedpools[2 * ((NB_SMALL_SIZE_CLASSES + 7) / 8) * 8] = {
11687db96d56Sopenharmony_ci    PT(0), PT(1), PT(2), PT(3), PT(4), PT(5), PT(6), PT(7)
11697db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 8
11707db96d56Sopenharmony_ci    , PT(8), PT(9), PT(10), PT(11), PT(12), PT(13), PT(14), PT(15)
11717db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 16
11727db96d56Sopenharmony_ci    , PT(16), PT(17), PT(18), PT(19), PT(20), PT(21), PT(22), PT(23)
11737db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 24
11747db96d56Sopenharmony_ci    , PT(24), PT(25), PT(26), PT(27), PT(28), PT(29), PT(30), PT(31)
11757db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 32
11767db96d56Sopenharmony_ci    , PT(32), PT(33), PT(34), PT(35), PT(36), PT(37), PT(38), PT(39)
11777db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 40
11787db96d56Sopenharmony_ci    , PT(40), PT(41), PT(42), PT(43), PT(44), PT(45), PT(46), PT(47)
11797db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 48
11807db96d56Sopenharmony_ci    , PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55)
11817db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 56
11827db96d56Sopenharmony_ci    , PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63)
11837db96d56Sopenharmony_ci#if NB_SMALL_SIZE_CLASSES > 64
11847db96d56Sopenharmony_ci#error "NB_SMALL_SIZE_CLASSES should be less than 64"
11857db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 64 */
11867db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 56 */
11877db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 48 */
11887db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 40 */
11897db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 32 */
11907db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 24 */
11917db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES > 16 */
11927db96d56Sopenharmony_ci#endif /* NB_SMALL_SIZE_CLASSES >  8 */
11937db96d56Sopenharmony_ci};
11947db96d56Sopenharmony_ci
11957db96d56Sopenharmony_ci/*==========================================================================
11967db96d56Sopenharmony_ciArena management.
11977db96d56Sopenharmony_ci
11987db96d56Sopenharmony_ci`arenas` is a vector of arena_objects.  It contains maxarenas entries, some of
11997db96d56Sopenharmony_ciwhich may not be currently used (== they're arena_objects that aren't
12007db96d56Sopenharmony_cicurrently associated with an allocated arena).  Note that arenas proper are
12017db96d56Sopenharmony_ciseparately malloc'ed.
12027db96d56Sopenharmony_ci
12037db96d56Sopenharmony_ciPrior to Python 2.5, arenas were never free()'ed.  Starting with Python 2.5,
12047db96d56Sopenharmony_ciwe do try to free() arenas, and use some mild heuristic strategies to increase
12057db96d56Sopenharmony_cithe likelihood that arenas eventually can be freed.
12067db96d56Sopenharmony_ci
12077db96d56Sopenharmony_ciunused_arena_objects
12087db96d56Sopenharmony_ci
12097db96d56Sopenharmony_ci    This is a singly-linked list of the arena_objects that are currently not
12107db96d56Sopenharmony_ci    being used (no arena is associated with them).  Objects are taken off the
12117db96d56Sopenharmony_ci    head of the list in new_arena(), and are pushed on the head of the list in
12127db96d56Sopenharmony_ci    PyObject_Free() when the arena is empty.  Key invariant:  an arena_object
12137db96d56Sopenharmony_ci    is on this list if and only if its .address member is 0.
12147db96d56Sopenharmony_ci
12157db96d56Sopenharmony_ciusable_arenas
12167db96d56Sopenharmony_ci
12177db96d56Sopenharmony_ci    This is a doubly-linked list of the arena_objects associated with arenas
12187db96d56Sopenharmony_ci    that have pools available.  These pools are either waiting to be reused,
12197db96d56Sopenharmony_ci    or have not been used before.  The list is sorted to have the most-
12207db96d56Sopenharmony_ci    allocated arenas first (ascending order based on the nfreepools member).
12217db96d56Sopenharmony_ci    This means that the next allocation will come from a heavily used arena,
12227db96d56Sopenharmony_ci    which gives the nearly empty arenas a chance to be returned to the system.
12237db96d56Sopenharmony_ci    In my unscientific tests this dramatically improved the number of arenas
12247db96d56Sopenharmony_ci    that could be freed.
12257db96d56Sopenharmony_ci
12267db96d56Sopenharmony_ciNote that an arena_object associated with an arena all of whose pools are
12277db96d56Sopenharmony_cicurrently in use isn't on either list.
12287db96d56Sopenharmony_ci
12297db96d56Sopenharmony_ciChanged in Python 3.8:  keeping usable_arenas sorted by number of free pools
12307db96d56Sopenharmony_ciused to be done by one-at-a-time linear search when an arena's number of
12317db96d56Sopenharmony_cifree pools changed.  That could, overall, consume time quadratic in the
12327db96d56Sopenharmony_cinumber of arenas.  That didn't really matter when there were only a few
12337db96d56Sopenharmony_cihundred arenas (typical!), but could be a timing disaster when there were
12347db96d56Sopenharmony_cihundreds of thousands.  See bpo-37029.
12357db96d56Sopenharmony_ci
12367db96d56Sopenharmony_ciNow we have a vector of "search fingers" to eliminate the need to search:
12377db96d56Sopenharmony_cinfp2lasta[nfp] returns the last ("rightmost") arena in usable_arenas
12387db96d56Sopenharmony_ciwith nfp free pools.  This is NULL if and only if there is no arena with
12397db96d56Sopenharmony_cinfp free pools in usable_arenas.
12407db96d56Sopenharmony_ci*/
12417db96d56Sopenharmony_ci
12427db96d56Sopenharmony_ci/* Array of objects used to track chunks of memory (arenas). */
12437db96d56Sopenharmony_cistatic struct arena_object* arenas = NULL;
12447db96d56Sopenharmony_ci/* Number of slots currently allocated in the `arenas` vector. */
12457db96d56Sopenharmony_cistatic uint maxarenas = 0;
12467db96d56Sopenharmony_ci
12477db96d56Sopenharmony_ci/* The head of the singly-linked, NULL-terminated list of available
12487db96d56Sopenharmony_ci * arena_objects.
12497db96d56Sopenharmony_ci */
12507db96d56Sopenharmony_cistatic struct arena_object* unused_arena_objects = NULL;
12517db96d56Sopenharmony_ci
12527db96d56Sopenharmony_ci/* The head of the doubly-linked, NULL-terminated at each end, list of
12537db96d56Sopenharmony_ci * arena_objects associated with arenas that have pools available.
12547db96d56Sopenharmony_ci */
12557db96d56Sopenharmony_cistatic struct arena_object* usable_arenas = NULL;
12567db96d56Sopenharmony_ci
12577db96d56Sopenharmony_ci/* nfp2lasta[nfp] is the last arena in usable_arenas with nfp free pools */
12587db96d56Sopenharmony_cistatic struct arena_object* nfp2lasta[MAX_POOLS_IN_ARENA + 1] = { NULL };
12597db96d56Sopenharmony_ci
12607db96d56Sopenharmony_ci/* How many arena_objects do we initially allocate?
12617db96d56Sopenharmony_ci * 16 = can allocate 16 arenas = 16 * ARENA_SIZE = 4MB before growing the
12627db96d56Sopenharmony_ci * `arenas` vector.
12637db96d56Sopenharmony_ci */
12647db96d56Sopenharmony_ci#define INITIAL_ARENA_OBJECTS 16
12657db96d56Sopenharmony_ci
12667db96d56Sopenharmony_ci/* Number of arenas allocated that haven't been free()'d. */
12677db96d56Sopenharmony_cistatic size_t narenas_currently_allocated = 0;
12687db96d56Sopenharmony_ci
12697db96d56Sopenharmony_ci/* Total number of times malloc() called to allocate an arena. */
12707db96d56Sopenharmony_cistatic size_t ntimes_arena_allocated = 0;
12717db96d56Sopenharmony_ci/* High water mark (max value ever seen) for narenas_currently_allocated. */
12727db96d56Sopenharmony_cistatic size_t narenas_highwater = 0;
12737db96d56Sopenharmony_ci
12747db96d56Sopenharmony_cistatic Py_ssize_t raw_allocated_blocks;
12757db96d56Sopenharmony_ci
12767db96d56Sopenharmony_ciPy_ssize_t
12777db96d56Sopenharmony_ci_Py_GetAllocatedBlocks(void)
12787db96d56Sopenharmony_ci{
12797db96d56Sopenharmony_ci    Py_ssize_t n = raw_allocated_blocks;
12807db96d56Sopenharmony_ci    /* add up allocated blocks for used pools */
12817db96d56Sopenharmony_ci    for (uint i = 0; i < maxarenas; ++i) {
12827db96d56Sopenharmony_ci        /* Skip arenas which are not allocated. */
12837db96d56Sopenharmony_ci        if (arenas[i].address == 0) {
12847db96d56Sopenharmony_ci            continue;
12857db96d56Sopenharmony_ci        }
12867db96d56Sopenharmony_ci
12877db96d56Sopenharmony_ci        uintptr_t base = (uintptr_t)_Py_ALIGN_UP(arenas[i].address, POOL_SIZE);
12887db96d56Sopenharmony_ci
12897db96d56Sopenharmony_ci        /* visit every pool in the arena */
12907db96d56Sopenharmony_ci        assert(base <= (uintptr_t) arenas[i].pool_address);
12917db96d56Sopenharmony_ci        for (; base < (uintptr_t) arenas[i].pool_address; base += POOL_SIZE) {
12927db96d56Sopenharmony_ci            poolp p = (poolp)base;
12937db96d56Sopenharmony_ci            n += p->ref.count;
12947db96d56Sopenharmony_ci        }
12957db96d56Sopenharmony_ci    }
12967db96d56Sopenharmony_ci    return n;
12977db96d56Sopenharmony_ci}
12987db96d56Sopenharmony_ci
12997db96d56Sopenharmony_ci#if WITH_PYMALLOC_RADIX_TREE
13007db96d56Sopenharmony_ci/*==========================================================================*/
13017db96d56Sopenharmony_ci/* radix tree for tracking arena usage.  If enabled, used to implement
13027db96d56Sopenharmony_ci   address_in_range().
13037db96d56Sopenharmony_ci
13047db96d56Sopenharmony_ci   memory address bit allocation for keys
13057db96d56Sopenharmony_ci
13067db96d56Sopenharmony_ci   64-bit pointers, IGNORE_BITS=0 and 2^20 arena size:
13077db96d56Sopenharmony_ci     15 -> MAP_TOP_BITS
13087db96d56Sopenharmony_ci     15 -> MAP_MID_BITS
13097db96d56Sopenharmony_ci     14 -> MAP_BOT_BITS
13107db96d56Sopenharmony_ci     20 -> ideal aligned arena
13117db96d56Sopenharmony_ci   ----
13127db96d56Sopenharmony_ci     64
13137db96d56Sopenharmony_ci
13147db96d56Sopenharmony_ci   64-bit pointers, IGNORE_BITS=16, and 2^20 arena size:
13157db96d56Sopenharmony_ci     16 -> IGNORE_BITS
13167db96d56Sopenharmony_ci     10 -> MAP_TOP_BITS
13177db96d56Sopenharmony_ci     10 -> MAP_MID_BITS
13187db96d56Sopenharmony_ci      8 -> MAP_BOT_BITS
13197db96d56Sopenharmony_ci     20 -> ideal aligned arena
13207db96d56Sopenharmony_ci   ----
13217db96d56Sopenharmony_ci     64
13227db96d56Sopenharmony_ci
13237db96d56Sopenharmony_ci   32-bit pointers and 2^18 arena size:
13247db96d56Sopenharmony_ci     14 -> MAP_BOT_BITS
13257db96d56Sopenharmony_ci     18 -> ideal aligned arena
13267db96d56Sopenharmony_ci   ----
13277db96d56Sopenharmony_ci     32
13287db96d56Sopenharmony_ci
13297db96d56Sopenharmony_ci*/
13307db96d56Sopenharmony_ci
13317db96d56Sopenharmony_ci#if SIZEOF_VOID_P == 8
13327db96d56Sopenharmony_ci
13337db96d56Sopenharmony_ci/* number of bits in a pointer */
13347db96d56Sopenharmony_ci#define POINTER_BITS 64
13357db96d56Sopenharmony_ci
13367db96d56Sopenharmony_ci/* High bits of memory addresses that will be ignored when indexing into the
13377db96d56Sopenharmony_ci * radix tree.  Setting this to zero is the safe default.  For most 64-bit
13387db96d56Sopenharmony_ci * machines, setting this to 16 would be safe.  The kernel would not give
13397db96d56Sopenharmony_ci * user-space virtual memory addresses that have significant information in
13407db96d56Sopenharmony_ci * those high bits.  The main advantage to setting IGNORE_BITS > 0 is that less
13417db96d56Sopenharmony_ci * virtual memory will be used for the top and middle radix tree arrays.  Those
13427db96d56Sopenharmony_ci * arrays are allocated in the BSS segment and so will typically consume real
13437db96d56Sopenharmony_ci * memory only if actually accessed.
13447db96d56Sopenharmony_ci */
13457db96d56Sopenharmony_ci#define IGNORE_BITS 0
13467db96d56Sopenharmony_ci
13477db96d56Sopenharmony_ci/* use the top and mid layers of the radix tree */
13487db96d56Sopenharmony_ci#define USE_INTERIOR_NODES
13497db96d56Sopenharmony_ci
13507db96d56Sopenharmony_ci#elif SIZEOF_VOID_P == 4
13517db96d56Sopenharmony_ci
13527db96d56Sopenharmony_ci#define POINTER_BITS 32
13537db96d56Sopenharmony_ci#define IGNORE_BITS 0
13547db96d56Sopenharmony_ci
13557db96d56Sopenharmony_ci#else
13567db96d56Sopenharmony_ci
13577db96d56Sopenharmony_ci /* Currently this code works for 64-bit or 32-bit pointers only.  */
13587db96d56Sopenharmony_ci#error "obmalloc radix tree requires 64-bit or 32-bit pointers."
13597db96d56Sopenharmony_ci
13607db96d56Sopenharmony_ci#endif /* SIZEOF_VOID_P */
13617db96d56Sopenharmony_ci
13627db96d56Sopenharmony_ci/* arena_coverage_t members require this to be true  */
13637db96d56Sopenharmony_ci#if ARENA_BITS >= 32
13647db96d56Sopenharmony_ci#   error "arena size must be < 2^32"
13657db96d56Sopenharmony_ci#endif
13667db96d56Sopenharmony_ci
13677db96d56Sopenharmony_ci/* the lower bits of the address that are not ignored */
13687db96d56Sopenharmony_ci#define ADDRESS_BITS (POINTER_BITS - IGNORE_BITS)
13697db96d56Sopenharmony_ci
13707db96d56Sopenharmony_ci#ifdef USE_INTERIOR_NODES
13717db96d56Sopenharmony_ci/* number of bits used for MAP_TOP and MAP_MID nodes */
13727db96d56Sopenharmony_ci#define INTERIOR_BITS ((ADDRESS_BITS - ARENA_BITS + 2) / 3)
13737db96d56Sopenharmony_ci#else
13747db96d56Sopenharmony_ci#define INTERIOR_BITS 0
13757db96d56Sopenharmony_ci#endif
13767db96d56Sopenharmony_ci
13777db96d56Sopenharmony_ci#define MAP_TOP_BITS INTERIOR_BITS
13787db96d56Sopenharmony_ci#define MAP_TOP_LENGTH (1 << MAP_TOP_BITS)
13797db96d56Sopenharmony_ci#define MAP_TOP_MASK (MAP_TOP_LENGTH - 1)
13807db96d56Sopenharmony_ci
13817db96d56Sopenharmony_ci#define MAP_MID_BITS INTERIOR_BITS
13827db96d56Sopenharmony_ci#define MAP_MID_LENGTH (1 << MAP_MID_BITS)
13837db96d56Sopenharmony_ci#define MAP_MID_MASK (MAP_MID_LENGTH - 1)
13847db96d56Sopenharmony_ci
13857db96d56Sopenharmony_ci#define MAP_BOT_BITS (ADDRESS_BITS - ARENA_BITS - 2*INTERIOR_BITS)
13867db96d56Sopenharmony_ci#define MAP_BOT_LENGTH (1 << MAP_BOT_BITS)
13877db96d56Sopenharmony_ci#define MAP_BOT_MASK (MAP_BOT_LENGTH - 1)
13887db96d56Sopenharmony_ci
13897db96d56Sopenharmony_ci#define MAP_BOT_SHIFT ARENA_BITS
13907db96d56Sopenharmony_ci#define MAP_MID_SHIFT (MAP_BOT_BITS + MAP_BOT_SHIFT)
13917db96d56Sopenharmony_ci#define MAP_TOP_SHIFT (MAP_MID_BITS + MAP_MID_SHIFT)
13927db96d56Sopenharmony_ci
13937db96d56Sopenharmony_ci#define AS_UINT(p) ((uintptr_t)(p))
13947db96d56Sopenharmony_ci#define MAP_BOT_INDEX(p) ((AS_UINT(p) >> MAP_BOT_SHIFT) & MAP_BOT_MASK)
13957db96d56Sopenharmony_ci#define MAP_MID_INDEX(p) ((AS_UINT(p) >> MAP_MID_SHIFT) & MAP_MID_MASK)
13967db96d56Sopenharmony_ci#define MAP_TOP_INDEX(p) ((AS_UINT(p) >> MAP_TOP_SHIFT) & MAP_TOP_MASK)
13977db96d56Sopenharmony_ci
13987db96d56Sopenharmony_ci#if IGNORE_BITS > 0
13997db96d56Sopenharmony_ci/* Return the ignored part of the pointer address.  Those bits should be same
14007db96d56Sopenharmony_ci * for all valid pointers if IGNORE_BITS is set correctly.
14017db96d56Sopenharmony_ci */
14027db96d56Sopenharmony_ci#define HIGH_BITS(p) (AS_UINT(p) >> ADDRESS_BITS)
14037db96d56Sopenharmony_ci#else
14047db96d56Sopenharmony_ci#define HIGH_BITS(p) 0
14057db96d56Sopenharmony_ci#endif
14067db96d56Sopenharmony_ci
14077db96d56Sopenharmony_ci
14087db96d56Sopenharmony_ci/* This is the leaf of the radix tree.  See arena_map_mark_used() for the
14097db96d56Sopenharmony_ci * meaning of these members. */
14107db96d56Sopenharmony_citypedef struct {
14117db96d56Sopenharmony_ci    int32_t tail_hi;
14127db96d56Sopenharmony_ci    int32_t tail_lo;
14137db96d56Sopenharmony_ci} arena_coverage_t;
14147db96d56Sopenharmony_ci
14157db96d56Sopenharmony_citypedef struct arena_map_bot {
14167db96d56Sopenharmony_ci    /* The members tail_hi and tail_lo are accessed together.  So, it
14177db96d56Sopenharmony_ci     * better to have them as an array of structs, rather than two
14187db96d56Sopenharmony_ci     * arrays.
14197db96d56Sopenharmony_ci     */
14207db96d56Sopenharmony_ci    arena_coverage_t arenas[MAP_BOT_LENGTH];
14217db96d56Sopenharmony_ci} arena_map_bot_t;
14227db96d56Sopenharmony_ci
14237db96d56Sopenharmony_ci#ifdef USE_INTERIOR_NODES
14247db96d56Sopenharmony_citypedef struct arena_map_mid {
14257db96d56Sopenharmony_ci    struct arena_map_bot *ptrs[MAP_MID_LENGTH];
14267db96d56Sopenharmony_ci} arena_map_mid_t;
14277db96d56Sopenharmony_ci
14287db96d56Sopenharmony_citypedef struct arena_map_top {
14297db96d56Sopenharmony_ci    struct arena_map_mid *ptrs[MAP_TOP_LENGTH];
14307db96d56Sopenharmony_ci} arena_map_top_t;
14317db96d56Sopenharmony_ci#endif
14327db96d56Sopenharmony_ci
14337db96d56Sopenharmony_ci/* The root of radix tree.  Note that by initializing like this, the memory
14347db96d56Sopenharmony_ci * should be in the BSS.  The OS will only memory map pages as the MAP_MID
14357db96d56Sopenharmony_ci * nodes get used (OS pages are demand loaded as needed).
14367db96d56Sopenharmony_ci */
14377db96d56Sopenharmony_ci#ifdef USE_INTERIOR_NODES
14387db96d56Sopenharmony_cistatic arena_map_top_t arena_map_root;
14397db96d56Sopenharmony_ci/* accounting for number of used interior nodes */
14407db96d56Sopenharmony_cistatic int arena_map_mid_count;
14417db96d56Sopenharmony_cistatic int arena_map_bot_count;
14427db96d56Sopenharmony_ci#else
14437db96d56Sopenharmony_cistatic arena_map_bot_t arena_map_root;
14447db96d56Sopenharmony_ci#endif
14457db96d56Sopenharmony_ci
14467db96d56Sopenharmony_ci/* Return a pointer to a bottom tree node, return NULL if it doesn't exist or
14477db96d56Sopenharmony_ci * it cannot be created */
14487db96d56Sopenharmony_cistatic inline Py_ALWAYS_INLINE arena_map_bot_t *
14497db96d56Sopenharmony_ciarena_map_get(block *p, int create)
14507db96d56Sopenharmony_ci{
14517db96d56Sopenharmony_ci#ifdef USE_INTERIOR_NODES
14527db96d56Sopenharmony_ci    /* sanity check that IGNORE_BITS is correct */
14537db96d56Sopenharmony_ci    assert(HIGH_BITS(p) == HIGH_BITS(&arena_map_root));
14547db96d56Sopenharmony_ci    int i1 = MAP_TOP_INDEX(p);
14557db96d56Sopenharmony_ci    if (arena_map_root.ptrs[i1] == NULL) {
14567db96d56Sopenharmony_ci        if (!create) {
14577db96d56Sopenharmony_ci            return NULL;
14587db96d56Sopenharmony_ci        }
14597db96d56Sopenharmony_ci        arena_map_mid_t *n = PyMem_RawCalloc(1, sizeof(arena_map_mid_t));
14607db96d56Sopenharmony_ci        if (n == NULL) {
14617db96d56Sopenharmony_ci            return NULL;
14627db96d56Sopenharmony_ci        }
14637db96d56Sopenharmony_ci        arena_map_root.ptrs[i1] = n;
14647db96d56Sopenharmony_ci        arena_map_mid_count++;
14657db96d56Sopenharmony_ci    }
14667db96d56Sopenharmony_ci    int i2 = MAP_MID_INDEX(p);
14677db96d56Sopenharmony_ci    if (arena_map_root.ptrs[i1]->ptrs[i2] == NULL) {
14687db96d56Sopenharmony_ci        if (!create) {
14697db96d56Sopenharmony_ci            return NULL;
14707db96d56Sopenharmony_ci        }
14717db96d56Sopenharmony_ci        arena_map_bot_t *n = PyMem_RawCalloc(1, sizeof(arena_map_bot_t));
14727db96d56Sopenharmony_ci        if (n == NULL) {
14737db96d56Sopenharmony_ci            return NULL;
14747db96d56Sopenharmony_ci        }
14757db96d56Sopenharmony_ci        arena_map_root.ptrs[i1]->ptrs[i2] = n;
14767db96d56Sopenharmony_ci        arena_map_bot_count++;
14777db96d56Sopenharmony_ci    }
14787db96d56Sopenharmony_ci    return arena_map_root.ptrs[i1]->ptrs[i2];
14797db96d56Sopenharmony_ci#else
14807db96d56Sopenharmony_ci    return &arena_map_root;
14817db96d56Sopenharmony_ci#endif
14827db96d56Sopenharmony_ci}
14837db96d56Sopenharmony_ci
14847db96d56Sopenharmony_ci
14857db96d56Sopenharmony_ci/* The radix tree only tracks arenas.  So, for 16 MiB arenas, we throw
14867db96d56Sopenharmony_ci * away 24 bits of the address.  That reduces the space requirement of
14877db96d56Sopenharmony_ci * the tree compared to similar radix tree page-map schemes.  In
14887db96d56Sopenharmony_ci * exchange for slashing the space requirement, it needs more
14897db96d56Sopenharmony_ci * computation to check an address.
14907db96d56Sopenharmony_ci *
14917db96d56Sopenharmony_ci * Tracking coverage is done by "ideal" arena address.  It is easier to
14927db96d56Sopenharmony_ci * explain in decimal so let's say that the arena size is 100 bytes.
14937db96d56Sopenharmony_ci * Then, ideal addresses are 100, 200, 300, etc.  For checking if a
14947db96d56Sopenharmony_ci * pointer address is inside an actual arena, we have to check two ideal
14957db96d56Sopenharmony_ci * arena addresses.  E.g. if pointer is 357, we need to check 200 and
14967db96d56Sopenharmony_ci * 300.  In the rare case that an arena is aligned in the ideal way
14977db96d56Sopenharmony_ci * (e.g. base address of arena is 200) then we only have to check one
14987db96d56Sopenharmony_ci * ideal address.
14997db96d56Sopenharmony_ci *
15007db96d56Sopenharmony_ci * The tree nodes for 200 and 300 both store the address of arena.
15017db96d56Sopenharmony_ci * There are two cases: the arena starts at a lower ideal arena and
15027db96d56Sopenharmony_ci * extends to this one, or the arena starts in this arena and extends to
15037db96d56Sopenharmony_ci * the next ideal arena.  The tail_lo and tail_hi members correspond to
15047db96d56Sopenharmony_ci * these two cases.
15057db96d56Sopenharmony_ci */
15067db96d56Sopenharmony_ci
15077db96d56Sopenharmony_ci
15087db96d56Sopenharmony_ci/* mark or unmark addresses covered by arena */
15097db96d56Sopenharmony_cistatic int
15107db96d56Sopenharmony_ciarena_map_mark_used(uintptr_t arena_base, int is_used)
15117db96d56Sopenharmony_ci{
15127db96d56Sopenharmony_ci    /* sanity check that IGNORE_BITS is correct */
15137db96d56Sopenharmony_ci    assert(HIGH_BITS(arena_base) == HIGH_BITS(&arena_map_root));
15147db96d56Sopenharmony_ci    arena_map_bot_t *n_hi = arena_map_get((block *)arena_base, is_used);
15157db96d56Sopenharmony_ci    if (n_hi == NULL) {
15167db96d56Sopenharmony_ci        assert(is_used); /* otherwise node should already exist */
15177db96d56Sopenharmony_ci        return 0; /* failed to allocate space for node */
15187db96d56Sopenharmony_ci    }
15197db96d56Sopenharmony_ci    int i3 = MAP_BOT_INDEX((block *)arena_base);
15207db96d56Sopenharmony_ci    int32_t tail = (int32_t)(arena_base & ARENA_SIZE_MASK);
15217db96d56Sopenharmony_ci    if (tail == 0) {
15227db96d56Sopenharmony_ci        /* is ideal arena address */
15237db96d56Sopenharmony_ci        n_hi->arenas[i3].tail_hi = is_used ? -1 : 0;
15247db96d56Sopenharmony_ci    }
15257db96d56Sopenharmony_ci    else {
15267db96d56Sopenharmony_ci        /* arena_base address is not ideal (aligned to arena size) and
15277db96d56Sopenharmony_ci         * so it potentially covers two MAP_BOT nodes.  Get the MAP_BOT node
15287db96d56Sopenharmony_ci         * for the next arena.  Note that it might be in different MAP_TOP
15297db96d56Sopenharmony_ci         * and MAP_MID nodes as well so we need to call arena_map_get()
15307db96d56Sopenharmony_ci         * again (do the full tree traversal).
15317db96d56Sopenharmony_ci         */
15327db96d56Sopenharmony_ci        n_hi->arenas[i3].tail_hi = is_used ? tail : 0;
15337db96d56Sopenharmony_ci        uintptr_t arena_base_next = arena_base + ARENA_SIZE;
15347db96d56Sopenharmony_ci        /* If arena_base is a legit arena address, so is arena_base_next - 1
15357db96d56Sopenharmony_ci         * (last address in arena).  If arena_base_next overflows then it
15367db96d56Sopenharmony_ci         * must overflow to 0.  However, that would mean arena_base was
15377db96d56Sopenharmony_ci         * "ideal" and we should not be in this case. */
15387db96d56Sopenharmony_ci        assert(arena_base < arena_base_next);
15397db96d56Sopenharmony_ci        arena_map_bot_t *n_lo = arena_map_get((block *)arena_base_next, is_used);
15407db96d56Sopenharmony_ci        if (n_lo == NULL) {
15417db96d56Sopenharmony_ci            assert(is_used); /* otherwise should already exist */
15427db96d56Sopenharmony_ci            n_hi->arenas[i3].tail_hi = 0;
15437db96d56Sopenharmony_ci            return 0; /* failed to allocate space for node */
15447db96d56Sopenharmony_ci        }
15457db96d56Sopenharmony_ci        int i3_next = MAP_BOT_INDEX(arena_base_next);
15467db96d56Sopenharmony_ci        n_lo->arenas[i3_next].tail_lo = is_used ? tail : 0;
15477db96d56Sopenharmony_ci    }
15487db96d56Sopenharmony_ci    return 1;
15497db96d56Sopenharmony_ci}
15507db96d56Sopenharmony_ci
15517db96d56Sopenharmony_ci/* Return true if 'p' is a pointer inside an obmalloc arena.
15527db96d56Sopenharmony_ci * _PyObject_Free() calls this so it needs to be very fast. */
15537db96d56Sopenharmony_cistatic int
15547db96d56Sopenharmony_ciarena_map_is_used(block *p)
15557db96d56Sopenharmony_ci{
15567db96d56Sopenharmony_ci    arena_map_bot_t *n = arena_map_get(p, 0);
15577db96d56Sopenharmony_ci    if (n == NULL) {
15587db96d56Sopenharmony_ci        return 0;
15597db96d56Sopenharmony_ci    }
15607db96d56Sopenharmony_ci    int i3 = MAP_BOT_INDEX(p);
15617db96d56Sopenharmony_ci    /* ARENA_BITS must be < 32 so that the tail is a non-negative int32_t. */
15627db96d56Sopenharmony_ci    int32_t hi = n->arenas[i3].tail_hi;
15637db96d56Sopenharmony_ci    int32_t lo = n->arenas[i3].tail_lo;
15647db96d56Sopenharmony_ci    int32_t tail = (int32_t)(AS_UINT(p) & ARENA_SIZE_MASK);
15657db96d56Sopenharmony_ci    return (tail < lo) || (tail >= hi && hi != 0);
15667db96d56Sopenharmony_ci}
15677db96d56Sopenharmony_ci
15687db96d56Sopenharmony_ci/* end of radix tree logic */
15697db96d56Sopenharmony_ci/*==========================================================================*/
15707db96d56Sopenharmony_ci#endif /* WITH_PYMALLOC_RADIX_TREE */
15717db96d56Sopenharmony_ci
15727db96d56Sopenharmony_ci
15737db96d56Sopenharmony_ci/* Allocate a new arena.  If we run out of memory, return NULL.  Else
15747db96d56Sopenharmony_ci * allocate a new arena, and return the address of an arena_object
15757db96d56Sopenharmony_ci * describing the new arena.  It's expected that the caller will set
15767db96d56Sopenharmony_ci * `usable_arenas` to the return value.
15777db96d56Sopenharmony_ci */
15787db96d56Sopenharmony_cistatic struct arena_object*
15797db96d56Sopenharmony_cinew_arena(void)
15807db96d56Sopenharmony_ci{
15817db96d56Sopenharmony_ci    struct arena_object* arenaobj;
15827db96d56Sopenharmony_ci    uint excess;        /* number of bytes above pool alignment */
15837db96d56Sopenharmony_ci    void *address;
15847db96d56Sopenharmony_ci    static int debug_stats = -1;
15857db96d56Sopenharmony_ci
15867db96d56Sopenharmony_ci    if (debug_stats == -1) {
15877db96d56Sopenharmony_ci        const char *opt = Py_GETENV("PYTHONMALLOCSTATS");
15887db96d56Sopenharmony_ci        debug_stats = (opt != NULL && *opt != '\0');
15897db96d56Sopenharmony_ci    }
15907db96d56Sopenharmony_ci    if (debug_stats) {
15917db96d56Sopenharmony_ci        _PyObject_DebugMallocStats(stderr);
15927db96d56Sopenharmony_ci    }
15937db96d56Sopenharmony_ci
15947db96d56Sopenharmony_ci    if (unused_arena_objects == NULL) {
15957db96d56Sopenharmony_ci        uint i;
15967db96d56Sopenharmony_ci        uint numarenas;
15977db96d56Sopenharmony_ci        size_t nbytes;
15987db96d56Sopenharmony_ci
15997db96d56Sopenharmony_ci        /* Double the number of arena objects on each allocation.
16007db96d56Sopenharmony_ci         * Note that it's possible for `numarenas` to overflow.
16017db96d56Sopenharmony_ci         */
16027db96d56Sopenharmony_ci        numarenas = maxarenas ? maxarenas << 1 : INITIAL_ARENA_OBJECTS;
16037db96d56Sopenharmony_ci        if (numarenas <= maxarenas)
16047db96d56Sopenharmony_ci            return NULL;                /* overflow */
16057db96d56Sopenharmony_ci#if SIZEOF_SIZE_T <= SIZEOF_INT
16067db96d56Sopenharmony_ci        if (numarenas > SIZE_MAX / sizeof(*arenas))
16077db96d56Sopenharmony_ci            return NULL;                /* overflow */
16087db96d56Sopenharmony_ci#endif
16097db96d56Sopenharmony_ci        nbytes = numarenas * sizeof(*arenas);
16107db96d56Sopenharmony_ci        arenaobj = (struct arena_object *)PyMem_RawRealloc(arenas, nbytes);
16117db96d56Sopenharmony_ci        if (arenaobj == NULL)
16127db96d56Sopenharmony_ci            return NULL;
16137db96d56Sopenharmony_ci        arenas = arenaobj;
16147db96d56Sopenharmony_ci
16157db96d56Sopenharmony_ci        /* We might need to fix pointers that were copied.  However,
16167db96d56Sopenharmony_ci         * new_arena only gets called when all the pages in the
16177db96d56Sopenharmony_ci         * previous arenas are full.  Thus, there are *no* pointers
16187db96d56Sopenharmony_ci         * into the old array. Thus, we don't have to worry about
16197db96d56Sopenharmony_ci         * invalid pointers.  Just to be sure, some asserts:
16207db96d56Sopenharmony_ci         */
16217db96d56Sopenharmony_ci        assert(usable_arenas == NULL);
16227db96d56Sopenharmony_ci        assert(unused_arena_objects == NULL);
16237db96d56Sopenharmony_ci
16247db96d56Sopenharmony_ci        /* Put the new arenas on the unused_arena_objects list. */
16257db96d56Sopenharmony_ci        for (i = maxarenas; i < numarenas; ++i) {
16267db96d56Sopenharmony_ci            arenas[i].address = 0;              /* mark as unassociated */
16277db96d56Sopenharmony_ci            arenas[i].nextarena = i < numarenas - 1 ?
16287db96d56Sopenharmony_ci                                   &arenas[i+1] : NULL;
16297db96d56Sopenharmony_ci        }
16307db96d56Sopenharmony_ci
16317db96d56Sopenharmony_ci        /* Update globals. */
16327db96d56Sopenharmony_ci        unused_arena_objects = &arenas[maxarenas];
16337db96d56Sopenharmony_ci        maxarenas = numarenas;
16347db96d56Sopenharmony_ci    }
16357db96d56Sopenharmony_ci
16367db96d56Sopenharmony_ci    /* Take the next available arena object off the head of the list. */
16377db96d56Sopenharmony_ci    assert(unused_arena_objects != NULL);
16387db96d56Sopenharmony_ci    arenaobj = unused_arena_objects;
16397db96d56Sopenharmony_ci    unused_arena_objects = arenaobj->nextarena;
16407db96d56Sopenharmony_ci    assert(arenaobj->address == 0);
16417db96d56Sopenharmony_ci    address = _PyObject_Arena.alloc(_PyObject_Arena.ctx, ARENA_SIZE);
16427db96d56Sopenharmony_ci#if WITH_PYMALLOC_RADIX_TREE
16437db96d56Sopenharmony_ci    if (address != NULL) {
16447db96d56Sopenharmony_ci        if (!arena_map_mark_used((uintptr_t)address, 1)) {
16457db96d56Sopenharmony_ci            /* marking arena in radix tree failed, abort */
16467db96d56Sopenharmony_ci            _PyObject_Arena.free(_PyObject_Arena.ctx, address, ARENA_SIZE);
16477db96d56Sopenharmony_ci            address = NULL;
16487db96d56Sopenharmony_ci        }
16497db96d56Sopenharmony_ci    }
16507db96d56Sopenharmony_ci#endif
16517db96d56Sopenharmony_ci    if (address == NULL) {
16527db96d56Sopenharmony_ci        /* The allocation failed: return NULL after putting the
16537db96d56Sopenharmony_ci         * arenaobj back.
16547db96d56Sopenharmony_ci         */
16557db96d56Sopenharmony_ci        arenaobj->nextarena = unused_arena_objects;
16567db96d56Sopenharmony_ci        unused_arena_objects = arenaobj;
16577db96d56Sopenharmony_ci        return NULL;
16587db96d56Sopenharmony_ci    }
16597db96d56Sopenharmony_ci    arenaobj->address = (uintptr_t)address;
16607db96d56Sopenharmony_ci
16617db96d56Sopenharmony_ci    ++narenas_currently_allocated;
16627db96d56Sopenharmony_ci    ++ntimes_arena_allocated;
16637db96d56Sopenharmony_ci    if (narenas_currently_allocated > narenas_highwater)
16647db96d56Sopenharmony_ci        narenas_highwater = narenas_currently_allocated;
16657db96d56Sopenharmony_ci    arenaobj->freepools = NULL;
16667db96d56Sopenharmony_ci    /* pool_address <- first pool-aligned address in the arena
16677db96d56Sopenharmony_ci       nfreepools <- number of whole pools that fit after alignment */
16687db96d56Sopenharmony_ci    arenaobj->pool_address = (block*)arenaobj->address;
16697db96d56Sopenharmony_ci    arenaobj->nfreepools = MAX_POOLS_IN_ARENA;
16707db96d56Sopenharmony_ci    excess = (uint)(arenaobj->address & POOL_SIZE_MASK);
16717db96d56Sopenharmony_ci    if (excess != 0) {
16727db96d56Sopenharmony_ci        --arenaobj->nfreepools;
16737db96d56Sopenharmony_ci        arenaobj->pool_address += POOL_SIZE - excess;
16747db96d56Sopenharmony_ci    }
16757db96d56Sopenharmony_ci    arenaobj->ntotalpools = arenaobj->nfreepools;
16767db96d56Sopenharmony_ci
16777db96d56Sopenharmony_ci    return arenaobj;
16787db96d56Sopenharmony_ci}
16797db96d56Sopenharmony_ci
16807db96d56Sopenharmony_ci
16817db96d56Sopenharmony_ci
16827db96d56Sopenharmony_ci#if WITH_PYMALLOC_RADIX_TREE
16837db96d56Sopenharmony_ci/* Return true if and only if P is an address that was allocated by
16847db96d56Sopenharmony_ci   pymalloc.  When the radix tree is used, 'poolp' is unused.
16857db96d56Sopenharmony_ci */
16867db96d56Sopenharmony_cistatic bool
16877db96d56Sopenharmony_ciaddress_in_range(void *p, poolp pool)
16887db96d56Sopenharmony_ci{
16897db96d56Sopenharmony_ci    return arena_map_is_used(p);
16907db96d56Sopenharmony_ci}
16917db96d56Sopenharmony_ci#else
16927db96d56Sopenharmony_ci/*
16937db96d56Sopenharmony_ciaddress_in_range(P, POOL)
16947db96d56Sopenharmony_ci
16957db96d56Sopenharmony_ciReturn true if and only if P is an address that was allocated by pymalloc.
16967db96d56Sopenharmony_ciPOOL must be the pool address associated with P, i.e., POOL = POOL_ADDR(P)
16977db96d56Sopenharmony_ci(the caller is asked to compute this because the macro expands POOL more than
16987db96d56Sopenharmony_cionce, and for efficiency it's best for the caller to assign POOL_ADDR(P) to a
16997db96d56Sopenharmony_civariable and pass the latter to the macro; because address_in_range is
17007db96d56Sopenharmony_cicalled on every alloc/realloc/free, micro-efficiency is important here).
17017db96d56Sopenharmony_ci
17027db96d56Sopenharmony_ciTricky:  Let B be the arena base address associated with the pool, B =
17037db96d56Sopenharmony_ciarenas[(POOL)->arenaindex].address.  Then P belongs to the arena if and only if
17047db96d56Sopenharmony_ci
17057db96d56Sopenharmony_ci    B <= P < B + ARENA_SIZE
17067db96d56Sopenharmony_ci
17077db96d56Sopenharmony_ciSubtracting B throughout, this is true iff
17087db96d56Sopenharmony_ci
17097db96d56Sopenharmony_ci    0 <= P-B < ARENA_SIZE
17107db96d56Sopenharmony_ci
17117db96d56Sopenharmony_ciBy using unsigned arithmetic, the "0 <=" half of the test can be skipped.
17127db96d56Sopenharmony_ci
17137db96d56Sopenharmony_ciObscure:  A PyMem "free memory" function can call the pymalloc free or realloc
17147db96d56Sopenharmony_cibefore the first arena has been allocated.  `arenas` is still NULL in that
17157db96d56Sopenharmony_cicase.  We're relying on that maxarenas is also 0 in that case, so that
17167db96d56Sopenharmony_ci(POOL)->arenaindex < maxarenas  must be false, saving us from trying to index
17177db96d56Sopenharmony_ciinto a NULL arenas.
17187db96d56Sopenharmony_ci
17197db96d56Sopenharmony_ciDetails:  given P and POOL, the arena_object corresponding to P is AO =
17207db96d56Sopenharmony_ciarenas[(POOL)->arenaindex].  Suppose obmalloc controls P.  Then (barring wild
17217db96d56Sopenharmony_cistores, etc), POOL is the correct address of P's pool, AO.address is the
17227db96d56Sopenharmony_cicorrect base address of the pool's arena, and P must be within ARENA_SIZE of
17237db96d56Sopenharmony_ciAO.address.  In addition, AO.address is not 0 (no arena can start at address 0
17247db96d56Sopenharmony_ci(NULL)).  Therefore address_in_range correctly reports that obmalloc
17257db96d56Sopenharmony_cicontrols P.
17267db96d56Sopenharmony_ci
17277db96d56Sopenharmony_ciNow suppose obmalloc does not control P (e.g., P was obtained via a direct
17287db96d56Sopenharmony_cicall to the system malloc() or realloc()).  (POOL)->arenaindex may be anything
17297db96d56Sopenharmony_ciin this case -- it may even be uninitialized trash.  If the trash arenaindex
17307db96d56Sopenharmony_ciis >= maxarenas, the macro correctly concludes at once that obmalloc doesn't
17317db96d56Sopenharmony_cicontrol P.
17327db96d56Sopenharmony_ci
17337db96d56Sopenharmony_ciElse arenaindex is < maxarena, and AO is read up.  If AO corresponds to an
17347db96d56Sopenharmony_ciallocated arena, obmalloc controls all the memory in slice AO.address :
17357db96d56Sopenharmony_ciAO.address+ARENA_SIZE.  By case assumption, P is not controlled by obmalloc,
17367db96d56Sopenharmony_ciso P doesn't lie in that slice, so the macro correctly reports that P is not
17377db96d56Sopenharmony_cicontrolled by obmalloc.
17387db96d56Sopenharmony_ci
17397db96d56Sopenharmony_ciFinally, if P is not controlled by obmalloc and AO corresponds to an unused
17407db96d56Sopenharmony_ciarena_object (one not currently associated with an allocated arena),
17417db96d56Sopenharmony_ciAO.address is 0, and the second test in the macro reduces to:
17427db96d56Sopenharmony_ci
17437db96d56Sopenharmony_ci    P < ARENA_SIZE
17447db96d56Sopenharmony_ci
17457db96d56Sopenharmony_ciIf P >= ARENA_SIZE (extremely likely), the macro again correctly concludes
17467db96d56Sopenharmony_cithat P is not controlled by obmalloc.  However, if P < ARENA_SIZE, this part
17477db96d56Sopenharmony_ciof the test still passes, and the third clause (AO.address != 0) is necessary
17487db96d56Sopenharmony_cito get the correct result:  AO.address is 0 in this case, so the macro
17497db96d56Sopenharmony_cicorrectly reports that P is not controlled by obmalloc (despite that P lies in
17507db96d56Sopenharmony_cislice AO.address : AO.address + ARENA_SIZE).
17517db96d56Sopenharmony_ci
17527db96d56Sopenharmony_ciNote:  The third (AO.address != 0) clause was added in Python 2.5.  Before
17537db96d56Sopenharmony_ci2.5, arenas were never free()'ed, and an arenaindex < maxarena always
17547db96d56Sopenharmony_cicorresponded to a currently-allocated arena, so the "P is not controlled by
17557db96d56Sopenharmony_ciobmalloc, AO corresponds to an unused arena_object, and P < ARENA_SIZE" case
17567db96d56Sopenharmony_ciwas impossible.
17577db96d56Sopenharmony_ci
17587db96d56Sopenharmony_ciNote that the logic is excruciating, and reading up possibly uninitialized
17597db96d56Sopenharmony_cimemory when P is not controlled by obmalloc (to get at (POOL)->arenaindex)
17607db96d56Sopenharmony_cicreates problems for some memory debuggers.  The overwhelming advantage is
17617db96d56Sopenharmony_cithat this test determines whether an arbitrary address is controlled by
17627db96d56Sopenharmony_ciobmalloc in a small constant time, independent of the number of arenas
17637db96d56Sopenharmony_ciobmalloc controls.  Since this test is needed at every entry point, it's
17647db96d56Sopenharmony_ciextremely desirable that it be this fast.
17657db96d56Sopenharmony_ci*/
17667db96d56Sopenharmony_ci
17677db96d56Sopenharmony_cistatic bool _Py_NO_SANITIZE_ADDRESS
17687db96d56Sopenharmony_ci            _Py_NO_SANITIZE_THREAD
17697db96d56Sopenharmony_ci            _Py_NO_SANITIZE_MEMORY
17707db96d56Sopenharmony_ciaddress_in_range(void *p, poolp pool)
17717db96d56Sopenharmony_ci{
17727db96d56Sopenharmony_ci    // Since address_in_range may be reading from memory which was not allocated
17737db96d56Sopenharmony_ci    // by Python, it is important that pool->arenaindex is read only once, as
17747db96d56Sopenharmony_ci    // another thread may be concurrently modifying the value without holding
17757db96d56Sopenharmony_ci    // the GIL. The following dance forces the compiler to read pool->arenaindex
17767db96d56Sopenharmony_ci    // only once.
17777db96d56Sopenharmony_ci    uint arenaindex = *((volatile uint *)&pool->arenaindex);
17787db96d56Sopenharmony_ci    return arenaindex < maxarenas &&
17797db96d56Sopenharmony_ci        (uintptr_t)p - arenas[arenaindex].address < ARENA_SIZE &&
17807db96d56Sopenharmony_ci        arenas[arenaindex].address != 0;
17817db96d56Sopenharmony_ci}
17827db96d56Sopenharmony_ci
17837db96d56Sopenharmony_ci#endif /* !WITH_PYMALLOC_RADIX_TREE */
17847db96d56Sopenharmony_ci
17857db96d56Sopenharmony_ci/*==========================================================================*/
17867db96d56Sopenharmony_ci
17877db96d56Sopenharmony_ci// Called when freelist is exhausted.  Extend the freelist if there is
17887db96d56Sopenharmony_ci// space for a block.  Otherwise, remove this pool from usedpools.
17897db96d56Sopenharmony_cistatic void
17907db96d56Sopenharmony_cipymalloc_pool_extend(poolp pool, uint size)
17917db96d56Sopenharmony_ci{
17927db96d56Sopenharmony_ci    if (UNLIKELY(pool->nextoffset <= pool->maxnextoffset)) {
17937db96d56Sopenharmony_ci        /* There is room for another block. */
17947db96d56Sopenharmony_ci        pool->freeblock = (block*)pool + pool->nextoffset;
17957db96d56Sopenharmony_ci        pool->nextoffset += INDEX2SIZE(size);
17967db96d56Sopenharmony_ci        *(block **)(pool->freeblock) = NULL;
17977db96d56Sopenharmony_ci        return;
17987db96d56Sopenharmony_ci    }
17997db96d56Sopenharmony_ci
18007db96d56Sopenharmony_ci    /* Pool is full, unlink from used pools. */
18017db96d56Sopenharmony_ci    poolp next;
18027db96d56Sopenharmony_ci    next = pool->nextpool;
18037db96d56Sopenharmony_ci    pool = pool->prevpool;
18047db96d56Sopenharmony_ci    next->prevpool = pool;
18057db96d56Sopenharmony_ci    pool->nextpool = next;
18067db96d56Sopenharmony_ci}
18077db96d56Sopenharmony_ci
18087db96d56Sopenharmony_ci/* called when pymalloc_alloc can not allocate a block from usedpool.
18097db96d56Sopenharmony_ci * This function takes new pool and allocate a block from it.
18107db96d56Sopenharmony_ci */
18117db96d56Sopenharmony_cistatic void*
18127db96d56Sopenharmony_ciallocate_from_new_pool(uint size)
18137db96d56Sopenharmony_ci{
18147db96d56Sopenharmony_ci    /* There isn't a pool of the right size class immediately
18157db96d56Sopenharmony_ci     * available:  use a free pool.
18167db96d56Sopenharmony_ci     */
18177db96d56Sopenharmony_ci    if (UNLIKELY(usable_arenas == NULL)) {
18187db96d56Sopenharmony_ci        /* No arena has a free pool:  allocate a new arena. */
18197db96d56Sopenharmony_ci#ifdef WITH_MEMORY_LIMITS
18207db96d56Sopenharmony_ci        if (narenas_currently_allocated >= MAX_ARENAS) {
18217db96d56Sopenharmony_ci            return NULL;
18227db96d56Sopenharmony_ci        }
18237db96d56Sopenharmony_ci#endif
18247db96d56Sopenharmony_ci        usable_arenas = new_arena();
18257db96d56Sopenharmony_ci        if (usable_arenas == NULL) {
18267db96d56Sopenharmony_ci            return NULL;
18277db96d56Sopenharmony_ci        }
18287db96d56Sopenharmony_ci        usable_arenas->nextarena = usable_arenas->prevarena = NULL;
18297db96d56Sopenharmony_ci        assert(nfp2lasta[usable_arenas->nfreepools] == NULL);
18307db96d56Sopenharmony_ci        nfp2lasta[usable_arenas->nfreepools] = usable_arenas;
18317db96d56Sopenharmony_ci    }
18327db96d56Sopenharmony_ci    assert(usable_arenas->address != 0);
18337db96d56Sopenharmony_ci
18347db96d56Sopenharmony_ci    /* This arena already had the smallest nfreepools value, so decreasing
18357db96d56Sopenharmony_ci     * nfreepools doesn't change that, and we don't need to rearrange the
18367db96d56Sopenharmony_ci     * usable_arenas list.  However, if the arena becomes wholly allocated,
18377db96d56Sopenharmony_ci     * we need to remove its arena_object from usable_arenas.
18387db96d56Sopenharmony_ci     */
18397db96d56Sopenharmony_ci    assert(usable_arenas->nfreepools > 0);
18407db96d56Sopenharmony_ci    if (nfp2lasta[usable_arenas->nfreepools] == usable_arenas) {
18417db96d56Sopenharmony_ci        /* It's the last of this size, so there won't be any. */
18427db96d56Sopenharmony_ci        nfp2lasta[usable_arenas->nfreepools] = NULL;
18437db96d56Sopenharmony_ci    }
18447db96d56Sopenharmony_ci    /* If any free pools will remain, it will be the new smallest. */
18457db96d56Sopenharmony_ci    if (usable_arenas->nfreepools > 1) {
18467db96d56Sopenharmony_ci        assert(nfp2lasta[usable_arenas->nfreepools - 1] == NULL);
18477db96d56Sopenharmony_ci        nfp2lasta[usable_arenas->nfreepools - 1] = usable_arenas;
18487db96d56Sopenharmony_ci    }
18497db96d56Sopenharmony_ci
18507db96d56Sopenharmony_ci    /* Try to get a cached free pool. */
18517db96d56Sopenharmony_ci    poolp pool = usable_arenas->freepools;
18527db96d56Sopenharmony_ci    if (LIKELY(pool != NULL)) {
18537db96d56Sopenharmony_ci        /* Unlink from cached pools. */
18547db96d56Sopenharmony_ci        usable_arenas->freepools = pool->nextpool;
18557db96d56Sopenharmony_ci        usable_arenas->nfreepools--;
18567db96d56Sopenharmony_ci        if (UNLIKELY(usable_arenas->nfreepools == 0)) {
18577db96d56Sopenharmony_ci            /* Wholly allocated:  remove. */
18587db96d56Sopenharmony_ci            assert(usable_arenas->freepools == NULL);
18597db96d56Sopenharmony_ci            assert(usable_arenas->nextarena == NULL ||
18607db96d56Sopenharmony_ci                   usable_arenas->nextarena->prevarena ==
18617db96d56Sopenharmony_ci                   usable_arenas);
18627db96d56Sopenharmony_ci            usable_arenas = usable_arenas->nextarena;
18637db96d56Sopenharmony_ci            if (usable_arenas != NULL) {
18647db96d56Sopenharmony_ci                usable_arenas->prevarena = NULL;
18657db96d56Sopenharmony_ci                assert(usable_arenas->address != 0);
18667db96d56Sopenharmony_ci            }
18677db96d56Sopenharmony_ci        }
18687db96d56Sopenharmony_ci        else {
18697db96d56Sopenharmony_ci            /* nfreepools > 0:  it must be that freepools
18707db96d56Sopenharmony_ci             * isn't NULL, or that we haven't yet carved
18717db96d56Sopenharmony_ci             * off all the arena's pools for the first
18727db96d56Sopenharmony_ci             * time.
18737db96d56Sopenharmony_ci             */
18747db96d56Sopenharmony_ci            assert(usable_arenas->freepools != NULL ||
18757db96d56Sopenharmony_ci                   usable_arenas->pool_address <=
18767db96d56Sopenharmony_ci                   (block*)usable_arenas->address +
18777db96d56Sopenharmony_ci                       ARENA_SIZE - POOL_SIZE);
18787db96d56Sopenharmony_ci        }
18797db96d56Sopenharmony_ci    }
18807db96d56Sopenharmony_ci    else {
18817db96d56Sopenharmony_ci        /* Carve off a new pool. */
18827db96d56Sopenharmony_ci        assert(usable_arenas->nfreepools > 0);
18837db96d56Sopenharmony_ci        assert(usable_arenas->freepools == NULL);
18847db96d56Sopenharmony_ci        pool = (poolp)usable_arenas->pool_address;
18857db96d56Sopenharmony_ci        assert((block*)pool <= (block*)usable_arenas->address +
18867db96d56Sopenharmony_ci                                 ARENA_SIZE - POOL_SIZE);
18877db96d56Sopenharmony_ci        pool->arenaindex = (uint)(usable_arenas - arenas);
18887db96d56Sopenharmony_ci        assert(&arenas[pool->arenaindex] == usable_arenas);
18897db96d56Sopenharmony_ci        pool->szidx = DUMMY_SIZE_IDX;
18907db96d56Sopenharmony_ci        usable_arenas->pool_address += POOL_SIZE;
18917db96d56Sopenharmony_ci        --usable_arenas->nfreepools;
18927db96d56Sopenharmony_ci
18937db96d56Sopenharmony_ci        if (usable_arenas->nfreepools == 0) {
18947db96d56Sopenharmony_ci            assert(usable_arenas->nextarena == NULL ||
18957db96d56Sopenharmony_ci                   usable_arenas->nextarena->prevarena ==
18967db96d56Sopenharmony_ci                   usable_arenas);
18977db96d56Sopenharmony_ci            /* Unlink the arena:  it is completely allocated. */
18987db96d56Sopenharmony_ci            usable_arenas = usable_arenas->nextarena;
18997db96d56Sopenharmony_ci            if (usable_arenas != NULL) {
19007db96d56Sopenharmony_ci                usable_arenas->prevarena = NULL;
19017db96d56Sopenharmony_ci                assert(usable_arenas->address != 0);
19027db96d56Sopenharmony_ci            }
19037db96d56Sopenharmony_ci        }
19047db96d56Sopenharmony_ci    }
19057db96d56Sopenharmony_ci
19067db96d56Sopenharmony_ci    /* Frontlink to used pools. */
19077db96d56Sopenharmony_ci    block *bp;
19087db96d56Sopenharmony_ci    poolp next = usedpools[size + size]; /* == prev */
19097db96d56Sopenharmony_ci    pool->nextpool = next;
19107db96d56Sopenharmony_ci    pool->prevpool = next;
19117db96d56Sopenharmony_ci    next->nextpool = pool;
19127db96d56Sopenharmony_ci    next->prevpool = pool;
19137db96d56Sopenharmony_ci    pool->ref.count = 1;
19147db96d56Sopenharmony_ci    if (pool->szidx == size) {
19157db96d56Sopenharmony_ci        /* Luckily, this pool last contained blocks
19167db96d56Sopenharmony_ci         * of the same size class, so its header
19177db96d56Sopenharmony_ci         * and free list are already initialized.
19187db96d56Sopenharmony_ci         */
19197db96d56Sopenharmony_ci        bp = pool->freeblock;
19207db96d56Sopenharmony_ci        assert(bp != NULL);
19217db96d56Sopenharmony_ci        pool->freeblock = *(block **)bp;
19227db96d56Sopenharmony_ci        return bp;
19237db96d56Sopenharmony_ci    }
19247db96d56Sopenharmony_ci    /*
19257db96d56Sopenharmony_ci     * Initialize the pool header, set up the free list to
19267db96d56Sopenharmony_ci     * contain just the second block, and return the first
19277db96d56Sopenharmony_ci     * block.
19287db96d56Sopenharmony_ci     */
19297db96d56Sopenharmony_ci    pool->szidx = size;
19307db96d56Sopenharmony_ci    size = INDEX2SIZE(size);
19317db96d56Sopenharmony_ci    bp = (block *)pool + POOL_OVERHEAD;
19327db96d56Sopenharmony_ci    pool->nextoffset = POOL_OVERHEAD + (size << 1);
19337db96d56Sopenharmony_ci    pool->maxnextoffset = POOL_SIZE - size;
19347db96d56Sopenharmony_ci    pool->freeblock = bp + size;
19357db96d56Sopenharmony_ci    *(block **)(pool->freeblock) = NULL;
19367db96d56Sopenharmony_ci    return bp;
19377db96d56Sopenharmony_ci}
19387db96d56Sopenharmony_ci
19397db96d56Sopenharmony_ci/* pymalloc allocator
19407db96d56Sopenharmony_ci
19417db96d56Sopenharmony_ci   Return a pointer to newly allocated memory if pymalloc allocated memory.
19427db96d56Sopenharmony_ci
19437db96d56Sopenharmony_ci   Return NULL if pymalloc failed to allocate the memory block: on bigger
19447db96d56Sopenharmony_ci   requests, on error in the code below (as a last chance to serve the request)
19457db96d56Sopenharmony_ci   or when the max memory limit has been reached.
19467db96d56Sopenharmony_ci*/
19477db96d56Sopenharmony_cistatic inline void*
19487db96d56Sopenharmony_cipymalloc_alloc(void *ctx, size_t nbytes)
19497db96d56Sopenharmony_ci{
19507db96d56Sopenharmony_ci#ifdef WITH_VALGRIND
19517db96d56Sopenharmony_ci    if (UNLIKELY(running_on_valgrind == -1)) {
19527db96d56Sopenharmony_ci        running_on_valgrind = RUNNING_ON_VALGRIND;
19537db96d56Sopenharmony_ci    }
19547db96d56Sopenharmony_ci    if (UNLIKELY(running_on_valgrind)) {
19557db96d56Sopenharmony_ci        return NULL;
19567db96d56Sopenharmony_ci    }
19577db96d56Sopenharmony_ci#endif
19587db96d56Sopenharmony_ci
19597db96d56Sopenharmony_ci    if (UNLIKELY(nbytes == 0)) {
19607db96d56Sopenharmony_ci        return NULL;
19617db96d56Sopenharmony_ci    }
19627db96d56Sopenharmony_ci    if (UNLIKELY(nbytes > SMALL_REQUEST_THRESHOLD)) {
19637db96d56Sopenharmony_ci        return NULL;
19647db96d56Sopenharmony_ci    }
19657db96d56Sopenharmony_ci
19667db96d56Sopenharmony_ci    uint size = (uint)(nbytes - 1) >> ALIGNMENT_SHIFT;
19677db96d56Sopenharmony_ci    poolp pool = usedpools[size + size];
19687db96d56Sopenharmony_ci    block *bp;
19697db96d56Sopenharmony_ci
19707db96d56Sopenharmony_ci    if (LIKELY(pool != pool->nextpool)) {
19717db96d56Sopenharmony_ci        /*
19727db96d56Sopenharmony_ci         * There is a used pool for this size class.
19737db96d56Sopenharmony_ci         * Pick up the head block of its free list.
19747db96d56Sopenharmony_ci         */
19757db96d56Sopenharmony_ci        ++pool->ref.count;
19767db96d56Sopenharmony_ci        bp = pool->freeblock;
19777db96d56Sopenharmony_ci        assert(bp != NULL);
19787db96d56Sopenharmony_ci
19797db96d56Sopenharmony_ci        if (UNLIKELY((pool->freeblock = *(block **)bp) == NULL)) {
19807db96d56Sopenharmony_ci            // Reached the end of the free list, try to extend it.
19817db96d56Sopenharmony_ci            pymalloc_pool_extend(pool, size);
19827db96d56Sopenharmony_ci        }
19837db96d56Sopenharmony_ci    }
19847db96d56Sopenharmony_ci    else {
19857db96d56Sopenharmony_ci        /* There isn't a pool of the right size class immediately
19867db96d56Sopenharmony_ci         * available:  use a free pool.
19877db96d56Sopenharmony_ci         */
19887db96d56Sopenharmony_ci        bp = allocate_from_new_pool(size);
19897db96d56Sopenharmony_ci    }
19907db96d56Sopenharmony_ci
19917db96d56Sopenharmony_ci    return (void *)bp;
19927db96d56Sopenharmony_ci}
19937db96d56Sopenharmony_ci
19947db96d56Sopenharmony_ci
19957db96d56Sopenharmony_cistatic void *
19967db96d56Sopenharmony_ci_PyObject_Malloc(void *ctx, size_t nbytes)
19977db96d56Sopenharmony_ci{
19987db96d56Sopenharmony_ci    void* ptr = pymalloc_alloc(ctx, nbytes);
19997db96d56Sopenharmony_ci    if (LIKELY(ptr != NULL)) {
20007db96d56Sopenharmony_ci        return ptr;
20017db96d56Sopenharmony_ci    }
20027db96d56Sopenharmony_ci
20037db96d56Sopenharmony_ci    ptr = PyMem_RawMalloc(nbytes);
20047db96d56Sopenharmony_ci    if (ptr != NULL) {
20057db96d56Sopenharmony_ci        raw_allocated_blocks++;
20067db96d56Sopenharmony_ci    }
20077db96d56Sopenharmony_ci    return ptr;
20087db96d56Sopenharmony_ci}
20097db96d56Sopenharmony_ci
20107db96d56Sopenharmony_ci
20117db96d56Sopenharmony_cistatic void *
20127db96d56Sopenharmony_ci_PyObject_Calloc(void *ctx, size_t nelem, size_t elsize)
20137db96d56Sopenharmony_ci{
20147db96d56Sopenharmony_ci    assert(elsize == 0 || nelem <= (size_t)PY_SSIZE_T_MAX / elsize);
20157db96d56Sopenharmony_ci    size_t nbytes = nelem * elsize;
20167db96d56Sopenharmony_ci
20177db96d56Sopenharmony_ci    void* ptr = pymalloc_alloc(ctx, nbytes);
20187db96d56Sopenharmony_ci    if (LIKELY(ptr != NULL)) {
20197db96d56Sopenharmony_ci        memset(ptr, 0, nbytes);
20207db96d56Sopenharmony_ci        return ptr;
20217db96d56Sopenharmony_ci    }
20227db96d56Sopenharmony_ci
20237db96d56Sopenharmony_ci    ptr = PyMem_RawCalloc(nelem, elsize);
20247db96d56Sopenharmony_ci    if (ptr != NULL) {
20257db96d56Sopenharmony_ci        raw_allocated_blocks++;
20267db96d56Sopenharmony_ci    }
20277db96d56Sopenharmony_ci    return ptr;
20287db96d56Sopenharmony_ci}
20297db96d56Sopenharmony_ci
20307db96d56Sopenharmony_ci
20317db96d56Sopenharmony_cistatic void
20327db96d56Sopenharmony_ciinsert_to_usedpool(poolp pool)
20337db96d56Sopenharmony_ci{
20347db96d56Sopenharmony_ci    assert(pool->ref.count > 0);            /* else the pool is empty */
20357db96d56Sopenharmony_ci
20367db96d56Sopenharmony_ci    uint size = pool->szidx;
20377db96d56Sopenharmony_ci    poolp next = usedpools[size + size];
20387db96d56Sopenharmony_ci    poolp prev = next->prevpool;
20397db96d56Sopenharmony_ci
20407db96d56Sopenharmony_ci    /* insert pool before next:   prev <-> pool <-> next */
20417db96d56Sopenharmony_ci    pool->nextpool = next;
20427db96d56Sopenharmony_ci    pool->prevpool = prev;
20437db96d56Sopenharmony_ci    next->prevpool = pool;
20447db96d56Sopenharmony_ci    prev->nextpool = pool;
20457db96d56Sopenharmony_ci}
20467db96d56Sopenharmony_ci
20477db96d56Sopenharmony_cistatic void
20487db96d56Sopenharmony_ciinsert_to_freepool(poolp pool)
20497db96d56Sopenharmony_ci{
20507db96d56Sopenharmony_ci    poolp next = pool->nextpool;
20517db96d56Sopenharmony_ci    poolp prev = pool->prevpool;
20527db96d56Sopenharmony_ci    next->prevpool = prev;
20537db96d56Sopenharmony_ci    prev->nextpool = next;
20547db96d56Sopenharmony_ci
20557db96d56Sopenharmony_ci    /* Link the pool to freepools.  This is a singly-linked
20567db96d56Sopenharmony_ci     * list, and pool->prevpool isn't used there.
20577db96d56Sopenharmony_ci     */
20587db96d56Sopenharmony_ci    struct arena_object *ao = &arenas[pool->arenaindex];
20597db96d56Sopenharmony_ci    pool->nextpool = ao->freepools;
20607db96d56Sopenharmony_ci    ao->freepools = pool;
20617db96d56Sopenharmony_ci    uint nf = ao->nfreepools;
20627db96d56Sopenharmony_ci    /* If this is the rightmost arena with this number of free pools,
20637db96d56Sopenharmony_ci     * nfp2lasta[nf] needs to change.  Caution:  if nf is 0, there
20647db96d56Sopenharmony_ci     * are no arenas in usable_arenas with that value.
20657db96d56Sopenharmony_ci     */
20667db96d56Sopenharmony_ci    struct arena_object* lastnf = nfp2lasta[nf];
20677db96d56Sopenharmony_ci    assert((nf == 0 && lastnf == NULL) ||
20687db96d56Sopenharmony_ci           (nf > 0 &&
20697db96d56Sopenharmony_ci            lastnf != NULL &&
20707db96d56Sopenharmony_ci            lastnf->nfreepools == nf &&
20717db96d56Sopenharmony_ci            (lastnf->nextarena == NULL ||
20727db96d56Sopenharmony_ci             nf < lastnf->nextarena->nfreepools)));
20737db96d56Sopenharmony_ci    if (lastnf == ao) {  /* it is the rightmost */
20747db96d56Sopenharmony_ci        struct arena_object* p = ao->prevarena;
20757db96d56Sopenharmony_ci        nfp2lasta[nf] = (p != NULL && p->nfreepools == nf) ? p : NULL;
20767db96d56Sopenharmony_ci    }
20777db96d56Sopenharmony_ci    ao->nfreepools = ++nf;
20787db96d56Sopenharmony_ci
20797db96d56Sopenharmony_ci    /* All the rest is arena management.  We just freed
20807db96d56Sopenharmony_ci     * a pool, and there are 4 cases for arena mgmt:
20817db96d56Sopenharmony_ci     * 1. If all the pools are free, return the arena to
20827db96d56Sopenharmony_ci     *    the system free().  Except if this is the last
20837db96d56Sopenharmony_ci     *    arena in the list, keep it to avoid thrashing:
20847db96d56Sopenharmony_ci     *    keeping one wholly free arena in the list avoids
20857db96d56Sopenharmony_ci     *    pathological cases where a simple loop would
20867db96d56Sopenharmony_ci     *    otherwise provoke needing to allocate and free an
20877db96d56Sopenharmony_ci     *    arena on every iteration.  See bpo-37257.
20887db96d56Sopenharmony_ci     * 2. If this is the only free pool in the arena,
20897db96d56Sopenharmony_ci     *    add the arena back to the `usable_arenas` list.
20907db96d56Sopenharmony_ci     * 3. If the "next" arena has a smaller count of free
20917db96d56Sopenharmony_ci     *    pools, we have to "slide this arena right" to
20927db96d56Sopenharmony_ci     *    restore that usable_arenas is sorted in order of
20937db96d56Sopenharmony_ci     *    nfreepools.
20947db96d56Sopenharmony_ci     * 4. Else there's nothing more to do.
20957db96d56Sopenharmony_ci     */
20967db96d56Sopenharmony_ci    if (nf == ao->ntotalpools && ao->nextarena != NULL) {
20977db96d56Sopenharmony_ci        /* Case 1.  First unlink ao from usable_arenas.
20987db96d56Sopenharmony_ci         */
20997db96d56Sopenharmony_ci        assert(ao->prevarena == NULL ||
21007db96d56Sopenharmony_ci               ao->prevarena->address != 0);
21017db96d56Sopenharmony_ci        assert(ao ->nextarena == NULL ||
21027db96d56Sopenharmony_ci               ao->nextarena->address != 0);
21037db96d56Sopenharmony_ci
21047db96d56Sopenharmony_ci        /* Fix the pointer in the prevarena, or the
21057db96d56Sopenharmony_ci         * usable_arenas pointer.
21067db96d56Sopenharmony_ci         */
21077db96d56Sopenharmony_ci        if (ao->prevarena == NULL) {
21087db96d56Sopenharmony_ci            usable_arenas = ao->nextarena;
21097db96d56Sopenharmony_ci            assert(usable_arenas == NULL ||
21107db96d56Sopenharmony_ci                   usable_arenas->address != 0);
21117db96d56Sopenharmony_ci        }
21127db96d56Sopenharmony_ci        else {
21137db96d56Sopenharmony_ci            assert(ao->prevarena->nextarena == ao);
21147db96d56Sopenharmony_ci            ao->prevarena->nextarena =
21157db96d56Sopenharmony_ci                ao->nextarena;
21167db96d56Sopenharmony_ci        }
21177db96d56Sopenharmony_ci        /* Fix the pointer in the nextarena. */
21187db96d56Sopenharmony_ci        if (ao->nextarena != NULL) {
21197db96d56Sopenharmony_ci            assert(ao->nextarena->prevarena == ao);
21207db96d56Sopenharmony_ci            ao->nextarena->prevarena =
21217db96d56Sopenharmony_ci                ao->prevarena;
21227db96d56Sopenharmony_ci        }
21237db96d56Sopenharmony_ci        /* Record that this arena_object slot is
21247db96d56Sopenharmony_ci         * available to be reused.
21257db96d56Sopenharmony_ci         */
21267db96d56Sopenharmony_ci        ao->nextarena = unused_arena_objects;
21277db96d56Sopenharmony_ci        unused_arena_objects = ao;
21287db96d56Sopenharmony_ci
21297db96d56Sopenharmony_ci#if WITH_PYMALLOC_RADIX_TREE
21307db96d56Sopenharmony_ci        /* mark arena region as not under control of obmalloc */
21317db96d56Sopenharmony_ci        arena_map_mark_used(ao->address, 0);
21327db96d56Sopenharmony_ci#endif
21337db96d56Sopenharmony_ci
21347db96d56Sopenharmony_ci        /* Free the entire arena. */
21357db96d56Sopenharmony_ci        _PyObject_Arena.free(_PyObject_Arena.ctx,
21367db96d56Sopenharmony_ci                             (void *)ao->address, ARENA_SIZE);
21377db96d56Sopenharmony_ci        ao->address = 0;                        /* mark unassociated */
21387db96d56Sopenharmony_ci        --narenas_currently_allocated;
21397db96d56Sopenharmony_ci
21407db96d56Sopenharmony_ci        return;
21417db96d56Sopenharmony_ci    }
21427db96d56Sopenharmony_ci
21437db96d56Sopenharmony_ci    if (nf == 1) {
21447db96d56Sopenharmony_ci        /* Case 2.  Put ao at the head of
21457db96d56Sopenharmony_ci         * usable_arenas.  Note that because
21467db96d56Sopenharmony_ci         * ao->nfreepools was 0 before, ao isn't
21477db96d56Sopenharmony_ci         * currently on the usable_arenas list.
21487db96d56Sopenharmony_ci         */
21497db96d56Sopenharmony_ci        ao->nextarena = usable_arenas;
21507db96d56Sopenharmony_ci        ao->prevarena = NULL;
21517db96d56Sopenharmony_ci        if (usable_arenas)
21527db96d56Sopenharmony_ci            usable_arenas->prevarena = ao;
21537db96d56Sopenharmony_ci        usable_arenas = ao;
21547db96d56Sopenharmony_ci        assert(usable_arenas->address != 0);
21557db96d56Sopenharmony_ci        if (nfp2lasta[1] == NULL) {
21567db96d56Sopenharmony_ci            nfp2lasta[1] = ao;
21577db96d56Sopenharmony_ci        }
21587db96d56Sopenharmony_ci
21597db96d56Sopenharmony_ci        return;
21607db96d56Sopenharmony_ci    }
21617db96d56Sopenharmony_ci
21627db96d56Sopenharmony_ci    /* If this arena is now out of order, we need to keep
21637db96d56Sopenharmony_ci     * the list sorted.  The list is kept sorted so that
21647db96d56Sopenharmony_ci     * the "most full" arenas are used first, which allows
21657db96d56Sopenharmony_ci     * the nearly empty arenas to be completely freed.  In
21667db96d56Sopenharmony_ci     * a few un-scientific tests, it seems like this
21677db96d56Sopenharmony_ci     * approach allowed a lot more memory to be freed.
21687db96d56Sopenharmony_ci     */
21697db96d56Sopenharmony_ci    /* If this is the only arena with nf, record that. */
21707db96d56Sopenharmony_ci    if (nfp2lasta[nf] == NULL) {
21717db96d56Sopenharmony_ci        nfp2lasta[nf] = ao;
21727db96d56Sopenharmony_ci    } /* else the rightmost with nf doesn't change */
21737db96d56Sopenharmony_ci    /* If this was the rightmost of the old size, it remains in place. */
21747db96d56Sopenharmony_ci    if (ao == lastnf) {
21757db96d56Sopenharmony_ci        /* Case 4.  Nothing to do. */
21767db96d56Sopenharmony_ci        return;
21777db96d56Sopenharmony_ci    }
21787db96d56Sopenharmony_ci    /* If ao were the only arena in the list, the last block would have
21797db96d56Sopenharmony_ci     * gotten us out.
21807db96d56Sopenharmony_ci     */
21817db96d56Sopenharmony_ci    assert(ao->nextarena != NULL);
21827db96d56Sopenharmony_ci
21837db96d56Sopenharmony_ci    /* Case 3:  We have to move the arena towards the end of the list,
21847db96d56Sopenharmony_ci     * because it has more free pools than the arena to its right.  It needs
21857db96d56Sopenharmony_ci     * to move to follow lastnf.
21867db96d56Sopenharmony_ci     * First unlink ao from usable_arenas.
21877db96d56Sopenharmony_ci     */
21887db96d56Sopenharmony_ci    if (ao->prevarena != NULL) {
21897db96d56Sopenharmony_ci        /* ao isn't at the head of the list */
21907db96d56Sopenharmony_ci        assert(ao->prevarena->nextarena == ao);
21917db96d56Sopenharmony_ci        ao->prevarena->nextarena = ao->nextarena;
21927db96d56Sopenharmony_ci    }
21937db96d56Sopenharmony_ci    else {
21947db96d56Sopenharmony_ci        /* ao is at the head of the list */
21957db96d56Sopenharmony_ci        assert(usable_arenas == ao);
21967db96d56Sopenharmony_ci        usable_arenas = ao->nextarena;
21977db96d56Sopenharmony_ci    }
21987db96d56Sopenharmony_ci    ao->nextarena->prevarena = ao->prevarena;
21997db96d56Sopenharmony_ci    /* And insert after lastnf. */
22007db96d56Sopenharmony_ci    ao->prevarena = lastnf;
22017db96d56Sopenharmony_ci    ao->nextarena = lastnf->nextarena;
22027db96d56Sopenharmony_ci    if (ao->nextarena != NULL) {
22037db96d56Sopenharmony_ci        ao->nextarena->prevarena = ao;
22047db96d56Sopenharmony_ci    }
22057db96d56Sopenharmony_ci    lastnf->nextarena = ao;
22067db96d56Sopenharmony_ci    /* Verify that the swaps worked. */
22077db96d56Sopenharmony_ci    assert(ao->nextarena == NULL || nf <= ao->nextarena->nfreepools);
22087db96d56Sopenharmony_ci    assert(ao->prevarena == NULL || nf > ao->prevarena->nfreepools);
22097db96d56Sopenharmony_ci    assert(ao->nextarena == NULL || ao->nextarena->prevarena == ao);
22107db96d56Sopenharmony_ci    assert((usable_arenas == ao && ao->prevarena == NULL)
22117db96d56Sopenharmony_ci           || ao->prevarena->nextarena == ao);
22127db96d56Sopenharmony_ci}
22137db96d56Sopenharmony_ci
22147db96d56Sopenharmony_ci/* Free a memory block allocated by pymalloc_alloc().
22157db96d56Sopenharmony_ci   Return 1 if it was freed.
22167db96d56Sopenharmony_ci   Return 0 if the block was not allocated by pymalloc_alloc(). */
22177db96d56Sopenharmony_cistatic inline int
22187db96d56Sopenharmony_cipymalloc_free(void *ctx, void *p)
22197db96d56Sopenharmony_ci{
22207db96d56Sopenharmony_ci    assert(p != NULL);
22217db96d56Sopenharmony_ci
22227db96d56Sopenharmony_ci#ifdef WITH_VALGRIND
22237db96d56Sopenharmony_ci    if (UNLIKELY(running_on_valgrind > 0)) {
22247db96d56Sopenharmony_ci        return 0;
22257db96d56Sopenharmony_ci    }
22267db96d56Sopenharmony_ci#endif
22277db96d56Sopenharmony_ci
22287db96d56Sopenharmony_ci    poolp pool = POOL_ADDR(p);
22297db96d56Sopenharmony_ci    if (UNLIKELY(!address_in_range(p, pool))) {
22307db96d56Sopenharmony_ci        return 0;
22317db96d56Sopenharmony_ci    }
22327db96d56Sopenharmony_ci    /* We allocated this address. */
22337db96d56Sopenharmony_ci
22347db96d56Sopenharmony_ci    /* Link p to the start of the pool's freeblock list.  Since
22357db96d56Sopenharmony_ci     * the pool had at least the p block outstanding, the pool
22367db96d56Sopenharmony_ci     * wasn't empty (so it's already in a usedpools[] list, or
22377db96d56Sopenharmony_ci     * was full and is in no list -- it's not in the freeblocks
22387db96d56Sopenharmony_ci     * list in any case).
22397db96d56Sopenharmony_ci     */
22407db96d56Sopenharmony_ci    assert(pool->ref.count > 0);            /* else it was empty */
22417db96d56Sopenharmony_ci    block *lastfree = pool->freeblock;
22427db96d56Sopenharmony_ci    *(block **)p = lastfree;
22437db96d56Sopenharmony_ci    pool->freeblock = (block *)p;
22447db96d56Sopenharmony_ci    pool->ref.count--;
22457db96d56Sopenharmony_ci
22467db96d56Sopenharmony_ci    if (UNLIKELY(lastfree == NULL)) {
22477db96d56Sopenharmony_ci        /* Pool was full, so doesn't currently live in any list:
22487db96d56Sopenharmony_ci         * link it to the front of the appropriate usedpools[] list.
22497db96d56Sopenharmony_ci         * This mimics LRU pool usage for new allocations and
22507db96d56Sopenharmony_ci         * targets optimal filling when several pools contain
22517db96d56Sopenharmony_ci         * blocks of the same size class.
22527db96d56Sopenharmony_ci         */
22537db96d56Sopenharmony_ci        insert_to_usedpool(pool);
22547db96d56Sopenharmony_ci        return 1;
22557db96d56Sopenharmony_ci    }
22567db96d56Sopenharmony_ci
22577db96d56Sopenharmony_ci    /* freeblock wasn't NULL, so the pool wasn't full,
22587db96d56Sopenharmony_ci     * and the pool is in a usedpools[] list.
22597db96d56Sopenharmony_ci     */
22607db96d56Sopenharmony_ci    if (LIKELY(pool->ref.count != 0)) {
22617db96d56Sopenharmony_ci        /* pool isn't empty:  leave it in usedpools */
22627db96d56Sopenharmony_ci        return 1;
22637db96d56Sopenharmony_ci    }
22647db96d56Sopenharmony_ci
22657db96d56Sopenharmony_ci    /* Pool is now empty:  unlink from usedpools, and
22667db96d56Sopenharmony_ci     * link to the front of freepools.  This ensures that
22677db96d56Sopenharmony_ci     * previously freed pools will be allocated later
22687db96d56Sopenharmony_ci     * (being not referenced, they are perhaps paged out).
22697db96d56Sopenharmony_ci     */
22707db96d56Sopenharmony_ci    insert_to_freepool(pool);
22717db96d56Sopenharmony_ci    return 1;
22727db96d56Sopenharmony_ci}
22737db96d56Sopenharmony_ci
22747db96d56Sopenharmony_ci
22757db96d56Sopenharmony_cistatic void
22767db96d56Sopenharmony_ci_PyObject_Free(void *ctx, void *p)
22777db96d56Sopenharmony_ci{
22787db96d56Sopenharmony_ci    /* PyObject_Free(NULL) has no effect */
22797db96d56Sopenharmony_ci    if (p == NULL) {
22807db96d56Sopenharmony_ci        return;
22817db96d56Sopenharmony_ci    }
22827db96d56Sopenharmony_ci
22837db96d56Sopenharmony_ci    if (UNLIKELY(!pymalloc_free(ctx, p))) {
22847db96d56Sopenharmony_ci        /* pymalloc didn't allocate this address */
22857db96d56Sopenharmony_ci        PyMem_RawFree(p);
22867db96d56Sopenharmony_ci        raw_allocated_blocks--;
22877db96d56Sopenharmony_ci    }
22887db96d56Sopenharmony_ci}
22897db96d56Sopenharmony_ci
22907db96d56Sopenharmony_ci
22917db96d56Sopenharmony_ci/* pymalloc realloc.
22927db96d56Sopenharmony_ci
22937db96d56Sopenharmony_ci   If nbytes==0, then as the Python docs promise, we do not treat this like
22947db96d56Sopenharmony_ci   free(p), and return a non-NULL result.
22957db96d56Sopenharmony_ci
22967db96d56Sopenharmony_ci   Return 1 if pymalloc reallocated memory and wrote the new pointer into
22977db96d56Sopenharmony_ci   newptr_p.
22987db96d56Sopenharmony_ci
22997db96d56Sopenharmony_ci   Return 0 if pymalloc didn't allocated p. */
23007db96d56Sopenharmony_cistatic int
23017db96d56Sopenharmony_cipymalloc_realloc(void *ctx, void **newptr_p, void *p, size_t nbytes)
23027db96d56Sopenharmony_ci{
23037db96d56Sopenharmony_ci    void *bp;
23047db96d56Sopenharmony_ci    poolp pool;
23057db96d56Sopenharmony_ci    size_t size;
23067db96d56Sopenharmony_ci
23077db96d56Sopenharmony_ci    assert(p != NULL);
23087db96d56Sopenharmony_ci
23097db96d56Sopenharmony_ci#ifdef WITH_VALGRIND
23107db96d56Sopenharmony_ci    /* Treat running_on_valgrind == -1 the same as 0 */
23117db96d56Sopenharmony_ci    if (UNLIKELY(running_on_valgrind > 0)) {
23127db96d56Sopenharmony_ci        return 0;
23137db96d56Sopenharmony_ci    }
23147db96d56Sopenharmony_ci#endif
23157db96d56Sopenharmony_ci
23167db96d56Sopenharmony_ci    pool = POOL_ADDR(p);
23177db96d56Sopenharmony_ci    if (!address_in_range(p, pool)) {
23187db96d56Sopenharmony_ci        /* pymalloc is not managing this block.
23197db96d56Sopenharmony_ci
23207db96d56Sopenharmony_ci           If nbytes <= SMALL_REQUEST_THRESHOLD, it's tempting to try to take
23217db96d56Sopenharmony_ci           over this block.  However, if we do, we need to copy the valid data
23227db96d56Sopenharmony_ci           from the C-managed block to one of our blocks, and there's no
23237db96d56Sopenharmony_ci           portable way to know how much of the memory space starting at p is
23247db96d56Sopenharmony_ci           valid.
23257db96d56Sopenharmony_ci
23267db96d56Sopenharmony_ci           As bug 1185883 pointed out the hard way, it's possible that the
23277db96d56Sopenharmony_ci           C-managed block is "at the end" of allocated VM space, so that a
23287db96d56Sopenharmony_ci           memory fault can occur if we try to copy nbytes bytes starting at p.
23297db96d56Sopenharmony_ci           Instead we punt: let C continue to manage this block. */
23307db96d56Sopenharmony_ci        return 0;
23317db96d56Sopenharmony_ci    }
23327db96d56Sopenharmony_ci
23337db96d56Sopenharmony_ci    /* pymalloc is in charge of this block */
23347db96d56Sopenharmony_ci    size = INDEX2SIZE(pool->szidx);
23357db96d56Sopenharmony_ci    if (nbytes <= size) {
23367db96d56Sopenharmony_ci        /* The block is staying the same or shrinking.
23377db96d56Sopenharmony_ci
23387db96d56Sopenharmony_ci           If it's shrinking, there's a tradeoff: it costs cycles to copy the
23397db96d56Sopenharmony_ci           block to a smaller size class, but it wastes memory not to copy it.
23407db96d56Sopenharmony_ci
23417db96d56Sopenharmony_ci           The compromise here is to copy on shrink only if at least 25% of
23427db96d56Sopenharmony_ci           size can be shaved off. */
23437db96d56Sopenharmony_ci        if (4 * nbytes > 3 * size) {
23447db96d56Sopenharmony_ci            /* It's the same, or shrinking and new/old > 3/4. */
23457db96d56Sopenharmony_ci            *newptr_p = p;
23467db96d56Sopenharmony_ci            return 1;
23477db96d56Sopenharmony_ci        }
23487db96d56Sopenharmony_ci        size = nbytes;
23497db96d56Sopenharmony_ci    }
23507db96d56Sopenharmony_ci
23517db96d56Sopenharmony_ci    bp = _PyObject_Malloc(ctx, nbytes);
23527db96d56Sopenharmony_ci    if (bp != NULL) {
23537db96d56Sopenharmony_ci        memcpy(bp, p, size);
23547db96d56Sopenharmony_ci        _PyObject_Free(ctx, p);
23557db96d56Sopenharmony_ci    }
23567db96d56Sopenharmony_ci    *newptr_p = bp;
23577db96d56Sopenharmony_ci    return 1;
23587db96d56Sopenharmony_ci}
23597db96d56Sopenharmony_ci
23607db96d56Sopenharmony_ci
23617db96d56Sopenharmony_cistatic void *
23627db96d56Sopenharmony_ci_PyObject_Realloc(void *ctx, void *ptr, size_t nbytes)
23637db96d56Sopenharmony_ci{
23647db96d56Sopenharmony_ci    void *ptr2;
23657db96d56Sopenharmony_ci
23667db96d56Sopenharmony_ci    if (ptr == NULL) {
23677db96d56Sopenharmony_ci        return _PyObject_Malloc(ctx, nbytes);
23687db96d56Sopenharmony_ci    }
23697db96d56Sopenharmony_ci
23707db96d56Sopenharmony_ci    if (pymalloc_realloc(ctx, &ptr2, ptr, nbytes)) {
23717db96d56Sopenharmony_ci        return ptr2;
23727db96d56Sopenharmony_ci    }
23737db96d56Sopenharmony_ci
23747db96d56Sopenharmony_ci    return PyMem_RawRealloc(ptr, nbytes);
23757db96d56Sopenharmony_ci}
23767db96d56Sopenharmony_ci
23777db96d56Sopenharmony_ci#else   /* ! WITH_PYMALLOC */
23787db96d56Sopenharmony_ci
23797db96d56Sopenharmony_ci/*==========================================================================*/
23807db96d56Sopenharmony_ci/* pymalloc not enabled:  Redirect the entry points to malloc.  These will
23817db96d56Sopenharmony_ci * only be used by extensions that are compiled with pymalloc enabled. */
23827db96d56Sopenharmony_ci
23837db96d56Sopenharmony_ciPy_ssize_t
23847db96d56Sopenharmony_ci_Py_GetAllocatedBlocks(void)
23857db96d56Sopenharmony_ci{
23867db96d56Sopenharmony_ci    return 0;
23877db96d56Sopenharmony_ci}
23887db96d56Sopenharmony_ci
23897db96d56Sopenharmony_ci#endif /* WITH_PYMALLOC */
23907db96d56Sopenharmony_ci
23917db96d56Sopenharmony_ci
23927db96d56Sopenharmony_ci/*==========================================================================*/
23937db96d56Sopenharmony_ci/* A x-platform debugging allocator.  This doesn't manage memory directly,
23947db96d56Sopenharmony_ci * it wraps a real allocator, adding extra debugging info to the memory blocks.
23957db96d56Sopenharmony_ci */
23967db96d56Sopenharmony_ci
23977db96d56Sopenharmony_ci/* Uncomment this define to add the "serialno" field */
23987db96d56Sopenharmony_ci/* #define PYMEM_DEBUG_SERIALNO */
23997db96d56Sopenharmony_ci
24007db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
24017db96d56Sopenharmony_cistatic size_t serialno = 0;     /* incremented on each debug {m,re}alloc */
24027db96d56Sopenharmony_ci
24037db96d56Sopenharmony_ci/* serialno is always incremented via calling this routine.  The point is
24047db96d56Sopenharmony_ci * to supply a single place to set a breakpoint.
24057db96d56Sopenharmony_ci */
24067db96d56Sopenharmony_cistatic void
24077db96d56Sopenharmony_cibumpserialno(void)
24087db96d56Sopenharmony_ci{
24097db96d56Sopenharmony_ci    ++serialno;
24107db96d56Sopenharmony_ci}
24117db96d56Sopenharmony_ci#endif
24127db96d56Sopenharmony_ci
24137db96d56Sopenharmony_ci#define SST SIZEOF_SIZE_T
24147db96d56Sopenharmony_ci
24157db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
24167db96d56Sopenharmony_ci#  define PYMEM_DEBUG_EXTRA_BYTES 4 * SST
24177db96d56Sopenharmony_ci#else
24187db96d56Sopenharmony_ci#  define PYMEM_DEBUG_EXTRA_BYTES 3 * SST
24197db96d56Sopenharmony_ci#endif
24207db96d56Sopenharmony_ci
24217db96d56Sopenharmony_ci/* Read sizeof(size_t) bytes at p as a big-endian size_t. */
24227db96d56Sopenharmony_cistatic size_t
24237db96d56Sopenharmony_ciread_size_t(const void *p)
24247db96d56Sopenharmony_ci{
24257db96d56Sopenharmony_ci    const uint8_t *q = (const uint8_t *)p;
24267db96d56Sopenharmony_ci    size_t result = *q++;
24277db96d56Sopenharmony_ci    int i;
24287db96d56Sopenharmony_ci
24297db96d56Sopenharmony_ci    for (i = SST; --i > 0; ++q)
24307db96d56Sopenharmony_ci        result = (result << 8) | *q;
24317db96d56Sopenharmony_ci    return result;
24327db96d56Sopenharmony_ci}
24337db96d56Sopenharmony_ci
24347db96d56Sopenharmony_ci/* Write n as a big-endian size_t, MSB at address p, LSB at
24357db96d56Sopenharmony_ci * p + sizeof(size_t) - 1.
24367db96d56Sopenharmony_ci */
24377db96d56Sopenharmony_cistatic void
24387db96d56Sopenharmony_ciwrite_size_t(void *p, size_t n)
24397db96d56Sopenharmony_ci{
24407db96d56Sopenharmony_ci    uint8_t *q = (uint8_t *)p + SST - 1;
24417db96d56Sopenharmony_ci    int i;
24427db96d56Sopenharmony_ci
24437db96d56Sopenharmony_ci    for (i = SST; --i >= 0; --q) {
24447db96d56Sopenharmony_ci        *q = (uint8_t)(n & 0xff);
24457db96d56Sopenharmony_ci        n >>= 8;
24467db96d56Sopenharmony_ci    }
24477db96d56Sopenharmony_ci}
24487db96d56Sopenharmony_ci
24497db96d56Sopenharmony_ci/* Let S = sizeof(size_t).  The debug malloc asks for 4 * S extra bytes and
24507db96d56Sopenharmony_ci   fills them with useful stuff, here calling the underlying malloc's result p:
24517db96d56Sopenharmony_ci
24527db96d56Sopenharmony_cip[0: S]
24537db96d56Sopenharmony_ci    Number of bytes originally asked for.  This is a size_t, big-endian (easier
24547db96d56Sopenharmony_ci    to read in a memory dump).
24557db96d56Sopenharmony_cip[S]
24567db96d56Sopenharmony_ci    API ID.  See PEP 445.  This is a character, but seems undocumented.
24577db96d56Sopenharmony_cip[S+1: 2*S]
24587db96d56Sopenharmony_ci    Copies of PYMEM_FORBIDDENBYTE.  Used to catch under- writes and reads.
24597db96d56Sopenharmony_cip[2*S: 2*S+n]
24607db96d56Sopenharmony_ci    The requested memory, filled with copies of PYMEM_CLEANBYTE.
24617db96d56Sopenharmony_ci    Used to catch reference to uninitialized memory.
24627db96d56Sopenharmony_ci    &p[2*S] is returned.  Note that this is 8-byte aligned if pymalloc
24637db96d56Sopenharmony_ci    handled the request itself.
24647db96d56Sopenharmony_cip[2*S+n: 2*S+n+S]
24657db96d56Sopenharmony_ci    Copies of PYMEM_FORBIDDENBYTE.  Used to catch over- writes and reads.
24667db96d56Sopenharmony_cip[2*S+n+S: 2*S+n+2*S]
24677db96d56Sopenharmony_ci    A serial number, incremented by 1 on each call to _PyMem_DebugMalloc
24687db96d56Sopenharmony_ci    and _PyMem_DebugRealloc.
24697db96d56Sopenharmony_ci    This is a big-endian size_t.
24707db96d56Sopenharmony_ci    If "bad memory" is detected later, the serial number gives an
24717db96d56Sopenharmony_ci    excellent way to set a breakpoint on the next run, to capture the
24727db96d56Sopenharmony_ci    instant at which this block was passed out.
24737db96d56Sopenharmony_ci
24747db96d56Sopenharmony_ciIf PYMEM_DEBUG_SERIALNO is not defined (default), the debug malloc only asks
24757db96d56Sopenharmony_cifor 3 * S extra bytes, and omits the last serialno field.
24767db96d56Sopenharmony_ci*/
24777db96d56Sopenharmony_ci
24787db96d56Sopenharmony_cistatic void *
24797db96d56Sopenharmony_ci_PyMem_DebugRawAlloc(int use_calloc, void *ctx, size_t nbytes)
24807db96d56Sopenharmony_ci{
24817db96d56Sopenharmony_ci    debug_alloc_api_t *api = (debug_alloc_api_t *)ctx;
24827db96d56Sopenharmony_ci    uint8_t *p;           /* base address of malloc'ed pad block */
24837db96d56Sopenharmony_ci    uint8_t *data;        /* p + 2*SST == pointer to data bytes */
24847db96d56Sopenharmony_ci    uint8_t *tail;        /* data + nbytes == pointer to tail pad bytes */
24857db96d56Sopenharmony_ci    size_t total;         /* nbytes + PYMEM_DEBUG_EXTRA_BYTES */
24867db96d56Sopenharmony_ci
24877db96d56Sopenharmony_ci    if (nbytes > (size_t)PY_SSIZE_T_MAX - PYMEM_DEBUG_EXTRA_BYTES) {
24887db96d56Sopenharmony_ci        /* integer overflow: can't represent total as a Py_ssize_t */
24897db96d56Sopenharmony_ci        return NULL;
24907db96d56Sopenharmony_ci    }
24917db96d56Sopenharmony_ci    total = nbytes + PYMEM_DEBUG_EXTRA_BYTES;
24927db96d56Sopenharmony_ci
24937db96d56Sopenharmony_ci    /* Layout: [SSSS IFFF CCCC...CCCC FFFF NNNN]
24947db96d56Sopenharmony_ci                ^--- p    ^--- data   ^--- tail
24957db96d56Sopenharmony_ci       S: nbytes stored as size_t
24967db96d56Sopenharmony_ci       I: API identifier (1 byte)
24977db96d56Sopenharmony_ci       F: Forbidden bytes (size_t - 1 bytes before, size_t bytes after)
24987db96d56Sopenharmony_ci       C: Clean bytes used later to store actual data
24997db96d56Sopenharmony_ci       N: Serial number stored as size_t
25007db96d56Sopenharmony_ci
25017db96d56Sopenharmony_ci       If PYMEM_DEBUG_SERIALNO is not defined (default), the last NNNN field
25027db96d56Sopenharmony_ci       is omitted. */
25037db96d56Sopenharmony_ci
25047db96d56Sopenharmony_ci    if (use_calloc) {
25057db96d56Sopenharmony_ci        p = (uint8_t *)api->alloc.calloc(api->alloc.ctx, 1, total);
25067db96d56Sopenharmony_ci    }
25077db96d56Sopenharmony_ci    else {
25087db96d56Sopenharmony_ci        p = (uint8_t *)api->alloc.malloc(api->alloc.ctx, total);
25097db96d56Sopenharmony_ci    }
25107db96d56Sopenharmony_ci    if (p == NULL) {
25117db96d56Sopenharmony_ci        return NULL;
25127db96d56Sopenharmony_ci    }
25137db96d56Sopenharmony_ci    data = p + 2*SST;
25147db96d56Sopenharmony_ci
25157db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
25167db96d56Sopenharmony_ci    bumpserialno();
25177db96d56Sopenharmony_ci#endif
25187db96d56Sopenharmony_ci
25197db96d56Sopenharmony_ci    /* at p, write size (SST bytes), id (1 byte), pad (SST-1 bytes) */
25207db96d56Sopenharmony_ci    write_size_t(p, nbytes);
25217db96d56Sopenharmony_ci    p[SST] = (uint8_t)api->api_id;
25227db96d56Sopenharmony_ci    memset(p + SST + 1, PYMEM_FORBIDDENBYTE, SST-1);
25237db96d56Sopenharmony_ci
25247db96d56Sopenharmony_ci    if (nbytes > 0 && !use_calloc) {
25257db96d56Sopenharmony_ci        memset(data, PYMEM_CLEANBYTE, nbytes);
25267db96d56Sopenharmony_ci    }
25277db96d56Sopenharmony_ci
25287db96d56Sopenharmony_ci    /* at tail, write pad (SST bytes) and serialno (SST bytes) */
25297db96d56Sopenharmony_ci    tail = data + nbytes;
25307db96d56Sopenharmony_ci    memset(tail, PYMEM_FORBIDDENBYTE, SST);
25317db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
25327db96d56Sopenharmony_ci    write_size_t(tail + SST, serialno);
25337db96d56Sopenharmony_ci#endif
25347db96d56Sopenharmony_ci
25357db96d56Sopenharmony_ci    return data;
25367db96d56Sopenharmony_ci}
25377db96d56Sopenharmony_ci
25387db96d56Sopenharmony_cistatic void *
25397db96d56Sopenharmony_ci_PyMem_DebugRawMalloc(void *ctx, size_t nbytes)
25407db96d56Sopenharmony_ci{
25417db96d56Sopenharmony_ci    return _PyMem_DebugRawAlloc(0, ctx, nbytes);
25427db96d56Sopenharmony_ci}
25437db96d56Sopenharmony_ci
25447db96d56Sopenharmony_cistatic void *
25457db96d56Sopenharmony_ci_PyMem_DebugRawCalloc(void *ctx, size_t nelem, size_t elsize)
25467db96d56Sopenharmony_ci{
25477db96d56Sopenharmony_ci    size_t nbytes;
25487db96d56Sopenharmony_ci    assert(elsize == 0 || nelem <= (size_t)PY_SSIZE_T_MAX / elsize);
25497db96d56Sopenharmony_ci    nbytes = nelem * elsize;
25507db96d56Sopenharmony_ci    return _PyMem_DebugRawAlloc(1, ctx, nbytes);
25517db96d56Sopenharmony_ci}
25527db96d56Sopenharmony_ci
25537db96d56Sopenharmony_ci
25547db96d56Sopenharmony_ci/* The debug free first checks the 2*SST bytes on each end for sanity (in
25557db96d56Sopenharmony_ci   particular, that the FORBIDDENBYTEs with the api ID are still intact).
25567db96d56Sopenharmony_ci   Then fills the original bytes with PYMEM_DEADBYTE.
25577db96d56Sopenharmony_ci   Then calls the underlying free.
25587db96d56Sopenharmony_ci*/
25597db96d56Sopenharmony_cistatic void
25607db96d56Sopenharmony_ci_PyMem_DebugRawFree(void *ctx, void *p)
25617db96d56Sopenharmony_ci{
25627db96d56Sopenharmony_ci    /* PyMem_Free(NULL) has no effect */
25637db96d56Sopenharmony_ci    if (p == NULL) {
25647db96d56Sopenharmony_ci        return;
25657db96d56Sopenharmony_ci    }
25667db96d56Sopenharmony_ci
25677db96d56Sopenharmony_ci    debug_alloc_api_t *api = (debug_alloc_api_t *)ctx;
25687db96d56Sopenharmony_ci    uint8_t *q = (uint8_t *)p - 2*SST;  /* address returned from malloc */
25697db96d56Sopenharmony_ci    size_t nbytes;
25707db96d56Sopenharmony_ci
25717db96d56Sopenharmony_ci    _PyMem_DebugCheckAddress(__func__, api->api_id, p);
25727db96d56Sopenharmony_ci    nbytes = read_size_t(q);
25737db96d56Sopenharmony_ci    nbytes += PYMEM_DEBUG_EXTRA_BYTES;
25747db96d56Sopenharmony_ci    memset(q, PYMEM_DEADBYTE, nbytes);
25757db96d56Sopenharmony_ci    api->alloc.free(api->alloc.ctx, q);
25767db96d56Sopenharmony_ci}
25777db96d56Sopenharmony_ci
25787db96d56Sopenharmony_ci
25797db96d56Sopenharmony_cistatic void *
25807db96d56Sopenharmony_ci_PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
25817db96d56Sopenharmony_ci{
25827db96d56Sopenharmony_ci    if (p == NULL) {
25837db96d56Sopenharmony_ci        return _PyMem_DebugRawAlloc(0, ctx, nbytes);
25847db96d56Sopenharmony_ci    }
25857db96d56Sopenharmony_ci
25867db96d56Sopenharmony_ci    debug_alloc_api_t *api = (debug_alloc_api_t *)ctx;
25877db96d56Sopenharmony_ci    uint8_t *head;        /* base address of malloc'ed pad block */
25887db96d56Sopenharmony_ci    uint8_t *data;        /* pointer to data bytes */
25897db96d56Sopenharmony_ci    uint8_t *r;
25907db96d56Sopenharmony_ci    uint8_t *tail;        /* data + nbytes == pointer to tail pad bytes */
25917db96d56Sopenharmony_ci    size_t total;         /* 2 * SST + nbytes + 2 * SST */
25927db96d56Sopenharmony_ci    size_t original_nbytes;
25937db96d56Sopenharmony_ci#define ERASED_SIZE 64
25947db96d56Sopenharmony_ci    uint8_t save[2*ERASED_SIZE];  /* A copy of erased bytes. */
25957db96d56Sopenharmony_ci
25967db96d56Sopenharmony_ci    _PyMem_DebugCheckAddress(__func__, api->api_id, p);
25977db96d56Sopenharmony_ci
25987db96d56Sopenharmony_ci    data = (uint8_t *)p;
25997db96d56Sopenharmony_ci    head = data - 2*SST;
26007db96d56Sopenharmony_ci    original_nbytes = read_size_t(head);
26017db96d56Sopenharmony_ci    if (nbytes > (size_t)PY_SSIZE_T_MAX - PYMEM_DEBUG_EXTRA_BYTES) {
26027db96d56Sopenharmony_ci        /* integer overflow: can't represent total as a Py_ssize_t */
26037db96d56Sopenharmony_ci        return NULL;
26047db96d56Sopenharmony_ci    }
26057db96d56Sopenharmony_ci    total = nbytes + PYMEM_DEBUG_EXTRA_BYTES;
26067db96d56Sopenharmony_ci
26077db96d56Sopenharmony_ci    tail = data + original_nbytes;
26087db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
26097db96d56Sopenharmony_ci    size_t block_serialno = read_size_t(tail + SST);
26107db96d56Sopenharmony_ci#endif
26117db96d56Sopenharmony_ci    /* Mark the header, the trailer, ERASED_SIZE bytes at the begin and
26127db96d56Sopenharmony_ci       ERASED_SIZE bytes at the end as dead and save the copy of erased bytes.
26137db96d56Sopenharmony_ci     */
26147db96d56Sopenharmony_ci    if (original_nbytes <= sizeof(save)) {
26157db96d56Sopenharmony_ci        memcpy(save, data, original_nbytes);
26167db96d56Sopenharmony_ci        memset(data - 2 * SST, PYMEM_DEADBYTE,
26177db96d56Sopenharmony_ci               original_nbytes + PYMEM_DEBUG_EXTRA_BYTES);
26187db96d56Sopenharmony_ci    }
26197db96d56Sopenharmony_ci    else {
26207db96d56Sopenharmony_ci        memcpy(save, data, ERASED_SIZE);
26217db96d56Sopenharmony_ci        memset(head, PYMEM_DEADBYTE, ERASED_SIZE + 2 * SST);
26227db96d56Sopenharmony_ci        memcpy(&save[ERASED_SIZE], tail - ERASED_SIZE, ERASED_SIZE);
26237db96d56Sopenharmony_ci        memset(tail - ERASED_SIZE, PYMEM_DEADBYTE,
26247db96d56Sopenharmony_ci               ERASED_SIZE + PYMEM_DEBUG_EXTRA_BYTES - 2 * SST);
26257db96d56Sopenharmony_ci    }
26267db96d56Sopenharmony_ci
26277db96d56Sopenharmony_ci    /* Resize and add decorations. */
26287db96d56Sopenharmony_ci    r = (uint8_t *)api->alloc.realloc(api->alloc.ctx, head, total);
26297db96d56Sopenharmony_ci    if (r == NULL) {
26307db96d56Sopenharmony_ci        /* if realloc() failed: rewrite header and footer which have
26317db96d56Sopenharmony_ci           just been erased */
26327db96d56Sopenharmony_ci        nbytes = original_nbytes;
26337db96d56Sopenharmony_ci    }
26347db96d56Sopenharmony_ci    else {
26357db96d56Sopenharmony_ci        head = r;
26367db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
26377db96d56Sopenharmony_ci        bumpserialno();
26387db96d56Sopenharmony_ci        block_serialno = serialno;
26397db96d56Sopenharmony_ci#endif
26407db96d56Sopenharmony_ci    }
26417db96d56Sopenharmony_ci    data = head + 2*SST;
26427db96d56Sopenharmony_ci
26437db96d56Sopenharmony_ci    write_size_t(head, nbytes);
26447db96d56Sopenharmony_ci    head[SST] = (uint8_t)api->api_id;
26457db96d56Sopenharmony_ci    memset(head + SST + 1, PYMEM_FORBIDDENBYTE, SST-1);
26467db96d56Sopenharmony_ci
26477db96d56Sopenharmony_ci    tail = data + nbytes;
26487db96d56Sopenharmony_ci    memset(tail, PYMEM_FORBIDDENBYTE, SST);
26497db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
26507db96d56Sopenharmony_ci    write_size_t(tail + SST, block_serialno);
26517db96d56Sopenharmony_ci#endif
26527db96d56Sopenharmony_ci
26537db96d56Sopenharmony_ci    /* Restore saved bytes. */
26547db96d56Sopenharmony_ci    if (original_nbytes <= sizeof(save)) {
26557db96d56Sopenharmony_ci        memcpy(data, save, Py_MIN(nbytes, original_nbytes));
26567db96d56Sopenharmony_ci    }
26577db96d56Sopenharmony_ci    else {
26587db96d56Sopenharmony_ci        size_t i = original_nbytes - ERASED_SIZE;
26597db96d56Sopenharmony_ci        memcpy(data, save, Py_MIN(nbytes, ERASED_SIZE));
26607db96d56Sopenharmony_ci        if (nbytes > i) {
26617db96d56Sopenharmony_ci            memcpy(data + i, &save[ERASED_SIZE],
26627db96d56Sopenharmony_ci                   Py_MIN(nbytes - i, ERASED_SIZE));
26637db96d56Sopenharmony_ci        }
26647db96d56Sopenharmony_ci    }
26657db96d56Sopenharmony_ci
26667db96d56Sopenharmony_ci    if (r == NULL) {
26677db96d56Sopenharmony_ci        return NULL;
26687db96d56Sopenharmony_ci    }
26697db96d56Sopenharmony_ci
26707db96d56Sopenharmony_ci    if (nbytes > original_nbytes) {
26717db96d56Sopenharmony_ci        /* growing: mark new extra memory clean */
26727db96d56Sopenharmony_ci        memset(data + original_nbytes, PYMEM_CLEANBYTE,
26737db96d56Sopenharmony_ci               nbytes - original_nbytes);
26747db96d56Sopenharmony_ci    }
26757db96d56Sopenharmony_ci
26767db96d56Sopenharmony_ci    return data;
26777db96d56Sopenharmony_ci}
26787db96d56Sopenharmony_ci
26797db96d56Sopenharmony_cistatic inline void
26807db96d56Sopenharmony_ci_PyMem_DebugCheckGIL(const char *func)
26817db96d56Sopenharmony_ci{
26827db96d56Sopenharmony_ci    if (!PyGILState_Check()) {
26837db96d56Sopenharmony_ci        _Py_FatalErrorFunc(func,
26847db96d56Sopenharmony_ci                           "Python memory allocator called "
26857db96d56Sopenharmony_ci                           "without holding the GIL");
26867db96d56Sopenharmony_ci    }
26877db96d56Sopenharmony_ci}
26887db96d56Sopenharmony_ci
26897db96d56Sopenharmony_cistatic void *
26907db96d56Sopenharmony_ci_PyMem_DebugMalloc(void *ctx, size_t nbytes)
26917db96d56Sopenharmony_ci{
26927db96d56Sopenharmony_ci    _PyMem_DebugCheckGIL(__func__);
26937db96d56Sopenharmony_ci    return _PyMem_DebugRawMalloc(ctx, nbytes);
26947db96d56Sopenharmony_ci}
26957db96d56Sopenharmony_ci
26967db96d56Sopenharmony_cistatic void *
26977db96d56Sopenharmony_ci_PyMem_DebugCalloc(void *ctx, size_t nelem, size_t elsize)
26987db96d56Sopenharmony_ci{
26997db96d56Sopenharmony_ci    _PyMem_DebugCheckGIL(__func__);
27007db96d56Sopenharmony_ci    return _PyMem_DebugRawCalloc(ctx, nelem, elsize);
27017db96d56Sopenharmony_ci}
27027db96d56Sopenharmony_ci
27037db96d56Sopenharmony_ci
27047db96d56Sopenharmony_cistatic void
27057db96d56Sopenharmony_ci_PyMem_DebugFree(void *ctx, void *ptr)
27067db96d56Sopenharmony_ci{
27077db96d56Sopenharmony_ci    _PyMem_DebugCheckGIL(__func__);
27087db96d56Sopenharmony_ci    _PyMem_DebugRawFree(ctx, ptr);
27097db96d56Sopenharmony_ci}
27107db96d56Sopenharmony_ci
27117db96d56Sopenharmony_ci
27127db96d56Sopenharmony_cistatic void *
27137db96d56Sopenharmony_ci_PyMem_DebugRealloc(void *ctx, void *ptr, size_t nbytes)
27147db96d56Sopenharmony_ci{
27157db96d56Sopenharmony_ci    _PyMem_DebugCheckGIL(__func__);
27167db96d56Sopenharmony_ci    return _PyMem_DebugRawRealloc(ctx, ptr, nbytes);
27177db96d56Sopenharmony_ci}
27187db96d56Sopenharmony_ci
27197db96d56Sopenharmony_ci/* Check the forbidden bytes on both ends of the memory allocated for p.
27207db96d56Sopenharmony_ci * If anything is wrong, print info to stderr via _PyObject_DebugDumpAddress,
27217db96d56Sopenharmony_ci * and call Py_FatalError to kill the program.
27227db96d56Sopenharmony_ci * The API id, is also checked.
27237db96d56Sopenharmony_ci */
27247db96d56Sopenharmony_cistatic void
27257db96d56Sopenharmony_ci_PyMem_DebugCheckAddress(const char *func, char api, const void *p)
27267db96d56Sopenharmony_ci{
27277db96d56Sopenharmony_ci    assert(p != NULL);
27287db96d56Sopenharmony_ci
27297db96d56Sopenharmony_ci    const uint8_t *q = (const uint8_t *)p;
27307db96d56Sopenharmony_ci    size_t nbytes;
27317db96d56Sopenharmony_ci    const uint8_t *tail;
27327db96d56Sopenharmony_ci    int i;
27337db96d56Sopenharmony_ci    char id;
27347db96d56Sopenharmony_ci
27357db96d56Sopenharmony_ci    /* Check the API id */
27367db96d56Sopenharmony_ci    id = (char)q[-SST];
27377db96d56Sopenharmony_ci    if (id != api) {
27387db96d56Sopenharmony_ci        _PyObject_DebugDumpAddress(p);
27397db96d56Sopenharmony_ci        _Py_FatalErrorFormat(func,
27407db96d56Sopenharmony_ci                             "bad ID: Allocated using API '%c', "
27417db96d56Sopenharmony_ci                             "verified using API '%c'",
27427db96d56Sopenharmony_ci                             id, api);
27437db96d56Sopenharmony_ci    }
27447db96d56Sopenharmony_ci
27457db96d56Sopenharmony_ci    /* Check the stuff at the start of p first:  if there's underwrite
27467db96d56Sopenharmony_ci     * corruption, the number-of-bytes field may be nuts, and checking
27477db96d56Sopenharmony_ci     * the tail could lead to a segfault then.
27487db96d56Sopenharmony_ci     */
27497db96d56Sopenharmony_ci    for (i = SST-1; i >= 1; --i) {
27507db96d56Sopenharmony_ci        if (*(q-i) != PYMEM_FORBIDDENBYTE) {
27517db96d56Sopenharmony_ci            _PyObject_DebugDumpAddress(p);
27527db96d56Sopenharmony_ci            _Py_FatalErrorFunc(func, "bad leading pad byte");
27537db96d56Sopenharmony_ci        }
27547db96d56Sopenharmony_ci    }
27557db96d56Sopenharmony_ci
27567db96d56Sopenharmony_ci    nbytes = read_size_t(q - 2*SST);
27577db96d56Sopenharmony_ci    tail = q + nbytes;
27587db96d56Sopenharmony_ci    for (i = 0; i < SST; ++i) {
27597db96d56Sopenharmony_ci        if (tail[i] != PYMEM_FORBIDDENBYTE) {
27607db96d56Sopenharmony_ci            _PyObject_DebugDumpAddress(p);
27617db96d56Sopenharmony_ci            _Py_FatalErrorFunc(func, "bad trailing pad byte");
27627db96d56Sopenharmony_ci        }
27637db96d56Sopenharmony_ci    }
27647db96d56Sopenharmony_ci}
27657db96d56Sopenharmony_ci
27667db96d56Sopenharmony_ci/* Display info to stderr about the memory block at p. */
27677db96d56Sopenharmony_cistatic void
27687db96d56Sopenharmony_ci_PyObject_DebugDumpAddress(const void *p)
27697db96d56Sopenharmony_ci{
27707db96d56Sopenharmony_ci    const uint8_t *q = (const uint8_t *)p;
27717db96d56Sopenharmony_ci    const uint8_t *tail;
27727db96d56Sopenharmony_ci    size_t nbytes;
27737db96d56Sopenharmony_ci    int i;
27747db96d56Sopenharmony_ci    int ok;
27757db96d56Sopenharmony_ci    char id;
27767db96d56Sopenharmony_ci
27777db96d56Sopenharmony_ci    fprintf(stderr, "Debug memory block at address p=%p:", p);
27787db96d56Sopenharmony_ci    if (p == NULL) {
27797db96d56Sopenharmony_ci        fprintf(stderr, "\n");
27807db96d56Sopenharmony_ci        return;
27817db96d56Sopenharmony_ci    }
27827db96d56Sopenharmony_ci    id = (char)q[-SST];
27837db96d56Sopenharmony_ci    fprintf(stderr, " API '%c'\n", id);
27847db96d56Sopenharmony_ci
27857db96d56Sopenharmony_ci    nbytes = read_size_t(q - 2*SST);
27867db96d56Sopenharmony_ci    fprintf(stderr, "    %zu bytes originally requested\n", nbytes);
27877db96d56Sopenharmony_ci
27887db96d56Sopenharmony_ci    /* In case this is nuts, check the leading pad bytes first. */
27897db96d56Sopenharmony_ci    fprintf(stderr, "    The %d pad bytes at p-%d are ", SST-1, SST-1);
27907db96d56Sopenharmony_ci    ok = 1;
27917db96d56Sopenharmony_ci    for (i = 1; i <= SST-1; ++i) {
27927db96d56Sopenharmony_ci        if (*(q-i) != PYMEM_FORBIDDENBYTE) {
27937db96d56Sopenharmony_ci            ok = 0;
27947db96d56Sopenharmony_ci            break;
27957db96d56Sopenharmony_ci        }
27967db96d56Sopenharmony_ci    }
27977db96d56Sopenharmony_ci    if (ok)
27987db96d56Sopenharmony_ci        fputs("FORBIDDENBYTE, as expected.\n", stderr);
27997db96d56Sopenharmony_ci    else {
28007db96d56Sopenharmony_ci        fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n",
28017db96d56Sopenharmony_ci            PYMEM_FORBIDDENBYTE);
28027db96d56Sopenharmony_ci        for (i = SST-1; i >= 1; --i) {
28037db96d56Sopenharmony_ci            const uint8_t byte = *(q-i);
28047db96d56Sopenharmony_ci            fprintf(stderr, "        at p-%d: 0x%02x", i, byte);
28057db96d56Sopenharmony_ci            if (byte != PYMEM_FORBIDDENBYTE)
28067db96d56Sopenharmony_ci                fputs(" *** OUCH", stderr);
28077db96d56Sopenharmony_ci            fputc('\n', stderr);
28087db96d56Sopenharmony_ci        }
28097db96d56Sopenharmony_ci
28107db96d56Sopenharmony_ci        fputs("    Because memory is corrupted at the start, the "
28117db96d56Sopenharmony_ci              "count of bytes requested\n"
28127db96d56Sopenharmony_ci              "       may be bogus, and checking the trailing pad "
28137db96d56Sopenharmony_ci              "bytes may segfault.\n", stderr);
28147db96d56Sopenharmony_ci    }
28157db96d56Sopenharmony_ci
28167db96d56Sopenharmony_ci    tail = q + nbytes;
28177db96d56Sopenharmony_ci    fprintf(stderr, "    The %d pad bytes at tail=%p are ", SST, (void *)tail);
28187db96d56Sopenharmony_ci    ok = 1;
28197db96d56Sopenharmony_ci    for (i = 0; i < SST; ++i) {
28207db96d56Sopenharmony_ci        if (tail[i] != PYMEM_FORBIDDENBYTE) {
28217db96d56Sopenharmony_ci            ok = 0;
28227db96d56Sopenharmony_ci            break;
28237db96d56Sopenharmony_ci        }
28247db96d56Sopenharmony_ci    }
28257db96d56Sopenharmony_ci    if (ok)
28267db96d56Sopenharmony_ci        fputs("FORBIDDENBYTE, as expected.\n", stderr);
28277db96d56Sopenharmony_ci    else {
28287db96d56Sopenharmony_ci        fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n",
28297db96d56Sopenharmony_ci                PYMEM_FORBIDDENBYTE);
28307db96d56Sopenharmony_ci        for (i = 0; i < SST; ++i) {
28317db96d56Sopenharmony_ci            const uint8_t byte = tail[i];
28327db96d56Sopenharmony_ci            fprintf(stderr, "        at tail+%d: 0x%02x",
28337db96d56Sopenharmony_ci                    i, byte);
28347db96d56Sopenharmony_ci            if (byte != PYMEM_FORBIDDENBYTE)
28357db96d56Sopenharmony_ci                fputs(" *** OUCH", stderr);
28367db96d56Sopenharmony_ci            fputc('\n', stderr);
28377db96d56Sopenharmony_ci        }
28387db96d56Sopenharmony_ci    }
28397db96d56Sopenharmony_ci
28407db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
28417db96d56Sopenharmony_ci    size_t serial = read_size_t(tail + SST);
28427db96d56Sopenharmony_ci    fprintf(stderr,
28437db96d56Sopenharmony_ci            "    The block was made by call #%zu to debug malloc/realloc.\n",
28447db96d56Sopenharmony_ci            serial);
28457db96d56Sopenharmony_ci#endif
28467db96d56Sopenharmony_ci
28477db96d56Sopenharmony_ci    if (nbytes > 0) {
28487db96d56Sopenharmony_ci        i = 0;
28497db96d56Sopenharmony_ci        fputs("    Data at p:", stderr);
28507db96d56Sopenharmony_ci        /* print up to 8 bytes at the start */
28517db96d56Sopenharmony_ci        while (q < tail && i < 8) {
28527db96d56Sopenharmony_ci            fprintf(stderr, " %02x", *q);
28537db96d56Sopenharmony_ci            ++i;
28547db96d56Sopenharmony_ci            ++q;
28557db96d56Sopenharmony_ci        }
28567db96d56Sopenharmony_ci        /* and up to 8 at the end */
28577db96d56Sopenharmony_ci        if (q < tail) {
28587db96d56Sopenharmony_ci            if (tail - q > 8) {
28597db96d56Sopenharmony_ci                fputs(" ...", stderr);
28607db96d56Sopenharmony_ci                q = tail - 8;
28617db96d56Sopenharmony_ci            }
28627db96d56Sopenharmony_ci            while (q < tail) {
28637db96d56Sopenharmony_ci                fprintf(stderr, " %02x", *q);
28647db96d56Sopenharmony_ci                ++q;
28657db96d56Sopenharmony_ci            }
28667db96d56Sopenharmony_ci        }
28677db96d56Sopenharmony_ci        fputc('\n', stderr);
28687db96d56Sopenharmony_ci    }
28697db96d56Sopenharmony_ci    fputc('\n', stderr);
28707db96d56Sopenharmony_ci
28717db96d56Sopenharmony_ci    fflush(stderr);
28727db96d56Sopenharmony_ci    _PyMem_DumpTraceback(fileno(stderr), p);
28737db96d56Sopenharmony_ci}
28747db96d56Sopenharmony_ci
28757db96d56Sopenharmony_ci
28767db96d56Sopenharmony_cistatic size_t
28777db96d56Sopenharmony_ciprintone(FILE *out, const char* msg, size_t value)
28787db96d56Sopenharmony_ci{
28797db96d56Sopenharmony_ci    int i, k;
28807db96d56Sopenharmony_ci    char buf[100];
28817db96d56Sopenharmony_ci    size_t origvalue = value;
28827db96d56Sopenharmony_ci
28837db96d56Sopenharmony_ci    fputs(msg, out);
28847db96d56Sopenharmony_ci    for (i = (int)strlen(msg); i < 35; ++i)
28857db96d56Sopenharmony_ci        fputc(' ', out);
28867db96d56Sopenharmony_ci    fputc('=', out);
28877db96d56Sopenharmony_ci
28887db96d56Sopenharmony_ci    /* Write the value with commas. */
28897db96d56Sopenharmony_ci    i = 22;
28907db96d56Sopenharmony_ci    buf[i--] = '\0';
28917db96d56Sopenharmony_ci    buf[i--] = '\n';
28927db96d56Sopenharmony_ci    k = 3;
28937db96d56Sopenharmony_ci    do {
28947db96d56Sopenharmony_ci        size_t nextvalue = value / 10;
28957db96d56Sopenharmony_ci        unsigned int digit = (unsigned int)(value - nextvalue * 10);
28967db96d56Sopenharmony_ci        value = nextvalue;
28977db96d56Sopenharmony_ci        buf[i--] = (char)(digit + '0');
28987db96d56Sopenharmony_ci        --k;
28997db96d56Sopenharmony_ci        if (k == 0 && value && i >= 0) {
29007db96d56Sopenharmony_ci            k = 3;
29017db96d56Sopenharmony_ci            buf[i--] = ',';
29027db96d56Sopenharmony_ci        }
29037db96d56Sopenharmony_ci    } while (value && i >= 0);
29047db96d56Sopenharmony_ci
29057db96d56Sopenharmony_ci    while (i >= 0)
29067db96d56Sopenharmony_ci        buf[i--] = ' ';
29077db96d56Sopenharmony_ci    fputs(buf, out);
29087db96d56Sopenharmony_ci
29097db96d56Sopenharmony_ci    return origvalue;
29107db96d56Sopenharmony_ci}
29117db96d56Sopenharmony_ci
29127db96d56Sopenharmony_civoid
29137db96d56Sopenharmony_ci_PyDebugAllocatorStats(FILE *out,
29147db96d56Sopenharmony_ci                       const char *block_name, int num_blocks, size_t sizeof_block)
29157db96d56Sopenharmony_ci{
29167db96d56Sopenharmony_ci    char buf1[128];
29177db96d56Sopenharmony_ci    char buf2[128];
29187db96d56Sopenharmony_ci    PyOS_snprintf(buf1, sizeof(buf1),
29197db96d56Sopenharmony_ci                  "%d %ss * %zd bytes each",
29207db96d56Sopenharmony_ci                  num_blocks, block_name, sizeof_block);
29217db96d56Sopenharmony_ci    PyOS_snprintf(buf2, sizeof(buf2),
29227db96d56Sopenharmony_ci                  "%48s ", buf1);
29237db96d56Sopenharmony_ci    (void)printone(out, buf2, num_blocks * sizeof_block);
29247db96d56Sopenharmony_ci}
29257db96d56Sopenharmony_ci
29267db96d56Sopenharmony_ci
29277db96d56Sopenharmony_ci#ifdef WITH_PYMALLOC
29287db96d56Sopenharmony_ci
29297db96d56Sopenharmony_ci#ifdef Py_DEBUG
29307db96d56Sopenharmony_ci/* Is target in the list?  The list is traversed via the nextpool pointers.
29317db96d56Sopenharmony_ci * The list may be NULL-terminated, or circular.  Return 1 if target is in
29327db96d56Sopenharmony_ci * list, else 0.
29337db96d56Sopenharmony_ci */
29347db96d56Sopenharmony_cistatic int
29357db96d56Sopenharmony_cipool_is_in_list(const poolp target, poolp list)
29367db96d56Sopenharmony_ci{
29377db96d56Sopenharmony_ci    poolp origlist = list;
29387db96d56Sopenharmony_ci    assert(target != NULL);
29397db96d56Sopenharmony_ci    if (list == NULL)
29407db96d56Sopenharmony_ci        return 0;
29417db96d56Sopenharmony_ci    do {
29427db96d56Sopenharmony_ci        if (target == list)
29437db96d56Sopenharmony_ci            return 1;
29447db96d56Sopenharmony_ci        list = list->nextpool;
29457db96d56Sopenharmony_ci    } while (list != NULL && list != origlist);
29467db96d56Sopenharmony_ci    return 0;
29477db96d56Sopenharmony_ci}
29487db96d56Sopenharmony_ci#endif
29497db96d56Sopenharmony_ci
29507db96d56Sopenharmony_ci/* Print summary info to "out" about the state of pymalloc's structures.
29517db96d56Sopenharmony_ci * In Py_DEBUG mode, also perform some expensive internal consistency
29527db96d56Sopenharmony_ci * checks.
29537db96d56Sopenharmony_ci *
29547db96d56Sopenharmony_ci * Return 0 if the memory debug hooks are not installed or no statistics was
29557db96d56Sopenharmony_ci * written into out, return 1 otherwise.
29567db96d56Sopenharmony_ci */
29577db96d56Sopenharmony_ciint
29587db96d56Sopenharmony_ci_PyObject_DebugMallocStats(FILE *out)
29597db96d56Sopenharmony_ci{
29607db96d56Sopenharmony_ci    if (!_PyMem_PymallocEnabled()) {
29617db96d56Sopenharmony_ci        return 0;
29627db96d56Sopenharmony_ci    }
29637db96d56Sopenharmony_ci
29647db96d56Sopenharmony_ci    uint i;
29657db96d56Sopenharmony_ci    const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
29667db96d56Sopenharmony_ci    /* # of pools, allocated blocks, and free blocks per class index */
29677db96d56Sopenharmony_ci    size_t numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
29687db96d56Sopenharmony_ci    size_t numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
29697db96d56Sopenharmony_ci    size_t numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
29707db96d56Sopenharmony_ci    /* total # of allocated bytes in used and full pools */
29717db96d56Sopenharmony_ci    size_t allocated_bytes = 0;
29727db96d56Sopenharmony_ci    /* total # of available bytes in used pools */
29737db96d56Sopenharmony_ci    size_t available_bytes = 0;
29747db96d56Sopenharmony_ci    /* # of free pools + pools not yet carved out of current arena */
29757db96d56Sopenharmony_ci    uint numfreepools = 0;
29767db96d56Sopenharmony_ci    /* # of bytes for arena alignment padding */
29777db96d56Sopenharmony_ci    size_t arena_alignment = 0;
29787db96d56Sopenharmony_ci    /* # of bytes in used and full pools used for pool_headers */
29797db96d56Sopenharmony_ci    size_t pool_header_bytes = 0;
29807db96d56Sopenharmony_ci    /* # of bytes in used and full pools wasted due to quantization,
29817db96d56Sopenharmony_ci     * i.e. the necessarily leftover space at the ends of used and
29827db96d56Sopenharmony_ci     * full pools.
29837db96d56Sopenharmony_ci     */
29847db96d56Sopenharmony_ci    size_t quantization = 0;
29857db96d56Sopenharmony_ci    /* # of arenas actually allocated. */
29867db96d56Sopenharmony_ci    size_t narenas = 0;
29877db96d56Sopenharmony_ci    /* running total -- should equal narenas * ARENA_SIZE */
29887db96d56Sopenharmony_ci    size_t total;
29897db96d56Sopenharmony_ci    char buf[128];
29907db96d56Sopenharmony_ci
29917db96d56Sopenharmony_ci    fprintf(out, "Small block threshold = %d, in %u size classes.\n",
29927db96d56Sopenharmony_ci            SMALL_REQUEST_THRESHOLD, numclasses);
29937db96d56Sopenharmony_ci
29947db96d56Sopenharmony_ci    for (i = 0; i < numclasses; ++i)
29957db96d56Sopenharmony_ci        numpools[i] = numblocks[i] = numfreeblocks[i] = 0;
29967db96d56Sopenharmony_ci
29977db96d56Sopenharmony_ci    /* Because full pools aren't linked to from anything, it's easiest
29987db96d56Sopenharmony_ci     * to march over all the arenas.  If we're lucky, most of the memory
29997db96d56Sopenharmony_ci     * will be living in full pools -- would be a shame to miss them.
30007db96d56Sopenharmony_ci     */
30017db96d56Sopenharmony_ci    for (i = 0; i < maxarenas; ++i) {
30027db96d56Sopenharmony_ci        uintptr_t base = arenas[i].address;
30037db96d56Sopenharmony_ci
30047db96d56Sopenharmony_ci        /* Skip arenas which are not allocated. */
30057db96d56Sopenharmony_ci        if (arenas[i].address == (uintptr_t)NULL)
30067db96d56Sopenharmony_ci            continue;
30077db96d56Sopenharmony_ci        narenas += 1;
30087db96d56Sopenharmony_ci
30097db96d56Sopenharmony_ci        numfreepools += arenas[i].nfreepools;
30107db96d56Sopenharmony_ci
30117db96d56Sopenharmony_ci        /* round up to pool alignment */
30127db96d56Sopenharmony_ci        if (base & (uintptr_t)POOL_SIZE_MASK) {
30137db96d56Sopenharmony_ci            arena_alignment += POOL_SIZE;
30147db96d56Sopenharmony_ci            base &= ~(uintptr_t)POOL_SIZE_MASK;
30157db96d56Sopenharmony_ci            base += POOL_SIZE;
30167db96d56Sopenharmony_ci        }
30177db96d56Sopenharmony_ci
30187db96d56Sopenharmony_ci        /* visit every pool in the arena */
30197db96d56Sopenharmony_ci        assert(base <= (uintptr_t) arenas[i].pool_address);
30207db96d56Sopenharmony_ci        for (; base < (uintptr_t) arenas[i].pool_address; base += POOL_SIZE) {
30217db96d56Sopenharmony_ci            poolp p = (poolp)base;
30227db96d56Sopenharmony_ci            const uint sz = p->szidx;
30237db96d56Sopenharmony_ci            uint freeblocks;
30247db96d56Sopenharmony_ci
30257db96d56Sopenharmony_ci            if (p->ref.count == 0) {
30267db96d56Sopenharmony_ci                /* currently unused */
30277db96d56Sopenharmony_ci#ifdef Py_DEBUG
30287db96d56Sopenharmony_ci                assert(pool_is_in_list(p, arenas[i].freepools));
30297db96d56Sopenharmony_ci#endif
30307db96d56Sopenharmony_ci                continue;
30317db96d56Sopenharmony_ci            }
30327db96d56Sopenharmony_ci            ++numpools[sz];
30337db96d56Sopenharmony_ci            numblocks[sz] += p->ref.count;
30347db96d56Sopenharmony_ci            freeblocks = NUMBLOCKS(sz) - p->ref.count;
30357db96d56Sopenharmony_ci            numfreeblocks[sz] += freeblocks;
30367db96d56Sopenharmony_ci#ifdef Py_DEBUG
30377db96d56Sopenharmony_ci            if (freeblocks > 0)
30387db96d56Sopenharmony_ci                assert(pool_is_in_list(p, usedpools[sz + sz]));
30397db96d56Sopenharmony_ci#endif
30407db96d56Sopenharmony_ci        }
30417db96d56Sopenharmony_ci    }
30427db96d56Sopenharmony_ci    assert(narenas == narenas_currently_allocated);
30437db96d56Sopenharmony_ci
30447db96d56Sopenharmony_ci    fputc('\n', out);
30457db96d56Sopenharmony_ci    fputs("class   size   num pools   blocks in use  avail blocks\n"
30467db96d56Sopenharmony_ci          "-----   ----   ---------   -------------  ------------\n",
30477db96d56Sopenharmony_ci          out);
30487db96d56Sopenharmony_ci
30497db96d56Sopenharmony_ci    for (i = 0; i < numclasses; ++i) {
30507db96d56Sopenharmony_ci        size_t p = numpools[i];
30517db96d56Sopenharmony_ci        size_t b = numblocks[i];
30527db96d56Sopenharmony_ci        size_t f = numfreeblocks[i];
30537db96d56Sopenharmony_ci        uint size = INDEX2SIZE(i);
30547db96d56Sopenharmony_ci        if (p == 0) {
30557db96d56Sopenharmony_ci            assert(b == 0 && f == 0);
30567db96d56Sopenharmony_ci            continue;
30577db96d56Sopenharmony_ci        }
30587db96d56Sopenharmony_ci        fprintf(out, "%5u %6u %11zu %15zu %13zu\n",
30597db96d56Sopenharmony_ci                i, size, p, b, f);
30607db96d56Sopenharmony_ci        allocated_bytes += b * size;
30617db96d56Sopenharmony_ci        available_bytes += f * size;
30627db96d56Sopenharmony_ci        pool_header_bytes += p * POOL_OVERHEAD;
30637db96d56Sopenharmony_ci        quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size);
30647db96d56Sopenharmony_ci    }
30657db96d56Sopenharmony_ci    fputc('\n', out);
30667db96d56Sopenharmony_ci#ifdef PYMEM_DEBUG_SERIALNO
30677db96d56Sopenharmony_ci    if (_PyMem_DebugEnabled()) {
30687db96d56Sopenharmony_ci        (void)printone(out, "# times object malloc called", serialno);
30697db96d56Sopenharmony_ci    }
30707db96d56Sopenharmony_ci#endif
30717db96d56Sopenharmony_ci    (void)printone(out, "# arenas allocated total", ntimes_arena_allocated);
30727db96d56Sopenharmony_ci    (void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas);
30737db96d56Sopenharmony_ci    (void)printone(out, "# arenas highwater mark", narenas_highwater);
30747db96d56Sopenharmony_ci    (void)printone(out, "# arenas allocated current", narenas);
30757db96d56Sopenharmony_ci
30767db96d56Sopenharmony_ci    PyOS_snprintf(buf, sizeof(buf),
30777db96d56Sopenharmony_ci                  "%zu arenas * %d bytes/arena",
30787db96d56Sopenharmony_ci                  narenas, ARENA_SIZE);
30797db96d56Sopenharmony_ci    (void)printone(out, buf, narenas * ARENA_SIZE);
30807db96d56Sopenharmony_ci
30817db96d56Sopenharmony_ci    fputc('\n', out);
30827db96d56Sopenharmony_ci
30837db96d56Sopenharmony_ci    /* Account for what all of those arena bytes are being used for. */
30847db96d56Sopenharmony_ci    total = printone(out, "# bytes in allocated blocks", allocated_bytes);
30857db96d56Sopenharmony_ci    total += printone(out, "# bytes in available blocks", available_bytes);
30867db96d56Sopenharmony_ci
30877db96d56Sopenharmony_ci    PyOS_snprintf(buf, sizeof(buf),
30887db96d56Sopenharmony_ci        "%u unused pools * %d bytes", numfreepools, POOL_SIZE);
30897db96d56Sopenharmony_ci    total += printone(out, buf, (size_t)numfreepools * POOL_SIZE);
30907db96d56Sopenharmony_ci
30917db96d56Sopenharmony_ci    total += printone(out, "# bytes lost to pool headers", pool_header_bytes);
30927db96d56Sopenharmony_ci    total += printone(out, "# bytes lost to quantization", quantization);
30937db96d56Sopenharmony_ci    total += printone(out, "# bytes lost to arena alignment", arena_alignment);
30947db96d56Sopenharmony_ci    (void)printone(out, "Total", total);
30957db96d56Sopenharmony_ci    assert(narenas * ARENA_SIZE == total);
30967db96d56Sopenharmony_ci
30977db96d56Sopenharmony_ci#if WITH_PYMALLOC_RADIX_TREE
30987db96d56Sopenharmony_ci    fputs("\narena map counts\n", out);
30997db96d56Sopenharmony_ci#ifdef USE_INTERIOR_NODES
31007db96d56Sopenharmony_ci    (void)printone(out, "# arena map mid nodes", arena_map_mid_count);
31017db96d56Sopenharmony_ci    (void)printone(out, "# arena map bot nodes", arena_map_bot_count);
31027db96d56Sopenharmony_ci    fputc('\n', out);
31037db96d56Sopenharmony_ci#endif
31047db96d56Sopenharmony_ci    total = printone(out, "# bytes lost to arena map root", sizeof(arena_map_root));
31057db96d56Sopenharmony_ci#ifdef USE_INTERIOR_NODES
31067db96d56Sopenharmony_ci    total += printone(out, "# bytes lost to arena map mid",
31077db96d56Sopenharmony_ci                      sizeof(arena_map_mid_t) * arena_map_mid_count);
31087db96d56Sopenharmony_ci    total += printone(out, "# bytes lost to arena map bot",
31097db96d56Sopenharmony_ci                      sizeof(arena_map_bot_t) * arena_map_bot_count);
31107db96d56Sopenharmony_ci    (void)printone(out, "Total", total);
31117db96d56Sopenharmony_ci#endif
31127db96d56Sopenharmony_ci#endif
31137db96d56Sopenharmony_ci
31147db96d56Sopenharmony_ci    return 1;
31157db96d56Sopenharmony_ci}
31167db96d56Sopenharmony_ci
31177db96d56Sopenharmony_ci#endif /* #ifdef WITH_PYMALLOC */
3118