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; |