Index: Source/wtf/PartitionAlloc.cpp |
diff --git a/Source/wtf/PartitionAlloc.cpp b/Source/wtf/PartitionAlloc.cpp |
index e1376d31d15f73e398eda6597064477621cbaf70..cb5dc0a85a4f984a9e5ae3df27e4fd4afe4dcf53 100644 |
--- a/Source/wtf/PartitionAlloc.cpp |
+++ b/Source/wtf/PartitionAlloc.cpp |
@@ -31,7 +31,6 @@ |
#include "config.h" |
#include "wtf/PartitionAlloc.h" |
-#include "wtf/PageAllocator.h" |
#include <string.h> |
#ifndef NDEBUG |
@@ -285,16 +284,16 @@ static ALWAYS_INLINE void partitionUnlinkPage(PartitionPageHeader* page) |
page->prev->next = page->next; |
} |
-static ALWAYS_INLINE void partitionLinkPage(PartitionPageHeader* newPage, PartitionPageHeader* prevPage) |
+static ALWAYS_INLINE void partitionLinkPageBefore(PartitionPageHeader* newPage, PartitionPageHeader* nextPage) |
{ |
- ASSERT(prevPage->prev->next == prevPage); |
- ASSERT(prevPage->next->prev == prevPage); |
+ ASSERT(nextPage->prev->next == nextPage); |
+ ASSERT(nextPage->next->prev == nextPage); |
- newPage->prev = prevPage; |
- newPage->next = prevPage->next; |
+ newPage->next = nextPage; |
+ newPage->prev = nextPage->prev; |
- prevPage->next->prev = newPage; |
- prevPage->next = newPage; |
+ nextPage->prev->next = newPage; |
+ nextPage->prev = newPage; |
} |
void* partitionAllocSlowPath(PartitionBucket* bucket) |
@@ -304,8 +303,8 @@ void* partitionAllocSlowPath(PartitionBucket* bucket) |
PartitionPageHeader* next = page->next; |
ASSERT(page == &bucket->root->seedPage || (page->bucket == bucket && next->bucket == bucket)); |
- // First, see if the partition page still has capacity and if so, fill out |
- // the freelist a little more. |
+ // First, see if the current partition page still has capacity and if so, |
+ // fill out the freelist a little more. |
if (LIKELY(page->numUnprovisionedSlots)) |
return partitionPageAllocAndFillFreelist(page); |
@@ -322,6 +321,10 @@ void* partitionAllocSlowPath(PartitionBucket* bucket) |
next->numAllocatedSlots++; |
return ret; |
} |
+ if (LIKELY(next->numUnprovisionedSlots)) { |
+ bucket->currPage = next; |
+ return partitionPageAllocAndFillFreelist(next); |
+ } |
// Pull this page out of the non-full page list, since it has no free |
// slots. |
// This tags the page as full so that free'ing can tell, and move |
@@ -334,7 +337,18 @@ void* partitionAllocSlowPath(PartitionBucket* bucket) |
next = next->next; |
} |
- // Second, look in our list of freed but reserved pages. |
+ // After we've considered and rejected every partition page in the list, |
+ // we should by definition have a single self-linked page left. We will |
+ // replace this single page with the new page we choose. |
+ ASSERT(page == page->next); |
+ ASSERT(page == page->prev); |
+ ASSERT(page == &bucket->root->seedPage || page->numAllocatedSlots == partitionBucketSlots(bucket)); |
+ if (LIKELY(page != &bucket->root->seedPage)) { |
+ page->numAllocatedSlots = -page->numAllocatedSlots; |
+ ++bucket->numFullPages; |
+ } |
+ |
+ // Third, look in our list of freed but reserved pages. |
PartitionPageHeader* newPage; |
PartitionFreepagelistEntry* pagelist = bucket->freePages; |
if (LIKELY(pagelist != 0)) { |
@@ -342,21 +356,13 @@ void* partitionAllocSlowPath(PartitionBucket* bucket) |
bucket->freePages = pagelist->next; |
partitionFree(pagelist); |
ASSERT(page != &bucket->root->seedPage); |
- partitionLinkPage(newPage, page); |
} else { |
- // Third. If we get here, we need a brand new page. |
+ // Fourth. If we get here, we need a brand new page. |
newPage = partitionAllocPage(bucket->root); |
- if (UNLIKELY(page == &bucket->root->seedPage)) { |
- // If this is the first page allocation to this bucket, then |
- // fully replace the seed page. This avoids pointlessly iterating |
- // over it. |
- newPage->prev = newPage; |
- newPage->next = newPage; |
- } else { |
- partitionLinkPage(newPage, page); |
- } |
} |
+ newPage->prev = newPage; |
+ newPage->next = newPage; |
bucket->currPage = newPage; |
partitionPageReset(newPage, bucket); |
return partitionPageAllocAndFillFreelist(newPage); |
@@ -367,10 +373,14 @@ void partitionFreeSlowPath(PartitionPageHeader* page) |
PartitionBucket* bucket = page->bucket; |
if (LIKELY(page->numAllocatedSlots == 0)) { |
// Page became fully unused. |
- // If it's the current page, leave it be so that we don't bounce a page |
- // onto the free page list and immediately back out again. |
- if (LIKELY(page == bucket->currPage)) |
- return; |
+ // If it's the current page, change it! |
+ if (LIKELY(page == bucket->currPage)) { |
+ if (UNLIKELY(page->next == page)) { |
+ // For now, we do not free the last partition page in a bucket. |
+ return; |
+ } |
+ bucket->currPage = page->next; |
+ } |
partitionUnlinkPage(page); |
partitionUnusePage(page); |
@@ -380,8 +390,11 @@ void partitionFreeSlowPath(PartitionPageHeader* page) |
bucket->freePages = entry; |
} else { |
// Fully used page became partially used. It must be put back on the |
- // non-full page list. |
- partitionLinkPage(page, bucket->currPage); |
+ // non-full page list. Also make it the current page to increase the |
+ // chances of it being filled up again. The old current page will be |
+ // the next page. |
+ partitionLinkPageBefore(page, bucket->currPage); |
+ bucket->currPage = page; |
page->numAllocatedSlots = -page->numAllocatedSlots - 2; |
ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1); |
--bucket->numFullPages; |