| 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 |