[heap] Adjust MarkingBarrier for MinorMC
This CL adjusts MarkingBarrier for MinorMC incremental marking. The MarkingBarrier will be activated in a follow-up CL that schedules MinorMC on a soft limit. Bug: v8:13012 Change-Id: I525f6f158c2d55074d66f51925a1d8220cd4e9b9 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3787874 Commit-Queue: Leon Bettscheider <bettscheider@google.com> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Cr-Commit-Position: refs/heads/main@{#82655}
This commit is contained in:
parent
3266dd845d
commit
772d2ba188
@ -278,7 +278,8 @@ void IncrementalMarking::StartMarking() {
|
|||||||
is_marking_ = true;
|
is_marking_ = true;
|
||||||
heap_->SetIsMarkingFlag(true);
|
heap_->SetIsMarkingFlag(true);
|
||||||
|
|
||||||
MarkingBarrier::ActivateAll(heap(), is_compacting_);
|
MarkingBarrier::ActivateAll(heap(), is_compacting_,
|
||||||
|
MarkingBarrierType::kMajor);
|
||||||
GlobalHandles::EnableMarkingBarrier(heap()->isolate());
|
GlobalHandles::EnableMarkingBarrier(heap()->isolate());
|
||||||
|
|
||||||
heap_->isolate()->compilation_cache()->MarkCompactPrologue();
|
heap_->isolate()->compilation_cache()->MarkCompactPrologue();
|
||||||
|
@ -156,6 +156,8 @@ class V8_EXPORT_PRIVATE IncrementalMarking final {
|
|||||||
// Performs incremental marking step for unit tests.
|
// Performs incremental marking step for unit tests.
|
||||||
void AdvanceForTesting(double max_step_size_in_ms);
|
void AdvanceForTesting(double max_step_size_in_ms);
|
||||||
|
|
||||||
|
bool is_minor() const { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class IncrementalMarkingRootMarkingVisitor;
|
class IncrementalMarkingRootMarkingVisitor;
|
||||||
|
|
||||||
|
@ -63,8 +63,10 @@ LocalHeap::LocalHeap(Heap* heap, ThreadKind kind,
|
|||||||
if (!is_main_thread()) {
|
if (!is_main_thread()) {
|
||||||
WriteBarrier::SetForThread(marking_barrier_.get());
|
WriteBarrier::SetForThread(marking_barrier_.get());
|
||||||
if (heap_->incremental_marking()->IsMarking()) {
|
if (heap_->incremental_marking()->IsMarking()) {
|
||||||
marking_barrier_->Activate(
|
marking_barrier_->Activate(heap_->incremental_marking()->IsCompacting(),
|
||||||
heap_->incremental_marking()->IsCompacting());
|
heap_->incremental_marking()->is_minor()
|
||||||
|
? MarkingBarrierType::kMinor
|
||||||
|
: MarkingBarrierType::kMajor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -30,12 +30,22 @@ bool MarkingBarrier::MarkValue(HeapObject host, HeapObject value) {
|
|||||||
}
|
}
|
||||||
BasicMemoryChunk* target_page = BasicMemoryChunk::FromHeapObject(value);
|
BasicMemoryChunk* target_page = BasicMemoryChunk::FromHeapObject(value);
|
||||||
if (is_shared_heap_ != target_page->InSharedHeap()) return false;
|
if (is_shared_heap_ != target_page->InSharedHeap()) return false;
|
||||||
|
|
||||||
|
if (is_minor()) {
|
||||||
|
// We do not need to insert into RememberedSet<OLD_TO_NEW> here because the
|
||||||
|
// C++ marking barrier already does this for us.
|
||||||
|
if (Heap::InYoungGeneration(value)) {
|
||||||
|
WhiteToGreyAndPush(value); // NEW->NEW
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
if (WhiteToGreyAndPush(value)) {
|
if (WhiteToGreyAndPush(value)) {
|
||||||
if (V8_UNLIKELY(FLAG_track_retaining_path)) {
|
if (V8_UNLIKELY(FLAG_track_retaining_path)) {
|
||||||
heap_->AddRetainingRoot(Root::kWriteBarrier, value);
|
heap_->AddRetainingRoot(Root::kWriteBarrier, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSlot>
|
template <typename TSlot>
|
||||||
@ -47,7 +57,8 @@ inline void MarkingBarrier::MarkRange(HeapObject host, TSlot start, TSlot end) {
|
|||||||
// Mark both, weak and strong edges.
|
// Mark both, weak and strong edges.
|
||||||
if (object.GetHeapObject(isolate, &heap_object)) {
|
if (object.GetHeapObject(isolate, &heap_object)) {
|
||||||
if (MarkValue(host, heap_object) && is_compacting_) {
|
if (MarkValue(host, heap_object) && is_compacting_) {
|
||||||
collector_->RecordSlot(host, HeapObjectSlot(slot), heap_object);
|
DCHECK(is_major());
|
||||||
|
major_collector_->RecordSlot(host, HeapObjectSlot(slot), heap_object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +66,7 @@ inline void MarkingBarrier::MarkRange(HeapObject host, TSlot start, TSlot end) {
|
|||||||
|
|
||||||
bool MarkingBarrier::WhiteToGreyAndPush(HeapObject obj) {
|
bool MarkingBarrier::WhiteToGreyAndPush(HeapObject obj) {
|
||||||
if (marking_state_.WhiteToGrey(obj)) {
|
if (marking_state_.WhiteToGrey(obj)) {
|
||||||
worklist_.Push(obj);
|
current_worklist_->Push(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -24,9 +24,11 @@ namespace internal {
|
|||||||
|
|
||||||
MarkingBarrier::MarkingBarrier(LocalHeap* local_heap)
|
MarkingBarrier::MarkingBarrier(LocalHeap* local_heap)
|
||||||
: heap_(local_heap->heap()),
|
: heap_(local_heap->heap()),
|
||||||
collector_(heap_->mark_compact_collector()),
|
major_collector_(heap_->mark_compact_collector()),
|
||||||
|
minor_collector_(heap_->minor_mark_compact_collector()),
|
||||||
incremental_marking_(heap_->incremental_marking()),
|
incremental_marking_(heap_->incremental_marking()),
|
||||||
worklist_(*collector_->marking_worklists()->shared()),
|
major_worklist_(*major_collector_->marking_worklists()->shared()),
|
||||||
|
minor_worklist_(*minor_collector_->marking_worklists()->shared()),
|
||||||
marking_state_(heap_->isolate()),
|
marking_state_(heap_->isolate()),
|
||||||
is_main_thread_barrier_(local_heap->is_main_thread()),
|
is_main_thread_barrier_(local_heap->is_main_thread()),
|
||||||
is_shared_heap_(heap_->IsShared()) {}
|
is_shared_heap_(heap_->IsShared()) {}
|
||||||
@ -38,15 +40,18 @@ void MarkingBarrier::Write(HeapObject host, HeapObjectSlot slot,
|
|||||||
DCHECK(IsCurrentMarkingBarrier());
|
DCHECK(IsCurrentMarkingBarrier());
|
||||||
if (MarkValue(host, value)) {
|
if (MarkValue(host, value)) {
|
||||||
if (is_compacting_ && slot.address()) {
|
if (is_compacting_ && slot.address()) {
|
||||||
collector_->RecordSlot(host, slot, value);
|
DCHECK(is_major());
|
||||||
|
major_collector_->RecordSlot(host, slot, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkingBarrier::WriteWithoutHost(HeapObject value) {
|
void MarkingBarrier::WriteWithoutHost(HeapObject value) {
|
||||||
DCHECK(is_main_thread_barrier_);
|
DCHECK(is_main_thread_barrier_);
|
||||||
|
if (is_minor() && !Heap::InYoungGeneration(value)) return;
|
||||||
|
|
||||||
if (WhiteToGreyAndPush(value)) {
|
if (WhiteToGreyAndPush(value)) {
|
||||||
if (V8_UNLIKELY(FLAG_track_retaining_path)) {
|
if (V8_UNLIKELY(FLAG_track_retaining_path) && is_major()) {
|
||||||
heap_->AddRetainingRoot(Root::kWriteBarrier, value);
|
heap_->AddRetainingRoot(Root::kWriteBarrier, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,10 +61,11 @@ void MarkingBarrier::Write(Code host, RelocInfo* reloc_info, HeapObject value) {
|
|||||||
DCHECK(IsCurrentMarkingBarrier());
|
DCHECK(IsCurrentMarkingBarrier());
|
||||||
if (MarkValue(host, value)) {
|
if (MarkValue(host, value)) {
|
||||||
if (is_compacting_) {
|
if (is_compacting_) {
|
||||||
|
DCHECK(is_major());
|
||||||
if (is_main_thread_barrier_) {
|
if (is_main_thread_barrier_) {
|
||||||
// An optimization to avoid allocating additional typed slots for the
|
// An optimization to avoid allocating additional typed slots for the
|
||||||
// main thread.
|
// main thread.
|
||||||
collector_->RecordRelocSlot(host, reloc_info, value);
|
major_collector_->RecordRelocSlot(host, reloc_info, value);
|
||||||
} else {
|
} else {
|
||||||
RecordRelocSlot(host, reloc_info, value);
|
RecordRelocSlot(host, reloc_info, value);
|
||||||
}
|
}
|
||||||
@ -74,13 +80,22 @@ void MarkingBarrier::Write(JSArrayBuffer host,
|
|||||||
// The extension will be marked when the marker visits the host object.
|
// The extension will be marked when the marker visits the host object.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (is_minor()) {
|
||||||
|
if (Heap::InYoungGeneration(host)) {
|
||||||
|
extension->YoungMark();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
extension->Mark();
|
extension->Mark();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkingBarrier::Write(DescriptorArray descriptor_array,
|
void MarkingBarrier::Write(DescriptorArray descriptor_array,
|
||||||
int number_of_own_descriptors) {
|
int number_of_own_descriptors) {
|
||||||
DCHECK(IsCurrentMarkingBarrier());
|
DCHECK(IsCurrentMarkingBarrier());
|
||||||
DCHECK(IsReadOnlyHeapObject(descriptor_array.map()));
|
DCHECK(IsReadOnlyHeapObject(descriptor_array.map()));
|
||||||
|
|
||||||
|
if (is_minor() && !heap_->InYoungGeneration(descriptor_array)) return;
|
||||||
|
|
||||||
// The DescriptorArray needs to be marked black here to ensure that slots are
|
// The DescriptorArray needs to be marked black here to ensure that slots are
|
||||||
// recorded by the Scavenger in case the DescriptorArray is promoted while
|
// recorded by the Scavenger in case the DescriptorArray is promoted while
|
||||||
// incremental marking is running. This is needed as the regular marking
|
// incremental marking is running. This is needed as the regular marking
|
||||||
@ -93,8 +108,14 @@ void MarkingBarrier::Write(DescriptorArray descriptor_array,
|
|||||||
MarkRange(descriptor_array, descriptor_array.GetFirstPointerSlot(),
|
MarkRange(descriptor_array, descriptor_array.GetFirstPointerSlot(),
|
||||||
descriptor_array.GetDescriptorSlot(0));
|
descriptor_array.GetDescriptorSlot(0));
|
||||||
}
|
}
|
||||||
const int16_t old_marked = descriptor_array.UpdateNumberOfMarkedDescriptors(
|
|
||||||
collector_->epoch(), number_of_own_descriptors);
|
// Concurrent MinorMC always marks the full young generation DescriptorArray.
|
||||||
|
// We cannot use epoch like MajorMC does because only the lower 2 bits are
|
||||||
|
// used, and with many MinorMC cycles this could lead to correctness issues.
|
||||||
|
const int16_t old_marked =
|
||||||
|
is_minor() ? 0
|
||||||
|
: descriptor_array.UpdateNumberOfMarkedDescriptors(
|
||||||
|
major_collector_->epoch(), number_of_own_descriptors);
|
||||||
if (old_marked < number_of_own_descriptors) {
|
if (old_marked < number_of_own_descriptors) {
|
||||||
// This marks the range from [old_marked, number_of_own_descriptors) instead
|
// This marks the range from [old_marked, number_of_own_descriptors) instead
|
||||||
// of registering weak slots which may temporarily hold alive more objects
|
// of registering weak slots which may temporarily hold alive more objects
|
||||||
@ -123,9 +144,12 @@ void MarkingBarrier::RecordRelocSlot(Code host, RelocInfo* rinfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void MarkingBarrier::ActivateAll(Heap* heap, bool is_compacting) {
|
void MarkingBarrier::ActivateAll(Heap* heap, bool is_compacting,
|
||||||
heap->safepoint()->IterateLocalHeaps([is_compacting](LocalHeap* local_heap) {
|
MarkingBarrierType marking_barrier_type) {
|
||||||
local_heap->marking_barrier()->Activate(is_compacting);
|
heap->safepoint()->IterateLocalHeaps(
|
||||||
|
[is_compacting, marking_barrier_type](LocalHeap* local_heap) {
|
||||||
|
local_heap->marking_barrier()->Activate(is_compacting,
|
||||||
|
marking_barrier_type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +168,7 @@ void MarkingBarrier::PublishAll(Heap* heap) {
|
|||||||
|
|
||||||
void MarkingBarrier::Publish() {
|
void MarkingBarrier::Publish() {
|
||||||
if (is_activated_) {
|
if (is_activated_) {
|
||||||
worklist_.Publish();
|
current_worklist_->Publish();
|
||||||
base::Optional<CodePageHeaderModificationScope> optional_rwx_write_scope;
|
base::Optional<CodePageHeaderModificationScope> optional_rwx_write_scope;
|
||||||
if (!typed_slots_map_.empty()) {
|
if (!typed_slots_map_.empty()) {
|
||||||
optional_rwx_write_scope.emplace(
|
optional_rwx_write_scope.emplace(
|
||||||
@ -200,7 +224,7 @@ void MarkingBarrier::Deactivate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DCHECK(typed_slots_map_.empty());
|
DCHECK(typed_slots_map_.empty());
|
||||||
DCHECK(worklist_.IsLocalEmpty());
|
DCHECK(current_worklist_->IsLocalEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkingBarrier::ActivateSpace(PagedSpace* space) {
|
void MarkingBarrier::ActivateSpace(PagedSpace* space) {
|
||||||
@ -217,10 +241,14 @@ void MarkingBarrier::ActivateSpace(NewSpace* space) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkingBarrier::Activate(bool is_compacting) {
|
void MarkingBarrier::Activate(bool is_compacting,
|
||||||
|
MarkingBarrierType marking_barrier_type) {
|
||||||
DCHECK(!is_activated_);
|
DCHECK(!is_activated_);
|
||||||
DCHECK(worklist_.IsLocalEmpty());
|
DCHECK(major_worklist_.IsLocalEmpty());
|
||||||
|
DCHECK(minor_worklist_.IsLocalEmpty());
|
||||||
is_compacting_ = is_compacting;
|
is_compacting_ = is_compacting;
|
||||||
|
marking_barrier_type_ = marking_barrier_type;
|
||||||
|
current_worklist_ = is_minor() ? &minor_worklist_ : &major_worklist_;
|
||||||
is_activated_ = true;
|
is_activated_ = true;
|
||||||
if (is_main_thread_barrier_) {
|
if (is_main_thread_barrier_) {
|
||||||
ActivateSpace(heap_->old_space());
|
ActivateSpace(heap_->old_space());
|
||||||
|
@ -18,16 +18,19 @@ class LocalHeap;
|
|||||||
class PagedSpace;
|
class PagedSpace;
|
||||||
class NewSpace;
|
class NewSpace;
|
||||||
|
|
||||||
|
enum class MarkingBarrierType { kMinor, kMajor };
|
||||||
|
|
||||||
class MarkingBarrier {
|
class MarkingBarrier {
|
||||||
public:
|
public:
|
||||||
explicit MarkingBarrier(LocalHeap*);
|
explicit MarkingBarrier(LocalHeap*);
|
||||||
~MarkingBarrier();
|
~MarkingBarrier();
|
||||||
|
|
||||||
void Activate(bool is_compacting);
|
void Activate(bool is_compacting, MarkingBarrierType marking_barrier_type);
|
||||||
void Deactivate();
|
void Deactivate();
|
||||||
void Publish();
|
void Publish();
|
||||||
|
|
||||||
static void ActivateAll(Heap* heap, bool is_compacting);
|
static void ActivateAll(Heap* heap, bool is_compacting,
|
||||||
|
MarkingBarrierType marking_barrier_type);
|
||||||
static void DeactivateAll(Heap* heap);
|
static void DeactivateAll(Heap* heap);
|
||||||
V8_EXPORT_PRIVATE static void PublishAll(Heap* heap);
|
V8_EXPORT_PRIVATE static void PublishAll(Heap* heap);
|
||||||
|
|
||||||
@ -58,10 +61,20 @@ class MarkingBarrier {
|
|||||||
template <typename TSlot>
|
template <typename TSlot>
|
||||||
inline void MarkRange(HeapObject value, TSlot start, TSlot end);
|
inline void MarkRange(HeapObject value, TSlot start, TSlot end);
|
||||||
|
|
||||||
|
bool is_minor() const {
|
||||||
|
return marking_barrier_type_ == MarkingBarrierType::kMinor;
|
||||||
|
}
|
||||||
|
bool is_major() const {
|
||||||
|
return marking_barrier_type_ == MarkingBarrierType::kMajor;
|
||||||
|
}
|
||||||
|
|
||||||
Heap* heap_;
|
Heap* heap_;
|
||||||
MarkCompactCollector* collector_;
|
MarkCompactCollector* major_collector_;
|
||||||
|
MinorMarkCompactCollector* minor_collector_;
|
||||||
IncrementalMarking* incremental_marking_;
|
IncrementalMarking* incremental_marking_;
|
||||||
MarkingWorklist::Local worklist_;
|
MarkingWorklist::Local major_worklist_;
|
||||||
|
MarkingWorklist::Local minor_worklist_;
|
||||||
|
MarkingWorklist::Local* current_worklist_;
|
||||||
MarkingState marking_state_;
|
MarkingState marking_state_;
|
||||||
std::unordered_map<MemoryChunk*, std::unique_ptr<TypedSlots>,
|
std::unordered_map<MemoryChunk*, std::unique_ptr<TypedSlots>,
|
||||||
MemoryChunk::Hasher>
|
MemoryChunk::Hasher>
|
||||||
@ -70,6 +83,7 @@ class MarkingBarrier {
|
|||||||
bool is_activated_ = false;
|
bool is_activated_ = false;
|
||||||
bool is_main_thread_barrier_;
|
bool is_main_thread_barrier_;
|
||||||
bool is_shared_heap_;
|
bool is_shared_heap_;
|
||||||
|
MarkingBarrierType marking_barrier_type_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
Loading…
Reference in New Issue
Block a user