This source file includes following definitions.
- TestSetup
- TestShutdown
- GetFullPage
- FreeFullPage
- CycleFreeCache
- CycleGenericFreeCache
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
#include "config.h"
#include "wtf/PartitionAlloc.h"
#include "wtf/BitwiseOperations.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#include <gtest/gtest.h>
#include <stdlib.h>
#include <string.h>
#if OS(POSIX)
#include <sys/mman.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
namespace {
static const size_t kTestMaxAllocation = 4096;
static SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator;
static PartitionAllocatorGeneric genericAllocator;
static const size_t kTestAllocSize = 16;
#ifdef NDEBUG
static const size_t kPointerOffset = 0;
static const size_t kExtraAllocSize = 0;
#else
static const size_t kPointerOffset = WTF::kCookieSize;
static const size_t kExtraAllocSize = WTF::kCookieSize * 2;
#endif
static const size_t kRealAllocSize = kTestAllocSize + kExtraAllocSize;
static const size_t kTestBucketIndex = kRealAllocSize >> WTF::kBucketShift;
static void TestSetup()
{
allocator.init();
genericAllocator.init();
}
static void TestShutdown()
{
EXPECT_TRUE(allocator.shutdown());
EXPECT_TRUE(genericAllocator.shutdown());
}
static WTF::PartitionPage* GetFullPage(size_t size)
{
size_t realSize = size + kExtraAllocSize;
size_t bucketIdx = realSize >> WTF::kBucketShift;
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
size_t numSlots = (bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / realSize;
void* first = 0;
void* last = 0;
size_t i;
for (i = 0; i < numSlots; ++i) {
void* ptr = partitionAlloc(allocator.root(), size);
EXPECT_TRUE(ptr);
if (!i)
first = WTF::partitionCookieFreePointerAdjust(ptr);
else if (i == numSlots - 1)
last = WTF::partitionCookieFreePointerAdjust(ptr);
}
EXPECT_EQ(WTF::partitionPointerToPage(first), WTF::partitionPointerToPage(last));
if (bucket->numSystemPagesPerSlotSpan == WTF::kNumSystemPagesPerPartitionPage)
EXPECT_EQ(reinterpret_cast<size_t>(first) & WTF::kPartitionPageBaseMask, reinterpret_cast<size_t>(last) & WTF::kPartitionPageBaseMask);
EXPECT_EQ(numSlots, static_cast<size_t>(bucket->activePagesHead->numAllocatedSlots));
EXPECT_EQ(0, bucket->activePagesHead->freelistHead);
EXPECT_TRUE(bucket->activePagesHead);
EXPECT_TRUE(bucket->activePagesHead != &WTF::PartitionRootGeneric::gSeedPage);
return bucket->activePagesHead;
}
static void FreeFullPage(WTF::PartitionPage* page)
{
size_t size = page->bucket->slotSize;
size_t numSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / size;
EXPECT_EQ(numSlots, static_cast<size_t>(abs(page->numAllocatedSlots)));
char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
size_t i;
for (i = 0; i < numSlots; ++i) {
partitionFree(ptr + kPointerOffset);
ptr += size;
}
}
static void CycleFreeCache(size_t size)
{
size_t realSize = size + kExtraAllocSize;
size_t bucketIdx = realSize >> WTF::kBucketShift;
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
ASSERT(!bucket->activePagesHead->numAllocatedSlots);
for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) {
void* ptr = partitionAlloc(allocator.root(), size);
EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
partitionFree(ptr);
EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
EXPECT_NE(-1, bucket->activePagesHead->freeCacheIndex);
}
}
static void CycleGenericFreeCache(size_t size)
{
for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) {
void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
WTF::PartitionBucket* bucket = page->bucket;
EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
partitionFreeGeneric(genericAllocator.root(), ptr);
EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
EXPECT_NE(-1, bucket->activePagesHead->freeCacheIndex);
}
}
TEST(WTF_PartitionAlloc, Basic)
{
TestSetup();
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
WTF::PartitionPage* seedPage = &WTF::PartitionRootGeneric::gSeedPage;
EXPECT_FALSE(bucket->freePagesHead);
EXPECT_EQ(seedPage, bucket->activePagesHead);
EXPECT_EQ(0, bucket->activePagesHead->nextPage);
void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
EXPECT_TRUE(ptr);
EXPECT_EQ(kPointerOffset, reinterpret_cast<size_t>(ptr) & WTF::kPartitionPageOffsetMask);
EXPECT_EQ(WTF::kPartitionPageSize + kPointerOffset, reinterpret_cast<size_t>(ptr) & WTF::kSuperPageOffsetMask);
partitionFree(ptr);
EXPECT_FALSE(bucket->freePagesHead);
TestShutdown();
}
TEST(WTF_PartitionAlloc, SimpleLeak)
{
TestSetup();
void* leakedPtr = partitionAlloc(allocator.root(), kTestAllocSize);
(void)leakedPtr;
void* leakedPtr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
(void)leakedPtr2;
EXPECT_FALSE(allocator.shutdown());
EXPECT_FALSE(genericAllocator.shutdown());
}
TEST(WTF_PartitionAlloc, MultiAlloc)
{
TestSetup();
char* ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
char* ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
EXPECT_TRUE(ptr1);
EXPECT_TRUE(ptr2);
ptrdiff_t diff = ptr2 - ptr1;
EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
partitionFree(ptr2);
ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
EXPECT_TRUE(ptr2);
diff = ptr2 - ptr1;
EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
partitionFree(ptr1);
ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
EXPECT_TRUE(ptr1);
diff = ptr2 - ptr1;
EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
char* ptr3 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
EXPECT_TRUE(ptr3);
diff = ptr3 - ptr1;
EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize * 2), diff);
partitionFree(ptr1);
partitionFree(ptr2);
partitionFree(ptr3);
TestShutdown();
}
TEST(WTF_PartitionAlloc, MultiPages)
{
TestSetup();
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
WTF::PartitionPage* page = GetFullPage(kTestAllocSize);
FreeFullPage(page);
EXPECT_FALSE(bucket->freePagesHead);
EXPECT_EQ(page, bucket->activePagesHead);
EXPECT_EQ(0, page->nextPage);
EXPECT_EQ(0, page->numAllocatedSlots);
page = GetFullPage(kTestAllocSize);
WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize);
EXPECT_EQ(page2, bucket->activePagesHead);
EXPECT_EQ(0, page2->nextPage);
EXPECT_EQ(reinterpret_cast<uintptr_t>(partitionPageToPointer(page)) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(page2)) & WTF::kSuperPageBaseMask);
FreeFullPage(page);
EXPECT_EQ(0, page->numAllocatedSlots);
EXPECT_FALSE(bucket->freePagesHead);
EXPECT_EQ(page, bucket->activePagesHead);
page = GetFullPage(kTestAllocSize);
EXPECT_FALSE(bucket->freePagesHead);
EXPECT_EQ(page, bucket->activePagesHead);
FreeFullPage(page);
FreeFullPage(page2);
EXPECT_EQ(0, page->numAllocatedSlots);
EXPECT_EQ(0, page2->numAllocatedSlots);
EXPECT_EQ(0, page2->numUnprovisionedSlots);
EXPECT_NE(-1, page2->freeCacheIndex);
TestShutdown();
}
TEST(WTF_PartitionAlloc, PageTransitions)
{
TestSetup();
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize);
EXPECT_EQ(page1, bucket->activePagesHead);
EXPECT_EQ(0, page1->nextPage);
WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize);
EXPECT_EQ(page2, bucket->activePagesHead);
EXPECT_EQ(0, page2->nextPage);
char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerOffset;
partitionFree(ptr);
EXPECT_EQ(page1, bucket->activePagesHead);
(void) partitionAlloc(allocator.root(), kTestAllocSize);
EXPECT_EQ(page1, bucket->activePagesHead);
EXPECT_EQ(page2, bucket->activePagesHead->nextPage);
WTF::PartitionPage* page3 = GetFullPage(kTestAllocSize);
EXPECT_EQ(page3, bucket->activePagesHead);
EXPECT_EQ(0, page3->nextPage);
ptr = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffset;
partitionFree(ptr);
char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
EXPECT_EQ(ptr, newPtr);
EXPECT_EQ(page2, bucket->activePagesHead);
EXPECT_EQ(page3, page2->nextPage);
ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerOffset;
partitionFree(ptr);
newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
EXPECT_EQ(ptr, newPtr);
EXPECT_EQ(page1, bucket->activePagesHead);
EXPECT_EQ(page2, page1->nextPage);
FreeFullPage(page3);
FreeFullPage(page2);
FreeFullPage(page1);
ptr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize));
partitionFree(ptr);
TestShutdown();
}
TEST(WTF_PartitionAlloc, FreePageListPageTransitions)
{
TestSetup();
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
size_t numToFillFreeListPage = WTF::kPartitionPageSize / (sizeof(WTF::PartitionPage) + kExtraAllocSize);
++numToFillFreeListPage;
OwnPtr<WTF::PartitionPage*[]> pages = adoptArrayPtr(new WTF::PartitionPage*[numToFillFreeListPage]);
size_t i;
for (i = 0; i < numToFillFreeListPage; ++i) {
pages[i] = GetFullPage(kTestAllocSize);
}
EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead);
for (i = 0; i < numToFillFreeListPage; ++i)
FreeFullPage(pages[i]);
EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
EXPECT_NE(-1, bucket->activePagesHead->nextPage->freeCacheIndex);
EXPECT_EQ(0, bucket->activePagesHead->nextPage->numAllocatedSlots);
EXPECT_EQ(0, bucket->activePagesHead->nextPage->numUnprovisionedSlots);
WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize * 2);
WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize * 2);
FreeFullPage(page1);
FreeFullPage(page2);
for (i = 0; i < numToFillFreeListPage; ++i) {
pages[i] = GetFullPage(kTestAllocSize);
}
EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead);
for (i = 0; i < numToFillFreeListPage; ++i)
FreeFullPage(pages[i]);
EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
EXPECT_NE(-1, bucket->activePagesHead->nextPage->freeCacheIndex);
EXPECT_EQ(0, bucket->activePagesHead->nextPage->numAllocatedSlots);
EXPECT_EQ(0, bucket->activePagesHead->nextPage->numUnprovisionedSlots);
TestShutdown();
}
TEST(WTF_PartitionAlloc, MultiPageAllocs)
{
TestSetup();
size_t numPagesNeeded = WTF::kNumPartitionPagesPerSuperPage;
--numPagesNeeded;
EXPECT_GT(numPagesNeeded, 1u);
OwnPtr<WTF::PartitionPage*[]> pages;
pages = adoptArrayPtr(new WTF::PartitionPage*[numPagesNeeded]);
uintptr_t firstSuperPageBase = 0;
size_t i;
for (i = 0; i < numPagesNeeded; ++i) {
pages[i] = GetFullPage(kTestAllocSize);
void* storagePtr = partitionPageToPointer(pages[i]);
if (!i)
firstSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & WTF::kSuperPageBaseMask;
if (i == numPagesNeeded - 1) {
uintptr_t secondSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & WTF::kSuperPageBaseMask;
uintptr_t secondSuperPageOffset = reinterpret_cast<uintptr_t>(storagePtr) & WTF::kSuperPageOffsetMask;
EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase);
EXPECT_EQ(WTF::kPartitionPageSize, secondSuperPageOffset);
}
}
for (i = 0; i < numPagesNeeded; ++i)
FreeFullPage(pages[i]);
TestShutdown();
}
TEST(WTF_PartitionAlloc, GenericAlloc)
{
TestSetup();
void* ptr = partitionAllocGeneric(genericAllocator.root(), 1);
EXPECT_TRUE(ptr);
partitionFreeGeneric(genericAllocator.root(), ptr);
ptr = partitionAllocGeneric(genericAllocator.root(), WTF::kGenericMaxBucketed + 1);
EXPECT_TRUE(ptr);
partitionFreeGeneric(genericAllocator.root(), ptr);
ptr = partitionAllocGeneric(genericAllocator.root(), 1);
EXPECT_TRUE(ptr);
void* origPtr = ptr;
char* charPtr = static_cast<char*>(ptr);
*charPtr = 'A';
void* newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 2);
EXPECT_EQ(ptr, newPtr);
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
EXPECT_EQ(ptr, newPtr);
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericSmallestBucket);
EXPECT_EQ(ptr, newPtr);
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericSmallestBucket + 1);
EXPECT_NE(newPtr, ptr);
char* newCharPtr = static_cast<char*>(newPtr);
EXPECT_EQ(*newCharPtr, 'A');
#ifndef NDEBUG
EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(*(newCharPtr + WTF::kGenericSmallestBucket)));
#endif
*newCharPtr = 'B';
void* reusedPtr = partitionAllocGeneric(genericAllocator.root(), 1);
EXPECT_EQ(reusedPtr, origPtr);
partitionFreeGeneric(genericAllocator.root(), reusedPtr);
ptr = newPtr;
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
EXPECT_EQ(newPtr, origPtr);
newCharPtr = static_cast<char*>(newPtr);
EXPECT_EQ(*newCharPtr, 'B');
*newCharPtr = 'C';
ptr = newPtr;
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed + 1);
EXPECT_NE(newPtr, ptr);
newCharPtr = static_cast<char*>(newPtr);
EXPECT_EQ(*newCharPtr, 'C');
*newCharPtr = 'D';
ptr = newPtr;
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed * 10);
newCharPtr = static_cast<char*>(newPtr);
EXPECT_EQ(*newCharPtr, 'D');
*newCharPtr = 'E';
ptr = newPtr;
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed * 2);
newCharPtr = static_cast<char*>(newPtr);
EXPECT_EQ(*newCharPtr, 'E');
*newCharPtr = 'F';
ptr = newPtr;
newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
EXPECT_NE(newPtr, ptr);
EXPECT_EQ(newPtr, origPtr);
newCharPtr = static_cast<char*>(newPtr);
EXPECT_EQ(*newCharPtr, 'F');
partitionFreeGeneric(genericAllocator.root(), newPtr);
TestShutdown();
}
TEST(WTF_PartitionAlloc, GenericAllocSizes)
{
TestSetup();
void* ptr = partitionAllocGeneric(genericAllocator.root(), 0);
EXPECT_TRUE(ptr);
partitionFreeGeneric(genericAllocator.root(), ptr);
size_t size = WTF::kPartitionPageSize - kExtraAllocSize;
ptr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr);
void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr2);
partitionFreeGeneric(genericAllocator.root(), ptr);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_NE(-1, page->freeCacheIndex);
partitionFreeGeneric(genericAllocator.root(), ptr2);
size = (((WTF::kPartitionPageSize * WTF::kMaxPartitionPagesPerSlotSpan) - WTF::kSystemPageSize) / 2) - kExtraAllocSize;
ptr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr);
memset(ptr, 'A', size);
ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr2);
void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr3);
void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr4);
page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr3));
EXPECT_NE(page, page2);
partitionFreeGeneric(genericAllocator.root(), ptr);
partitionFreeGeneric(genericAllocator.root(), ptr3);
partitionFreeGeneric(genericAllocator.root(), ptr2);
EXPECT_NE(-1, page->freeCacheIndex);
EXPECT_EQ(0, page->numAllocatedSlots);
EXPECT_EQ(0, page->numUnprovisionedSlots);
void* newPtr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_EQ(ptr3, newPtr);
newPtr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_EQ(ptr2, newPtr);
#if OS(LINUX) && defined(NDEBUG)
EXPECT_EQ(0, *(reinterpret_cast<char*>(newPtr) + (size - 1)));
#endif
partitionFreeGeneric(genericAllocator.root(), newPtr);
partitionFreeGeneric(genericAllocator.root(), ptr3);
partitionFreeGeneric(genericAllocator.root(), ptr4);
ptr = partitionAllocGeneric(genericAllocator.root(), 512 * 1024 * 1024);
partitionFreeGeneric(genericAllocator.root(), ptr);
size = 20 * 1024 * 1024;
size -= WTF::kSystemPageSize;
size -= 1;
ptr = partitionAllocGeneric(genericAllocator.root(), size);
char* charPtr = reinterpret_cast<char*>(ptr);
*(charPtr + (size - 1)) = 'A';
partitionFreeGeneric(genericAllocator.root(), ptr);
partitionFreeGeneric(genericAllocator.root(), 0);
EXPECT_EQ(0, partitionAllocGenericFlags(genericAllocator.root(), WTF::PartitionAllocReturnNull, 3u * 1024 * 1024 * 1024));
TestShutdown();
}
TEST(WTF_PartitionAlloc, GenericAllocGetSize)
{
TestSetup();
void* ptr;
size_t requestedSize, actualSize, predictedSize;
EXPECT_TRUE(partitionAllocSupportsGetSize());
requestedSize = 511 - kExtraAllocSize;
predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
EXPECT_TRUE(ptr);
actualSize = partitionAllocGetSize(ptr);
EXPECT_EQ(predictedSize, actualSize);
EXPECT_LT(requestedSize, actualSize);
partitionFreeGeneric(genericAllocator.root(), ptr);
requestedSize = (256 * 1024) - kExtraAllocSize;
predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
EXPECT_TRUE(ptr);
actualSize = partitionAllocGetSize(ptr);
EXPECT_EQ(predictedSize, actualSize);
EXPECT_EQ(requestedSize, actualSize);
partitionFreeGeneric(genericAllocator.root(), ptr);
requestedSize = (256 * 1024) - WTF::kSystemPageSize - kExtraAllocSize;
predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
EXPECT_TRUE(ptr);
actualSize = partitionAllocGetSize(ptr);
EXPECT_EQ(predictedSize, actualSize);
EXPECT_EQ(requestedSize + WTF::kSystemPageSize, actualSize);
char* charPtr = reinterpret_cast<char*>(ptr);
*(charPtr + (actualSize - 1)) = 'A';
partitionFreeGeneric(genericAllocator.root(), ptr);
requestedSize = 512 * 1024 * 1024 - 1;
predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
EXPECT_TRUE(ptr);
actualSize = partitionAllocGetSize(ptr);
EXPECT_EQ(predictedSize, actualSize);
EXPECT_LT(requestedSize, actualSize);
partitionFreeGeneric(genericAllocator.root(), ptr);
requestedSize = INT_MAX;
predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSize);
EXPECT_EQ(requestedSize, predictedSize);
TestShutdown();
}
TEST(WTF_PartitionAlloc, Realloc)
{
TestSetup();
void* ptr = partitionReallocGeneric(genericAllocator.root(), 0, kTestAllocSize);
memset(ptr, 'A', kTestAllocSize);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
void* ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, 0);
EXPECT_EQ(0, ptr2);
EXPECT_EQ(WTF::partitionCookieFreePointerAdjust(ptr), page->freelistHead);
size_t size = WTF::kSystemPageSize - kExtraAllocSize;
EXPECT_EQ(size, partitionAllocActualSize(genericAllocator.root(), size));
ptr = partitionAllocGeneric(genericAllocator.root(), size);
memset(ptr, 'A', size);
ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, size + 1);
EXPECT_NE(ptr, ptr2);
char* charPtr2 = static_cast<char*>(ptr2);
EXPECT_EQ('A', charPtr2[0]);
EXPECT_EQ('A', charPtr2[size - 1]);
#ifndef NDEBUG
EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(charPtr2[size]));
#endif
ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - 1);
EXPECT_NE(ptr2, ptr);
char* charPtr = static_cast<char*>(ptr);
EXPECT_EQ('A', charPtr[0]);
EXPECT_EQ('A', charPtr[size - 2]);
#ifndef NDEBUG
EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1]));
#endif
partitionFreeGeneric(genericAllocator.root(), ptr);
size = WTF::kGenericMaxBucketed + 16 * WTF::kSystemPageSize;
ptr = partitionAllocGeneric(genericAllocator.root(), size);
size_t actualSize = partitionAllocGetSize(ptr);
ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMaxBucketed - 16 * WTF::kSystemPageSize);
EXPECT_EQ(ptr, ptr2);
EXPECT_EQ(actualSize - 32 * WTF::kSystemPageSize, partitionAllocGetSize(ptr2));
ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - WTF::kSystemPageSize);
EXPECT_EQ(ptr2, ptr);
EXPECT_EQ(actualSize - WTF::kSystemPageSize, partitionAllocGetSize(ptr));
partitionFreeGeneric(genericAllocator.root(), ptr);
TestShutdown();
}
TEST(WTF_PartitionAlloc, PartialPageFreelists)
{
TestSetup();
size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
EXPECT_EQ(WTF::kSystemPageSize - WTF::kAllocationGranularity, bigSize + kExtraAllocSize);
size_t bucketIdx = (bigSize + kExtraAllocSize) >> WTF::kBucketShift;
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
EXPECT_EQ(0, bucket->freePagesHead);
void* ptr = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(ptr);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
size_t totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (bigSize + kExtraAllocSize);
EXPECT_EQ(4u, totalSlots);
EXPECT_TRUE(page->freelistHead);
EXPECT_EQ(1, page->numAllocatedSlots);
EXPECT_EQ(2, page->numUnprovisionedSlots);
void* ptr2 = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(ptr2);
EXPECT_FALSE(page->freelistHead);
EXPECT_EQ(2, page->numAllocatedSlots);
EXPECT_EQ(2, page->numUnprovisionedSlots);
void* ptr3 = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(ptr3);
EXPECT_TRUE(page->freelistHead);
EXPECT_EQ(3, page->numAllocatedSlots);
EXPECT_EQ(0, page->numUnprovisionedSlots);
void* ptr4 = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(ptr4);
EXPECT_FALSE(page->freelistHead);
EXPECT_EQ(4, page->numAllocatedSlots);
EXPECT_EQ(0, page->numUnprovisionedSlots);
void* ptr5 = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(ptr5);
WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr5));
EXPECT_EQ(1, page2->numAllocatedSlots);
partitionFree(ptr);
ptr = partitionAlloc(allocator.root(), bigSize);
void* ptr6 = partitionAlloc(allocator.root(), bigSize);
partitionFree(ptr);
partitionFree(ptr2);
partitionFree(ptr3);
partitionFree(ptr4);
partitionFree(ptr5);
partitionFree(ptr6);
EXPECT_NE(-1, page->freeCacheIndex);
EXPECT_NE(-1, page2->freeCacheIndex);
EXPECT_TRUE(page2->freelistHead);
EXPECT_EQ(0, page2->numAllocatedSlots);
size_t mediumSize = (WTF::kSystemPageSize / 2) - kExtraAllocSize;
bucketIdx = (mediumSize + kExtraAllocSize) >> WTF::kBucketShift;
bucket = &allocator.root()->buckets()[bucketIdx];
EXPECT_EQ(0, bucket->freePagesHead);
ptr = partitionAlloc(allocator.root(), mediumSize);
EXPECT_TRUE(ptr);
page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(1, page->numAllocatedSlots);
totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (mediumSize + kExtraAllocSize);
size_t firstPageSlots = WTF::kSystemPageSize / (mediumSize + kExtraAllocSize);
EXPECT_EQ(2u, firstPageSlots);
EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
partitionFree(ptr);
size_t smallSize = (WTF::kSystemPageSize / 4) - kExtraAllocSize;
bucketIdx = (smallSize + kExtraAllocSize) >> WTF::kBucketShift;
bucket = &allocator.root()->buckets()[bucketIdx];
EXPECT_EQ(0, bucket->freePagesHead);
ptr = partitionAlloc(allocator.root(), smallSize);
EXPECT_TRUE(ptr);
page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(1, page->numAllocatedSlots);
totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (smallSize + kExtraAllocSize);
firstPageSlots = WTF::kSystemPageSize / (smallSize + kExtraAllocSize);
EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
partitionFree(ptr);
EXPECT_TRUE(page->freelistHead);
EXPECT_EQ(0, page->numAllocatedSlots);
size_t verySmallSize = 32 - kExtraAllocSize;
bucketIdx = (verySmallSize + kExtraAllocSize) >> WTF::kBucketShift;
bucket = &allocator.root()->buckets()[bucketIdx];
EXPECT_EQ(0, bucket->freePagesHead);
ptr = partitionAlloc(allocator.root(), verySmallSize);
EXPECT_TRUE(ptr);
page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(1, page->numAllocatedSlots);
totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (verySmallSize + kExtraAllocSize);
firstPageSlots = WTF::kSystemPageSize / (verySmallSize + kExtraAllocSize);
EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
partitionFree(ptr);
EXPECT_TRUE(page->freelistHead);
EXPECT_EQ(0, page->numAllocatedSlots);
size_t pageAndAHalfSize = (WTF::kSystemPageSize + (WTF::kSystemPageSize / 2)) - kExtraAllocSize;
ptr = partitionAllocGeneric(genericAllocator.root(), pageAndAHalfSize);
EXPECT_TRUE(ptr);
page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(1, page->numAllocatedSlots);
EXPECT_TRUE(page->freelistHead);
totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (pageAndAHalfSize + kExtraAllocSize);
EXPECT_EQ(totalSlots - 2, page->numUnprovisionedSlots);
partitionFreeGeneric(genericAllocator.root(), ptr);
size_t pageSize = WTF::kSystemPageSize - kExtraAllocSize;
ptr = partitionAllocGeneric(genericAllocator.root(), pageSize);
EXPECT_TRUE(ptr);
page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(1, page->numAllocatedSlots);
EXPECT_FALSE(page->freelistHead);
totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / (pageSize + kExtraAllocSize);
EXPECT_EQ(totalSlots - 1, page->numUnprovisionedSlots);
partitionFreeGeneric(genericAllocator.root(), ptr);
TestShutdown();
}
TEST(WTF_PartitionAlloc, PageRefilling)
{
TestSetup();
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize);
WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize);
void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
EXPECT_TRUE(ptr);
EXPECT_NE(page1, bucket->activePagesHead);
EXPECT_NE(page2, bucket->activePagesHead);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(1, page->numAllocatedSlots);
char* ptr2 = reinterpret_cast<char*>(WTF::partitionPageToPointer(page1)) + kPointerOffset;
partitionFree(ptr2);
ptr2 = reinterpret_cast<char*>(WTF::partitionPageToPointer(page2)) + kPointerOffset;
partitionFree(ptr2);
(void) partitionAlloc(allocator.root(), kTestAllocSize);
(void) partitionAlloc(allocator.root(), kTestAllocSize);
EXPECT_EQ(1, page->numAllocatedSlots);
FreeFullPage(page2);
FreeFullPage(page1);
partitionFree(ptr);
TestShutdown();
}
TEST(WTF_PartitionAlloc, PartialPages)
{
TestSetup();
size_t size = sizeof(void*);
WTF::PartitionBucket* bucket = 0;
while (size < kTestMaxAllocation) {
bucket = &allocator.root()->buckets()[size >> WTF::kBucketShift];
if (bucket->numSystemPagesPerSlotSpan % WTF::kNumSystemPagesPerPartitionPage)
break;
size += sizeof(void*);
}
EXPECT_LT(size, kTestMaxAllocation);
WTF::PartitionPage* page1 = GetFullPage(size);
WTF::PartitionPage* page2 = GetFullPage(size);
FreeFullPage(page2);
FreeFullPage(page1);
TestShutdown();
}
TEST(WTF_PartitionAlloc, MappingCollision)
{
TestSetup();
size_t numPartitionPagesNeeded = WTF::kNumPartitionPagesPerSuperPage - 2;
OwnPtr<WTF::PartitionPage*[]> firstSuperPagePages = adoptArrayPtr(new WTF::PartitionPage*[numPartitionPagesNeeded]);
OwnPtr<WTF::PartitionPage*[]> secondSuperPagePages = adoptArrayPtr(new WTF::PartitionPage*[numPartitionPagesNeeded]);
size_t i;
for (i = 0; i < numPartitionPagesNeeded; ++i)
firstSuperPagePages[i] = GetFullPage(kTestAllocSize);
char* pageBase = reinterpret_cast<char*>(WTF::partitionPageToPointer(firstSuperPagePages[0]));
EXPECT_EQ(WTF::kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & WTF::kSuperPageOffsetMask);
pageBase -= WTF::kPartitionPageSize;
void* map1 = WTF::allocPages(pageBase - WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
EXPECT_TRUE(map1);
void* map2 = WTF::allocPages(pageBase + WTF::kSuperPageSize, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
EXPECT_TRUE(map2);
WTF::setSystemPagesInaccessible(map1, WTF::kPageAllocationGranularity);
WTF::setSystemPagesInaccessible(map2, WTF::kPageAllocationGranularity);
for (i = 0; i < numPartitionPagesNeeded; ++i)
secondSuperPagePages[i] = GetFullPage(kTestAllocSize);
WTF::freePages(map1, WTF::kPageAllocationGranularity);
WTF::freePages(map2, WTF::kPageAllocationGranularity);
pageBase = reinterpret_cast<char*>(partitionPageToPointer(secondSuperPagePages[0]));
EXPECT_EQ(WTF::kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & WTF::kSuperPageOffsetMask);
pageBase -= WTF::kPartitionPageSize;
map1 = WTF::allocPages(pageBase - WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
EXPECT_TRUE(map1);
map2 = WTF::allocPages(pageBase + WTF::kSuperPageSize, WTF::kPageAllocationGranularity, WTF::kPageAllocationGranularity);
EXPECT_TRUE(map2);
WTF::setSystemPagesInaccessible(map1, WTF::kPageAllocationGranularity);
WTF::setSystemPagesInaccessible(map2, WTF::kPageAllocationGranularity);
WTF::PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize);
WTF::freePages(map1, WTF::kPageAllocationGranularity);
WTF::freePages(map2, WTF::kPageAllocationGranularity);
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSuperPage)) & WTF::kPartitionPageOffsetMask);
EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(firstSuperPagePages[0])) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSuperPage)) & WTF::kSuperPageBaseMask);
EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(secondSuperPagePages[0])) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSuperPage)) & WTF::kSuperPageBaseMask);
FreeFullPage(pageInThirdSuperPage);
for (i = 0; i < numPartitionPagesNeeded; ++i) {
FreeFullPage(firstSuperPagePages[i]);
FreeFullPage(secondSuperPagePages[i]);
}
TestShutdown();
}
TEST(WTF_PartitionAlloc, FreeCache)
{
TestSetup();
size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
size_t bucketIdx = (bigSize + kExtraAllocSize) >> WTF::kBucketShift;
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
void* ptr = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(ptr);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
EXPECT_EQ(0, bucket->freePagesHead);
EXPECT_EQ(1, page->numAllocatedSlots);
partitionFree(ptr);
EXPECT_EQ(0, page->numAllocatedSlots);
EXPECT_NE(-1, page->freeCacheIndex);
EXPECT_TRUE(page->freelistHead);
CycleFreeCache(kTestAllocSize);
EXPECT_FALSE(page->freelistHead);
EXPECT_EQ(-1, page->freeCacheIndex);
EXPECT_EQ(0, page->numAllocatedSlots);
ptr = partitionAlloc(allocator.root(), bigSize);
EXPECT_FALSE(bucket->freePagesHead);
partitionFree(ptr);
for (size_t i = 0; i < WTF::kMaxFreeableSpans * 2; ++i) {
ptr = partitionAlloc(allocator.root(), bigSize);
EXPECT_TRUE(page->freelistHead);
partitionFree(ptr);
EXPECT_TRUE(page->freelistHead);
}
TestShutdown();
}
TEST(WTF_PartitionAlloc, LostFreePagesBug)
{
TestSetup();
size_t size = WTF::kPartitionPageSize - kExtraAllocSize;
void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr);
void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr2);
WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr2));
WTF::PartitionBucket* bucket = page->bucket;
EXPECT_EQ(0, bucket->freePagesHead);
EXPECT_EQ(-1, page->numAllocatedSlots);
EXPECT_EQ(1, page2->numAllocatedSlots);
partitionFreeGeneric(genericAllocator.root(), ptr);
partitionFreeGeneric(genericAllocator.root(), ptr2);
EXPECT_EQ(0, bucket->freePagesHead);
EXPECT_EQ(0, page->numAllocatedSlots);
EXPECT_EQ(0, page2->numAllocatedSlots);
EXPECT_TRUE(page->freelistHead);
EXPECT_TRUE(page2->freelistHead);
CycleGenericFreeCache(kTestAllocSize);
EXPECT_FALSE(page->freelistHead);
EXPECT_FALSE(page2->freelistHead);
EXPECT_FALSE(bucket->freePagesHead);
EXPECT_TRUE(bucket->activePagesHead);
EXPECT_TRUE(bucket->activePagesHead->nextPage);
ptr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr);
partitionFreeGeneric(genericAllocator.root(), ptr);
EXPECT_TRUE(bucket->activePagesHead);
EXPECT_TRUE(bucket->freePagesHead);
CycleGenericFreeCache(kTestAllocSize);
ptr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr);
partitionFreeGeneric(genericAllocator.root(), ptr);
EXPECT_TRUE(bucket->activePagesHead);
EXPECT_TRUE(bucket->freePagesHead);
TestShutdown();
}
#if !OS(ANDROID)
TEST(WTF_PartitionAllocDeathTest, LargeAllocs)
{
TestSetup();
EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size_t>(-1)), "");
EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size_t>(INT_MAX) + 1), "");
TestShutdown();
}
TEST(WTF_PartitionAllocDeathTest, ImmediateDoubleFree)
{
TestSetup();
void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
EXPECT_TRUE(ptr);
partitionFreeGeneric(genericAllocator.root(), ptr);
EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), "");
TestShutdown();
}
TEST(WTF_PartitionAllocDeathTest, RefcountDoubleFree)
{
TestSetup();
void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
EXPECT_TRUE(ptr);
void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
EXPECT_TRUE(ptr2);
partitionFreeGeneric(genericAllocator.root(), ptr);
partitionFreeGeneric(genericAllocator.root(), ptr2);
EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), "");
TestShutdown();
}
TEST(WTF_PartitionAllocDeathTest, GuardPages)
{
TestSetup();
size_t size = (WTF::kGenericMaxBucketed + WTF::kSystemPageSize) - kExtraAllocSize;
void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
EXPECT_TRUE(ptr);
char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset;
EXPECT_DEATH(*(charPtr - 1) = 'A', "");
EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', "");
partitionFreeGeneric(genericAllocator.root(), ptr);
TestShutdown();
}
#endif
TEST(WTF_PartitionAlloc, CLZWorks)
{
EXPECT_EQ(32u, WTF::countLeadingZeros32(0));
EXPECT_EQ(31u, WTF::countLeadingZeros32(1));
EXPECT_EQ(1u, WTF::countLeadingZeros32(1 << 30));
EXPECT_EQ(0u, WTF::countLeadingZeros32(1 << 31));
#if CPU(64BIT)
EXPECT_EQ(64u, WTF::countLeadingZerosSizet(0ull));
EXPECT_EQ(63u, WTF::countLeadingZerosSizet(1ull));
EXPECT_EQ(32u, WTF::countLeadingZerosSizet(1ull << 31));
EXPECT_EQ(1u, WTF::countLeadingZerosSizet(1ull << 62));
EXPECT_EQ(0u, WTF::countLeadingZerosSizet(1ull << 63));
#else
EXPECT_EQ(32u, WTF::countLeadingZerosSizet(0));
EXPECT_EQ(31u, WTF::countLeadingZerosSizet(1));
EXPECT_EQ(1u, WTF::countLeadingZerosSizet(1 << 30));
EXPECT_EQ(0u, WTF::countLeadingZerosSizet(1 << 31));
#endif
}
}
#endif