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

Unified Diff: third_party/WebKit/Source/platform/heap/HeapPage.cpp

Issue 2015173003: Address ThreadHeap::willObjectBeLazilySwept() corner case. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 7 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
Index: third_party/WebKit/Source/platform/heap/HeapPage.cpp
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index 18e7458187c12776d8922f17bca8914ea4504b28..003ebe770db88ee992d7f8b0c29f9f14ba922aba 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -49,6 +49,7 @@
#include "wtf/CurrentTime.h"
#include "wtf/LeakAnnotations.h"
#include "wtf/PassOwnPtr.h"
+#include "wtf/TemporaryChange.h"
#include "wtf/allocator/PageAllocator.h"
#include "wtf/allocator/Partitions.h"
@@ -315,6 +316,13 @@ bool BaseArena::lazySweepWithDeadline(double deadlineSeconds)
ASSERT(getThreadState()->sweepForbidden());
ASSERT(!getThreadState()->isMainThread() || ScriptForbiddenScope::isScriptForbidden());
+ NormalPageArena* normalArena = nullptr;
+ if (m_firstUnsweptPage && !m_firstUnsweptPage->isLargeObjectPage()) {
haraken 2016/05/31 05:41:16 Why is it enough to check if the first unswept pag
sof 2016/05/31 07:24:09 How can an arena contain a mixture of large and no
+ // Mark this NormalPageArena as being lazily swept.
+ NormalPage* normalPage = reinterpret_cast<NormalPage*>(m_firstUnsweptPage);
+ normalArena = normalPage->arenaForNormalPage();
+ normalArena->setIsLazySweeping(true);
+ }
int pageCount = 1;
while (m_firstUnsweptPage) {
sweepUnsweptPage();
@@ -322,12 +330,16 @@ bool BaseArena::lazySweepWithDeadline(double deadlineSeconds)
if (deadlineSeconds <= monotonicallyIncreasingTime()) {
// Deadline has come.
ThreadHeap::reportMemoryUsageForTracing();
+ if (normalArena)
+ normalArena->setIsLazySweeping(false);
return !m_firstUnsweptPage;
}
}
pageCount++;
}
ThreadHeap::reportMemoryUsageForTracing();
+ if (normalArena)
+ normalArena->setIsLazySweeping(false);
return true;
}
@@ -353,12 +365,72 @@ Address BaseArena::allocateLargeObject(size_t allocationSize, size_t gcInfoIndex
return largeObject;
}
+bool BaseArena::willObjectBeLazilySwept(BasePage* page, void* objectPointer) const
+{
+ // If not on the current page being (potentially) lazily swept, |objectPointer|
+ // is an unmarked, sweepable object.
+ if (page != m_firstUnsweptPage)
+ return true;
+
+ DCHECK(!page->isLargeObjectPage());
+ // Check if the arena is currently being lazily swept.
+ NormalPage* normalPage = reinterpret_cast<NormalPage*>(page);
+ NormalPageArena* normalArena = normalPage->arenaForNormalPage();
+ if (!normalArena->isLazySweeping())
+ return true;
+
+ // Rare special case: unmarked object is on the page being lazily swept,
+ // and a finalizer for an object on that page calls ThreadHeap::willObjectBeLazilySwept().
+ //
+ // Need to determine if |objectPointer| represents a live (unmarked) object or an
+ // unmarked object that will be lazily swept later. As lazy page sweeping
+ // doesn't record a frontier pointer representing how far along it is, the
+ // page is scanned from the start, skipping past freed & unmarked regions.
+ //
+ // If no marked objects are encountered before |objectPointer|, we know
+ // that the finalizing object calling willObjectBeLazilySwept() comes later,
+ // and |objectPointer| has been deemed to be alive already (=> it won't be swept.)
+ //
+ // If a marked object is encountered before |objectPointer|, it will
+ // not have been lazily swept past already. Hence it represents an unmarked,
+ // sweepable object.
+ //
+ // As willObjectBeLazilySwept() is used rarely and it happening to be
+ // used while runnning a finalizer on the page being lazily swept is
+ // even rarer, the page scan is considered acceptable and something
+ // really wanted -- willObjectBeLazilySwept()'s result can be trusted.
+ Address pageEnd = normalPage->payloadEnd();
+ for (Address headerAddress = normalPage->payload(); headerAddress < pageEnd; ) {
haraken 2016/05/30 23:54:49 Instead of scanning the entire page, it would be b
sof 2016/05/31 05:13:23 You can make trade offs like that, i.e., take the
haraken 2016/05/31 05:26:38 Yeah, that makes sense. The reason I didn't want t
+ HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAddress);
+ size_t size = header->size();
+ // Scan made it to |objectPointer| without encountering any marked objects.
+ // => lazy sweep will have processed this unmarked, but live, object.
+ // => |objectPointer| will not be lazily swept.
+ //
+ // Notice that |objectPointer| might be pointer to a GarbageCollectedMixin,
+ // hence using fromPayload() to derive the HeapObjectHeader isn't possible
+ // (and use its value to check if |headerAddress| is equal to it.)
+ if (headerAddress > objectPointer)
+ return false;
+ if (!header->isFree() && header->isMarked()) {
haraken 2016/05/30 23:54:49 Hmm, I don't fully understand why this check is do
sof 2016/05/31 05:13:23 That won't work as you could be scanning freelist
haraken 2016/05/31 05:26:38 Sorry, I meant: for (/* scan the page */) { if
sof 2016/05/31 05:32:25 No, we already know that objectPointer is unmarked
haraken 2016/05/31 05:41:16 OK. Do you need to check !header->isFree()? If hea
+ // There must be a marked object on this page and the one located must
+ // have room after it for the unmarked |objectPointer| object.
+ DCHECK(headerAddress + size < pageEnd);
+ return true;
+ }
+ headerAddress += size;
+ }
+ NOTREACHED();
+ return true;
+}
+
NormalPageArena::NormalPageArena(ThreadState* state, int index)
: BaseArena(state, index)
, m_currentAllocationPoint(nullptr)
, m_remainingAllocationSize(0)
, m_lastRemainingAllocationSize(0)
, m_promptlyFreedSize(0)
+ , m_isLazySweeping(false)
{
clearFreeLists();
}
@@ -621,6 +693,7 @@ bool NormalPageArena::shrinkObject(HeapObjectHeader* header, size_t newSize)
Address NormalPageArena::lazySweepPages(size_t allocationSize, size_t gcInfoIndex)
{
ASSERT(!hasCurrentAllocationArea());
+ TemporaryChange<bool> isLazySweeping(m_isLazySweeping, true);
Address result = nullptr;
while (m_firstUnsweptPage) {
BasePage* page = m_firstUnsweptPage;

Powered by Google App Engine
This is Rietveld 408576698