Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 // The significant page transitions are: | 216 // The significant page transitions are: |
| 217 // - free() will detect when a full page has a slot free()'d and immediately | 217 // - free() will detect when a full page has a slot free()'d and immediately |
| 218 // return the page to the head of the active list. | 218 // return the page to the head of the active list. |
| 219 // - free() will detect when a page is fully emptied. It _may_ add it to the | 219 // - free() will detect when a page is fully emptied. It _may_ add it to the |
| 220 // free list and it _may_ leave it on the active list until a future list scan. | 220 // free list and it _may_ leave it on the active list until a future list scan. |
| 221 // - malloc() _may_ scan the active page list in order to fulfil the request. | 221 // - malloc() _may_ scan the active page list in order to fulfil the request. |
| 222 // If it does this, full and free pages encountered will be booted out of the | 222 // If it does this, full and free pages encountered will be booted out of the |
| 223 // active list. If there are no suitable active pages found, a free page (if one | 223 // active list. If there are no suitable active pages found, a free page (if one |
| 224 // exists) will be pulled from the free list on to the active list. | 224 // exists) will be pulled from the free list on to the active list. |
| 225 struct PartitionPage { | 225 struct PartitionPage { |
| 226 union { // Accessed most in hot path => goes first. | 226 PartitionFreelistEntry* freelistHead; |
| 227 PartitionFreelistEntry* freelistHead; // If the page is active. | 227 PartitionPage* next; |
|
Tom Sepez
2014/01/13 18:15:55
nit: nextPage or some such. Too many lists to sim
| |
| 228 PartitionPage* freePageNext; // If the page is free. | |
| 229 } u; | |
| 230 PartitionPage* activePageNext; | |
| 231 PartitionBucket* bucket; | 228 PartitionBucket* bucket; |
| 232 int16_t numAllocatedSlots; // Deliberately signed, -1 for free page, -n for full pages. | 229 int16_t numAllocatedSlots; // Deliberately signed, -1 for free page, -n for full pages. |
| 233 uint16_t numUnprovisionedSlots; | 230 uint16_t numUnprovisionedSlots; |
| 234 uint16_t pageOffset; | 231 uint16_t pageOffset; |
| 235 uint16_t flags; | |
| 236 }; | 232 }; |
| 237 static uint16_t kPartitionPageFlagFree = 1; | 233 static uint16_t kPartitionPageFlagFree = 1; |
| 238 | 234 |
| 239 struct PartitionBucket { | 235 struct PartitionBucket { |
| 240 PartitionPage* activePagesHead; // Accessed most in hot path => goes first. | 236 PartitionPage* activePagesHead; // Accessed most in hot path => goes first. |
| 241 PartitionPage* freePagesHead; | 237 PartitionPage* freePagesHead; |
| 242 uint16_t slotSize; | 238 uint16_t slotSize; |
| 243 uint16_t numSystemPagesPerSlotSpan; | 239 uint16_t numSystemPagesPerSlotSpan; |
| 244 uint32_t numFullPages; | 240 uint32_t numFullPages; |
| 245 }; | 241 }; |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 PartitionSuperPageExtentEntry* entry = firstExtent->next; | 460 PartitionSuperPageExtentEntry* entry = firstExtent->next; |
| 465 while (UNLIKELY(entry != 0)) { | 461 while (UNLIKELY(entry != 0)) { |
| 466 if (ptr >= entry->superPageBase && ptr < entry->superPagesEnd) | 462 if (ptr >= entry->superPageBase && ptr < entry->superPagesEnd) |
| 467 return true; | 463 return true; |
| 468 entry = entry->next; | 464 entry = entry->next; |
| 469 } | 465 } |
| 470 | 466 |
| 471 return false; | 467 return false; |
| 472 } | 468 } |
| 473 | 469 |
| 474 ALWAYS_INLINE bool partitionPageIsFree(PartitionPage* page) | |
| 475 { | |
| 476 return (page->flags & kPartitionPageFlagFree); | |
| 477 } | |
| 478 | |
| 479 ALWAYS_INLINE PartitionFreelistEntry* partitionPageFreelistHead(PartitionPage* p age) | |
| 480 { | |
| 481 ASSERT((page == &PartitionRootBase::gSeedPage && !page->u.freelistHead) || ! partitionPageIsFree(page)); | |
| 482 return page->u.freelistHead; | |
| 483 } | |
| 484 | |
| 485 ALWAYS_INLINE void partitionPageSetFreelistHead(PartitionPage* page, PartitionFr eelistEntry* newHead) | |
| 486 { | |
| 487 ASSERT(!partitionPageIsFree(page)); | |
| 488 page->u.freelistHead = newHead; | |
| 489 } | |
| 490 | |
| 491 ALWAYS_INLINE void* partitionBucketAlloc(PartitionRootBase* root, size_t size, P artitionBucket* bucket) | 470 ALWAYS_INLINE void* partitionBucketAlloc(PartitionRootBase* root, size_t size, P artitionBucket* bucket) |
| 492 { | 471 { |
| 493 PartitionPage* page = bucket->activePagesHead; | 472 PartitionPage* page = bucket->activePagesHead; |
| 494 ASSERT(page == &PartitionRootBase::gSeedPage || page->numAllocatedSlots >= 0 ); | 473 ASSERT(page->numAllocatedSlots >= 0); |
| 495 void* ret = partitionPageFreelistHead(page); | 474 void* ret = page->freelistHead; |
| 496 if (LIKELY(ret != 0)) { | 475 if (LIKELY(ret != 0)) { |
| 497 // If these asserts fire, you probably corrupted memory. | 476 // If these asserts fire, you probably corrupted memory. |
| 498 ASSERT(partitionPointerIsValid(root, ret)); | 477 ASSERT(partitionPointerIsValid(root, ret)); |
| 499 ASSERT(partitionPointerToPage(ret)); | 478 ASSERT(partitionPointerToPage(ret)); |
| 500 PartitionFreelistEntry* newHead = partitionFreelistMask(static_cast<Part itionFreelistEntry*>(ret)->next); | 479 PartitionFreelistEntry* newHead = partitionFreelistMask(static_cast<Part itionFreelistEntry*>(ret)->next); |
| 501 partitionPageSetFreelistHead(page, newHead); | 480 page->freelistHead = newHead; |
| 502 ASSERT(!ret || partitionPointerIsValid(root, ret)); | 481 ASSERT(!ret || partitionPointerIsValid(root, ret)); |
| 503 ASSERT(!ret || partitionPointerToPage(ret)); | 482 ASSERT(!ret || partitionPointerToPage(ret)); |
| 504 page->numAllocatedSlots++; | 483 page->numAllocatedSlots++; |
| 505 } else { | 484 } else { |
| 506 ret = partitionAllocSlowPath(root, size, bucket); | 485 ret = partitionAllocSlowPath(root, size, bucket); |
| 507 } | 486 } |
| 508 #ifndef NDEBUG | 487 #ifndef NDEBUG |
| 509 // This will go away once we don't use tcmalloc to back larger allocations. | 488 // This will go away once we don't use tcmalloc to back larger allocations. |
| 510 if (!partitionPointerIsValid(root, ret)) | 489 if (!partitionPointerIsValid(root, ret)) |
| 511 return ret; | 490 return ret; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 547 ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) | 526 ALWAYS_INLINE void partitionFreeWithPage(void* ptr, PartitionPage* page) |
| 548 { | 527 { |
| 549 // If these asserts fire, you probably corrupted memory. | 528 // If these asserts fire, you probably corrupted memory. |
| 550 #ifndef NDEBUG | 529 #ifndef NDEBUG |
| 551 size_t bucketSize = page->bucket->slotSize; | 530 size_t bucketSize = page->bucket->slotSize; |
| 552 void* ptrEnd = static_cast<char*>(ptr) + bucketSize; | 531 void* ptrEnd = static_cast<char*>(ptr) + bucketSize; |
| 553 ASSERT(*(static_cast<uintptr_t*>(ptr)) == kCookieValue); | 532 ASSERT(*(static_cast<uintptr_t*>(ptr)) == kCookieValue); |
| 554 ASSERT(*(static_cast<uintptr_t*>(ptrEnd) - 1) == kCookieValue); | 533 ASSERT(*(static_cast<uintptr_t*>(ptrEnd) - 1) == kCookieValue); |
| 555 memset(ptr, kFreedByte, bucketSize); | 534 memset(ptr, kFreedByte, bucketSize); |
| 556 #endif | 535 #endif |
| 557 PartitionFreelistEntry* freelistHead = partitionPageFreelistHead(page); | 536 ASSERT(page->numAllocatedSlots); |
| 537 PartitionFreelistEntry* freelistHead = page->freelistHead; | |
| 558 ASSERT(!freelistHead || partitionPointerIsValid(partitionPageToRoot(page), f reelistHead)); | 538 ASSERT(!freelistHead || partitionPointerIsValid(partitionPageToRoot(page), f reelistHead)); |
| 559 ASSERT(!freelistHead || partitionPointerToPage(freelistHead)); | 539 ASSERT(!freelistHead || partitionPointerToPage(freelistHead)); |
| 560 RELEASE_ASSERT(ptr != freelistHead); // Catches an immediate double free. | 540 RELEASE_ASSERT(ptr != freelistHead); // Catches an immediate double free. |
| 561 ASSERT(!freelistHead || ptr != partitionFreelistMask(freelistHead->next)); / / Look for double free one level deeper in debug. | 541 ASSERT(!freelistHead || ptr != partitionFreelistMask(freelistHead->next)); / / Look for double free one level deeper in debug. |
| 562 PartitionFreelistEntry* entry = static_cast<PartitionFreelistEntry*>(ptr); | 542 PartitionFreelistEntry* entry = static_cast<PartitionFreelistEntry*>(ptr); |
| 563 entry->next = partitionFreelistMask(freelistHead); | 543 entry->next = partitionFreelistMask(freelistHead); |
| 564 partitionPageSetFreelistHead(page, entry); | 544 page->freelistHead = entry; |
| 565 --page->numAllocatedSlots; | 545 --page->numAllocatedSlots; |
| 566 if (UNLIKELY(page->numAllocatedSlots <= 0)) | 546 if (UNLIKELY(page->numAllocatedSlots <= 0)) |
| 567 partitionFreeSlowPath(page); | 547 partitionFreeSlowPath(page); |
| 568 } | 548 } |
| 569 | 549 |
| 570 ALWAYS_INLINE void partitionFree(void* ptr) | 550 ALWAYS_INLINE void partitionFree(void* ptr) |
| 571 { | 551 { |
| 572 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 552 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 573 free(ptr); | 553 free(ptr); |
| 574 #else | 554 #else |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 663 using WTF::PartitionRoot; | 643 using WTF::PartitionRoot; |
| 664 using WTF::partitionAllocInit; | 644 using WTF::partitionAllocInit; |
| 665 using WTF::partitionAllocShutdown; | 645 using WTF::partitionAllocShutdown; |
| 666 using WTF::partitionAlloc; | 646 using WTF::partitionAlloc; |
| 667 using WTF::partitionFree; | 647 using WTF::partitionFree; |
| 668 using WTF::partitionAllocGeneric; | 648 using WTF::partitionAllocGeneric; |
| 669 using WTF::partitionFreeGeneric; | 649 using WTF::partitionFreeGeneric; |
| 670 using WTF::partitionReallocGeneric; | 650 using WTF::partitionReallocGeneric; |
| 671 | 651 |
| 672 #endif // WTF_PartitionAlloc_h | 652 #endif // WTF_PartitionAlloc_h |
| OLD | NEW |