Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2230)

Unified Diff: Source/wtf/PartitionAlloc.cpp

Issue 136333002: PartitionAlloc: simplify PartitionPage structure some more. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fix bug. Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/wtf/PartitionAlloc.h ('k') | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/wtf/PartitionAlloc.cpp
diff --git a/Source/wtf/PartitionAlloc.cpp b/Source/wtf/PartitionAlloc.cpp
index dbb43fd913ab13adf8c0fde031255b00f71f75db..b4b4f6a1c7833ccad39775f938d058a0ef22977e 100644
--- a/Source/wtf/PartitionAlloc.cpp
+++ b/Source/wtf/PartitionAlloc.cpp
@@ -99,12 +99,6 @@ static size_t partitionBucketNumSystemPages(size_t size)
return bestPages;
}
-static ALWAYS_INLINE void partitionPageMarkFree(PartitionPage* page)
-{
- ASSERT(!partitionPageIsFree(page));
- page->flags |= kPartitionPageFlagFree;
-}
-
static void parititonAllocBaseInit(PartitionRootBase* root)
{
ASSERT(!root->initialized);
@@ -114,7 +108,6 @@ static void parititonAllocBaseInit(PartitionRootBase* root)
PartitionRootBase::gInitialized = true;
// We mark the seed page as free to make sure it is skipped by our
// logic to find a new active page.
- partitionPageMarkFree(&PartitionRootBase::gSeedPage);
PartitionRootBase::gPagedBucket.activePagesHead = &PartitionRootGeneric::gSeedPage;
}
spinLockUnlock(&PartitionRootBase::gInitializedLock);
@@ -243,9 +236,9 @@ static bool partitionAllocShutdownBucket(PartitionBucket* bucket)
bool noLeaks = !bucket->numFullPages;
PartitionPage* page = bucket->activePagesHead;
while (page) {
- if (!partitionPageIsFree(page) && page->numAllocatedSlots)
+ if (page->numAllocatedSlots)
noLeaks = false;
- page = page->activePageNext;
+ page = page->nextPage;
}
return noLeaks;
@@ -393,13 +386,13 @@ static ALWAYS_INLINE size_t partitionBucketPartitionPages(const PartitionBucket*
static ALWAYS_INLINE void partitionPageReset(PartitionPage* page, PartitionBucket* bucket)
{
ASSERT(page != &PartitionRootGeneric::gSeedPage);
- page->flags = 0;
page->numAllocatedSlots = 0;
page->numUnprovisionedSlots = partitionBucketSlots(bucket);
ASSERT(page->numUnprovisionedSlots);
page->bucket = bucket;
+ page->nextPage = 0;
// NULLing the freelist is not strictly necessary but it makes an ASSERT in partitionPageFillFreelist simpler.
- partitionPageSetFreelistHead(page, 0);
+ page->freelistHead = 0;
page->pageOffset = 0;
size_t numPartitionPages = partitionBucketPartitionPages(bucket);
size_t i;
@@ -421,7 +414,8 @@ static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page
// (The third state is "on the freelist". If we have a non-empty freelist, we should not get here.)
ASSERT(numSlots + page->numAllocatedSlots == partitionBucketSlots(bucket));
// Similarly, make explicitly sure that the freelist is empty.
- ASSERT(!partitionPageFreelistHead(page));
+ ASSERT(!page->freelistHead);
+ ASSERT(page->numAllocatedSlots >= 0);
size_t size = bucket->slotSize;
char* base = reinterpret_cast<char*>(partitionPageToPointer(page));
@@ -458,7 +452,7 @@ static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page
if (LIKELY(numNewFreelistEntries)) {
char* freelistPointer = firstFreelistPointer;
PartitionFreelistEntry* entry = reinterpret_cast<PartitionFreelistEntry*>(freelistPointer);
- partitionPageSetFreelistHead(page, entry);
+ page->freelistHead = entry;
while (--numNewFreelistEntries) {
freelistPointer += size;
PartitionFreelistEntry* nextEntry = reinterpret_cast<PartitionFreelistEntry*>(freelistPointer);
@@ -467,7 +461,7 @@ static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page
}
entry->next = partitionFreelistMask(0);
} else {
- partitionPageSetFreelistHead(page, 0);
+ page->freelistHead = 0;
}
return returnObject;
}
@@ -481,47 +475,49 @@ static ALWAYS_INLINE char* partitionPageAllocAndFillFreelist(PartitionPage* page
static ALWAYS_INLINE bool partitionSetNewActivePage(PartitionBucket* bucket, bool currentPageOk)
{
PartitionPage* page = bucket->activePagesHead;
+ if (page == &PartitionRootBase::gSeedPage) {
+ ASSERT(!page->nextPage);
+ return false;
+ }
+
if (!currentPageOk)
- page = page->activePageNext;
+ page = page->nextPage;
- for (; page; page = page->activePageNext) {
+ PartitionPage* nextPage = 0;
+ for (; page; page = nextPage) {
+ nextPage = page->nextPage;
ASSERT(page->bucket == bucket->activePagesHead->bucket);
-
- // Skip over free pages. We need this check first so that we can trust
- // that the page union field really containts a freelist pointer.
- if (UNLIKELY(partitionPageIsFree(page)))
- continue;
+ ASSERT(page != bucket->freePagesHead);
+ ASSERT(!bucket->freePagesHead || page != bucket->freePagesHead->nextPage);
// Page is usable if it has something on the freelist, or unprovisioned
// slots that can be turned into a freelist.
- if (LIKELY(partitionPageFreelistHead(page) != 0) || LIKELY(page->numUnprovisionedSlots)) {
+ if (LIKELY(page->freelistHead != 0) || LIKELY(page->numUnprovisionedSlots)) {
bucket->activePagesHead = page;
return true;
}
- // If we get here, we found a full page. Skip over it too, and also tag
- // it as full (via a negative value). We need it tagged so that free'ing
- // can tell, and move it back into the active page list.
- ASSERT(page->numAllocatedSlots == static_cast<int>(partitionBucketSlots(bucket)));
- page->numAllocatedSlots = -page->numAllocatedSlots;
- ++bucket->numFullPages;
+
+ ASSERT(page->numAllocatedSlots >= 0);
+ if (LIKELY(page->numAllocatedSlots == 0)) {
+ // We hit a free page, so shepherd it on to the free page list.
+ page->nextPage = bucket->freePagesHead;
+ bucket->freePagesHead = page;
+ } else {
+ // If we get here, we found a full page. Skip over it too, and also
+ // tag it as full (via a negative value). We need it tagged so that
+ // free'ing can tell, and move it back into the active page list.
+ ASSERT(page->numAllocatedSlots == static_cast<int>(partitionBucketSlots(bucket)));
+ page->numAllocatedSlots = -page->numAllocatedSlots;
+ ++bucket->numFullPages;
+ // Not necessary but might help stop accidents.
+ page->nextPage = 0;
+ }
}
- bucket->activePagesHead->activePageNext = 0;
+ bucket->activePagesHead->nextPage = 0;
return false;
}
-static ALWAYS_INLINE void partitionPageSetFreePageNext(PartitionPage* page, PartitionPage* nextFree)
-{
- ASSERT(partitionPageIsFree(page));
- page->u.freePageNext = nextFree;
-}
-
-static ALWAYS_INLINE PartitionPage* partitionPageFreePageNext(PartitionPage* page)
-{
- ASSERT(partitionPageIsFree(page));
- return page->u.freePageNext;
-}
-
static ALWAYS_INLINE bool partitionBucketIsPaged(PartitionBucket* bucket)
{
return !bucket->slotSize;
@@ -530,7 +526,7 @@ static ALWAYS_INLINE bool partitionBucketIsPaged(PartitionBucket* bucket)
void* partitionAllocSlowPath(PartitionRootBase* root, size_t size, PartitionBucket* bucket)
{
// The slow path is called when the freelist is empty.
- ASSERT(!partitionPageFreelistHead(bucket->activePagesHead));
+ ASSERT(!bucket->activePagesHead->freelistHead);
// For the partitionAllocGeneric API, we have a bunch of buckets marked
// as special cases. We bounce them through to the slow path so that we
@@ -547,9 +543,9 @@ void* partitionAllocSlowPath(PartitionRootBase* root, size_t size, PartitionBuck
// Change active page, accepting the current page as a candidate.
if (LIKELY(partitionSetNewActivePage(bucket, true))) {
PartitionPage* newPage = bucket->activePagesHead;
- if (LIKELY(partitionPageFreelistHead(newPage) != 0)) {
- PartitionFreelistEntry* ret = partitionPageFreelistHead(newPage);
- partitionPageSetFreelistHead(newPage, partitionFreelistMask(ret->next));
+ if (LIKELY(newPage->freelistHead != 0)) {
+ PartitionFreelistEntry* ret = newPage->freelistHead;
+ newPage->freelistHead = partitionFreelistMask(ret->next);
newPage->numAllocatedSlots++;
return ret;
}
@@ -561,7 +557,10 @@ void* partitionAllocSlowPath(PartitionRootBase* root, size_t size, PartitionBuck
PartitionPage* newPage = bucket->freePagesHead;
if (LIKELY(newPage != 0)) {
ASSERT(newPage != &PartitionRootGeneric::gSeedPage);
- bucket->freePagesHead = partitionPageFreePageNext(newPage);
+ ASSERT(!newPage->freelistHead);
+ ASSERT(!newPage->numAllocatedSlots);
+ ASSERT(!newPage->numUnprovisionedSlots);
+ bucket->freePagesHead = newPage->nextPage;
} else {
// Third. If we get here, we need a brand new page.
size_t numPartitionPages = partitionBucketPartitionPages(bucket);
@@ -570,23 +569,23 @@ void* partitionAllocSlowPath(PartitionRootBase* root, size_t size, PartitionBuck
newPage = partitionPointerToPageNoAlignmentCheck(rawNewPage);
}
- newPage->activePageNext = 0;
partitionPageReset(newPage, bucket);
bucket->activePagesHead = newPage;
return partitionPageAllocAndFillFreelist(newPage);
}
-static ALWAYS_INLINE void partitionPutPageOnFreelist(PartitionPage* page, PartitionBucket* bucket)
+static ALWAYS_INLINE void partitionFreePage(PartitionPage* page)
{
+ ASSERT(page->freelistHead);
+ ASSERT(!page->numAllocatedSlots);
partitionUnusePage(page);
- // We actually leave the freed page in the active list as well as
- // putting it on the free list. We'll evict it from the active list soon
- // enough in partitionAllocSlowPath. Pulling this trick enables us to
- // use a singly-linked page list for all cases, which is critical in
- // keeping the page metadata structure down to 32-bytes in size.
- partitionPageMarkFree(page);
- partitionPageSetFreePageNext(page, bucket->freePagesHead);
- bucket->freePagesHead = page;
+ // We actually leave the freed page in the active list. We'll sweep it on
+ // to the free page list when we next walk the active page list. Pulling
+ // this trick enables us to use a singly-linked page list for all cases,
+ // which is critical in keeping the page metadata structure down to 32
+ // bytes in size.
+ page->freelistHead = 0;
+ page->numUnprovisionedSlots = 0;
}
void partitionFreeSlowPath(PartitionPage* page)
@@ -605,11 +604,16 @@ void partitionFreeSlowPath(PartitionPage* page)
// a repeating state change between 0 and 1 objects of a given
// size allocated; and each state change incurs either a system
// call or a page fault, or more.
- ASSERT(!page->activePageNext);
+ ASSERT(!page->nextPage);
return;
}
+ // Link the to-be-freed page back in after the new current page, to
+ // avoid losing a reference to it.
+ PartitionPage* currentPage = bucket->activePagesHead;
+ page->nextPage = currentPage->nextPage;
+ currentPage->nextPage = page;
}
- partitionPutPageOnFreelist(page, bucket);
+ partitionFreePage(page);
} else {
// Ensure that the page is full. That's the only valid case if we
// arrive here.
@@ -620,7 +624,7 @@ void partitionFreeSlowPath(PartitionPage* page)
// 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.
- page->activePageNext = bucket->activePagesHead;
+ page->nextPage = bucket->activePagesHead;
bucket->activePagesHead = page;
--bucket->numFullPages;
// Special case: for a partition page with just a single slot, it may
@@ -731,7 +735,7 @@ void partitionDumpStats(const PartitionRoot& root)
PartitionPage* freePages = bucket.freePagesHead;
while (freePages) {
++numFreePages;
- freePages = partitionPageFreePageNext(freePages);
+ freePages = freePages->nextPage;
}
size_t bucketSlotSize = bucket.slotSize;
size_t bucketNumSlots = partitionBucketSlots(&bucket);
@@ -754,7 +758,7 @@ void partitionDumpStats(const PartitionRoot& root)
if (!page->numAllocatedSlots)
numFreeableBytes += pageBytesResident;
}
- page = page->activePageNext;
+ page = page->nextPage;
} while (page != bucket.activePagesHead);
totalLive += numActiveBytes;
totalResident += numResidentBytes;
« no previous file with comments | « Source/wtf/PartitionAlloc.h ('k') | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698