Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: third_party/WebKit/Source/wtf/PartitionAllocTest.cpp

Issue 1436153002: Apply clang-format with Chromium-style without column limit. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 30 matching lines...) Expand all
41 #include <string.h> 41 #include <string.h>
42 42
43 #if OS(POSIX) 43 #if OS(POSIX)
44 #include <sys/mman.h> 44 #include <sys/mman.h>
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 WTF { 55 namespace WTF {
56 56
57 namespace { 57 namespace {
58 58
59 const size_t kTestMaxAllocation = 4096; 59 const size_t kTestMaxAllocation = 4096;
60 SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator; 60 SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator;
61 PartitionAllocatorGeneric genericAllocator; 61 PartitionAllocatorGeneric genericAllocator;
62 62
63 const size_t kTestAllocSize = 16; 63 const size_t kTestAllocSize = 16;
64 #if !ENABLE(ASSERT) 64 #if !ENABLE(ASSERT)
65 const size_t kPointerOffset = 0; 65 const size_t kPointerOffset = 0;
66 const size_t kExtraAllocSize = 0; 66 const size_t kExtraAllocSize = 0;
67 #else 67 #else
68 const size_t kPointerOffset = WTF::kCookieSize; 68 const size_t kPointerOffset = WTF::kCookieSize;
69 const size_t kExtraAllocSize = WTF::kCookieSize * 2; 69 const size_t kExtraAllocSize = WTF::kCookieSize * 2;
70 #endif 70 #endif
71 const size_t kRealAllocSize = kTestAllocSize + kExtraAllocSize; 71 const size_t kRealAllocSize = kTestAllocSize + kExtraAllocSize;
72 const size_t kTestBucketIndex = kRealAllocSize >> WTF::kBucketShift; 72 const size_t kTestBucketIndex = kRealAllocSize >> WTF::kBucketShift;
73 73
74 void TestSetup() 74 void TestSetup() {
75 { 75 allocator.init();
76 allocator.init(); 76 genericAllocator.init();
77 genericAllocator.init(); 77 }
78 } 78
79 79 void TestShutdown() {
80 void TestShutdown() 80 // We expect no leaks in the general case. We have a test for leak
81 { 81 // detection.
82 // We expect no leaks in the general case. We have a test for leak 82 EXPECT_TRUE(allocator.shutdown());
83 // detection. 83 EXPECT_TRUE(genericAllocator.shutdown());
84 EXPECT_TRUE(allocator.shutdown());
85 EXPECT_TRUE(genericAllocator.shutdown());
86 } 84 }
87 85
88 #if !CPU(64BIT) || OS(POSIX) 86 #if !CPU(64BIT) || OS(POSIX)
89 bool SetAddressSpaceLimit() 87 bool SetAddressSpaceLimit() {
90 {
91 #if !CPU(64BIT) 88 #if !CPU(64BIT)
92 // 32 bits => address space is limited already. 89 // 32 bits => address space is limited already.
93 return true; 90 return true;
94 #elif OS(POSIX) && !OS(MACOSX) 91 #elif OS(POSIX) && !OS(MACOSX)
95 // Mac will accept RLIMIT_AS changes but it is not enforced. 92 // Mac will accept RLIMIT_AS changes but it is not enforced.
96 // See https://crbug.com/435269 and rdar://17576114. 93 // See https://crbug.com/435269 and rdar://17576114.
97 const size_t kAddressSpaceLimit = static_cast<size_t>(4096) * 1024 * 1024; 94 const size_t kAddressSpaceLimit = static_cast<size_t>(4096) * 1024 * 1024;
98 struct rlimit limit; 95 struct rlimit limit;
99 if (getrlimit(RLIMIT_AS, &limit) != 0) 96 if (getrlimit(RLIMIT_AS, &limit) != 0)
100 return false; 97 return false;
101 if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > kAddressSpaceLimit) { 98 if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > kAddressSpaceLimit) {
102 limit.rlim_cur = kAddressSpaceLimit; 99 limit.rlim_cur = kAddressSpaceLimit;
103 if (setrlimit(RLIMIT_AS, &limit) != 0) 100 if (setrlimit(RLIMIT_AS, &limit) != 0)
104 return false; 101 return false;
102 }
103 return true;
104 #else
105 return false;
106 #endif
107 }
108
109 bool ClearAddressSpaceLimit() {
110 #if !CPU(64BIT)
111 return true;
112 #elif OS(POSIX)
113 struct rlimit limit;
114 if (getrlimit(RLIMIT_AS, &limit) != 0)
115 return false;
116 limit.rlim_cur = limit.rlim_max;
117 if (setrlimit(RLIMIT_AS, &limit) != 0)
118 return false;
119 return true;
120 #else
121 return false;
122 #endif
123 }
124 #endif
125
126 PartitionPage* GetFullPage(size_t size) {
127 size_t realSize = size + kExtraAllocSize;
128 size_t bucketIdx = realSize >> kBucketShift;
129 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
130 size_t numSlots = (bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / real Size;
131 void* first = 0;
132 void* last = 0;
133 size_t i;
134 for (i = 0; i < numSlots; ++i) {
135 void* ptr = partitionAlloc(allocator.root(), size);
136 EXPECT_TRUE(ptr);
137 if (!i)
138 first = partitionCookieFreePointerAdjust(ptr);
139 else if (i == numSlots - 1)
140 last = partitionCookieFreePointerAdjust(ptr);
141 }
142 EXPECT_EQ(partitionPointerToPage(first), partitionPointerToPage(last));
143 if (bucket->numSystemPagesPerSlotSpan == kNumSystemPagesPerPartitionPage)
144 EXPECT_EQ(reinterpret_cast<size_t>(first) & kPartitionPageBaseMask, reinterp ret_cast<size_t>(last) & kPartitionPageBaseMask);
145 EXPECT_EQ(numSlots, static_cast<size_t>(bucket->activePagesHead->numAllocatedS lots));
146 EXPECT_EQ(0, bucket->activePagesHead->freelistHead);
147 EXPECT_TRUE(bucket->activePagesHead);
148 EXPECT_TRUE(bucket->activePagesHead != &PartitionRootGeneric::gSeedPage);
149 return bucket->activePagesHead;
150 }
151
152 void FreeFullPage(PartitionPage* page) {
153 size_t size = page->bucket->slotSize;
154 size_t numSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / size;
155 EXPECT_EQ(numSlots, static_cast<size_t>(abs(page->numAllocatedSlots)));
156 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
157 size_t i;
158 for (i = 0; i < numSlots; ++i) {
159 partitionFree(ptr + kPointerOffset);
160 ptr += size;
161 }
162 }
163
164 void CycleFreeCache(size_t size) {
165 size_t realSize = size + kExtraAllocSize;
166 size_t bucketIdx = realSize >> kBucketShift;
167 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
168 ASSERT(!bucket->activePagesHead->numAllocatedSlots);
169
170 for (size_t i = 0; i < kMaxFreeableSpans; ++i) {
171 void* ptr = partitionAlloc(allocator.root(), size);
172 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
173 partitionFree(ptr);
174 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
175 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex);
176 }
177 }
178
179 void CycleGenericFreeCache(size_t size) {
180 for (size_t i = 0; i < kMaxFreeableSpans; ++i) {
181 void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
182 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr));
183 PartitionBucket* bucket = page->bucket;
184 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
185 partitionFreeGeneric(genericAllocator.root(), ptr);
186 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
187 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex);
188 }
189 }
190
191 void CheckPageInCore(void* ptr, bool inCore) {
192 #if OS(LINUX)
193 unsigned char ret;
194 EXPECT_EQ(0, mincore(ptr, kSystemPageSize, &ret));
195 EXPECT_EQ(inCore, ret);
196 #endif
197 }
198
199 class MockPartitionStatsDumper : public PartitionStatsDumper {
200 public:
201 MockPartitionStatsDumper()
202 : m_totalResidentBytes(0), m_totalActiveBytes(0), m_totalDecommittableByte s(0), m_totalDiscardableBytes(0) {}
203
204 void partitionDumpTotals(const char* partitionName, const PartitionMemoryStats * memoryStats) override {
205 EXPECT_GE(memoryStats->totalMmappedBytes, memoryStats->totalResidentBytes);
206 EXPECT_EQ(m_totalResidentBytes, memoryStats->totalResidentBytes);
207 EXPECT_EQ(m_totalActiveBytes, memoryStats->totalActiveBytes);
208 EXPECT_EQ(m_totalDecommittableBytes, memoryStats->totalDecommittableBytes);
209 EXPECT_EQ(m_totalDiscardableBytes, memoryStats->totalDiscardableBytes);
210 }
211
212 void partitionsDumpBucketStats(const char* partitionName, const PartitionBucke tMemoryStats* memoryStats) override {
213 (void)partitionName;
214 EXPECT_TRUE(memoryStats->isValid);
215 EXPECT_EQ(0u, memoryStats->bucketSlotSize & kAllocationGranularityMask);
216 m_bucketStats.append(*memoryStats);
217 m_totalResidentBytes += memoryStats->residentBytes;
218 m_totalActiveBytes += memoryStats->activeBytes;
219 m_totalDecommittableBytes += memoryStats->decommittableBytes;
220 m_totalDiscardableBytes += memoryStats->discardableBytes;
221 }
222
223 bool IsMemoryAllocationRecorded() {
224 return m_totalResidentBytes != 0 && m_totalActiveBytes != 0;
225 }
226
227 const PartitionBucketMemoryStats* GetBucketStats(size_t bucketSize) {
228 for (size_t i = 0; i < m_bucketStats.size(); ++i) {
229 if (m_bucketStats[i].bucketSlotSize == bucketSize)
230 return &m_bucketStats[i];
105 } 231 }
106 return true; 232 return 0;
107 #else 233 }
108 return false; 234
109 #endif 235 private:
110 } 236 size_t m_totalResidentBytes;
111 237 size_t m_totalActiveBytes;
112 bool ClearAddressSpaceLimit() 238 size_t m_totalDecommittableBytes;
113 { 239 size_t m_totalDiscardableBytes;
114 #if !CPU(64BIT) 240
115 return true; 241 Vector<PartitionBucketMemoryStats> m_bucketStats;
116 #elif OS(POSIX)
117 struct rlimit limit;
118 if (getrlimit(RLIMIT_AS, &limit) != 0)
119 return false;
120 limit.rlim_cur = limit.rlim_max;
121 if (setrlimit(RLIMIT_AS, &limit) != 0)
122 return false;
123 return true;
124 #else
125 return false;
126 #endif
127 }
128 #endif
129
130 PartitionPage* GetFullPage(size_t size)
131 {
132 size_t realSize = size + kExtraAllocSize;
133 size_t bucketIdx = realSize >> kBucketShift;
134 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
135 size_t numSlots = (bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / re alSize;
136 void* first = 0;
137 void* last = 0;
138 size_t i;
139 for (i = 0; i < numSlots; ++i) {
140 void* ptr = partitionAlloc(allocator.root(), size);
141 EXPECT_TRUE(ptr);
142 if (!i)
143 first = partitionCookieFreePointerAdjust(ptr);
144 else if (i == numSlots - 1)
145 last = partitionCookieFreePointerAdjust(ptr);
146 }
147 EXPECT_EQ(partitionPointerToPage(first), partitionPointerToPage(last));
148 if (bucket->numSystemPagesPerSlotSpan == kNumSystemPagesPerPartitionPage)
149 EXPECT_EQ(reinterpret_cast<size_t>(first) & kPartitionPageBaseMask, rein terpret_cast<size_t>(last) & kPartitionPageBaseMask);
150 EXPECT_EQ(numSlots, static_cast<size_t>(bucket->activePagesHead->numAllocate dSlots));
151 EXPECT_EQ(0, bucket->activePagesHead->freelistHead);
152 EXPECT_TRUE(bucket->activePagesHead);
153 EXPECT_TRUE(bucket->activePagesHead != &PartitionRootGeneric::gSeedPage);
154 return bucket->activePagesHead;
155 }
156
157 void FreeFullPage(PartitionPage* page)
158 {
159 size_t size = page->bucket->slotSize;
160 size_t numSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize ) / size;
161 EXPECT_EQ(numSlots, static_cast<size_t>(abs(page->numAllocatedSlots)));
162 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page));
163 size_t i;
164 for (i = 0; i < numSlots; ++i) {
165 partitionFree(ptr + kPointerOffset);
166 ptr += size;
167 }
168 }
169
170 void CycleFreeCache(size_t size)
171 {
172 size_t realSize = size + kExtraAllocSize;
173 size_t bucketIdx = realSize >> kBucketShift;
174 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
175 ASSERT(!bucket->activePagesHead->numAllocatedSlots);
176
177 for (size_t i = 0; i < kMaxFreeableSpans; ++i) {
178 void* ptr = partitionAlloc(allocator.root(), size);
179 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
180 partitionFree(ptr);
181 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
182 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex);
183 }
184 }
185
186 void CycleGenericFreeCache(size_t size)
187 {
188 for (size_t i = 0; i < kMaxFreeableSpans; ++i) {
189 void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
190 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerA djust(ptr));
191 PartitionBucket* bucket = page->bucket;
192 EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
193 partitionFreeGeneric(genericAllocator.root(), ptr);
194 EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
195 EXPECT_NE(-1, bucket->activePagesHead->emptyCacheIndex);
196 }
197 }
198
199 void CheckPageInCore(void* ptr, bool inCore)
200 {
201 #if OS(LINUX)
202 unsigned char ret;
203 EXPECT_EQ(0, mincore(ptr, kSystemPageSize, &ret));
204 EXPECT_EQ(inCore, ret);
205 #endif
206 }
207
208 class MockPartitionStatsDumper : public PartitionStatsDumper {
209 public:
210 MockPartitionStatsDumper()
211 : m_totalResidentBytes(0)
212 , m_totalActiveBytes(0)
213 , m_totalDecommittableBytes(0)
214 , m_totalDiscardableBytes(0) { }
215
216 void partitionDumpTotals(const char* partitionName, const PartitionMemorySta ts* memoryStats) override
217 {
218 EXPECT_GE(memoryStats->totalMmappedBytes, memoryStats->totalResidentByte s);
219 EXPECT_EQ(m_totalResidentBytes, memoryStats->totalResidentBytes);
220 EXPECT_EQ(m_totalActiveBytes, memoryStats->totalActiveBytes);
221 EXPECT_EQ(m_totalDecommittableBytes, memoryStats->totalDecommittableByte s);
222 EXPECT_EQ(m_totalDiscardableBytes, memoryStats->totalDiscardableBytes);
223 }
224
225 void partitionsDumpBucketStats(const char* partitionName, const PartitionBuc ketMemoryStats* memoryStats) override
226 {
227 (void) partitionName;
228 EXPECT_TRUE(memoryStats->isValid);
229 EXPECT_EQ(0u, memoryStats->bucketSlotSize & kAllocationGranularityMask);
230 m_bucketStats.append(*memoryStats);
231 m_totalResidentBytes += memoryStats->residentBytes;
232 m_totalActiveBytes += memoryStats->activeBytes;
233 m_totalDecommittableBytes += memoryStats->decommittableBytes;
234 m_totalDiscardableBytes += memoryStats->discardableBytes;
235 }
236
237 bool IsMemoryAllocationRecorded()
238 {
239 return m_totalResidentBytes != 0 && m_totalActiveBytes != 0;
240 }
241
242 const PartitionBucketMemoryStats* GetBucketStats(size_t bucketSize)
243 {
244 for (size_t i = 0; i < m_bucketStats.size(); ++i) {
245 if (m_bucketStats[i].bucketSlotSize == bucketSize)
246 return &m_bucketStats[i];
247 }
248 return 0;
249 }
250
251 private:
252 size_t m_totalResidentBytes;
253 size_t m_totalActiveBytes;
254 size_t m_totalDecommittableBytes;
255 size_t m_totalDiscardableBytes;
256
257 Vector<PartitionBucketMemoryStats> m_bucketStats;
258 }; 242 };
259 243
260 } // anonymous namespace 244 } // anonymous namespace
261 245
262 // Check that the most basic of allocate / free pairs work. 246 // Check that the most basic of allocate / free pairs work.
263 TEST(PartitionAllocTest, Basic) 247 TEST(PartitionAllocTest, Basic) {
264 { 248 TestSetup();
265 TestSetup(); 249 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
266 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; 250 PartitionPage* seedPage = &PartitionRootGeneric::gSeedPage;
267 PartitionPage* seedPage = &PartitionRootGeneric::gSeedPage; 251
268 252 EXPECT_FALSE(bucket->emptyPagesHead);
269 EXPECT_FALSE(bucket->emptyPagesHead); 253 EXPECT_FALSE(bucket->decommittedPagesHead);
270 EXPECT_FALSE(bucket->decommittedPagesHead); 254 EXPECT_EQ(seedPage, bucket->activePagesHead);
271 EXPECT_EQ(seedPage, bucket->activePagesHead); 255 EXPECT_EQ(0, bucket->activePagesHead->nextPage);
272 EXPECT_EQ(0, bucket->activePagesHead->nextPage); 256
273 257 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
274 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); 258 EXPECT_TRUE(ptr);
275 EXPECT_TRUE(ptr); 259 EXPECT_EQ(kPointerOffset, reinterpret_cast<size_t>(ptr) & kPartitionPageOffset Mask);
276 EXPECT_EQ(kPointerOffset, reinterpret_cast<size_t>(ptr) & kPartitionPageOffs etMask); 260 // Check that the offset appears to include a guard page.
277 // Check that the offset appears to include a guard page. 261 EXPECT_EQ(kPartitionPageSize + kPointerOffset, reinterpret_cast<size_t>(ptr) & kSuperPageOffsetMask);
278 EXPECT_EQ(kPartitionPageSize + kPointerOffset, reinterpret_cast<size_t>(ptr) & kSuperPageOffsetMask); 262
279 263 partitionFree(ptr);
280 partitionFree(ptr); 264 // Expect that the last active page gets noticed as empty but doesn't get
281 // Expect that the last active page gets noticed as empty but doesn't get 265 // decommitted.
282 // decommitted. 266 EXPECT_TRUE(bucket->emptyPagesHead);
283 EXPECT_TRUE(bucket->emptyPagesHead); 267 EXPECT_FALSE(bucket->decommittedPagesHead);
284 EXPECT_FALSE(bucket->decommittedPagesHead); 268
285 269 TestShutdown();
286 TestShutdown();
287 } 270 }
288 271
289 // Check that we can detect a memory leak. 272 // Check that we can detect a memory leak.
290 TEST(PartitionAllocTest, SimpleLeak) 273 TEST(PartitionAllocTest, SimpleLeak) {
291 { 274 TestSetup();
292 TestSetup(); 275 void* leakedPtr = partitionAlloc(allocator.root(), kTestAllocSize);
293 void* leakedPtr = partitionAlloc(allocator.root(), kTestAllocSize); 276 (void)leakedPtr;
294 (void)leakedPtr; 277 void* leakedPtr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSi ze);
295 void* leakedPtr2 = partitionAllocGeneric(genericAllocator.root(), kTestAlloc Size); 278 (void)leakedPtr2;
296 (void)leakedPtr2; 279 EXPECT_FALSE(allocator.shutdown());
297 EXPECT_FALSE(allocator.shutdown()); 280 EXPECT_FALSE(genericAllocator.shutdown());
298 EXPECT_FALSE(genericAllocator.shutdown());
299 } 281 }
300 282
301 // Test multiple allocations, and freelist handling. 283 // Test multiple allocations, and freelist handling.
302 TEST(PartitionAllocTest, MultiAlloc) 284 TEST(PartitionAllocTest, MultiAlloc) {
303 { 285 TestSetup();
304 TestSetup(); 286
305 287 char* ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAll ocSize));
306 char* ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestA llocSize)); 288 char* ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAll ocSize));
307 char* ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestA llocSize)); 289 EXPECT_TRUE(ptr1);
308 EXPECT_TRUE(ptr1); 290 EXPECT_TRUE(ptr2);
309 EXPECT_TRUE(ptr2); 291 ptrdiff_t diff = ptr2 - ptr1;
310 ptrdiff_t diff = ptr2 - ptr1; 292 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
311 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff); 293
312 294 // Check that we re-use the just-freed slot.
313 // Check that we re-use the just-freed slot. 295 partitionFree(ptr2);
314 partitionFree(ptr2); 296 ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize ));
315 ptr2 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSi ze)); 297 EXPECT_TRUE(ptr2);
316 EXPECT_TRUE(ptr2); 298 diff = ptr2 - ptr1;
317 diff = ptr2 - ptr1; 299 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
318 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff); 300 partitionFree(ptr1);
319 partitionFree(ptr1); 301 ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize ));
320 ptr1 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSi ze)); 302 EXPECT_TRUE(ptr1);
321 EXPECT_TRUE(ptr1); 303 diff = ptr2 - ptr1;
322 diff = ptr2 - ptr1; 304 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff);
323 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize), diff); 305
324 306 char* ptr3 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAll ocSize));
325 char* ptr3 = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestA llocSize)); 307 EXPECT_TRUE(ptr3);
326 EXPECT_TRUE(ptr3); 308 diff = ptr3 - ptr1;
327 diff = ptr3 - ptr1; 309 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize * 2), diff);
328 EXPECT_EQ(static_cast<ptrdiff_t>(kRealAllocSize * 2), diff); 310
329 311 partitionFree(ptr1);
330 partitionFree(ptr1); 312 partitionFree(ptr2);
331 partitionFree(ptr2); 313 partitionFree(ptr3);
332 partitionFree(ptr3); 314
333 315 TestShutdown();
334 TestShutdown();
335 } 316 }
336 317
337 // Test a bucket with multiple pages. 318 // Test a bucket with multiple pages.
338 TEST(PartitionAllocTest, MultiPages) 319 TEST(PartitionAllocTest, MultiPages) {
339 { 320 TestSetup();
340 TestSetup(); 321 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
341 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; 322
342 323 PartitionPage* page = GetFullPage(kTestAllocSize);
343 PartitionPage* page = GetFullPage(kTestAllocSize); 324 FreeFullPage(page);
344 FreeFullPage(page); 325 EXPECT_TRUE(bucket->emptyPagesHead);
345 EXPECT_TRUE(bucket->emptyPagesHead); 326 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
346 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead); 327 EXPECT_EQ(0, page->nextPage);
347 EXPECT_EQ(0, page->nextPage); 328 EXPECT_EQ(0, page->numAllocatedSlots);
348 EXPECT_EQ(0, page->numAllocatedSlots); 329
349 330 page = GetFullPage(kTestAllocSize);
350 page = GetFullPage(kTestAllocSize); 331 PartitionPage* page2 = GetFullPage(kTestAllocSize);
351 PartitionPage* page2 = GetFullPage(kTestAllocSize); 332
352 333 EXPECT_EQ(page2, bucket->activePagesHead);
353 EXPECT_EQ(page2, bucket->activePagesHead); 334 EXPECT_EQ(0, page2->nextPage);
354 EXPECT_EQ(0, page2->nextPage); 335 EXPECT_EQ(reinterpret_cast<uintptr_t>(partitionPageToPointer(page)) & kSuperPa geBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(page2)) & kSuperP ageBaseMask);
355 EXPECT_EQ(reinterpret_cast<uintptr_t>(partitionPageToPointer(page)) & kSuper PageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer(page2)) & kSupe rPageBaseMask); 336
356 337 // Fully free the non-current page. This will leave us with no current
357 // Fully free the non-current page. This will leave us with no current 338 // active page because one is empty and the other is full.
358 // active page because one is empty and the other is full. 339 FreeFullPage(page);
359 FreeFullPage(page); 340 EXPECT_EQ(0, page->numAllocatedSlots);
360 EXPECT_EQ(0, page->numAllocatedSlots); 341 EXPECT_TRUE(bucket->emptyPagesHead);
361 EXPECT_TRUE(bucket->emptyPagesHead); 342 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
362 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead); 343
363 344 // Allocate a new page, it should pull from the freelist.
364 // Allocate a new page, it should pull from the freelist. 345 page = GetFullPage(kTestAllocSize);
365 page = GetFullPage(kTestAllocSize); 346 EXPECT_FALSE(bucket->emptyPagesHead);
366 EXPECT_FALSE(bucket->emptyPagesHead); 347 EXPECT_EQ(page, bucket->activePagesHead);
367 EXPECT_EQ(page, bucket->activePagesHead); 348
368 349 FreeFullPage(page);
369 FreeFullPage(page); 350 FreeFullPage(page2);
370 FreeFullPage(page2); 351 EXPECT_EQ(0, page->numAllocatedSlots);
371 EXPECT_EQ(0, page->numAllocatedSlots); 352 EXPECT_EQ(0, page2->numAllocatedSlots);
372 EXPECT_EQ(0, page2->numAllocatedSlots); 353 EXPECT_EQ(0, page2->numUnprovisionedSlots);
373 EXPECT_EQ(0, page2->numUnprovisionedSlots); 354 EXPECT_NE(-1, page2->emptyCacheIndex);
374 EXPECT_NE(-1, page2->emptyCacheIndex); 355
375 356 TestShutdown();
376 TestShutdown();
377 } 357 }
378 358
379 // Test some finer aspects of internal page transitions. 359 // Test some finer aspects of internal page transitions.
380 TEST(PartitionAllocTest, PageTransitions) 360 TEST(PartitionAllocTest, PageTransitions) {
381 { 361 TestSetup();
382 TestSetup(); 362 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
383 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; 363
384 364 PartitionPage* page1 = GetFullPage(kTestAllocSize);
385 PartitionPage* page1 = GetFullPage(kTestAllocSize); 365 EXPECT_EQ(page1, bucket->activePagesHead);
386 EXPECT_EQ(page1, bucket->activePagesHead); 366 EXPECT_EQ(0, page1->nextPage);
387 EXPECT_EQ(0, page1->nextPage); 367 PartitionPage* page2 = GetFullPage(kTestAllocSize);
388 PartitionPage* page2 = GetFullPage(kTestAllocSize); 368 EXPECT_EQ(page2, bucket->activePagesHead);
389 EXPECT_EQ(page2, bucket->activePagesHead); 369 EXPECT_EQ(0, page2->nextPage);
390 EXPECT_EQ(0, page2->nextPage); 370
391 371 // Bounce page1 back into the non-full list then fill it up again.
392 // Bounce page1 back into the non-full list then fill it up again. 372 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerO ffset;
393 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointe rOffset; 373 partitionFree(ptr);
394 partitionFree(ptr); 374 EXPECT_EQ(page1, bucket->activePagesHead);
395 EXPECT_EQ(page1, bucket->activePagesHead); 375 (void)partitionAlloc(allocator.root(), kTestAllocSize);
396 (void) partitionAlloc(allocator.root(), kTestAllocSize); 376 EXPECT_EQ(page1, bucket->activePagesHead);
397 EXPECT_EQ(page1, bucket->activePagesHead); 377 EXPECT_EQ(page2, bucket->activePagesHead->nextPage);
398 EXPECT_EQ(page2, bucket->activePagesHead->nextPage); 378
399 379 // Allocating another page at this point should cause us to scan over page1
400 // Allocating another page at this point should cause us to scan over page1 380 // (which is both full and NOT our current page), and evict it from the
401 // (which is both full and NOT our current page), and evict it from the 381 // freelist. Older code had a O(n^2) condition due to failure to do this.
402 // freelist. Older code had a O(n^2) condition due to failure to do this. 382 PartitionPage* page3 = GetFullPage(kTestAllocSize);
403 PartitionPage* page3 = GetFullPage(kTestAllocSize); 383 EXPECT_EQ(page3, bucket->activePagesHead);
404 EXPECT_EQ(page3, bucket->activePagesHead); 384 EXPECT_EQ(0, page3->nextPage);
405 EXPECT_EQ(0, page3->nextPage); 385
406 386 // Work out a pointer into page2 and free it.
407 // Work out a pointer into page2 and free it. 387 ptr = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffset;
408 ptr = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffse t; 388 partitionFree(ptr);
409 partitionFree(ptr); 389 // Trying to allocate at this time should cause us to cycle around to page2
410 // Trying to allocate at this time should cause us to cycle around to page2 390 // and find the recently freed slot.
411 // and find the recently freed slot. 391 char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestA llocSize));
412 char* newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTes tAllocSize)); 392 EXPECT_EQ(ptr, newPtr);
413 EXPECT_EQ(ptr, newPtr); 393 EXPECT_EQ(page2, bucket->activePagesHead);
414 EXPECT_EQ(page2, bucket->activePagesHead); 394 EXPECT_EQ(page3, page2->nextPage);
415 EXPECT_EQ(page3, page2->nextPage); 395
416 396 // Work out a pointer into page1 and free it. This should pull the page
417 // Work out a pointer into page1 and free it. This should pull the page 397 // back into the list of available pages.
418 // back into the list of available pages. 398 ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerOffset;
419 ptr = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointerOffse t; 399 partitionFree(ptr);
420 partitionFree(ptr); 400 // This allocation should be satisfied by page1.
421 // This allocation should be satisfied by page1. 401 newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSi ze));
422 newPtr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAlloc Size)); 402 EXPECT_EQ(ptr, newPtr);
423 EXPECT_EQ(ptr, newPtr); 403 EXPECT_EQ(page1, bucket->activePagesHead);
424 EXPECT_EQ(page1, bucket->activePagesHead); 404 EXPECT_EQ(page2, page1->nextPage);
425 EXPECT_EQ(page2, page1->nextPage); 405
426 406 FreeFullPage(page3);
427 FreeFullPage(page3); 407 FreeFullPage(page2);
428 FreeFullPage(page2); 408 FreeFullPage(page1);
429 FreeFullPage(page1); 409
430 410 // Allocating whilst in this state exposed a bug, so keep the test.
431 // Allocating whilst in this state exposed a bug, so keep the test. 411 ptr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSize) );
432 ptr = reinterpret_cast<char*>(partitionAlloc(allocator.root(), kTestAllocSiz e)); 412 partitionFree(ptr);
433 partitionFree(ptr); 413
434 414 TestShutdown();
435 TestShutdown();
436 } 415 }
437 416
438 // Test some corner cases relating to page transitions in the internal 417 // Test some corner cases relating to page transitions in the internal
439 // free page list metadata bucket. 418 // free page list metadata bucket.
440 TEST(PartitionAllocTest, FreePageListPageTransitions) 419 TEST(PartitionAllocTest, FreePageListPageTransitions) {
441 { 420 TestSetup();
442 TestSetup(); 421 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
443 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; 422
444 423 size_t numToFillFreeListPage = kPartitionPageSize / (sizeof(PartitionPage) + k ExtraAllocSize);
445 size_t numToFillFreeListPage = kPartitionPageSize / (sizeof(PartitionPage) + kExtraAllocSize); 424 // The +1 is because we need to account for the fact that the current page
446 // The +1 is because we need to account for the fact that the current page 425 // never gets thrown on the freelist.
447 // never gets thrown on the freelist. 426 ++numToFillFreeListPage;
448 ++numToFillFreeListPage; 427 OwnPtr<PartitionPage* []> pages = adoptArrayPtr(new PartitionPage*[numToFillFr eeListPage]);
449 OwnPtr<PartitionPage*[]> pages = adoptArrayPtr(new PartitionPage*[numToFillF reeListPage]); 428
450 429 size_t i;
451 size_t i; 430 for (i = 0; i < numToFillFreeListPage; ++i) {
452 for (i = 0; i < numToFillFreeListPage; ++i) { 431 pages[i] = GetFullPage(kTestAllocSize);
453 pages[i] = GetFullPage(kTestAllocSize); 432 }
454 } 433 EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead);
455 EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead); 434 for (i = 0; i < numToFillFreeListPage; ++i)
456 for (i = 0; i < numToFillFreeListPage; ++i) 435 FreeFullPage(pages[i]);
457 FreeFullPage(pages[i]); 436 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
458 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead); 437 EXPECT_TRUE(bucket->emptyPagesHead);
459 EXPECT_TRUE(bucket->emptyPagesHead); 438
460 439 // Allocate / free in a different bucket size so we get control of a
461 // Allocate / free in a different bucket size so we get control of a 440 // different free page list. We need two pages because one will be the last
462 // different free page list. We need two pages because one will be the last 441 // active page and not get freed.
463 // active page and not get freed. 442 PartitionPage* page1 = GetFullPage(kTestAllocSize * 2);
464 PartitionPage* page1 = GetFullPage(kTestAllocSize * 2); 443 PartitionPage* page2 = GetFullPage(kTestAllocSize * 2);
465 PartitionPage* page2 = GetFullPage(kTestAllocSize * 2); 444 FreeFullPage(page1);
466 FreeFullPage(page1); 445 FreeFullPage(page2);
467 FreeFullPage(page2); 446
468 447 for (i = 0; i < numToFillFreeListPage; ++i) {
469 for (i = 0; i < numToFillFreeListPage; ++i) { 448 pages[i] = GetFullPage(kTestAllocSize);
470 pages[i] = GetFullPage(kTestAllocSize); 449 }
471 } 450 EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead);
472 EXPECT_EQ(pages[numToFillFreeListPage - 1], bucket->activePagesHead); 451
473 452 for (i = 0; i < numToFillFreeListPage; ++i)
474 for (i = 0; i < numToFillFreeListPage; ++i) 453 FreeFullPage(pages[i]);
475 FreeFullPage(pages[i]); 454 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
476 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead); 455 EXPECT_TRUE(bucket->emptyPagesHead);
477 EXPECT_TRUE(bucket->emptyPagesHead); 456
478 457 TestShutdown();
479 TestShutdown();
480 } 458 }
481 459
482 // Test a large series of allocations that cross more than one underlying 460 // Test a large series of allocations that cross more than one underlying
483 // 64KB super page allocation. 461 // 64KB super page allocation.
484 TEST(PartitionAllocTest, MultiPageAllocs) 462 TEST(PartitionAllocTest, MultiPageAllocs) {
485 { 463 TestSetup();
486 TestSetup(); 464 // This is guaranteed to cross a super page boundary because the first
487 // This is guaranteed to cross a super page boundary because the first 465 // partition page "slot" will be taken up by a guard page.
488 // partition page "slot" will be taken up by a guard page. 466 size_t numPagesNeeded = kNumPartitionPagesPerSuperPage;
489 size_t numPagesNeeded = kNumPartitionPagesPerSuperPage; 467 // The super page should begin and end in a guard so we one less page in
490 // The super page should begin and end in a guard so we one less page in 468 // order to allocate a single page in the new super page.
491 // order to allocate a single page in the new super page. 469 --numPagesNeeded;
492 --numPagesNeeded; 470
493 471 EXPECT_GT(numPagesNeeded, 1u);
494 EXPECT_GT(numPagesNeeded, 1u); 472 OwnPtr<PartitionPage* []> pages;
495 OwnPtr<PartitionPage*[]> pages; 473 pages = adoptArrayPtr(new PartitionPage*[numPagesNeeded]);
496 pages = adoptArrayPtr(new PartitionPage*[numPagesNeeded]); 474 uintptr_t firstSuperPageBase = 0;
497 uintptr_t firstSuperPageBase = 0; 475 size_t i;
498 size_t i; 476 for (i = 0; i < numPagesNeeded; ++i) {
499 for (i = 0; i < numPagesNeeded; ++i) { 477 pages[i] = GetFullPage(kTestAllocSize);
500 pages[i] = GetFullPage(kTestAllocSize); 478 void* storagePtr = partitionPageToPointer(pages[i]);
501 void* storagePtr = partitionPageToPointer(pages[i]); 479 if (!i)
502 if (!i) 480 firstSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & kSuperPageB aseMask;
503 firstSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & kSupe rPageBaseMask; 481 if (i == numPagesNeeded - 1) {
504 if (i == numPagesNeeded - 1) { 482 uintptr_t secondSuperPageBase = reinterpret_cast<uintptr_t>(storagePtr) & kSuperPageBaseMask;
505 uintptr_t secondSuperPageBase = reinterpret_cast<uintptr_t>(storageP tr) & kSuperPageBaseMask; 483 uintptr_t secondSuperPageOffset = reinterpret_cast<uintptr_t>(storagePtr) & kSuperPageOffsetMask;
506 uintptr_t secondSuperPageOffset = reinterpret_cast<uintptr_t>(storag ePtr) & kSuperPageOffsetMask; 484 EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase);
507 EXPECT_FALSE(secondSuperPageBase == firstSuperPageBase); 485 // Check that we allocated a guard page for the second page.
508 // Check that we allocated a guard page for the second page. 486 EXPECT_EQ(kPartitionPageSize, secondSuperPageOffset);
509 EXPECT_EQ(kPartitionPageSize, secondSuperPageOffset);
510 }
511 } 487 }
512 for (i = 0; i < numPagesNeeded; ++i) 488 }
513 FreeFullPage(pages[i]); 489 for (i = 0; i < numPagesNeeded; ++i)
514 490 FreeFullPage(pages[i]);
515 TestShutdown(); 491
492 TestShutdown();
516 } 493 }
517 494
518 // Test the generic allocation functions that can handle arbitrary sizes and 495 // Test the generic allocation functions that can handle arbitrary sizes and
519 // reallocing etc. 496 // reallocing etc.
520 TEST(PartitionAllocTest, GenericAlloc) 497 TEST(PartitionAllocTest, GenericAlloc) {
521 { 498 TestSetup();
522 TestSetup(); 499
523 500 void* ptr = partitionAllocGeneric(genericAllocator.root(), 1);
524 void* ptr = partitionAllocGeneric(genericAllocator.root(), 1); 501 EXPECT_TRUE(ptr);
525 EXPECT_TRUE(ptr); 502 partitionFreeGeneric(genericAllocator.root(), ptr);
526 partitionFreeGeneric(genericAllocator.root(), ptr); 503 ptr = partitionAllocGeneric(genericAllocator.root(), kGenericMaxBucketed + 1);
527 ptr = partitionAllocGeneric(genericAllocator.root(), kGenericMaxBucketed + 1 ); 504 EXPECT_TRUE(ptr);
528 EXPECT_TRUE(ptr); 505 partitionFreeGeneric(genericAllocator.root(), ptr);
529 partitionFreeGeneric(genericAllocator.root(), ptr); 506
530 507 ptr = partitionAllocGeneric(genericAllocator.root(), 1);
531 ptr = partitionAllocGeneric(genericAllocator.root(), 1); 508 EXPECT_TRUE(ptr);
532 EXPECT_TRUE(ptr); 509 void* origPtr = ptr;
533 void* origPtr = ptr; 510 char* charPtr = static_cast<char*>(ptr);
534 char* charPtr = static_cast<char*>(ptr); 511 *charPtr = 'A';
535 *charPtr = 'A'; 512
536 513 // Change the size of the realloc, remaining inside the same bucket.
537 // Change the size of the realloc, remaining inside the same bucket. 514 void* newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 2);
538 void* newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 2); 515 EXPECT_EQ(ptr, newPtr);
539 EXPECT_EQ(ptr, newPtr); 516 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
540 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); 517 EXPECT_EQ(ptr, newPtr);
541 EXPECT_EQ(ptr, newPtr); 518 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericSmalles tBucket);
542 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericSmall estBucket); 519 EXPECT_EQ(ptr, newPtr);
543 EXPECT_EQ(ptr, newPtr); 520
544 521 // Change the size of the realloc, switching buckets.
545 // Change the size of the realloc, switching buckets. 522 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericSmalles tBucket + 1);
546 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericSmall estBucket + 1); 523 EXPECT_NE(newPtr, ptr);
547 EXPECT_NE(newPtr, ptr); 524 // Check that the realloc copied correctly.
548 // Check that the realloc copied correctly. 525 char* newCharPtr = static_cast<char*>(newPtr);
549 char* newCharPtr = static_cast<char*>(newPtr); 526 EXPECT_EQ(*newCharPtr, 'A');
550 EXPECT_EQ(*newCharPtr, 'A');
551 #if ENABLE(ASSERT) 527 #if ENABLE(ASSERT)
552 // Subtle: this checks for an old bug where we copied too much from the 528 // Subtle: this checks for an old bug where we copied too much from the
553 // source of the realloc. The condition can be detected by a trashing of 529 // source of the realloc. The condition can be detected by a trashing of
554 // the uninitialized value in the space of the upsized allocation. 530 // the uninitialized value in the space of the upsized allocation.
555 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(*(newCharPtr + kGen ericSmallestBucket))); 531 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(*(newCharPtr + kGener icSmallestBucket)));
556 #endif 532 #endif
557 *newCharPtr = 'B'; 533 *newCharPtr = 'B';
558 // The realloc moved. To check that the old allocation was freed, we can 534 // The realloc moved. To check that the old allocation was freed, we can
559 // do an alloc of the old allocation size and check that the old allocation 535 // do an alloc of the old allocation size and check that the old allocation
560 // address is at the head of the freelist and reused. 536 // address is at the head of the freelist and reused.
561 void* reusedPtr = partitionAllocGeneric(genericAllocator.root(), 1); 537 void* reusedPtr = partitionAllocGeneric(genericAllocator.root(), 1);
562 EXPECT_EQ(reusedPtr, origPtr); 538 EXPECT_EQ(reusedPtr, origPtr);
563 partitionFreeGeneric(genericAllocator.root(), reusedPtr); 539 partitionFreeGeneric(genericAllocator.root(), reusedPtr);
564 540
565 // Downsize the realloc. 541 // Downsize the realloc.
566 ptr = newPtr; 542 ptr = newPtr;
567 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); 543 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
568 EXPECT_EQ(newPtr, origPtr); 544 EXPECT_EQ(newPtr, origPtr);
569 newCharPtr = static_cast<char*>(newPtr); 545 newCharPtr = static_cast<char*>(newPtr);
570 EXPECT_EQ(*newCharPtr, 'B'); 546 EXPECT_EQ(*newCharPtr, 'B');
571 *newCharPtr = 'C'; 547 *newCharPtr = 'C';
572 548
573 // Upsize the realloc to outside the partition. 549 // Upsize the realloc to outside the partition.
574 ptr = newPtr; 550 ptr = newPtr;
575 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBu cketed + 1); 551 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBuck eted + 1);
576 EXPECT_NE(newPtr, ptr); 552 EXPECT_NE(newPtr, ptr);
577 newCharPtr = static_cast<char*>(newPtr); 553 newCharPtr = static_cast<char*>(newPtr);
578 EXPECT_EQ(*newCharPtr, 'C'); 554 EXPECT_EQ(*newCharPtr, 'C');
579 *newCharPtr = 'D'; 555 *newCharPtr = 'D';
580 556
581 // Upsize and downsize the realloc, remaining outside the partition. 557 // Upsize and downsize the realloc, remaining outside the partition.
582 ptr = newPtr; 558 ptr = newPtr;
583 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBu cketed * 10); 559 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBuck eted * 10);
584 newCharPtr = static_cast<char*>(newPtr); 560 newCharPtr = static_cast<char*>(newPtr);
585 EXPECT_EQ(*newCharPtr, 'D'); 561 EXPECT_EQ(*newCharPtr, 'D');
586 *newCharPtr = 'E'; 562 *newCharPtr = 'E';
587 ptr = newPtr; 563 ptr = newPtr;
588 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBu cketed * 2); 564 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBuck eted * 2);
589 newCharPtr = static_cast<char*>(newPtr); 565 newCharPtr = static_cast<char*>(newPtr);
590 EXPECT_EQ(*newCharPtr, 'E'); 566 EXPECT_EQ(*newCharPtr, 'E');
591 *newCharPtr = 'F'; 567 *newCharPtr = 'F';
592 568
593 // Downsize the realloc to inside the partition. 569 // Downsize the realloc to inside the partition.
594 ptr = newPtr; 570 ptr = newPtr;
595 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1); 571 newPtr = partitionReallocGeneric(genericAllocator.root(), ptr, 1);
596 EXPECT_NE(newPtr, ptr); 572 EXPECT_NE(newPtr, ptr);
597 EXPECT_EQ(newPtr, origPtr); 573 EXPECT_EQ(newPtr, origPtr);
598 newCharPtr = static_cast<char*>(newPtr); 574 newCharPtr = static_cast<char*>(newPtr);
599 EXPECT_EQ(*newCharPtr, 'F'); 575 EXPECT_EQ(*newCharPtr, 'F');
600 576
601 partitionFreeGeneric(genericAllocator.root(), newPtr); 577 partitionFreeGeneric(genericAllocator.root(), newPtr);
602 TestShutdown(); 578 TestShutdown();
603 } 579 }
604 580
605 // Test the generic allocation functions can handle some specific sizes of 581 // Test the generic allocation functions can handle some specific sizes of
606 // interest. 582 // interest.
607 TEST(PartitionAllocTest, GenericAllocSizes) 583 TEST(PartitionAllocTest, GenericAllocSizes) {
608 { 584 TestSetup();
609 TestSetup(); 585
610 586 void* ptr = partitionAllocGeneric(genericAllocator.root(), 0);
611 void* ptr = partitionAllocGeneric(genericAllocator.root(), 0); 587 EXPECT_TRUE(ptr);
612 EXPECT_TRUE(ptr); 588 partitionFreeGeneric(genericAllocator.root(), ptr);
613 partitionFreeGeneric(genericAllocator.root(), ptr); 589
614 590 // kPartitionPageSize is interesting because it results in just one
615 // kPartitionPageSize is interesting because it results in just one 591 // allocation per page, which tripped up some corner cases.
616 // allocation per page, which tripped up some corner cases. 592 size_t size = kPartitionPageSize - kExtraAllocSize;
617 size_t size = kPartitionPageSize - kExtraAllocSize; 593 ptr = partitionAllocGeneric(genericAllocator.root(), size);
618 ptr = partitionAllocGeneric(genericAllocator.root(), size); 594 EXPECT_TRUE(ptr);
619 EXPECT_TRUE(ptr); 595 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
620 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); 596 EXPECT_TRUE(ptr2);
621 EXPECT_TRUE(ptr2); 597 partitionFreeGeneric(genericAllocator.root(), ptr);
622 partitionFreeGeneric(genericAllocator.root(), ptr); 598 // Should be freeable at this point.
623 // Should be freeable at this point. 599 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjust( ptr));
624 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); 600 EXPECT_NE(-1, page->emptyCacheIndex);
625 EXPECT_NE(-1, page->emptyCacheIndex); 601 partitionFreeGeneric(genericAllocator.root(), ptr2);
626 partitionFreeGeneric(genericAllocator.root(), ptr2); 602
627 603 size = (((kPartitionPageSize * kMaxPartitionPagesPerSlotSpan) - kSystemPageSiz e) / 2) - kExtraAllocSize;
628 size = (((kPartitionPageSize * kMaxPartitionPagesPerSlotSpan) - kSystemPageS ize) / 2) - kExtraAllocSize; 604 ptr = partitionAllocGeneric(genericAllocator.root(), size);
629 ptr = partitionAllocGeneric(genericAllocator.root(), size); 605 EXPECT_TRUE(ptr);
630 EXPECT_TRUE(ptr); 606 memset(ptr, 'A', size);
631 memset(ptr, 'A', size); 607 ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
632 ptr2 = partitionAllocGeneric(genericAllocator.root(), size); 608 EXPECT_TRUE(ptr2);
633 EXPECT_TRUE(ptr2); 609 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size);
634 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size); 610 EXPECT_TRUE(ptr3);
635 EXPECT_TRUE(ptr3); 611 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size);
636 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size); 612 EXPECT_TRUE(ptr4);
637 EXPECT_TRUE(ptr4); 613
638 614 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
639 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); 615 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdjust (ptr3));
640 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr3)); 616 EXPECT_NE(page, page2);
641 EXPECT_NE(page, page2); 617
642 618 partitionFreeGeneric(genericAllocator.root(), ptr);
643 partitionFreeGeneric(genericAllocator.root(), ptr); 619 partitionFreeGeneric(genericAllocator.root(), ptr3);
644 partitionFreeGeneric(genericAllocator.root(), ptr3); 620 partitionFreeGeneric(genericAllocator.root(), ptr2);
645 partitionFreeGeneric(genericAllocator.root(), ptr2); 621 // Should be freeable at this point.
646 // Should be freeable at this point. 622 EXPECT_NE(-1, page->emptyCacheIndex);
647 EXPECT_NE(-1, page->emptyCacheIndex); 623 EXPECT_EQ(0, page->numAllocatedSlots);
648 EXPECT_EQ(0, page->numAllocatedSlots); 624 EXPECT_EQ(0, page->numUnprovisionedSlots);
649 EXPECT_EQ(0, page->numUnprovisionedSlots); 625 void* newPtr = partitionAllocGeneric(genericAllocator.root(), size);
650 void* newPtr = partitionAllocGeneric(genericAllocator.root(), size); 626 EXPECT_EQ(ptr3, newPtr);
651 EXPECT_EQ(ptr3, newPtr); 627 newPtr = partitionAllocGeneric(genericAllocator.root(), size);
652 newPtr = partitionAllocGeneric(genericAllocator.root(), size); 628 EXPECT_EQ(ptr2, newPtr);
653 EXPECT_EQ(ptr2, newPtr);
654 #if OS(LINUX) && !ENABLE(ASSERT) 629 #if OS(LINUX) && !ENABLE(ASSERT)
655 // On Linux, we have a guarantee that freelisting a page should cause its 630 // On Linux, we have a guarantee that freelisting a page should cause its
656 // contents to be nulled out. We check for null here to detect an bug we 631 // contents to be nulled out. We check for null here to detect an bug we
657 // had where a large slot size was causing us to not properly free all 632 // had where a large slot size was causing us to not properly free all
658 // resources back to the system. 633 // resources back to the system.
659 // We only run the check when asserts are disabled because when they are 634 // We only run the check when asserts are disabled because when they are
660 // enabled, the allocated area is overwritten with an "uninitialized" 635 // enabled, the allocated area is overwritten with an "uninitialized"
661 // byte pattern. 636 // byte pattern.
662 EXPECT_EQ(0, *(reinterpret_cast<char*>(newPtr) + (size - 1))); 637 EXPECT_EQ(0, *(reinterpret_cast<char*>(newPtr) + (size - 1)));
663 #endif 638 #endif
664 partitionFreeGeneric(genericAllocator.root(), newPtr); 639 partitionFreeGeneric(genericAllocator.root(), newPtr);
665 partitionFreeGeneric(genericAllocator.root(), ptr3); 640 partitionFreeGeneric(genericAllocator.root(), ptr3);
666 partitionFreeGeneric(genericAllocator.root(), ptr4); 641 partitionFreeGeneric(genericAllocator.root(), ptr4);
667 642
668 // Can we allocate a massive (512MB) size? 643 // Can we allocate a massive (512MB) size?
669 // Allocate 512MB, but +1, to test for cookie writing alignment issues. 644 // Allocate 512MB, but +1, to test for cookie writing alignment issues.
670 ptr = partitionAllocGeneric(genericAllocator.root(), 512 * 1024 * 1024 + 1); 645 ptr = partitionAllocGeneric(genericAllocator.root(), 512 * 1024 * 1024 + 1);
671 partitionFreeGeneric(genericAllocator.root(), ptr); 646 partitionFreeGeneric(genericAllocator.root(), ptr);
672 647
673 // Check a more reasonable, but still direct mapped, size. 648 // Check a more reasonable, but still direct mapped, size.
674 // Chop a system page and a byte off to test for rounding errors. 649 // Chop a system page and a byte off to test for rounding errors.
675 size = 20 * 1024 * 1024; 650 size = 20 * 1024 * 1024;
676 size -= kSystemPageSize; 651 size -= kSystemPageSize;
677 size -= 1; 652 size -= 1;
678 ptr = partitionAllocGeneric(genericAllocator.root(), size); 653 ptr = partitionAllocGeneric(genericAllocator.root(), size);
679 char* charPtr = reinterpret_cast<char*>(ptr); 654 char* charPtr = reinterpret_cast<char*>(ptr);
680 *(charPtr + (size - 1)) = 'A'; 655 *(charPtr + (size - 1)) = 'A';
681 partitionFreeGeneric(genericAllocator.root(), ptr); 656 partitionFreeGeneric(genericAllocator.root(), ptr);
682 657
683 // Can we free null? 658 // Can we free null?
684 partitionFreeGeneric(genericAllocator.root(), 0); 659 partitionFreeGeneric(genericAllocator.root(), 0);
685 660
686 // Do we correctly get a null for a failed allocation? 661 // Do we correctly get a null for a failed allocation?
687 EXPECT_EQ(0, partitionAllocGenericFlags(genericAllocator.root(), PartitionAl locReturnNull, 3u * 1024 * 1024 * 1024)); 662 EXPECT_EQ(0, partitionAllocGenericFlags(genericAllocator.root(), PartitionAllo cReturnNull, 3u * 1024 * 1024 * 1024));
688 663
689 TestShutdown(); 664 TestShutdown();
690 } 665 }
691 666
692 // Test that we can fetch the real allocated size after an allocation. 667 // Test that we can fetch the real allocated size after an allocation.
693 TEST(PartitionAllocTest, GenericAllocGetSize) 668 TEST(PartitionAllocTest, GenericAllocGetSize) {
694 { 669 TestSetup();
695 TestSetup(); 670
696 671 void* ptr;
697 void* ptr; 672 size_t requestedSize, actualSize, predictedSize;
698 size_t requestedSize, actualSize, predictedSize; 673
699 674 EXPECT_TRUE(partitionAllocSupportsGetSize());
700 EXPECT_TRUE(partitionAllocSupportsGetSize()); 675
701 676 // Allocate something small.
702 // Allocate something small. 677 requestedSize = 511 - kExtraAllocSize;
703 requestedSize = 511 - kExtraAllocSize; 678 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSiz e);
704 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); 679 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
705 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); 680 EXPECT_TRUE(ptr);
706 EXPECT_TRUE(ptr); 681 actualSize = partitionAllocGetSize(ptr);
707 actualSize = partitionAllocGetSize(ptr); 682 EXPECT_EQ(predictedSize, actualSize);
708 EXPECT_EQ(predictedSize, actualSize); 683 EXPECT_LT(requestedSize, actualSize);
709 EXPECT_LT(requestedSize, actualSize); 684 partitionFreeGeneric(genericAllocator.root(), ptr);
710 partitionFreeGeneric(genericAllocator.root(), ptr); 685
711 686 // Allocate a size that should be a perfect match for a bucket, because it
712 // Allocate a size that should be a perfect match for a bucket, because it 687 // is an exact power of 2.
713 // is an exact power of 2. 688 requestedSize = (256 * 1024) - kExtraAllocSize;
714 requestedSize = (256 * 1024) - kExtraAllocSize; 689 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSiz e);
715 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); 690 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
716 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); 691 EXPECT_TRUE(ptr);
717 EXPECT_TRUE(ptr); 692 actualSize = partitionAllocGetSize(ptr);
718 actualSize = partitionAllocGetSize(ptr); 693 EXPECT_EQ(predictedSize, actualSize);
719 EXPECT_EQ(predictedSize, actualSize); 694 EXPECT_EQ(requestedSize, actualSize);
720 EXPECT_EQ(requestedSize, actualSize); 695 partitionFreeGeneric(genericAllocator.root(), ptr);
721 partitionFreeGeneric(genericAllocator.root(), ptr); 696
722 697 // Allocate a size that is a system page smaller than a bucket. GetSize()
723 // Allocate a size that is a system page smaller than a bucket. GetSize() 698 // should return a larger size than we asked for now.
724 // should return a larger size than we asked for now. 699 requestedSize = (256 * 1024) - kSystemPageSize - kExtraAllocSize;
725 requestedSize = (256 * 1024) - kSystemPageSize - kExtraAllocSize; 700 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSiz e);
726 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); 701 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
727 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); 702 EXPECT_TRUE(ptr);
728 EXPECT_TRUE(ptr); 703 actualSize = partitionAllocGetSize(ptr);
729 actualSize = partitionAllocGetSize(ptr); 704 EXPECT_EQ(predictedSize, actualSize);
730 EXPECT_EQ(predictedSize, actualSize); 705 EXPECT_EQ(requestedSize + kSystemPageSize, actualSize);
731 EXPECT_EQ(requestedSize + kSystemPageSize, actualSize); 706 // Check that we can write at the end of the reported size too.
732 // Check that we can write at the end of the reported size too. 707 char* charPtr = reinterpret_cast<char*>(ptr);
733 char* charPtr = reinterpret_cast<char*>(ptr); 708 *(charPtr + (actualSize - 1)) = 'A';
734 *(charPtr + (actualSize - 1)) = 'A'; 709 partitionFreeGeneric(genericAllocator.root(), ptr);
735 partitionFreeGeneric(genericAllocator.root(), ptr); 710
736 711 // Allocate something very large, and uneven.
737 // Allocate something very large, and uneven. 712 requestedSize = 512 * 1024 * 1024 - 1;
738 requestedSize = 512 * 1024 * 1024 - 1; 713 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSiz e);
739 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); 714 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize);
740 ptr = partitionAllocGeneric(genericAllocator.root(), requestedSize); 715 EXPECT_TRUE(ptr);
741 EXPECT_TRUE(ptr); 716 actualSize = partitionAllocGetSize(ptr);
742 actualSize = partitionAllocGetSize(ptr); 717 EXPECT_EQ(predictedSize, actualSize);
743 EXPECT_EQ(predictedSize, actualSize); 718 EXPECT_LT(requestedSize, actualSize);
744 EXPECT_LT(requestedSize, actualSize); 719 partitionFreeGeneric(genericAllocator.root(), ptr);
745 partitionFreeGeneric(genericAllocator.root(), ptr); 720
746 721 // Too large allocation.
747 // Too large allocation. 722 requestedSize = INT_MAX;
748 requestedSize = INT_MAX; 723 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedSiz e);
749 predictedSize = partitionAllocActualSize(genericAllocator.root(), requestedS ize); 724 EXPECT_EQ(requestedSize, predictedSize);
750 EXPECT_EQ(requestedSize, predictedSize); 725
751 726 TestShutdown();
752 TestShutdown();
753 } 727 }
754 728
755 // Test the realloc() contract. 729 // Test the realloc() contract.
756 TEST(PartitionAllocTest, Realloc) 730 TEST(PartitionAllocTest, Realloc) {
757 { 731 TestSetup();
758 TestSetup(); 732
759 733 // realloc(0, size) should be equivalent to malloc().
760 // realloc(0, size) should be equivalent to malloc(). 734 void* ptr = partitionReallocGeneric(genericAllocator.root(), 0, kTestAllocSize );
761 void* ptr = partitionReallocGeneric(genericAllocator.root(), 0, kTestAllocSi ze); 735 memset(ptr, 'A', kTestAllocSize);
762 memset(ptr, 'A', kTestAllocSize); 736 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjust( ptr));
763 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); 737 // realloc(ptr, 0) should be equivalent to free().
764 // realloc(ptr, 0) should be equivalent to free(). 738 void* ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, 0);
765 void* ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, 0); 739 EXPECT_EQ(0, ptr2);
766 EXPECT_EQ(0, ptr2); 740 EXPECT_EQ(partitionCookieFreePointerAdjust(ptr), page->freelistHead);
767 EXPECT_EQ(partitionCookieFreePointerAdjust(ptr), page->freelistHead); 741
768 742 // Test that growing an allocation with realloc() copies everything from the
769 // Test that growing an allocation with realloc() copies everything from the 743 // old allocation.
770 // old allocation. 744 size_t size = kSystemPageSize - kExtraAllocSize;
771 size_t size = kSystemPageSize - kExtraAllocSize; 745 EXPECT_EQ(size, partitionAllocActualSize(genericAllocator.root(), size));
772 EXPECT_EQ(size, partitionAllocActualSize(genericAllocator.root(), size)); 746 ptr = partitionAllocGeneric(genericAllocator.root(), size);
773 ptr = partitionAllocGeneric(genericAllocator.root(), size); 747 memset(ptr, 'A', size);
774 memset(ptr, 'A', size); 748 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, size + 1);
775 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, size + 1); 749 EXPECT_NE(ptr, ptr2);
776 EXPECT_NE(ptr, ptr2); 750 char* charPtr2 = static_cast<char*>(ptr2);
777 char* charPtr2 = static_cast<char*>(ptr2); 751 EXPECT_EQ('A', charPtr2[0]);
778 EXPECT_EQ('A', charPtr2[0]); 752 EXPECT_EQ('A', charPtr2[size - 1]);
779 EXPECT_EQ('A', charPtr2[size - 1]);
780 #if ENABLE(ASSERT) 753 #if ENABLE(ASSERT)
781 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr2[size])); 754 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr2[size]));
782 #endif 755 #endif
783 756
784 // Test that shrinking an allocation with realloc() also copies everything 757 // Test that shrinking an allocation with realloc() also copies everything
785 // from the old allocation. 758 // from the old allocation.
786 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - 1); 759 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - 1);
787 EXPECT_NE(ptr2, ptr); 760 EXPECT_NE(ptr2, ptr);
788 char* charPtr = static_cast<char*>(ptr); 761 char* charPtr = static_cast<char*>(ptr);
789 EXPECT_EQ('A', charPtr[0]); 762 EXPECT_EQ('A', charPtr[0]);
790 EXPECT_EQ('A', charPtr[size - 2]); 763 EXPECT_EQ('A', charPtr[size - 2]);
791 #if ENABLE(ASSERT) 764 #if ENABLE(ASSERT)
792 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1])) ; 765 EXPECT_EQ(kUninitializedByte, static_cast<unsigned char>(charPtr[size - 1]));
793 #endif 766 #endif
794 767
795 partitionFreeGeneric(genericAllocator.root(), ptr); 768 partitionFreeGeneric(genericAllocator.root(), ptr);
796 769
797 // Test that shrinking a direct mapped allocation happens in-place. 770 // Test that shrinking a direct mapped allocation happens in-place.
798 size = kGenericMaxBucketed + 16 * kSystemPageSize; 771 size = kGenericMaxBucketed + 16 * kSystemPageSize;
799 ptr = partitionAllocGeneric(genericAllocator.root(), size); 772 ptr = partitionAllocGeneric(genericAllocator.root(), size);
800 size_t actualSize = partitionAllocGetSize(ptr); 773 size_t actualSize = partitionAllocGetSize(ptr);
801 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBuck eted + 8 * kSystemPageSize); 774 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, kGenericMaxBucket ed + 8 * kSystemPageSize);
802 EXPECT_EQ(ptr, ptr2); 775 EXPECT_EQ(ptr, ptr2);
803 EXPECT_EQ(actualSize - 8 * kSystemPageSize, partitionAllocGetSize(ptr2)); 776 EXPECT_EQ(actualSize - 8 * kSystemPageSize, partitionAllocGetSize(ptr2));
804 777
805 // Test that a previously in-place shrunk direct mapped allocation can be 778 // Test that a previously in-place shrunk direct mapped allocation can be
806 // expanded up again within its original size. 779 // expanded up again within its original size.
807 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - kSystemP ageSize); 780 ptr = partitionReallocGeneric(genericAllocator.root(), ptr2, size - kSystemPag eSize);
808 EXPECT_EQ(ptr2, ptr); 781 EXPECT_EQ(ptr2, ptr);
809 EXPECT_EQ(actualSize - kSystemPageSize, partitionAllocGetSize(ptr)); 782 EXPECT_EQ(actualSize - kSystemPageSize, partitionAllocGetSize(ptr));
810 783
811 // Test that a direct mapped allocation is performed not in-place when the 784 // Test that a direct mapped allocation is performed not in-place when the
812 // new size is small enough. 785 // new size is small enough.
813 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, kSystemPageSize ); 786 ptr2 = partitionReallocGeneric(genericAllocator.root(), ptr, kSystemPageSize);
814 EXPECT_NE(ptr, ptr2); 787 EXPECT_NE(ptr, ptr2);
815 788
816 partitionFreeGeneric(genericAllocator.root(), ptr2); 789 partitionFreeGeneric(genericAllocator.root(), ptr2);
817 790
818 TestShutdown(); 791 TestShutdown();
819 } 792 }
820 793
821 // Tests the handing out of freelists for partial pages. 794 // Tests the handing out of freelists for partial pages.
822 TEST(PartitionAllocTest, PartialPageFreelists) 795 TEST(PartitionAllocTest, PartialPageFreelists) {
823 { 796 TestSetup();
824 TestSetup(); 797
825 798 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
826 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize; 799 EXPECT_EQ(kSystemPageSize - kAllocationGranularity, bigSize + kExtraAllocSize) ;
827 EXPECT_EQ(kSystemPageSize - kAllocationGranularity, bigSize + kExtraAllocSiz e); 800 size_t bucketIdx = (bigSize + kExtraAllocSize) >> kBucketShift;
828 size_t bucketIdx = (bigSize + kExtraAllocSize) >> kBucketShift; 801 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
829 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx]; 802 EXPECT_EQ(0, bucket->emptyPagesHead);
830 EXPECT_EQ(0, bucket->emptyPagesHead); 803
831 804 void* ptr = partitionAlloc(allocator.root(), bigSize);
832 void* ptr = partitionAlloc(allocator.root(), bigSize); 805 EXPECT_TRUE(ptr);
833 EXPECT_TRUE(ptr); 806
834 807 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjust( ptr));
835 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); 808 size_t totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize ) / (bigSize + kExtraAllocSize);
836 size_t totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSi ze) / (bigSize + kExtraAllocSize); 809 EXPECT_EQ(4u, totalSlots);
837 EXPECT_EQ(4u, totalSlots); 810 // The freelist should have one entry, because we were able to exactly fit
838 // The freelist should have one entry, because we were able to exactly fit 811 // one object slot and one freelist pointer (the null that the head points
839 // one object slot and one freelist pointer (the null that the head points 812 // to) into a system page.
840 // to) into a system page. 813 EXPECT_TRUE(page->freelistHead);
814 EXPECT_EQ(1, page->numAllocatedSlots);
815 EXPECT_EQ(2, page->numUnprovisionedSlots);
816
817 void* ptr2 = partitionAlloc(allocator.root(), bigSize);
818 EXPECT_TRUE(ptr2);
819 EXPECT_FALSE(page->freelistHead);
820 EXPECT_EQ(2, page->numAllocatedSlots);
821 EXPECT_EQ(2, page->numUnprovisionedSlots);
822
823 void* ptr3 = partitionAlloc(allocator.root(), bigSize);
824 EXPECT_TRUE(ptr3);
825 EXPECT_TRUE(page->freelistHead);
826 EXPECT_EQ(3, page->numAllocatedSlots);
827 EXPECT_EQ(0, page->numUnprovisionedSlots);
828
829 void* ptr4 = partitionAlloc(allocator.root(), bigSize);
830 EXPECT_TRUE(ptr4);
831 EXPECT_FALSE(page->freelistHead);
832 EXPECT_EQ(4, page->numAllocatedSlots);
833 EXPECT_EQ(0, page->numUnprovisionedSlots);
834
835 void* ptr5 = partitionAlloc(allocator.root(), bigSize);
836 EXPECT_TRUE(ptr5);
837
838 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdjust (ptr5));
839 EXPECT_EQ(1, page2->numAllocatedSlots);
840
841 // Churn things a little whilst there's a partial page freelist.
842 partitionFree(ptr);
843 ptr = partitionAlloc(allocator.root(), bigSize);
844 void* ptr6 = partitionAlloc(allocator.root(), bigSize);
845
846 partitionFree(ptr);
847 partitionFree(ptr2);
848 partitionFree(ptr3);
849 partitionFree(ptr4);
850 partitionFree(ptr5);
851 partitionFree(ptr6);
852 EXPECT_NE(-1, page->emptyCacheIndex);
853 EXPECT_NE(-1, page2->emptyCacheIndex);
854 EXPECT_TRUE(page2->freelistHead);
855 EXPECT_EQ(0, page2->numAllocatedSlots);
856
857 // And test a couple of sizes that do not cross kSystemPageSize with a single allocation.
858 size_t mediumSize = (kSystemPageSize / 2) - kExtraAllocSize;
859 bucketIdx = (mediumSize + kExtraAllocSize) >> kBucketShift;
860 bucket = &allocator.root()->buckets()[bucketIdx];
861 EXPECT_EQ(0, bucket->emptyPagesHead);
862
863 ptr = partitionAlloc(allocator.root(), mediumSize);
864 EXPECT_TRUE(ptr);
865 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
866 EXPECT_EQ(1, page->numAllocatedSlots);
867 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / (me diumSize + kExtraAllocSize);
868 size_t firstPageSlots = kSystemPageSize / (mediumSize + kExtraAllocSize);
869 EXPECT_EQ(2u, firstPageSlots);
870 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
871
872 partitionFree(ptr);
873
874 size_t smallSize = (kSystemPageSize / 4) - kExtraAllocSize;
875 bucketIdx = (smallSize + kExtraAllocSize) >> kBucketShift;
876 bucket = &allocator.root()->buckets()[bucketIdx];
877 EXPECT_EQ(0, bucket->emptyPagesHead);
878
879 ptr = partitionAlloc(allocator.root(), smallSize);
880 EXPECT_TRUE(ptr);
881 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
882 EXPECT_EQ(1, page->numAllocatedSlots);
883 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / (sm allSize + kExtraAllocSize);
884 firstPageSlots = kSystemPageSize / (smallSize + kExtraAllocSize);
885 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
886
887 partitionFree(ptr);
888 EXPECT_TRUE(page->freelistHead);
889 EXPECT_EQ(0, page->numAllocatedSlots);
890
891 size_t verySmallSize = 32 - kExtraAllocSize;
892 bucketIdx = (verySmallSize + kExtraAllocSize) >> kBucketShift;
893 bucket = &allocator.root()->buckets()[bucketIdx];
894 EXPECT_EQ(0, bucket->emptyPagesHead);
895
896 ptr = partitionAlloc(allocator.root(), verySmallSize);
897 EXPECT_TRUE(ptr);
898 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
899 EXPECT_EQ(1, page->numAllocatedSlots);
900 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / (ve rySmallSize + kExtraAllocSize);
901 firstPageSlots = kSystemPageSize / (verySmallSize + kExtraAllocSize);
902 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
903
904 partitionFree(ptr);
905 EXPECT_TRUE(page->freelistHead);
906 EXPECT_EQ(0, page->numAllocatedSlots);
907
908 // And try an allocation size (against the generic allocator) that is
909 // larger than a system page.
910 size_t pageAndAHalfSize = (kSystemPageSize + (kSystemPageSize / 2)) - kExtraAl locSize;
911 ptr = partitionAllocGeneric(genericAllocator.root(), pageAndAHalfSize);
912 EXPECT_TRUE(ptr);
913 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
914 EXPECT_EQ(1, page->numAllocatedSlots);
915 EXPECT_TRUE(page->freelistHead);
916 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / (pa geAndAHalfSize + kExtraAllocSize);
917 EXPECT_EQ(totalSlots - 2, page->numUnprovisionedSlots);
918 partitionFreeGeneric(genericAllocator.root(), ptr);
919
920 // And then make sure than exactly the page size only faults one page.
921 size_t pageSize = kSystemPageSize - kExtraAllocSize;
922 ptr = partitionAllocGeneric(genericAllocator.root(), pageSize);
923 EXPECT_TRUE(ptr);
924 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
925 EXPECT_EQ(1, page->numAllocatedSlots);
926 EXPECT_FALSE(page->freelistHead);
927 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / (pa geSize + kExtraAllocSize);
928 EXPECT_EQ(totalSlots - 1, page->numUnprovisionedSlots);
929 partitionFreeGeneric(genericAllocator.root(), ptr);
930
931 TestShutdown();
932 }
933
934 // Test some of the fragmentation-resistant properties of the allocator.
935 TEST(PartitionAllocTest, PageRefilling) {
936 TestSetup();
937 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex];
938
939 // Grab two full pages and a non-full page.
940 PartitionPage* page1 = GetFullPage(kTestAllocSize);
941 PartitionPage* page2 = GetFullPage(kTestAllocSize);
942 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
943 EXPECT_TRUE(ptr);
944 EXPECT_NE(page1, bucket->activePagesHead);
945 EXPECT_NE(page2, bucket->activePagesHead);
946 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjust( ptr));
947 EXPECT_EQ(1, page->numAllocatedSlots);
948
949 // Work out a pointer into page2 and free it; and then page1 and free it.
950 char* ptr2 = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPointer Offset;
951 partitionFree(ptr2);
952 ptr2 = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffset ;
953 partitionFree(ptr2);
954
955 // If we perform two allocations from the same bucket now, we expect to
956 // refill both the nearly full pages.
957 (void)partitionAlloc(allocator.root(), kTestAllocSize);
958 (void)partitionAlloc(allocator.root(), kTestAllocSize);
959 EXPECT_EQ(1, page->numAllocatedSlots);
960
961 FreeFullPage(page2);
962 FreeFullPage(page1);
963 partitionFree(ptr);
964
965 TestShutdown();
966 }
967
968 // Basic tests to ensure that allocations work for partial page buckets.
969 TEST(PartitionAllocTest, PartialPages) {
970 TestSetup();
971
972 // Find a size that is backed by a partial partition page.
973 size_t size = sizeof(void*);
974 PartitionBucket* bucket = 0;
975 while (size < kTestMaxAllocation) {
976 bucket = &allocator.root()->buckets()[size >> kBucketShift];
977 if (bucket->numSystemPagesPerSlotSpan % kNumSystemPagesPerPartitionPage)
978 break;
979 size += sizeof(void*);
980 }
981 EXPECT_LT(size, kTestMaxAllocation);
982
983 PartitionPage* page1 = GetFullPage(size);
984 PartitionPage* page2 = GetFullPage(size);
985 FreeFullPage(page2);
986 FreeFullPage(page1);
987
988 TestShutdown();
989 }
990
991 // Test correct handling if our mapping collides with another.
992 TEST(PartitionAllocTest, MappingCollision) {
993 TestSetup();
994 // The -2 is because the first and last partition pages in a super page are
995 // guard pages.
996 size_t numPartitionPagesNeeded = kNumPartitionPagesPerSuperPage - 2;
997 OwnPtr<PartitionPage* []> firstSuperPagePages = adoptArrayPtr(new PartitionPag e*[numPartitionPagesNeeded]);
998 OwnPtr<PartitionPage* []> secondSuperPagePages = adoptArrayPtr(new PartitionPa ge*[numPartitionPagesNeeded]);
999
1000 size_t i;
1001 for (i = 0; i < numPartitionPagesNeeded; ++i)
1002 firstSuperPagePages[i] = GetFullPage(kTestAllocSize);
1003
1004 char* pageBase = reinterpret_cast<char*>(partitionPageToPointer(firstSuperPage Pages[0]));
1005 EXPECT_EQ(kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & kSuperPa geOffsetMask);
1006 pageBase -= kPartitionPageSize;
1007 // Map a single system page either side of the mapping for our allocations,
1008 // with the goal of tripping up alignment of the next mapping.
1009 void* map1 = allocPages(pageBase - kPageAllocationGranularity, kPageAllocation Granularity, kPageAllocationGranularity, PageInaccessible);
1010 EXPECT_TRUE(map1);
1011 void* map2 = allocPages(pageBase + kSuperPageSize, kPageAllocationGranularity, kPageAllocationGranularity, PageInaccessible);
1012 EXPECT_TRUE(map2);
1013
1014 for (i = 0; i < numPartitionPagesNeeded; ++i)
1015 secondSuperPagePages[i] = GetFullPage(kTestAllocSize);
1016
1017 freePages(map1, kPageAllocationGranularity);
1018 freePages(map2, kPageAllocationGranularity);
1019
1020 pageBase = reinterpret_cast<char*>(partitionPageToPointer(secondSuperPagePages [0]));
1021 EXPECT_EQ(kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & kSuperPa geOffsetMask);
1022 pageBase -= kPartitionPageSize;
1023 // Map a single system page either side of the mapping for our allocations,
1024 // with the goal of tripping up alignment of the next mapping.
1025 map1 = allocPages(pageBase - kPageAllocationGranularity, kPageAllocationGranul arity, kPageAllocationGranularity, PageAccessible);
1026 EXPECT_TRUE(map1);
1027 map2 = allocPages(pageBase + kSuperPageSize, kPageAllocationGranularity, kPage AllocationGranularity, PageAccessible);
1028 EXPECT_TRUE(map2);
1029 setSystemPagesInaccessible(map1, kPageAllocationGranularity);
1030 setSystemPagesInaccessible(map2, kPageAllocationGranularity);
1031
1032 PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize);
1033 freePages(map1, kPageAllocationGranularity);
1034 freePages(map2, kPageAllocationGranularity);
1035
1036 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThirdSu perPage)) & kPartitionPageOffsetMask);
1037
1038 // And make sure we really did get a page in a new superpage.
1039 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(firstSuperPagePag es[0])) & kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointer (pageInThirdSuperPage)) & kSuperPageBaseMask);
1040 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(secondSuperPagePa ges[0])) & kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPointe r(pageInThirdSuperPage)) & kSuperPageBaseMask);
1041
1042 FreeFullPage(pageInThirdSuperPage);
1043 for (i = 0; i < numPartitionPagesNeeded; ++i) {
1044 FreeFullPage(firstSuperPagePages[i]);
1045 FreeFullPage(secondSuperPagePages[i]);
1046 }
1047
1048 TestShutdown();
1049 }
1050
1051 // Tests that pages in the free page cache do get freed as appropriate.
1052 TEST(PartitionAllocTest, FreeCache) {
1053 TestSetup();
1054
1055 EXPECT_EQ(0U, allocator.root()->totalSizeOfCommittedPages);
1056
1057 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
1058 size_t bucketIdx = (bigSize + kExtraAllocSize) >> kBucketShift;
1059 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
1060
1061 void* ptr = partitionAlloc(allocator.root(), bigSize);
1062 EXPECT_TRUE(ptr);
1063 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjust( ptr));
1064 EXPECT_EQ(0, bucket->emptyPagesHead);
1065 EXPECT_EQ(1, page->numAllocatedSlots);
1066 EXPECT_EQ(kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages);
1067 partitionFree(ptr);
1068 EXPECT_EQ(0, page->numAllocatedSlots);
1069 EXPECT_NE(-1, page->emptyCacheIndex);
1070 EXPECT_TRUE(page->freelistHead);
1071
1072 CycleFreeCache(kTestAllocSize);
1073
1074 // Flushing the cache should have really freed the unused page.
1075 EXPECT_FALSE(page->freelistHead);
1076 EXPECT_EQ(-1, page->emptyCacheIndex);
1077 EXPECT_EQ(0, page->numAllocatedSlots);
1078 PartitionBucket* cycleFreeCacheBucket = &allocator.root()->buckets()[kTestBuck etIndex];
1079 EXPECT_EQ(cycleFreeCacheBucket->numSystemPagesPerSlotSpan * kSystemPageSize, a llocator.root()->totalSizeOfCommittedPages);
1080
1081 // Check that an allocation works ok whilst in this state (a free'd page
1082 // as the active pages head).
1083 ptr = partitionAlloc(allocator.root(), bigSize);
1084 EXPECT_FALSE(bucket->emptyPagesHead);
1085 partitionFree(ptr);
1086
1087 // Also check that a page that is bouncing immediately between empty and
1088 // used does not get freed.
1089 for (size_t i = 0; i < kMaxFreeableSpans * 2; ++i) {
1090 ptr = partitionAlloc(allocator.root(), bigSize);
841 EXPECT_TRUE(page->freelistHead); 1091 EXPECT_TRUE(page->freelistHead);
842 EXPECT_EQ(1, page->numAllocatedSlots);
843 EXPECT_EQ(2, page->numUnprovisionedSlots);
844
845 void* ptr2 = partitionAlloc(allocator.root(), bigSize);
846 EXPECT_TRUE(ptr2);
847 EXPECT_FALSE(page->freelistHead);
848 EXPECT_EQ(2, page->numAllocatedSlots);
849 EXPECT_EQ(2, page->numUnprovisionedSlots);
850
851 void* ptr3 = partitionAlloc(allocator.root(), bigSize);
852 EXPECT_TRUE(ptr3);
853 EXPECT_TRUE(page->freelistHead);
854 EXPECT_EQ(3, page->numAllocatedSlots);
855 EXPECT_EQ(0, page->numUnprovisionedSlots);
856
857 void* ptr4 = partitionAlloc(allocator.root(), bigSize);
858 EXPECT_TRUE(ptr4);
859 EXPECT_FALSE(page->freelistHead);
860 EXPECT_EQ(4, page->numAllocatedSlots);
861 EXPECT_EQ(0, page->numUnprovisionedSlots);
862
863 void* ptr5 = partitionAlloc(allocator.root(), bigSize);
864 EXPECT_TRUE(ptr5);
865
866 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr5));
867 EXPECT_EQ(1, page2->numAllocatedSlots);
868
869 // Churn things a little whilst there's a partial page freelist.
870 partitionFree(ptr);
871 ptr = partitionAlloc(allocator.root(), bigSize);
872 void* ptr6 = partitionAlloc(allocator.root(), bigSize);
873
874 partitionFree(ptr);
875 partitionFree(ptr2);
876 partitionFree(ptr3);
877 partitionFree(ptr4);
878 partitionFree(ptr5);
879 partitionFree(ptr6);
880 EXPECT_NE(-1, page->emptyCacheIndex);
881 EXPECT_NE(-1, page2->emptyCacheIndex);
882 EXPECT_TRUE(page2->freelistHead);
883 EXPECT_EQ(0, page2->numAllocatedSlots);
884
885 // And test a couple of sizes that do not cross kSystemPageSize with a singl e allocation.
886 size_t mediumSize = (kSystemPageSize / 2) - kExtraAllocSize;
887 bucketIdx = (mediumSize + kExtraAllocSize) >> kBucketShift;
888 bucket = &allocator.root()->buckets()[bucketIdx];
889 EXPECT_EQ(0, bucket->emptyPagesHead);
890
891 ptr = partitionAlloc(allocator.root(), mediumSize);
892 EXPECT_TRUE(ptr);
893 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
894 EXPECT_EQ(1, page->numAllocatedSlots);
895 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( mediumSize + kExtraAllocSize);
896 size_t firstPageSlots = kSystemPageSize / (mediumSize + kExtraAllocSize);
897 EXPECT_EQ(2u, firstPageSlots);
898 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
899
900 partitionFree(ptr);
901
902 size_t smallSize = (kSystemPageSize / 4) - kExtraAllocSize;
903 bucketIdx = (smallSize + kExtraAllocSize) >> kBucketShift;
904 bucket = &allocator.root()->buckets()[bucketIdx];
905 EXPECT_EQ(0, bucket->emptyPagesHead);
906
907 ptr = partitionAlloc(allocator.root(), smallSize);
908 EXPECT_TRUE(ptr);
909 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr));
910 EXPECT_EQ(1, page->numAllocatedSlots);
911 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( smallSize + kExtraAllocSize);
912 firstPageSlots = kSystemPageSize / (smallSize + kExtraAllocSize);
913 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots);
914
915 partitionFree(ptr); 1092 partitionFree(ptr);
916 EXPECT_TRUE(page->freelistHead); 1093 EXPECT_TRUE(page->freelistHead);
917 EXPECT_EQ(0, page->numAllocatedSlots); 1094 }
918 1095 EXPECT_EQ(kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages);
919 size_t verySmallSize = 32 - kExtraAllocSize; 1096 TestShutdown();
920 bucketIdx = (verySmallSize + kExtraAllocSize) >> kBucketShift; 1097 }
921 bucket = &allocator.root()->buckets()[bucketIdx]; 1098
922 EXPECT_EQ(0, bucket->emptyPagesHead); 1099 // Tests for a bug we had with losing references to free pages.
923 1100 TEST(PartitionAllocTest, LostFreePagesBug) {
924 ptr = partitionAlloc(allocator.root(), verySmallSize); 1101 TestSetup();
925 EXPECT_TRUE(ptr); 1102
926 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); 1103 size_t size = kPartitionPageSize - kExtraAllocSize;
927 EXPECT_EQ(1, page->numAllocatedSlots); 1104
928 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( verySmallSize + kExtraAllocSize); 1105 void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
929 firstPageSlots = kSystemPageSize / (verySmallSize + kExtraAllocSize); 1106 EXPECT_TRUE(ptr);
930 EXPECT_EQ(totalSlots - firstPageSlots, page->numUnprovisionedSlots); 1107 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
931 1108 EXPECT_TRUE(ptr2);
932 partitionFree(ptr); 1109
933 EXPECT_TRUE(page->freelistHead); 1110 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjust( ptr));
934 EXPECT_EQ(0, page->numAllocatedSlots); 1111 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdjust (ptr2));
935 1112 PartitionBucket* bucket = page->bucket;
936 // And try an allocation size (against the generic allocator) that is 1113
937 // larger than a system page. 1114 EXPECT_EQ(0, bucket->emptyPagesHead);
938 size_t pageAndAHalfSize = (kSystemPageSize + (kSystemPageSize / 2)) - kExtra AllocSize; 1115 EXPECT_EQ(-1, page->numAllocatedSlots);
939 ptr = partitionAllocGeneric(genericAllocator.root(), pageAndAHalfSize); 1116 EXPECT_EQ(1, page2->numAllocatedSlots);
940 EXPECT_TRUE(ptr); 1117
941 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); 1118 partitionFreeGeneric(genericAllocator.root(), ptr);
942 EXPECT_EQ(1, page->numAllocatedSlots); 1119 partitionFreeGeneric(genericAllocator.root(), ptr2);
943 EXPECT_TRUE(page->freelistHead); 1120
944 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( pageAndAHalfSize + kExtraAllocSize); 1121 EXPECT_TRUE(bucket->emptyPagesHead);
945 EXPECT_EQ(totalSlots - 2, page->numUnprovisionedSlots); 1122 EXPECT_TRUE(bucket->emptyPagesHead->nextPage);
946 partitionFreeGeneric(genericAllocator.root(), ptr); 1123 EXPECT_EQ(0, page->numAllocatedSlots);
947 1124 EXPECT_EQ(0, page2->numAllocatedSlots);
948 // And then make sure than exactly the page size only faults one page. 1125 EXPECT_TRUE(page->freelistHead);
949 size_t pageSize = kSystemPageSize - kExtraAllocSize; 1126 EXPECT_TRUE(page2->freelistHead);
950 ptr = partitionAllocGeneric(genericAllocator.root(), pageSize); 1127
951 EXPECT_TRUE(ptr); 1128 CycleGenericFreeCache(kTestAllocSize);
952 page = partitionPointerToPage(partitionCookieFreePointerAdjust(ptr)); 1129
953 EXPECT_EQ(1, page->numAllocatedSlots); 1130 EXPECT_FALSE(page->freelistHead);
954 EXPECT_FALSE(page->freelistHead); 1131 EXPECT_FALSE(page2->freelistHead);
955 totalSlots = (page->bucket->numSystemPagesPerSlotSpan * kSystemPageSize) / ( pageSize + kExtraAllocSize); 1132
956 EXPECT_EQ(totalSlots - 1, page->numUnprovisionedSlots); 1133 EXPECT_TRUE(bucket->emptyPagesHead);
957 partitionFreeGeneric(genericAllocator.root(), ptr); 1134 EXPECT_TRUE(bucket->emptyPagesHead->nextPage);
958 1135 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
959 TestShutdown(); 1136
960 } 1137 // At this moment, we have two decommitted pages, on the empty list.
961 1138 ptr = partitionAllocGeneric(genericAllocator.root(), size);
962 // Test some of the fragmentation-resistant properties of the allocator. 1139 EXPECT_TRUE(ptr);
963 TEST(PartitionAllocTest, PageRefilling) 1140 partitionFreeGeneric(genericAllocator.root(), ptr);
964 { 1141
965 TestSetup(); 1142 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
966 PartitionBucket* bucket = &allocator.root()->buckets()[kTestBucketIndex]; 1143 EXPECT_TRUE(bucket->emptyPagesHead);
967 1144 EXPECT_TRUE(bucket->decommittedPagesHead);
968 // Grab two full pages and a non-full page. 1145
969 PartitionPage* page1 = GetFullPage(kTestAllocSize); 1146 CycleGenericFreeCache(kTestAllocSize);
970 PartitionPage* page2 = GetFullPage(kTestAllocSize); 1147
971 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); 1148 // We're now set up to trigger a historical bug by scanning over the active
972 EXPECT_TRUE(ptr); 1149 // pages list. The current code gets into a different state, but we'll keep
973 EXPECT_NE(page1, bucket->activePagesHead); 1150 // the test as being an interesting corner case.
974 EXPECT_NE(page2, bucket->activePagesHead); 1151 ptr = partitionAllocGeneric(genericAllocator.root(), size);
975 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr)); 1152 EXPECT_TRUE(ptr);
976 EXPECT_EQ(1, page->numAllocatedSlots); 1153 partitionFreeGeneric(genericAllocator.root(), ptr);
977 1154
978 // Work out a pointer into page2 and free it; and then page1 and free it. 1155 EXPECT_TRUE(bucket->activePagesHead);
979 char* ptr2 = reinterpret_cast<char*>(partitionPageToPointer(page1)) + kPoint erOffset; 1156 EXPECT_TRUE(bucket->emptyPagesHead);
980 partitionFree(ptr2); 1157 EXPECT_TRUE(bucket->decommittedPagesHead);
981 ptr2 = reinterpret_cast<char*>(partitionPageToPointer(page2)) + kPointerOffs et; 1158
982 partitionFree(ptr2); 1159 TestShutdown();
983 1160 }
984 // If we perform two allocations from the same bucket now, we expect to 1161
985 // refill both the nearly full pages. 1162 #if !CPU(64BIT) || OS(POSIX)
986 (void) partitionAlloc(allocator.root(), kTestAllocSize); 1163
987 (void) partitionAlloc(allocator.root(), kTestAllocSize); 1164 static void DoReturnNullTest(size_t allocSize) {
988 EXPECT_EQ(1, page->numAllocatedSlots); 1165 TestSetup();
989 1166
990 FreeFullPage(page2); 1167 EXPECT_TRUE(SetAddressSpaceLimit());
991 FreeFullPage(page1); 1168
992 partitionFree(ptr); 1169 // Work out the number of allocations for 6 GB of memory.
993 1170 const int numAllocations = (6 * 1024 * 1024) / (allocSize / 1024);
994 TestShutdown(); 1171
995 } 1172 void** ptrs = reinterpret_cast<void**>(partitionAllocGeneric(genericAllocator. root(), numAllocations * sizeof(void*)));
996 1173 int i;
997 // Basic tests to ensure that allocations work for partial page buckets. 1174
998 TEST(PartitionAllocTest, PartialPages) 1175 for (i = 0; i < numAllocations; ++i) {
999 { 1176 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionAlloc ReturnNull, allocSize);
1000 TestSetup(); 1177 if (!i)
1001 1178 EXPECT_TRUE(ptrs[0]);
1002 // Find a size that is backed by a partial partition page. 1179 if (!ptrs[i]) {
1003 size_t size = sizeof(void*); 1180 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionAll ocReturnNull, allocSize);
1004 PartitionBucket* bucket = 0; 1181 EXPECT_FALSE(ptrs[i]);
1005 while (size < kTestMaxAllocation) { 1182 break;
1006 bucket = &allocator.root()->buckets()[size >> kBucketShift];
1007 if (bucket->numSystemPagesPerSlotSpan % kNumSystemPagesPerPartitionPage)
1008 break;
1009 size += sizeof(void*);
1010 } 1183 }
1011 EXPECT_LT(size, kTestMaxAllocation); 1184 }
1012 1185
1013 PartitionPage* page1 = GetFullPage(size); 1186 // We shouldn't succeed in allocating all 6 GB of memory. If we do, then
1014 PartitionPage* page2 = GetFullPage(size); 1187 // we're not actually testing anything here.
1015 FreeFullPage(page2); 1188 EXPECT_LT(i, numAllocations);
1016 FreeFullPage(page1); 1189
1017 1190 // Free, reallocate and free again each block we allocated. We do this to
1018 TestShutdown(); 1191 // check that freeing memory also works correctly after a failed allocation.
1019 } 1192 for (--i; i >= 0; --i) {
1020 1193 partitionFreeGeneric(genericAllocator.root(), ptrs[i]);
1021 // Test correct handling if our mapping collides with another. 1194 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionAlloc ReturnNull, allocSize);
1022 TEST(PartitionAllocTest, MappingCollision) 1195 EXPECT_TRUE(ptrs[i]);
1023 { 1196 partitionFreeGeneric(genericAllocator.root(), ptrs[i]);
1024 TestSetup(); 1197 }
1025 // The -2 is because the first and last partition pages in a super page are 1198
1026 // guard pages. 1199 partitionFreeGeneric(genericAllocator.root(), ptrs);
1027 size_t numPartitionPagesNeeded = kNumPartitionPagesPerSuperPage - 2; 1200
1028 OwnPtr<PartitionPage*[]> firstSuperPagePages = adoptArrayPtr(new PartitionPa ge*[numPartitionPagesNeeded]); 1201 EXPECT_TRUE(ClearAddressSpaceLimit());
1029 OwnPtr<PartitionPage*[]> secondSuperPagePages = adoptArrayPtr(new PartitionP age*[numPartitionPagesNeeded]); 1202
1030 1203 TestShutdown();
1031 size_t i;
1032 for (i = 0; i < numPartitionPagesNeeded; ++i)
1033 firstSuperPagePages[i] = GetFullPage(kTestAllocSize);
1034
1035 char* pageBase = reinterpret_cast<char*>(partitionPageToPointer(firstSuperPa gePages[0]));
1036 EXPECT_EQ(kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & kSuper PageOffsetMask);
1037 pageBase -= kPartitionPageSize;
1038 // Map a single system page either side of the mapping for our allocations,
1039 // with the goal of tripping up alignment of the next mapping.
1040 void* map1 = allocPages(pageBase - kPageAllocationGranularity, kPageAllocati onGranularity, kPageAllocationGranularity, PageInaccessible);
1041 EXPECT_TRUE(map1);
1042 void* map2 = allocPages(pageBase + kSuperPageSize, kPageAllocationGranularit y, kPageAllocationGranularity, PageInaccessible);
1043 EXPECT_TRUE(map2);
1044
1045 for (i = 0; i < numPartitionPagesNeeded; ++i)
1046 secondSuperPagePages[i] = GetFullPage(kTestAllocSize);
1047
1048 freePages(map1, kPageAllocationGranularity);
1049 freePages(map2, kPageAllocationGranularity);
1050
1051 pageBase = reinterpret_cast<char*>(partitionPageToPointer(secondSuperPagePag es[0]));
1052 EXPECT_EQ(kPartitionPageSize, reinterpret_cast<uintptr_t>(pageBase) & kSuper PageOffsetMask);
1053 pageBase -= kPartitionPageSize;
1054 // Map a single system page either side of the mapping for our allocations,
1055 // with the goal of tripping up alignment of the next mapping.
1056 map1 = allocPages(pageBase - kPageAllocationGranularity, kPageAllocationGran ularity, kPageAllocationGranularity, PageAccessible);
1057 EXPECT_TRUE(map1);
1058 map2 = allocPages(pageBase + kSuperPageSize, kPageAllocationGranularity, kPa geAllocationGranularity, PageAccessible);
1059 EXPECT_TRUE(map2);
1060 setSystemPagesInaccessible(map1, kPageAllocationGranularity);
1061 setSystemPagesInaccessible(map2, kPageAllocationGranularity);
1062
1063 PartitionPage* pageInThirdSuperPage = GetFullPage(kTestAllocSize);
1064 freePages(map1, kPageAllocationGranularity);
1065 freePages(map2, kPageAllocationGranularity);
1066
1067 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(partitionPageToPointer(pageInThird SuperPage)) & kPartitionPageOffsetMask);
1068
1069 // And make sure we really did get a page in a new superpage.
1070 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(firstSuperPageP ages[0])) & kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPoint er(pageInThirdSuperPage)) & kSuperPageBaseMask);
1071 EXPECT_NE(reinterpret_cast<uintptr_t>(partitionPageToPointer(secondSuperPage Pages[0])) & kSuperPageBaseMask, reinterpret_cast<uintptr_t>(partitionPageToPoin ter(pageInThirdSuperPage)) & kSuperPageBaseMask);
1072
1073 FreeFullPage(pageInThirdSuperPage);
1074 for (i = 0; i < numPartitionPagesNeeded; ++i) {
1075 FreeFullPage(firstSuperPagePages[i]);
1076 FreeFullPage(secondSuperPagePages[i]);
1077 }
1078
1079 TestShutdown();
1080 }
1081
1082 // Tests that pages in the free page cache do get freed as appropriate.
1083 TEST(PartitionAllocTest, FreeCache)
1084 {
1085 TestSetup();
1086
1087 EXPECT_EQ(0U, allocator.root()->totalSizeOfCommittedPages);
1088
1089 size_t bigSize = allocator.root()->maxAllocation - kExtraAllocSize;
1090 size_t bucketIdx = (bigSize + kExtraAllocSize) >> kBucketShift;
1091 PartitionBucket* bucket = &allocator.root()->buckets()[bucketIdx];
1092
1093 void* ptr = partitionAlloc(allocator.root(), bigSize);
1094 EXPECT_TRUE(ptr);
1095 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr));
1096 EXPECT_EQ(0, bucket->emptyPagesHead);
1097 EXPECT_EQ(1, page->numAllocatedSlots);
1098 EXPECT_EQ(kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages);
1099 partitionFree(ptr);
1100 EXPECT_EQ(0, page->numAllocatedSlots);
1101 EXPECT_NE(-1, page->emptyCacheIndex);
1102 EXPECT_TRUE(page->freelistHead);
1103
1104 CycleFreeCache(kTestAllocSize);
1105
1106 // Flushing the cache should have really freed the unused page.
1107 EXPECT_FALSE(page->freelistHead);
1108 EXPECT_EQ(-1, page->emptyCacheIndex);
1109 EXPECT_EQ(0, page->numAllocatedSlots);
1110 PartitionBucket* cycleFreeCacheBucket = &allocator.root()->buckets()[kTestBu cketIndex];
1111 EXPECT_EQ(cycleFreeCacheBucket->numSystemPagesPerSlotSpan * kSystemPageSize, allocator.root()->totalSizeOfCommittedPages);
1112
1113 // Check that an allocation works ok whilst in this state (a free'd page
1114 // as the active pages head).
1115 ptr = partitionAlloc(allocator.root(), bigSize);
1116 EXPECT_FALSE(bucket->emptyPagesHead);
1117 partitionFree(ptr);
1118
1119 // Also check that a page that is bouncing immediately between empty and
1120 // used does not get freed.
1121 for (size_t i = 0; i < kMaxFreeableSpans * 2; ++i) {
1122 ptr = partitionAlloc(allocator.root(), bigSize);
1123 EXPECT_TRUE(page->freelistHead);
1124 partitionFree(ptr);
1125 EXPECT_TRUE(page->freelistHead);
1126 }
1127 EXPECT_EQ(kPartitionPageSize, allocator.root()->totalSizeOfCommittedPages);
1128 TestShutdown();
1129 }
1130
1131 // Tests for a bug we had with losing references to free pages.
1132 TEST(PartitionAllocTest, LostFreePagesBug)
1133 {
1134 TestSetup();
1135
1136 size_t size = kPartitionPageSize - kExtraAllocSize;
1137
1138 void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
1139 EXPECT_TRUE(ptr);
1140 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
1141 EXPECT_TRUE(ptr2);
1142
1143 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr));
1144 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr2));
1145 PartitionBucket* bucket = page->bucket;
1146
1147 EXPECT_EQ(0, bucket->emptyPagesHead);
1148 EXPECT_EQ(-1, page->numAllocatedSlots);
1149 EXPECT_EQ(1, page2->numAllocatedSlots);
1150
1151 partitionFreeGeneric(genericAllocator.root(), ptr);
1152 partitionFreeGeneric(genericAllocator.root(), ptr2);
1153
1154 EXPECT_TRUE(bucket->emptyPagesHead);
1155 EXPECT_TRUE(bucket->emptyPagesHead->nextPage);
1156 EXPECT_EQ(0, page->numAllocatedSlots);
1157 EXPECT_EQ(0, page2->numAllocatedSlots);
1158 EXPECT_TRUE(page->freelistHead);
1159 EXPECT_TRUE(page2->freelistHead);
1160
1161 CycleGenericFreeCache(kTestAllocSize);
1162
1163 EXPECT_FALSE(page->freelistHead);
1164 EXPECT_FALSE(page2->freelistHead);
1165
1166 EXPECT_TRUE(bucket->emptyPagesHead);
1167 EXPECT_TRUE(bucket->emptyPagesHead->nextPage);
1168 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
1169
1170 // At this moment, we have two decommitted pages, on the empty list.
1171 ptr = partitionAllocGeneric(genericAllocator.root(), size);
1172 EXPECT_TRUE(ptr);
1173 partitionFreeGeneric(genericAllocator.root(), ptr);
1174
1175 EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->activePagesHead);
1176 EXPECT_TRUE(bucket->emptyPagesHead);
1177 EXPECT_TRUE(bucket->decommittedPagesHead);
1178
1179 CycleGenericFreeCache(kTestAllocSize);
1180
1181 // We're now set up to trigger a historical bug by scanning over the active
1182 // pages list. The current code gets into a different state, but we'll keep
1183 // the test as being an interesting corner case.
1184 ptr = partitionAllocGeneric(genericAllocator.root(), size);
1185 EXPECT_TRUE(ptr);
1186 partitionFreeGeneric(genericAllocator.root(), ptr);
1187
1188 EXPECT_TRUE(bucket->activePagesHead);
1189 EXPECT_TRUE(bucket->emptyPagesHead);
1190 EXPECT_TRUE(bucket->decommittedPagesHead);
1191
1192 TestShutdown();
1193 }
1194
1195 #if !CPU(64BIT) || OS(POSIX)
1196
1197 static void DoReturnNullTest(size_t allocSize)
1198 {
1199 TestSetup();
1200
1201 EXPECT_TRUE(SetAddressSpaceLimit());
1202
1203 // Work out the number of allocations for 6 GB of memory.
1204 const int numAllocations = (6 * 1024 * 1024) / (allocSize / 1024);
1205
1206 void** ptrs = reinterpret_cast<void**>(partitionAllocGeneric(genericAllocato r.root(), numAllocations * sizeof(void*)));
1207 int i;
1208
1209 for (i = 0; i < numAllocations; ++i) {
1210 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionA llocReturnNull, allocSize);
1211 if (!i)
1212 EXPECT_TRUE(ptrs[0]);
1213 if (!ptrs[i]) {
1214 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), Partit ionAllocReturnNull, allocSize);
1215 EXPECT_FALSE(ptrs[i]);
1216 break;
1217 }
1218 }
1219
1220 // We shouldn't succeed in allocating all 6 GB of memory. If we do, then
1221 // we're not actually testing anything here.
1222 EXPECT_LT(i, numAllocations);
1223
1224 // Free, reallocate and free again each block we allocated. We do this to
1225 // check that freeing memory also works correctly after a failed allocation.
1226 for (--i; i >= 0; --i) {
1227 partitionFreeGeneric(genericAllocator.root(), ptrs[i]);
1228 ptrs[i] = partitionAllocGenericFlags(genericAllocator.root(), PartitionA llocReturnNull, allocSize);
1229 EXPECT_TRUE(ptrs[i]);
1230 partitionFreeGeneric(genericAllocator.root(), ptrs[i]);
1231 }
1232
1233 partitionFreeGeneric(genericAllocator.root(), ptrs);
1234
1235 EXPECT_TRUE(ClearAddressSpaceLimit());
1236
1237 TestShutdown();
1238 } 1204 }
1239 1205
1240 // Tests that if an allocation fails in "return null" mode, repeating it doesn't 1206 // Tests that if an allocation fails in "return null" mode, repeating it doesn't
1241 // crash, and still returns null. The test tries to allocate 6 GB of memory in 1207 // crash, and still returns null. The test tries to allocate 6 GB of memory in
1242 // 512 kB blocks. On 64-bit POSIX systems, the address space is limited to 4 GB 1208 // 512 kB blocks. On 64-bit POSIX systems, the address space is limited to 4 GB
1243 // using setrlimit() first. 1209 // using setrlimit() first.
1244 #if OS(MACOSX) 1210 #if OS(MACOSX)
1245 #define MAYBE_RepeatedReturnNull DISABLED_RepeatedReturnNull 1211 #define MAYBE_RepeatedReturnNull DISABLED_RepeatedReturnNull
1246 #else 1212 #else
1247 #define MAYBE_RepeatedReturnNull RepeatedReturnNull 1213 #define MAYBE_RepeatedReturnNull RepeatedReturnNull
1248 #endif 1214 #endif
1249 TEST(PartitionAllocTest, MAYBE_RepeatedReturnNull) 1215 TEST(PartitionAllocTest, MAYBE_RepeatedReturnNull) {
1250 { 1216 // A single-slot but non-direct-mapped allocation size.
1251 // A single-slot but non-direct-mapped allocation size. 1217 DoReturnNullTest(512 * 1024);
1252 DoReturnNullTest(512 * 1024);
1253 } 1218 }
1254 1219
1255 // Another "return null" test but for larger, direct-mapped allocations. 1220 // Another "return null" test but for larger, direct-mapped allocations.
1256 #if OS(MACOSX) 1221 #if OS(MACOSX)
1257 #define MAYBE_RepeatedReturnNullDirect DISABLED_RepeatedReturnNullDirect 1222 #define MAYBE_RepeatedReturnNullDirect DISABLED_RepeatedReturnNullDirect
1258 #else 1223 #else
1259 #define MAYBE_RepeatedReturnNullDirect RepeatedReturnNullDirect 1224 #define MAYBE_RepeatedReturnNullDirect RepeatedReturnNullDirect
1260 #endif 1225 #endif
1261 TEST(PartitionAllocTest, MAYBE_RepeatedReturnNullDirect) 1226 TEST(PartitionAllocTest, MAYBE_RepeatedReturnNullDirect) {
1262 { 1227 // A direct-mapped allocation size.
1263 // A direct-mapped allocation size. 1228 DoReturnNullTest(256 * 1024 * 1024);
1264 DoReturnNullTest(256 * 1024 * 1024); 1229 }
1265 } 1230
1266 1231 #endif // !CPU(64BIT) || OS(POSIX)
1267 #endif // !CPU(64BIT) || OS(POSIX)
1268 1232
1269 #if !OS(ANDROID) 1233 #if !OS(ANDROID)
1270 1234
1271 // Make sure that malloc(-1) dies. 1235 // Make sure that malloc(-1) dies.
1272 // In the past, we had an integer overflow that would alias malloc(-1) to 1236 // In the past, we had an integer overflow that would alias malloc(-1) to
1273 // malloc(0), which is not good. 1237 // malloc(0), which is not good.
1274 TEST(PartitionAllocDeathTest, LargeAllocs) 1238 TEST(PartitionAllocDeathTest, LargeAllocs) {
1275 { 1239 TestSetup();
1276 TestSetup(); 1240 // Largest alloc.
1277 // Largest alloc. 1241 EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size_t >(-1)), "");
1278 EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size _t>(-1)), ""); 1242 // And the smallest allocation we expect to die.
1279 // And the smallest allocation we expect to die. 1243 EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size_t >(INT_MAX) + 1), "");
1280 EXPECT_DEATH(partitionAllocGeneric(genericAllocator.root(), static_cast<size _t>(INT_MAX) + 1), ""); 1244
1281 1245 TestShutdown();
1282 TestShutdown();
1283 } 1246 }
1284 1247
1285 // Check that our immediate double-free detection works. 1248 // Check that our immediate double-free detection works.
1286 TEST(PartitionAllocDeathTest, ImmediateDoubleFree) 1249 TEST(PartitionAllocDeathTest, ImmediateDoubleFree) {
1287 { 1250 TestSetup();
1288 TestSetup(); 1251
1289 1252 void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
1290 void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize); 1253 EXPECT_TRUE(ptr);
1291 EXPECT_TRUE(ptr); 1254 partitionFreeGeneric(genericAllocator.root(), ptr);
1292 partitionFreeGeneric(genericAllocator.root(), ptr); 1255
1293 1256 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), "");
1294 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), ""); 1257
1295 1258 TestShutdown();
1296 TestShutdown();
1297 } 1259 }
1298 1260
1299 // Check that our refcount-based double-free detection works. 1261 // Check that our refcount-based double-free detection works.
1300 TEST(PartitionAllocDeathTest, RefcountDoubleFree) 1262 TEST(PartitionAllocDeathTest, RefcountDoubleFree) {
1301 { 1263 TestSetup();
1302 TestSetup(); 1264
1303 1265 void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
1304 void* ptr = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize); 1266 EXPECT_TRUE(ptr);
1305 EXPECT_TRUE(ptr); 1267 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize);
1306 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kTestAllocSize); 1268 EXPECT_TRUE(ptr2);
1307 EXPECT_TRUE(ptr2); 1269 partitionFreeGeneric(genericAllocator.root(), ptr);
1308 partitionFreeGeneric(genericAllocator.root(), ptr); 1270 partitionFreeGeneric(genericAllocator.root(), ptr2);
1309 partitionFreeGeneric(genericAllocator.root(), ptr2); 1271 // This is not an immediate double-free so our immediate detection won't
1310 // This is not an immediate double-free so our immediate detection won't 1272 // fire. However, it does take the "refcount" of the partition page to -1,
1311 // fire. However, it does take the "refcount" of the partition page to -1, 1273 // which is illegal and should be trapped.
1312 // which is illegal and should be trapped. 1274 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), "");
1313 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), ptr), ""); 1275
1314 1276 TestShutdown();
1315 TestShutdown();
1316 } 1277 }
1317 1278
1318 // Check that guard pages are present where expected. 1279 // Check that guard pages are present where expected.
1319 TEST(PartitionAllocDeathTest, GuardPages) 1280 TEST(PartitionAllocDeathTest, GuardPages) {
1320 { 1281 TestSetup();
1321 TestSetup(); 1282
1322 1283 // partitionAlloc adds kPartitionPageSize to the requested size
1323 // partitionAlloc adds kPartitionPageSize to the requested size 1284 // (for metadata), and then rounds that size to kPageAllocationGranularity.
1324 // (for metadata), and then rounds that size to kPageAllocationGranularity. 1285 // To be able to reliably write one past a direct allocation, choose a size
1325 // To be able to reliably write one past a direct allocation, choose a size 1286 // that's
1326 // that's 1287 // a) larger than kGenericMaxBucketed (to make the allocation direct)
1327 // a) larger than kGenericMaxBucketed (to make the allocation direct) 1288 // b) aligned at kPageAllocationGranularity boundaries after
1328 // b) aligned at kPageAllocationGranularity boundaries after 1289 // kPartitionPageSize has been added to it.
1329 // kPartitionPageSize has been added to it. 1290 // (On 32-bit, partitionAlloc adds another kSystemPageSize to the
1330 // (On 32-bit, partitionAlloc adds another kSystemPageSize to the 1291 // allocation size before rounding, but there it marks the memory right
1331 // allocation size before rounding, but there it marks the memory right 1292 // after size as inaccessible, so it's fine to write 1 past the size we
1332 // after size as inaccessible, so it's fine to write 1 past the size we 1293 // hand to partitionAlloc and we don't need to worry about allocation
1333 // hand to partitionAlloc and we don't need to worry about allocation 1294 // granularities.)
1334 // granularities.) 1295 #define ALIGN(N, A) (((N) + (A)-1) / (A) * (A))
1335 #define ALIGN(N, A) (((N) + (A) - 1) / (A) * (A)) 1296 const int kSize = ALIGN(kGenericMaxBucketed + 1 + kPartitionPageSize, kPageAll ocationGranularity) - kPartitionPageSize;
1336 const int kSize = ALIGN(kGenericMaxBucketed + 1 + kPartitionPageSize, kPageA llocationGranularity) - kPartitionPageSize;
1337 #undef ALIGN 1297 #undef ALIGN
1338 static_assert(kSize > kGenericMaxBucketed, "allocation not large enough for direct allocation"); 1298 static_assert(kSize > kGenericMaxBucketed, "allocation not large enough for di rect allocation");
1339 size_t size = kSize - kExtraAllocSize; 1299 size_t size = kSize - kExtraAllocSize;
1340 void* ptr = partitionAllocGeneric(genericAllocator.root(), size); 1300 void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
1341 1301
1342 EXPECT_TRUE(ptr); 1302 EXPECT_TRUE(ptr);
1343 char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset; 1303 char* charPtr = reinterpret_cast<char*>(ptr) - kPointerOffset;
1344 1304
1345 EXPECT_DEATH(*(charPtr - 1) = 'A', ""); 1305 EXPECT_DEATH(*(charPtr - 1) = 'A', "");
1346 EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', ""); 1306 EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', "");
1347 1307
1348 partitionFreeGeneric(genericAllocator.root(), ptr); 1308 partitionFreeGeneric(genericAllocator.root(), ptr);
1349 1309
1350 TestShutdown(); 1310 TestShutdown();
1351 } 1311 }
1352 1312
1353 // Check that a bad free() is caught where the free() refers to an unused 1313 // Check that a bad free() is caught where the free() refers to an unused
1354 // partition page of a large allocation. 1314 // partition page of a large allocation.
1355 TEST(PartitionAllocDeathTest, FreeWrongPartitionPage) 1315 TEST(PartitionAllocDeathTest, FreeWrongPartitionPage) {
1356 { 1316 TestSetup();
1357 TestSetup(); 1317
1358 1318 // This large size will result in a direct mapped allocation with guard
1359 // This large size will result in a direct mapped allocation with guard 1319 // pages at either end.
1360 // pages at either end. 1320 void* ptr = partitionAllocGeneric(genericAllocator.root(), kPartitionPageSize * 2);
1361 void* ptr = partitionAllocGeneric(genericAllocator.root(), kPartitionPageSiz e * 2); 1321 EXPECT_TRUE(ptr);
1362 EXPECT_TRUE(ptr); 1322 char* badPtr = reinterpret_cast<char*>(ptr) + kPartitionPageSize;
1363 char* badPtr = reinterpret_cast<char*>(ptr) + kPartitionPageSize; 1323
1364 1324 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), badPtr), "");
1365 EXPECT_DEATH(partitionFreeGeneric(genericAllocator.root(), badPtr), ""); 1325
1366 1326 partitionFreeGeneric(genericAllocator.root(), ptr);
1367 partitionFreeGeneric(genericAllocator.root(), ptr); 1327
1368 1328 TestShutdown();
1369 TestShutdown(); 1329 }
1370 } 1330
1371 1331 #endif // !OS(ANDROID)
1372 #endif // !OS(ANDROID)
1373 1332
1374 // Tests that partitionDumpStatsGeneric and partitionDumpStats runs without 1333 // Tests that partitionDumpStatsGeneric and partitionDumpStats runs without
1375 // crashing and returns non zero values when memory is allocated. 1334 // crashing and returns non zero values when memory is allocated.
1376 TEST(PartitionAllocTest, DumpMemoryStats) 1335 TEST(PartitionAllocTest, DumpMemoryStats) {
1377 { 1336 TestSetup();
1378 TestSetup(); 1337 {
1379 { 1338 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize);
1380 void* ptr = partitionAlloc(allocator.root(), kTestAllocSize); 1339 MockPartitionStatsDumper mockStatsDumper;
1381 MockPartitionStatsDumper mockStatsDumper; 1340 partitionDumpStats(allocator.root(), "mock_allocator", false /* detailed dum p */, &mockStatsDumper);
1382 partitionDumpStats(allocator.root(), "mock_allocator", false /* detailed dump */, &mockStatsDumper); 1341 EXPECT_TRUE(mockStatsDumper.IsMemoryAllocationRecorded());
1383 EXPECT_TRUE(mockStatsDumper.IsMemoryAllocationRecorded()); 1342
1384 1343 partitionFree(ptr);
1385 partitionFree(ptr); 1344 }
1386 } 1345
1387 1346 // This series of tests checks the active -> empty -> decommitted states.
1388 // This series of tests checks the active -> empty -> decommitted states. 1347 {
1389 { 1348 void* genericPtr = partitionAllocGeneric(genericAllocator.root(), 2048 - kEx traAllocSize);
1390 void* genericPtr = partitionAllocGeneric(genericAllocator.root(), 2048 - kExtraAllocSize); 1349 {
1391 { 1350 MockPartitionStatsDumper mockStatsDumperGeneric;
1392 MockPartitionStatsDumper mockStatsDumperGeneric; 1351 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1393 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1352 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1394 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1353
1395 1354 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(2048);
1396 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(2048); 1355 EXPECT_TRUE(stats);
1397 EXPECT_TRUE(stats); 1356 EXPECT_TRUE(stats->isValid);
1398 EXPECT_TRUE(stats->isValid); 1357 EXPECT_EQ(2048u, stats->bucketSlotSize);
1399 EXPECT_EQ(2048u, stats->bucketSlotSize); 1358 EXPECT_EQ(2048u, stats->activeBytes);
1400 EXPECT_EQ(2048u, stats->activeBytes); 1359 EXPECT_EQ(kSystemPageSize, stats->residentBytes);
1401 EXPECT_EQ(kSystemPageSize, stats->residentBytes); 1360 EXPECT_EQ(0u, stats->decommittableBytes);
1402 EXPECT_EQ(0u, stats->decommittableBytes); 1361 EXPECT_EQ(0u, stats->discardableBytes);
1403 EXPECT_EQ(0u, stats->discardableBytes); 1362 EXPECT_EQ(0u, stats->numFullPages);
1404 EXPECT_EQ(0u, stats->numFullPages); 1363 EXPECT_EQ(1u, stats->numActivePages);
1405 EXPECT_EQ(1u, stats->numActivePages); 1364 EXPECT_EQ(0u, stats->numEmptyPages);
1406 EXPECT_EQ(0u, stats->numEmptyPages); 1365 EXPECT_EQ(0u, stats->numDecommittedPages);
1407 EXPECT_EQ(0u, stats->numDecommittedPages); 1366 }
1408 } 1367
1409 1368 partitionFreeGeneric(genericAllocator.root(), genericPtr);
1410 partitionFreeGeneric(genericAllocator.root(), genericPtr); 1369
1411 1370 {
1412 { 1371 MockPartitionStatsDumper mockStatsDumperGeneric;
1413 MockPartitionStatsDumper mockStatsDumperGeneric; 1372 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1414 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1373 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1415 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1374
1416 1375 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(2048);
1417 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(2048); 1376 EXPECT_TRUE(stats);
1418 EXPECT_TRUE(stats); 1377 EXPECT_TRUE(stats->isValid);
1419 EXPECT_TRUE(stats->isValid); 1378 EXPECT_EQ(2048u, stats->bucketSlotSize);
1420 EXPECT_EQ(2048u, stats->bucketSlotSize); 1379 EXPECT_EQ(0u, stats->activeBytes);
1421 EXPECT_EQ(0u, stats->activeBytes); 1380 EXPECT_EQ(kSystemPageSize, stats->residentBytes);
1422 EXPECT_EQ(kSystemPageSize, stats->residentBytes); 1381 EXPECT_EQ(kSystemPageSize, stats->decommittableBytes);
1423 EXPECT_EQ(kSystemPageSize, stats->decommittableBytes); 1382 EXPECT_EQ(0u, stats->discardableBytes);
1424 EXPECT_EQ(0u, stats->discardableBytes); 1383 EXPECT_EQ(0u, stats->numFullPages);
1425 EXPECT_EQ(0u, stats->numFullPages); 1384 EXPECT_EQ(0u, stats->numActivePages);
1426 EXPECT_EQ(0u, stats->numActivePages); 1385 EXPECT_EQ(1u, stats->numEmptyPages);
1427 EXPECT_EQ(1u, stats->numEmptyPages); 1386 EXPECT_EQ(0u, stats->numDecommittedPages);
1428 EXPECT_EQ(0u, stats->numDecommittedPages); 1387 }
1429 } 1388
1430 1389 CycleGenericFreeCache(kTestAllocSize);
1431 CycleGenericFreeCache(kTestAllocSize); 1390
1432 1391 {
1433 { 1392 MockPartitionStatsDumper mockStatsDumperGeneric;
1434 MockPartitionStatsDumper mockStatsDumperGeneric; 1393 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1435 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1394 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1436 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1395
1437 1396 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(2048);
1438 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(2048); 1397 EXPECT_TRUE(stats);
1439 EXPECT_TRUE(stats); 1398 EXPECT_TRUE(stats->isValid);
1440 EXPECT_TRUE(stats->isValid); 1399 EXPECT_EQ(2048u, stats->bucketSlotSize);
1441 EXPECT_EQ(2048u, stats->bucketSlotSize); 1400 EXPECT_EQ(0u, stats->activeBytes);
1442 EXPECT_EQ(0u, stats->activeBytes); 1401 EXPECT_EQ(0u, stats->residentBytes);
1443 EXPECT_EQ(0u, stats->residentBytes); 1402 EXPECT_EQ(0u, stats->decommittableBytes);
1444 EXPECT_EQ(0u, stats->decommittableBytes); 1403 EXPECT_EQ(0u, stats->discardableBytes);
1445 EXPECT_EQ(0u, stats->discardableBytes); 1404 EXPECT_EQ(0u, stats->numFullPages);
1446 EXPECT_EQ(0u, stats->numFullPages); 1405 EXPECT_EQ(0u, stats->numActivePages);
1447 EXPECT_EQ(0u, stats->numActivePages); 1406 EXPECT_EQ(0u, stats->numEmptyPages);
1448 EXPECT_EQ(0u, stats->numEmptyPages); 1407 EXPECT_EQ(1u, stats->numDecommittedPages);
1449 EXPECT_EQ(1u, stats->numDecommittedPages); 1408 }
1450 } 1409 }
1451 } 1410
1452 1411 // This test checks for correct empty page list accounting.
1453 // This test checks for correct empty page list accounting. 1412 {
1454 { 1413 size_t size = kPartitionPageSize - kExtraAllocSize;
1455 size_t size = kPartitionPageSize - kExtraAllocSize; 1414 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), size);
1456 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), size); 1415 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
1457 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); 1416 partitionFreeGeneric(genericAllocator.root(), ptr1);
1458 partitionFreeGeneric(genericAllocator.root(), ptr1); 1417 partitionFreeGeneric(genericAllocator.root(), ptr2);
1459 partitionFreeGeneric(genericAllocator.root(), ptr2); 1418
1460 1419 CycleGenericFreeCache(kTestAllocSize);
1461 CycleGenericFreeCache(kTestAllocSize); 1420
1462 1421 ptr1 = partitionAllocGeneric(genericAllocator.root(), size);
1463 ptr1 = partitionAllocGeneric(genericAllocator.root(), size); 1422
1464 1423 {
1465 { 1424 MockPartitionStatsDumper mockStatsDumperGeneric;
1466 MockPartitionStatsDumper mockStatsDumperGeneric; 1425 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1467 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1426 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1468 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1427
1469 1428 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(kPartitionPageSize);
1470 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(kPartitionPageSize); 1429 EXPECT_TRUE(stats);
1471 EXPECT_TRUE(stats); 1430 EXPECT_TRUE(stats->isValid);
1472 EXPECT_TRUE(stats->isValid); 1431 EXPECT_EQ(kPartitionPageSize, stats->bucketSlotSize);
1473 EXPECT_EQ(kPartitionPageSize, stats->bucketSlotSize); 1432 EXPECT_EQ(kPartitionPageSize, stats->activeBytes);
1474 EXPECT_EQ(kPartitionPageSize, stats->activeBytes); 1433 EXPECT_EQ(kPartitionPageSize, stats->residentBytes);
1475 EXPECT_EQ(kPartitionPageSize, stats->residentBytes); 1434 EXPECT_EQ(0u, stats->decommittableBytes);
1476 EXPECT_EQ(0u, stats->decommittableBytes); 1435 EXPECT_EQ(0u, stats->discardableBytes);
1477 EXPECT_EQ(0u, stats->discardableBytes); 1436 EXPECT_EQ(1u, stats->numFullPages);
1478 EXPECT_EQ(1u, stats->numFullPages); 1437 EXPECT_EQ(0u, stats->numActivePages);
1479 EXPECT_EQ(0u, stats->numActivePages); 1438 EXPECT_EQ(0u, stats->numEmptyPages);
1480 EXPECT_EQ(0u, stats->numEmptyPages); 1439 EXPECT_EQ(1u, stats->numDecommittedPages);
1481 EXPECT_EQ(1u, stats->numDecommittedPages); 1440 }
1482 } 1441 partitionFreeGeneric(genericAllocator.root(), ptr1);
1483 partitionFreeGeneric(genericAllocator.root(), ptr1); 1442 }
1484 } 1443
1485 1444 // This test checks for correct direct mapped accounting.
1486 // This test checks for correct direct mapped accounting. 1445 {
1487 { 1446 size_t sizeSmaller = kGenericMaxBucketed + 1;
1488 size_t sizeSmaller = kGenericMaxBucketed + 1; 1447 size_t sizeBigger = (kGenericMaxBucketed * 2) + 1;
1489 size_t sizeBigger = (kGenericMaxBucketed * 2) + 1; 1448 size_t realSizeSmaller = (sizeSmaller + kSystemPageOffsetMask) & kSystemPage BaseMask;
1490 size_t realSizeSmaller = (sizeSmaller + kSystemPageOffsetMask) & kSystem PageBaseMask; 1449 size_t realSizeBigger = (sizeBigger + kSystemPageOffsetMask) & kSystemPageBa seMask;
1491 size_t realSizeBigger = (sizeBigger + kSystemPageOffsetMask) & kSystemPa geBaseMask; 1450 void* ptr = partitionAllocGeneric(genericAllocator.root(), sizeSmaller);
1492 void* ptr = partitionAllocGeneric(genericAllocator.root(), sizeSmaller); 1451 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), sizeBigger);
1493 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), sizeBigger); 1452
1494 1453 {
1495 { 1454 MockPartitionStatsDumper mockStatsDumperGeneric;
1496 MockPartitionStatsDumper mockStatsDumperGeneric; 1455 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1497 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1456 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1498 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1457
1499 1458 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(realSizeSmaller);
1500 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(realSizeSmaller); 1459 EXPECT_TRUE(stats);
1501 EXPECT_TRUE(stats); 1460 EXPECT_TRUE(stats->isValid);
1502 EXPECT_TRUE(stats->isValid); 1461 EXPECT_TRUE(stats->isDirectMap);
1503 EXPECT_TRUE(stats->isDirectMap); 1462 EXPECT_EQ(realSizeSmaller, stats->bucketSlotSize);
1504 EXPECT_EQ(realSizeSmaller, stats->bucketSlotSize); 1463 EXPECT_EQ(realSizeSmaller, stats->activeBytes);
1505 EXPECT_EQ(realSizeSmaller, stats->activeBytes); 1464 EXPECT_EQ(realSizeSmaller, stats->residentBytes);
1506 EXPECT_EQ(realSizeSmaller, stats->residentBytes); 1465 EXPECT_EQ(0u, stats->decommittableBytes);
1507 EXPECT_EQ(0u, stats->decommittableBytes); 1466 EXPECT_EQ(0u, stats->discardableBytes);
1508 EXPECT_EQ(0u, stats->discardableBytes); 1467 EXPECT_EQ(1u, stats->numFullPages);
1509 EXPECT_EQ(1u, stats->numFullPages); 1468 EXPECT_EQ(0u, stats->numActivePages);
1510 EXPECT_EQ(0u, stats->numActivePages); 1469 EXPECT_EQ(0u, stats->numEmptyPages);
1511 EXPECT_EQ(0u, stats->numEmptyPages); 1470 EXPECT_EQ(0u, stats->numDecommittedPages);
1512 EXPECT_EQ(0u, stats->numDecommittedPages); 1471
1513 1472 stats = mockStatsDumperGeneric.GetBucketStats(realSizeBigger);
1514 stats = mockStatsDumperGeneric.GetBucketStats(realSizeBigger); 1473 EXPECT_TRUE(stats);
1515 EXPECT_TRUE(stats); 1474 EXPECT_TRUE(stats->isValid);
1516 EXPECT_TRUE(stats->isValid); 1475 EXPECT_TRUE(stats->isDirectMap);
1517 EXPECT_TRUE(stats->isDirectMap); 1476 EXPECT_EQ(realSizeBigger, stats->bucketSlotSize);
1518 EXPECT_EQ(realSizeBigger, stats->bucketSlotSize); 1477 EXPECT_EQ(realSizeBigger, stats->activeBytes);
1519 EXPECT_EQ(realSizeBigger, stats->activeBytes); 1478 EXPECT_EQ(realSizeBigger, stats->residentBytes);
1520 EXPECT_EQ(realSizeBigger, stats->residentBytes); 1479 EXPECT_EQ(0u, stats->decommittableBytes);
1521 EXPECT_EQ(0u, stats->decommittableBytes); 1480 EXPECT_EQ(0u, stats->discardableBytes);
1522 EXPECT_EQ(0u, stats->discardableBytes); 1481 EXPECT_EQ(1u, stats->numFullPages);
1523 EXPECT_EQ(1u, stats->numFullPages); 1482 EXPECT_EQ(0u, stats->numActivePages);
1524 EXPECT_EQ(0u, stats->numActivePages); 1483 EXPECT_EQ(0u, stats->numEmptyPages);
1525 EXPECT_EQ(0u, stats->numEmptyPages); 1484 EXPECT_EQ(0u, stats->numDecommittedPages);
1526 EXPECT_EQ(0u, stats->numDecommittedPages); 1485 }
1527 } 1486
1528 1487 partitionFreeGeneric(genericAllocator.root(), ptr2);
1529 partitionFreeGeneric(genericAllocator.root(), ptr2); 1488 partitionFreeGeneric(genericAllocator.root(), ptr);
1530 partitionFreeGeneric(genericAllocator.root(), ptr); 1489
1531 1490 // Whilst we're here, allocate again and free with different ordering
1532 // Whilst we're here, allocate again and free with different ordering 1491 // to give a workout to our linked list code.
1533 // to give a workout to our linked list code. 1492 ptr = partitionAllocGeneric(genericAllocator.root(), sizeSmaller);
1534 ptr = partitionAllocGeneric(genericAllocator.root(), sizeSmaller); 1493 ptr2 = partitionAllocGeneric(genericAllocator.root(), sizeBigger);
1535 ptr2 = partitionAllocGeneric(genericAllocator.root(), sizeBigger); 1494 partitionFreeGeneric(genericAllocator.root(), ptr);
1536 partitionFreeGeneric(genericAllocator.root(), ptr); 1495 partitionFreeGeneric(genericAllocator.root(), ptr2);
1537 partitionFreeGeneric(genericAllocator.root(), ptr2); 1496 }
1538 } 1497
1539 1498 // This test checks large-but-not-quite-direct allocations.
1540 // This test checks large-but-not-quite-direct allocations. 1499 {
1541 { 1500 void* ptr = partitionAllocGeneric(genericAllocator.root(), 65536 + 1);
1542 void* ptr = partitionAllocGeneric(genericAllocator.root(), 65536 + 1); 1501
1543 1502 {
1544 { 1503 MockPartitionStatsDumper mockStatsDumperGeneric;
1545 MockPartitionStatsDumper mockStatsDumperGeneric; 1504 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1546 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1505 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1547 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1506
1548 1507 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder);
1549 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder); 1508 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(slotSize);
1550 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(slotSize); 1509 EXPECT_TRUE(stats);
1551 EXPECT_TRUE(stats); 1510 EXPECT_TRUE(stats->isValid);
1552 EXPECT_TRUE(stats->isValid); 1511 EXPECT_FALSE(stats->isDirectMap);
1553 EXPECT_FALSE(stats->isDirectMap); 1512 EXPECT_EQ(slotSize, stats->bucketSlotSize);
1554 EXPECT_EQ(slotSize, stats->bucketSlotSize); 1513 EXPECT_EQ(65536u + 1 + kExtraAllocSize, stats->activeBytes);
1555 EXPECT_EQ(65536u + 1 + kExtraAllocSize, stats->activeBytes); 1514 EXPECT_EQ(slotSize, stats->residentBytes);
1556 EXPECT_EQ(slotSize, stats->residentBytes); 1515 EXPECT_EQ(0u, stats->decommittableBytes);
1557 EXPECT_EQ(0u, stats->decommittableBytes); 1516 EXPECT_EQ(kSystemPageSize, stats->discardableBytes);
1558 EXPECT_EQ(kSystemPageSize, stats->discardableBytes); 1517 EXPECT_EQ(1u, stats->numFullPages);
1559 EXPECT_EQ(1u, stats->numFullPages); 1518 EXPECT_EQ(0u, stats->numActivePages);
1560 EXPECT_EQ(0u, stats->numActivePages); 1519 EXPECT_EQ(0u, stats->numEmptyPages);
1561 EXPECT_EQ(0u, stats->numEmptyPages); 1520 EXPECT_EQ(0u, stats->numDecommittedPages);
1562 EXPECT_EQ(0u, stats->numDecommittedPages); 1521 }
1563 } 1522
1564 1523 partitionFreeGeneric(genericAllocator.root(), ptr);
1565 partitionFreeGeneric(genericAllocator.root(), ptr); 1524
1566 1525 {
1567 { 1526 MockPartitionStatsDumper mockStatsDumperGeneric;
1568 MockPartitionStatsDumper mockStatsDumperGeneric; 1527 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1569 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1528 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1570 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1529
1571 1530 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder);
1572 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder); 1531 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(slotSize);
1573 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(slotSize); 1532 EXPECT_TRUE(stats);
1574 EXPECT_TRUE(stats); 1533 EXPECT_TRUE(stats->isValid);
1575 EXPECT_TRUE(stats->isValid); 1534 EXPECT_FALSE(stats->isDirectMap);
1576 EXPECT_FALSE(stats->isDirectMap); 1535 EXPECT_EQ(slotSize, stats->bucketSlotSize);
1577 EXPECT_EQ(slotSize, stats->bucketSlotSize); 1536 EXPECT_EQ(0u, stats->activeBytes);
1578 EXPECT_EQ(0u, stats->activeBytes); 1537 EXPECT_EQ(slotSize, stats->residentBytes);
1579 EXPECT_EQ(slotSize, stats->residentBytes); 1538 EXPECT_EQ(slotSize, stats->decommittableBytes);
1580 EXPECT_EQ(slotSize, stats->decommittableBytes); 1539 EXPECT_EQ(0u, stats->numFullPages);
1581 EXPECT_EQ(0u, stats->numFullPages); 1540 EXPECT_EQ(0u, stats->numActivePages);
1582 EXPECT_EQ(0u, stats->numActivePages); 1541 EXPECT_EQ(1u, stats->numEmptyPages);
1583 EXPECT_EQ(1u, stats->numEmptyPages); 1542 EXPECT_EQ(0u, stats->numDecommittedPages);
1584 EXPECT_EQ(0u, stats->numDecommittedPages); 1543 }
1585 } 1544
1586 1545 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), 65536 + kSystemP ageSize + 1);
1587 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), 65536 + kSys temPageSize + 1); 1546 EXPECT_EQ(ptr, ptr2);
1588 EXPECT_EQ(ptr, ptr2); 1547
1589 1548 {
1590 { 1549 MockPartitionStatsDumper mockStatsDumperGeneric;
1591 MockPartitionStatsDumper mockStatsDumperGeneric; 1550 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1592 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1551 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1593 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1552
1594 1553 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder);
1595 size_t slotSize = 65536 + (65536 / kGenericNumBucketsPerOrder); 1554 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(slotSize);
1596 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(slotSize); 1555 EXPECT_TRUE(stats);
1597 EXPECT_TRUE(stats); 1556 EXPECT_TRUE(stats->isValid);
1598 EXPECT_TRUE(stats->isValid); 1557 EXPECT_FALSE(stats->isDirectMap);
1599 EXPECT_FALSE(stats->isDirectMap); 1558 EXPECT_EQ(slotSize, stats->bucketSlotSize);
1600 EXPECT_EQ(slotSize, stats->bucketSlotSize); 1559 EXPECT_EQ(65536u + kSystemPageSize + 1 + kExtraAllocSize, stats->activeByt es);
1601 EXPECT_EQ(65536u + kSystemPageSize + 1 + kExtraAllocSize, stats->act iveBytes); 1560 EXPECT_EQ(slotSize, stats->residentBytes);
1602 EXPECT_EQ(slotSize, stats->residentBytes); 1561 EXPECT_EQ(0u, stats->decommittableBytes);
1603 EXPECT_EQ(0u, stats->decommittableBytes); 1562 EXPECT_EQ(0u, stats->discardableBytes);
1604 EXPECT_EQ(0u, stats->discardableBytes); 1563 EXPECT_EQ(1u, stats->numFullPages);
1605 EXPECT_EQ(1u, stats->numFullPages); 1564 EXPECT_EQ(0u, stats->numActivePages);
1606 EXPECT_EQ(0u, stats->numActivePages); 1565 EXPECT_EQ(0u, stats->numEmptyPages);
1607 EXPECT_EQ(0u, stats->numEmptyPages); 1566 EXPECT_EQ(0u, stats->numDecommittedPages);
1608 EXPECT_EQ(0u, stats->numDecommittedPages); 1567 }
1609 } 1568
1610 1569 partitionFreeGeneric(genericAllocator.root(), ptr2);
1611 partitionFreeGeneric(genericAllocator.root(), ptr2); 1570 }
1612 } 1571
1613 1572 TestShutdown();
1614 TestShutdown();
1615 } 1573 }
1616 1574
1617 // Tests the API to purge freeable memory. 1575 // Tests the API to purge freeable memory.
1618 TEST(PartitionAllocTest, Purge) 1576 TEST(PartitionAllocTest, Purge) {
1619 { 1577 TestSetup();
1620 TestSetup(); 1578
1621 1579 char* ptr = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator.roo t(), 2048 - kExtraAllocSize));
1622 char* ptr = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator.r oot(), 2048 - kExtraAllocSize)); 1580 partitionFreeGeneric(genericAllocator.root(), ptr);
1623 partitionFreeGeneric(genericAllocator.root(), ptr); 1581 {
1624 { 1582 MockPartitionStatsDumper mockStatsDumperGeneric;
1625 MockPartitionStatsDumper mockStatsDumperGeneric; 1583 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator", false /* detailed dump */, &mockStatsDumperGeneric);
1626 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocat or", false /* detailed dump */, &mockStatsDumperGeneric); 1584 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1627 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1585
1628 1586 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucketSt ats(2048);
1629 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBuck etStats(2048); 1587 EXPECT_TRUE(stats);
1630 EXPECT_TRUE(stats); 1588 EXPECT_TRUE(stats->isValid);
1631 EXPECT_TRUE(stats->isValid); 1589 EXPECT_EQ(kSystemPageSize, stats->decommittableBytes);
1632 EXPECT_EQ(kSystemPageSize, stats->decommittableBytes); 1590 EXPECT_EQ(kSystemPageSize, stats->residentBytes);
1633 EXPECT_EQ(kSystemPageSize, stats->residentBytes); 1591 }
1634 } 1592 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitEmp tyPages);
1635 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitE mptyPages); 1593 {
1636 { 1594 MockPartitionStatsDumper mockStatsDumperGeneric;
1637 MockPartitionStatsDumper mockStatsDumperGeneric; 1595 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator", false /* detailed dump */, &mockStatsDumperGeneric);
1638 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocat or", false /* detailed dump */, &mockStatsDumperGeneric); 1596 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1639 EXPECT_FALSE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1597
1640 1598 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucketSt ats(2048);
1641 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBuck etStats(2048); 1599 EXPECT_TRUE(stats);
1642 EXPECT_TRUE(stats); 1600 EXPECT_TRUE(stats->isValid);
1643 EXPECT_TRUE(stats->isValid); 1601 EXPECT_EQ(0u, stats->decommittableBytes);
1644 EXPECT_EQ(0u, stats->decommittableBytes); 1602 EXPECT_EQ(0u, stats->residentBytes);
1645 EXPECT_EQ(0u, stats->residentBytes); 1603 }
1646 } 1604 // Calling purge again here is a good way of testing we didn't mess up the
1647 // Calling purge again here is a good way of testing we didn't mess up the 1605 // state of the free cache ring.
1648 // state of the free cache ring. 1606 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitEmp tyPages);
1649 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitE mptyPages); 1607
1650 1608 char* bigPtr = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), 256 * 1024));
1651 char* bigPtr = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocato r.root(), 256 * 1024)); 1609 partitionFreeGeneric(genericAllocator.root(), bigPtr);
1652 partitionFreeGeneric(genericAllocator.root(), bigPtr); 1610 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitEmp tyPages);
1653 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitE mptyPages); 1611
1654 1612 CheckPageInCore(ptr - kPointerOffset, false);
1655 CheckPageInCore(ptr - kPointerOffset, false); 1613 CheckPageInCore(bigPtr - kPointerOffset, false);
1656 CheckPageInCore(bigPtr - kPointerOffset, false); 1614
1657 1615 TestShutdown();
1658 TestShutdown();
1659 } 1616 }
1660 1617
1661 // Tests that we prefer to allocate into a non-empty partition page over an 1618 // Tests that we prefer to allocate into a non-empty partition page over an
1662 // empty one. This is an important aspect of minimizing memory usage for some 1619 // empty one. This is an important aspect of minimizing memory usage for some
1663 // allocation sizes, particularly larger ones. 1620 // allocation sizes, particularly larger ones.
1664 TEST(PartitionAllocTest, PreferActiveOverEmpty) 1621 TEST(PartitionAllocTest, PreferActiveOverEmpty) {
1665 { 1622 TestSetup();
1666 TestSetup(); 1623
1667 1624 size_t size = (kSystemPageSize * 2) - kExtraAllocSize;
1668 size_t size = (kSystemPageSize * 2) - kExtraAllocSize; 1625 // Allocate 3 full slot spans worth of 8192-byte allocations.
1669 // Allocate 3 full slot spans worth of 8192-byte allocations. 1626 // Each slot span for this size is 16384 bytes, or 1 partition page and 2
1670 // Each slot span for this size is 16384 bytes, or 1 partition page and 2 1627 // slots.
1671 // slots. 1628 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), size);
1672 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), size); 1629 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
1673 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size); 1630 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size);
1674 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), size); 1631 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size);
1675 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), size); 1632 void* ptr5 = partitionAllocGeneric(genericAllocator.root(), size);
1676 void* ptr5 = partitionAllocGeneric(genericAllocator.root(), size); 1633 void* ptr6 = partitionAllocGeneric(genericAllocator.root(), size);
1677 void* ptr6 = partitionAllocGeneric(genericAllocator.root(), size); 1634
1678 1635 PartitionPage* page1 = partitionPointerToPage(partitionCookieFreePointerAdjust (ptr1));
1679 PartitionPage* page1 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr1)); 1636 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdjust (ptr3));
1680 PartitionPage* page2 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr3)); 1637 PartitionPage* page3 = partitionPointerToPage(partitionCookieFreePointerAdjust (ptr6));
1681 PartitionPage* page3 = partitionPointerToPage(partitionCookieFreePointerAdju st(ptr6)); 1638 EXPECT_NE(page1, page2);
1682 EXPECT_NE(page1, page2); 1639 EXPECT_NE(page2, page3);
1683 EXPECT_NE(page2, page3); 1640 PartitionBucket* bucket = page1->bucket;
1684 PartitionBucket* bucket = page1->bucket; 1641 EXPECT_EQ(page3, bucket->activePagesHead);
1685 EXPECT_EQ(page3, bucket->activePagesHead); 1642
1686 1643 // Free up the 2nd slot in each slot span.
1687 // Free up the 2nd slot in each slot span. 1644 // This leaves the active list containing 3 pages, each with 1 used and 1
1688 // This leaves the active list containing 3 pages, each with 1 used and 1 1645 // free slot. The active page will be the one containing ptr1.
1689 // free slot. The active page will be the one containing ptr1. 1646 partitionFreeGeneric(genericAllocator.root(), ptr6);
1690 partitionFreeGeneric(genericAllocator.root(), ptr6); 1647 partitionFreeGeneric(genericAllocator.root(), ptr4);
1648 partitionFreeGeneric(genericAllocator.root(), ptr2);
1649 EXPECT_EQ(page1, bucket->activePagesHead);
1650
1651 // Empty the middle page in the active list.
1652 partitionFreeGeneric(genericAllocator.root(), ptr3);
1653 EXPECT_EQ(page1, bucket->activePagesHead);
1654
1655 // Empty the the first page in the active list -- also the current page.
1656 partitionFreeGeneric(genericAllocator.root(), ptr1);
1657
1658 // A good choice here is to re-fill the third page since the first two are
1659 // empty. We used to fail that.
1660 void* ptr7 = partitionAllocGeneric(genericAllocator.root(), size);
1661 EXPECT_EQ(ptr6, ptr7);
1662 EXPECT_EQ(page3, bucket->activePagesHead);
1663
1664 partitionFreeGeneric(genericAllocator.root(), ptr5);
1665 partitionFreeGeneric(genericAllocator.root(), ptr7);
1666
1667 TestShutdown();
1668 }
1669
1670 // Tests the API to purge discardable memory.
1671 TEST(PartitionAllocTest, PurgeDiscardable) {
1672 TestSetup();
1673
1674 // Free the second of two 4096 byte allocations and then purge.
1675 {
1676 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1677 char* ptr2 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), kSystemPageSize - kExtraAllocSize));
1678 partitionFreeGeneric(genericAllocator.root(), ptr2);
1679 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr1));
1680 EXPECT_EQ(2u, page->numUnprovisionedSlots);
1681 {
1682 MockPartitionStatsDumper mockStatsDumperGeneric;
1683 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1684 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1685
1686 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(kSystemPageSize);
1687 EXPECT_TRUE(stats);
1688 EXPECT_TRUE(stats->isValid);
1689 EXPECT_EQ(0u, stats->decommittableBytes);
1690 EXPECT_EQ(kSystemPageSize, stats->discardableBytes);
1691 EXPECT_EQ(kSystemPageSize, stats->activeBytes);
1692 EXPECT_EQ(2 * kSystemPageSize, stats->residentBytes);
1693 }
1694 CheckPageInCore(ptr2 - kPointerOffset, true);
1695 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDiscardUn usedSystemPages);
1696 CheckPageInCore(ptr2 - kPointerOffset, false);
1697 EXPECT_EQ(3u, page->numUnprovisionedSlots);
1698
1699 partitionFreeGeneric(genericAllocator.root(), ptr1);
1700 }
1701 // Free the first of two 4096 byte allocations and then purge.
1702 {
1703 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), kSystemPageSize - kExtraAllocSize));
1704 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1705 partitionFreeGeneric(genericAllocator.root(), ptr1);
1706 {
1707 MockPartitionStatsDumper mockStatsDumperGeneric;
1708 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1709 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1710
1711 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(kSystemPageSize);
1712 EXPECT_TRUE(stats);
1713 EXPECT_TRUE(stats->isValid);
1714 EXPECT_EQ(0u, stats->decommittableBytes);
1715 EXPECT_EQ(kSystemPageSize, stats->discardableBytes);
1716 EXPECT_EQ(kSystemPageSize, stats->activeBytes);
1717 EXPECT_EQ(2 * kSystemPageSize, stats->residentBytes);
1718 }
1719 CheckPageInCore(ptr1 - kPointerOffset, true);
1720 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDiscardUn usedSystemPages);
1721 CheckPageInCore(ptr1 - kPointerOffset, false);
1722
1723 partitionFreeGeneric(genericAllocator.root(), ptr2);
1724 }
1725 {
1726 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), 9216 - kExtraAllocSize));
1727 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), 9216 - kExtraAll ocSize);
1728 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), 9216 - kExtraAll ocSize);
1729 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), 9216 - kExtraAll ocSize);
1730 memset(ptr1, 'A', 9216 - kExtraAllocSize);
1731 memset(ptr2, 'A', 9216 - kExtraAllocSize);
1732 partitionFreeGeneric(genericAllocator.root(), ptr2);
1733 partitionFreeGeneric(genericAllocator.root(), ptr1);
1734 {
1735 MockPartitionStatsDumper mockStatsDumperGeneric;
1736 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1737 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1738
1739 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(9216);
1740 EXPECT_TRUE(stats);
1741 EXPECT_TRUE(stats->isValid);
1742 EXPECT_EQ(0u, stats->decommittableBytes);
1743 EXPECT_EQ(2 * kSystemPageSize, stats->discardableBytes);
1744 EXPECT_EQ(9216u * 2, stats->activeBytes);
1745 EXPECT_EQ(9 * kSystemPageSize, stats->residentBytes);
1746 }
1747 CheckPageInCore(ptr1 - kPointerOffset, true);
1748 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1749 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1750 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), true);
1751 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 4), true);
1752 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDiscardUn usedSystemPages);
1753 CheckPageInCore(ptr1 - kPointerOffset, true);
1754 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, false);
1755 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1756 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), false);
1757 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 4), true);
1758
1759 partitionFreeGeneric(genericAllocator.root(), ptr3);
1691 partitionFreeGeneric(genericAllocator.root(), ptr4); 1760 partitionFreeGeneric(genericAllocator.root(), ptr4);
1692 partitionFreeGeneric(genericAllocator.root(), ptr2); 1761 }
1693 EXPECT_EQ(page1, bucket->activePagesHead); 1762 {
1694 1763 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), (64 * kSystemPageSize) - kExtraAllocSize));
1695 // Empty the middle page in the active list. 1764 memset(ptr1, 'A', (64 * kSystemPageSize) - kExtraAllocSize);
1765 partitionFreeGeneric(genericAllocator.root(), ptr1);
1766 ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator.root() , (61 * kSystemPageSize) - kExtraAllocSize));
1767 {
1768 MockPartitionStatsDumper mockStatsDumperGeneric;
1769 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1770 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1771
1772 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(64 * kSystemPageSize);
1773 EXPECT_TRUE(stats);
1774 EXPECT_TRUE(stats->isValid);
1775 EXPECT_EQ(0u, stats->decommittableBytes);
1776 EXPECT_EQ(3 * kSystemPageSize, stats->discardableBytes);
1777 EXPECT_EQ(61 * kSystemPageSize, stats->activeBytes);
1778 EXPECT_EQ(64 * kSystemPageSize, stats->residentBytes);
1779 }
1780 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 60), true);
1781 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 61), true);
1782 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 62), true);
1783 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 63), true);
1784 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDiscardUn usedSystemPages);
1785 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 60), true);
1786 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 61), false);
1787 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 62), false);
1788 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 63), false);
1789
1790 partitionFreeGeneric(genericAllocator.root(), ptr1);
1791 }
1792 // This sub-test tests truncation of the provisioned slots in a trickier
1793 // case where the freelist is rewritten.
1794 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitEmp tyPages);
1795 {
1796 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), kSystemPageSize - kExtraAllocSize));
1797 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1798 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1799 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1800 ptr1[0] = 'A';
1801 ptr1[kSystemPageSize] = 'A';
1802 ptr1[kSystemPageSize * 2] = 'A';
1803 ptr1[kSystemPageSize * 3] = 'A';
1804 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr1));
1805 partitionFreeGeneric(genericAllocator.root(), ptr2);
1806 partitionFreeGeneric(genericAllocator.root(), ptr4);
1807 partitionFreeGeneric(genericAllocator.root(), ptr1);
1808 EXPECT_EQ(0u, page->numUnprovisionedSlots);
1809
1810 {
1811 MockPartitionStatsDumper mockStatsDumperGeneric;
1812 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1813 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1814
1815 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(kSystemPageSize);
1816 EXPECT_TRUE(stats);
1817 EXPECT_TRUE(stats->isValid);
1818 EXPECT_EQ(0u, stats->decommittableBytes);
1819 EXPECT_EQ(2 * kSystemPageSize, stats->discardableBytes);
1820 EXPECT_EQ(kSystemPageSize, stats->activeBytes);
1821 EXPECT_EQ(4 * kSystemPageSize, stats->residentBytes);
1822 }
1823 CheckPageInCore(ptr1 - kPointerOffset, true);
1824 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1825 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1826 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), true);
1827 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDiscardUn usedSystemPages);
1828 EXPECT_EQ(1u, page->numUnprovisionedSlots);
1829 CheckPageInCore(ptr1 - kPointerOffset, true);
1830 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, false);
1831 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1832 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), false);
1833
1834 // Let's check we didn't brick the freelist.
1835 void* ptr1b = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1836 EXPECT_EQ(ptr1, ptr1b);
1837 void* ptr2b = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1838 EXPECT_EQ(ptr2, ptr2b);
1839 EXPECT_FALSE(page->freelistHead);
1840
1841 partitionFreeGeneric(genericAllocator.root(), ptr1);
1842 partitionFreeGeneric(genericAllocator.root(), ptr2);
1696 partitionFreeGeneric(genericAllocator.root(), ptr3); 1843 partitionFreeGeneric(genericAllocator.root(), ptr3);
1697 EXPECT_EQ(page1, bucket->activePagesHead); 1844 }
1698 1845 // This sub-test is similar, but tests a double-truncation.
1699 // Empty the the first page in the active list -- also the current page. 1846 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitEmp tyPages);
1700 partitionFreeGeneric(genericAllocator.root(), ptr1); 1847 {
1701 1848 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator. root(), kSystemPageSize - kExtraAllocSize));
1702 // A good choice here is to re-fill the third page since the first two are 1849 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1703 // empty. We used to fail that. 1850 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1704 void* ptr7 = partitionAllocGeneric(genericAllocator.root(), size); 1851 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), kSystemPageSize - kExtraAllocSize);
1705 EXPECT_EQ(ptr6, ptr7); 1852 ptr1[0] = 'A';
1706 EXPECT_EQ(page3, bucket->activePagesHead); 1853 ptr1[kSystemPageSize] = 'A';
1707 1854 ptr1[kSystemPageSize * 2] = 'A';
1708 partitionFreeGeneric(genericAllocator.root(), ptr5); 1855 ptr1[kSystemPageSize * 3] = 'A';
1709 partitionFreeGeneric(genericAllocator.root(), ptr7); 1856 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerAdjus t(ptr1));
1710 1857 partitionFreeGeneric(genericAllocator.root(), ptr4);
1711 TestShutdown(); 1858 partitionFreeGeneric(genericAllocator.root(), ptr3);
1712 } 1859 EXPECT_EQ(0u, page->numUnprovisionedSlots);
1713 1860
1714 // Tests the API to purge discardable memory. 1861 {
1715 TEST(PartitionAllocTest, PurgeDiscardable) 1862 MockPartitionStatsDumper mockStatsDumperGeneric;
1716 { 1863 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_allocator ", false /* detailed dump */, &mockStatsDumperGeneric);
1717 TestSetup(); 1864 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1718 1865
1719 // Free the second of two 4096 byte allocations and then purge. 1866 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.GetBucket Stats(kSystemPageSize);
1720 { 1867 EXPECT_TRUE(stats);
1721 void* ptr1 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize); 1868 EXPECT_TRUE(stats->isValid);
1722 char* ptr2 = reinterpret_cast<char*>(partitionAllocGeneric(genericAlloca tor.root(), kSystemPageSize - kExtraAllocSize)); 1869 EXPECT_EQ(0u, stats->decommittableBytes);
1723 partitionFreeGeneric(genericAllocator.root(), ptr2); 1870 EXPECT_EQ(2 * kSystemPageSize, stats->discardableBytes);
1724 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerA djust(ptr1)); 1871 EXPECT_EQ(2 * kSystemPageSize, stats->activeBytes);
1725 EXPECT_EQ(2u, page->numUnprovisionedSlots); 1872 EXPECT_EQ(4 * kSystemPageSize, stats->residentBytes);
1726 { 1873 }
1727 MockPartitionStatsDumper mockStatsDumperGeneric; 1874 CheckPageInCore(ptr1 - kPointerOffset, true);
1728 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric); 1875 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1729 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded()); 1876 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1730 1877 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), true);
1731 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(kSystemPageSize); 1878 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDiscardUn usedSystemPages);
1732 EXPECT_TRUE(stats); 1879 EXPECT_EQ(2u, page->numUnprovisionedSlots);
1733 EXPECT_TRUE(stats->isValid); 1880 CheckPageInCore(ptr1 - kPointerOffset, true);
1734 EXPECT_EQ(0u, stats->decommittableBytes); 1881 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1735 EXPECT_EQ(kSystemPageSize, stats->discardableBytes); 1882 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), false);
1736 EXPECT_EQ(kSystemPageSize, stats->activeBytes); 1883 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), false);
1737 EXPECT_EQ(2 * kSystemPageSize, stats->residentBytes); 1884
1738 } 1885 EXPECT_FALSE(page->freelistHead);
1739 CheckPageInCore(ptr2 - kPointerOffset, true); 1886
1740 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDisca rdUnusedSystemPages); 1887 partitionFreeGeneric(genericAllocator.root(), ptr1);
1741 CheckPageInCore(ptr2 - kPointerOffset, false); 1888 partitionFreeGeneric(genericAllocator.root(), ptr2);
1742 EXPECT_EQ(3u, page->numUnprovisionedSlots); 1889 }
1743 1890
1744 partitionFreeGeneric(genericAllocator.root(), ptr1); 1891 TestShutdown();
1745 }
1746 // Free the first of two 4096 byte allocations and then purge.
1747 {
1748 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAlloca tor.root(), kSystemPageSize - kExtraAllocSize));
1749 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1750 partitionFreeGeneric(genericAllocator.root(), ptr1);
1751 {
1752 MockPartitionStatsDumper mockStatsDumperGeneric;
1753 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric);
1754 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1755
1756 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(kSystemPageSize);
1757 EXPECT_TRUE(stats);
1758 EXPECT_TRUE(stats->isValid);
1759 EXPECT_EQ(0u, stats->decommittableBytes);
1760 EXPECT_EQ(kSystemPageSize, stats->discardableBytes);
1761 EXPECT_EQ(kSystemPageSize, stats->activeBytes);
1762 EXPECT_EQ(2 * kSystemPageSize, stats->residentBytes);
1763 }
1764 CheckPageInCore(ptr1 - kPointerOffset, true);
1765 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDisca rdUnusedSystemPages);
1766 CheckPageInCore(ptr1 - kPointerOffset, false);
1767
1768 partitionFreeGeneric(genericAllocator.root(), ptr2);
1769 }
1770 {
1771 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAlloca tor.root(), 9216 - kExtraAllocSize));
1772 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), 9216 - kExtr aAllocSize);
1773 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), 9216 - kExtr aAllocSize);
1774 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), 9216 - kExtr aAllocSize);
1775 memset(ptr1, 'A', 9216 - kExtraAllocSize);
1776 memset(ptr2, 'A', 9216 - kExtraAllocSize);
1777 partitionFreeGeneric(genericAllocator.root(), ptr2);
1778 partitionFreeGeneric(genericAllocator.root(), ptr1);
1779 {
1780 MockPartitionStatsDumper mockStatsDumperGeneric;
1781 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric);
1782 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1783
1784 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(9216);
1785 EXPECT_TRUE(stats);
1786 EXPECT_TRUE(stats->isValid);
1787 EXPECT_EQ(0u, stats->decommittableBytes);
1788 EXPECT_EQ(2 * kSystemPageSize, stats->discardableBytes);
1789 EXPECT_EQ(9216u * 2, stats->activeBytes);
1790 EXPECT_EQ(9 * kSystemPageSize, stats->residentBytes);
1791 }
1792 CheckPageInCore(ptr1 - kPointerOffset, true);
1793 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1794 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1795 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), true);
1796 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 4), true);
1797 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDisca rdUnusedSystemPages);
1798 CheckPageInCore(ptr1 - kPointerOffset, true);
1799 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, false);
1800 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1801 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), false);
1802 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 4), true);
1803
1804 partitionFreeGeneric(genericAllocator.root(), ptr3);
1805 partitionFreeGeneric(genericAllocator.root(), ptr4);
1806 }
1807 {
1808 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAlloca tor.root(), (64 * kSystemPageSize) - kExtraAllocSize));
1809 memset(ptr1, 'A', (64 * kSystemPageSize) - kExtraAllocSize);
1810 partitionFreeGeneric(genericAllocator.root(), ptr1);
1811 ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAllocator.ro ot(), (61 * kSystemPageSize) - kExtraAllocSize));
1812 {
1813 MockPartitionStatsDumper mockStatsDumperGeneric;
1814 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric);
1815 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1816
1817 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(64 * kSystemPageSize);
1818 EXPECT_TRUE(stats);
1819 EXPECT_TRUE(stats->isValid);
1820 EXPECT_EQ(0u, stats->decommittableBytes);
1821 EXPECT_EQ(3 * kSystemPageSize, stats->discardableBytes);
1822 EXPECT_EQ(61 * kSystemPageSize, stats->activeBytes);
1823 EXPECT_EQ(64 * kSystemPageSize, stats->residentBytes);
1824 }
1825 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 60), true);
1826 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 61), true);
1827 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 62), true);
1828 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 63), true);
1829 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDisca rdUnusedSystemPages);
1830 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 60), true);
1831 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 61), false);
1832 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 62), false);
1833 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 63), false);
1834
1835 partitionFreeGeneric(genericAllocator.root(), ptr1);
1836 }
1837 // This sub-test tests truncation of the provisioned slots in a trickier
1838 // case where the freelist is rewritten.
1839 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitE mptyPages);
1840 {
1841 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAlloca tor.root(), kSystemPageSize - kExtraAllocSize));
1842 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1843 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1844 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1845 ptr1[0] = 'A';
1846 ptr1[kSystemPageSize] = 'A';
1847 ptr1[kSystemPageSize * 2] = 'A';
1848 ptr1[kSystemPageSize * 3] = 'A';
1849 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerA djust(ptr1));
1850 partitionFreeGeneric(genericAllocator.root(), ptr2);
1851 partitionFreeGeneric(genericAllocator.root(), ptr4);
1852 partitionFreeGeneric(genericAllocator.root(), ptr1);
1853 EXPECT_EQ(0u, page->numUnprovisionedSlots);
1854
1855 {
1856 MockPartitionStatsDumper mockStatsDumperGeneric;
1857 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric);
1858 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1859
1860 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(kSystemPageSize);
1861 EXPECT_TRUE(stats);
1862 EXPECT_TRUE(stats->isValid);
1863 EXPECT_EQ(0u, stats->decommittableBytes);
1864 EXPECT_EQ(2 * kSystemPageSize, stats->discardableBytes);
1865 EXPECT_EQ(kSystemPageSize, stats->activeBytes);
1866 EXPECT_EQ(4 * kSystemPageSize, stats->residentBytes);
1867 }
1868 CheckPageInCore(ptr1 - kPointerOffset, true);
1869 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1870 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1871 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), true);
1872 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDisca rdUnusedSystemPages);
1873 EXPECT_EQ(1u, page->numUnprovisionedSlots);
1874 CheckPageInCore(ptr1 - kPointerOffset, true);
1875 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, false);
1876 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1877 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), false);
1878
1879 // Let's check we didn't brick the freelist.
1880 void* ptr1b = partitionAllocGeneric(genericAllocator.root(), kSystemPage Size - kExtraAllocSize);
1881 EXPECT_EQ(ptr1, ptr1b);
1882 void* ptr2b = partitionAllocGeneric(genericAllocator.root(), kSystemPage Size - kExtraAllocSize);
1883 EXPECT_EQ(ptr2, ptr2b);
1884 EXPECT_FALSE(page->freelistHead);
1885
1886 partitionFreeGeneric(genericAllocator.root(), ptr1);
1887 partitionFreeGeneric(genericAllocator.root(), ptr2);
1888 partitionFreeGeneric(genericAllocator.root(), ptr3);
1889 }
1890 // This sub-test is similar, but tests a double-truncation.
1891 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDecommitE mptyPages);
1892 {
1893 char* ptr1 = reinterpret_cast<char*>(partitionAllocGeneric(genericAlloca tor.root(), kSystemPageSize - kExtraAllocSize));
1894 void* ptr2 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1895 void* ptr3 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1896 void* ptr4 = partitionAllocGeneric(genericAllocator.root(), kSystemPageS ize - kExtraAllocSize);
1897 ptr1[0] = 'A';
1898 ptr1[kSystemPageSize] = 'A';
1899 ptr1[kSystemPageSize * 2] = 'A';
1900 ptr1[kSystemPageSize * 3] = 'A';
1901 PartitionPage* page = partitionPointerToPage(partitionCookieFreePointerA djust(ptr1));
1902 partitionFreeGeneric(genericAllocator.root(), ptr4);
1903 partitionFreeGeneric(genericAllocator.root(), ptr3);
1904 EXPECT_EQ(0u, page->numUnprovisionedSlots);
1905
1906 {
1907 MockPartitionStatsDumper mockStatsDumperGeneric;
1908 partitionDumpStatsGeneric(genericAllocator.root(), "mock_generic_all ocator", false /* detailed dump */, &mockStatsDumperGeneric);
1909 EXPECT_TRUE(mockStatsDumperGeneric.IsMemoryAllocationRecorded());
1910
1911 const PartitionBucketMemoryStats* stats = mockStatsDumperGeneric.Get BucketStats(kSystemPageSize);
1912 EXPECT_TRUE(stats);
1913 EXPECT_TRUE(stats->isValid);
1914 EXPECT_EQ(0u, stats->decommittableBytes);
1915 EXPECT_EQ(2 * kSystemPageSize, stats->discardableBytes);
1916 EXPECT_EQ(2 * kSystemPageSize, stats->activeBytes);
1917 EXPECT_EQ(4 * kSystemPageSize, stats->residentBytes);
1918 }
1919 CheckPageInCore(ptr1 - kPointerOffset, true);
1920 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1921 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), true);
1922 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), true);
1923 partitionPurgeMemoryGeneric(genericAllocator.root(), PartitionPurgeDisca rdUnusedSystemPages);
1924 EXPECT_EQ(2u, page->numUnprovisionedSlots);
1925 CheckPageInCore(ptr1 - kPointerOffset, true);
1926 CheckPageInCore(ptr1 - kPointerOffset + kSystemPageSize, true);
1927 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 2), false);
1928 CheckPageInCore(ptr1 - kPointerOffset + (kSystemPageSize * 3), false);
1929
1930 EXPECT_FALSE(page->freelistHead);
1931
1932 partitionFreeGeneric(genericAllocator.root(), ptr1);
1933 partitionFreeGeneric(genericAllocator.root(), ptr2);
1934 }
1935
1936 TestShutdown();
1937 } 1892 }
1938 1893
1939 // Tests that the countLeadingZeros() functions work to our satisfaction. 1894 // Tests that the countLeadingZeros() functions work to our satisfaction.
1940 // It doesn't seem worth the overhead of a whole new file for these tests, so 1895 // It doesn't seem worth the overhead of a whole new file for these tests, so
1941 // we'll put them here since partitionAllocGeneric will depend heavily on these 1896 // we'll put them here since partitionAllocGeneric will depend heavily on these
1942 // functions working correctly. 1897 // functions working correctly.
1943 TEST(PartitionAllocTest, CLZWorks) 1898 TEST(PartitionAllocTest, CLZWorks) {
1944 { 1899 EXPECT_EQ(32u, countLeadingZeros32(0u));
1945 EXPECT_EQ(32u, countLeadingZeros32(0u)); 1900 EXPECT_EQ(31u, countLeadingZeros32(1u));
1946 EXPECT_EQ(31u, countLeadingZeros32(1u)); 1901 EXPECT_EQ(1u, countLeadingZeros32(1u << 30));
1947 EXPECT_EQ(1u, countLeadingZeros32(1u << 30)); 1902 EXPECT_EQ(0u, countLeadingZeros32(1u << 31));
1948 EXPECT_EQ(0u, countLeadingZeros32(1u << 31));
1949 1903
1950 #if CPU(64BIT) 1904 #if CPU(64BIT)
1951 EXPECT_EQ(64u, countLeadingZerosSizet(0ull)); 1905 EXPECT_EQ(64u, countLeadingZerosSizet(0ull));
1952 EXPECT_EQ(63u, countLeadingZerosSizet(1ull)); 1906 EXPECT_EQ(63u, countLeadingZerosSizet(1ull));
1953 EXPECT_EQ(32u, countLeadingZerosSizet(1ull << 31)); 1907 EXPECT_EQ(32u, countLeadingZerosSizet(1ull << 31));
1954 EXPECT_EQ(1u, countLeadingZerosSizet(1ull << 62)); 1908 EXPECT_EQ(1u, countLeadingZerosSizet(1ull << 62));
1955 EXPECT_EQ(0u, countLeadingZerosSizet(1ull << 63)); 1909 EXPECT_EQ(0u, countLeadingZerosSizet(1ull << 63));
1956 #else 1910 #else
1957 EXPECT_EQ(32u, countLeadingZerosSizet(0u)); 1911 EXPECT_EQ(32u, countLeadingZerosSizet(0u));
1958 EXPECT_EQ(31u, countLeadingZerosSizet(1u)); 1912 EXPECT_EQ(31u, countLeadingZerosSizet(1u));
1959 EXPECT_EQ(1u, countLeadingZerosSizet(1u << 30)); 1913 EXPECT_EQ(1u, countLeadingZerosSizet(1u << 30));
1960 EXPECT_EQ(0u, countLeadingZerosSizet(1u << 31)); 1914 EXPECT_EQ(0u, countLeadingZerosSizet(1u << 31));
1961 #endif 1915 #endif
1962 } 1916 }
1963 1917
1964 } // namespace WTF 1918 } // namespace WTF
1965 1919
1966 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) 1920 #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/PartitionAlloc.cpp ('k') | third_party/WebKit/Source/wtf/PartitionAllocator.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698