OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 13 matching lines...) Expand all Loading... |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 #include "wtf/PartitionAlloc.h" | 32 #include "wtf/PartitionAlloc.h" |
33 | 33 |
34 #include "wtf/PageAllocator.h" | |
35 #include <string.h> | 34 #include <string.h> |
36 | 35 |
37 #ifndef NDEBUG | 36 #ifndef NDEBUG |
38 #include <stdio.h> | 37 #include <stdio.h> |
39 #endif | 38 #endif |
40 | 39 |
41 // A super page is at least 4 partition pages in order to make re-entrancy consi
derations simpler in partitionAllocPage(). | 40 // A super page is at least 4 partition pages in order to make re-entrancy consi
derations simpler in partitionAllocPage(). |
42 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_partition_
page_size); | 41 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_partition_
page_size); |
43 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_partition_pa
ge_multiple); | 42 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_partition_pa
ge_multiple); |
44 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSubPartitionPageSize), ok_sub_p
artition_page_multiple); | 43 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSubPartitionPageSize), ok_sub_p
artition_page_multiple); |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 | 277 |
279 static ALWAYS_INLINE void partitionUnlinkPage(PartitionPageHeader* page) | 278 static ALWAYS_INLINE void partitionUnlinkPage(PartitionPageHeader* page) |
280 { | 279 { |
281 ASSERT(page->prev->next == page); | 280 ASSERT(page->prev->next == page); |
282 ASSERT(page->next->prev == page); | 281 ASSERT(page->next->prev == page); |
283 | 282 |
284 page->next->prev = page->prev; | 283 page->next->prev = page->prev; |
285 page->prev->next = page->next; | 284 page->prev->next = page->next; |
286 } | 285 } |
287 | 286 |
288 static ALWAYS_INLINE void partitionLinkPage(PartitionPageHeader* newPage, Partit
ionPageHeader* prevPage) | 287 static ALWAYS_INLINE void partitionLinkPageBefore(PartitionPageHeader* newPage,
PartitionPageHeader* nextPage) |
289 { | 288 { |
290 ASSERT(prevPage->prev->next == prevPage); | 289 ASSERT(nextPage->prev->next == nextPage); |
291 ASSERT(prevPage->next->prev == prevPage); | 290 ASSERT(nextPage->next->prev == nextPage); |
292 | 291 |
293 newPage->prev = prevPage; | 292 newPage->next = nextPage; |
294 newPage->next = prevPage->next; | 293 newPage->prev = nextPage->prev; |
295 | 294 |
296 prevPage->next->prev = newPage; | 295 nextPage->prev->next = newPage; |
297 prevPage->next = newPage; | 296 nextPage->prev = newPage; |
298 } | 297 } |
299 | 298 |
300 void* partitionAllocSlowPath(PartitionBucket* bucket) | 299 void* partitionAllocSlowPath(PartitionBucket* bucket) |
301 { | 300 { |
302 // The slow path is called when the freelist is empty. | 301 // The slow path is called when the freelist is empty. |
303 PartitionPageHeader* page = bucket->currPage; | 302 PartitionPageHeader* page = bucket->currPage; |
304 PartitionPageHeader* next = page->next; | 303 PartitionPageHeader* next = page->next; |
305 ASSERT(page == &bucket->root->seedPage || (page->bucket == bucket && next->b
ucket == bucket)); | 304 ASSERT(page == &bucket->root->seedPage || (page->bucket == bucket && next->b
ucket == bucket)); |
306 | 305 |
307 // First, see if the partition page still has capacity and if so, fill out | 306 // First, see if the current partition page still has capacity and if so, |
308 // the freelist a little more. | 307 // fill out the freelist a little more. |
309 if (LIKELY(page->numUnprovisionedSlots)) | 308 if (LIKELY(page->numUnprovisionedSlots)) |
310 return partitionPageAllocAndFillFreelist(page); | 309 return partitionPageAllocAndFillFreelist(page); |
311 | 310 |
312 // Second, look for a page in our linked ring list of non-full pages. | 311 // Second, look for a page in our linked ring list of non-full pages. |
313 while (LIKELY(next != page)) { | 312 while (LIKELY(next != page)) { |
314 ASSERT(next->bucket == bucket); | 313 ASSERT(next->bucket == bucket); |
315 ASSERT(next->next->prev == next); | 314 ASSERT(next->next->prev == next); |
316 ASSERT(next->prev->next == next); | 315 ASSERT(next->prev->next == next); |
317 ASSERT(next != &bucket->root->seedPage); | 316 ASSERT(next != &bucket->root->seedPage); |
318 if (LIKELY(next->freelistHead != 0)) { | 317 if (LIKELY(next->freelistHead != 0)) { |
319 bucket->currPage = next; | 318 bucket->currPage = next; |
320 PartitionFreelistEntry* ret = next->freelistHead; | 319 PartitionFreelistEntry* ret = next->freelistHead; |
321 next->freelistHead = partitionFreelistMask(ret->next); | 320 next->freelistHead = partitionFreelistMask(ret->next); |
322 next->numAllocatedSlots++; | 321 next->numAllocatedSlots++; |
323 return ret; | 322 return ret; |
324 } | 323 } |
| 324 if (LIKELY(next->numUnprovisionedSlots)) { |
| 325 bucket->currPage = next; |
| 326 return partitionPageAllocAndFillFreelist(next); |
| 327 } |
325 // Pull this page out of the non-full page list, since it has no free | 328 // Pull this page out of the non-full page list, since it has no free |
326 // slots. | 329 // slots. |
327 // This tags the page as full so that free'ing can tell, and move | 330 // This tags the page as full so that free'ing can tell, and move |
328 // the page back into the non-full page list when appropriate. | 331 // the page back into the non-full page list when appropriate. |
329 ASSERT(next->numAllocatedSlots == partitionBucketSlots(bucket)); | 332 ASSERT(next->numAllocatedSlots == partitionBucketSlots(bucket)); |
330 next->numAllocatedSlots = -next->numAllocatedSlots; | 333 next->numAllocatedSlots = -next->numAllocatedSlots; |
331 partitionUnlinkPage(next); | 334 partitionUnlinkPage(next); |
332 ++bucket->numFullPages; | 335 ++bucket->numFullPages; |
333 | 336 |
334 next = next->next; | 337 next = next->next; |
335 } | 338 } |
336 | 339 |
337 // Second, look in our list of freed but reserved pages. | 340 // After we've considered and rejected every partition page in the list, |
| 341 // we should by definition have a single self-linked page left. We will |
| 342 // replace this single page with the new page we choose. |
| 343 ASSERT(page == page->next); |
| 344 ASSERT(page == page->prev); |
| 345 ASSERT(page == &bucket->root->seedPage || page->numAllocatedSlots == partiti
onBucketSlots(bucket)); |
| 346 if (LIKELY(page != &bucket->root->seedPage)) { |
| 347 page->numAllocatedSlots = -page->numAllocatedSlots; |
| 348 ++bucket->numFullPages; |
| 349 } |
| 350 |
| 351 // Third, look in our list of freed but reserved pages. |
338 PartitionPageHeader* newPage; | 352 PartitionPageHeader* newPage; |
339 PartitionFreepagelistEntry* pagelist = bucket->freePages; | 353 PartitionFreepagelistEntry* pagelist = bucket->freePages; |
340 if (LIKELY(pagelist != 0)) { | 354 if (LIKELY(pagelist != 0)) { |
341 newPage = pagelist->page; | 355 newPage = pagelist->page; |
342 bucket->freePages = pagelist->next; | 356 bucket->freePages = pagelist->next; |
343 partitionFree(pagelist); | 357 partitionFree(pagelist); |
344 ASSERT(page != &bucket->root->seedPage); | 358 ASSERT(page != &bucket->root->seedPage); |
345 partitionLinkPage(newPage, page); | |
346 } else { | 359 } else { |
347 // Third. If we get here, we need a brand new page. | 360 // Fourth. If we get here, we need a brand new page. |
348 newPage = partitionAllocPage(bucket->root); | 361 newPage = partitionAllocPage(bucket->root); |
349 if (UNLIKELY(page == &bucket->root->seedPage)) { | |
350 // If this is the first page allocation to this bucket, then | |
351 // fully replace the seed page. This avoids pointlessly iterating | |
352 // over it. | |
353 newPage->prev = newPage; | |
354 newPage->next = newPage; | |
355 } else { | |
356 partitionLinkPage(newPage, page); | |
357 } | |
358 } | 362 } |
359 | 363 |
| 364 newPage->prev = newPage; |
| 365 newPage->next = newPage; |
360 bucket->currPage = newPage; | 366 bucket->currPage = newPage; |
361 partitionPageReset(newPage, bucket); | 367 partitionPageReset(newPage, bucket); |
362 return partitionPageAllocAndFillFreelist(newPage); | 368 return partitionPageAllocAndFillFreelist(newPage); |
363 } | 369 } |
364 | 370 |
365 void partitionFreeSlowPath(PartitionPageHeader* page) | 371 void partitionFreeSlowPath(PartitionPageHeader* page) |
366 { | 372 { |
367 PartitionBucket* bucket = page->bucket; | 373 PartitionBucket* bucket = page->bucket; |
368 if (LIKELY(page->numAllocatedSlots == 0)) { | 374 if (LIKELY(page->numAllocatedSlots == 0)) { |
369 // Page became fully unused. | 375 // Page became fully unused. |
370 // If it's the current page, leave it be so that we don't bounce a page | 376 // If it's the current page, change it! |
371 // onto the free page list and immediately back out again. | 377 if (LIKELY(page == bucket->currPage)) { |
372 if (LIKELY(page == bucket->currPage)) | 378 if (UNLIKELY(page->next == page)) { |
373 return; | 379 // For now, we do not free the last partition page in a bucket. |
| 380 return; |
| 381 } |
| 382 bucket->currPage = page->next; |
| 383 } |
374 | 384 |
375 partitionUnlinkPage(page); | 385 partitionUnlinkPage(page); |
376 partitionUnusePage(page); | 386 partitionUnusePage(page); |
377 PartitionFreepagelistEntry* entry = static_cast<PartitionFreepagelistEnt
ry*>(partitionBucketAlloc(&bucket->root->buckets()[kInternalMetadataBucket])); | 387 PartitionFreepagelistEntry* entry = static_cast<PartitionFreepagelistEnt
ry*>(partitionBucketAlloc(&bucket->root->buckets()[kInternalMetadataBucket])); |
378 entry->page = page; | 388 entry->page = page; |
379 entry->next = bucket->freePages; | 389 entry->next = bucket->freePages; |
380 bucket->freePages = entry; | 390 bucket->freePages = entry; |
381 } else { | 391 } else { |
382 // Fully used page became partially used. It must be put back on the | 392 // Fully used page became partially used. It must be put back on the |
383 // non-full page list. | 393 // non-full page list. Also make it the current page to increase the |
384 partitionLinkPage(page, bucket->currPage); | 394 // chances of it being filled up again. The old current page will be |
| 395 // the next page. |
| 396 partitionLinkPageBefore(page, bucket->currPage); |
| 397 bucket->currPage = page; |
385 page->numAllocatedSlots = -page->numAllocatedSlots - 2; | 398 page->numAllocatedSlots = -page->numAllocatedSlots - 2; |
386 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1); | 399 ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1); |
387 --bucket->numFullPages; | 400 --bucket->numFullPages; |
388 } | 401 } |
389 } | 402 } |
390 | 403 |
391 void* partitionReallocGeneric(PartitionRoot* root, void* ptr, size_t newSize) | 404 void* partitionReallocGeneric(PartitionRoot* root, void* ptr, size_t newSize) |
392 { | 405 { |
393 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 406 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
394 return realloc(ptr, newSize); | 407 return realloc(ptr, newSize); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 printf("total live: %ld bytes\n", totalLive); | 485 printf("total live: %ld bytes\n", totalLive); |
473 printf("total resident: %ld bytes\n", totalResident); | 486 printf("total resident: %ld bytes\n", totalResident); |
474 printf("total freeable: %ld bytes\n", totalFreeable); | 487 printf("total freeable: %ld bytes\n", totalFreeable); |
475 fflush(stdout); | 488 fflush(stdout); |
476 } | 489 } |
477 | 490 |
478 #endif // !NDEBUG | 491 #endif // !NDEBUG |
479 | 492 |
480 } // namespace WTF | 493 } // namespace WTF |
481 | 494 |
OLD | NEW |