Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 #include <sys/resource.h> | 45 #include <sys/resource.h> |
| 46 #include <sys/time.h> | 46 #include <sys/time.h> |
| 47 | 47 |
| 48 #ifndef MAP_ANONYMOUS | 48 #ifndef MAP_ANONYMOUS |
| 49 #define MAP_ANONYMOUS MAP_ANON | 49 #define MAP_ANONYMOUS MAP_ANON |
| 50 #endif | 50 #endif |
| 51 #endif // OS(POSIX) | 51 #endif // OS(POSIX) |
| 52 | 52 |
| 53 #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 53 #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 54 | 54 |
| 55 namespace { | 55 namespace WTF { |
| 56 | 56 |
| 57 static const size_t kTestMaxAllocation = 4096; | 57 static const size_t kTestMaxAllocation = 4096; |
|
kochi
2015/06/15 03:34:22
How about using 'namespace {}' to remove all the '
tkent
2015/06/15 04:45:57
Done.
| |
| 58 static SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator; | 58 static SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator; |
| 59 static PartitionAllocatorGeneric genericAllocator; | 59 static PartitionAllocatorGeneric genericAllocator; |
| 60 | 60 |
| 61 static const size_t kTestAllocSize = 16; | 61 static const size_t kTestAllocSize = 16; |
| 62 #if !ENABLE(ASSERT) | 62 #if !ENABLE(ASSERT) |
| 63 static const size_t kPointerOffset = 0; | 63 static const size_t kPointerOffset = 0; |
| 64 static const size_t kExtraAllocSize = 0; | 64 static const size_t kExtraAllocSize = 0; |
| 65 #else | 65 #else |
| 66 static const size_t kPointerOffset = WTF::kCookieSize; | 66 static const size_t kPointerOffset = WTF::kCookieSize; |
| 67 static const size_t kExtraAllocSize = WTF::kCookieSize * 2; | 67 static const size_t kExtraAllocSize = WTF::kCookieSize * 2; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 116 return false; | 116 return false; |
| 117 limit.rlim_cur = limit.rlim_max; | 117 limit.rlim_cur = limit.rlim_max; |
| 118 if (setrlimit(RLIMIT_AS, &limit) != 0) | 118 if (setrlimit(RLIMIT_AS, &limit) != 0) |
| 119 return false; | 119 return false; |
| 120 return true; | 120 return true; |
| 121 #else | 121 #else |
| 122 return false; | 122 return false; |
| 123 #endif | 123 #endif |
| 124 } | 124 } |
| 125 | 125 |
| 126 static WTF::PartitionPage* GetFullPage(size_t size) | 126 static PartitionPage* GetFullPage(size_t size) |
| 127 { | 127 { |
| 128 size_t realSize = size + kExtraAllocSize; | 128 size_t realSize = size + kExtraAllocSize; |
| 129 size_t bucketIdx = realSize >> WTF::kBucketShift; | 129 size_t bucketIdx = realSize >> kBucketShift; |
| 130 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; | 130 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
| 131 size_t numSlots = (bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize) / realSize; | 131 size_t numSlots = (bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / re alSize; |
| 132 void* first = 0; | 132 void* first = 0; |
| 133 void* last = 0; | 133 void* last = 0; |
| 134 size_t i; | 134 size_t i; |
| 135 for (i = 0; i < numSlots; ++i) { | 135 for (i = 0; i < numSlots; ++i) { |
| 136 void* ptr = partitionAlloc(allocator.root(), size); | 136 void* ptr = partitionAlloc(allocator.root(), size); |
| 137 EXPECT_TRUE(ptr); | 137 EXPECT_TRUE(ptr); |
| 138 if (!i) | 138 if (!i) |
| 139 first = WTF::partitionCookieFreePointerAdjust(ptr); | 139 first = partitionCookieFreePointerAdjust(ptr); |
| 140 else if (i == numSlots - 1) | 140 else if (i == numSlots - 1) |
| 141 last = WTF::partitionCookieFreePointerAdjust(ptr); | 141 last = partitionCookieFreePointerAdjust(ptr); |
| 142 } | 142 } |
| 143 EXPECT_EQ(WTF::partitionPointerToPage(first), WTF::partitionPointerToPage(la st)); | 143 EXPECT_EQ(partitionPointerToPage(first), partitionPointerToPage(last)); |
| 144 if (bucket->numSystemPagesPerSlotSpan == WTF::kNumSystemPagesPerPartitionPag e) | 144 if (bucket->numSystemPagesPerSlotSpan == kNumSystemPagesPerPartitionPage) |
| 145 EXPECT_EQ(reinterpret_cast<size_t>(first) & WTF::kPartitionPageBaseMask, reinterpret_cast<size_t>(last) & WTF::kPartitionPageBaseMask); | 145 EXPECT_EQ(reinterpret_cast<size_t>(first) & kPartitionPageBaseMask, rein terpret_cast<size_t>(last) & kPartitionPageBaseMask); |
| 146 EXPECT_EQ(numSlots, static_cast<size_t>(bucket->activePagesHead->numAllocate dSlots)); | 146 EXPECT_EQ(numSlots, static_cast<size_t>(bucket->activePagesHead->numAllocate dSlots)); |
| 147 EXPECT_EQ(0, bucket->activePagesHead->freelistHead); | 147 EXPECT_EQ(0, bucket->activePagesHead->freelistHead); |
| 148 EXPECT_TRUE(bucket->activePagesHead); | 148 EXPECT_TRUE(bucket->activePagesHead); |
| 149 EXPECT_TRUE(bucket->activePagesHead != &WTF::PartitionRootGeneric::gSeedPage ); | 149 EXPECT_TRUE(bucket->activePagesHead != &PartitionRootGeneric::gSeedPage); |
| 150 return bucket->activePagesHead; | 150 return bucket->activePagesHead; |
| 151 } | 151 } |
| 152 | 152 |
| 153 static void FreeFullPage(WTF::PartitionPage* page) | 153 static void FreeFullPage(PartitionPage* page) |
| 154 { | 154 { |
| 155 size_t size = page->bucket->slotSize; | 155 size_t size = page->bucket->slotSize; |
| 156 size_t numSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPag eSize) / size; | 156 size_t numSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize ) / size; |
| 157 EXPECT_EQ(numSlots, static_cast<size_t>(abs(page->numAllocatedSlots))); | 157 EXPECT_EQ(numSlots, static_cast<size_t>(abs(page->numAllocatedSlots))); |
| 158 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | 158 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
| 159 size_t i; | 159 size_t i; |
| 160 for (i = 0; i < numSlots; ++i) { | 160 for (i = 0; i < numSlots; ++i) { |
| 161 partitionFree(ptr + kPointerOffset); | 161 partitionFree(ptr + kPointerOffset); |
| 162 ptr += size; | 162 ptr += size; |
| 163 } | 163 } |
| 164 } | 164 } |
| 165 | 165 |
| 166 static void CycleFreeCache(size_t size) | 166 static void CycleFreeCache(size_t size) |
| 167 { | 167 { |
| 168 size_t realSize = size + kExtraAllocSize; | 168 size_t realSize = size + kExtraAllocSize; |
| 169 size_t bucketIdx = realSize >> WTF::kBucketShift; | 169 size_t bucketIdx = realSize >> kBucketShift; |
| 170 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; | 170 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
| 171 ASSERT(!bucket->activePagesHead->numAllocatedSlots); | 171 ASSERT(!bucket->activePagesHead->numAllocatedSlots); |
| 172 | 172 |
| 173 for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) { | 173 for (size_t i = 0; i < kMaxFreeableSpans; ++i) { |
| 174 void* ptr = partitionAlloc(allocator.root(), size); | 174 void* ptr = partitionAlloc(allocator.root(), size); |
| 175 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots); | 175 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots); |
| 176 partitionFree(ptr); | 176 partitionFree(ptr); |
| 177 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots); | 177 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots); |
| 178 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex); | 178 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex); |
| 179 } | 179 } |
| 180 } | 180 } |
| 181 | 181 |
| 182 static void CycleGenericFreeCache(size_t size) | 182 static void CycleGenericFreeCache(size_t size) |
| 183 { | 183 { |
| 184 for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) { | 184 for (size_t i = 0; i < kMaxFreeableSpans; ++i) { |
| 185 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); | 185 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 186 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCoo kieFreePointerAdjust(ptr)); | 186 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerA djust(ptr)); |
| 187 WTF::PartitionBucket* bucket = page->bucket; | 187 PartitionBucket* bucket = page->bucket; |
| 188 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots); | 188 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots); |
| 189 partitionFreeGeneric(genericAllocator.root(), ptr); | 189 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 190 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots); | 190 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots); |
| 191 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex); | 191 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex); |
| 192 } | 192 } |
| 193 } | 193 } |
| 194 | 194 |
| 195 class MockPartitionStatsDumper : public WTF::PartitionStatsDumper { | 195 class MockPartitionStatsDumper : public PartitionStatsDumper { |
| 196 public: | 196 public: |
| 197 MockPartitionStatsDumper() | 197 MockPartitionStatsDumper() |
| 198 : m_totalResidentBytes(0) | 198 : m_totalResidentBytes(0) |
| 199 , m_totalActiveBytes(0) { } | 199 , m_totalActiveBytes(0) { } |
| 200 | 200 |
| 201 virtual void partitionsDumpBucketStats(const char* partitionName, const WTF: :PartitionBucketMemoryStats* memoryStats) override | 201 virtual void partitionsDumpBucketStats(const char* partitionName, const Part itionBucketMemoryStats* memoryStats) override |
| 202 { | 202 { |
| 203 (void) partitionName; | 203 (void) partitionName; |
| 204 EXPECT_TRUE(memoryStats->isValid); | 204 EXPECT_TRUE(memoryStats->isValid); |
| 205 EXPECT_EQ(0u, memoryStats->bucketSlotSize & WTF::kAllocationGranularityM ask); | 205 EXPECT_EQ(0u, memoryStats->bucketSlotSize & kAllocationGranularityMask); |
| 206 m_bucketStats.append(*memoryStats); | 206 m_bucketStats.append(*memoryStats); |
| 207 m_totalResidentBytes += memoryStats->residentBytes; | 207 m_totalResidentBytes += memoryStats->residentBytes; |
| 208 m_totalActiveBytes += memoryStats->activeBytes; | 208 m_totalActiveBytes += memoryStats->activeBytes; |
| 209 } | 209 } |
| 210 | 210 |
| 211 bool IsMemoryAllocationRecorded() | 211 bool IsMemoryAllocationRecorded() |
| 212 { | 212 { |
| 213 return m_totalResidentBytes != 0 && m_totalActiveBytes != 0; | 213 return m_totalResidentBytes != 0 && m_totalActiveBytes != 0; |
| 214 } | 214 } |
| 215 | 215 |
| 216 const WTF::PartitionBucketMemoryStats* GetBucketStats(size_t bucketSize) | 216 const PartitionBucketMemoryStats* GetBucketStats(size_t bucketSize) |
| 217 { | 217 { |
| 218 for (size_t i = 0; i < m_bucketStats.size(); ++i) { | 218 for (size_t i = 0; i < m_bucketStats.size(); ++i) { |
| 219 if (m_bucketStats[i].bucketSlotSize == bucketSize) | 219 if (m_bucketStats[i].bucketSlotSize == bucketSize) |
| 220 return &m_bucketStats[i]; | 220 return &m_bucketStats[i]; |
| 221 } | 221 } |
| 222 return 0; | 222 return 0; |
| 223 } | 223 } |
| 224 | 224 |
| 225 private: | 225 private: |
| 226 size_t m_totalResidentBytes; | 226 size_t m_totalResidentBytes; |
| 227 size_t m_totalActiveBytes; | 227 size_t m_totalActiveBytes; |
| 228 | 228 |
| 229 Vector<WTF::PartitionBucketMemoryStats> m_bucketStats; | 229 Vector<PartitionBucketMemoryStats> m_bucketStats; |
| 230 }; | 230 }; |
| 231 | 231 |
| 232 // Check that the most basic of allocate / free pairs work. | 232 // Check that the most basic of allocate / free pairs work. |
| 233 TEST(PartitionAllocTest, Basic) | 233 TEST(PartitionAllocTest, Basic) |
| 234 { | 234 { |
| 235 TestSetup(); | 235 TestSetup(); |
| 236 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex ]; | 236 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; |
| 237 WTF::PartitionPage* seedPage = &WTF::PartitionRootGeneric::gSeedPage; | 237 PartitionPage* seedPage = &PartitionRootGeneric::gSeedPage; |
| 238 | 238 |
| 239 EXPECT_FALSE(bucket->emptyPagesHead); | 239 EXPECT_FALSE(bucket->emptyPagesHead); |
| 240 EXPECT_EQ(seedPage, bucket->activePagesHead); | 240 EXPECT_EQ(seedPage, bucket->activePagesHead); |
| 241 EXPECT_EQ(0, bucket->activePagesHead->nextPage); | 241 EXPECT_EQ(0, bucket->activePagesHead->nextPage); |
| 242 | 242 |
| 243 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); | 243 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); |
| 244 EXPECT_TRUE(ptr); | 244 EXPECT_TRUE(ptr); |
| 245 EXPECT_EQ(kPointerOffset, reinterpret_cast<size_t>(ptr) & WTF::kPartitionPag eOffsetMask); | 245 EXPECT_EQ(kPointerOffset, reinterpret_cast<size_t>(ptr) & kPartitionPageOffs etMask); |
| 246 // Check that the offset appears to include a guard page. | 246 // Check that the offset appears to include a guard page. |
| 247 EXPECT_EQ(WTF::kPartitionPageSize + kPointerOffset, reinterpret_cast<size_t> (ptr) & WTF::kSuperPageOffsetMask); | 247 EXPECT_EQ(kPartitionPageSize + kPointerOffset, reinterpret_cast<size_t>(ptr) & kSuperPageOffsetMask); |
| 248 | 248 |
| 249 partitionFree(ptr); | 249 partitionFree(ptr); |
| 250 // Expect that the last active page does not get tossed to the freelist. | 250 // Expect that the last active page does not get tossed to the freelist. |
| 251 EXPECT_FALSE(bucket->emptyPagesHead); | 251 EXPECT_FALSE(bucket->emptyPagesHead); |
| 252 | 252 |
| 253 TestShutdown(); | 253 TestShutdown(); |
| 254 } | 254 } |
| 255 | 255 |
| 256 // Check that we can detect a memory leak. | 256 // Check that we can detect a memory leak. |
| 257 TEST(PartitionAllocTest, SimpleLeak) | 257 TEST(PartitionAllocTest, SimpleLeak) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 partitionFree(ptr2); | 298 partitionFree(ptr2); |
| 299 partitionFree(ptr3); | 299 partitionFree(ptr3); |
| 300 | 300 |
| 301 TestShutdown(); | 301 TestShutdown(); |
| 302 } | 302 } |
| 303 | 303 |
| 304 // Test a bucket with multiple pages. | 304 // Test a bucket with multiple pages. |
| 305 TEST(PartitionAllocTest, MultiPages) | 305 TEST(PartitionAllocTest, MultiPages) |
| 306 { | 306 { |
| 307 TestSetup(); | 307 TestSetup(); |
| 308 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex ]; | 308 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; |
| 309 | 309 |
| 310 WTF::PartitionPage* page = GetFullPage(kTestAllocSize); | 310 PartitionPage* page = GetFullPage(kTestAllocSize); |
| 311 FreeFullPage(page); | 311 FreeFullPage(page); |
| 312 EXPECT_FALSE(bucket->emptyPagesHead); | 312 EXPECT_FALSE(bucket->emptyPagesHead); |
| 313 EXPECT_EQ(page, bucket->activePagesHead); | 313 EXPECT_EQ(page, bucket->activePagesHead); |
| 314 EXPECT_EQ(0, page->nextPage); | 314 EXPECT_EQ(0, page->nextPage); |
| 315 EXPECT_EQ(0, page->numAllocatedSlots); | 315 EXPECT_EQ(0, page->numAllocatedSlots); |
| 316 | 316 |
| 317 page = GetFullPage(kTestAllocSize); | 317 page = GetFullPage(kTestAllocSize); |
| 318 WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize); | 318 PartitionPage* page2 = GetFullPage(kTestAllocSize); |
| 319 | 319 |
| 320 EXPECT_EQ(page2, bucket->activePagesHead); | 320 EXPECT_EQ(page2, bucket->activePagesHead); |
| 321 EXPECT_EQ(0, page2->nextPage); | 321 EXPECT_EQ(0, page2->nextPage); |
| 322 EXPECT_EQ(reinterpret_cast<uintptr_t>(partitionPageToPointer(page)) & WTF::k SuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(page2)) & WTF::kSuperPageBaseMask); | 322 EXPECT_EQ(reinterpret_cast<uintptr_t>(partitionPageToPointer(page)) & kSuper PageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(page2)) & kSupe rPageBaseMask); |
| 323 | 323 |
| 324 // Fully free the non-current page. It should not be freelisted because | 324 // Fully free the non-current page. It should not be freelisted because |
| 325 // there is no other immediately useable page. The other page is full. | 325 // there is no other immediately useable page. The other page is full. |
| 326 FreeFullPage(page); | 326 FreeFullPage(page); |
| 327 EXPECT_EQ(0, page->numAllocatedSlots); | 327 EXPECT_EQ(0, page->numAllocatedSlots); |
| 328 EXPECT_FALSE(bucket->emptyPagesHead); | 328 EXPECT_FALSE(bucket->emptyPagesHead); |
| 329 EXPECT_EQ(page, bucket->activePagesHead); | 329 EXPECT_EQ(page, bucket->activePagesHead); |
| 330 | 330 |
| 331 // Allocate a new page, it should pull from the freelist. | 331 // Allocate a new page, it should pull from the freelist. |
| 332 page = GetFullPage(kTestAllocSize); | 332 page = GetFullPage(kTestAllocSize); |
| 333 EXPECT_FALSE(bucket->emptyPagesHead); | 333 EXPECT_FALSE(bucket->emptyPagesHead); |
| 334 EXPECT_EQ(page, bucket->activePagesHead); | 334 EXPECT_EQ(page, bucket->activePagesHead); |
| 335 | 335 |
| 336 FreeFullPage(page); | 336 FreeFullPage(page); |
| 337 FreeFullPage(page2); | 337 FreeFullPage(page2); |
| 338 EXPECT_EQ(0, page->numAllocatedSlots); | 338 EXPECT_EQ(0, page->numAllocatedSlots); |
| 339 EXPECT_EQ(0, page2->numAllocatedSlots); | 339 EXPECT_EQ(0, page2->numAllocatedSlots); |
| 340 EXPECT_EQ(0, page2->numUnprovisionedSlots); | 340 EXPECT_EQ(0, page2->numUnprovisionedSlots); |
| 341 EXPECT_NE(-1, page2->emptyCacheIndex); | 341 EXPECT_NE(-1, page2->emptyCacheIndex); |
| 342 | 342 |
| 343 TestShutdown(); | 343 TestShutdown(); |
| 344 } | 344 } |
| 345 | 345 |
| 346 // Test some finer aspects of internal page transitions. | 346 // Test some finer aspects of internal page transitions. |
| 347 TEST(PartitionAllocTest, PageTransitions) | 347 TEST(PartitionAllocTest, PageTransitions) |
| 348 { | 348 { |
| 349 TestSetup(); | 349 TestSetup(); |
| 350 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex ]; | 350 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; |
| 351 | 351 |
| 352 WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize); | 352 PartitionPage* page1 = GetFullPage(kTestAllocSize); |
| 353 EXPECT_EQ(page1, bucket->activePagesHead); | 353 EXPECT_EQ(page1, bucket->activePagesHead); |
| 354 EXPECT_EQ(0, page1->nextPage); | 354 EXPECT_EQ(0, page1->nextPage); |
| 355 WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize); | 355 PartitionPage* page2 = GetFullPage(kTestAllocSize); |
| 356 EXPECT_EQ(page2, bucket->activePagesHead); | 356 EXPECT_EQ(page2, bucket->activePagesHead); |
| 357 EXPECT_EQ(0, page2->nextPage); | 357 EXPECT_EQ(0, page2->nextPage); |
| 358 | 358 |
| 359 // Bounce page1 back into the non-full list then fill it up again. | 359 // Bounce page1 back into the non-full list then fill it up again. |
| 360 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointe rOffset; | 360 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointe rOffset; |
| 361 partitionFree(ptr); | 361 partitionFree(ptr); |
| 362 EXPECT_EQ(page1, bucket->activePagesHead); | 362 EXPECT_EQ(page1, bucket->activePagesHead); |
| 363 (void) partitionAlloc(allocator.root(), kTestAllocSize); | 363 (void) partitionAlloc(allocator.root(), kTestAllocSize); |
| 364 EXPECT_EQ(page1, bucket->activePagesHead); | 364 EXPECT_EQ(page1, bucket->activePagesHead); |
| 365 EXPECT_EQ(page2, bucket->activePagesHead->nextPage); | 365 EXPECT_EQ(page2, bucket->activePagesHead->nextPage); |
| 366 | 366 |
| 367 // Allocating another page at this point should cause us to scan over page1 | 367 // Allocating another page at this point should cause us to scan over page1 |
| 368 // (which is both full and NOT our current page), and evict it from the | 368 // (which is both full and NOT our current page), and evict it from the |
| 369 // freelist. Older code had a O(n^2) condition due to failure to do this. | 369 // freelist. Older code had a O(n^2) condition due to failure to do this. |
| 370 WTF::PartitionPage* page3 = GetFullPage(kTestAllocSize); | 370 PartitionPage* page3 = GetFullPage(kTestAllocSize); |
| 371 EXPECT_EQ(page3, bucket->activePagesHead); | 371 EXPECT_EQ(page3, bucket->activePagesHead); |
| 372 EXPECT_EQ(0, page3->nextPage); | 372 EXPECT_EQ(0, page3->nextPage); |
| 373 | 373 |
| 374 // Work out a pointer into page2 and free it. | 374 // Work out a pointer into page2 and free it. |
| 375 ptr = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffse t; | 375 ptr = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffse t; |
| 376 partitionFree(ptr); | 376 partitionFree(ptr); |
| 377 // Trying to allocate at this time should cause us to cycle around to page2 | 377 // Trying to allocate at this time should cause us to cycle around to page2 |
| 378 // and find the recently freed slot. | 378 // and find the recently freed slot. |
| 379 char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTes tAllocSize)); | 379 char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTes tAllocSize)); |
| 380 EXPECT_EQ(ptr, newPtr); | 380 EXPECT_EQ(ptr, newPtr); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 400 partitionFree(ptr); | 400 partitionFree(ptr); |
| 401 | 401 |
| 402 TestShutdown(); | 402 TestShutdown(); |
| 403 } | 403 } |
| 404 | 404 |
| 405 // Test some corner cases relating to page transitions in the internal | 405 // Test some corner cases relating to page transitions in the internal |
| 406 // free page list metadata bucket. | 406 // free page list metadata bucket. |
| 407 TEST(PartitionAllocTest, FreePageListPageTransitions) | 407 TEST(PartitionAllocTest, FreePageListPageTransitions) |
| 408 { | 408 { |
| 409 TestSetup(); | 409 TestSetup(); |
| 410 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex ]; | 410 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; |
| 411 | 411 |
| 412 size_t numToFillFreeListPage = WTF::kPartitionPageSize / (sizeof(WTF::Partit ionPage) + kExtraAllocSize); | 412 size_t numToFillFreeListPage = kPartitionPageSize / (sizeof(PartitionPage) + kExtraAllocSize); |
| 413 // The +1 is because we need to account for the fact that the current page | 413 // The +1 is because we need to account for the fact that the current page |
| 414 // never gets thrown on the freelist. | 414 // never gets thrown on the freelist. |
| 415 ++numToFillFreeListPage; | 415 ++numToFillFreeListPage; |
| 416 OwnPtr<WTF::PartitionPage*[]> pages = adoptArrayPtr(new WTF::PartitionPage*[ numToFillFreeListPage]); | 416 OwnPtr<PartitionPage*[]> pages = adoptArrayPtr(new PartitionPage*[numToFillF reeListPage]); |
| 417 | 417 |
| 418 size_t i; | 418 size_t i; |
| 419 for (i = 0; i < numToFillFreeListPage; ++i) { | 419 for (i = 0; i < numToFillFreeListPage; ++i) { |
| 420 pages[i] = GetFullPage(kTestAllocSize); | 420 pages[i] = GetFullPage(kTestAllocSize); |
| 421 } | 421 } |
| 422 EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead); | 422 EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead); |
| 423 for (i = 0; i < numToFillFreeListPage; ++i) | 423 for (i = 0; i < numToFillFreeListPage; ++i) |
| 424 FreeFullPage(pages[i]); | 424 FreeFullPage(pages[i]); |
| 425 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots); | 425 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots); |
| 426 EXPECT_NE(-1, bucket->activePagesHead->nextPage->emptyCacheIndex); | 426 EXPECT_NE(-1, bucket->activePagesHead->nextPage->emptyCacheIndex); |
| 427 EXPECT_EQ(0, bucket->activePagesHead->nextPage->numAllocatedSlots); | 427 EXPECT_EQ(0, bucket->activePagesHead->nextPage->numAllocatedSlots); |
| 428 EXPECT_EQ(0, bucket->activePagesHead->nextPage->numUnprovisionedSlots); | 428 EXPECT_EQ(0, bucket->activePagesHead->nextPage->numUnprovisionedSlots); |
| 429 | 429 |
| 430 // Allocate / free in a different bucket size so we get control of a | 430 // Allocate / free in a different bucket size so we get control of a |
| 431 // different free page list. We need two pages because one will be the last | 431 // different free page list. We need two pages because one will be the last |
| 432 // active page and not get freed. | 432 // active page and not get freed. |
| 433 WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize * 2); | 433 PartitionPage* page1 = GetFullPage(kTestAllocSize * 2); |
| 434 WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize * 2); | 434 PartitionPage* page2 = GetFullPage(kTestAllocSize * 2); |
| 435 FreeFullPage(page1); | 435 FreeFullPage(page1); |
| 436 FreeFullPage(page2); | 436 FreeFullPage(page2); |
| 437 | 437 |
| 438 // If we re-allocate all kTestAllocSize allocations, we'll pull all the | 438 // If we re-allocate all kTestAllocSize allocations, we'll pull all the |
| 439 // free pages and end up freeing the first page for free page objects. | 439 // free pages and end up freeing the first page for free page objects. |
| 440 // It's getting a bit tricky but a nice re-entrancy is going on: | 440 // It's getting a bit tricky but a nice re-entrancy is going on: |
| 441 // alloc(kTestAllocSize) -> pulls page from free page list -> | 441 // alloc(kTestAllocSize) -> pulls page from free page list -> |
| 442 // free(PartitionFreepagelistEntry) -> last entry in page freed -> | 442 // free(PartitionFreepagelistEntry) -> last entry in page freed -> |
| 443 // alloc(PartitionFreepagelistEntry). | 443 // alloc(PartitionFreepagelistEntry). |
| 444 for (i = 0; i < numToFillFreeListPage; ++i) { | 444 for (i = 0; i < numToFillFreeListPage; ++i) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 460 TestShutdown(); | 460 TestShutdown(); |
| 461 } | 461 } |
| 462 | 462 |
| 463 // Test a large series of allocations that cross more than one underlying | 463 // Test a large series of allocations that cross more than one underlying |
| 464 // 64KB super page allocation. | 464 // 64KB super page allocation. |
| 465 TEST(PartitionAllocTest, MultiPageAllocs) | 465 TEST(PartitionAllocTest, MultiPageAllocs) |
| 466 { | 466 { |
| 467 TestSetup(); | 467 TestSetup(); |
| 468 // This is guaranteed to cross a super page boundary because the first | 468 // This is guaranteed to cross a super page boundary because the first |
| 469 // partition page "slot" will be taken up by a guard page. | 469 // partition page "slot" will be taken up by a guard page. |
| 470 size_t numPagesNeeded = WTF::kNumPartitionPagesPerSuperPage; | 470 size_t numPagesNeeded = kNumPartitionPagesPerSuperPage; |
| 471 // The super page should begin and end in a guard so we one less page in | 471 // The super page should begin and end in a guard so we one less page in |
| 472 // order to allocate a single page in the new super page. | 472 // order to allocate a single page in the new super page. |
| 473 --numPagesNeeded; | 473 --numPagesNeeded; |
| 474 | 474 |
| 475 EXPECT_GT(numPagesNeeded, 1u); | 475 EXPECT_GT(numPagesNeeded, 1u); |
| 476 OwnPtr<WTF::PartitionPage*[]> pages; | 476 OwnPtr<PartitionPage*[]> pages; |
| 477 pages = adoptArrayPtr(new WTF::PartitionPage*[numPagesNeeded]); | 477 pages = adoptArrayPtr(new PartitionPage*[numPagesNeeded]); |
| 478 uintptr_t firstSuperPageBase = 0; | 478 uintptr_t firstSuperPageBase = 0; |
| 479 size_t i; | 479 size_t i; |
| 480 for (i = 0; i < numPagesNeeded; ++i) { | 480 for (i = 0; i < numPagesNeeded; ++i) { |
| 481 pages[i] = GetFullPage(kTestAllocSize); | 481 pages[i] = GetFullPage(kTestAllocSize); |
| 482 void* storagePtr = partitionPageToPointer(pages[i]); | 482 void* storagePtr = partitionPageToPointer(pages[i]); |
| 483 if (!i) | 483 if (!i) |
| 484 firstSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & WTF:: kSuperPageBaseMask; | 484 firstSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & kSupe rPageBaseMask; |
| 485 if (i == numPagesNeeded - 1) { | 485 if (i == numPagesNeeded - 1) { |
| 486 uintptr_t secondSuperPageBase = reinterpret_cast<uintptr_t>(storageP tr) & WTF::kSuperPageBaseMask; | 486 uintptr_t secondSuperPageBase = reinterpret_cast<uintptr_t>(storageP tr) & kSuperPageBaseMask; |
| 487 uintptr_t secondSuperPageOffset = reinterpret_cast<uintptr_t>(storag ePtr) & WTF::kSuperPageOffsetMask; | 487 uintptr_t secondSuperPageOffset = reinterpret_cast<uintptr_t>(storag ePtr) & kSuperPageOffsetMask; |
| 488 EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase); | 488 EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase); |
| 489 // Check that we allocated a guard page for the second page. | 489 // Check that we allocated a guard page for the second page. |
| 490 EXPECT_EQ(WTF::kPartitionPageSize, secondSuperPageOffset); | 490 EXPECT_EQ(kPartitionPageSize, secondSuperPageOffset); |
| 491 } | 491 } |
| 492 } | 492 } |
| 493 for (i = 0; i < numPagesNeeded; ++i) | 493 for (i = 0; i < numPagesNeeded; ++i) |
| 494 FreeFullPage(pages[i]); | 494 FreeFullPage(pages[i]); |
| 495 | 495 |
| 496 TestShutdown(); | 496 TestShutdown(); |
| 497 } | 497 } |
| 498 | 498 |
| 499 // Test the generic allocation functions that can handle arbitrary sizes and | 499 // Test the generic allocation functions that can handle arbitrary sizes and |
| 500 // reallocing etc. | 500 // reallocing etc. |
| 501 TEST(PartitionAllocTest, GenericAlloc) | 501 TEST(PartitionAllocTest, GenericAlloc) |
| 502 { | 502 { |
| 503 TestSetup(); | 503 TestSetup(); |
| 504 | 504 |
| 505 void* ptr = partitionAllocGeneric(genericAllocator.root(), 1); | 505 void* ptr = partitionAllocGeneric(genericAllocator.root(), 1); |
| 506 EXPECT_TRUE(ptr); | 506 EXPECT_TRUE(ptr); |
| 507 partitionFreeGeneric(genericAllocator.root(), ptr); | 507 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 508 ptr = partitionAllocGeneric(genericAllocator.root(), WTF::kGenericMaxBuckete d + 1); | 508 ptr = partitionAllocGeneric(genericAllocator.root(), kGenericMaxBucketed + 1 ); |
| 509 EXPECT_TRUE(ptr); | 509 EXPECT_TRUE(ptr); |
| 510 partitionFreeGeneric(genericAllocator.root(), ptr); | 510 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 511 | 511 |
| 512 ptr = partitionAllocGeneric(genericAllocator.root(), 1); | 512 ptr = partitionAllocGeneric(genericAllocator.root(), 1); |
| 513 EXPECT_TRUE(ptr); | 513 EXPECT_TRUE(ptr); |
| 514 void* origPtr = ptr; | 514 void* origPtr = ptr; |
| 515 char* charPtr = static_cast<char*>(ptr); | 515 char* charPtr = static_cast<char*>(ptr); |
| 516 *charPtr = 'A'; | 516 *charPtr = 'A'; |
| 517 | 517 |
| 518 // Change the size of the realloc, remaining inside the same bucket. | 518 // Change the size of the realloc, remaining inside the same bucket. |
| 519 void* newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 2); | 519 void* newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 2); |
| 520 EXPECT_EQ(ptr, newPtr); | 520 EXPECT_EQ(ptr, newPtr); |
| 521 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); | 521 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); |
| 522 EXPECT_EQ(ptr, newPtr); | 522 EXPECT_EQ(ptr, newPtr); |
| 523 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGeneric SmallestBucket); | 523 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericSmall estBucket); |
| 524 EXPECT_EQ(ptr, newPtr); | 524 EXPECT_EQ(ptr, newPtr); |
| 525 | 525 |
| 526 // Change the size of the realloc, switching buckets. | 526 // Change the size of the realloc, switching buckets. |
| 527 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGeneric SmallestBucket + 1); | 527 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericSmall estBucket + 1); |
| 528 EXPECT_NE(newPtr, ptr); | 528 EXPECT_NE(newPtr, ptr); |
| 529 // Check that the realloc copied correctly. | 529 // Check that the realloc copied correctly. |
| 530 char* newCharPtr = static_cast<char*>(newPtr); | 530 char* newCharPtr = static_cast<char*>(newPtr); |
| 531 EXPECT_EQ(*newCharPtr, 'A'); | 531 EXPECT_EQ(*newCharPtr, 'A'); |
| 532 #if ENABLE(ASSERT) | 532 #if ENABLE(ASSERT) |
| 533 // Subtle: this checks for an old bug where we copied too much from the | 533 // Subtle: this checks for an old bug where we copied too much from the |
| 534 // source of the realloc. The condition can be detected by a trashing of | 534 // source of the realloc. The condition can be detected by a trashing of |
| 535 // the uninitialized value in the space of the upsized allocation. | 535 // the uninitialized value in the space of the upsized allocation. |
| 536 EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(*(newCharPtr + WTF::kGenericSmallestBucket))); | 536 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(*(newCharPtr + kGen ericSmallestBucket))); |
| 537 #endif | 537 #endif |
| 538 *newCharPtr = 'B'; | 538 *newCharPtr = 'B'; |
| 539 // The realloc moved. To check that the old allocation was freed, we can | 539 // The realloc moved. To check that the old allocation was freed, we can |
| 540 // do an alloc of the old allocation size and check that the old allocation | 540 // do an alloc of the old allocation size and check that the old allocation |
| 541 // address is at the head of the freelist and reused. | 541 // address is at the head of the freelist and reused. |
| 542 void* reusedPtr = partitionAllocGeneric(genericAllocator.root(), 1); | 542 void* reusedPtr = partitionAllocGeneric(genericAllocator.root(), 1); |
| 543 EXPECT_EQ(reusedPtr, origPtr); | 543 EXPECT_EQ(reusedPtr, origPtr); |
| 544 partitionFreeGeneric(genericAllocator.root(), reusedPtr); | 544 partitionFreeGeneric(genericAllocator.root(), reusedPtr); |
| 545 | 545 |
| 546 // Downsize the realloc. | 546 // Downsize the realloc. |
| 547 ptr = newPtr; | 547 ptr = newPtr; |
| 548 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); | 548 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); |
| 549 EXPECT_EQ(newPtr, origPtr); | 549 EXPECT_EQ(newPtr, origPtr); |
| 550 newCharPtr = static_cast<char*>(newPtr); | 550 newCharPtr = static_cast<char*>(newPtr); |
| 551 EXPECT_EQ(*newCharPtr, 'B'); | 551 EXPECT_EQ(*newCharPtr, 'B'); |
| 552 *newCharPtr = 'C'; | 552 *newCharPtr = 'C'; |
| 553 | 553 |
| 554 // Upsize the realloc to outside the partition. | 554 // Upsize the realloc to outside the partition. |
| 555 ptr = newPtr; | 555 ptr = newPtr; |
| 556 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGeneric MaxBucketed + 1); | 556 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBu cketed + 1); |
| 557 EXPECT_NE(newPtr, ptr); | 557 EXPECT_NE(newPtr, ptr); |
| 558 newCharPtr = static_cast<char*>(newPtr); | 558 newCharPtr = static_cast<char*>(newPtr); |
| 559 EXPECT_EQ(*newCharPtr, 'C'); | 559 EXPECT_EQ(*newCharPtr, 'C'); |
| 560 *newCharPtr = 'D'; | 560 *newCharPtr = 'D'; |
| 561 | 561 |
| 562 // Upsize and downsize the realloc, remaining outside the partition. | 562 // Upsize and downsize the realloc, remaining outside the partition. |
| 563 ptr = newPtr; | 563 ptr = newPtr; |
| 564 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGeneric MaxBucketed * 10); | 564 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBu cketed * 10); |
| 565 newCharPtr = static_cast<char*>(newPtr); | 565 newCharPtr = static_cast<char*>(newPtr); |
| 566 EXPECT_EQ(*newCharPtr, 'D'); | 566 EXPECT_EQ(*newCharPtr, 'D'); |
| 567 *newCharPtr = 'E'; | 567 *newCharPtr = 'E'; |
| 568 ptr = newPtr; | 568 ptr = newPtr; |
| 569 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGeneric MaxBucketed * 2); | 569 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBu cketed * 2); |
| 570 newCharPtr = static_cast<char*>(newPtr); | 570 newCharPtr = static_cast<char*>(newPtr); |
| 571 EXPECT_EQ(*newCharPtr, 'E'); | 571 EXPECT_EQ(*newCharPtr, 'E'); |
| 572 *newCharPtr = 'F'; | 572 *newCharPtr = 'F'; |
| 573 | 573 |
| 574 // Downsize the realloc to inside the partition. | 574 // Downsize the realloc to inside the partition. |
| 575 ptr = newPtr; | 575 ptr = newPtr; |
| 576 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); | 576 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); |
| 577 EXPECT_NE(newPtr, ptr); | 577 EXPECT_NE(newPtr, ptr); |
| 578 EXPECT_EQ(newPtr, origPtr); | 578 EXPECT_EQ(newPtr, origPtr); |
| 579 newCharPtr = static_cast<char*>(newPtr); | 579 newCharPtr = static_cast<char*>(newPtr); |
| 580 EXPECT_EQ(*newCharPtr, 'F'); | 580 EXPECT_EQ(*newCharPtr, 'F'); |
| 581 | 581 |
| 582 partitionFreeGeneric(genericAllocator.root(), newPtr); | 582 partitionFreeGeneric(genericAllocator.root(), newPtr); |
| 583 TestShutdown(); | 583 TestShutdown(); |
| 584 } | 584 } |
| 585 | 585 |
| 586 // Test the generic allocation functions can handle some specific sizes of | 586 // Test the generic allocation functions can handle some specific sizes of |
| 587 // interest. | 587 // interest. |
| 588 TEST(PartitionAllocTest, GenericAllocSizes) | 588 TEST(PartitionAllocTest, GenericAllocSizes) |
| 589 { | 589 { |
| 590 TestSetup(); | 590 TestSetup(); |
| 591 | 591 |
| 592 void* ptr = partitionAllocGeneric(genericAllocator.root(), 0); | 592 void* ptr = partitionAllocGeneric(genericAllocator.root(), 0); |
| 593 EXPECT_TRUE(ptr); | 593 EXPECT_TRUE(ptr); |
| 594 partitionFreeGeneric(genericAllocator.root(), ptr); | 594 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 595 | 595 |
| 596 // kPartitionPageSize is interesting because it results in just one | 596 // kPartitionPageSize is interesting because it results in just one |
| 597 // allocation per page, which tripped up some corner cases. | 597 // allocation per page, which tripped up some corner cases. |
| 598 size_t size = WTF::kPartitionPageSize - kExtraAllocSize; | 598 size_t size = kPartitionPageSize - kExtraAllocSize; |
| 599 ptr = partitionAllocGeneric(genericAllocator.root(), size); | 599 ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 600 EXPECT_TRUE(ptr); | 600 EXPECT_TRUE(ptr); |
| 601 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); | 601 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); |
| 602 EXPECT_TRUE(ptr2); | 602 EXPECT_TRUE(ptr2); |
| 603 partitionFreeGeneric(genericAllocator.root(), ptr); | 603 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 604 // Should be freeable at this point. | 604 // Should be freeable at this point. |
| 605 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieF reePointerAdjust(ptr)); | 605 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); |
| 606 EXPECT_NE(-1, page->emptyCacheIndex); | 606 EXPECT_NE(-1, page->emptyCacheIndex); |
| 607 partitionFreeGeneric(genericAllocator.root(), ptr2); | 607 partitionFreeGeneric(genericAllocator.root(), ptr2); |
| 608 | 608 |
| 609 size = (((WTF::kPartitionPageSize * WTF::kMaxPartitionPagesPerSlotSpan) - WT F::kSystemPageSize) / 2) - kExtraAllocSize; | 609 size = (((kPartitionPageSize * kMaxPartitionPagesPerSlotSpan) - kSystemPageS ize) / 2) - kExtraAllocSize; |
| 610 ptr = partitionAllocGeneric(genericAllocator.root(), size); | 610 ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 611 EXPECT_TRUE(ptr); | 611 EXPECT_TRUE(ptr); |
| 612 memset(ptr, 'A', size); | 612 memset(ptr, 'A', size); |
| 613 ptr2 = partitionAllocGeneric(genericAllocator.root(), size); | 613 ptr2 = partitionAllocGeneric(genericAllocator.root(), size); |
| 614 EXPECT_TRUE(ptr2); | 614 EXPECT_TRUE(ptr2); |
| 615 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size); | 615 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size); |
| 616 EXPECT_TRUE(ptr3); | 616 EXPECT_TRUE(ptr3); |
| 617 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size); | 617 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size); |
| 618 EXPECT_TRUE(ptr4); | 618 EXPECT_TRUE(ptr4); |
| 619 | 619 |
| 620 page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr )); | 620 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); |
| 621 WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookie FreePointerAdjust(ptr3)); | 621 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr3)); |
| 622 EXPECT_NE(page, page2); | 622 EXPECT_NE(page, page2); |
| 623 | 623 |
| 624 partitionFreeGeneric(genericAllocator.root(), ptr); | 624 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 625 partitionFreeGeneric(genericAllocator.root(), ptr3); | 625 partitionFreeGeneric(genericAllocator.root(), ptr3); |
| 626 partitionFreeGeneric(genericAllocator.root(), ptr2); | 626 partitionFreeGeneric(genericAllocator.root(), ptr2); |
| 627 // Should be freeable at this point. | 627 // Should be freeable at this point. |
| 628 EXPECT_NE(-1, page->emptyCacheIndex); | 628 EXPECT_NE(-1, page->emptyCacheIndex); |
| 629 EXPECT_EQ(0, page->numAllocatedSlots); | 629 EXPECT_EQ(0, page->numAllocatedSlots); |
| 630 EXPECT_EQ(0, page->numUnprovisionedSlots); | 630 EXPECT_EQ(0, page->numUnprovisionedSlots); |
| 631 void* newPtr = partitionAllocGeneric(genericAllocator.root(), size); | 631 void* newPtr = partitionAllocGeneric(genericAllocator.root(), size); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 646 partitionFreeGeneric(genericAllocator.root(), ptr3); | 646 partitionFreeGeneric(genericAllocator.root(), ptr3); |
| 647 partitionFreeGeneric(genericAllocator.root(), ptr4); | 647 partitionFreeGeneric(genericAllocator.root(), ptr4); |
| 648 | 648 |
| 649 // Can we allocate a massive (512MB) size? | 649 // Can we allocate a massive (512MB) size? |
| 650 ptr = partitionAllocGeneric(genericAllocator.root(), 512 * 1024 * 1024); | 650 ptr = partitionAllocGeneric(genericAllocator.root(), 512 * 1024 * 1024); |
| 651 partitionFreeGeneric(genericAllocator.root(), ptr); | 651 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 652 | 652 |
| 653 // Check a more reasonable, but still direct mapped, size. | 653 // Check a more reasonable, but still direct mapped, size. |
| 654 // Chop a system page and a byte off to test for rounding errors. | 654 // Chop a system page and a byte off to test for rounding errors. |
| 655 size = 20 * 1024 * 1024; | 655 size = 20 * 1024 * 1024; |
| 656 size -= WTF::kSystemPageSize; | 656 size -= kSystemPageSize; |
| 657 size -= 1; | 657 size -= 1; |
| 658 ptr = partitionAllocGeneric(genericAllocator.root(), size); | 658 ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 659 char* charPtr = reinterpret_cast<char*>(ptr); | 659 char* charPtr = reinterpret_cast<char*>(ptr); |
| 660 *(charPtr + (size - 1)) = 'A'; | 660 *(charPtr + (size - 1)) = 'A'; |
| 661 partitionFreeGeneric(genericAllocator.root(), ptr); | 661 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 662 | 662 |
| 663 // Can we free null? | 663 // Can we free null? |
| 664 partitionFreeGeneric(genericAllocator.root(), 0); | 664 partitionFreeGeneric(genericAllocator.root(), 0); |
| 665 | 665 |
| 666 // Do we correctly get a null for a failed allocation? | 666 // Do we correctly get a null for a failed allocation? |
| 667 EXPECT_EQ(0, partitionAllocGenericFlags(genericAllocator.root(), WTF::Partit ionAllocReturnNull, 3u * 1024 * 1024 * 1024)); | 667 EXPECT_EQ(0, partitionAllocGenericFlags(genericAllocator.root(), PartitionAl locReturnNull, 3u * 1024 * 1024 * 1024)); |
| 668 | 668 |
| 669 TestShutdown(); | 669 TestShutdown(); |
| 670 } | 670 } |
| 671 | 671 |
| 672 // Test that we can fetch the real allocated size after an allocation. | 672 // Test that we can fetch the real allocated size after an allocation. |
| 673 TEST(PartitionAllocTest, GenericAllocGetSize) | 673 TEST(PartitionAllocTest, GenericAllocGetSize) |
| 674 { | 674 { |
| 675 TestSetup(); | 675 TestSetup(); |
| 676 | 676 |
| 677 void* ptr; | 677 void* ptr; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 695 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); | 695 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); |
| 696 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); | 696 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); |
| 697 EXPECT_TRUE(ptr); | 697 EXPECT_TRUE(ptr); |
| 698 actualSize = partitionAllocGetSize(ptr); | 698 actualSize = partitionAllocGetSize(ptr); |
| 699 EXPECT_EQ(predictedSize, actualSize); | 699 EXPECT_EQ(predictedSize, actualSize); |
| 700 EXPECT_EQ(requestedSize, actualSize); | 700 EXPECT_EQ(requestedSize, actualSize); |
| 701 partitionFreeGeneric(genericAllocator.root(), ptr); | 701 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 702 | 702 |
| 703 // Allocate a size that is a system page smaller than a bucket. GetSize() | 703 // Allocate a size that is a system page smaller than a bucket. GetSize() |
| 704 // should return a larger size than we asked for now. | 704 // should return a larger size than we asked for now. |
| 705 requestedSize = (256 * 1024) - WTF::kSystemPageSize - kExtraAllocSize; | 705 requestedSize = (256 * 1024) - kSystemPageSize - kExtraAllocSize; |
| 706 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); | 706 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); |
| 707 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); | 707 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); |
| 708 EXPECT_TRUE(ptr); | 708 EXPECT_TRUE(ptr); |
| 709 actualSize = partitionAllocGetSize(ptr); | 709 actualSize = partitionAllocGetSize(ptr); |
| 710 EXPECT_EQ(predictedSize, actualSize); | 710 EXPECT_EQ(predictedSize, actualSize); |
| 711 EXPECT_EQ(requestedSize + WTF::kSystemPageSize, actualSize); | 711 EXPECT_EQ(requestedSize + kSystemPageSize, actualSize); |
| 712 // Check that we can write at the end of the reported size too. | 712 // Check that we can write at the end of the reported size too. |
| 713 char* charPtr = reinterpret_cast<char*>(ptr); | 713 char* charPtr = reinterpret_cast<char*>(ptr); |
| 714 *(charPtr + (actualSize - 1)) = 'A'; | 714 *(charPtr + (actualSize - 1)) = 'A'; |
| 715 partitionFreeGeneric(genericAllocator.root(), ptr); | 715 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 716 | 716 |
| 717 // Allocate something very large, and uneven. | 717 // Allocate something very large, and uneven. |
| 718 requestedSize = 512 * 1024 * 1024 - 1; | 718 requestedSize = 512 * 1024 * 1024 - 1; |
| 719 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); | 719 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); |
| 720 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); | 720 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); |
| 721 EXPECT_TRUE(ptr); | 721 EXPECT_TRUE(ptr); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 733 } | 733 } |
| 734 | 734 |
| 735 // Test the realloc() contract. | 735 // Test the realloc() contract. |
| 736 TEST(PartitionAllocTest, Realloc) | 736 TEST(PartitionAllocTest, Realloc) |
| 737 { | 737 { |
| 738 TestSetup(); | 738 TestSetup(); |
| 739 | 739 |
| 740 // realloc(0, size) should be equivalent to malloc(). | 740 // realloc(0, size) should be equivalent to malloc(). |
| 741 void* ptr = partitionReallocGeneric(genericAllocator.root(), 0, kTestAllocSi ze); | 741 void* ptr = partitionReallocGeneric(genericAllocator.root(), 0, kTestAllocSi ze); |
| 742 memset(ptr, 'A', kTestAllocSize); | 742 memset(ptr, 'A', kTestAllocSize); |
| 743 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieF reePointerAdjust(ptr)); | 743 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); |
| 744 // realloc(ptr, 0) should be equivalent to free(). | 744 // realloc(ptr, 0) should be equivalent to free(). |
| 745 void* ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, 0); | 745 void* ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, 0); |
| 746 EXPECT_EQ(0, ptr2); | 746 EXPECT_EQ(0, ptr2); |
| 747 EXPECT_EQ(WTF::partitionCookieFreePointerAdjust(ptr), page->freelistHead); | 747 EXPECT_EQ(partitionCookieFreePointerAdjust(ptr), page->freelistHead); |
| 748 | 748 |
| 749 // Test that growing an allocation with realloc() copies everything from the | 749 // Test that growing an allocation with realloc() copies everything from the |
| 750 // old allocation. | 750 // old allocation. |
| 751 size_t size = WTF::kSystemPageSize - kExtraAllocSize; | 751 size_t size = kSystemPageSize - kExtraAllocSize; |
| 752 EXPECT_EQ(size, partitionAllocActualSize(genericAllocator.root(), size)); | 752 EXPECT_EQ(size, partitionAllocActualSize(genericAllocator.root(), size)); |
| 753 ptr = partitionAllocGeneric(genericAllocator.root(), size); | 753 ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 754 memset(ptr, 'A', size); | 754 memset(ptr, 'A', size); |
| 755 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, size + 1); | 755 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, size + 1); |
| 756 EXPECT_NE(ptr, ptr2); | 756 EXPECT_NE(ptr, ptr2); |
| 757 char* charPtr2 = static_cast<char*>(ptr2); | 757 char* charPtr2 = static_cast<char*>(ptr2); |
| 758 EXPECT_EQ('A', charPtr2[0]); | 758 EXPECT_EQ('A', charPtr2[0]); |
| 759 EXPECT_EQ('A', charPtr2[size - 1]); | 759 EXPECT_EQ('A', charPtr2[size - 1]); |
| 760 #if ENABLE(ASSERT) | 760 #if ENABLE(ASSERT) |
| 761 EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(charPtr2[size] )); | 761 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr2[size])); |
| 762 #endif | 762 #endif |
| 763 | 763 |
| 764 // Test that shrinking an allocation with realloc() also copies everything | 764 // Test that shrinking an allocation with realloc() also copies everything |
| 765 // from the old allocation. | 765 // from the old allocation. |
| 766 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - 1); | 766 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - 1); |
| 767 EXPECT_NE(ptr2, ptr); | 767 EXPECT_NE(ptr2, ptr); |
| 768 char* charPtr = static_cast<char*>(ptr); | 768 char* charPtr = static_cast<char*>(ptr); |
| 769 EXPECT_EQ('A', charPtr[0]); | 769 EXPECT_EQ('A', charPtr[0]); |
| 770 EXPECT_EQ('A', charPtr[size - 2]); | 770 EXPECT_EQ('A', charPtr[size - 2]); |
| 771 #if ENABLE(ASSERT) | 771 #if ENABLE(ASSERT) |
| 772 EXPECT_EQ(WTF::kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1])); | 772 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1])) ; |
| 773 #endif | 773 #endif |
| 774 | 774 |
| 775 partitionFreeGeneric(genericAllocator.root(), ptr); | 775 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 776 | 776 |
| 777 // Test that shrinking a direct mapped allocation happens in-place. | 777 // Test that shrinking a direct mapped allocation happens in-place. |
| 778 size = WTF::kGenericMaxBucketed + 16 * WTF::kSystemPageSize; | 778 size = kGenericMaxBucketed + 16 * kSystemPageSize; |
| 779 ptr = partitionAllocGeneric(genericAllocator.root(), size); | 779 ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 780 size_t actualSize = partitionAllocGetSize(ptr); | 780 size_t actualSize = partitionAllocGetSize(ptr); |
| 781 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kGenericMa xBucketed + 8 * WTF::kSystemPageSize); | 781 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBuck eted + 8 * kSystemPageSize); |
| 782 EXPECT_EQ(ptr, ptr2); | 782 EXPECT_EQ(ptr, ptr2); |
| 783 EXPECT_EQ(actualSize - 8 * WTF::kSystemPageSize, partitionAllocGetSize(ptr2) ); | 783 EXPECT_EQ(actualSize - 8 * kSystemPageSize, partitionAllocGetSize(ptr2)); |
| 784 | 784 |
| 785 // Test that a previously in-place shrunk direct mapped allocation can be | 785 // Test that a previously in-place shrunk direct mapped allocation can be |
| 786 // expanded up again within its original size. | 786 // expanded up again within its original size. |
| 787 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - WTF::kSy stemPageSize); | 787 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - kSystemP ageSize); |
| 788 EXPECT_EQ(ptr2, ptr); | 788 EXPECT_EQ(ptr2, ptr); |
| 789 EXPECT_EQ(actualSize - WTF::kSystemPageSize, partitionAllocGetSize(ptr)); | 789 EXPECT_EQ(actualSize - kSystemPageSize, partitionAllocGetSize(ptr)); |
| 790 | 790 |
| 791 // Test that a direct mapped allocation is performed not in-place when the | 791 // Test that a direct mapped allocation is performed not in-place when the |
| 792 // new size is small enough. | 792 // new size is small enough. |
| 793 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, WTF::kSystemPag eSize); | 793 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, kSystemPageSize ); |
| 794 EXPECT_NE(ptr, ptr2); | 794 EXPECT_NE(ptr, ptr2); |
| 795 | 795 |
| 796 partitionFreeGeneric(genericAllocator.root(), ptr2); | 796 partitionFreeGeneric(genericAllocator.root(), ptr2); |
| 797 | 797 |
| 798 TestShutdown(); | 798 TestShutdown(); |
| 799 } | 799 } |
| 800 | 800 |
| 801 // Tests the handing out of freelists for partial pages. | 801 // Tests the handing out of freelists for partial pages. |
| 802 TEST(PartitionAllocTest, PartialPageFreelists) | 802 TEST(PartitionAllocTest, PartialPageFreelists) |
| 803 { | 803 { |
| 804 TestSetup(); | 804 TestSetup(); |
| 805 | 805 |
| 806 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize; | 806 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize; |
| 807 EXPECT_EQ(WTF::kSystemPageSize - WTF::kAllocationGranularity, bigSize + kExt raAllocSize); | 807 EXPECT_EQ(kSystemPageSize - kAllocationGranularity, bigSize + kExtraAllocSiz e); |
| 808 size_t bucketIdx = (bigSize + kExtraAllocSize) >> WTF::kBucketShift; | 808 size_t bucketIdx = (bigSize + kExtraAllocSize) >> kBucketShift; |
| 809 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; | 809 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
| 810 EXPECT_EQ(0, bucket->emptyPagesHead); | 810 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 811 | 811 |
| 812 void* ptr = partitionAlloc(allocator.root(), bigSize); | 812 void* ptr = partitionAlloc(allocator.root(), bigSize); |
| 813 EXPECT_TRUE(ptr); | 813 EXPECT_TRUE(ptr); |
| 814 | 814 |
| 815 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieF reePointerAdjust(ptr)); | 815 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); |
| 816 size_t totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemP ageSize) / (bigSize + kExtraAllocSize); | 816 size_t totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSi ze) / (bigSize + kExtraAllocSize); |
| 817 EXPECT_EQ(4u, totalSlots); | 817 EXPECT_EQ(4u, totalSlots); |
| 818 // The freelist should have one entry, because we were able to exactly fit | 818 // The freelist should have one entry, because we were able to exactly fit |
| 819 // one object slot and one freelist pointer (the null that the head points | 819 // one object slot and one freelist pointer (the null that the head points |
| 820 // to) into a system page. | 820 // to) into a system page. |
| 821 EXPECT_TRUE(page->freelistHead); | 821 EXPECT_TRUE(page->freelistHead); |
| 822 EXPECT_EQ(1, page->numAllocatedSlots); | 822 EXPECT_EQ(1, page->numAllocatedSlots); |
| 823 EXPECT_EQ(2, page->numUnprovisionedSlots); | 823 EXPECT_EQ(2, page->numUnprovisionedSlots); |
| 824 | 824 |
| 825 void* ptr2 = partitionAlloc(allocator.root(), bigSize); | 825 void* ptr2 = partitionAlloc(allocator.root(), bigSize); |
| 826 EXPECT_TRUE(ptr2); | 826 EXPECT_TRUE(ptr2); |
| 827 EXPECT_FALSE(page->freelistHead); | 827 EXPECT_FALSE(page->freelistHead); |
| 828 EXPECT_EQ(2, page->numAllocatedSlots); | 828 EXPECT_EQ(2, page->numAllocatedSlots); |
| 829 EXPECT_EQ(2, page->numUnprovisionedSlots); | 829 EXPECT_EQ(2, page->numUnprovisionedSlots); |
| 830 | 830 |
| 831 void* ptr3 = partitionAlloc(allocator.root(), bigSize); | 831 void* ptr3 = partitionAlloc(allocator.root(), bigSize); |
| 832 EXPECT_TRUE(ptr3); | 832 EXPECT_TRUE(ptr3); |
| 833 EXPECT_TRUE(page->freelistHead); | 833 EXPECT_TRUE(page->freelistHead); |
| 834 EXPECT_EQ(3, page->numAllocatedSlots); | 834 EXPECT_EQ(3, page->numAllocatedSlots); |
| 835 EXPECT_EQ(0, page->numUnprovisionedSlots); | 835 EXPECT_EQ(0, page->numUnprovisionedSlots); |
| 836 | 836 |
| 837 void* ptr4 = partitionAlloc(allocator.root(), bigSize); | 837 void* ptr4 = partitionAlloc(allocator.root(), bigSize); |
| 838 EXPECT_TRUE(ptr4); | 838 EXPECT_TRUE(ptr4); |
| 839 EXPECT_FALSE(page->freelistHead); | 839 EXPECT_FALSE(page->freelistHead); |
| 840 EXPECT_EQ(4, page->numAllocatedSlots); | 840 EXPECT_EQ(4, page->numAllocatedSlots); |
| 841 EXPECT_EQ(0, page->numUnprovisionedSlots); | 841 EXPECT_EQ(0, page->numUnprovisionedSlots); |
| 842 | 842 |
| 843 void* ptr5 = partitionAlloc(allocator.root(), bigSize); | 843 void* ptr5 = partitionAlloc(allocator.root(), bigSize); |
| 844 EXPECT_TRUE(ptr5); | 844 EXPECT_TRUE(ptr5); |
| 845 | 845 |
| 846 WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookie FreePointerAdjust(ptr5)); | 846 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr5)); |
| 847 EXPECT_EQ(1, page2->numAllocatedSlots); | 847 EXPECT_EQ(1, page2->numAllocatedSlots); |
| 848 | 848 |
| 849 // Churn things a little whilst there's a partial page freelist. | 849 // Churn things a little whilst there's a partial page freelist. |
| 850 partitionFree(ptr); | 850 partitionFree(ptr); |
| 851 ptr = partitionAlloc(allocator.root(), bigSize); | 851 ptr = partitionAlloc(allocator.root(), bigSize); |
| 852 void* ptr6 = partitionAlloc(allocator.root(), bigSize); | 852 void* ptr6 = partitionAlloc(allocator.root(), bigSize); |
| 853 | 853 |
| 854 partitionFree(ptr); | 854 partitionFree(ptr); |
| 855 partitionFree(ptr2); | 855 partitionFree(ptr2); |
| 856 partitionFree(ptr3); | 856 partitionFree(ptr3); |
| 857 partitionFree(ptr4); | 857 partitionFree(ptr4); |
| 858 partitionFree(ptr5); | 858 partitionFree(ptr5); |
| 859 partitionFree(ptr6); | 859 partitionFree(ptr6); |
| 860 EXPECT_NE(-1, page->emptyCacheIndex); | 860 EXPECT_NE(-1, page->emptyCacheIndex); |
| 861 EXPECT_NE(-1, page2->emptyCacheIndex); | 861 EXPECT_NE(-1, page2->emptyCacheIndex); |
| 862 EXPECT_TRUE(page2->freelistHead); | 862 EXPECT_TRUE(page2->freelistHead); |
| 863 EXPECT_EQ(0, page2->numAllocatedSlots); | 863 EXPECT_EQ(0, page2->numAllocatedSlots); |
| 864 | 864 |
| 865 // And test a couple of sizes that do not cross kSystemPageSize with a singl e allocation. | 865 // And test a couple of sizes that do not cross kSystemPageSize with a singl e allocation. |
| 866 size_t mediumSize = (WTF::kSystemPageSize / 2) - kExtraAllocSize; | 866 size_t mediumSize = (kSystemPageSize / 2) - kExtraAllocSize; |
| 867 bucketIdx = (mediumSize + kExtraAllocSize) >> WTF::kBucketShift; | 867 bucketIdx = (mediumSize + kExtraAllocSize) >> kBucketShift; |
| 868 bucket = &allocator.root()->buckets()[bucketIdx]; | 868 bucket = &allocator.root()->buckets()[bucketIdx]; |
| 869 EXPECT_EQ(0, bucket->emptyPagesHead); | 869 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 870 | 870 |
| 871 ptr = partitionAlloc(allocator.root(), mediumSize); | 871 ptr = partitionAlloc(allocator.root(), mediumSize); |
| 872 EXPECT_TRUE(ptr); | 872 EXPECT_TRUE(ptr); |
| 873 page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr )); | 873 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); |
| 874 EXPECT_EQ(1, page->numAllocatedSlots); | 874 EXPECT_EQ(1, page->numAllocatedSlots); |
| 875 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize ) / (mediumSize + kExtraAllocSize); | 875 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( mediumSize + kExtraAllocSize); |
| 876 size_t firstPageSlots = WTF::kSystemPageSize / (mediumSize + kExtraAllocSize ); | 876 size_t firstPageSlots = kSystemPageSize / (mediumSize + kExtraAllocSize); |
| 877 EXPECT_EQ(2u, firstPageSlots); | 877 EXPECT_EQ(2u, firstPageSlots); |
| 878 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); | 878 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); |
| 879 | 879 |
| 880 partitionFree(ptr); | 880 partitionFree(ptr); |
| 881 | 881 |
| 882 size_t smallSize = (WTF::kSystemPageSize / 4) - kExtraAllocSize; | 882 size_t smallSize = (kSystemPageSize / 4) - kExtraAllocSize; |
| 883 bucketIdx = (smallSize + kExtraAllocSize) >> WTF::kBucketShift; | 883 bucketIdx = (smallSize + kExtraAllocSize) >> kBucketShift; |
| 884 bucket = &allocator.root()->buckets()[bucketIdx]; | 884 bucket = &allocator.root()->buckets()[bucketIdx]; |
| 885 EXPECT_EQ(0, bucket->emptyPagesHead); | 885 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 886 | 886 |
| 887 ptr = partitionAlloc(allocator.root(), smallSize); | 887 ptr = partitionAlloc(allocator.root(), smallSize); |
| 888 EXPECT_TRUE(ptr); | 888 EXPECT_TRUE(ptr); |
| 889 page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr )); | 889 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); |
| 890 EXPECT_EQ(1, page->numAllocatedSlots); | 890 EXPECT_EQ(1, page->numAllocatedSlots); |
| 891 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize ) / (smallSize + kExtraAllocSize); | 891 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( smallSize + kExtraAllocSize); |
| 892 firstPageSlots = WTF::kSystemPageSize / (smallSize + kExtraAllocSize); | 892 firstPageSlots = kSystemPageSize / (smallSize + kExtraAllocSize); |
| 893 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); | 893 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); |
| 894 | 894 |
| 895 partitionFree(ptr); | 895 partitionFree(ptr); |
| 896 EXPECT_TRUE(page->freelistHead); | 896 EXPECT_TRUE(page->freelistHead); |
| 897 EXPECT_EQ(0, page->numAllocatedSlots); | 897 EXPECT_EQ(0, page->numAllocatedSlots); |
| 898 | 898 |
| 899 size_t verySmallSize = 32 - kExtraAllocSize; | 899 size_t verySmallSize = 32 - kExtraAllocSize; |
| 900 bucketIdx = (verySmallSize + kExtraAllocSize) >> WTF::kBucketShift; | 900 bucketIdx = (verySmallSize + kExtraAllocSize) >> kBucketShift; |
| 901 bucket = &allocator.root()->buckets()[bucketIdx]; | 901 bucket = &allocator.root()->buckets()[bucketIdx]; |
| 902 EXPECT_EQ(0, bucket->emptyPagesHead); | 902 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 903 | 903 |
| 904 ptr = partitionAlloc(allocator.root(), verySmallSize); | 904 ptr = partitionAlloc(allocator.root(), verySmallSize); |
| 905 EXPECT_TRUE(ptr); | 905 EXPECT_TRUE(ptr); |
| 906 page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr )); | 906 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); |
| 907 EXPECT_EQ(1, page->numAllocatedSlots); | 907 EXPECT_EQ(1, page->numAllocatedSlots); |
| 908 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize ) / (verySmallSize + kExtraAllocSize); | 908 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( verySmallSize + kExtraAllocSize); |
| 909 firstPageSlots = WTF::kSystemPageSize / (verySmallSize + kExtraAllocSize); | 909 firstPageSlots = kSystemPageSize / (verySmallSize + kExtraAllocSize); |
| 910 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); | 910 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); |
| 911 | 911 |
| 912 partitionFree(ptr); | 912 partitionFree(ptr); |
| 913 EXPECT_TRUE(page->freelistHead); | 913 EXPECT_TRUE(page->freelistHead); |
| 914 EXPECT_EQ(0, page->numAllocatedSlots); | 914 EXPECT_EQ(0, page->numAllocatedSlots); |
| 915 | 915 |
| 916 // And try an allocation size (against the generic allocator) that is | 916 // And try an allocation size (against the generic allocator) that is |
| 917 // larger than a system page. | 917 // larger than a system page. |
| 918 size_t pageAndAHalfSize = (WTF::kSystemPageSize + (WTF::kSystemPageSize / 2) ) - kExtraAllocSize; | 918 size_t pageAndAHalfSize = (kSystemPageSize + (kSystemPageSize / 2)) - kExtra AllocSize; |
| 919 ptr = partitionAllocGeneric(genericAllocator.root(), pageAndAHalfSize); | 919 ptr = partitionAllocGeneric(genericAllocator.root(), pageAndAHalfSize); |
| 920 EXPECT_TRUE(ptr); | 920 EXPECT_TRUE(ptr); |
| 921 page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr )); | 921 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); |
| 922 EXPECT_EQ(1, page->numAllocatedSlots); | 922 EXPECT_EQ(1, page->numAllocatedSlots); |
| 923 EXPECT_TRUE(page->freelistHead); | 923 EXPECT_TRUE(page->freelistHead); |
| 924 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize ) / (pageAndAHalfSize + kExtraAllocSize); | 924 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( pageAndAHalfSize + kExtraAllocSize); |
| 925 EXPECT_EQ(totalSlots - 2, page->numUnprovisionedSlots); | 925 EXPECT_EQ(totalSlots - 2, page->numUnprovisionedSlots); |
| 926 partitionFreeGeneric(genericAllocator.root(), ptr); | 926 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 927 | 927 |
| 928 // And then make sure than exactly the page size only faults one page. | 928 // And then make sure than exactly the page size only faults one page. |
| 929 size_t pageSize = WTF::kSystemPageSize - kExtraAllocSize; | 929 size_t pageSize = kSystemPageSize - kExtraAllocSize; |
| 930 ptr = partitionAllocGeneric(genericAllocator.root(), pageSize); | 930 ptr = partitionAllocGeneric(genericAllocator.root(), pageSize); |
| 931 EXPECT_TRUE(ptr); | 931 EXPECT_TRUE(ptr); |
| 932 page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr )); | 932 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); |
| 933 EXPECT_EQ(1, page->numAllocatedSlots); | 933 EXPECT_EQ(1, page->numAllocatedSlots); |
| 934 EXPECT_FALSE(page->freelistHead); | 934 EXPECT_FALSE(page->freelistHead); |
| 935 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * WTF::kSystemPageSize ) / (pageSize + kExtraAllocSize); | 935 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( pageSize + kExtraAllocSize); |
| 936 EXPECT_EQ(totalSlots - 1, page->numUnprovisionedSlots); | 936 EXPECT_EQ(totalSlots - 1, page->numUnprovisionedSlots); |
| 937 partitionFreeGeneric(genericAllocator.root(), ptr); | 937 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 938 | 938 |
| 939 TestShutdown(); | 939 TestShutdown(); |
| 940 } | 940 } |
| 941 | 941 |
| 942 // Test some of the fragmentation-resistant properties of the allocator. | 942 // Test some of the fragmentation-resistant properties of the allocator. |
| 943 TEST(PartitionAllocTest, PageRefilling) | 943 TEST(PartitionAllocTest, PageRefilling) |
| 944 { | 944 { |
| 945 TestSetup(); | 945 TestSetup(); |
| 946 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex ]; | 946 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; |
| 947 | 947 |
| 948 // Grab two full pages and a non-full page. | 948 // Grab two full pages and a non-full page. |
| 949 WTF::PartitionPage* page1 = GetFullPage(kTestAllocSize); | 949 PartitionPage* page1 = GetFullPage(kTestAllocSize); |
| 950 WTF::PartitionPage* page2 = GetFullPage(kTestAllocSize); | 950 PartitionPage* page2 = GetFullPage(kTestAllocSize); |
| 951 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); | 951 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); |
| 952 EXPECT_TRUE(ptr); | 952 EXPECT_TRUE(ptr); |
| 953 EXPECT_NE(page1, bucket->activePagesHead); | 953 EXPECT_NE(page1, bucket->activePagesHead); |
| 954 EXPECT_NE(page2, bucket->activePagesHead); | 954 EXPECT_NE(page2, bucket->activePagesHead); |
| 955 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieF reePointerAdjust(ptr)); | 955 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); |
| 956 EXPECT_EQ(1, page->numAllocatedSlots); | 956 EXPECT_EQ(1, page->numAllocatedSlots); |
| 957 | 957 |
| 958 // Work out a pointer into page2 and free it; and then page1 and free it. | 958 // Work out a pointer into page2 and free it; and then page1 and free it. |
| 959 char* ptr2 = reinterpret_cast<char*>(WTF::partitionPageToPointer(page1)) + k PointerOffset; | 959 char* ptr2 = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPoint erOffset; |
| 960 partitionFree(ptr2); | 960 partitionFree(ptr2); |
| 961 ptr2 = reinterpret_cast<char*>(WTF::partitionPageToPointer(page2)) + kPointe rOffset; | 961 ptr2 = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffs et; |
| 962 partitionFree(ptr2); | 962 partitionFree(ptr2); |
| 963 | 963 |
| 964 // If we perform two allocations from the same bucket now, we expect to | 964 // If we perform two allocations from the same bucket now, we expect to |
| 965 // refill both the nearly full pages. | 965 // refill both the nearly full pages. |
| 966 (void) partitionAlloc(allocator.root(), kTestAllocSize); | 966 (void) partitionAlloc(allocator.root(), kTestAllocSize); |
| 967 (void) partitionAlloc(allocator.root(), kTestAllocSize); | 967 (void) partitionAlloc(allocator.root(), kTestAllocSize); |
| 968 EXPECT_EQ(1, page->numAllocatedSlots); | 968 EXPECT_EQ(1, page->numAllocatedSlots); |
| 969 | 969 |
| 970 FreeFullPage(page2); | 970 FreeFullPage(page2); |
| 971 FreeFullPage(page1); | 971 FreeFullPage(page1); |
| 972 partitionFree(ptr); | 972 partitionFree(ptr); |
| 973 | 973 |
| 974 TestShutdown(); | 974 TestShutdown(); |
| 975 } | 975 } |
| 976 | 976 |
| 977 // Basic tests to ensure that allocations work for partial page buckets. | 977 // Basic tests to ensure that allocations work for partial page buckets. |
| 978 TEST(PartitionAllocTest, PartialPages) | 978 TEST(PartitionAllocTest, PartialPages) |
| 979 { | 979 { |
| 980 TestSetup(); | 980 TestSetup(); |
| 981 | 981 |
| 982 // Find a size that is backed by a partial partition page. | 982 // Find a size that is backed by a partial partition page. |
| 983 size_t size = sizeof(void*); | 983 size_t size = sizeof(void*); |
| 984 WTF::PartitionBucket* bucket = 0; | 984 PartitionBucket* bucket = 0; |
| 985 while (size < kTestMaxAllocation) { | 985 while (size < kTestMaxAllocation) { |
| 986 bucket = &allocator.root()->buckets()[size >> WTF::kBucketShift]; | 986 bucket = &allocator.root()->buckets()[size >> kBucketShift]; |
| 987 if (bucket->numSystemPagesPerSlotSpan % WTF::kNumSystemPagesPerPartition Page) | 987 if (bucket->numSystemPagesPerSlotSpan % kNumSystemPagesPerPartitionPage) |
| 988 break; | 988 break; |
| 989 size += sizeof(void*); | 989 size += sizeof(void*); |
| 990 } | 990 } |
| 991 EXPECT_LT(size, kTestMaxAllocation); | 991 EXPECT_LT(size, kTestMaxAllocation); |
| 992 | 992 |
| 993 WTF::PartitionPage* page1 = GetFullPage(size); | 993 PartitionPage* page1 = GetFullPage(size); |
| 994 WTF::PartitionPage* page2 = GetFullPage(size); | 994 PartitionPage* page2 = GetFullPage(size); |
| 995 FreeFullPage(page2); | 995 FreeFullPage(page2); |
| 996 FreeFullPage(page1); | 996 FreeFullPage(page1); |
| 997 | 997 |
| 998 TestShutdown(); | 998 TestShutdown(); |
| 999 } | 999 } |
| 1000 | 1000 |
| 1001 // Test correct handling if our mapping collides with another. | 1001 // Test correct handling if our mapping collides with another. |
| 1002 TEST(PartitionAllocTest, MappingCollision) | 1002 TEST(PartitionAllocTest, MappingCollision) |
| 1003 { | 1003 { |
| 1004 TestSetup(); | 1004 TestSetup(); |
| 1005 // The -2 is because the first and last partition pages in a super page are | 1005 // The -2 is because the first and last partition pages in a super page are |
| 1006 // guard pages. | 1006 // guard pages. |
| 1007 size_t numPartitionPagesNeeded = WTF::kNumPartitionPagesPerSuperPage - 2; | 1007 size_t numPartitionPagesNeeded = kNumPartitionPagesPerSuperPage - 2; |
| 1008 OwnPtr<WTF::PartitionPage*[]> firstSuperPagePages = adoptArrayPtr(new WTF::P artitionPage*[numPartitionPagesNeeded]); | 1008 OwnPtr<PartitionPage*[]> firstSuperPagePages = adoptArrayPtr(new PartitionPa ge*[numPartitionPagesNeeded]); |
| 1009 OwnPtr<WTF::PartitionPage*[]> secondSuperPagePages = adoptArrayPtr(new WTF:: PartitionPage*[numPartitionPagesNeeded]); | 1009 OwnPtr<PartitionPage*[]> secondSuperPagePages = adoptArrayPtr(new PartitionP age*[numPartitionPagesNeeded]); |
| 1010 | 1010 |
| 1011 size_t i; | 1011 size_t i; |
| 1012 for (i = 0; i < numPartitionPagesNeeded; ++i) | 1012 for (i = 0; i < numPartitionPagesNeeded; ++i) |
| 1013 firstSuperPagePages[i] = GetFullPage(kTestAllocSize); | 1013 firstSuperPagePages[i] = GetFullPage(kTestAllocSize); |
| 1014 | 1014 |
| 1015 char* pageBase = reinterpret_cast<char*>(WTF::partitionPageToPointer(firstSu perPagePages[0])); | 1015 char* pageBase = reinterpret_cast<char*>(partitionPageToPointer(firstSuperPa gePages[0])); |
| 1016 EXPECT_EQ(WTF::kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & W TF::kSuperPageOffsetMask); | 1016 EXPECT_EQ(kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & kSuper PageOffsetMask); |
| 1017 pageBase -= WTF::kPartitionPageSize; | 1017 pageBase -= kPartitionPageSize; |
| 1018 // Map a single system page either side of the mapping for our allocations, | 1018 // Map a single system page either side of the mapping for our allocations, |
| 1019 // with the goal of tripping up alignment of the next mapping. | 1019 // with the goal of tripping up alignment of the next mapping. |
| 1020 void* map1 = WTF::allocPages(pageBase - WTF::kPageAllocationGranularity, WTF ::kPageAllocationGranularity, WTF::kPageAllocationGranularity, WTF::PageInaccess ible); | 1020 void* map1 = allocPages(pageBase - kPageAllocationGranularity, kPageAllocati onGranularity, kPageAllocationGranularity, PageInaccessible); |
| 1021 EXPECT_TRUE(map1); | 1021 EXPECT_TRUE(map1); |
| 1022 void* map2 = WTF::allocPages(pageBase + WTF::kSuperPageSize, WTF::kPageAlloc ationGranularity, WTF::kPageAllocationGranularity, WTF::PageInaccessible); | 1022 void* map2 = allocPages(pageBase + kSuperPageSize, kPageAllocationGranularit y, kPageAllocationGranularity, PageInaccessible); |
| 1023 EXPECT_TRUE(map2); | 1023 EXPECT_TRUE(map2); |
| 1024 | 1024 |
| 1025 for (i = 0; i < numPartitionPagesNeeded; ++i) | 1025 for (i = 0; i < numPartitionPagesNeeded; ++i) |
| 1026 secondSuperPagePages[i] = GetFullPage(kTestAllocSize); | 1026 secondSuperPagePages[i] = GetFullPage(kTestAllocSize); |
| 1027 | 1027 |
| 1028 WTF::freePages(map1, WTF::kPageAllocationGranularity); | 1028 freePages(map1, kPageAllocationGranularity); |
| 1029 WTF::freePages(map2, WTF::kPageAllocationGranularity); | 1029 freePages(map2, kPageAllocationGranularity); |
| 1030 | 1030 |
| 1031 pageBase = reinterpret_cast<char*>(partitionPageToPointer(secondSuperPagePag es[0])); | 1031 pageBase = reinterpret_cast<char*>(partitionPageToPointer(secondSuperPagePag es[0])); |
| 1032 EXPECT_EQ(WTF::kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & W TF::kSuperPageOffsetMask); | 1032 EXPECT_EQ(kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & kSuper PageOffsetMask); |
| 1033 pageBase -= WTF::kPartitionPageSize; | 1033 pageBase -= kPartitionPageSize; |
| 1034 // Map a single system page either side of the mapping for our allocations, | 1034 // Map a single system page either side of the mapping for our allocations, |
| 1035 // with the goal of tripping up alignment of the next mapping. | 1035 // with the goal of tripping up alignment of the next mapping. |
| 1036 map1 = WTF::allocPages(pageBase - WTF::kPageAllocationGranularity, WTF::kPag eAllocationGranularity, WTF::kPageAllocationGranularity, WTF::PageAccessible); | 1036 map1 = allocPages(pageBase - kPageAllocationGranularity, kPageAllocationGran ularity, kPageAllocationGranularity, PageAccessible); |
| 1037 EXPECT_TRUE(map1); | 1037 EXPECT_TRUE(map1); |
| 1038 map2 = WTF::allocPages(pageBase + WTF::kSuperPageSize, WTF::kPageAllocationG ranularity, WTF::kPageAllocationGranularity, WTF::PageAccessible); | 1038 map2 = allocPages(pageBase + kSuperPageSize, kPageAllocationGranularity, kPa geAllocationGranularity, PageAccessible); |
| 1039 EXPECT_TRUE(map2); | 1039 EXPECT_TRUE(map2); |
| 1040 WTF::setSystemPagesInaccessible(map1, WTF::kPageAllocationGranularity); | 1040 setSystemPagesInaccessible(map1, kPageAllocationGranularity); |
| 1041 WTF::setSystemPagesInaccessible(map2, WTF::kPageAllocationGranularity); | 1041 setSystemPagesInaccessible(map2, kPageAllocationGranularity); |
| 1042 | 1042 |
| 1043 WTF::PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize); | 1043 PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize); |
| 1044 WTF::freePages(map1, WTF::kPageAllocationGranularity); | 1044 freePages(map1, kPageAllocationGranularity); |
| 1045 WTF::freePages(map2, WTF::kPageAllocationGranularity); | 1045 freePages(map2, kPageAllocationGranularity); |
| 1046 | 1046 |
| 1047 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThird SuperPage)) & WTF::kPartitionPageOffsetMask); | 1047 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThird SuperPage)) & kPartitionPageOffsetMask); |
| 1048 | 1048 |
| 1049 // And make sure we really did get a page in a new superpage. | 1049 // And make sure we really did get a page in a new superpage. |
| 1050 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(firstSuperPageP ages[0])) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageTo Pointer(pageInThirdSuperPage)) & WTF::kSuperPageBaseMask); | 1050 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(firstSuperPageP ages[0])) & kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPoint er(pageInThirdSuperPage)) & kSuperPageBaseMask); |
| 1051 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(secondSuperPage Pages[0])) & WTF::kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageT oPointer(pageInThirdSuperPage)) & WTF::kSuperPageBaseMask); | 1051 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(secondSuperPage Pages[0])) & kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPoin ter(pageInThirdSuperPage)) & kSuperPageBaseMask); |
| 1052 | 1052 |
| 1053 FreeFullPage(pageInThirdSuperPage); | 1053 FreeFullPage(pageInThirdSuperPage); |
| 1054 for (i = 0; i < numPartitionPagesNeeded; ++i) { | 1054 for (i = 0; i < numPartitionPagesNeeded; ++i) { |
| 1055 FreeFullPage(firstSuperPagePages[i]); | 1055 FreeFullPage(firstSuperPagePages[i]); |
| 1056 FreeFullPage(secondSuperPagePages[i]); | 1056 FreeFullPage(secondSuperPagePages[i]); |
| 1057 } | 1057 } |
| 1058 | 1058 |
| 1059 TestShutdown(); | 1059 TestShutdown(); |
| 1060 } | 1060 } |
| 1061 | 1061 |
| 1062 // Tests that pages in the free page cache do get freed as appropriate. | 1062 // Tests that pages in the free page cache do get freed as appropriate. |
| 1063 TEST(PartitionAllocTest, FreeCache) | 1063 TEST(PartitionAllocTest, FreeCache) |
| 1064 { | 1064 { |
| 1065 TestSetup(); | 1065 TestSetup(); |
| 1066 | 1066 |
| 1067 EXPECT_EQ(0U, allocator.root()->totalSizeOfCommittedPages); | 1067 EXPECT_EQ(0U, allocator.root()->totalSizeOfCommittedPages); |
| 1068 | 1068 |
| 1069 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize; | 1069 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize; |
| 1070 size_t bucketIdx = (bigSize + kExtraAllocSize) >> WTF::kBucketShift; | 1070 size_t bucketIdx = (bigSize + kExtraAllocSize) >> kBucketShift; |
| 1071 WTF::PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; | 1071 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; |
| 1072 | 1072 |
| 1073 void* ptr = partitionAlloc(allocator.root(), bigSize); | 1073 void* ptr = partitionAlloc(allocator.root(), bigSize); |
| 1074 EXPECT_TRUE(ptr); | 1074 EXPECT_TRUE(ptr); |
| 1075 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieF reePointerAdjust(ptr)); | 1075 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); |
| 1076 EXPECT_EQ(0, bucket->emptyPagesHead); | 1076 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 1077 EXPECT_EQ(1, page->numAllocatedSlots); | 1077 EXPECT_EQ(1, page->numAllocatedSlots); |
| 1078 EXPECT_EQ(WTF::kPartitionPageSize, allocator.root()->totalSizeOfCommittedPag es); | 1078 EXPECT_EQ(kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages); |
| 1079 partitionFree(ptr); | 1079 partitionFree(ptr); |
| 1080 EXPECT_EQ(0, page->numAllocatedSlots); | 1080 EXPECT_EQ(0, page->numAllocatedSlots); |
| 1081 EXPECT_NE(-1, page->emptyCacheIndex); | 1081 EXPECT_NE(-1, page->emptyCacheIndex); |
| 1082 EXPECT_TRUE(page->freelistHead); | 1082 EXPECT_TRUE(page->freelistHead); |
| 1083 | 1083 |
| 1084 CycleFreeCache(kTestAllocSize); | 1084 CycleFreeCache(kTestAllocSize); |
| 1085 | 1085 |
| 1086 // Flushing the cache should have really freed the unused page. | 1086 // Flushing the cache should have really freed the unused page. |
| 1087 EXPECT_FALSE(page->freelistHead); | 1087 EXPECT_FALSE(page->freelistHead); |
| 1088 EXPECT_EQ(-1, page->emptyCacheIndex); | 1088 EXPECT_EQ(-1, page->emptyCacheIndex); |
| 1089 EXPECT_EQ(0, page->numAllocatedSlots); | 1089 EXPECT_EQ(0, page->numAllocatedSlots); |
| 1090 WTF::PartitionBucket* cycleFreeCacheBucket = &allocator.root()->buckets()[kT estBucketIndex]; | 1090 PartitionBucket* cycleFreeCacheBucket = &allocator.root()->buckets()[kTestBu cketIndex]; |
| 1091 EXPECT_EQ(cycleFreeCacheBucket->numSystemPagesPerSlotSpan * WTF::kSystemPage Size, allocator.root()->totalSizeOfCommittedPages); | 1091 EXPECT_EQ(cycleFreeCacheBucket->numSystemPagesPerSlotSpan * kSystemPageSize, allocator.root()->totalSizeOfCommittedPages); |
| 1092 | 1092 |
| 1093 // Check that an allocation works ok whilst in this state (a free'd page | 1093 // Check that an allocation works ok whilst in this state (a free'd page |
| 1094 // as the active pages head). | 1094 // as the active pages head). |
| 1095 ptr = partitionAlloc(allocator.root(), bigSize); | 1095 ptr = partitionAlloc(allocator.root(), bigSize); |
| 1096 EXPECT_FALSE(bucket->emptyPagesHead); | 1096 EXPECT_FALSE(bucket->emptyPagesHead); |
| 1097 partitionFree(ptr); | 1097 partitionFree(ptr); |
| 1098 | 1098 |
| 1099 // Also check that a page that is bouncing immediately between empty and | 1099 // Also check that a page that is bouncing immediately between empty and |
| 1100 // used does not get freed. | 1100 // used does not get freed. |
| 1101 for (size_t i = 0; i < WTF::kMaxFreeableSpans * 2; ++i) { | 1101 for (size_t i = 0; i < kMaxFreeableSpans * 2; ++i) { |
| 1102 ptr = partitionAlloc(allocator.root(), bigSize); | 1102 ptr = partitionAlloc(allocator.root(), bigSize); |
| 1103 EXPECT_TRUE(page->freelistHead); | 1103 EXPECT_TRUE(page->freelistHead); |
| 1104 partitionFree(ptr); | 1104 partitionFree(ptr); |
| 1105 EXPECT_TRUE(page->freelistHead); | 1105 EXPECT_TRUE(page->freelistHead); |
| 1106 } | 1106 } |
| 1107 EXPECT_EQ(WTF::kPartitionPageSize, allocator.root()->totalSizeOfCommittedPag es); | 1107 EXPECT_EQ(kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages); |
| 1108 TestShutdown(); | 1108 TestShutdown(); |
| 1109 } | 1109 } |
| 1110 | 1110 |
| 1111 // Tests for a bug we had with losing references to free pages. | 1111 // Tests for a bug we had with losing references to free pages. |
| 1112 TEST(PartitionAllocTest, LostFreePagesBug) | 1112 TEST(PartitionAllocTest, LostFreePagesBug) |
| 1113 { | 1113 { |
| 1114 TestSetup(); | 1114 TestSetup(); |
| 1115 | 1115 |
| 1116 size_t size = WTF::kPartitionPageSize - kExtraAllocSize; | 1116 size_t size = kPartitionPageSize - kExtraAllocSize; |
| 1117 | 1117 |
| 1118 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); | 1118 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 1119 EXPECT_TRUE(ptr); | 1119 EXPECT_TRUE(ptr); |
| 1120 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); | 1120 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); |
| 1121 EXPECT_TRUE(ptr2); | 1121 EXPECT_TRUE(ptr2); |
| 1122 | 1122 |
| 1123 WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieF reePointerAdjust(ptr)); | 1123 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); |
| 1124 WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookie FreePointerAdjust(ptr2)); | 1124 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr2)); |
| 1125 WTF::PartitionBucket* bucket = page->bucket; | 1125 PartitionBucket* bucket = page->bucket; |
| 1126 | 1126 |
| 1127 EXPECT_EQ(0, bucket->emptyPagesHead); | 1127 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 1128 EXPECT_EQ(-1, page->numAllocatedSlots); | 1128 EXPECT_EQ(-1, page->numAllocatedSlots); |
| 1129 EXPECT_EQ(1, page2->numAllocatedSlots); | 1129 EXPECT_EQ(1, page2->numAllocatedSlots); |
| 1130 | 1130 |
| 1131 partitionFreeGeneric(genericAllocator.root(), ptr); | 1131 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 1132 partitionFreeGeneric(genericAllocator.root(), ptr2); | 1132 partitionFreeGeneric(genericAllocator.root(), ptr2); |
| 1133 | 1133 |
| 1134 EXPECT_EQ(0, bucket->emptyPagesHead); | 1134 EXPECT_EQ(0, bucket->emptyPagesHead); |
| 1135 EXPECT_EQ(0, page->numAllocatedSlots); | 1135 EXPECT_EQ(0, page->numAllocatedSlots); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1188 EXPECT_TRUE(SetAddressSpaceLimit()); | 1188 EXPECT_TRUE(SetAddressSpaceLimit()); |
| 1189 | 1189 |
| 1190 // 512 kB x 12288 == 6 GB | 1190 // 512 kB x 12288 == 6 GB |
| 1191 const size_t blockSize = 512 * 1024; | 1191 const size_t blockSize = 512 * 1024; |
| 1192 const int numAllocations = 12288; | 1192 const int numAllocations = 12288; |
| 1193 | 1193 |
| 1194 void* ptrs[numAllocations]; | 1194 void* ptrs[numAllocations]; |
| 1195 int i; | 1195 int i; |
| 1196 | 1196 |
| 1197 for (i = 0; i < numAllocations; ++i) { | 1197 for (i = 0; i < numAllocations; ++i) { |
| 1198 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), WTF::Parti tionAllocReturnNull, blockSize); | 1198 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionA llocReturnNull, blockSize); |
| 1199 if (!ptrs[i]) { | 1199 if (!ptrs[i]) { |
| 1200 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), WTF::P artitionAllocReturnNull, blockSize); | 1200 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), Partit ionAllocReturnNull, blockSize); |
| 1201 EXPECT_FALSE(ptrs[i]); | 1201 EXPECT_FALSE(ptrs[i]); |
| 1202 break; | 1202 break; |
| 1203 } | 1203 } |
| 1204 } | 1204 } |
| 1205 | 1205 |
| 1206 // We shouldn't succeed in allocating all 6 GB of memory. If we do, then | 1206 // We shouldn't succeed in allocating all 6 GB of memory. If we do, then |
| 1207 // we're not actually testing anything here. | 1207 // we're not actually testing anything here. |
| 1208 EXPECT_LT(i, numAllocations); | 1208 EXPECT_LT(i, numAllocations); |
| 1209 | 1209 |
| 1210 // Free, reallocate and free again each block we allocated. We do this to | 1210 // Free, reallocate and free again each block we allocated. We do this to |
| 1211 // check that freeing memory also works correctly after a failed allocation. | 1211 // check that freeing memory also works correctly after a failed allocation. |
| 1212 for (--i; i >= 0; --i) { | 1212 for (--i; i >= 0; --i) { |
| 1213 partitionFreeGeneric(genericAllocator.root(), ptrs[i]); | 1213 partitionFreeGeneric(genericAllocator.root(), ptrs[i]); |
| 1214 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), WTF::Parti tionAllocReturnNull, blockSize); | 1214 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionA llocReturnNull, blockSize); |
| 1215 EXPECT_TRUE(ptrs[i]); | 1215 EXPECT_TRUE(ptrs[i]); |
| 1216 partitionFreeGeneric(genericAllocator.root(), ptrs[i]); | 1216 partitionFreeGeneric(genericAllocator.root(), ptrs[i]); |
| 1217 } | 1217 } |
| 1218 | 1218 |
| 1219 EXPECT_TRUE(ClearAddressSpaceLimit()); | 1219 EXPECT_TRUE(ClearAddressSpaceLimit()); |
| 1220 | 1220 |
| 1221 TestShutdown(); | 1221 TestShutdown(); |
| 1222 } | 1222 } |
| 1223 | 1223 |
| 1224 #endif // !CPU(64BIT) || OS(POSIX) | 1224 #endif // !CPU(64BIT) || OS(POSIX) |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1272 TestShutdown(); | 1272 TestShutdown(); |
| 1273 } | 1273 } |
| 1274 | 1274 |
| 1275 // Check that guard pages are present where expected. | 1275 // Check that guard pages are present where expected. |
| 1276 TEST(PartitionAllocDeathTest, GuardPages) | 1276 TEST(PartitionAllocDeathTest, GuardPages) |
| 1277 { | 1277 { |
| 1278 TestSetup(); | 1278 TestSetup(); |
| 1279 | 1279 |
| 1280 // This large size will result in a direct mapped allocation with guard | 1280 // This large size will result in a direct mapped allocation with guard |
| 1281 // pages at either end. | 1281 // pages at either end. |
| 1282 size_t size = (WTF::kGenericMaxBucketed + WTF::kSystemPageSize) - kExtraAllo cSize; | 1282 size_t size = (kGenericMaxBucketed + kSystemPageSize) - kExtraAllocSize; |
| 1283 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); | 1283 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); |
| 1284 EXPECT_TRUE(ptr); | 1284 EXPECT_TRUE(ptr); |
| 1285 char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset; | 1285 char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset; |
| 1286 | 1286 |
| 1287 EXPECT_DEATH(*(charPtr - 1) = 'A', ""); | 1287 EXPECT_DEATH(*(charPtr - 1) = 'A', ""); |
| 1288 EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', ""); | 1288 EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', ""); |
| 1289 | 1289 |
| 1290 partitionFreeGeneric(genericAllocator.root(), ptr); | 1290 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 1291 | 1291 |
| 1292 TestShutdown(); | 1292 TestShutdown(); |
| 1293 } | 1293 } |
| 1294 | 1294 |
| 1295 // Check that a bad free() is caught where the free() refers to an unused | 1295 // Check that a bad free() is caught where the free() refers to an unused |
| 1296 // partition page of a large allocation. | 1296 // partition page of a large allocation. |
| 1297 TEST(PartitionAllocDeathTest, FreeWrongPartitionPage) | 1297 TEST(PartitionAllocDeathTest, FreeWrongPartitionPage) |
| 1298 { | 1298 { |
| 1299 TestSetup(); | 1299 TestSetup(); |
| 1300 | 1300 |
| 1301 // This large size will result in a direct mapped allocation with guard | 1301 // This large size will result in a direct mapped allocation with guard |
| 1302 // pages at either end. | 1302 // pages at either end. |
| 1303 void* ptr = partitionAllocGeneric(genericAllocator.root(), WTF::kPartitionPa geSize * 2); | 1303 void* ptr = partitionAllocGeneric(genericAllocator.root(), kPartitionPageSiz e * 2); |
| 1304 EXPECT_TRUE(ptr); | 1304 EXPECT_TRUE(ptr); |
| 1305 char* badPtr = reinterpret_cast<char*>(ptr) + WTF::kPartitionPageSize; | 1305 char* badPtr = reinterpret_cast<char*>(ptr) + kPartitionPageSize; |
| 1306 | 1306 |
| 1307 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), badPtr), ""); | 1307 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), badPtr), ""); |
| 1308 | 1308 |
| 1309 partitionFreeGeneric(genericAllocator.root(), ptr); | 1309 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 1310 | 1310 |
| 1311 TestShutdown(); | 1311 TestShutdown(); |
| 1312 } | 1312 } |
| 1313 | 1313 |
| 1314 #endif // !OS(ANDROID) | 1314 #endif // !OS(ANDROID) |
| 1315 | 1315 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1328 } | 1328 } |
| 1329 | 1329 |
| 1330 // This series of tests checks the active -> empty -> decommitted states. | 1330 // This series of tests checks the active -> empty -> decommitted states. |
| 1331 { | 1331 { |
| 1332 void* genericPtr = partitionAllocGeneric(genericAllocator.root(), 2048 - kExtraAllocSize); | 1332 void* genericPtr = partitionAllocGeneric(genericAllocator.root(), 2048 - kExtraAllocSize); |
| 1333 { | 1333 { |
| 1334 MockPartitionStatsDumper mockStatsDumperGeneric; | 1334 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1335 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); | 1335 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); |
| 1336 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1336 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1337 | 1337 |
| 1338 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneri c.GetBucketStats(2048); | 1338 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(2048); |
| 1339 EXPECT_TRUE(stats); | 1339 EXPECT_TRUE(stats); |
| 1340 EXPECT_TRUE(stats->isValid); | 1340 EXPECT_TRUE(stats->isValid); |
| 1341 EXPECT_EQ(2048u, stats->bucketSlotSize); | 1341 EXPECT_EQ(2048u, stats->bucketSlotSize); |
| 1342 EXPECT_EQ(2048u, stats->activeBytes); | 1342 EXPECT_EQ(2048u, stats->activeBytes); |
| 1343 EXPECT_EQ(WTF::kSystemPageSize, stats->residentBytes); | 1343 EXPECT_EQ(kSystemPageSize, stats->residentBytes); |
| 1344 EXPECT_EQ(0u, stats->freeableBytes); | 1344 EXPECT_EQ(0u, stats->freeableBytes); |
| 1345 EXPECT_EQ(0u, stats->numFullPages); | 1345 EXPECT_EQ(0u, stats->numFullPages); |
| 1346 EXPECT_EQ(1u, stats->numActivePages); | 1346 EXPECT_EQ(1u, stats->numActivePages); |
| 1347 EXPECT_EQ(0u, stats->numEmptyPages); | 1347 EXPECT_EQ(0u, stats->numEmptyPages); |
| 1348 EXPECT_EQ(0u, stats->numDecommittedPages); | 1348 EXPECT_EQ(0u, stats->numDecommittedPages); |
| 1349 } | 1349 } |
| 1350 | 1350 |
| 1351 partitionFreeGeneric(genericAllocator.root(), genericPtr); | 1351 partitionFreeGeneric(genericAllocator.root(), genericPtr); |
| 1352 | 1352 |
| 1353 { | 1353 { |
| 1354 MockPartitionStatsDumper mockStatsDumperGeneric; | 1354 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1355 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); | 1355 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); |
| 1356 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1356 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1357 | 1357 |
| 1358 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneri c.GetBucketStats(2048); | 1358 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(2048); |
| 1359 EXPECT_TRUE(stats); | 1359 EXPECT_TRUE(stats); |
| 1360 EXPECT_TRUE(stats->isValid); | 1360 EXPECT_TRUE(stats->isValid); |
| 1361 EXPECT_EQ(2048u, stats->bucketSlotSize); | 1361 EXPECT_EQ(2048u, stats->bucketSlotSize); |
| 1362 EXPECT_EQ(0u, stats->activeBytes); | 1362 EXPECT_EQ(0u, stats->activeBytes); |
| 1363 EXPECT_EQ(WTF::kSystemPageSize, stats->residentBytes); | 1363 EXPECT_EQ(kSystemPageSize, stats->residentBytes); |
| 1364 EXPECT_EQ(WTF::kSystemPageSize, stats->freeableBytes); | 1364 EXPECT_EQ(kSystemPageSize, stats->freeableBytes); |
| 1365 EXPECT_EQ(0u, stats->numFullPages); | 1365 EXPECT_EQ(0u, stats->numFullPages); |
| 1366 EXPECT_EQ(0u, stats->numActivePages); | 1366 EXPECT_EQ(0u, stats->numActivePages); |
| 1367 EXPECT_EQ(1u, stats->numEmptyPages); | 1367 EXPECT_EQ(1u, stats->numEmptyPages); |
| 1368 EXPECT_EQ(0u, stats->numDecommittedPages); | 1368 EXPECT_EQ(0u, stats->numDecommittedPages); |
| 1369 } | 1369 } |
| 1370 | 1370 |
| 1371 CycleGenericFreeCache(kTestAllocSize); | 1371 CycleGenericFreeCache(kTestAllocSize); |
| 1372 | 1372 |
| 1373 { | 1373 { |
| 1374 MockPartitionStatsDumper mockStatsDumperGeneric; | 1374 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1375 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); | 1375 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); |
| 1376 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1376 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1377 | 1377 |
| 1378 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneri c.GetBucketStats(2048); | 1378 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(2048); |
| 1379 EXPECT_TRUE(stats); | 1379 EXPECT_TRUE(stats); |
| 1380 EXPECT_TRUE(stats->isValid); | 1380 EXPECT_TRUE(stats->isValid); |
| 1381 EXPECT_EQ(2048u, stats->bucketSlotSize); | 1381 EXPECT_EQ(2048u, stats->bucketSlotSize); |
| 1382 EXPECT_EQ(0u, stats->activeBytes); | 1382 EXPECT_EQ(0u, stats->activeBytes); |
| 1383 EXPECT_EQ(0u, stats->residentBytes); | 1383 EXPECT_EQ(0u, stats->residentBytes); |
| 1384 EXPECT_EQ(0u, stats->freeableBytes); | 1384 EXPECT_EQ(0u, stats->freeableBytes); |
| 1385 EXPECT_EQ(0u, stats->numFullPages); | 1385 EXPECT_EQ(0u, stats->numFullPages); |
| 1386 EXPECT_EQ(0u, stats->numActivePages); | 1386 EXPECT_EQ(0u, stats->numActivePages); |
| 1387 EXPECT_EQ(0u, stats->numEmptyPages); | 1387 EXPECT_EQ(0u, stats->numEmptyPages); |
| 1388 EXPECT_EQ(1u, stats->numDecommittedPages); | 1388 EXPECT_EQ(1u, stats->numDecommittedPages); |
| 1389 } | 1389 } |
| 1390 } | 1390 } |
| 1391 | 1391 |
| 1392 // This test checks for correct empty page list accounting. | 1392 // This test checks for correct empty page list accounting. |
| 1393 { | 1393 { |
| 1394 size_t size = WTF::kPartitionPageSize - kExtraAllocSize; | 1394 size_t size = kPartitionPageSize - kExtraAllocSize; |
| 1395 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), size); | 1395 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), size); |
| 1396 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); | 1396 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); |
| 1397 partitionFreeGeneric(genericAllocator.root(), ptr1); | 1397 partitionFreeGeneric(genericAllocator.root(), ptr1); |
| 1398 partitionFreeGeneric(genericAllocator.root(), ptr2); | 1398 partitionFreeGeneric(genericAllocator.root(), ptr2); |
| 1399 | 1399 |
| 1400 CycleGenericFreeCache(kTestAllocSize); | 1400 CycleGenericFreeCache(kTestAllocSize); |
| 1401 | 1401 |
| 1402 ptr1 = partitionAllocGeneric(genericAllocator.root(), size); | 1402 ptr1 = partitionAllocGeneric(genericAllocator.root(), size); |
| 1403 | 1403 |
| 1404 { | 1404 { |
| 1405 MockPartitionStatsDumper mockStatsDumperGeneric; | 1405 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1406 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); | 1406 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); |
| 1407 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1407 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1408 | 1408 |
| 1409 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneri c.GetBucketStats(WTF::kPartitionPageSize); | 1409 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(kPartitionPageSize); |
| 1410 EXPECT_TRUE(stats); | 1410 EXPECT_TRUE(stats); |
| 1411 EXPECT_TRUE(stats->isValid); | 1411 EXPECT_TRUE(stats->isValid); |
| 1412 EXPECT_EQ(WTF::kPartitionPageSize, stats->bucketSlotSize); | 1412 EXPECT_EQ(kPartitionPageSize, stats->bucketSlotSize); |
| 1413 EXPECT_EQ(WTF::kPartitionPageSize, stats->activeBytes); | 1413 EXPECT_EQ(kPartitionPageSize, stats->activeBytes); |
| 1414 EXPECT_EQ(WTF::kPartitionPageSize, stats->residentBytes); | 1414 EXPECT_EQ(kPartitionPageSize, stats->residentBytes); |
| 1415 EXPECT_EQ(0u, stats->freeableBytes); | 1415 EXPECT_EQ(0u, stats->freeableBytes); |
| 1416 EXPECT_EQ(1u, stats->numFullPages); | 1416 EXPECT_EQ(1u, stats->numFullPages); |
| 1417 EXPECT_EQ(0u, stats->numActivePages); | 1417 EXPECT_EQ(0u, stats->numActivePages); |
| 1418 EXPECT_EQ(0u, stats->numEmptyPages); | 1418 EXPECT_EQ(0u, stats->numEmptyPages); |
| 1419 EXPECT_EQ(1u, stats->numDecommittedPages); | 1419 EXPECT_EQ(1u, stats->numDecommittedPages); |
| 1420 } | 1420 } |
| 1421 partitionFreeGeneric(genericAllocator.root(), ptr1); | 1421 partitionFreeGeneric(genericAllocator.root(), ptr1); |
| 1422 } | 1422 } |
| 1423 | 1423 |
| 1424 // This test checks for correct direct mapped accounting. | 1424 // This test checks for correct direct mapped accounting. |
| 1425 { | 1425 { |
| 1426 size_t sizeSmaller = WTF::kGenericMaxBucketed + 1; | 1426 size_t sizeSmaller = kGenericMaxBucketed + 1; |
| 1427 size_t sizeBigger = (WTF::kGenericMaxBucketed * 2) + 1; | 1427 size_t sizeBigger = (kGenericMaxBucketed * 2) + 1; |
| 1428 size_t realSizeSmaller = (sizeSmaller + WTF::kSystemPageOffsetMask) & WT F::kSystemPageBaseMask; | 1428 size_t realSizeSmaller = (sizeSmaller + kSystemPageOffsetMask) & kSystem PageBaseMask; |
| 1429 size_t realSizeBigger = (sizeBigger + WTF::kSystemPageOffsetMask) & WTF: :kSystemPageBaseMask; | 1429 size_t realSizeBigger = (sizeBigger + kSystemPageOffsetMask) & kSystemPa geBaseMask; |
| 1430 void* ptr = partitionAllocGeneric(genericAllocator.root(), sizeSmaller); | 1430 void* ptr = partitionAllocGeneric(genericAllocator.root(), sizeSmaller); |
| 1431 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), sizeBigger); | 1431 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), sizeBigger); |
| 1432 | 1432 |
| 1433 { | 1433 { |
| 1434 MockPartitionStatsDumper mockStatsDumperGeneric; | 1434 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1435 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); | 1435 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); |
| 1436 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1436 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1437 | 1437 |
| 1438 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneri c.GetBucketStats(realSizeSmaller); | 1438 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(realSizeSmaller); |
| 1439 EXPECT_TRUE(stats); | 1439 EXPECT_TRUE(stats); |
| 1440 EXPECT_TRUE(stats->isValid); | 1440 EXPECT_TRUE(stats->isValid); |
| 1441 EXPECT_TRUE(stats->isDirectMap); | 1441 EXPECT_TRUE(stats->isDirectMap); |
| 1442 EXPECT_EQ(realSizeSmaller, stats->bucketSlotSize); | 1442 EXPECT_EQ(realSizeSmaller, stats->bucketSlotSize); |
| 1443 EXPECT_EQ(realSizeSmaller, stats->activeBytes); | 1443 EXPECT_EQ(realSizeSmaller, stats->activeBytes); |
| 1444 EXPECT_EQ(realSizeSmaller, stats->residentBytes); | 1444 EXPECT_EQ(realSizeSmaller, stats->residentBytes); |
| 1445 EXPECT_EQ(0u, stats->freeableBytes); | 1445 EXPECT_EQ(0u, stats->freeableBytes); |
| 1446 EXPECT_EQ(1u, stats->numFullPages); | 1446 EXPECT_EQ(1u, stats->numFullPages); |
| 1447 EXPECT_EQ(0u, stats->numActivePages); | 1447 EXPECT_EQ(0u, stats->numActivePages); |
| 1448 EXPECT_EQ(0u, stats->numEmptyPages); | 1448 EXPECT_EQ(0u, stats->numEmptyPages); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1475 | 1475 |
| 1476 // This test checks large-but-not-quite-direct allocations. | 1476 // This test checks large-but-not-quite-direct allocations. |
| 1477 { | 1477 { |
| 1478 void* ptr = partitionAllocGeneric(genericAllocator.root(), 65537); | 1478 void* ptr = partitionAllocGeneric(genericAllocator.root(), 65537); |
| 1479 | 1479 |
| 1480 { | 1480 { |
| 1481 MockPartitionStatsDumper mockStatsDumperGeneric; | 1481 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1482 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); | 1482 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", &mockStatsDumperGeneric); |
| 1483 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1483 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1484 | 1484 |
| 1485 size_t slotSize = 65536 + (65536 / WTF::kGenericNumBucketsPerOrder); | 1485 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder); |
| 1486 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneri c.GetBucketStats(slotSize); | 1486 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(slotSize); |
| 1487 EXPECT_TRUE(stats); | 1487 EXPECT_TRUE(stats); |
| 1488 EXPECT_TRUE(stats->isValid); | 1488 EXPECT_TRUE(stats->isValid); |
| 1489 EXPECT_FALSE(stats->isDirectMap); | 1489 EXPECT_FALSE(stats->isDirectMap); |
| 1490 EXPECT_EQ(slotSize, stats->bucketSlotSize); | 1490 EXPECT_EQ(slotSize, stats->bucketSlotSize); |
| 1491 EXPECT_EQ(65536 + WTF::kSystemPageSize, stats->activeBytes); | 1491 EXPECT_EQ(65536 + kSystemPageSize, stats->activeBytes); |
| 1492 EXPECT_EQ(slotSize, stats->residentBytes); | 1492 EXPECT_EQ(slotSize, stats->residentBytes); |
| 1493 EXPECT_EQ(0u, stats->freeableBytes); | 1493 EXPECT_EQ(0u, stats->freeableBytes); |
| 1494 EXPECT_EQ(1u, stats->numFullPages); | 1494 EXPECT_EQ(1u, stats->numFullPages); |
| 1495 EXPECT_EQ(0u, stats->numActivePages); | 1495 EXPECT_EQ(0u, stats->numActivePages); |
| 1496 EXPECT_EQ(0u, stats->numEmptyPages); | 1496 EXPECT_EQ(0u, stats->numEmptyPages); |
| 1497 EXPECT_EQ(0u, stats->numDecommittedPages); | 1497 EXPECT_EQ(0u, stats->numDecommittedPages); |
| 1498 } | 1498 } |
| 1499 | 1499 |
| 1500 partitionFreeGeneric(genericAllocator.root(), ptr); | 1500 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 1501 } | 1501 } |
| 1502 | 1502 |
| 1503 TestShutdown(); | 1503 TestShutdown(); |
| 1504 } | 1504 } |
| 1505 | 1505 |
| 1506 // Tests the API to purge freeable memory. | 1506 // Tests the API to purge freeable memory. |
| 1507 TEST(PartitionAllocTest, Purge) | 1507 TEST(PartitionAllocTest, Purge) |
| 1508 { | 1508 { |
| 1509 TestSetup(); | 1509 TestSetup(); |
| 1510 | 1510 |
| 1511 void* ptr = partitionAllocGeneric(genericAllocator.root(), 2048 - kExtraAllo cSize); | 1511 void* ptr = partitionAllocGeneric(genericAllocator.root(), 2048 - kExtraAllo cSize); |
| 1512 partitionFreeGeneric(genericAllocator.root(), ptr); | 1512 partitionFreeGeneric(genericAllocator.root(), ptr); |
| 1513 { | 1513 { |
| 1514 MockPartitionStatsDumper mockStatsDumperGeneric; | 1514 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1515 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocat or", &mockStatsDumperGeneric); | 1515 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocat or", &mockStatsDumperGeneric); |
| 1516 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1516 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1517 | 1517 |
| 1518 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Ge tBucketStats(2048); | 1518 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBuck etStats(2048); |
| 1519 EXPECT_TRUE(stats); | 1519 EXPECT_TRUE(stats); |
| 1520 EXPECT_TRUE(stats->isValid); | 1520 EXPECT_TRUE(stats->isValid); |
| 1521 EXPECT_EQ(WTF::kSystemPageSize, stats->freeableBytes); | 1521 EXPECT_EQ(kSystemPageSize, stats->freeableBytes); |
| 1522 EXPECT_EQ(WTF::kSystemPageSize, stats->residentBytes); | 1522 EXPECT_EQ(kSystemPageSize, stats->residentBytes); |
| 1523 } | 1523 } |
| 1524 partitionPurgeMemoryGeneric(genericAllocator.root()); | 1524 partitionPurgeMemoryGeneric(genericAllocator.root()); |
| 1525 { | 1525 { |
| 1526 MockPartitionStatsDumper mockStatsDumperGeneric; | 1526 MockPartitionStatsDumper mockStatsDumperGeneric; |
| 1527 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocat or", &mockStatsDumperGeneric); | 1527 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocat or", &mockStatsDumperGeneric); |
| 1528 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); | 1528 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); |
| 1529 | 1529 |
| 1530 const WTF::PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Ge tBucketStats(2048); | 1530 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBuck etStats(2048); |
| 1531 EXPECT_TRUE(stats); | 1531 EXPECT_TRUE(stats); |
| 1532 EXPECT_TRUE(stats->isValid); | 1532 EXPECT_TRUE(stats->isValid); |
| 1533 EXPECT_EQ(0u, stats->freeableBytes); | 1533 EXPECT_EQ(0u, stats->freeableBytes); |
| 1534 EXPECT_EQ(0u, stats->residentBytes); | 1534 EXPECT_EQ(0u, stats->residentBytes); |
| 1535 } | 1535 } |
| 1536 // Calling purge again here is a good way of testing we didn't mess up the | 1536 // Calling purge again here is a good way of testing we didn't mess up the |
| 1537 // state of the free cache ring. | 1537 // state of the free cache ring. |
| 1538 partitionPurgeMemoryGeneric(genericAllocator.root()); | 1538 partitionPurgeMemoryGeneric(genericAllocator.root()); |
| 1539 TestShutdown(); | 1539 TestShutdown(); |
| 1540 } | 1540 } |
| 1541 | 1541 |
| 1542 // Tests that the countLeadingZeros() functions work to our satisfaction. | 1542 // Tests that the countLeadingZeros() functions work to our satisfaction. |
| 1543 // It doesn't seem worth the overhead of a whole new file for these tests, so | 1543 // It doesn't seem worth the overhead of a whole new file for these tests, so |
| 1544 // we'll put them here since partitionAllocGeneric will depend heavily on these | 1544 // we'll put them here since partitionAllocGeneric will depend heavily on these |
| 1545 // functions working correctly. | 1545 // functions working correctly. |
| 1546 TEST(PartitionAllocTest, CLZWorks) | 1546 TEST(PartitionAllocTest, CLZWorks) |
| 1547 { | 1547 { |
| 1548 EXPECT_EQ(32u, WTF::countLeadingZeros32(0u)); | 1548 EXPECT_EQ(32u, countLeadingZeros32(0u)); |
| 1549 EXPECT_EQ(31u, WTF::countLeadingZeros32(1u)); | 1549 EXPECT_EQ(31u, countLeadingZeros32(1u)); |
| 1550 EXPECT_EQ(1u, WTF::countLeadingZeros32(1u << 30)); | 1550 EXPECT_EQ(1u, countLeadingZeros32(1u << 30)); |
| 1551 EXPECT_EQ(0u, WTF::countLeadingZeros32(1u << 31)); | 1551 EXPECT_EQ(0u, countLeadingZeros32(1u << 31)); |
| 1552 | 1552 |
| 1553 #if CPU(64BIT) | 1553 #if CPU(64BIT) |
| 1554 EXPECT_EQ(64u, WTF::countLeadingZerosSizet(0ull)); | 1554 EXPECT_EQ(64u, countLeadingZerosSizet(0ull)); |
| 1555 EXPECT_EQ(63u, WTF::countLeadingZerosSizet(1ull)); | 1555 EXPECT_EQ(63u, countLeadingZerosSizet(1ull)); |
| 1556 EXPECT_EQ(32u, WTF::countLeadingZerosSizet(1ull << 31)); | 1556 EXPECT_EQ(32u, countLeadingZerosSizet(1ull << 31)); |
| 1557 EXPECT_EQ(1u, WTF::countLeadingZerosSizet(1ull << 62)); | 1557 EXPECT_EQ(1u, countLeadingZerosSizet(1ull << 62)); |
| 1558 EXPECT_EQ(0u, WTF::countLeadingZerosSizet(1ull << 63)); | 1558 EXPECT_EQ(0u, countLeadingZerosSizet(1ull << 63)); |
| 1559 #else | 1559 #else |
| 1560 EXPECT_EQ(32u, WTF::countLeadingZerosSizet(0u)); | 1560 EXPECT_EQ(32u, countLeadingZerosSizet(0u)); |
| 1561 EXPECT_EQ(31u, WTF::countLeadingZerosSizet(1u)); | 1561 EXPECT_EQ(31u, countLeadingZerosSizet(1u)); |
| 1562 EXPECT_EQ(1u, WTF::countLeadingZerosSizet(1u << 30)); | 1562 EXPECT_EQ(1u, countLeadingZerosSizet(1u << 30)); |
| 1563 EXPECT_EQ(0u, WTF::countLeadingZerosSizet(1u << 31)); | 1563 EXPECT_EQ(0u, countLeadingZerosSizet(1u << 31)); |
| 1564 #endif | 1564 #endif |
| 1565 } | 1565 } |
| 1566 | 1566 |
| 1567 } // namespace | 1567 } // namespace WTF |
| 1568 | 1568 |
| 1569 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 1569 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| OLD | NEW |