Commit d2c093bc authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[heap] Support for minor MC marking during incremental marking

BUG=chromium:651354

Change-Id: Ia8511723b17936b78b33ea685704237c100648e1
Reviewed-on: https://chromium-review.googlesource.com/439285
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43422}
parent c605ea03
......@@ -644,7 +644,6 @@ DEFINE_INT(min_progress_during_incremental_marking_finalization, 32,
DEFINE_INT(max_incremental_marking_finalization_rounds, 3,
"at most try this many times to finalize incremental marking")
DEFINE_BOOL(minor_mc, false, "perform young generation mark compact GCs")
DEFINE_NEG_IMPLICATION(minor_mc, incremental_marking)
DEFINE_BOOL(black_allocation, true, "use black allocation")
DEFINE_BOOL(concurrent_sweeping, true, "use concurrent sweeping")
DEFINE_BOOL(parallel_compaction, true, "use parallel compaction")
......
......@@ -12,10 +12,11 @@
namespace v8 {
namespace internal {
template <MarkingMode mode>
void MarkCompactCollector::PushBlack(HeapObject* obj) {
DCHECK(ObjectMarking::IsBlack(obj));
if (!marking_deque()->Push(obj)) {
ObjectMarking::BlackToGrey(obj);
DCHECK(ObjectMarking::IsBlack<mode>(obj));
if (!marking_deque<mode>()->Push(obj)) {
ObjectMarking::BlackToGrey<mode>(obj);
}
}
......@@ -27,10 +28,11 @@ void MarkCompactCollector::UnshiftBlack(HeapObject* obj) {
}
}
template <MarkingMode mode>
void MarkCompactCollector::MarkObject(HeapObject* obj) {
if (ObjectMarking::IsWhite(obj)) {
ObjectMarking::WhiteToBlack(obj);
PushBlack(obj);
if (ObjectMarking::IsWhite<mode>(obj)) {
ObjectMarking::WhiteToBlack<mode>(obj);
PushBlack<mode>(obj);
}
}
......
This diff is collapsed.
......@@ -17,8 +17,6 @@
namespace v8 {
namespace internal {
enum class MarkCompactMode { FULL, YOUNG_GENERATION };
// Callback function, returns whether an object is alive. The heap size
// of the object is returned in size. It optionally updates the offset
// to the first live object in the page (only used for old and map objects).
......@@ -31,87 +29,103 @@ typedef void (*MarkObjectFunction)(Heap* heap, HeapObject* object);
class CodeFlusher;
class MarkCompactCollector;
class MarkingVisitor;
template <MarkCompactMode mode>
template <MarkingMode mode>
class RootMarkingVisitor;
class ObjectMarking : public AllStatic {
public:
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static MarkBit MarkBitFrom(HeapObject* obj) {
const Address address = obj->address();
MemoryChunk* p = MemoryChunk::FromAddress(address);
return p->markbits()->MarkBitFromIndex(p->AddressToMarkbitIndex(address));
const MemoryChunk* p = MemoryChunk::FromAddress(address);
return p->markbits<mode>()->MarkBitFromIndex(
p->AddressToMarkbitIndex(address));
}
static Marking::ObjectColor Color(HeapObject* obj) {
return Marking::Color(ObjectMarking::MarkBitFrom(obj));
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static Marking::ObjectColor Color(HeapObject* obj) {
return Marking::Color(ObjectMarking::MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static bool IsImpossible(HeapObject* obj) {
return Marking::IsImpossible(MarkBitFrom(obj));
return Marking::IsImpossible(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static bool IsBlack(HeapObject* obj) {
return Marking::IsBlack(MarkBitFrom(obj));
return Marking::IsBlack(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static bool IsWhite(HeapObject* obj) {
return Marking::IsWhite(MarkBitFrom(obj));
return Marking::IsWhite(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static bool IsGrey(HeapObject* obj) {
return Marking::IsGrey(MarkBitFrom(obj));
return Marking::IsGrey(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static bool IsBlackOrGrey(HeapObject* obj) {
return Marking::IsBlackOrGrey(MarkBitFrom(obj));
return Marking::IsBlackOrGrey(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void ClearMarkBit(HeapObject* obj) {
Marking::MarkWhite(MarkBitFrom(obj));
Marking::MarkWhite(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void BlackToWhite(HeapObject* obj) {
DCHECK(IsBlack(obj));
MarkBit markbit = MarkBitFrom(obj);
DCHECK(IsBlack<mode>(obj));
MarkBit markbit = MarkBitFrom<mode>(obj);
Marking::BlackToWhite(markbit);
MemoryChunk::IncrementLiveBytes(obj, -obj->Size());
MemoryChunk::IncrementLiveBytes<mode>(obj, -obj->Size());
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void GreyToWhite(HeapObject* obj) {
DCHECK(IsGrey(obj));
Marking::GreyToWhite(MarkBitFrom(obj));
DCHECK(IsGrey<mode>(obj));
Marking::GreyToWhite(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void BlackToGrey(HeapObject* obj) {
DCHECK(IsBlack(obj));
MarkBit markbit = MarkBitFrom(obj);
DCHECK(IsBlack<mode>(obj));
MarkBit markbit = MarkBitFrom<mode>(obj);
Marking::BlackToGrey(markbit);
MemoryChunk::IncrementLiveBytes(obj, -obj->Size());
MemoryChunk::IncrementLiveBytes<mode>(obj, -obj->Size());
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void WhiteToGrey(HeapObject* obj) {
DCHECK(IsWhite(obj));
Marking::WhiteToGrey(MarkBitFrom(obj));
DCHECK(IsWhite<mode>(obj));
Marking::WhiteToGrey(MarkBitFrom<mode>(obj));
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void WhiteToBlack(HeapObject* obj) {
DCHECK(IsWhite(obj));
MarkBit markbit = MarkBitFrom(obj);
DCHECK(IsWhite<mode>(obj));
MarkBit markbit = MarkBitFrom<mode>(obj);
Marking::WhiteToBlack(markbit);
MemoryChunk::IncrementLiveBytes(obj, obj->Size());
MemoryChunk::IncrementLiveBytes<mode>(obj, obj->Size());
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void GreyToBlack(HeapObject* obj) {
DCHECK(IsGrey(obj));
MarkBit markbit = MarkBitFrom(obj);
DCHECK(IsGrey<mode>(obj));
MarkBit markbit = MarkBitFrom<mode>(obj);
Marking::GreyToBlack(markbit);
MemoryChunk::IncrementLiveBytes(obj, obj->Size());
MemoryChunk::IncrementLiveBytes<mode>(obj, obj->Size());
}
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE static void AnyToGrey(HeapObject* obj) {
MarkBit markbit = MarkBitFrom(obj);
MarkBit markbit = MarkBitFrom<mode>(obj);
if (Marking::IsBlack(markbit)) {
MemoryChunk::IncrementLiveBytes(obj, -obj->Size());
MemoryChunk::IncrementLiveBytes<mode>(obj, -obj->Size());
}
Marking::AnyToGrey(markbit);
}
......@@ -573,7 +587,11 @@ class MarkCompactCollector {
// is marked.
void MarkImplicitRefGroups(MarkObjectFunction mark_object);
MarkingDeque* marking_deque() { return &marking_deque_; }
template <MarkingMode mode = MarkingMode::FULL>
MarkingDeque* marking_deque() {
return mode == MarkingMode::FULL ? &marking_deque_
: &marking_deque_young_generation_;
}
Sweeper& sweeper() { return sweeper_; }
......@@ -631,7 +649,7 @@ class MarkCompactCollector {
friend class MarkCompactMarkingVisitor;
friend class MarkingVisitor;
friend class RecordMigratedSlotVisitor;
template <MarkCompactMode mode>
template <MarkingMode mode>
friend class RootMarkingVisitor;
friend class SharedFunctionInfoMarkingVisitor;
friend class StaticYoungGenerationMarkingVisitor;
......@@ -649,26 +667,28 @@ class MarkCompactCollector {
// Pushes a black object onto the marking stack and accounts for live bytes.
// Note that this assumes live bytes have not yet been counted.
INLINE(void PushBlack(HeapObject* obj));
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE void PushBlack(HeapObject* obj);
// Unshifts a black object into the marking stack and accounts for live bytes.
// Note that this assumes lives bytes have already been counted.
INLINE(void UnshiftBlack(HeapObject* obj));
V8_INLINE void UnshiftBlack(HeapObject* obj);
// Marks the object black and pushes it on the marking stack.
// This is for non-incremental marking only.
INLINE(void MarkObject(HeapObject* obj));
template <MarkingMode mode = MarkingMode::FULL>
V8_INLINE void MarkObject(HeapObject* obj);
// Mark the heap roots and all objects reachable from them.
void MarkRoots(RootMarkingVisitor<MarkCompactMode::FULL>* visitor);
void MarkRoots(RootMarkingVisitor<MarkingMode::FULL>* visitor);
// Mark the string table specially. References to internalized strings from
// the string table are weak.
void MarkStringTable(RootMarkingVisitor<MarkCompactMode::FULL>* visitor);
void MarkStringTable(RootMarkingVisitor<MarkingMode::FULL>* visitor);
// Mark objects reachable (transitively) from objects in the marking stack
// or overflowed in the heap.
template <MarkCompactMode mode>
template <MarkingMode mode>
void ProcessMarkingDeque();
// Mark objects reachable (transitively) from objects in the marking stack
......@@ -692,13 +712,13 @@ class MarkCompactCollector {
// stack. This function empties the marking stack, but may leave
// overflowed objects in the heap, in which case the marking stack's
// overflow flag will be set.
template <MarkCompactMode mode>
template <MarkingMode mode>
void EmptyMarkingDeque();
// Refill the marking stack with overflowed objects from the heap. This
// function either leaves the marking stack full or clears the overflow
// flag on the marking stack.
template <MarkCompactMode mode>
template <MarkingMode mode>
void RefillMarkingDeque();
// Helper methods for refilling the marking stack by discovering grey objects
......@@ -816,6 +836,7 @@ class MarkCompactCollector {
bool have_code_to_deoptimize_;
MarkingDeque marking_deque_;
MarkingDeque marking_deque_young_generation_;
CodeFlusher* code_flusher_;
......
......@@ -226,27 +226,52 @@ void Page::InitializeFreeListCategories() {
}
}
template <MarkingMode mode>
void MemoryChunk::IncrementLiveBytes(HeapObject* object, int by) {
MemoryChunk::FromAddress(object->address())->IncrementLiveBytes(by);
MemoryChunk::FromAddress(object->address())->IncrementLiveBytes<mode>(by);
}
template <MarkingMode mode>
void MemoryChunk::TraceLiveBytes(intptr_t old_value, intptr_t new_value) {
if (!FLAG_trace_live_bytes) return;
PrintIsolate(heap()->isolate(),
"live-bytes[%p:%s]: %" V8PRIdPTR "-> %" V8PRIdPTR "\n",
static_cast<void*>(this),
mode == MarkingMode::FULL ? "internal" : "external", old_value,
new_value);
}
template <MarkingMode mode>
void MemoryChunk::ResetLiveBytes() {
if (FLAG_trace_live_bytes) {
PrintIsolate(heap()->isolate(), "live-bytes: reset page=%p %d->0\n",
static_cast<void*>(this), live_byte_count_);
switch (mode) {
case MarkingMode::FULL:
TraceLiveBytes(live_byte_count_, 0);
live_byte_count_ = 0;
break;
case MarkingMode::YOUNG_GENERATION:
TraceLiveBytes(young_generation_live_byte_count_, 0);
young_generation_live_byte_count_ = 0;
break;
}
live_byte_count_ = 0;
}
template <MarkingMode mode>
void MemoryChunk::IncrementLiveBytes(int by) {
if (FLAG_trace_live_bytes) {
PrintIsolate(
heap()->isolate(), "live-bytes: update page=%p delta=%d %d->%d\n",
static_cast<void*>(this), by, live_byte_count_, live_byte_count_ + by);
switch (mode) {
case MarkingMode::FULL:
TraceLiveBytes(live_byte_count_, live_byte_count_ + by);
live_byte_count_ += by;
DCHECK_GE(live_byte_count_, 0);
DCHECK_LE(static_cast<size_t>(live_byte_count_), size_);
break;
case MarkingMode::YOUNG_GENERATION:
TraceLiveBytes(young_generation_live_byte_count_,
young_generation_live_byte_count_ + by);
young_generation_live_byte_count_ += by;
DCHECK_GE(young_generation_live_byte_count_, 0);
DCHECK_LE(static_cast<size_t>(young_generation_live_byte_count_), size_);
break;
}
live_byte_count_ += by;
DCHECK_GE(live_byte_count_, 0);
DCHECK_LE(static_cast<size_t>(live_byte_count_), size_);
}
bool PagedSpace::Contains(Address addr) {
......
......@@ -538,8 +538,8 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap, Address base, size_t size,
chunk->mutex_ = new base::Mutex();
chunk->available_in_free_list_ = 0;
chunk->wasted_memory_ = 0;
chunk->ResetLiveBytes();
chunk->ClearLiveness();
chunk->young_generation_bitmap_ = nullptr;
chunk->set_next_chunk(nullptr);
chunk->set_prev_chunk(nullptr);
chunk->local_tracker_ = nullptr;
......@@ -1119,6 +1119,7 @@ void MemoryChunk::ReleaseAllocatedMemory() {
if (typed_old_to_new_slots_.Value() != nullptr) ReleaseTypedOldToNewSlots();
if (typed_old_to_old_slots_ != nullptr) ReleaseTypedOldToOldSlots();
if (local_tracker_ != nullptr) ReleaseLocalTracker();
if (young_generation_bitmap_ != nullptr) ReleaseExternalBitmap();
}
static SlotSet* AllocateSlotSet(size_t size, Address page_start) {
......@@ -1184,6 +1185,18 @@ void MemoryChunk::ReleaseLocalTracker() {
local_tracker_ = nullptr;
}
void MemoryChunk::AllocateExternalBitmap() {
DCHECK_NULL(young_generation_bitmap_);
young_generation_bitmap_ = static_cast<Bitmap*>(calloc(1, Bitmap::kSize));
young_generation_live_byte_count_ = 0;
}
void MemoryChunk::ReleaseExternalBitmap() {
DCHECK_NOT_NULL(young_generation_bitmap_);
free(young_generation_bitmap_);
young_generation_bitmap_ = nullptr;
}
void MemoryChunk::ClearLiveness() {
markbits()->Clear();
ResetLiveBytes();
......
......@@ -224,6 +224,10 @@ class FreeListCategory {
friend class PagedSpace;
};
// MarkingMode determines which bitmaps and counters should be used when
// accessing marking information on MemoryChunk.
enum class MarkingMode { FULL, YOUNG_GENERATION };
// MemoryChunk represents a memory region owned by a specific space.
// It is divided into the header and the body. Chunk start is always
// 1MB aligned. Start of the body is aligned so it can accommodate
......@@ -323,30 +327,32 @@ class MemoryChunk {
static const intptr_t kReservationOffset = kAreaEndOffset + kPointerSize;
static const intptr_t kOwnerOffset = kReservationOffset + 2 * kPointerSize;
static const size_t kMinHeaderSize =
kSizeOffset + kSizetSize // size_t size
+ kIntptrSize // Flags flags_
+ kPointerSize // Address area_start_
+ kPointerSize // Address area_end_
+ 2 * kPointerSize // base::VirtualMemory reservation_
+ kPointerSize // Address owner_
+ kPointerSize // Heap* heap_
+ kIntSize // int progress_bar_
+ kIntSize // int live_bytes_count_
+ kPointerSize // SlotSet* old_to_new_slots_
+ kPointerSize // SlotSet* old_to_old_slots_
+ kPointerSize // TypedSlotSet* typed_old_to_new_slots_
+ kPointerSize // TypedSlotSet* typed_old_to_old_slots_
+ kPointerSize // SkipList* skip_list_
+ kPointerSize // AtomicValue high_water_mark_
+ kPointerSize // base::Mutex* mutex_
+ kPointerSize // base::AtomicWord concurrent_sweeping_
+ 2 * kSizetSize // AtomicNumber free-list statistics
+ kPointerSize // AtomicValue next_chunk_
+ kPointerSize // AtomicValue prev_chunk_
// FreeListCategory categories_[kNumberOfCategories]
+ FreeListCategory::kSize * kNumberOfCategories +
kPointerSize; // LocalArrayBufferTracker* local_tracker_
static const size_t kMinHeaderSize = kSizeOffset // NOLINT
+ kSizetSize // size_t size
+ kIntptrSize // Flags flags_
+ kPointerSize // Address area_start_
+ kPointerSize // Address area_end_
+ 2 * kPointerSize // base::VirtualMemory reservation_
+ kPointerSize // Address owner_
+ kPointerSize // Heap* heap_
+ kIntSize // int progress_bar_
+ kIntSize // int live_bytes_count_
+ kPointerSize // SlotSet* old_to_new_slots_
+ kPointerSize // SlotSet* old_to_old_slots_
+ kPointerSize // TypedSlotSet* typed_old_to_new_slots_
+ kPointerSize // TypedSlotSet* typed_old_to_old_slots_
+ kPointerSize // SkipList* skip_list_
+ kPointerSize // AtomicValue high_water_mark_
+ kPointerSize // base::Mutex* mutex_
+ kPointerSize // base::AtomicWord concurrent_sweeping_
+ 2 * kSizetSize // AtomicNumber free-list statistics
+ kPointerSize // AtomicValue next_chunk_
+ kPointerSize // AtomicValue prev_chunk_
+ FreeListCategory::kSize * kNumberOfCategories
// FreeListCategory categories_[kNumberOfCategories]
+ kPointerSize // LocalArrayBufferTracker* local_tracker_
+ kIntptrSize // intptr_t young_generation_live_byte_count_
+ kPointerSize; // Bitmap* young_generation_bitmap_
// We add some more space to the computed header size to amount for missing
// alignment requirements in our computation.
......@@ -370,6 +376,7 @@ class MemoryChunk {
static const int kAllocatableMemory = kPageSize - kObjectStartOffset;
template <MarkingMode mode = MarkingMode::FULL>
static inline void IncrementLiveBytes(HeapObject* object, int by);
// Only works if the pointer is in the first kPageSize of the MemoryChunk.
......@@ -395,7 +402,9 @@ class MemoryChunk {
static bool IsValid(MemoryChunk* chunk) { return chunk != nullptr; }
Address address() { return reinterpret_cast<Address>(this); }
Address address() const {
return reinterpret_cast<Address>(const_cast<MemoryChunk*>(this));
}
base::Mutex* mutex() { return mutex_; }
......@@ -418,12 +427,24 @@ class MemoryChunk {
}
// Manage live byte count, i.e., count of bytes in black objects.
template <MarkingMode mode = MarkingMode::FULL>
inline void ResetLiveBytes();
template <MarkingMode mode = MarkingMode::FULL>
inline void IncrementLiveBytes(int by);
template <MarkingMode mode = MarkingMode::FULL>
int LiveBytes() {
DCHECK_LE(static_cast<unsigned>(live_byte_count_), size_);
return live_byte_count_;
switch (mode) {
case MarkingMode::FULL:
DCHECK_LE(static_cast<unsigned>(live_byte_count_), size_);
return live_byte_count_;
case MarkingMode::YOUNG_GENERATION:
DCHECK_LE(static_cast<unsigned>(young_generation_live_byte_count_),
size_);
return static_cast<int>(young_generation_live_byte_count_);
}
UNREACHABLE();
return 0;
}
void SetLiveBytes(int live_bytes) {
......@@ -461,6 +482,8 @@ class MemoryChunk {
void ReleaseTypedOldToOldSlots();
void AllocateLocalTracker();
void ReleaseLocalTracker();
void AllocateExternalBitmap();
void ReleaseExternalBitmap();
Address area_start() { return area_start_; }
Address area_end() { return area_end_; }
......@@ -489,15 +512,18 @@ class MemoryChunk {
}
}
inline Bitmap* markbits() {
return Bitmap::FromAddress(address() + kHeaderSize);
template <MarkingMode mode = MarkingMode::FULL>
inline Bitmap* markbits() const {
return mode == MarkingMode::FULL
? Bitmap::FromAddress(address() + kHeaderSize)
: young_generation_bitmap_;
}
inline uint32_t AddressToMarkbitIndex(Address addr) {
inline uint32_t AddressToMarkbitIndex(Address addr) const {
return static_cast<uint32_t>(addr - this->address()) >> kPointerSizeLog2;
}
inline Address MarkbitIndexToAddress(uint32_t index) {
inline Address MarkbitIndexToAddress(uint32_t index) const {
return this->address() + (index << kPointerSizeLog2);
}
......@@ -588,6 +614,9 @@ class MemoryChunk {
base::VirtualMemory* reserved_memory() { return &reservation_; }
template <MarkingMode mode = MarkingMode::FULL>
inline void TraceLiveBytes(intptr_t old_value, intptr_t new_value);
size_t size_;
Flags flags_;
......@@ -643,6 +672,9 @@ class MemoryChunk {
LocalArrayBufferTracker* local_tracker_;
intptr_t young_generation_live_byte_count_;
Bitmap* young_generation_bitmap_;
private:
void InitializeReservedMemory() { reservation_.Reset(); }
......@@ -2643,6 +2675,9 @@ class NewSpace : public Space {
std::unique_ptr<ObjectIterator> GetObjectIterator() override;
SemiSpace& from_space() { return from_space_; }
SemiSpace& to_space() { return to_space_; }
private:
// Update allocation info to match the current to-space page.
void UpdateAllocationInfo();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment