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 29 matching lines...) Expand all Loading... | |
| 40 // Two partition pages are used as guard / metadata page so make sure the super | 40 // Two partition pages are used as guard / metadata page so make sure the super |
| 41 // page size is bigger. | 41 // page size is bigger. |
| 42 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_super_page _size); | 42 COMPILE_ASSERT(WTF::kPartitionPageSize * 4 <= WTF::kSuperPageSize, ok_super_page _size); |
| 43 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_super_page_m ultiple); | 43 COMPILE_ASSERT(!(WTF::kSuperPageSize % WTF::kPartitionPageSize), ok_super_page_m ultiple); |
| 44 // Four system pages gives us room to hack out a still-guard-paged piece | 44 // Four system pages gives us room to hack out a still-guard-paged piece |
| 45 // of metadata in the middle of a guard partition page. | 45 // of metadata in the middle of a guard partition page. |
| 46 COMPILE_ASSERT(WTF::kSystemPageSize * 4 <= WTF::kPartitionPageSize, ok_partition _page_size); | 46 COMPILE_ASSERT(WTF::kSystemPageSize * 4 <= WTF::kPartitionPageSize, ok_partition _page_size); |
| 47 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSystemPageSize), ok_partition_p age_multiple); | 47 COMPILE_ASSERT(!(WTF::kPartitionPageSize % WTF::kSystemPageSize), ok_partition_p age_multiple); |
| 48 COMPILE_ASSERT(sizeof(WTF::PartitionPage) <= WTF::kPageMetadataSize, PartitionPa ge_not_too_big); | 48 COMPILE_ASSERT(sizeof(WTF::PartitionPage) <= WTF::kPageMetadataSize, PartitionPa ge_not_too_big); |
| 49 COMPILE_ASSERT(sizeof(WTF::PartitionSuperPageExtentEntry) <= WTF::kPageMetadataS ize, PartitionSuperPageExtentEntry_not_too_big); | 49 COMPILE_ASSERT(sizeof(WTF::PartitionSuperPageExtentEntry) <= WTF::kPageMetadataS ize, PartitionSuperPageExtentEntry_not_too_big); |
| 50 COMPILE_ASSERT(sizeof(WTF::PartitionBucket) <= WTF::kPageMetadataSize, Partition Bucket_not_too_big); | |
| 50 COMPILE_ASSERT(WTF::kPageMetadataSize * WTF::kNumPartitionPagesPerSuperPage <= W TF::kSystemPageSize, page_metadata_fits_in_hole); | 51 COMPILE_ASSERT(WTF::kPageMetadataSize * WTF::kNumPartitionPagesPerSuperPage <= W TF::kSystemPageSize, page_metadata_fits_in_hole); |
| 51 // Check that some of our zanier calculations worked out as expected. | 52 // Check that some of our zanier calculations worked out as expected. |
| 52 COMPILE_ASSERT(WTF::kGenericSmallestBucket == 8, generic_smallest_bucket); | 53 COMPILE_ASSERT(WTF::kGenericSmallestBucket == 8, generic_smallest_bucket); |
| 53 COMPILE_ASSERT(WTF::kGenericMaxBucketed == 983040, generic_max_bucketed); | 54 COMPILE_ASSERT(WTF::kGenericMaxBucketed == 983040, generic_max_bucketed); |
| 54 | 55 |
| 55 namespace WTF { | 56 namespace WTF { |
| 56 | 57 |
| 57 int PartitionRootBase::gInitializedLock = 0; | 58 int PartitionRootBase::gInitializedLock = 0; |
| 58 bool PartitionRootBase::gInitialized = false; | 59 bool PartitionRootBase::gInitialized = false; |
| 59 PartitionPage PartitionRootBase::gSeedPage; | 60 PartitionPage PartitionRootBase::gSeedPage; |
| (...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 RELEASE_ASSERT(bucket->numFullPages); | 518 RELEASE_ASSERT(bucket->numFullPages); |
| 518 // Not necessary but might help stop accidents. | 519 // Not necessary but might help stop accidents. |
| 519 page->nextPage = 0; | 520 page->nextPage = 0; |
| 520 } | 521 } |
| 521 } | 522 } |
| 522 | 523 |
| 523 bucket->activePagesHead = 0; | 524 bucket->activePagesHead = 0; |
| 524 return false; | 525 return false; |
| 525 } | 526 } |
| 526 | 527 |
| 528 struct PartitionDirectMapExtent { | |
| 529 size_t mapSize; // Mapped size, not including guard pages and meta-data. | |
| 530 }; | |
| 531 | |
| 532 static ALWAYS_INLINE PartitionDirectMapExtent* partitionPageToDirectMapExtent(Pa rtitionPage* page) | |
| 533 { | |
| 534 ASSERT(partitionBucketIsDirectMapped(page->bucket)); | |
| 535 return reinterpret_cast<PartitionDirectMapExtent*>(reinterpret_cast<char*>(p age) + 2 * kPageMetadataSize); | |
| 536 } | |
| 537 | |
| 527 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size) | 538 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size) |
| 528 { | 539 { |
| 529 size = partitionDirectMapSize(size); | 540 size = partitionDirectMapSize(size); |
| 530 | 541 |
| 531 // Because we need to fake looking like a super page, We need to allocate | 542 // Because we need to fake looking like a super page, We need to allocate |
| 532 // a bunch of system pages more than "size": | 543 // a bunch of system pages more than "size": |
| 533 // - The first few system pages are the partition page in which the super | 544 // - The first few system pages are the partition page in which the super |
| 534 // page metadata is stored. We fault just one system page out of a partition | 545 // page metadata is stored. We fault just one system page out of a partition |
| 535 // page sized clump. | 546 // page sized clump. |
| 536 // - We add a trailing guard page. | 547 // - We add a trailing guard page. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 574 page->numUnprovisionedSlots = 0; | 585 page->numUnprovisionedSlots = 0; |
| 575 page->pageOffset = 0; | 586 page->pageOffset = 0; |
| 576 page->freeCacheIndex = 0; | 587 page->freeCacheIndex = 0; |
| 577 | 588 |
| 578 bucket->activePagesHead = 0; | 589 bucket->activePagesHead = 0; |
| 579 bucket->freePagesHead = 0; | 590 bucket->freePagesHead = 0; |
| 580 bucket->slotSize = size; | 591 bucket->slotSize = size; |
| 581 bucket->numSystemPagesPerSlotSpan = 0; | 592 bucket->numSystemPagesPerSlotSpan = 0; |
| 582 bucket->numFullPages = 0; | 593 bucket->numFullPages = 0; |
| 583 | 594 |
| 595 PartitionDirectMapExtent* mapExtent = partitionPageToDirectMapExtent(page); | |
| 596 mapExtent->mapSize = mapSize - kPartitionPageSize - kSystemPageSize; | |
| 597 | |
| 584 return ret; | 598 return ret; |
| 585 } | 599 } |
| 586 | 600 |
| 587 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) | 601 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) |
| 588 { | 602 { |
| 589 size_t unmapSize = page->bucket->slotSize; | 603 size_t unmapSize = partitionPageToDirectMapExtent(page)->mapSize; |
| 604 | |
| 590 // Add on the size of the trailing guard page and preceeding partition | 605 // Add on the size of the trailing guard page and preceeding partition |
| 591 // page, then round up to allocation granularity. | 606 // page. |
| 592 unmapSize += kPartitionPageSize + kSystemPageSize; | 607 unmapSize += kPartitionPageSize + kSystemPageSize; |
| 593 unmapSize += kPageAllocationGranularityOffsetMask; | 608 |
| 594 unmapSize &= kPageAllocationGranularityBaseMask; | 609 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); |
| 595 | 610 |
| 596 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | 611 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
| 597 // Account for the mapping starting a partition page before the actual | 612 // Account for the mapping starting a partition page before the actual |
| 598 // allocation address. | 613 // allocation address. |
| 599 ptr -= kPartitionPageSize; | 614 ptr -= kPartitionPageSize; |
| 600 | 615 |
| 601 freePages(ptr, unmapSize); | 616 freePages(ptr, unmapSize); |
| 602 } | 617 } |
| 603 | 618 |
| 604 void* partitionAllocSlowPath(PartitionRootBase* root, int flags, size_t size, Pa rtitionBucket* bucket) | 619 void* partitionAllocSlowPath(PartitionRootBase* root, int flags, size_t size, Pa rtitionBucket* bucket) |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 756 page->nextPage = bucket->activePagesHead; | 771 page->nextPage = bucket->activePagesHead; |
| 757 bucket->activePagesHead = page; | 772 bucket->activePagesHead = page; |
| 758 --bucket->numFullPages; | 773 --bucket->numFullPages; |
| 759 // Special case: for a partition page with just a single slot, it may | 774 // Special case: for a partition page with just a single slot, it may |
| 760 // now be empty and we want to run it through the empty logic. | 775 // now be empty and we want to run it through the empty logic. |
| 761 if (UNLIKELY(page->numAllocatedSlots == 0)) | 776 if (UNLIKELY(page->numAllocatedSlots == 0)) |
| 762 partitionFreeSlowPath(page); | 777 partitionFreeSlowPath(page); |
| 763 } | 778 } |
| 764 } | 779 } |
| 765 | 780 |
| 781 bool partitionReallocDirectMappedInPlace(PartitionRootGeneric* root, void* ptr, size_t newSize) | |
| 782 { | |
| 783 newSize = partitionCookieSizeAdjustAdd(newSize); | |
| 784 | |
| 785 // Note that the new size might be a bucketed size; this function is called | |
| 786 // whenever we're reallocating a direct mapped allocation. | |
| 787 newSize = partitionDirectMapSize(newSize); | |
| 788 if (newSize < kGenericMinDirectMapped) | |
| 789 return false; | |
| 790 | |
| 791 PartitionPage* page = partitionPointerToPage(ptr); | |
|
Chris Evans
2014/03/06 05:55:13
Pass in page instead of ptr to this function to av
| |
| 792 PartitionBucket* bucket = page->bucket; | |
| 793 | |
| 794 ASSERT(partitionBucketIsDirectMapped(bucket)); | |
| 795 | |
| 796 // bucket->slotSize is the current size of the allocation. | |
| 797 if (newSize == bucket->slotSize) | |
|
Chris Evans
2014/03/06 05:55:13
This check looks duplicated with a check in the pa
Jens Widell
2014/03/06 06:03:04
If you mean the actualOldSize/actualNewSize compar
| |
| 798 return true; | |
| 799 | |
| 800 char* charPtr = static_cast<char*>(ptr); | |
| 801 | |
| 802 if (newSize < bucket->slotSize) { | |
| 803 // Shrink by decommitting unneeded pages and making them inaccessible. | |
| 804 size_t decommitSize = bucket->slotSize - newSize; | |
| 805 decommitSystemPages(charPtr + newSize, decommitSize); | |
| 806 setSystemPagesInaccessible(charPtr + newSize, decommitSize); | |
| 807 } else if (newSize <= partitionPageToDirectMapExtent(page)->mapSize) { | |
| 808 // Grow within the actually allocated memory. Just need to make the | |
| 809 // pages accessible again. | |
| 810 size_t recommitSize = newSize - bucket->slotSize; | |
| 811 setSystemPagesAccessible(charPtr + bucket->slotSize, recommitSize); | |
| 812 | |
| 813 #ifndef NDEBUG | |
| 814 memset(charPtr + bucket->slotSize, kUninitializedByte, recommitSize); | |
| 815 #endif | |
| 816 } else { | |
| 817 // We can't perform the realloc in-place. | |
| 818 // TODO: support this too when possible. | |
| 819 return false; | |
| 820 } | |
| 821 | |
| 822 #ifndef NDEBUG | |
| 823 // Write a new trailing cookie. | |
| 824 partitionCookieWriteValue(charPtr + newSize - kCookieSize); | |
| 825 #endif | |
| 826 | |
| 827 bucket->slotSize = newSize; | |
| 828 return true; | |
| 829 } | |
| 830 | |
| 766 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize) | 831 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize) |
| 767 { | 832 { |
| 768 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 833 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 769 return realloc(ptr, newSize); | 834 return realloc(ptr, newSize); |
| 770 #else | 835 #else |
| 771 if (UNLIKELY(!ptr)) | 836 if (UNLIKELY(!ptr)) |
| 772 return partitionAllocGeneric(root, newSize); | 837 return partitionAllocGeneric(root, newSize); |
| 773 if (UNLIKELY(!newSize)) { | 838 if (UNLIKELY(!newSize)) { |
| 774 partitionFreeGeneric(root, ptr); | 839 partitionFreeGeneric(root, ptr); |
| 775 return 0; | 840 return 0; |
| 776 } | 841 } |
| 777 | 842 |
| 843 RELEASE_ASSERT(newSize <= INT_MAX - kSystemPageSize); | |
|
Chris Evans
2014/03/06 05:55:13
The RHS is just kGenericMaxDirectMapped, I think.
| |
| 844 | |
| 778 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr))); | 845 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr))); |
| 779 | 846 |
| 847 void* realPtr = partitionCookieFreePointerAdjust(ptr); | |
| 848 PartitionPage* page = partitionPointerToPage(realPtr); | |
| 849 | |
| 850 if (partitionBucketIsDirectMapped(page->bucket)) { | |
|
Chris Evans
2014/03/06 05:55:13
Might as well wrap that condition in an UNLIKELY ?
| |
| 851 // We may be able to perform the realloc in place by changing the | |
| 852 // accessibility of memory pages and, if reducing the size, decommitting | |
| 853 // them. | |
| 854 if (partitionReallocDirectMappedInPlace(root, realPtr, newSize)) | |
|
Chris Evans
2014/03/06 05:55:13
Pass in the page and not the pointer to do a littl
| |
| 855 return ptr; | |
| 856 } | |
| 857 | |
| 780 size_t actualNewSize = partitionAllocActualSize(root, newSize); | 858 size_t actualNewSize = partitionAllocActualSize(root, newSize); |
| 781 size_t actualOldSize = partitionAllocGetSize(ptr); | 859 size_t actualOldSize = partitionAllocGetSize(ptr); |
| 782 | 860 |
| 783 // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the | 861 // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the |
| 784 // new size is a significant percentage smaller. We could do the same if we | 862 // new size is a significant percentage smaller. We could do the same if we |
| 785 // determine it is a win. | 863 // determine it is a win. |
| 786 if (actualNewSize == actualOldSize) { | 864 if (actualNewSize == actualOldSize) { |
| 787 // Trying to allocate a block of size newSize would give us a block of | 865 // Trying to allocate a block of size newSize would give us a block of |
| 788 // the same size as the one we've already got, so no point in doing | 866 // the same size as the one we've already got, so no point in doing |
| 789 // anything here. | 867 // anything here. |
| 790 // TODO: for an upsize or downsize on a direct mapped allocation, we | |
| 791 // should really try and resize it in-place. | |
| 792 return ptr; | 868 return ptr; |
| 793 } | 869 } |
| 794 | 870 |
| 795 // This realloc cannot be resized in-place. Sadness. | 871 // This realloc cannot be resized in-place. Sadness. |
| 796 void* ret = partitionAllocGeneric(root, newSize); | 872 void* ret = partitionAllocGeneric(root, newSize); |
| 797 size_t copySize = actualOldSize; | 873 size_t copySize = actualOldSize; |
| 798 if (newSize < copySize) | 874 if (newSize < copySize) |
| 799 copySize = newSize; | 875 copySize = newSize; |
| 800 | 876 |
| 801 memcpy(ret, ptr, copySize); | 877 memcpy(ret, ptr, copySize); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 855 printf("total live: %zu bytes\n", totalLive); | 931 printf("total live: %zu bytes\n", totalLive); |
| 856 printf("total resident: %zu bytes\n", totalResident); | 932 printf("total resident: %zu bytes\n", totalResident); |
| 857 printf("total freeable: %zu bytes\n", totalFreeable); | 933 printf("total freeable: %zu bytes\n", totalFreeable); |
| 858 fflush(stdout); | 934 fflush(stdout); |
| 859 } | 935 } |
| 860 | 936 |
| 861 #endif // !NDEBUG | 937 #endif // !NDEBUG |
| 862 | 938 |
| 863 } // namespace WTF | 939 } // namespace WTF |
| 864 | 940 |
| OLD | NEW |