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 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 517 RELEASE_ASSERT(bucket->numFullPages); | 517 RELEASE_ASSERT(bucket->numFullPages); |
| 518 // Not necessary but might help stop accidents. | 518 // Not necessary but might help stop accidents. |
| 519 page->nextPage = 0; | 519 page->nextPage = 0; |
| 520 } | 520 } |
| 521 } | 521 } |
| 522 | 522 |
| 523 bucket->activePagesHead = 0; | 523 bucket->activePagesHead = 0; |
| 524 return false; | 524 return false; |
| 525 } | 525 } |
| 526 | 526 |
| 527 static ALWAYS_INLINE size_t partitionDirectMapAvailableSize(PartitionPage* page) | |
|
Chris Evans
2014/03/05 07:57:04
This function seems a bit complicated, or at least
| |
| 528 { | |
| 529 // Return the size of the mapping, *not* including space where meta-data is | |
| 530 // stored, and *not* including one trailing inaccessible system page; IOW | |
| 531 // the size of the area available for the actual allocation. Some of the | |
| 532 // pages at the end of this memory range may have been decommitted and made | |
| 533 // inaccessible by a partitionReallocGeneric() call. | |
| 534 // | |
| 535 // The value of bucket->slotSize is size of the current allocation. | |
| 536 | |
| 537 PartitionBucket* bucket = page->bucket; | |
| 538 | |
| 539 ASSERT(partitionBucketIsDirectMapped(bucket)); | |
| 540 ASSERT(bucket != &PartitionRootBase::gPagedBucket); | |
| 541 | |
| 542 char* ptr = static_cast<char*>(partitionPageToPointer(page)); | |
| 543 char* endPtr = reinterpret_cast<char*>(bucket->freePagesHead) - kSystemPageS ize; | |
| 544 | |
| 545 size_t size = endPtr - ptr; | |
| 546 ASSERT(bucket->slotSize <= size); | |
| 547 return size; | |
| 548 } | |
| 549 | |
| 527 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size) | 550 static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags , size_t size) |
| 528 { | 551 { |
| 529 size = partitionDirectMapSize(size); | 552 size = partitionDirectMapSize(size); |
| 530 | 553 |
| 531 // Because we need to fake looking like a super page, We need to allocate | 554 // Because we need to fake looking like a super page, We need to allocate |
| 532 // a bunch of system pages more than "size": | 555 // a bunch of system pages more than "size": |
| 533 // - The first few system pages are the partition page in which the super | 556 // - 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 | 557 // page metadata is stored. We fault just one system page out of a partition |
| 535 // page sized clump. | 558 // page sized clump. |
| 536 // - We add a trailing guard page. | 559 // - We add a trailing guard page. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 569 PartitionBucket* bucket = reinterpret_cast<PartitionBucket*>(reinterpret_cas t<char*>(page) + kPageMetadataSize); | 592 PartitionBucket* bucket = reinterpret_cast<PartitionBucket*>(reinterpret_cas t<char*>(page) + kPageMetadataSize); |
| 570 page->freelistHead = 0; | 593 page->freelistHead = 0; |
| 571 page->nextPage = 0; | 594 page->nextPage = 0; |
| 572 page->bucket = bucket; | 595 page->bucket = bucket; |
| 573 page->numAllocatedSlots = 1; | 596 page->numAllocatedSlots = 1; |
| 574 page->numUnprovisionedSlots = 0; | 597 page->numUnprovisionedSlots = 0; |
| 575 page->pageOffset = 0; | 598 page->pageOffset = 0; |
| 576 page->freeCacheIndex = 0; | 599 page->freeCacheIndex = 0; |
| 577 | 600 |
| 578 bucket->activePagesHead = 0; | 601 bucket->activePagesHead = 0; |
| 579 bucket->freePagesHead = 0; | 602 bucket->freePagesHead = reinterpret_cast<PartitionPage*>(ptr + mapSize); |
|
Chris Evans
2014/03/05 07:57:04
I'm not a huge fan of this.
For each direct mappi
Jens Widell
2014/03/05 08:11:43
I certainly wasn't either. :-)
| |
| 580 bucket->slotSize = size; | 603 bucket->slotSize = size; |
| 581 bucket->numSystemPagesPerSlotSpan = 0; | 604 bucket->numSystemPagesPerSlotSpan = 0; |
| 582 bucket->numFullPages = 0; | 605 bucket->numFullPages = 0; |
| 583 | 606 |
| 607 ASSERT(size <= partitionDirectMapAvailableSize(page)); | |
| 608 | |
| 584 return ret; | 609 return ret; |
| 585 } | 610 } |
| 586 | 611 |
| 587 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) | 612 static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) |
| 588 { | 613 { |
| 589 size_t unmapSize = page->bucket->slotSize; | 614 size_t unmapSize = partitionDirectMapAvailableSize(page); |
| 615 | |
| 590 // Add on the size of the trailing guard page and preceeding partition | 616 // Add on the size of the trailing guard page and preceeding partition |
| 591 // page, then round up to allocation granularity. | 617 // page. |
| 592 unmapSize += kPartitionPageSize + kSystemPageSize; | 618 unmapSize += kPartitionPageSize + kSystemPageSize; |
| 593 unmapSize += kPageAllocationGranularityOffsetMask; | 619 |
| 594 unmapSize &= kPageAllocationGranularityBaseMask; | 620 ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); |
| 595 | 621 |
| 596 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); | 622 char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
| 597 // Account for the mapping starting a partition page before the actual | 623 // Account for the mapping starting a partition page before the actual |
| 598 // allocation address. | 624 // allocation address. |
| 599 ptr -= kPartitionPageSize; | 625 ptr -= kPartitionPageSize; |
| 600 | 626 |
| 601 freePages(ptr, unmapSize); | 627 freePages(ptr, unmapSize); |
| 602 } | 628 } |
| 603 | 629 |
| 604 void* partitionAllocSlowPath(PartitionRootBase* root, int flags, size_t size, Pa rtitionBucket* bucket) | 630 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; | 782 page->nextPage = bucket->activePagesHead; |
| 757 bucket->activePagesHead = page; | 783 bucket->activePagesHead = page; |
| 758 --bucket->numFullPages; | 784 --bucket->numFullPages; |
| 759 // Special case: for a partition page with just a single slot, it may | 785 // 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. | 786 // now be empty and we want to run it through the empty logic. |
| 761 if (UNLIKELY(page->numAllocatedSlots == 0)) | 787 if (UNLIKELY(page->numAllocatedSlots == 0)) |
| 762 partitionFreeSlowPath(page); | 788 partitionFreeSlowPath(page); |
| 763 } | 789 } |
| 764 } | 790 } |
| 765 | 791 |
| 792 bool partitionReallocDirectMappedInPlace(PartitionRootGeneric* root, void* ptr, size_t newSize) | |
| 793 { | |
| 794 newSize = partitionCookieSizeAdjustAdd(newSize); | |
| 795 ASSERT(partitionDirectMapSize(newSize) == newSize); | |
|
Chris Evans
2014/03/05 07:57:04
I think we also need newSize to be a multiple of k
Jens Widell
2014/03/05 08:11:43
The value returned by partitionDirectMapSize(size)
| |
| 796 | |
| 797 char* realPtr = static_cast<char*>(partitionCookieFreePointerAdjust(ptr)); | |
| 798 PartitionPage* page = partitionPointerToPage(realPtr); | |
| 799 PartitionBucket* bucket = page->bucket; | |
| 800 | |
| 801 // bucket->slotSize is the current size of the allocation. | |
| 802 // bucket->freePagesHead points to the first system page beyond what we | |
| 803 // first allocated; we can grow the allocation up to that point. | |
| 804 | |
| 805 ASSERT(partitionBucketIsDirectMapped(bucket)); | |
| 806 ASSERT(newSize != bucket->slotSize); | |
| 807 | |
| 808 if (newSize < bucket->slotSize) { | |
| 809 // Shrink by decommitting unneeded pages and making them inaccessible. | |
| 810 // TODO: maybe refuse if the new size is too much smaller? | |
| 811 size_t decommitSize = bucket->slotSize - newSize; | |
| 812 decommitSystemPages(realPtr + newSize, decommitSize); | |
| 813 setSystemPagesInaccessible(realPtr + newSize, decommitSize); | |
| 814 } else if (newSize <= partitionDirectMapAvailableSize(page)) { | |
| 815 // Grow within the actually allocated memory. Just need to make the | |
| 816 // pages accessible again. | |
| 817 size_t recommitSize = newSize - bucket->slotSize; | |
| 818 setSystemPagesAccessible(realPtr + bucket->slotSize, recommitSize); | |
| 819 | |
| 820 #ifndef NDEBUG | |
| 821 memset(realPtr + bucket->slotSize, kUninitializedByte, recommitSize); | |
| 822 #endif | |
| 823 } else { | |
| 824 // We can't perform the realloc in-place. | |
|
Chris Evans
2014/03/05 07:57:04
I think we can fill in this branch in the future (
| |
| 825 return false; | |
| 826 } | |
| 827 | |
| 828 #ifndef NDEBUG | |
| 829 // Write a new trailing cookie. | |
| 830 partitionCookieWriteValue(realPtr + newSize - kCookieSize); | |
| 831 #endif | |
| 832 | |
| 833 bucket->slotSize = newSize; | |
| 834 return true; | |
| 835 } | |
| 836 | |
| 766 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize) | 837 void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS ize) |
| 767 { | 838 { |
| 768 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 839 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 769 return realloc(ptr, newSize); | 840 return realloc(ptr, newSize); |
| 770 #else | 841 #else |
| 771 if (UNLIKELY(!ptr)) | 842 if (UNLIKELY(!ptr)) |
| 772 return partitionAllocGeneric(root, newSize); | 843 return partitionAllocGeneric(root, newSize); |
| 773 if (UNLIKELY(!newSize)) { | 844 if (UNLIKELY(!newSize)) { |
| 774 partitionFreeGeneric(root, ptr); | 845 partitionFreeGeneric(root, ptr); |
| 775 return 0; | 846 return 0; |
| 776 } | 847 } |
|
Chris Evans
2014/03/05 07:57:04
Can we just put a no nonsense RELEASE_ASSERT here?
| |
| 777 | 848 |
| 778 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr))); | 849 ASSERT(partitionPointerIsValid(partitionCookieFreePointerAdjust(ptr))); |
| 779 | 850 |
| 780 size_t actualNewSize = partitionAllocActualSize(root, newSize); | 851 size_t actualNewSize = partitionAllocActualSize(root, newSize); |
| 781 size_t actualOldSize = partitionAllocGetSize(ptr); | 852 size_t actualOldSize = partitionAllocGetSize(ptr); |
| 782 | 853 |
| 783 // TODO: note that tcmalloc will "ignore" a downsizing realloc() unless the | 854 // 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 | 855 // new size is a significant percentage smaller. We could do the same if we |
| 785 // determine it is a win. | 856 // determine it is a win. |
| 786 if (actualNewSize == actualOldSize) { | 857 if (actualNewSize == actualOldSize) { |
| 787 // Trying to allocate a block of size newSize would give us a block of | 858 // 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 | 859 // the same size as the one we've already got, so no point in doing |
| 789 // anything here. | 860 // 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; | 861 return ptr; |
| 793 } | 862 } |
| 794 | 863 |
| 864 if (partitionSizeIsDirectMapped(actualOldSize) && partitionSizeIsDirectMappe d(actualNewSize)) { | |
|
Chris Evans
2014/03/05 07:57:04
I actually think we might want to relax the second
Jens Widell
2014/03/05 08:11:43
The reason I didn't do that was to avoid having an
| |
| 865 // We may be able to perform the realloc in place by changing the | |
| 866 // accessibility of memory pages and, if reducing the size, decommitting | |
| 867 // them. | |
| 868 if (partitionReallocDirectMappedInPlace(root, ptr, actualNewSize)) | |
| 869 return ptr; | |
| 870 } | |
| 871 | |
| 795 // This realloc cannot be resized in-place. Sadness. | 872 // This realloc cannot be resized in-place. Sadness. |
| 796 void* ret = partitionAllocGeneric(root, newSize); | 873 void* ret = partitionAllocGeneric(root, newSize); |
| 797 size_t copySize = actualOldSize; | 874 size_t copySize = actualOldSize; |
| 798 if (newSize < copySize) | 875 if (newSize < copySize) |
| 799 copySize = newSize; | 876 copySize = newSize; |
| 800 | 877 |
| 801 memcpy(ret, ptr, copySize); | 878 memcpy(ret, ptr, copySize); |
| 802 partitionFreeGeneric(root, ptr); | 879 partitionFreeGeneric(root, ptr); |
| 803 return ret; | 880 return ret; |
| 804 #endif | 881 #endif |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 855 printf("total live: %zu bytes\n", totalLive); | 932 printf("total live: %zu bytes\n", totalLive); |
| 856 printf("total resident: %zu bytes\n", totalResident); | 933 printf("total resident: %zu bytes\n", totalResident); |
| 857 printf("total freeable: %zu bytes\n", totalFreeable); | 934 printf("total freeable: %zu bytes\n", totalFreeable); |
| 858 fflush(stdout); | 935 fflush(stdout); |
| 859 } | 936 } |
| 860 | 937 |
| 861 #endif // !NDEBUG | 938 #endif // !NDEBUG |
| 862 | 939 |
| 863 } // namespace WTF | 940 } // namespace WTF |
| 864 | 941 |
| OLD | NEW |