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

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

Issue 2570483002: Revert of Simple BlinkGC heap compaction. (Closed)
Patch Set: Created 4 years 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/HeapCompact.cpp
diff --git a/third_party/WebKit/Source/platform/heap/HeapCompact.cpp b/third_party/WebKit/Source/platform/heap/HeapCompact.cpp
deleted file mode 100644
index 43f2d2283ef72598229a152879bd69bbc001aa69..0000000000000000000000000000000000000000
--- a/third_party/WebKit/Source/platform/heap/HeapCompact.cpp
+++ /dev/null
@@ -1,479 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "platform/heap/HeapCompact.h"
-
-#include "platform/RuntimeEnabledFeatures.h"
-#include "platform/heap/Heap.h"
-#include "platform/heap/SparseHeapBitmap.h"
-#include "wtf/CurrentTime.h"
-#include "wtf/HashMap.h"
-#include "wtf/HashSet.h"
-#include "wtf/Vector.h"
-
-namespace blink {
-
-bool HeapCompact::s_forceCompactionGC = false;
-
-// The real worker behind heap compaction, recording references to movable
-// objects ("slots".) When the objects end up being compacted and moved,
-// relocate() will adjust the slots to point to the new location of the
-// object along with handling fixups for interior pointers.
-//
-// The "fixups" object is created and maintained for the lifetime of one
-// heap compaction-enhanced GC.
-class HeapCompact::MovableObjectFixups final {
- public:
- static std::unique_ptr<MovableObjectFixups> create() {
- return WTF::wrapUnique(new MovableObjectFixups);
- }
-
- ~MovableObjectFixups() {}
-
- // For the arenas being compacted, record all pages belonging to them.
- // This is needed to handle 'interior slots', pointers that themselves
- // can move (independently from the reference the slot points to.)
- void addCompactingPage(BasePage* page) {
- DCHECK(!page->isLargeObjectPage());
- m_relocatablePages.add(page);
- }
-
- void addInteriorFixup(MovableReference* slot) {
- auto it = m_interiorFixups.find(slot);
- // Ephemeron fixpoint iterations may cause repeated registrations.
- if (UNLIKELY(it != m_interiorFixups.end())) {
- DCHECK(!it->value);
- return;
- }
- m_interiorFixups.add(slot, nullptr);
- LOG_HEAP_COMPACTION("Interior slot: %p\n", slot);
- Address slotAddress = reinterpret_cast<Address>(slot);
- if (!m_interiors) {
- m_interiors = SparseHeapBitmap::create(slotAddress);
- return;
- }
- m_interiors->add(slotAddress);
- }
-
- void add(MovableReference* slot) {
- MovableReference reference = *slot;
- BasePage* refPage = pageFromObject(reference);
- // Nothing to compact on a large object's page.
- if (refPage->isLargeObjectPage())
- return;
-
-#if DCHECK_IS_ON()
- DCHECK(HeapCompact::isCompactableArena(refPage->arena()->arenaIndex()));
- auto it = m_fixups.find(reference);
- DCHECK(it == m_fixups.end() || it->value == slot);
-#endif
-
- // TODO: when updateHeapResidency() becomes more discriminating about
- // leaving out arenas that aren't worth compacting, a check for
- // isCompactingArena() would be appropriate here, leaving early if
- // |refPage|'s arena isn't in the set.
-
- m_fixups.add(reference, slot);
-
- // Note: |slot| will reside outside the Oilpan heap if it is a
- // PersistentHeapCollectionBase. Hence pageFromObject() cannot be
- // used, as it sanity checks the |BasePage| it returns. Simply
- // derive the raw BasePage address here and check if it is a member
- // of the compactable and relocatable page address set.
- Address slotAddress = reinterpret_cast<Address>(slot);
- BasePage* slotPage = reinterpret_cast<BasePage*>(
- blinkPageAddress(slotAddress) + blinkGuardPageSize);
- if (LIKELY(!m_relocatablePages.contains(slotPage)))
- return;
-#if ENABLE(ASSERT)
- slotPage->contains(slotAddress);
-#endif
- // Unlikely case, the slot resides on a compacting arena's page.
- // => It is an 'interior slot' (interior to a movable backing store.)
- // Record it as an interior slot, which entails:
- //
- // - Storing it in the interior map, which maps the slot to
- // its (eventual) location. Initially nullptr.
- // - Mark it as being interior pointer within the page's
- // "interior" bitmap. This bitmap is used when moving a backing
- // store, quickly/ier checking if interior slots will have to
- // be additionally redirected.
- addInteriorFixup(slot);
- }
-
- void addFixupCallback(MovableReference reference,
- MovingObjectCallback callback,
- void* callbackData) {
- DCHECK(!m_fixupCallbacks.contains(reference));
- m_fixupCallbacks.add(reference, std::pair<void*, MovingObjectCallback>(
- callbackData, callback));
- }
-
- void relocateInteriorFixups(Address from, Address to, size_t size) {
- SparseHeapBitmap* range = m_interiors->hasRange(from, size);
- if (LIKELY(!range))
- return;
-
- // Scan through the payload, looking for interior pointer slots
- // to adjust. If the backing store of such an interior slot hasn't
- // been moved already, update the slot -> real location mapping.
- // When the backing store is eventually moved, it'll use that location.
- //
- for (size_t offset = 0; offset < size; offset += sizeof(void*)) {
- if (!range->isSet(from + offset))
- continue;
- MovableReference* slot =
- reinterpret_cast<MovableReference*>(from + offset);
- auto it = m_interiorFixups.find(slot);
- if (it == m_interiorFixups.end())
- continue;
-
- // TODO: with the right sparse bitmap representation, it could be possible
- // to quickly determine if we've now stepped past the last address
- // that needed fixup in [address, address + size). Breaking out of this
- // loop might be worth doing for hash table backing stores with a very
- // low load factor. But interior fixups are rare.
-
- // If |slot|'s mapping is set, then the slot has been adjusted already.
- if (it->value)
- continue;
- Address fixup = to + offset;
- LOG_HEAP_COMPACTION("Range interior fixup: %p %p %p\n", from + offset,
- it->value, fixup);
- // Fill in the relocated location of the original slot at |slot|.
- // when the backing store corresponding to |slot| is eventually
- // moved/compacted, it'll update |to + offset| with a pointer to the
- // moved backing store.
- m_interiorFixups.set(slot, fixup);
- }
- }
-
- void relocate(Address from, Address to) {
- auto it = m_fixups.find(from);
- DCHECK(it != m_fixups.end());
-#if DCHECK_IS_ON()
- BasePage* fromPage = pageFromObject(from);
- DCHECK(m_relocatablePages.contains(fromPage));
-#endif
- MovableReference* slot = reinterpret_cast<MovableReference*>(it->value);
- auto interior = m_interiorFixups.find(slot);
- if (interior != m_interiorFixups.end()) {
- MovableReference* slotLocation =
- reinterpret_cast<MovableReference*>(interior->value);
- if (!slotLocation) {
- m_interiorFixups.set(slot, to);
- } else {
- LOG_HEAP_COMPACTION("Redirected slot: %p => %p\n", slot, slotLocation);
- slot = slotLocation;
- }
- }
- // If the slot has subsequently been updated, a prefinalizer or
- // a destructor having mutated and expanded/shrunk the collection,
- // do not update and relocate the slot -- |from| is no longer valid
- // and referenced.
- //
- // The slot's contents may also have been cleared during weak processing;
- // no work to be done in that case either.
- if (UNLIKELY(*slot != from)) {
- LOG_HEAP_COMPACTION(
- "No relocation: slot = %p, *slot = %p, from = %p, to = %p\n", slot,
- *slot, from, to);
-#if DCHECK_IS_ON()
- // Verify that the already updated slot is valid, meaning:
- // - has been cleared.
- // - has been updated & expanded with a large object backing store.
- // - has been updated with a larger, freshly allocated backing store.
- // (on a fresh page in a compactable arena that is not being
- // compacted.)
- if (!*slot)
- return;
- BasePage* slotPage = pageFromObject(*slot);
- DCHECK(
- slotPage->isLargeObjectPage() ||
- (HeapCompact::isCompactableArena(slotPage->arena()->arenaIndex()) &&
- !m_relocatablePages.contains(slotPage)));
-#endif
- return;
- }
- *slot = to;
-
- size_t size = 0;
- auto callback = m_fixupCallbacks.find(from);
- if (UNLIKELY(callback != m_fixupCallbacks.end())) {
- size = HeapObjectHeader::fromPayload(to)->payloadSize();
- callback->value.second(callback->value.first, from, to, size);
- }
-
- if (!m_interiors)
- return;
-
- if (!size)
- size = HeapObjectHeader::fromPayload(to)->payloadSize();
- relocateInteriorFixups(from, to, size);
- }
-
-#if DEBUG_HEAP_COMPACTION
- void dumpDebugStats() {
- LOG_HEAP_COMPACTION(
- "Fixups: pages=%u objects=%u callbacks=%u interior-size=%zu"
- " interiors-f=%u\n",
- m_relocatablePages.size(), m_fixups.size(), m_fixupCallbacks.size(),
- m_interiors ? m_interiors->intervalCount() : 0,
- m_interiorFixups.size());
- }
-#endif
-
- private:
- MovableObjectFixups() {}
-
- // Tracking movable and updatable references. For now, we keep a
- // map which for each movable object, recording the slot that
- // points to it. Upon moving the object, that slot needs to be
- // updated.
- //
- // (TODO: consider in-place updating schemes.)
- HashMap<MovableReference, MovableReference*> m_fixups;
-
- // Map from movable reference to callbacks that need to be invoked
- // when the object moves.
- HashMap<MovableReference, std::pair<void*, MovingObjectCallback>>
- m_fixupCallbacks;
-
- // Slot => relocated slot/final location.
- HashMap<MovableReference*, Address> m_interiorFixups;
-
- // All pages that are being compacted.
- HashSet<BasePage*> m_relocatablePages;
-
- std::unique_ptr<SparseHeapBitmap> m_interiors;
-};
-
-HeapCompact::HeapCompact()
- : m_doCompact(false),
- m_gcCountSinceLastCompaction(0),
- m_threadCount(0),
- m_freeListSize(0),
- m_compactableArenas(0u),
- m_freedPages(0),
- m_freedSize(0)
-#if DEBUG_LOG_HEAP_COMPACTION_RUNNING_TIME
- ,
- m_startCompactionTimeMS(0)
-#endif
-{
- // The heap compaction implementation assumes the contiguous range,
- //
- // [Vector1ArenaIndex, HashTableArenaIndex]
- //
- // in a few places. Use static asserts here to not have that assumption
- // be silently invalidated by ArenaIndices changes.
- static_assert(BlinkGC::Vector1ArenaIndex + 3 == BlinkGC::Vector4ArenaIndex,
- "unexpected ArenaIndices ordering");
- static_assert(
- BlinkGC::Vector4ArenaIndex + 1 == BlinkGC::InlineVectorArenaIndex,
- "unexpected ArenaIndices ordering");
- static_assert(
- BlinkGC::InlineVectorArenaIndex + 1 == BlinkGC::HashTableArenaIndex,
- "unexpected ArenaIndices ordering");
-}
-
-HeapCompact::~HeapCompact() {}
-
-HeapCompact::MovableObjectFixups& HeapCompact::fixups() {
- if (!m_fixups)
- m_fixups = MovableObjectFixups::create();
- return *m_fixups;
-}
-
-bool HeapCompact::shouldCompact(ThreadState* state,
- BlinkGC::GCType gcType,
- BlinkGC::GCReason reason) {
-#if !ENABLE_HEAP_COMPACTION
- return false;
-#else
- if (!RuntimeEnabledFeatures::heapCompactionEnabled())
- return false;
-
- LOG_HEAP_COMPACTION("shouldCompact(): gc=%s count=%zu free=%zu\n",
- ThreadState::gcReasonString(reason),
- m_gcCountSinceLastCompaction, m_freeListSize);
- m_gcCountSinceLastCompaction++;
- // It is only safe to compact during non-conservative GCs.
- // TODO: for the main thread, limit this further to only idle GCs.
- if (reason != BlinkGC::IdleGC && reason != BlinkGC::PreciseGC &&
- reason != BlinkGC::ForcedGC)
- return false;
-
- const ThreadHeap& heap = state->heap();
- // If any of the participating threads require a stack scan,
- // do not compact.
- //
- // Why? Should the stack contain an iterator pointing into its
- // associated backing store, its references wouldn't be
- // correctly relocated.
- for (ThreadState* state : heap.threads()) {
- if (state->stackState() == BlinkGC::HeapPointersOnStack) {
- return false;
- }
- }
-
- // Compaction enable rules:
- // - It's been a while since the last time.
- // - "Considerable" amount of heap memory is bound up in freelist
- // allocations. For now, use a fixed limit irrespective of heap
- // size.
- //
- // As this isn't compacting all arenas, the cost of doing compaction
- // isn't a worry as it will additionally only be done by idle GCs.
- // TODO: add some form of compaction overhead estimate to the marking
- // time estimate.
-
- updateHeapResidency(state);
-
-#if STRESS_TEST_HEAP_COMPACTION
- // Exercise the handling of object movement by compacting as
- // often as possible.
- return true;
-#else
- return s_forceCompactionGC ||
- (m_gcCountSinceLastCompaction > kGCCountSinceLastCompactionThreshold &&
- m_freeListSize > kFreeListSizeThreshold);
-#endif
-#endif
-}
-
-BlinkGC::GCType HeapCompact::initialize(ThreadState* state) {
- DCHECK(RuntimeEnabledFeatures::heapCompactionEnabled());
- LOG_HEAP_COMPACTION("Compacting: free=%zu\n", m_freeListSize);
- m_doCompact = true;
- m_freedPages = 0;
- m_freedSize = 0;
- m_threadCount = state->heap().threads().size();
- m_fixups.reset();
- m_gcCountSinceLastCompaction = 0;
- s_forceCompactionGC = false;
- return BlinkGC::GCWithSweepCompaction;
-}
-
-void HeapCompact::registerMovingObjectReference(MovableReference* slot) {
- if (!m_doCompact)
- return;
-
- fixups().add(slot);
-}
-
-void HeapCompact::registerMovingObjectCallback(MovableReference reference,
- MovingObjectCallback callback,
- void* callbackData) {
- if (!m_doCompact)
- return;
-
- fixups().addFixupCallback(reference, callback, callbackData);
-}
-
-void HeapCompact::updateHeapResidency(ThreadState* threadState) {
- size_t totalArenaSize = 0;
- size_t totalFreeListSize = 0;
-
- m_compactableArenas = 0;
-#if DEBUG_HEAP_FREELIST
- LOG_HEAP_FREELIST("Arena residencies: {");
-#endif
- for (int i = BlinkGC::Vector1ArenaIndex; i <= BlinkGC::HashTableArenaIndex;
- ++i) {
- NormalPageArena* arena =
- static_cast<NormalPageArena*>(threadState->arena(i));
- size_t arenaSize = arena->arenaSize();
- size_t freeListSize = arena->freeListSize();
- totalArenaSize += arenaSize;
- totalFreeListSize += freeListSize;
- LOG_HEAP_FREELIST("%d: [%zu, %zu], ", i, arenaSize, freeListSize);
- // TODO: be more discriminating and consider arena
- // load factor, effectiveness of past compactions etc.
- if (!arenaSize)
- continue;
- // Mark the arena as compactable.
- m_compactableArenas |= (0x1u << (BlinkGC::Vector1ArenaIndex + i));
- }
- LOG_HEAP_FREELIST("}\nTotal = %zu, Free = %zu\n", totalArenaSize,
- totalFreeListSize);
-
- // TODO(sof): consider smoothing the reported sizes.
- m_freeListSize = totalFreeListSize;
-}
-
-void HeapCompact::finishedArenaCompaction(NormalPageArena* arena,
- size_t freedPages,
- size_t freedSize) {
- if (!m_doCompact)
- return;
-
- m_freedPages += freedPages;
- m_freedSize += freedSize;
-}
-
-void HeapCompact::relocate(Address from, Address to) {
- DCHECK(m_fixups);
- m_fixups->relocate(from, to);
-}
-
-void HeapCompact::startThreadCompaction() {
- if (!m_doCompact)
- return;
-#if DEBUG_LOG_HEAP_COMPACTION_RUNNING_TIME
- MutexLocker locker(m_mutex);
- if (!m_startCompactionTimeMS)
- m_startCompactionTimeMS = WTF::currentTimeMS();
-#endif
-}
-
-void HeapCompact::finishThreadCompaction() {
- if (!m_doCompact)
- return;
-
- MutexLocker locker(m_mutex);
- // Final one clears out.
- if (!--m_threadCount) {
-#if DEBUG_HEAP_COMPACTION
- if (m_fixups)
- m_fixups->dumpDebugStats();
-#endif
- m_fixups.reset();
- m_doCompact = false;
-#if DEBUG_LOG_HEAP_COMPACTION_RUNNING_TIME
- double end = WTF::currentTimeMS();
- LOG_HEAP_COMPACTION_INTERNAL(
- "Compaction stats: time=%gms, pages freed=%zu, size=%zu\n",
- end - m_startCompactionTimeMS, m_freedPages, m_freedSize);
- m_startCompactionTimeMS = 0;
-#else
- LOG_HEAP_COMPACTION("Compaction stats: freed pages=%zu size=%zu\n",
- m_freedPages, m_freedSize);
-#endif
- // Compaction has been completed by all participating threads, unblock
- // them all.
- m_finished.broadcast();
- } else {
- // Letting a thread return here and let it exit its safe point opens up
- // the possibility of it accessing heaps of other threads that are
- // still being compacted. It is not in a valid state until objects have
- // all been moved together, hence all GC-participating threads must
- // complete compaction together. Grab the condition variable and wait.
- m_finished.wait(m_mutex);
- }
-}
-
-void HeapCompact::addCompactingPage(BasePage* page) {
- DCHECK(m_doCompact);
- DCHECK(isCompactingArena(page->arena()->arenaIndex()));
- fixups().addCompactingPage(page);
-}
-
-bool HeapCompact::scheduleCompactionGCForTesting(bool value) {
- bool current = s_forceCompactionGC;
- s_forceCompactionGC = value;
- return current;
-}
-
-} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/platform/heap/HeapCompact.h ('k') | third_party/WebKit/Source/platform/heap/HeapCompactTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698