void* allocPages(void* addr, size_t len, size_t align) { RELEASE_ASSERT(len < INT_MAX - align); ASSERT(len >= kPageAllocationGranularity); ASSERT(!(len & kPageAllocationGranularityOffsetMask)); ASSERT(align >= kPageAllocationGranularity); ASSERT(!(align & kPageAllocationGranularityOffsetMask)); ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffsetMask)); size_t alignOffsetMask = align - 1; size_t alignBaseMask = ~alignOffsetMask; ASSERT(!(reinterpret_cast<uintptr_t>(addr) & alignOffsetMask)); // If the client passed null as the address, choose a good one. if (!addr) { addr = getRandomPageBase(); addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & alignBaseMask); } // The common case, which is also the least work we can do, is that the // address and length are suitable. Just try it. void* ret = systemAllocPages(addr, len); // If the alignment is to our liking, we're done. if (!(reinterpret_cast<uintptr_t>(ret) & alignOffsetMask)) return ret; // Annoying. Unmap and map a larger range to be sure to succeed on the // second, slower attempt. freePages(ret, len); size_t tryLen = len + (align - kPageAllocationGranularity); // We loop to cater for the unlikely case where another thread maps on top // of the aligned location we choose. int count = 0; while (count++ < 100) { ret = systemAllocPages(addr, tryLen); // We can now try and trim out a subset of the mapping. addr = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(ret) + alignOffsetMask) & alignBaseMask); // On POSIX systems, we can trim the oversized mapping to fit exactly. // This will always work on POSIX systems. if (trimMapping(ret, tryLen, addr, len)) return addr; // On Windows, you can't trim an existing mapping so we unmap and remap // a subset. We used to do for all platforms, but OSX 10.8 has a // broken mmap() that ignores address hints for valid, unused addresses. freePages(ret, tryLen); ret = systemAllocPages(addr, len); if (ret == addr) return ret; // Unlikely race / collision. Do the simple thing and just start again. freePages(ret, len); addr = getRandomPageBase(); addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & alignBaseMask); } IMMEDIATE_CRASH(); return 0; }
void* allocPages(void* addr, size_t len, size_t align, PageAccessibilityConfiguration pageAccessibility) { ASSERT(len >= kPageAllocationGranularity); ASSERT(!(len & kPageAllocationGranularityOffsetMask)); ASSERT(align >= kPageAllocationGranularity); ASSERT(!(align & kPageAllocationGranularityOffsetMask)); ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffsetMask)); uintptr_t alignOffsetMask = align - 1; uintptr_t alignBaseMask = ~alignOffsetMask; ASSERT(!(reinterpret_cast<uintptr_t>(addr) & alignOffsetMask)); // If the client passed null as the address, choose a good one. if (!addr) { addr = getRandomPageBase(); addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & alignBaseMask); } // First try to force an exact-size, aligned allocation from our random base. for (int count = 0; count < 3; ++count) { void* ret = systemAllocPages(addr, len, pageAccessibility); if (kHintIsAdvisory || ret) { // If the alignment is to our liking, we're done. if (!(reinterpret_cast<uintptr_t>(ret)& alignOffsetMask)) return ret; freePages(ret, len); #if CPU(32BIT) addr = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(ret)+align) & alignBaseMask); #endif } else if (!addr) { // We know we're OOM when an unhinted allocation fails. return nullptr; } else { #if CPU(32BIT) addr = reinterpret_cast<char*>(addr) + align; #endif } #if !CPU(32BIT) // Keep trying random addresses on systems that have a large address space. addr = getRandomPageBase(); addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & alignBaseMask); #endif } // Map a larger allocation so we can force alignment, but continue randomizing only on 64-bit POSIX. size_t tryLen = len + (align - kPageAllocationGranularity); RELEASE_ASSERT(tryLen >= len); void* ret; do { // Don't continue to burn cycles on mandatory hints (Windows). addr = kHintIsAdvisory ? getRandomPageBase() : nullptr; ret = systemAllocPages(addr, tryLen, pageAccessibility); // The retries are for Windows, where a race can steal our mapping on resize. } while (ret && !(ret = trimMapping(ret, tryLen, len, align, pageAccessibility))); return ret; }