| 662 | EM_JS_DEPS(_em_malloc_deps, "$ptrToString"); |
| 663 | |
| 664 | static void *allocate_memory(size_t alignment, size_t size) { |
| 665 | ASSERT_MALLOC_IS_ACQUIRED(); |
| 666 | |
| 667 | #ifdef EMMALLOC_VERBOSE |
| 668 | MAIN_THREAD_ASYNC_EM_ASM(out('allocate_memory(align=' + $0 + ', size=' + Number($1) + ' bytes)'), alignment, size); |
| 669 | #endif |
| 670 | |
| 671 | #ifdef EMMALLOC_MEMVALIDATE |
| 672 | validate_memory_regions(); |
| 673 | #endif |
| 674 | |
| 675 | if (!IS_POWER_OF_2(alignment)) { |
| 676 | #ifdef EMMALLOC_VERBOSE |
| 677 | MAIN_THREAD_ASYNC_EM_ASM(out('Allocation failed: alignment not power of 2!')); |
| 678 | #endif |
| 679 | return 0; |
| 680 | } |
| 681 | |
| 682 | if (size > MAX_ALLOC_SIZE) { |
| 683 | #ifdef EMMALLOC_VERBOSE |
| 684 | MAIN_THREAD_ASYNC_EM_ASM(out('Allocation failed: attempted allocation size is too large: ' + Number($0) + 'bytes! (negative integer wraparound?)'), size); |
| 685 | #endif |
| 686 | return 0; |
| 687 | } |
| 688 | |
| 689 | alignment = validate_alloc_alignment(alignment); |
| 690 | size = validate_alloc_size(size); |
| 691 | |
| 692 | // Attempt to allocate memory starting from smallest bucket that can contain the required amount of memory. |
| 693 | // Under normal alignment conditions this should always be the first or second bucket we look at, but if |
| 694 | // performing an allocation with complex alignment, we may need to look at multiple buckets. |
| 695 | int bucketIndex = compute_free_list_bucket(size); |
| 696 | BUCKET_BITMASK_T bucketMask = freeRegionBucketsUsed >> bucketIndex; |
| 697 | |
| 698 | // Loop through each bucket that has free regions in it, based on bits set in freeRegionBucketsUsed bitmap. |
| 699 | while (bucketMask) { |
| 700 | BUCKET_BITMASK_T indexAdd = __builtin_ctzll(bucketMask); |
| 701 | bucketIndex += indexAdd; |
| 702 | bucketMask >>= indexAdd; |
| 703 | assert(bucketIndex >= 0); |
| 704 | assert(bucketIndex <= NUM_FREE_BUCKETS-1); |
| 705 | assert(freeRegionBucketsUsed & (((BUCKET_BITMASK_T)1) << bucketIndex)); |
| 706 | |
| 707 | Region *freeRegion = freeRegionBuckets[bucketIndex].next; |
| 708 | assert(freeRegion); |
| 709 | if (freeRegion != &freeRegionBuckets[bucketIndex]) { |
| 710 | void *ptr = attempt_allocate(freeRegion, alignment, size); |
| 711 | if (ptr) { |
| 712 | return ptr; |
| 713 | } |
| 714 | |
| 715 | // We were not able to allocate from the first region found in this bucket, so penalize |
| 716 | // the region by cycling it to the end of the doubly circular linked list. (constant time) |
| 717 | // This provides a randomized guarantee that when performing allocations of size k to a |
| 718 | // bucket of [k-something, k+something] range, we will not always attempt to satisfy the |
| 719 | // allocation from the same available region at the front of the list, but we try each |
| 720 | // region in turn. |
| 721 | unlink_from_free_list(freeRegion); |
no test coverage detected