blob: e7e13334f1097d7ccef34eac2d4bf84f8f20f3e2 [file] [log] [blame]
// 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.
#ifndef HeapCompact_h
#define HeapCompact_h
#include "platform/PlatformExport.h"
#include "platform/heap/BlinkGC.h"
#include "wtf/DataLog.h"
#include "wtf/PtrUtil.h"
#include "wtf/ThreadingPrimitives.h"
#include "wtf/Vector.h"
#include <bitset>
#include <utility>
// Compaction-specific debug switches:
// Set to 0 to prevent compaction GCs, disabling the heap compaction feature.
#define ENABLE_HEAP_COMPACTION 1
// Emit debug info during compaction.
#define DEBUG_HEAP_COMPACTION 0
// Emit stats on freelist occupancy.
// 0 - disabled, 1 - minimal, 2 - verbose.
#define DEBUG_HEAP_FREELIST 0
// Log the amount of time spent compacting.
#define DEBUG_LOG_HEAP_COMPACTION_RUNNING_TIME 0
// Compact during all idle + precise GCs; for debugging.
#define STRESS_TEST_HEAP_COMPACTION 0
namespace blink {
class NormalPageArena;
class BasePage;
class ThreadState;
class PLATFORM_EXPORT HeapCompact final {
public:
static std::unique_ptr<HeapCompact> create() {
return WTF::wrapUnique(new HeapCompact);
}
~HeapCompact();
// Determine if a GC for the given type and reason should also perform
// additional heap compaction.
//
bool shouldCompact(ThreadState*, BlinkGC::GCType, BlinkGC::GCReason);
// Compaction should be performed as part of the ongoing GC, initialize
// the heap compaction pass. Returns the appropriate visitor type to
// use when running the marking phase.
void initialize(ThreadState*);
// Returns true if the ongoing GC will perform compaction.
bool isCompacting() const { return m_doCompact; }
// Returns true if the ongoing GC will perform compaction for the given
// heap arena.
bool isCompactingArena(int arenaIndex) const {
return m_doCompact && (m_compactableArenas & (0x1u << arenaIndex));
}
// Returns |true| if the ongoing GC may compact the given arena/sub-heap.
static bool isCompactableArena(int arenaIndex) {
return arenaIndex >= BlinkGC::Vector1ArenaIndex &&
arenaIndex <= BlinkGC::HashTableArenaIndex;
}
// See |Heap::registerMovingObjectReference()| documentation.
void registerMovingObjectReference(MovableReference* slot);
// See |Heap::registerMovingObjectCallback()| documentation.
void registerMovingObjectCallback(MovableReference,
MovingObjectCallback,
void* callbackData);
// Thread signalling that a compaction pass is starting or has
// completed.
//
// A thread participating in a heap GC will wait on the completion
// of compaction across all threads. No thread can be allowed to
// potentially access another thread's heap arenas while they're
// still being compacted.
void startThreadCompaction();
void finishThreadCompaction();
// Perform any relocation post-processing after having completed compacting
// the given arena. The number of pages that were freed together with the
// total size (in bytes) of freed heap storage, are passed in as arguments.
void finishedArenaCompaction(NormalPageArena*,
size_t freedPages,
size_t freedSize);
// Register the heap page as containing live objects that will all be
// compacted. Registration happens as part of making the arenas ready
// for a GC.
void addCompactingPage(BasePage*);
// Notify heap compaction that object at |from| has been relocated to.. |to|.
// (Called by the sweep compaction pass.)
void relocate(Address from, Address to);
// For unit testing only: arrange for a compaction GC to be triggered
// next time a non-conservative GC is run. Sets the compact-next flag
// to the new value, returning old.
static bool scheduleCompactionGCForTesting(bool);
private:
class MovableObjectFixups;
HeapCompact();
// Sample the amount of fragmentation and heap memory currently residing
// on the freelists of the arenas we're able to compact. The computed
// numbers will be subsequently used to determine if a heap compaction
// is on order (shouldCompact().)
void updateHeapResidency(ThreadState*);
// Parameters controlling when compaction should be done:
// Number of GCs that must have passed since last compaction GC.
static const int kGCCountSinceLastCompactionThreshold = 10;
// Freelist size threshold that must be exceeded before compaction
// should be considered.
static const size_t kFreeListSizeThreshold = 512 * 1024;
MovableObjectFixups& fixups();
std::unique_ptr<MovableObjectFixups> m_fixups;
// Set to |true| when a compacting sweep will go ahead.
bool m_doCompact;
size_t m_gcCountSinceLastCompaction;
// Lock protecting finishedThreadCompaction() signalling.
Mutex m_mutex;
// All threads performing a GC must synchronize on completion
// of all heap compactions. Not doing so risks one thread resuming
// the mutator, which could perform cross-thread access to a heap
// that's still in the process of being compacted.
ThreadCondition m_finished;
// Number of heap threads participating in the compaction.
int m_threadCount;
// Last reported freelist size, across all compactable arenas.
size_t m_freeListSize;
// If compacting, i'th heap arena will be compacted
// if corresponding bit is set. Indexes are in
// the range of BlinkGC::ArenaIndices.
unsigned m_compactableArenas;
// Stats, number of (complete) pages freed/decommitted +
// bytes freed (which will include partial pages.)
size_t m_freedPages;
size_t m_freedSize;
double m_startCompactionTimeMS;
static bool s_forceCompactionGC;
};
} // namespace blink
// Logging macros activated by debug switches.
#define LOG_HEAP_COMPACTION_INTERNAL(msg, ...) dataLogF(msg, ##__VA_ARGS__)
#if DEBUG_HEAP_COMPACTION
#define LOG_HEAP_COMPACTION(msg, ...) \
LOG_HEAP_COMPACTION_INTERNAL(msg, ##__VA_ARGS__)
#else
#define LOG_HEAP_COMPACTION(msg, ...) \
do { \
} while (0)
#endif
#if DEBUG_HEAP_FREELIST
#define LOG_HEAP_FREELIST(msg, ...) \
LOG_HEAP_COMPACTION_INTERNAL(msg, ##__VA_ARGS__)
#else
#define LOG_HEAP_FREELIST(msg, ...) \
do { \
} while (0)
#endif
#if DEBUG_HEAP_FREELIST == 2
#define LOG_HEAP_FREELIST_VERBOSE(msg, ...) \
LOG_HEAP_COMPACTION_INTERNAL(msg, ##__VA_ARGS__)
#else
#define LOG_HEAP_FREELIST_VERBOSE(msg, ...) \
do { \
} while (0)
#endif
#endif // HeapCompact_h