Index: Source/wtf/PartitionAllocTest.cpp |
diff --git a/Source/wtf/PartitionAllocTest.cpp b/Source/wtf/PartitionAllocTest.cpp |
index 80a1fd137247018f2909b76806606b62a6622e91..f7f9f55b11568663ab272aa287d3db7a0633b2e2 100644 |
--- a/Source/wtf/PartitionAllocTest.cpp |
+++ b/Source/wtf/PartitionAllocTest.cpp |
@@ -218,20 +218,30 @@ TEST(WTF_PartitionAlloc, PageTransitions) |
WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
WTF::PartitionPageHeader* page1 = GetFullPage(kTestAllocSize); |
+ EXPECT_EQ(page1, bucket->currPage); |
+ EXPECT_EQ(page1, page1->next); |
+ EXPECT_EQ(page1, page1->prev); |
WTF::PartitionPageHeader* page2 = GetFullPage(kTestAllocSize); |
EXPECT_EQ(page2, bucket->currPage); |
- EXPECT_EQ(page1, page2->next); |
- EXPECT_EQ(page1, page2->prev); |
+ EXPECT_EQ(page2, page2->next); |
+ EXPECT_EQ(page2, page2->prev); |
+ |
+ // Bounce page1 back into the non-full list then fill it up again. |
+ char* ptr = reinterpret_cast<char*>(page1) + sizeof(WTF::PartitionPageHeader); |
+ partitionFree(ptr); |
+ (void) partitionAlloc(allocator.root(), kTestAllocSize); |
+ EXPECT_EQ(page1, bucket->currPage); |
+ |
// Allocating another page at this point should cause us to scan over page1 |
// (which is both full and NOT our current page), and evict it from the |
// freelist. Older code had a O(n^2) condition due to failure to do this. |
WTF::PartitionPageHeader* page3 = GetFullPage(kTestAllocSize); |
EXPECT_EQ(page3, bucket->currPage); |
- EXPECT_EQ(page2, page3->next); |
- EXPECT_EQ(page3, page2->next); |
+ EXPECT_EQ(page3, page3->next); |
+ EXPECT_EQ(page3, page3->next); |
// Work out a pointer into page2 and free it. |
- char* ptr = reinterpret_cast<char*>(page2) + sizeof(WTF::PartitionPageHeader); |
+ ptr = reinterpret_cast<char*>(page2) + sizeof(WTF::PartitionPageHeader); |
partitionFree(ptr); |
// Trying to allocate at this time should cause us to cycle around to page2 |
// and find the recently freed slot. |
@@ -469,10 +479,16 @@ TEST(WTF_PartitionAlloc, PartialPageFreelists) |
WTF::PartitionPageHeader* page2 = reinterpret_cast<WTF::PartitionPageHeader*>(reinterpret_cast<size_t>(ptr4) & WTF::kPartitionPageBaseMask); |
EXPECT_EQ(1, page2->numAllocatedSlots); |
+ // Churn things a little whilst there's a partial page freelist. |
+ partitionFree(ptr); |
+ ptr = partitionAlloc(allocator.root(), bigSize); |
+ void* ptr5 = partitionAlloc(allocator.root(), bigSize); |
+ |
partitionFree(ptr); |
partitionFree(ptr2); |
partitionFree(ptr3); |
partitionFree(ptr4); |
+ partitionFree(ptr5); |
EXPECT_TRUE(bucket->freePages); |
EXPECT_EQ(page, bucket->freePages->page); |
EXPECT_TRUE(page2->freelistHead); |
@@ -529,6 +545,42 @@ TEST(WTF_PartitionAlloc, PartialPageFreelists) |
TestShutdown(); |
} |
+// Test some of the fragmentation-resistant properties of the allocator. |
+TEST(WTF_PartitionAlloc, PageRefilling) |
+{ |
+ TestSetup(); |
+ size_t bucketIdx = kTestAllocSize >> WTF::kBucketShift; |
+ WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
+ |
+ // Grab two full pages and a non-full page. |
+ WTF::PartitionPageHeader* page1 = GetFullPage(kTestAllocSize); |
+ WTF::PartitionPageHeader* page2 = GetFullPage(kTestAllocSize); |
+ void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); |
+ EXPECT_TRUE(ptr); |
+ EXPECT_NE(page1, bucket->currPage); |
+ EXPECT_NE(page2, bucket->currPage); |
+ WTF::PartitionPageHeader* page = reinterpret_cast<WTF::PartitionPageHeader*>(reinterpret_cast<size_t>(ptr) & WTF::kPartitionPageBaseMask); |
+ EXPECT_EQ(1, page->numAllocatedSlots); |
+ |
+ // Work out a pointer into page2 and free it; and then page1 and free it. |
+ char* ptr2 = reinterpret_cast<char*>(page1) + sizeof(WTF::PartitionPageHeader); |
+ partitionFree(ptr2); |
+ ptr2 = reinterpret_cast<char*>(page2) + sizeof(WTF::PartitionPageHeader); |
+ partitionFree(ptr2); |
+ |
+ // If we perform two allocations from the same bucket now, we expect to |
+ // refill both the nearly full pages. |
+ (void) partitionAlloc(allocator.root(), kTestAllocSize); |
+ (void) partitionAlloc(allocator.root(), kTestAllocSize); |
+ EXPECT_EQ(1, page->numAllocatedSlots); |
+ |
+ FreeFullPage(page2, kTestAllocSize); |
+ FreeFullPage(page1, kTestAllocSize); |
+ partitionFree(ptr); |
+ |
+ TestShutdown(); |
+} |
+ |
#if OS(POSIX) |
// Test correct handling if our mapping collides with another. |