Skip to content

Commit e8621a7

Browse files
committed
clean up csize functions
1 parent 32a782f commit e8621a7

8 files changed

Lines changed: 132 additions & 80 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ if (MI_BUILD_TESTS)
11511151
endforeach()
11521152

11531153
# static override test
1154-
if(MI_BUILD_OBJECT AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
1154+
if(MI_BUILD_OBJECT AND MI_OVERRIDE AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
11551155
add_executable(mimalloc-test-stress-static test/test-stress.c)
11561156
target_compile_definitions(mimalloc-test-stress-static PRIVATE ${mi_defines} "USE_STD_MALLOC=1")
11571157
target_compile_options(mimalloc-test-stress-static PRIVATE ${mi_cflags})
@@ -1161,7 +1161,7 @@ if (MI_BUILD_TESTS)
11611161
endif()
11621162

11631163
# dynamic override test
1164-
if(MI_BUILD_SHARED AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN)) # AND NOT (APPLE AND MI_USE_CXX))
1164+
if(MI_BUILD_SHARED AND MI_OVERRIDE AND NOT (MI_CYGWIN OR (MI_TRACK STREQUAL "ASAN") OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN)) # AND NOT (APPLE AND MI_USE_CXX))
11651165
add_executable(mimalloc-test-stress-dynamic test/test-stress.c)
11661166
target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE ${mi_defines} "USE_STD_MALLOC=1")
11671167
target_compile_options(mimalloc-test-stress-dynamic PRIVATE ${mi_cflags})

include/mimalloc-new-delete.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ terms of the MIT license. A copy of the license can be found in the file
3737
void operator delete (void* p, const std::nothrow_t&) noexcept { mi_free(p); }
3838
void operator delete[](void* p, const std::nothrow_t&) noexcept { mi_free(p); }
3939

40-
mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
40+
mi_decl_new(n) void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
4141
mi_decl_new(n) void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); }
4242

4343
mi_decl_new_nothrow(n) void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }

include/mimalloc.h

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -396,43 +396,6 @@ mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_zalloc_aligned(
396396
mi_decl_nodiscard mi_decl_export void* mi_theap_realloc(mi_theap_t* theap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);
397397
mi_decl_nodiscard mi_decl_export void* mi_theap_rezalloc(mi_theap_t* theap, void* p, size_t newsize) mi_attr_noexcept mi_attr_alloc_size(3);
398398

399-
// ------------------------------------------------------
400-
// Fast constant size allocations.
401-
// ------------------------------------------------------
402-
403-
// Machine word size allocation. `wsize` is the allocation size in machine words (`sizeof(size_t)`)
404-
mi_decl_nodiscard mi_decl_restrict void* mi_wzalloc_small(size_t wsize) mi_attr_noexcept;
405-
mi_decl_nodiscard mi_decl_restrict void* mi_wmalloc_small(size_t wsize) mi_attr_noexcept;
406-
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wmalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept;
407-
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wzalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept;
408-
409-
// get the machine word size from a byte size.
410-
static inline size_t mi_wsize_from_size(size_t size) {
411-
return ((size + sizeof(size_t) - 1) / sizeof(size_t));
412-
}
413-
414-
static inline mi_decl_restrict void* mi_malloc_csize(size_t size) mi_attr_noexcept {
415-
if (size <= MI_SMALL_SIZE_MAX) { return mi_wmalloc_small(mi_wsize_from_size(size)); } else { return mi_malloc(size); }
416-
}
417-
static inline mi_decl_restrict void* mi_zalloc_csize(size_t size) mi_attr_noexcept {
418-
if (size <= MI_SMALL_SIZE_MAX) { return mi_wzalloc_small(mi_wsize_from_size(size)); } else { return mi_zalloc(size); }
419-
}
420-
static inline mi_decl_restrict void* mi_theap_malloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
421-
assert(theap!=NULL);
422-
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wmalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_malloc(theap,size); }
423-
}
424-
static inline mi_decl_restrict void* mi_theap_zalloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
425-
assert(theap!=NULL);
426-
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wzalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_zalloc(theap,size); }
427-
}
428-
static inline void mi_free_csize(void* p, size_t size) mi_attr_noexcept {
429-
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small(p); } else { mi_free(p); }
430-
}
431-
static inline void mi_free_csize_nonnull(void* p, size_t size) mi_attr_noexcept {
432-
assert(p!=NULL);
433-
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small_nonnull(p); } else { mi_free(p); }
434-
}
435-
436399
// ------------------------------------------------------
437400
// Experimental
438401
// ------------------------------------------------------
@@ -588,8 +551,13 @@ mi_decl_export int mi_wdupenv_s(wchar_t** buf, size_t* size, const wchar_t* name
588551
mi_decl_nodiscard mi_decl_export mi_decl_restrict wchar_t* mi_wcsdup(const wchar_t* s) mi_attr_noexcept mi_attr_malloc;
589552
mi_decl_nodiscard mi_decl_export mi_decl_restrict unsigned char* mi_mbsdup(const unsigned char* s) mi_attr_noexcept mi_attr_malloc;
590553

591-
// The `mi_new` wrappers implement C++ semantics on out-of-memory instead of directly returning `NULL`.
592-
// (and call `std::get_new_handler` and potentially raise a `std::bad_alloc` exception).
554+
// --------------------------------------------------------
555+
// C++ wrappers
556+
// The `mi_new` wrappers implement C++ semantics on out-of-memory
557+
// instead of directly returning `NULL`. (and call `std::get_new_handler`
558+
// and potentially raise a `std::bad_alloc` exception).
559+
// --------------------------------------------------------
560+
593561
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new(size_t size) mi_attr_malloc mi_attr_alloc_size(1);
594562
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_aligned(size_t size, size_t alignment) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
595563
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
@@ -601,6 +569,63 @@ mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount,
601569
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size_t size) mi_attr_malloc mi_attr_alloc_size(2);
602570
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);
603571

