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 |