Chromium Code Reviews| Index: Source/wtf/PartitionAlloc.cpp |
| diff --git a/Source/wtf/PartitionAlloc.cpp b/Source/wtf/PartitionAlloc.cpp |
| index e62a9a66235e23719cd2c5eb30ae29ed76cfdc52..01c8144e7e483a4a472d7095897a8d3dc8342ee4 100644 |
| --- a/Source/wtf/PartitionAlloc.cpp |
| +++ b/Source/wtf/PartitionAlloc.cpp |
| @@ -524,6 +524,29 @@ static ALWAYS_INLINE bool partitionSetNewActivePage(PartitionPage* page) |
| return false; |
| } |
| +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
|
| +{ |
| + // Return the size of the mapping, *not* including space where meta-data is |
| + // stored, and *not* including one trailing inaccessible system page; IOW |
| + // the size of the area available for the actual allocation. Some of the |
| + // pages at the end of this memory range may have been decommitted and made |
| + // inaccessible by a partitionReallocGeneric() call. |
| + // |
| + // The value of bucket->slotSize is size of the current allocation. |
| + |
| + PartitionBucket* bucket = page->bucket; |
| + |
| + ASSERT(partitionBucketIsDirectMapped(bucket)); |
| + ASSERT(bucket != &PartitionRootBase::gPagedBucket); |
| + |
| + char* ptr = static_cast<char*>(partitionPageToPointer(page)); |
| + char* endPtr = reinterpret_cast<char*>(bucket->freePagesHead) - kSystemPageSize; |
| + |
| + size_t size = endPtr - ptr; |
| + ASSERT(bucket->slotSize <= size); |
| + return size; |
| +} |
| + |
| static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags, size_t size) |
| { |
| size = partitionDirectMapSize(size); |
| @@ -576,22 +599,25 @@ static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags |
| page->freeCacheIndex = 0; |
| bucket->activePagesHead = 0; |
| - bucket->freePagesHead = 0; |
| + 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. :-)
|
| bucket->slotSize = size; |
| bucket->numSystemPagesPerSlotSpan = 0; |
| bucket->numFullPages = 0; |
| + ASSERT(size <= partitionDirectMapAvailableSize(page)); |
| + |
| return ret; |
| } |
| static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) |
| { |
| - size_t unmapSize = page->bucket->slotSize; |
| + size_t unmapSize = partitionDirectMapAvailableSize(page); |
| + |
| // Add on the size of the trailing guard page and preceeding partition |
| - // page, then round up to allocation granularity. |
| + // page. |
| unmapSize += kPartitionPageSize + kSystemPageSize; |
| - unmapSize += kPageAllocationGranularityOffsetMask; |
| - unmapSize &= kPageAllocationGranularityBaseMask; |
| + |
| + ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); |
| char* ptr = reinterpret_cast<char*>(partitionPageToPointer(page)); |
| // Account for the mapping starting a partition page before the actual |
| @@ -763,6 +789,51 @@ void partitionFreeSlowPath(PartitionPage* page) |
| } |
| } |
| +bool partitionReallocDirectMappedInPlace(PartitionRootGeneric* root, void* ptr, size_t newSize) |
| +{ |
| + newSize = partitionCookieSizeAdjustAdd(newSize); |
| + 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)
|
| + |
| + char* realPtr = static_cast<char*>(partitionCookieFreePointerAdjust(ptr)); |
| + PartitionPage* page = partitionPointerToPage(realPtr); |
| + PartitionBucket* bucket = page->bucket; |
| + |
| + // bucket->slotSize is the current size of the allocation. |
| + // bucket->freePagesHead points to the first system page beyond what we |
| + // first allocated; we can grow the allocation up to that point. |
| + |
| + ASSERT(partitionBucketIsDirectMapped(bucket)); |
| + ASSERT(newSize != bucket->slotSize); |
| + |
| + if (newSize < bucket->slotSize) { |
| + // Shrink by decommitting unneeded pages and making them inaccessible. |
| + // TODO: maybe refuse if the new size is too much smaller? |
| + size_t decommitSize = bucket->slotSize - newSize; |
| + decommitSystemPages(realPtr + newSize, decommitSize); |
| + setSystemPagesInaccessible(realPtr + newSize, decommitSize); |
| + } else if (newSize <= partitionDirectMapAvailableSize(page)) { |
| + // Grow within the actually allocated memory. Just need to make the |
| + // pages accessible again. |
| + size_t recommitSize = newSize - bucket->slotSize; |
| + setSystemPagesAccessible(realPtr + bucket->slotSize, recommitSize); |
| + |
| +#ifndef NDEBUG |
| + memset(realPtr + bucket->slotSize, kUninitializedByte, recommitSize); |
| +#endif |
| + } else { |
| + // 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 (
|
| + return false; |
| + } |
| + |
| +#ifndef NDEBUG |
| + // Write a new trailing cookie. |
| + partitionCookieWriteValue(realPtr + newSize - kCookieSize); |
| +#endif |
| + |
| + bucket->slotSize = newSize; |
| + return true; |
| +} |
| + |
| void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newSize) |
| { |
| #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| @@ -787,11 +858,17 @@ void* partitionReallocGeneric(PartitionRootGeneric* root, void* ptr, size_t newS |
| // Trying to allocate a block of size newSize would give us a block of |
| // the same size as the one we've already got, so no point in doing |
| // anything here. |
| - // TODO: for an upsize or downsize on a direct mapped allocation, we |
| - // should really try and resize it in-place. |
| return ptr; |
| } |
| + if (partitionSizeIsDirectMapped(actualOldSize) && partitionSizeIsDirectMapped(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
|
| + // We may be able to perform the realloc in place by changing the |
| + // accessibility of memory pages and, if reducing the size, decommitting |
| + // them. |
| + if (partitionReallocDirectMappedInPlace(root, ptr, actualNewSize)) |
| + return ptr; |
| + } |
| + |
| // This realloc cannot be resized in-place. Sadness. |
| void* ret = partitionAllocGeneric(root, newSize); |
| size_t copySize = actualOldSize; |