572+
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_alloc_new(mi_theap_t* theap, size_t size) mi_attr_malloc mi_attr_alloc_size(2);
573+
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_alloc_new_n(mi_theap_t* theap, size_t count, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);
574+
mi_decl_nodiscard mi_decl_export mi_decl_restrict void* mi_theap_alloc_new_nothrow(mi_theap_t* theap, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
575+
576+
577+
// --------------------------------------------------------------------------
578+
// Inlined constant size allocations.
579+
// These are meant for runtime systems, or overrides where we need the best
580+
// performance for small, constant-size allocations.
581+
// These are only better than the regular functions if the size or alignment
582+
// are indeed constant at the call site.
583+
// --------------------------------------------------------------------------
584+
585+
// Internal machine word size allocation. `wsize` is the allocation size in machine words (`sizeof(size_t)`)
586+
mi_decl_nodiscard mi_decl_restrict void* mi_wzalloc_small(size_t wsize) mi_attr_noexcept mi_attr_malloc;
587+
mi_decl_nodiscard mi_decl_restrict void* mi_wmalloc_small(size_t wsize) mi_attr_noexcept mi_attr_malloc;
588+
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wmalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept mi_attr_malloc;
589+
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wzalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept mi_attr_malloc;
590+
591+
static inline size_t mi_wsize_from_size(size_t size) mi_attr_noexcept {
592+
return (size + sizeof(size_t) - 1) / sizeof(size_t);
593+
}
594+
595+
static inline mi_decl_restrict void* mi_malloc_csize(size_t size) mi_attr_noexcept {
596+
if (size <= MI_SMALL_SIZE_MAX) { return mi_wmalloc_small(mi_wsize_from_size(size)); } else { return mi_malloc(size); }
597+
}
598+
static inline mi_decl_restrict void* mi_zalloc_csize(size_t size) mi_attr_noexcept {
599+
if (size <= MI_SMALL_SIZE_MAX) { return mi_wzalloc_small(mi_wsize_from_size(size)); } else { return mi_zalloc(size); }
600+
}
601+
static inline mi_decl_restrict void* mi_theap_malloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
602+
assert(theap!=NULL);
603+
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wmalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_malloc(theap,size); }
604+
}
605+
static inline mi_decl_restrict void* mi_theap_zalloc_csize(mi_theap_t* theap, size_t size) mi_attr_noexcept {
606+
assert(theap!=NULL);
607+
if (size <= MI_SMALL_SIZE_MAX) { return mi_theap_wzalloc_small(theap,mi_wsize_from_size(size)); } else { return mi_theap_zalloc(theap,size); }
608+
}
609+
610+
static inline void mi_free_csize(void* p, size_t size) mi_attr_noexcept {
611+
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small(p); } else { mi_free(p); }
612+
}
613+
static inline void mi_free_csize_nonnull(void* p, size_t size) mi_attr_noexcept {
614+
assert(p!=NULL);
615+
if (size <= MI_SMALL_SIZE_MAX) { mi_free_small_nonnull(p); } else { mi_free(p); }
616+
}
617+
static inline void mi_free_csize_aligned(void* p, size_t size, size_t aligned) mi_attr_noexcept {
618+
if (aligned <= size && size <= MI_SMALL_SIZE_MAX) { mi_free_small(p); } else { mi_free(p); }
619+
}
620+
static inline void mi_free_csize_aligned_nonnull(void* p, size_t size, size_t aligned) mi_attr_noexcept {
621+
assert(p!=NULL);
622+
if (aligned <= size && size <= MI_SMALL_SIZE_MAX) { mi_free_small_nonnull(p); } else { mi_free(p); }
623+
}
624+
625+
// ------------------------------------------------------
626+
// C++ standard library allocator interface.
627+
// ------------------------------------------------------
628+
604629
#ifdef __cplusplus
605630
}
606631
#endif

