Free a block fast path written carefully to prevent spilling on the stack
| 532 | // Free a block |
| 533 | // fast path written carefully to prevent spilling on the stack |
| 534 | void mi_free(void* p) mi_attr_noexcept |
| 535 | { |
| 536 | if mi_unlikely(p == NULL) return; |
| 537 | mi_segment_t* const segment = mi_checked_ptr_segment(p,"mi_free"); |
| 538 | const bool is_local= (_mi_thread_id() == mi_atomic_load_relaxed(&segment->thread_id)); |
| 539 | mi_page_t* const page = _mi_segment_page_of(segment, p); |
| 540 | |
| 541 | if mi_likely(is_local) { // thread-local free? |
| 542 | if mi_likely(page->flags.full_aligned == 0) // and it is not a full page (full pages need to move from the full bin), nor has aligned blocks (aligned blocks need to be unaligned) |
| 543 | { |
| 544 | mi_block_t* const block = (mi_block_t*)p; |
| 545 | if mi_unlikely(mi_check_is_double_free(page, block)) return; |
| 546 | mi_check_padding(page, block); |
| 547 | mi_stat_free(page, block); |
| 548 | #if (MI_DEBUG!=0) && !MI_TRACK_ENABLED |
| 549 | memset(block, MI_DEBUG_FREED, mi_page_block_size(page)); |
| 550 | #endif |
| 551 | mi_track_free(p); |
| 552 | mi_block_set_next(page, block, page->local_free); |
| 553 | page->local_free = block; |
| 554 | if mi_unlikely(--page->used == 0) { // using this expression generates better code than: page->used--; if (mi_page_all_free(page)) |
| 555 | _mi_page_retire(page); |
| 556 | } |
| 557 | } |
| 558 | else { |
| 559 | // page is full or contains (inner) aligned blocks; use generic path |
| 560 | _mi_free_generic(segment, page, true, p); |
| 561 | } |
| 562 | } |
| 563 | else { |
| 564 | // not thread-local; use generic path |
| 565 | _mi_free_generic(segment, page, false, p); |