#pragma once
#ifndef MIMALLOC_TYPES_H
#define MIMALLOC_TYPES_H
#include <mimalloc-stats.h>
#include <stddef.h>
#include <stdint.h>
#include "atomic.h"
#ifdef _MSC_VER
#pragma warning(disable:4214)
#endif
#ifndef MI_MAX_ALIGN_SIZE
#define MI_MAX_ALIGN_SIZE 16
#endif
#if !defined(MI_SECURE)
#define MI_SECURE 0
#endif
#if !defined(MI_DEBUG)
#if defined(MI_BUILD_RELEASE) || defined(NDEBUG)
#define MI_DEBUG 0
#else
#define MI_DEBUG 2
#endif
#endif
#if defined(MI_GUARDED)
#define MI_PADDING 0
#endif
#if !defined(MI_PADDING) && (MI_SECURE>=3 || MI_DEBUG>=1 || (MI_TRACK_VALGRIND || MI_TRACK_ASAN || MI_TRACK_ETW))
#define MI_PADDING 1
#endif
#if !defined(MI_PADDING_CHECK) && MI_PADDING && (MI_SECURE>=3 || MI_DEBUG>=1)
#define MI_PADDING_CHECK 1
#endif
#if (MI_SECURE>=3 || MI_DEBUG>=1)
#define MI_ENCODE_FREELIST 1
#endif
#if INTPTR_MAX > INT64_MAX
# define MI_INTPTR_SHIFT (4)
#elif INTPTR_MAX == INT64_MAX
# define MI_INTPTR_SHIFT (3)
#elif INTPTR_MAX == INT32_MAX
# define MI_INTPTR_SHIFT (2)
#else
#error platform pointers must be 32, 64, or 128 bits
#endif
#if SIZE_MAX == UINT64_MAX
# define MI_SIZE_SHIFT (3)
typedef int64_t mi_ssize_t;
#elif SIZE_MAX == UINT32_MAX
# define MI_SIZE_SHIFT (2)
typedef int32_t mi_ssize_t;
#else
#error platform objects must be 32 or 64 bits
#endif
#if (SIZE_MAX/2) > LONG_MAX
# define MI_ZU(x) x##ULL
# define MI_ZI(x) x##LL
#else
# define MI_ZU(x) x##UL
# define MI_ZI(x) x##L
#endif
#define MI_INTPTR_SIZE (1<<MI_INTPTR_SHIFT)
#define MI_INTPTR_BITS (MI_INTPTR_SIZE*8)
#define MI_SIZE_SIZE (1<<MI_SIZE_SHIFT)
#define MI_SIZE_BITS (MI_SIZE_SIZE*8)
#define MI_KiB (MI_ZU(1024))
#define MI_MiB (MI_KiB*MI_KiB)
#define MI_GiB (MI_MiB*MI_KiB)
#ifndef MI_SEGMENT_SLICE_SHIFT
#define MI_SEGMENT_SLICE_SHIFT (13 + MI_INTPTR_SHIFT)
#endif
#ifndef MI_SEGMENT_SHIFT
#if MI_INTPTR_SIZE > 4
#define MI_SEGMENT_SHIFT ( 9 + MI_SEGMENT_SLICE_SHIFT)
#else
#define MI_SEGMENT_SHIFT ( 7 + MI_SEGMENT_SLICE_SHIFT)
#endif
#endif
#ifndef MI_SMALL_PAGE_SHIFT
#define MI_SMALL_PAGE_SHIFT (MI_SEGMENT_SLICE_SHIFT)
#endif
#ifndef MI_MEDIUM_PAGE_SHIFT
#define MI_MEDIUM_PAGE_SHIFT ( 3 + MI_SMALL_PAGE_SHIFT)
#endif
#define MI_SEGMENT_SIZE (MI_ZU(1)<<MI_SEGMENT_SHIFT)
#define MI_SEGMENT_ALIGN MI_SEGMENT_SIZE
#define MI_SEGMENT_MASK ((uintptr_t)(MI_SEGMENT_ALIGN - 1))
#define MI_SEGMENT_SLICE_SIZE (MI_ZU(1)<< MI_SEGMENT_SLICE_SHIFT)
#define MI_SLICES_PER_SEGMENT (MI_SEGMENT_SIZE / MI_SEGMENT_SLICE_SIZE)
#define MI_SMALL_PAGE_SIZE (MI_ZU(1)<<MI_SMALL_PAGE_SHIFT)
#define MI_MEDIUM_PAGE_SIZE (MI_ZU(1)<<MI_MEDIUM_PAGE_SHIFT)
#define MI_SMALL_OBJ_SIZE_MAX (MI_SMALL_PAGE_SIZE/8)
#define MI_MEDIUM_OBJ_SIZE_MAX (MI_MEDIUM_PAGE_SIZE/8)
#define MI_MEDIUM_OBJ_WSIZE_MAX (MI_MEDIUM_OBJ_SIZE_MAX/MI_INTPTR_SIZE)
#define MI_LARGE_OBJ_SIZE_MAX (MI_SEGMENT_SIZE/2)
#define MI_LARGE_OBJ_WSIZE_MAX (MI_LARGE_OBJ_SIZE_MAX/MI_INTPTR_SIZE)
#if MI_BIN_HUGE != 73U
#error "mimalloc internal: expecting 73 bins"
#endif
#if (MI_MEDIUM_OBJ_WSIZE_MAX >= 655360)
#error "mimalloc internal: define more bins"
#endif
#define MI_MAX_ALIGN_GUARANTEE (MI_MEDIUM_OBJ_SIZE_MAX)
#define MI_BLOCK_ALIGNMENT_MAX (MI_SEGMENT_SIZE >> 1)
#define MI_MAX_SLICE_OFFSET_COUNT ((MI_BLOCK_ALIGNMENT_MAX / MI_SEGMENT_SLICE_SIZE) - 1)
#if (PTRDIFF_MAX > INT32_MAX) && (PTRDIFF_MAX >= (MI_SEGMENT_SLIZE_SIZE * UINT32_MAX))
#define MI_MAX_ALLOC_SIZE (MI_SEGMENT_SLICE_SIZE * (UINT32_MAX-1))
#else
#define MI_MAX_ALLOC_SIZE PTRDIFF_MAX
#endif
typedef uintptr_t mi_encoded_t;
typedef size_t mi_threadid_t;
typedef struct mi_block_s {
mi_encoded_t next;
} mi_block_t;
#if MI_GUARDED
#define MI_BLOCK_TAG_ALIGNED ((mi_encoded_t)(0))
#define MI_BLOCK_TAG_GUARDED (~MI_BLOCK_TAG_ALIGNED)
#endif
typedef enum mi_delayed_e {
MI_USE_DELAYED_FREE = 0, MI_DELAYED_FREEING = 1, MI_NO_DELAYED_FREE = 2, MI_NEVER_DELAYED_FREE = 3 } mi_delayed_t;
#if !MI_TSAN
typedef union mi_page_flags_s {
uint8_t full_aligned;
struct {
uint8_t in_full : 1;
uint8_t has_aligned : 1;
} x;
} mi_page_flags_t;
#else
typedef union mi_page_flags_s {
uint32_t full_aligned;
struct {
uint8_t in_full;
uint8_t has_aligned;
} x;
} mi_page_flags_t;
#endif
typedef uintptr_t mi_thread_free_t;
typedef struct mi_page_s {
uint32_t slice_count; uint32_t slice_offset; uint8_t is_committed:1; uint8_t is_zero_init:1; uint8_t is_huge:1; uint16_t capacity; uint16_t reserved; mi_page_flags_t flags; uint8_t free_is_zero:1; uint8_t retire_expire:7;
mi_block_t* free; mi_block_t* local_free; uint16_t used; uint8_t block_size_shift; uint8_t heap_tag; size_t block_size; uint8_t* page_start;
#if (MI_ENCODE_FREELIST || MI_PADDING)
uintptr_t keys[2]; #endif
_Atomic(mi_thread_free_t) xthread_free; _Atomic(uintptr_t) xheap;
struct mi_page_s* next; struct mi_page_s* prev;
void* padding[1];
} mi_page_t;
typedef enum mi_page_kind_e {
MI_PAGE_SMALL, MI_PAGE_MEDIUM, MI_PAGE_LARGE, MI_PAGE_HUGE } mi_page_kind_t;
typedef enum mi_segment_kind_e {
MI_SEGMENT_NORMAL, MI_SEGMENT_HUGE, } mi_segment_kind_t;
#define MI_MINIMAL_COMMIT_SIZE (1*MI_SEGMENT_SLICE_SIZE)
#define MI_COMMIT_SIZE (MI_SEGMENT_SLICE_SIZE)
#define MI_COMMIT_MASK_BITS (MI_SEGMENT_SIZE / MI_COMMIT_SIZE)
#define MI_COMMIT_MASK_FIELD_BITS MI_SIZE_BITS
#define MI_COMMIT_MASK_FIELD_COUNT (MI_COMMIT_MASK_BITS / MI_COMMIT_MASK_FIELD_BITS)
#if (MI_COMMIT_MASK_BITS != (MI_COMMIT_MASK_FIELD_COUNT * MI_COMMIT_MASK_FIELD_BITS))
#error "the segment size must be exactly divisible by the (commit size * size_t bits)"
#endif
typedef struct mi_commit_mask_s {
size_t mask[MI_COMMIT_MASK_FIELD_COUNT];
} mi_commit_mask_t;
typedef mi_page_t mi_slice_t;
typedef int64_t mi_msecs_t;
typedef enum mi_memkind_e {
MI_MEM_NONE, MI_MEM_EXTERNAL, MI_MEM_STATIC, MI_MEM_OS, MI_MEM_OS_HUGE, MI_MEM_OS_REMAP, MI_MEM_ARENA } mi_memkind_t;
static inline bool mi_memkind_is_os(mi_memkind_t memkind) {
return (memkind >= MI_MEM_OS && memkind <= MI_MEM_OS_REMAP);
}
typedef struct mi_memid_os_info {
void* base; size_t size; } mi_memid_os_info_t;
typedef struct mi_memid_arena_info {
size_t block_index; mi_arena_id_t id; bool is_exclusive; } mi_memid_arena_info_t;
typedef struct mi_memid_s {
union {
mi_memid_os_info_t os; mi_memid_arena_info_t arena; } mem;
bool is_pinned; bool initially_committed; bool initially_zero; mi_memkind_t memkind;
} mi_memid_t;
typedef struct mi_subproc_s mi_subproc_t;
typedef struct mi_segment_s {
mi_memid_t memid; bool allow_decommit; bool allow_purge; size_t segment_size;
mi_subproc_t* subproc;
mi_msecs_t purge_expire; mi_commit_mask_t purge_mask; mi_commit_mask_t commit_mask;
struct mi_segment_s* next; bool was_reclaimed; bool dont_free;
size_t abandoned; size_t abandoned_visits; size_t used; uintptr_t cookie;
struct mi_segment_s* abandoned_os_next; struct mi_segment_s* abandoned_os_prev;
size_t segment_slices; size_t segment_info_slices;
mi_segment_kind_t kind;
size_t slice_entries; _Atomic(mi_threadid_t) thread_id;
mi_slice_t slices[MI_SLICES_PER_SEGMENT+1]; } mi_segment_t;
typedef struct mi_tld_s mi_tld_t;
typedef struct mi_page_queue_s {
mi_page_t* first;
mi_page_t* last;
size_t block_size;
} mi_page_queue_t;
#define MI_BIN_FULL (MI_BIN_HUGE+1)
typedef struct mi_random_cxt_s {
uint32_t input[16];
uint32_t output[16];
int output_available;
bool weak;
} mi_random_ctx_t;
#if (MI_PADDING)
typedef struct mi_padding_s {
uint32_t canary; uint32_t delta; } mi_padding_t;
#define MI_PADDING_SIZE (sizeof(mi_padding_t))
#define MI_PADDING_WSIZE ((MI_PADDING_SIZE + MI_INTPTR_SIZE - 1) / MI_INTPTR_SIZE)
#else
#define MI_PADDING_SIZE 0
#define MI_PADDING_WSIZE 0
#endif
#define MI_PAGES_DIRECT (MI_SMALL_WSIZE_MAX + MI_PADDING_WSIZE + 1)
struct mi_heap_s {
mi_tld_t* tld;
_Atomic(mi_block_t*) thread_delayed_free;
mi_threadid_t thread_id; mi_arena_id_t arena_id; uintptr_t cookie; uintptr_t keys[2]; mi_random_ctx_t random; size_t page_count; size_t page_retired_min; size_t page_retired_max; long generic_count; long generic_collect_count; mi_heap_t* next; bool no_reclaim; uint8_t tag; #if MI_GUARDED
size_t guarded_size_min; size_t guarded_size_max; size_t guarded_sample_rate; size_t guarded_sample_count; #endif
mi_page_t* pages_free_direct[MI_PAGES_DIRECT]; mi_page_queue_t pages[MI_BIN_FULL + 1]; };
struct mi_subproc_s {
_Atomic(size_t) abandoned_count; _Atomic(size_t) abandoned_os_list_count; mi_lock_t abandoned_os_lock; mi_lock_t abandoned_os_visit_lock; mi_segment_t* abandoned_os_list; mi_segment_t* abandoned_os_list_tail; mi_memid_t memid; };
typedef struct mi_span_queue_s {
mi_slice_t* first;
mi_slice_t* last;
size_t slice_count;
} mi_span_queue_t;
#define MI_SEGMENT_BIN_MAX (35)
typedef struct mi_segments_tld_s {
mi_span_queue_t spans[MI_SEGMENT_BIN_MAX+1]; size_t count; size_t peak_count; size_t current_size; size_t peak_size; size_t reclaim_count; mi_subproc_t* subproc; mi_stats_t* stats; } mi_segments_tld_t;
struct mi_tld_s {
unsigned long long heartbeat; bool recurse; mi_heap_t* heap_backing; mi_heap_t* heaps; mi_segments_tld_t segments; mi_stats_t stats; };
#if !defined(MI_DEBUG_UNINIT)
#define MI_DEBUG_UNINIT (0xD0)
#endif
#if !defined(MI_DEBUG_FREED)
#define MI_DEBUG_FREED (0xDF)
#endif
#if !defined(MI_DEBUG_PADDING)
#define MI_DEBUG_PADDING (0xDE)
#endif
#ifndef MI_STAT
#if (MI_DEBUG>0)
#define MI_STAT 2
#else
#define MI_STAT 0
#endif
#endif
void _mi_stat_increase(mi_stat_count_t* stat, size_t amount);
void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount);
void _mi_stat_adjust_decrease(mi_stat_count_t* stat, size_t amount);
void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount);
#if (MI_STAT)
#define mi_stat_increase(stat,amount) _mi_stat_increase( &(stat), amount)
#define mi_stat_decrease(stat,amount) _mi_stat_decrease( &(stat), amount)
#define mi_stat_adjust_decrease(stat,amount) _mi_stat_adjust_decrease( &(stat), amount)
#define mi_stat_counter_increase(stat,amount) _mi_stat_counter_increase( &(stat), amount)
#else
#define mi_stat_increase(stat,amount) ((void)0)
#define mi_stat_decrease(stat,amount) ((void)0)
#define mi_stat_adjust_decrease(stat,amount) ((void)0)
#define mi_stat_counter_increase(stat,amount) ((void)0)
#endif
#define mi_heap_stat_counter_increase(heap,stat,amount) mi_stat_counter_increase( (heap)->tld->stats.stat, amount)
#define mi_heap_stat_increase(heap,stat,amount) mi_stat_increase( (heap)->tld->stats.stat, amount)
#define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount)
#define mi_heap_stat_adjust_decrease(heap,stat,amount) mi_stat_adjust_decrease( (heap)->tld->stats.stat, amount)
#endif