include/mimalloc/types.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,13 @@ typedef struct mi_page_s {
535535
#define MI_MAX_SINGLETON_BIN MI_BIN_HUGE
536536
#endif
537537

538+
// The small object max size must be larger than twice the small size max minus one,
539+
// such that any aligned allocation with `alignment <= size <= MI_SMALL_SIZE_MAX` will
540+
// be allocated in a small page (so `mi_free_csize` can delegate correctly to `mi_free_small`.
541+
#if MI_SMALL_MAX_OBJ_SIZE <= (2*(MI_SMALL_WSIZE_MAX * MI_SIZE_SIZE)-1)
542+
#error "mimalloc internal: the small object max size is too small"
543+
#endif
544+
538545
// ------------------------------------------------------
539546
// Page kinds
540547
// ------------------------------------------------------

src/alloc.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -818,15 +818,15 @@ static mi_decl_noinline void* mi_theap_try_new(mi_theap_t* theap, size_t size, b
818818
return p;
819819
}
820820

821-
static mi_decl_noinline void* mi_try_new(size_t size, bool nothrow) {
822-
return mi_theap_try_new(_mi_theap_default(), size, nothrow);
823-
}
821+
// static mi_decl_noinline void* mi_try_new(size_t size, bool nothrow) {
822+
// return mi_theap_try_new(_mi_theap_default(), size, nothrow);
823+
// }
824824

825825
static mi_decl_noinline void* mi_heap_try_new(mi_heap_t* heap, size_t size, bool nothrow) {
826826
return mi_theap_try_new(_mi_heap_theap(heap), size, nothrow);
827827
}
828828

829-
mi_decl_nodiscard static mi_decl_restrict void* mi_theap_alloc_new(mi_theap_t* theap, size_t size) {
829+
mi_decl_nodiscard mi_decl_restrict void* mi_theap_alloc_new(mi_theap_t* theap, size_t size) {
830830
void* p = mi_theap_malloc(theap,size);
831831
if mi_unlikely(p == NULL) return mi_theap_try_new(theap, size, false);
832832
return p;
@@ -842,7 +842,7 @@ mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size
842842
return p;
843843
}
844844

845-
mi_decl_nodiscard static mi_decl_restrict void* mi_theap_alloc_new_n(mi_theap_t* theap, size_t count, size_t size) {
845+
mi_decl_nodiscard mi_decl_restrict void* mi_theap_alloc_new_n(mi_theap_t* theap, size_t count, size_t size) {
846846
size_t total;
847847
if mi_unlikely(mi_count_size_overflow(count, size, &total)) {
848848
mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc
@@ -861,12 +861,17 @@ mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, si
861861
return mi_theap_alloc_new_n(_mi_heap_theap(heap), count, size);
862862
}
863863

864-
mi_decl_nodiscard mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept {
865-
void* p = mi_malloc(size);
866-
if mi_unlikely(p == NULL) return mi_try_new(size, true);
864+
865+
mi_decl_nodiscard mi_decl_restrict void* mi_theap_alloc_new_nothrow(mi_theap_t* theap, size_t size) mi_attr_noexcept {
866+
void* p = mi_theap_malloc(theap,size);
867+
if mi_unlikely(p == NULL) return mi_theap_try_new(theap, size, true);
867868
return p;
868869
}
869870

871+
mi_decl_nodiscard mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept {
872+
return mi_theap_alloc_new_nothrow(_mi_theap_default(), size);
873+
}
874+
870875
static mi_decl_noinline void* mi_try_new_aligned(size_t size, size_t alignment, bool nothrow) {
871876
void* p = NULL;
872877
for(int i = 0; i < MI_TRY_NEW_MAX && p==NULL && mi_try_new_handler(nothrow); i++) {

src/arena.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,11 +889,15 @@ mi_decl_maybe_unused static size_t mi_page_block_start(size_t block_size, bool o
889889
if (os_align) {
890890
offset = MI_PAGE_ALIGN;
891891
}
892-
else if (_mi_is_power_of_two(block_size) && block_size <= MI_PAGE_MAX_START_BLOCK_ALIGN2) {
892+
else if (block_size != 0 && _mi_is_power_of_two(block_size) && block_size <= MI_PAGE_MAX_START_BLOCK_ALIGN2) {
893893
// naturally align power-of-2 blocks up to MI_PAGE_MAX_START_BLOCK_ALIGN2 size (4KiB)
894894
offset = _mi_align_up(mi_page_info_size(), block_size);
895895
if (block_size < 64) { offset += 3*block_size; }
896896
}
897+
else if (block_size != 0 && block_size <= MI_SMALL_SIZE_MAX) {
898+
// align small blocks to their size
899+
offset = _mi_align_up(mi_page_info_size(), block_size);
900+
}
897901
else if (block_size != 0 && (block_size % MI_PAGE_OSPAGE_BLOCK_ALIGN2) == 0) {
898902
// also align large pages that are a multiple of MI_PAGE_OSPAGE_BLOCK_ALIGN2 (4KiB)
899903
offset = _mi_align_up(mi_page_info_size(), MI_PAGE_OSPAGE_BLOCK_ALIGN2);

src/free.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ void mi_free_size(void* p, size_t size) mi_attr_noexcept {
345345
if (page==NULL) return;
346346
mi_assert(p!=NULL);
347347
const mi_block_t* block = _mi_page_ptr_unalign(page, p);
348-
const size_t usable = mi_page_usable_size(page,p);
348+
const size_t usable = _mi_page_usable_size(page,p);
349349
if mi_unlikely(size > usable) {
350350
const bool is_guarded = mi_block_ptr_is_guarded(block,p);
351351
if (!is_guarded) {

test/test-api.c

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -73,26 +73,6 @@ static bool mem_is_zero(const void* p, size_t size) {
7373
int main(void) {
7474
mi_option_disable(mi_option_verbose);
7575

76-
#if 1
77-
#if defined(__cplusplus) && !defined(_MSC_VER)
78-
CHECK_BODY("c++ new-handler") {
79-
std::set_new_handler([]{ throw std::bad_alloc(); });
80-
void* p = mi_new_nothrow(SIZE_MAX/2);
81-
result = (p==NULL);
82-
}
83-
CHECK_BODY("c++ new handler2") {
84-
try {
85-
void* p = mi_new_n(SIZE_MAX/2, 4);
86-
(void)(p);
87-
result = false;
88-
}
89-
catch(std::bad_alloc) {
90-
result = true;
91-
}
92-
}
93-
#endif
94-
#endif
95-
9676
// ---------------------------------------------------
9777
// Malloc
9878
// ---------------------------------------------------
@@ -319,12 +299,22 @@ int main(void) {
319299
for(int i = 0; i < 10 && ok; i++) {
320300
mi_free(p[i]);
321301
}
322-
/*
323-
if (ok && align <= size && ((size + MI_PADDING_SIZE) & (align-1)) == 0) {
324-
size_t bsize = mi_good_size(size);
325-
ok = (align <= bsize && (bsize & (align-1)) == 0);
302+
}
303+
}
304+
result = ok;
305+
}
306+
CHECK_BODY("mimalloc-size-aligned14") {
307+
bool ok = true;
308+
for( size_t size = 1; size <= (MI_SMALL_SIZE_MAX * 2) && ok; size++ ) {
309+
for(size_t align = 1; align <= 16*size && ok; align *= 2) {
310+
void* p[10];
311+
for(int i = 0; i < 10 && ok; i++) {
312+
p[i] = mi_malloc_aligned(size,align);;
313+
ok = (p[i] != NULL && ((uintptr_t)(p[i]) % align) == 0);
314+
}
315+
for(int i = 0; i < 10 && ok; i++) {
316+
mi_free_size_aligned(p[i],size,align);
326317
}
327-
*/
328318
}
329319
}
330320
result = ok;
@@ -355,9 +345,7 @@ int main(void) {
355345
memset(junk, 0xAB, size);
356346
mi_free(junk);
357347
uint8_t* z = (uint8_t*)mi_theap_zalloc_csize(theap, size);
358-
for (size_t i = 0; i < size; i++) {
359-
if (z[i] != 0) { ok = false; break; }
360-
}
348+
ok = mem_is_zero(z, size);
361349
mi_free(z);
362350
}
363351
result = ok;
@@ -496,6 +484,29 @@ int main(void) {
496484
}
497485
#endif
498486

487+
488+
// ---------------------------------------------------
489+
// C++
490+
// ---------------------------------------------------
491+
492+
#if defined(__cplusplus) && !defined(_MSC_VER)
493+
CHECK_BODY("c++ new-handler") {
494+
std::set_new_handler([]{ throw std::bad_alloc(); });
495+
void* p = mi_new_nothrow(SIZE_MAX/2);
496+
result = (p==NULL);
497+
}
498+
CHECK_BODY("c++ new handler2") {
499+
try {
500+
void* p = mi_new_n(SIZE_MAX/2, 4);
501+
(void)(p);
502+
result = false;
503+
}
504+
catch(std::bad_alloc) {
505+
result = true;
506+
}
507+
}
508+
#endif
509+
499510
// ---------------------------------------------------
500511
// Heaps
501512
// ---------------------------------------------------

0 commit comments

Comments
 (0)