[heap] Refactor live object visitation
- Restructure the methods that are not allowed to fail to avoid a branch.
- Undo compaction changes for the reland as they require further investigation
This reverts commit 7dea0f7b38
.
Bug: chromium:651354
Change-Id: I93e8601bcdec534f41f8e27fd83848f8ef0f1244
Reviewed-on: https://chromium-review.googlesource.com/549462
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46259}
This commit is contained in:
parent
3c41aba2ab
commit
ab028038db
@ -3518,7 +3518,7 @@ class Evacuator : public Malloced {
|
|||||||
|
|
||||||
virtual ~Evacuator() {}
|
virtual ~Evacuator() {}
|
||||||
|
|
||||||
bool EvacuatePage(Page* page);
|
void EvacuatePage(Page* page);
|
||||||
|
|
||||||
void AddObserver(MigrationObserver* observer) {
|
void AddObserver(MigrationObserver* observer) {
|
||||||
new_space_visitor_.AddObserver(observer);
|
new_space_visitor_.AddObserver(observer);
|
||||||
@ -3536,7 +3536,7 @@ class Evacuator : public Malloced {
|
|||||||
static const int kInitialLocalPretenuringFeedbackCapacity = 256;
|
static const int kInitialLocalPretenuringFeedbackCapacity = 256;
|
||||||
|
|
||||||
// |saved_live_bytes| returns the live bytes of the page that was processed.
|
// |saved_live_bytes| returns the live bytes of the page that was processed.
|
||||||
virtual bool RawEvacuatePage(Page* page, intptr_t* saved_live_bytes) = 0;
|
virtual void RawEvacuatePage(Page* page, intptr_t* saved_live_bytes) = 0;
|
||||||
|
|
||||||
inline Heap* heap() { return heap_; }
|
inline Heap* heap() { return heap_; }
|
||||||
|
|
||||||
@ -3564,31 +3564,29 @@ class Evacuator : public Malloced {
|
|||||||
intptr_t bytes_compacted_;
|
intptr_t bytes_compacted_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Evacuator::EvacuatePage(Page* page) {
|
void Evacuator::EvacuatePage(Page* page) {
|
||||||
bool success = false;
|
|
||||||
DCHECK(page->SweepingDone());
|
DCHECK(page->SweepingDone());
|
||||||
intptr_t saved_live_bytes = 0;
|
intptr_t saved_live_bytes = 0;
|
||||||
double evacuation_time = 0.0;
|
double evacuation_time = 0.0;
|
||||||
{
|
{
|
||||||
AlwaysAllocateScope always_allocate(heap()->isolate());
|
AlwaysAllocateScope always_allocate(heap()->isolate());
|
||||||
TimedScope timed_scope(&evacuation_time);
|
TimedScope timed_scope(&evacuation_time);
|
||||||
success = RawEvacuatePage(page, &saved_live_bytes);
|
RawEvacuatePage(page, &saved_live_bytes);
|
||||||
}
|
}
|
||||||
ReportCompactionProgress(evacuation_time, saved_live_bytes);
|
ReportCompactionProgress(evacuation_time, saved_live_bytes);
|
||||||
if (FLAG_trace_evacuation) {
|
if (FLAG_trace_evacuation) {
|
||||||
PrintIsolate(heap()->isolate(),
|
PrintIsolate(
|
||||||
"evacuation[%p]: page=%p new_space=%d "
|
heap()->isolate(),
|
||||||
"page_evacuation=%d executable=%d contains_age_mark=%d "
|
"evacuation[%p]: page=%p new_space=%d "
|
||||||
"live_bytes=%" V8PRIdPTR " time=%f success=%d\n",
|
"page_evacuation=%d executable=%d contains_age_mark=%d "
|
||||||
static_cast<void*>(this), static_cast<void*>(page),
|
"live_bytes=%" V8PRIdPTR " time=%f success=%d\n",
|
||||||
page->InNewSpace(),
|
static_cast<void*>(this), static_cast<void*>(page), page->InNewSpace(),
|
||||||
page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) ||
|
page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) ||
|
||||||
page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION),
|
page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION),
|
||||||
page->IsFlagSet(MemoryChunk::IS_EXECUTABLE),
|
page->IsFlagSet(MemoryChunk::IS_EXECUTABLE),
|
||||||
page->Contains(heap()->new_space()->age_mark()),
|
page->Contains(heap()->new_space()->age_mark()), saved_live_bytes,
|
||||||
saved_live_bytes, evacuation_time, success);
|
evacuation_time, page->IsFlagSet(Page::COMPACTION_WAS_ABORTED));
|
||||||
}
|
}
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Evacuator::Finalize() {
|
void Evacuator::Finalize() {
|
||||||
@ -3616,64 +3614,51 @@ class FullEvacuator : public Evacuator {
|
|||||||
: Evacuator(collector->heap(), record_visitor), collector_(collector) {}
|
: Evacuator(collector->heap(), record_visitor), collector_(collector) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool RawEvacuatePage(Page* page, intptr_t* live_bytes) override;
|
void RawEvacuatePage(Page* page, intptr_t* live_bytes) override;
|
||||||
|
|
||||||
MarkCompactCollector* collector_;
|
MarkCompactCollector* collector_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool FullEvacuator::RawEvacuatePage(Page* page, intptr_t* live_bytes) {
|
void FullEvacuator::RawEvacuatePage(Page* page, intptr_t* live_bytes) {
|
||||||
bool success = false;
|
|
||||||
LiveObjectVisitor object_visitor;
|
|
||||||
const MarkingState state = collector_->marking_state(page);
|
const MarkingState state = collector_->marking_state(page);
|
||||||
*live_bytes = state.live_bytes();
|
*live_bytes = state.live_bytes();
|
||||||
|
HeapObject* failed_object = nullptr;
|
||||||
switch (ComputeEvacuationMode(page)) {
|
switch (ComputeEvacuationMode(page)) {
|
||||||
case kObjectsNewToOld:
|
case kObjectsNewToOld:
|
||||||
success = object_visitor.VisitBlackObjects(
|
LiveObjectVisitor::VisitBlackObjectsNoFail(
|
||||||
page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
|
page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
|
||||||
DCHECK(success);
|
|
||||||
ArrayBufferTracker::ProcessBuffers(
|
ArrayBufferTracker::ProcessBuffers(
|
||||||
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
|
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
|
||||||
break;
|
break;
|
||||||
case kPageNewToOld:
|
case kPageNewToOld:
|
||||||
success = object_visitor.VisitBlackObjects(
|
LiveObjectVisitor::VisitBlackObjectsNoFail(
|
||||||
page, state, &new_to_old_page_visitor_,
|
page, state, &new_to_old_page_visitor_,
|
||||||
LiveObjectVisitor::kKeepMarking);
|
LiveObjectVisitor::kKeepMarking);
|
||||||
DCHECK(success);
|
|
||||||
new_to_old_page_visitor_.account_moved_bytes(state.live_bytes());
|
new_to_old_page_visitor_.account_moved_bytes(state.live_bytes());
|
||||||
// ArrayBufferTracker will be updated during sweeping.
|
// ArrayBufferTracker will be updated during sweeping.
|
||||||
break;
|
break;
|
||||||
case kPageNewToNew:
|
case kPageNewToNew:
|
||||||
success = object_visitor.VisitBlackObjects(
|
LiveObjectVisitor::VisitBlackObjectsNoFail(
|
||||||
page, state, &new_to_new_page_visitor_,
|
page, state, &new_to_new_page_visitor_,
|
||||||
LiveObjectVisitor::kKeepMarking);
|
LiveObjectVisitor::kKeepMarking);
|
||||||
DCHECK(success);
|
|
||||||
new_to_new_page_visitor_.account_moved_bytes(state.live_bytes());
|
new_to_new_page_visitor_.account_moved_bytes(state.live_bytes());
|
||||||
// ArrayBufferTracker will be updated during sweeping.
|
// ArrayBufferTracker will be updated during sweeping.
|
||||||
break;
|
break;
|
||||||
case kObjectsOldToOld:
|
case kObjectsOldToOld: {
|
||||||
success = object_visitor.VisitBlackObjects(
|
const bool success = LiveObjectVisitor::VisitBlackObjects(
|
||||||
page, state, &old_space_visitor_, LiveObjectVisitor::kClearMarkbits);
|
page, state, &old_space_visitor_, LiveObjectVisitor::kClearMarkbits,
|
||||||
|
&failed_object);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// Aborted compaction page. We have to record slots here, since we
|
// Aborted compaction page. Actual processing happens on the main
|
||||||
// might not have recorded them in first place.
|
// thread for simplicity reasons.
|
||||||
// Note: We mark the page as aborted here to be able to record slots
|
collector_->ReportAbortedEvacuationCandidate(failed_object, page);
|
||||||
// for code objects in |RecordMigratedSlotVisitor| and to be able
|
|
||||||
// to identify the page later on for post processing.
|
|
||||||
page->SetFlag(Page::COMPACTION_WAS_ABORTED);
|
|
||||||
EvacuateRecordOnlyVisitor record_visitor(heap());
|
|
||||||
success = object_visitor.VisitBlackObjects(
|
|
||||||
page, state, &record_visitor, LiveObjectVisitor::kKeepMarking);
|
|
||||||
ArrayBufferTracker::ProcessBuffers(
|
|
||||||
page, ArrayBufferTracker::kUpdateForwardedKeepOthers);
|
|
||||||
DCHECK(success);
|
|
||||||
success = false;
|
|
||||||
} else {
|
} else {
|
||||||
ArrayBufferTracker::ProcessBuffers(
|
ArrayBufferTracker::ProcessBuffers(
|
||||||
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
|
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class YoungGenerationEvacuator : public Evacuator {
|
class YoungGenerationEvacuator : public Evacuator {
|
||||||
@ -3683,30 +3668,26 @@ class YoungGenerationEvacuator : public Evacuator {
|
|||||||
: Evacuator(collector->heap(), record_visitor), collector_(collector) {}
|
: Evacuator(collector->heap(), record_visitor), collector_(collector) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool RawEvacuatePage(Page* page, intptr_t* live_bytes) override;
|
void RawEvacuatePage(Page* page, intptr_t* live_bytes) override;
|
||||||
|
|
||||||
MinorMarkCompactCollector* collector_;
|
MinorMarkCompactCollector* collector_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool YoungGenerationEvacuator::RawEvacuatePage(Page* page,
|
void YoungGenerationEvacuator::RawEvacuatePage(Page* page,
|
||||||
intptr_t* live_bytes) {
|
intptr_t* live_bytes) {
|
||||||
bool success = false;
|
|
||||||
LiveObjectVisitor object_visitor;
|
|
||||||
const MarkingState state = collector_->marking_state(page);
|
const MarkingState state = collector_->marking_state(page);
|
||||||
*live_bytes = state.live_bytes();
|
*live_bytes = state.live_bytes();
|
||||||
switch (ComputeEvacuationMode(page)) {
|
switch (ComputeEvacuationMode(page)) {
|
||||||
case kObjectsNewToOld:
|
case kObjectsNewToOld:
|
||||||
success = object_visitor.VisitGreyObjectsNoFail(
|
LiveObjectVisitor::VisitGreyObjectsNoFail(
|
||||||
page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
|
page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
|
||||||
DCHECK(success);
|
|
||||||
ArrayBufferTracker::ProcessBuffers(
|
ArrayBufferTracker::ProcessBuffers(
|
||||||
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
|
page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
|
||||||
break;
|
break;
|
||||||
case kPageNewToOld:
|
case kPageNewToOld:
|
||||||
success = object_visitor.VisitGreyObjectsNoFail(
|
LiveObjectVisitor::VisitGreyObjectsNoFail(
|
||||||
page, state, &new_to_old_page_visitor_,
|
page, state, &new_to_old_page_visitor_,
|
||||||
LiveObjectVisitor::kKeepMarking);
|
LiveObjectVisitor::kKeepMarking);
|
||||||
DCHECK(success);
|
|
||||||
new_to_old_page_visitor_.account_moved_bytes(state.live_bytes());
|
new_to_old_page_visitor_.account_moved_bytes(state.live_bytes());
|
||||||
// TODO(mlippautz): If cleaning array buffers is too slow here we can
|
// TODO(mlippautz): If cleaning array buffers is too slow here we can
|
||||||
// delay it until the next GC.
|
// delay it until the next GC.
|
||||||
@ -3723,10 +3704,9 @@ bool YoungGenerationEvacuator::RawEvacuatePage(Page* page,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kPageNewToNew:
|
case kPageNewToNew:
|
||||||
success = object_visitor.VisitGreyObjectsNoFail(
|
LiveObjectVisitor::VisitGreyObjectsNoFail(
|
||||||
page, state, &new_to_new_page_visitor_,
|
page, state, &new_to_new_page_visitor_,
|
||||||
LiveObjectVisitor::kKeepMarking);
|
LiveObjectVisitor::kKeepMarking);
|
||||||
DCHECK(success);
|
|
||||||
new_to_new_page_visitor_.account_moved_bytes(state.live_bytes());
|
new_to_new_page_visitor_.account_moved_bytes(state.live_bytes());
|
||||||
// TODO(mlippautz): If cleaning array buffers is too slow here we can
|
// TODO(mlippautz): If cleaning array buffers is too slow here we can
|
||||||
// delay it until the next GC.
|
// delay it until the next GC.
|
||||||
@ -3746,7 +3726,6 @@ bool YoungGenerationEvacuator::RawEvacuatePage(Page* page,
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PageEvacuationItem : public ItemParallelJob::Item {
|
class PageEvacuationItem : public ItemParallelJob::Item {
|
||||||
@ -4076,16 +4055,17 @@ bool MarkCompactCollector::WillBeDeoptimized(Code* code) {
|
|||||||
|
|
||||||
void MarkCompactCollector::RecordLiveSlotsOnPage(Page* page) {
|
void MarkCompactCollector::RecordLiveSlotsOnPage(Page* page) {
|
||||||
EvacuateRecordOnlyVisitor visitor(heap());
|
EvacuateRecordOnlyVisitor visitor(heap());
|
||||||
LiveObjectVisitor object_visitor;
|
LiveObjectVisitor::VisitBlackObjectsNoFail(page, MarkingState::Internal(page),
|
||||||
object_visitor.VisitBlackObjects(page, MarkingState::Internal(page), &visitor,
|
&visitor,
|
||||||
LiveObjectVisitor::kKeepMarking);
|
LiveObjectVisitor::kKeepMarking);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Visitor>
|
template <class Visitor>
|
||||||
bool LiveObjectVisitor::VisitBlackObjects(MemoryChunk* chunk,
|
bool LiveObjectVisitor::VisitBlackObjects(MemoryChunk* chunk,
|
||||||
const MarkingState& state,
|
const MarkingState& state,
|
||||||
Visitor* visitor,
|
Visitor* visitor,
|
||||||
IterationMode iteration_mode) {
|
IterationMode iteration_mode,
|
||||||
|
HeapObject** failed_object) {
|
||||||
for (auto object_and_size : LiveObjectRange<kBlackObjects>(chunk, state)) {
|
for (auto object_and_size : LiveObjectRange<kBlackObjects>(chunk, state)) {
|
||||||
HeapObject* const object = object_and_size.first;
|
HeapObject* const object = object_and_size.first;
|
||||||
if (!visitor->Visit(object, object_and_size.second)) {
|
if (!visitor->Visit(object, object_and_size.second)) {
|
||||||
@ -4093,12 +4073,7 @@ bool LiveObjectVisitor::VisitBlackObjects(MemoryChunk* chunk,
|
|||||||
state.bitmap()->ClearRange(
|
state.bitmap()->ClearRange(
|
||||||
chunk->AddressToMarkbitIndex(chunk->area_start()),
|
chunk->AddressToMarkbitIndex(chunk->area_start()),
|
||||||
chunk->AddressToMarkbitIndex(object->address()));
|
chunk->AddressToMarkbitIndex(object->address()));
|
||||||
RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, chunk->address(),
|
*failed_object = object;
|
||||||
object->address(),
|
|
||||||
SlotSet::PREFREE_EMPTY_BUCKETS);
|
|
||||||
RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(chunk, chunk->address(),
|
|
||||||
object->address());
|
|
||||||
RecomputeLiveBytes(chunk, state);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -4110,21 +4085,37 @@ bool LiveObjectVisitor::VisitBlackObjects(MemoryChunk* chunk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Visitor>
|
template <class Visitor>
|
||||||
bool LiveObjectVisitor::VisitGreyObjectsNoFail(MemoryChunk* chunk,
|
void LiveObjectVisitor::VisitBlackObjectsNoFail(MemoryChunk* chunk,
|
||||||
|
const MarkingState& state,
|
||||||
|
Visitor* visitor,
|
||||||
|
IterationMode iteration_mode) {
|
||||||
|
for (auto object_and_size : LiveObjectRange<kBlackObjects>(chunk, state)) {
|
||||||
|
HeapObject* const object = object_and_size.first;
|
||||||
|
DCHECK(ObjectMarking::IsBlack(object, state));
|
||||||
|
const bool success = visitor->Visit(object, object_and_size.second);
|
||||||
|
USE(success);
|
||||||
|
DCHECK(success);
|
||||||
|
}
|
||||||
|
if (iteration_mode == kClearMarkbits) {
|
||||||
|
state.ClearLiveness();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Visitor>
|
||||||
|
void LiveObjectVisitor::VisitGreyObjectsNoFail(MemoryChunk* chunk,
|
||||||
const MarkingState& state,
|
const MarkingState& state,
|
||||||
Visitor* visitor,
|
Visitor* visitor,
|
||||||
IterationMode iteration_mode) {
|
IterationMode iteration_mode) {
|
||||||
for (auto object_and_size : LiveObjectRange<kGreyObjects>(chunk, state)) {
|
for (auto object_and_size : LiveObjectRange<kGreyObjects>(chunk, state)) {
|
||||||
HeapObject* const object = object_and_size.first;
|
HeapObject* const object = object_and_size.first;
|
||||||
DCHECK(ObjectMarking::IsGrey(object, state));
|
DCHECK(ObjectMarking::IsGrey(object, state));
|
||||||
if (!visitor->Visit(object, object_and_size.second)) {
|
const bool success = visitor->Visit(object, object_and_size.second);
|
||||||
UNREACHABLE();
|
USE(success);
|
||||||
}
|
DCHECK(success);
|
||||||
}
|
}
|
||||||
if (iteration_mode == kClearMarkbits) {
|
if (iteration_mode == kClearMarkbits) {
|
||||||
state.ClearLiveness();
|
state.ClearLiveness();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LiveObjectVisitor::RecomputeLiveBytes(MemoryChunk* chunk,
|
void LiveObjectVisitor::RecomputeLiveBytes(MemoryChunk* chunk,
|
||||||
@ -4560,18 +4551,56 @@ void MinorMarkCompactCollector::UpdatePointersAfterEvacuation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MarkCompactCollector::ReportAbortedEvacuationCandidate(
|
||||||
|
HeapObject* failed_object, Page* page) {
|
||||||
|
base::LockGuard<base::Mutex> guard(&mutex_);
|
||||||
|
|
||||||
|
page->SetFlag(Page::COMPACTION_WAS_ABORTED);
|
||||||
|
aborted_evacuation_candidates_.push_back(std::make_pair(failed_object, page));
|
||||||
|
}
|
||||||
|
|
||||||
void MarkCompactCollector::PostProcessEvacuationCandidates() {
|
void MarkCompactCollector::PostProcessEvacuationCandidates() {
|
||||||
int aborted_pages = 0;
|
for (auto object_and_page : aborted_evacuation_candidates_) {
|
||||||
|
HeapObject* failed_object = object_and_page.first;
|
||||||
|
Page* page = object_and_page.second;
|
||||||
|
DCHECK(page->IsFlagSet(Page::COMPACTION_WAS_ABORTED));
|
||||||
|
// Aborted compaction page. We have to record slots here, since we
|
||||||
|
// might not have recorded them in first place.
|
||||||
|
|
||||||
|
// Remove outdated slots.
|
||||||
|
RememberedSet<OLD_TO_NEW>::RemoveRange(page, page->address(),
|
||||||
|
failed_object->address(),
|
||||||
|
SlotSet::PREFREE_EMPTY_BUCKETS);
|
||||||
|
RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, page->address(),
|
||||||
|
failed_object->address());
|
||||||
|
const MarkingState state = marking_state(page);
|
||||||
|
// Recompute live bytes.
|
||||||
|
LiveObjectVisitor::RecomputeLiveBytes(page, state);
|
||||||
|
// Re-record slots.
|
||||||
|
EvacuateRecordOnlyVisitor record_visitor(heap());
|
||||||
|
LiveObjectVisitor::VisitBlackObjectsNoFail(page, state, &record_visitor,
|
||||||
|
LiveObjectVisitor::kKeepMarking);
|
||||||
|
// Fix up array buffers.
|
||||||
|
ArrayBufferTracker::ProcessBuffers(
|
||||||
|
page, ArrayBufferTracker::kUpdateForwardedKeepOthers);
|
||||||
|
}
|
||||||
|
const int aborted_pages =
|
||||||
|
static_cast<int>(aborted_evacuation_candidates_.size());
|
||||||
|
aborted_evacuation_candidates_.clear();
|
||||||
|
int aborted_pages_verified = 0;
|
||||||
for (Page* p : old_space_evacuation_pages_) {
|
for (Page* p : old_space_evacuation_pages_) {
|
||||||
if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) {
|
if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) {
|
||||||
|
// After clearing the evacuation candidate flag the page is again in a
|
||||||
|
// regular state.
|
||||||
p->ClearEvacuationCandidate();
|
p->ClearEvacuationCandidate();
|
||||||
aborted_pages++;
|
aborted_pages_verified++;
|
||||||
} else {
|
} else {
|
||||||
DCHECK(p->IsEvacuationCandidate());
|
DCHECK(p->IsEvacuationCandidate());
|
||||||
DCHECK(p->SweepingDone());
|
DCHECK(p->SweepingDone());
|
||||||
p->Unlink();
|
p->Unlink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DCHECK_EQ(aborted_pages_verified, aborted_pages);
|
||||||
if (FLAG_trace_evacuation && (aborted_pages > 0)) {
|
if (FLAG_trace_evacuation && (aborted_pages > 0)) {
|
||||||
PrintIsolate(isolate(), "%8.0f ms: evacuation: aborted=%d\n",
|
PrintIsolate(isolate(), "%8.0f ms: evacuation: aborted=%d\n",
|
||||||
isolate()->time_millis_since_init(), aborted_pages);
|
isolate()->time_millis_since_init(), aborted_pages);
|
||||||
|
@ -230,28 +230,38 @@ class LiveObjectRange {
|
|||||||
Address end_;
|
Address end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LiveObjectVisitor BASE_EMBEDDED {
|
class LiveObjectVisitor : AllStatic {
|
||||||
public:
|
public:
|
||||||
enum IterationMode {
|
enum IterationMode {
|
||||||
kKeepMarking,
|
kKeepMarking,
|
||||||
kClearMarkbits,
|
kClearMarkbits,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Visits black objects on a MemoryChunk until the Visitor returns for an
|
// Visits black objects on a MemoryChunk until the Visitor returns |false| for
|
||||||
// object. If IterationMode::kClearMarkbits is passed the markbits and slots
|
// an object. If IterationMode::kClearMarkbits is passed the markbits and
|
||||||
// for visited objects are cleared for each successfully visited object.
|
// slots for visited objects are cleared for each successfully visited object.
|
||||||
template <class Visitor>
|
template <class Visitor>
|
||||||
bool VisitBlackObjects(MemoryChunk* chunk, const MarkingState& state,
|
static bool VisitBlackObjects(MemoryChunk* chunk, const MarkingState& state,
|
||||||
Visitor* visitor, IterationMode iteration_mode);
|
Visitor* visitor, IterationMode iteration_mode,
|
||||||
|
HeapObject** failed_object);
|
||||||
|
|
||||||
// Visits grey objects on a Memorychunk. Is not allowed to fail visitation
|
// Visits black objects on a MemoryChunk. The visitor is not allowed to fail
|
||||||
// for an object.
|
// visitation for an object.
|
||||||
template <class Visitor>
|
template <class Visitor>
|
||||||
bool VisitGreyObjectsNoFail(MemoryChunk* chunk, const MarkingState& state,
|
static void VisitBlackObjectsNoFail(MemoryChunk* chunk,
|
||||||
Visitor* visitor, IterationMode iteration_mode);
|
const MarkingState& state,
|
||||||
|
Visitor* visitor,
|
||||||
|
IterationMode iteration_mode);
|
||||||
|
|
||||||
private:
|
// Visits black objects on a MemoryChunk. The visitor is not allowed to fail
|
||||||
void RecomputeLiveBytes(MemoryChunk* chunk, const MarkingState& state);
|
// visitation for an object.
|
||||||
|
template <class Visitor>
|
||||||
|
static void VisitGreyObjectsNoFail(MemoryChunk* chunk,
|
||||||
|
const MarkingState& state,
|
||||||
|
Visitor* visitor,
|
||||||
|
IterationMode iteration_mode);
|
||||||
|
|
||||||
|
static void RecomputeLiveBytes(MemoryChunk* chunk, const MarkingState& state);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PageEvacuationMode { NEW_TO_NEW, NEW_TO_OLD };
|
enum PageEvacuationMode { NEW_TO_NEW, NEW_TO_OLD };
|
||||||
@ -744,7 +754,9 @@ class MarkCompactCollector final : public MarkCompactCollectorBase {
|
|||||||
|
|
||||||
void ReleaseEvacuationCandidates();
|
void ReleaseEvacuationCandidates();
|
||||||
void PostProcessEvacuationCandidates();
|
void PostProcessEvacuationCandidates();
|
||||||
|
void ReportAbortedEvacuationCandidate(HeapObject* failed_object, Page* page);
|
||||||
|
|
||||||
|
base::Mutex mutex_;
|
||||||
base::Semaphore page_parallel_job_semaphore_;
|
base::Semaphore page_parallel_job_semaphore_;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -781,10 +793,12 @@ class MarkCompactCollector final : public MarkCompactCollectorBase {
|
|||||||
// Pages that are actually processed during evacuation.
|
// Pages that are actually processed during evacuation.
|
||||||
List<Page*> old_space_evacuation_pages_;
|
List<Page*> old_space_evacuation_pages_;
|
||||||
List<Page*> new_space_evacuation_pages_;
|
List<Page*> new_space_evacuation_pages_;
|
||||||
|
std::vector<std::pair<HeapObject*, Page*>> aborted_evacuation_candidates_;
|
||||||
|
|
||||||
Sweeper sweeper_;
|
Sweeper sweeper_;
|
||||||
|
|
||||||
friend class CodeMarkingVisitor;
|
friend class CodeMarkingVisitor;
|
||||||
|
friend class FullEvacuator;
|
||||||
friend class Heap;
|
friend class Heap;
|
||||||
friend class IncrementalMarkingMarkingVisitor;
|
friend class IncrementalMarkingMarkingVisitor;
|
||||||
friend class MarkCompactMarkingVisitor;
|
friend class MarkCompactMarkingVisitor;
|
||||||
|
Loading…
Reference in New Issue
Block a user