diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f7e0956..301fdea7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -750,8 +750,8 @@ if (MI_BUILD_TESTS) endif() target_compile_options(mimalloc-test-stress-dynamic PRIVATE ${mi_cflags}) target_include_directories(mimalloc-test-stress-dynamic PRIVATE include) - target_link_libraries(mimalloc-test-stress-dynamic PRIVATE mimalloc ${mi_libraries}) # mi_version if(WIN32) + target_link_libraries(mimalloc-test-stress-dynamic PRIVATE mimalloc ${mi_libraries}) # mi_version add_test(NAME test-stress-dynamic COMMAND ${CMAKE_COMMAND} -E env MIMALLOC_SHOW_STATS=1 $) else() if(APPLE) diff --git a/bin/mimalloc-redirect-arm64.dll b/bin/mimalloc-redirect-arm64.dll old mode 100644 new mode 100755 index e6360285..27172d2c Binary files a/bin/mimalloc-redirect-arm64.dll and b/bin/mimalloc-redirect-arm64.dll differ diff --git a/bin/mimalloc-redirect-arm64.lib b/bin/mimalloc-redirect-arm64.lib old mode 100644 new mode 100755 index 11d71ef9..dca80b9b Binary files a/bin/mimalloc-redirect-arm64.lib and b/bin/mimalloc-redirect-arm64.lib differ diff --git a/bin/mimalloc-redirect-arm64ec.dll b/bin/mimalloc-redirect-arm64ec.dll old mode 100644 new mode 100755 index f5ee4e47..a228af39 Binary files a/bin/mimalloc-redirect-arm64ec.dll and b/bin/mimalloc-redirect-arm64ec.dll differ diff --git a/bin/mimalloc-redirect-arm64ec.lib b/bin/mimalloc-redirect-arm64ec.lib old mode 100644 new mode 100755 index b88e8fc1..0ce77436 Binary files a/bin/mimalloc-redirect-arm64ec.lib and b/bin/mimalloc-redirect-arm64ec.lib differ diff --git a/bin/mimalloc-redirect.dll b/bin/mimalloc-redirect.dll old mode 100644 new mode 100755 index 9e015cc6..ec035f1b Binary files a/bin/mimalloc-redirect.dll and b/bin/mimalloc-redirect.dll differ diff --git a/bin/mimalloc-redirect.lib b/bin/mimalloc-redirect.lib old mode 100644 new mode 100755 index 1d710c01..785fa475 Binary files a/bin/mimalloc-redirect.lib and b/bin/mimalloc-redirect.lib differ diff --git a/bin/mimalloc-redirect32.dll b/bin/mimalloc-redirect32.dll old mode 100644 new mode 100755 index 32799ffe..92578f24 Binary files a/bin/mimalloc-redirect32.dll and b/bin/mimalloc-redirect32.dll differ diff --git a/bin/mimalloc-redirect32.lib b/bin/mimalloc-redirect32.lib old mode 100644 new mode 100755 index e2927250..bf649787 Binary files a/bin/mimalloc-redirect32.lib and b/bin/mimalloc-redirect32.lib differ diff --git a/cmake/mimalloc-config-version.cmake b/cmake/mimalloc-config-version.cmake index bd4adb2a..ad066d09 100644 --- a/cmake/mimalloc-config-version.cmake +++ b/cmake/mimalloc-config-version.cmake @@ -1,6 +1,6 @@ set(mi_version_major 3) set(mi_version_minor 0) -set(mi_version_patch 3) +set(mi_version_patch 4) set(mi_version ${mi_version_major}.${mi_version_minor}) set(PACKAGE_VERSION ${mi_version}) diff --git a/include/mimalloc.h b/include/mimalloc.h index 3be9f619..c4a4eb19 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -8,7 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file #ifndef MIMALLOC_H #define MIMALLOC_H -#define MI_MALLOC_VERSION 303 // major + 2 digits minor +#define MI_MALLOC_VERSION 304 // major + 2 digits minor // ------------------------------------------------------ // Compiler specific attributes diff --git a/include/mimalloc/atomic.h b/include/mimalloc/atomic.h index 2d890954..e1a6d76d 100644 --- a/include/mimalloc/atomic.h +++ b/include/mimalloc/atomic.h @@ -376,8 +376,9 @@ static inline void mi_atomic_yield(void) { _mm_pause(); } #elif (defined(__GNUC__) || defined(__clang__)) && \ - (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__armel__) || defined(__ARMEL__) || \ - defined(__aarch64__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)) || defined(__POWERPC__) + (defined(__x86_64__) || defined(__i386__) || \ + defined(__aarch64__) || defined(__arm__) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__POWERPC__)) #if defined(__x86_64__) || defined(__i386__) static inline void mi_atomic_yield(void) { __asm__ volatile ("pause" ::: "memory"); @@ -386,10 +387,16 @@ static inline void mi_atomic_yield(void) { static inline void mi_atomic_yield(void) { __asm__ volatile("wfe"); } -#elif (defined(__arm__) && __ARM_ARCH >= 7) +#elif defined(__arm__) +#if __ARM_ARCH >= 7 static inline void mi_atomic_yield(void) { __asm__ volatile("yield" ::: "memory"); } +#else +static inline void mi_atomic_yield(void) { + __asm__ volatile ("nop" ::: "memory"); +} +#endif #elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__POWERPC__) #ifdef __APPLE__ static inline void mi_atomic_yield(void) { @@ -400,10 +407,6 @@ static inline void mi_atomic_yield(void) { __asm__ __volatile__ ("or 27,27,27" ::: "memory"); } #endif -#elif defined(__armel__) || defined(__ARMEL__) -static inline void mi_atomic_yield(void) { - __asm__ volatile ("nop" ::: "memory"); -} #endif #elif defined(__sun) // Fallback for other archs diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index 88404f98..9ec28503 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -339,10 +339,6 @@ typedef struct mi_option_desc_s { const char* legacy_name; // potential legacy option name } mi_option_desc_t; -// the static options -extern mi_decl_hidden mi_option_desc_t mi_options[_mi_option_last]; - - /* ----------------------------------------------------------- Inlined definitions ----------------------------------------------------------- */ @@ -570,14 +566,14 @@ static inline size_t _mi_page_map_index(const void* p, size_t* sub_idx) { static inline mi_page_t* _mi_unchecked_ptr_page(const void* p) { size_t sub_idx; const size_t idx = _mi_page_map_index(p, &sub_idx); - return _mi_page_map[idx][sub_idx]; + return _mi_page_map[idx][sub_idx]; // NULL if p==NULL } static inline mi_page_t* _mi_checked_ptr_page(const void* p) { size_t sub_idx; const size_t idx = _mi_page_map_index(p, &sub_idx); mi_page_t** const sub = _mi_page_map[idx]; - if mi_unlikely(sub == NULL) return (mi_page_t*)&_mi_page_empty; + if mi_unlikely(sub == NULL) return NULL; return sub[sub_idx]; } diff --git a/readme.md b/readme.md index 81f2057e..5a495275 100644 --- a/readme.md +++ b/readme.md @@ -12,9 +12,9 @@ is a general purpose allocator with excellent [performance](#performance) charac Initially developed by Daan Leijen for the runtime systems of the [Koka](https://koka-lang.github.io) and [Lean](https://github.com/leanprover/lean) languages. -Latest release : `v3.0.2` (beta) (2025-03-06). -Latest v2 release: `v2.2.2` (2025-03-06). -Latest v1 release: `v1.9.2` (2024-03-06). +Latest release : `v3.0.3` (beta) (2025-03-28). +Latest v2 release: `v2.2.3` (2025-03-28). +Latest v1 release: `v1.9.3` (2024-03-28). mimalloc is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: @@ -84,6 +84,9 @@ Enjoy! ### Releases +* 2025-03-28, `v1.9.3`, `v2.2.3`, `v3.0.3` (beta): Various small bug and build fixes, including: + fix arm32 pre v7 builds, fix mingw build, get runtime statistics, improve statistic commit counts, + fix execution on non BMI1 x64 systems. * 2025-03-06, `v1.9.2`, `v2.2.2`, `v3.0.2-beta`: Various small bug and build fixes. Add `mi_options_print`, `mi_arenas_print`, and the experimental `mi_stat_get` and `mi_stat_get_json`. Add `mi_thread_set_in_threadpool` and `mi_heap_set_numa_affinity` (v3 only). Add vcpkg portfile. diff --git a/src/free.c b/src/free.c index 00ecf34d..6b9d3431 100644 --- a/src/free.c +++ b/src/free.c @@ -115,6 +115,7 @@ static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, vo // free a local pointer (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, void* p) mi_attr_noexcept { + mi_assert_internal(p!=NULL && page != NULL); mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(page, p) : (mi_block_t*)p); mi_block_check_unguard(page, block, p); mi_free_block_local(page, block, true /* track stats */, true /* check for a full page */); @@ -122,11 +123,7 @@ static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, void* p) mi_ // free a pointer owned by another thread (page parameter comes first for better codegen) static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, void* p) mi_attr_noexcept { - if (p==NULL) return; // a NULL pointer is seen as abandoned (tid==0) with a full flag set - #if !MI_PAGE_MAP_FLAT - if (page==&_mi_page_empty) return; // an invalid pointer may lead to using the empty page - #endif - mi_assert_internal(p!=NULL && page != NULL && page != &_mi_page_empty); + mi_assert_internal(p!=NULL && page != NULL); mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865) mi_block_check_unguard(page, block, p); mi_free_block_mt(page, block); @@ -150,13 +147,8 @@ static inline mi_page_t* mi_validate_ptr_page(const void* p, const char* msg) return NULL; } mi_page_t* page = _mi_safe_ptr_page(p); - if (page == NULL) { - if (p != NULL) { - _mi_error_message(EINVAL, "%s: invalid pointer: %p\n", msg, p); - } - #if !MI_PAGE_MAP_FLAT - page = (mi_page_t*)&_mi_page_empty; - #endif + if (p != NULL && page == NULL) { + _mi_error_message(EINVAL, "%s: invalid pointer: %p\n", msg, p); } return page; #else @@ -169,12 +161,9 @@ static inline mi_page_t* mi_validate_ptr_page(const void* p, const char* msg) void mi_free(void* p) mi_attr_noexcept { mi_page_t* const page = mi_validate_ptr_page(p,"mi_free"); - - #if MI_PAGE_MAP_FLAT // if not flat, p==NULL leads to `_mi_page_empty` which leads to `mi_free_generic_mt` if mi_unlikely(page==NULL) return; - #endif - mi_assert_internal(page!=NULL); - + mi_assert_internal(p!=NULL && page!=NULL); + const mi_threadid_t xtid = (_mi_prim_thread_id() ^ mi_page_xthread_id(page)); if mi_likely(xtid == 0) { // `tid == mi_page_thread_id(page) && mi_page_flags(page) == 0` // thread-local, aligned, and not a full page diff --git a/src/init.c b/src/init.c index 6d4ce65e..892f4988 100644 --- a/src/init.c +++ b/src/init.c @@ -16,7 +16,7 @@ terms of the MIT license. A copy of the license can be found in the file // Empty page used to initialize the small free pages array const mi_page_t _mi_page_empty = { - MI_ATOMIC_VAR_INIT(MI_PAGE_IN_FULL_QUEUE), // xthread_id (must set flag to catch NULL on a free) + MI_ATOMIC_VAR_INIT(0), // xthread_id NULL, // free 0, // used 0, // capacity diff --git a/src/options.c b/src/options.c index 2657cb6b..f1d16d6b 100644 --- a/src/options.c +++ b/src/options.c @@ -98,8 +98,8 @@ int mi_version(void) mi_attr_noexcept { #endif #endif -// Static options (only exposed for the debugger) -mi_option_desc_t mi_options[_mi_option_last] = +// Static options +static mi_option_desc_t mi_options[_mi_option_last] = { // stable options #if MI_DEBUG || defined(MI_SHOW_ERRORS) @@ -329,7 +329,7 @@ static void mi_cdecl mi_out_stderr(const char* msg, void* arg) { #ifndef MI_MAX_DELAY_OUTPUT #define MI_MAX_DELAY_OUTPUT ((size_t)(16*1024)) #endif -static char out_buf[MI_MAX_DELAY_OUTPUT+1]; +static char mi_output_buffer[MI_MAX_DELAY_OUTPUT+1]; static _Atomic(size_t) out_len; static void mi_cdecl mi_out_buf(const char* msg, void* arg) { @@ -345,7 +345,8 @@ static void mi_cdecl mi_out_buf(const char* msg, void* arg) { if (start+n >= MI_MAX_DELAY_OUTPUT) { n = MI_MAX_DELAY_OUTPUT-start-1; } - _mi_memcpy(&out_buf[start], msg, n); + mi_assert_internal(start + n <= MI_MAX_DELAY_OUTPUT); + _mi_memcpy(&mi_output_buffer[start], msg, n); } static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) { @@ -354,10 +355,10 @@ static void mi_out_buf_flush(mi_output_fun* out, bool no_more_buf, void* arg) { size_t count = mi_atomic_add_acq_rel(&out_len, (no_more_buf ? MI_MAX_DELAY_OUTPUT : 1)); // and output the current contents if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT; - out_buf[count] = 0; - out(out_buf,arg); + mi_output_buffer[count] = 0; + out(mi_output_buffer,arg); if (!no_more_buf) { - out_buf[count] = '\n'; // if continue with the buffer, insert a newline + mi_output_buffer[count] = '\n'; // if continue with the buffer, insert a newline } } diff --git a/src/page-map.c b/src/page-map.c index 44d6de4a..78e8ab8e 100644 --- a/src/page-map.c +++ b/src/page-map.c @@ -210,9 +210,7 @@ bool _mi_page_map_init(void) { if (!mi_page_map_memid.initially_committed) { _mi_os_commit(_mi_page_map[0], os_page_size, NULL); // only first OS page } - _mi_page_map[0][0] = (mi_page_t*)&_mi_page_empty; // caught in `mi_free` - - mi_assert_internal(_mi_ptr_page(NULL)==&_mi_page_empty); + mi_assert_internal(_mi_ptr_page(NULL)==NULL); return true; } diff --git a/src/stats.c b/src/stats.c index 7a045386..3b53d5a9 100644 --- a/src/stats.c +++ b/src/stats.c @@ -227,12 +227,14 @@ static void mi_stat_peak_print(const mi_stat_count_t* stat, const char* msg, int _mi_fprintf(out, arg, "\n"); } +#if MI_STAT>1 static void mi_stat_total_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) { _mi_fprintf(out, arg, "%10s:", msg); _mi_fprintf(out, arg, "%12s", " "); // no peak mi_print_amount(stat->total, unit, out, arg); _mi_fprintf(out, arg, "\n"); } +#endif static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) { _mi_fprintf(out, arg, "%10s:", msg);