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

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

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