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

Unified Diff: src/heap/mark-compact.cc

Issue 1488593003: Optimize clearing of map transitions. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Address comment Created 5 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
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/objects-visiting.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/heap/mark-compact.cc
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc
index 42cb71e8e182f30913ebff21b44ab84a601f47bd..82031986e0540ed09463b23f84510e0ef77c3896 100644
--- a/src/heap/mark-compact.cc
+++ b/src/heap/mark-compact.cc
@@ -362,7 +362,9 @@ void MarkCompactCollector::CollectGarbage() {
DCHECK(heap_->incremental_marking()->IsStopped());
- ProcessWeakReferences();
+ ClearNonLiveReferences();
+
+ ClearWeakCollections();
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
@@ -1937,33 +1939,6 @@ void MarkCompactCollector::RetainMaps() {
}
-DependentCode* MarkCompactCollector::DependentCodeListFromNonLiveMaps() {
- GCTracer::Scope gc_scope(heap()->tracer(),
- GCTracer::Scope::MC_EXTRACT_DEPENDENT_CODE);
- ArrayList* retained_maps = heap()->retained_maps();
- int length = retained_maps->Length();
- DependentCode* head = DependentCode::cast(heap()->empty_fixed_array());
- for (int i = 0; i < length; i += 2) {
- DCHECK(retained_maps->Get(i)->IsWeakCell());
- WeakCell* cell = WeakCell::cast(retained_maps->Get(i));
- DCHECK(!cell->cleared());
- Map* map = Map::cast(cell->value());
- MarkBit map_mark = Marking::MarkBitFrom(map);
- if (Marking::IsWhite(map_mark)) {
- DependentCode* candidate = map->dependent_code();
- // We rely on the fact that the weak code group comes first.
- STATIC_ASSERT(DependentCode::kWeakCodeGroup == 0);
- if (candidate->length() > 0 &&
- candidate->group() == DependentCode::kWeakCodeGroup) {
- candidate->set_next_link(head);
- head = candidate;
- }
- }
- }
- return head;
-}
-
-
void MarkCompactCollector::EnsureMarkingDequeIsReserved() {
DCHECK(!marking_deque_.in_use());
if (marking_deque_memory_ == NULL) {
@@ -2270,42 +2245,34 @@ void MarkCompactCollector::ProcessAndClearOptimizedCodeMaps() {
}
-void MarkCompactCollector::ProcessWeakReferences() {
- // This should be done before processing weak cells because it checks
- // mark bits of maps in weak cells.
- DependentCode* dependent_code_list = DependentCodeListFromNonLiveMaps();
-
- // Process weak cells before MarkCodeForDeoptimization and
- // ClearNonLiveReferences so that weak cells in dependent code arrays are
- // cleared or contain only live code objects.
- ProcessAndClearWeakCells();
+void MarkCompactCollector::ClearNonLiveReferences() {
+ GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_CLEAR);
- MarkDependentCodeListForDeoptimization(dependent_code_list);
+ DependentCode* dependent_code_list;
+ Object* non_live_map_list;
+ ClearWeakCells(&non_live_map_list, &dependent_code_list);
- ClearNonLiveReferences();
+ {
+ GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_CLEAR_MAP);
+ ClearSimpleMapTransitions(non_live_map_list);
+ ClearFullMapTransitions();
+ }
- ClearWeakCollections();
+ MarkDependentCodeForDeoptimization(dependent_code_list);
}
-void MarkCompactCollector::ClearNonLiveReferences() {
+void MarkCompactCollector::MarkDependentCodeForDeoptimization(
+ DependentCode* list_head) {
GCTracer::Scope gc_scope(heap()->tracer(),
- GCTracer::Scope::MC_NONLIVEREFERENCES);
+ GCTracer::Scope::MC_CLEAR_DEPENDENT_CODE);
- ProcessAndClearTransitionArrays();
-
- // Iterate over the map space, setting map transitions that go from
- // a marked map to an unmarked map to null transitions. This action
- // is carried out only on maps of JSObjects and related subtypes.
- HeapObjectIterator map_iterator(heap()->map_space());
- for (HeapObject* obj = map_iterator.Next(); obj != NULL;
- obj = map_iterator.Next()) {
- Map* map = Map::cast(obj);
- if (!map->CanTransition()) continue;
- MarkBit map_mark = Marking::MarkBitFrom(map);
- if (Marking::IsWhite(map_mark)) {
- ClearNonLiveMapTransitions(map);
- }
+ Isolate* isolate = this->isolate();
+ DependentCode* current = list_head;
+ while (current->length() > 0) {
+ have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization(
+ isolate, DependentCode::kWeakCodeGroup);
+ current = current->next_link();
}
WeakHashTable* table = heap_->weak_object_to_code_table();
@@ -2320,7 +2287,7 @@ void MarkCompactCollector::ClearNonLiveReferences() {
if (WeakCell::cast(key)->cleared()) {
have_code_to_deoptimize_ |=
DependentCode::cast(value)->MarkCodeForDeoptimization(
- isolate(), DependentCode::kWeakCodeGroup);
+ isolate, DependentCode::kWeakCodeGroup);
table->set(key_index, heap_->the_hole_value());
table->set(value_index, heap_->the_hole_value());
table->ElementRemoved();
@@ -2329,146 +2296,145 @@ void MarkCompactCollector::ClearNonLiveReferences() {
}
-void MarkCompactCollector::MarkDependentCodeListForDeoptimization(
- DependentCode* list_head) {
- GCTracer::Scope gc_scope(heap()->tracer(),
- GCTracer::Scope::MC_DEOPT_DEPENDENT_CODE);
- Isolate* isolate = this->isolate();
- DependentCode* current = list_head;
- while (current->length() > 0) {
- have_code_to_deoptimize_ |= current->MarkCodeForDeoptimization(
- isolate, DependentCode::kWeakCodeGroup);
- current = current->next_link();
- }
-}
-
-
-void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map) {
- Object* potential_parent = map->GetBackPointer();
- if (!potential_parent->IsMap()) return;
- Map* parent = Map::cast(potential_parent);
-
- // Follow back pointer, check whether we are dealing with a map transition
- // from a live map to a dead path and in case clear transitions of parent.
- DCHECK(!Marking::IsGrey(Marking::MarkBitFrom(map)));
- bool parent_is_alive = Marking::IsBlack(Marking::MarkBitFrom(parent));
- if (parent_is_alive) {
- ClearMapTransitions(parent, map);
+void MarkCompactCollector::ClearSimpleMapTransitions(
+ Object* non_live_map_list) {
+ Object* the_hole_value = heap()->the_hole_value();
+ Object* weak_cell_obj = non_live_map_list;
+ while (weak_cell_obj != Smi::FromInt(0)) {
+ WeakCell* weak_cell = WeakCell::cast(weak_cell_obj);
+ Map* map = Map::cast(weak_cell->value());
+ DCHECK(Marking::IsWhite(Marking::MarkBitFrom(map)));
+ Object* potential_parent = map->constructor_or_backpointer();
+ if (potential_parent->IsMap()) {
+ Map* parent = Map::cast(potential_parent);
+ if (Marking::IsBlackOrGrey(Marking::MarkBitFrom(parent)) &&
+ parent->raw_transitions() == weak_cell) {
+ ClearSimpleMapTransition(parent, map);
+ }
+ }
+ weak_cell->clear();
+ weak_cell_obj = weak_cell->next();
+ weak_cell->clear_next(the_hole_value);
}
}
-// Clear a possible back pointer in case the transition leads to a dead map.
-// Return true in case a back pointer has been cleared and false otherwise.
-bool MarkCompactCollector::ClearMapBackPointer(Map* target) {
- DCHECK(!Marking::IsGrey(Marking::MarkBitFrom(target)));
- if (Marking::IsBlack(Marking::MarkBitFrom(target))) return false;
- target->SetBackPointer(heap_->undefined_value(), SKIP_WRITE_BARRIER);
- return true;
-}
-
-
-void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
- Object* transitions = map->raw_transitions();
- int num_transitions = TransitionArray::NumberOfTransitions(transitions);
-
+void MarkCompactCollector::ClearSimpleMapTransition(Map* map,
+ Map* dead_transition) {
+ // A previously existing simple transition (stored in a WeakCell) is going
+ // to be cleared. Clear the useless cell pointer, and take ownership
+ // of the descriptor array.
+ map->set_raw_transitions(Smi::FromInt(0));
int number_of_own_descriptors = map->NumberOfOwnDescriptors();
DescriptorArray* descriptors = map->instance_descriptors();
-
- // A previously existing simple transition (stored in a WeakCell) may have
- // been cleared. Clear the useless cell pointer, and take ownership
- // of the descriptor array.
- if (transitions->IsWeakCell() && WeakCell::cast(transitions)->cleared()) {
- map->set_raw_transitions(Smi::FromInt(0));
- }
- if (num_transitions == 0 &&
- descriptors == dead_transition->instance_descriptors() &&
+ if (descriptors == dead_transition->instance_descriptors() &&
number_of_own_descriptors > 0) {
- TrimDescriptorArray(map, descriptors, number_of_own_descriptors);
+ TrimDescriptorArray(map, descriptors);
DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
map->set_owns_descriptors(true);
- return;
}
+}
- int transition_index = 0;
- bool descriptors_owner_died = false;
+void MarkCompactCollector::ClearFullMapTransitions() {
+ HeapObject* undefined = heap()->undefined_value();
+ Object* obj = heap()->encountered_transition_arrays();
+ while (obj != Smi::FromInt(0)) {
+ TransitionArray* array = TransitionArray::cast(obj);
+ int num_transitions = array->number_of_entries();
+ DCHECK_EQ(TransitionArray::NumberOfTransitions(array), num_transitions);
+ if (num_transitions > 0) {
+ Map* map = array->GetTarget(0);
+ Map* parent = Map::cast(map->constructor_or_backpointer());
+ bool parent_is_alive =
+ Marking::IsBlackOrGrey(Marking::MarkBitFrom(parent));
+ DescriptorArray* descriptors =
+ parent_is_alive ? parent->instance_descriptors() : nullptr;
+ bool descriptors_owner_died =
+ CompactTransitionArray(parent, array, descriptors);
+ if (descriptors_owner_died) {
+ TrimDescriptorArray(parent, descriptors);
+ }
+ }
+ obj = array->next_link();
+ array->set_next_link(undefined, SKIP_WRITE_BARRIER);
+ }
+ heap()->set_encountered_transition_arrays(Smi::FromInt(0));
+}
+
- // Compact all live descriptors to the left.
+bool MarkCompactCollector::CompactTransitionArray(
+ Map* map, TransitionArray* transitions, DescriptorArray* descriptors) {
+ int num_transitions = transitions->number_of_entries();
+ bool descriptors_owner_died = false;
+ int transition_index = 0;
+ // Compact all live transitions to the left.
for (int i = 0; i < num_transitions; ++i) {
- Map* target = TransitionArray::GetTarget(transitions, i);
- if (ClearMapBackPointer(target)) {
- if (target->instance_descriptors() == descriptors) {
+ Map* target = transitions->GetTarget(i);
+ DCHECK_EQ(target->constructor_or_backpointer(), map);
+ if (Marking::IsWhite(Marking::MarkBitFrom(target))) {
+ if (descriptors != nullptr &&
+ target->instance_descriptors() == descriptors) {
descriptors_owner_died = true;
}
} else {
if (i != transition_index) {
- DCHECK(TransitionArray::IsFullTransitionArray(transitions));
- TransitionArray* t = TransitionArray::cast(transitions);
- Name* key = t->GetKey(i);
- t->SetKey(transition_index, key);
- Object** key_slot = t->GetKeySlot(transition_index);
- RecordSlot(t, key_slot, key);
+ Name* key = transitions->GetKey(i);
+ transitions->SetKey(transition_index, key);
+ Object** key_slot = transitions->GetKeySlot(transition_index);
+ RecordSlot(transitions, key_slot, key);
// Target slots do not need to be recorded since maps are not compacted.
- t->SetTarget(transition_index, t->GetTarget(i));
+ transitions->SetTarget(transition_index, transitions->GetTarget(i));
}
transition_index++;
}
}
-
// If there are no transitions to be cleared, return.
- // TODO(verwaest) Should be an assert, otherwise back pointers are not
- // properly cleared.
- if (transition_index == num_transitions) return;
-
- if (descriptors_owner_died) {
- if (number_of_own_descriptors > 0) {
- TrimDescriptorArray(map, descriptors, number_of_own_descriptors);
- DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
- map->set_owns_descriptors(true);
- } else {
- DCHECK(descriptors == heap_->empty_descriptor_array());
- }
+ if (transition_index == num_transitions) {
+ DCHECK(!descriptors_owner_died);
+ return false;
}
-
// Note that we never eliminate a transition array, though we might right-trim
// such that number_of_transitions() == 0. If this assumption changes,
// TransitionArray::Insert() will need to deal with the case that a transition
// array disappeared during GC.
int trim = TransitionArray::Capacity(transitions) - transition_index;
if (trim > 0) {
- // Non-full-TransitionArray cases can never reach this point.
- DCHECK(TransitionArray::IsFullTransitionArray(transitions));
- TransitionArray* t = TransitionArray::cast(transitions);
heap_->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(
- t, trim * TransitionArray::kTransitionSize);
- t->SetNumberOfTransitions(transition_index);
- // The map still has a full transition array.
- DCHECK(TransitionArray::IsFullTransitionArray(map->raw_transitions()));
+ transitions, trim * TransitionArray::kTransitionSize);
+ transitions->SetNumberOfTransitions(transition_index);
}
+ return descriptors_owner_died;
}
void MarkCompactCollector::TrimDescriptorArray(Map* map,
- DescriptorArray* descriptors,
- int number_of_own_descriptors) {
+ DescriptorArray* descriptors) {
+ int number_of_own_descriptors = map->NumberOfOwnDescriptors();
+ if (number_of_own_descriptors == 0) {
+ DCHECK(descriptors == heap_->empty_descriptor_array());
+ return;
+ }
+
int number_of_descriptors = descriptors->number_of_descriptors_storage();
int to_trim = number_of_descriptors - number_of_own_descriptors;
- if (to_trim == 0) return;
-
- heap_->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(
- descriptors, to_trim * DescriptorArray::kDescriptorSize);
- descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
+ if (to_trim > 0) {
+ heap_->RightTrimFixedArray<Heap::SEQUENTIAL_TO_SWEEPER>(
+ descriptors, to_trim * DescriptorArray::kDescriptorSize);
+ descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
- if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors);
- descriptors->Sort();
+ if (descriptors->HasEnumCache()) TrimEnumCache(map, descriptors);
+ descriptors->Sort();
- if (FLAG_unbox_double_fields) {
- LayoutDescriptor* layout_descriptor = map->layout_descriptor();
- layout_descriptor = layout_descriptor->Trim(heap_, map, descriptors,
- number_of_own_descriptors);
- SLOW_DCHECK(layout_descriptor->IsConsistentWithMap(map, true));
+ if (FLAG_unbox_double_fields) {
+ LayoutDescriptor* layout_descriptor = map->layout_descriptor();
+ layout_descriptor = layout_descriptor->Trim(heap_, map, descriptors,
+ number_of_own_descriptors);
+ SLOW_DCHECK(layout_descriptor->IsConsistentWithMap(map, true));
+ }
}
+ DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
+ map->set_owns_descriptors(true);
}
@@ -2560,11 +2526,20 @@ void MarkCompactCollector::AbortWeakCollections() {
}
-void MarkCompactCollector::ProcessAndClearWeakCells() {
- GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_WEAKCELL);
- Object* weak_cell_obj = heap()->encountered_weak_cells();
+void MarkCompactCollector::ClearWeakCells(Object** non_live_map_list,
+ DependentCode** dependent_code_list) {
+ Heap* heap = this->heap();
+ GCTracer::Scope gc_scope(heap->tracer(), GCTracer::Scope::MC_CLEAR_WEAKCELL);
+ Object* weak_cell_obj = heap->encountered_weak_cells();
+ Object* the_hole_value = heap->the_hole_value();
+ DependentCode* dependent_code_head =
+ DependentCode::cast(heap->empty_fixed_array());
+ Object* non_live_map_head = Smi::FromInt(0);
while (weak_cell_obj != Smi::FromInt(0)) {
WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
+ Object* next_weak_cell = weak_cell->next();
+ bool clear_value = true;
+ bool clear_next = true;
// We do not insert cleared weak cells into the list, so the value
// cannot be a Smi here.
HeapObject* value = HeapObject::cast(weak_cell->value());
@@ -2585,47 +2560,59 @@ void MarkCompactCollector::ProcessAndClearWeakCells() {
RecordSlot(value, slot, *slot);
slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset);
RecordSlot(weak_cell, slot, *slot);
- } else {
- weak_cell->clear();
+ clear_value = false;
}
- } else {
- weak_cell->clear();
+ }
+ if (value->IsMap()) {
+ // The map is non-live.
+ Map* map = Map::cast(value);
+ // Add dependent code to the dependent_code_list.
+ DependentCode* candidate = map->dependent_code();
+ // We rely on the fact that the weak code group comes first.
+ STATIC_ASSERT(DependentCode::kWeakCodeGroup == 0);
+ if (candidate->length() > 0 &&
+ candidate->group() == DependentCode::kWeakCodeGroup) {
+ candidate->set_next_link(dependent_code_head);
+ dependent_code_head = candidate;
+ }
+ // Add the weak cell to the non_live_map list.
+ weak_cell->set_next(non_live_map_head);
+ non_live_map_head = weak_cell;
+ clear_value = false;
+ clear_next = false;
}
} else {
+ // The value of the weak cell is alive.
Object** slot = HeapObject::RawField(weak_cell, WeakCell::kValueOffset);
RecordSlot(weak_cell, slot, *slot);
+ clear_value = false;
}
- weak_cell_obj = weak_cell->next();
- weak_cell->clear_next(heap());
+ if (clear_value) {
+ weak_cell->clear();
+ }
+ if (clear_next) {
+ weak_cell->clear_next(the_hole_value);
+ }
+ weak_cell_obj = next_weak_cell;
}
- heap()->set_encountered_weak_cells(Smi::FromInt(0));
+ heap->set_encountered_weak_cells(Smi::FromInt(0));
+ *non_live_map_list = non_live_map_head;
+ *dependent_code_list = dependent_code_head;
}
void MarkCompactCollector::AbortWeakCells() {
+ Object* the_hole_value = heap()->the_hole_value();
Object* weak_cell_obj = heap()->encountered_weak_cells();
while (weak_cell_obj != Smi::FromInt(0)) {
WeakCell* weak_cell = reinterpret_cast<WeakCell*>(weak_cell_obj);
weak_cell_obj = weak_cell->next();
- weak_cell->clear_next(heap());
+ weak_cell->clear_next(the_hole_value);
}
heap()->set_encountered_weak_cells(Smi::FromInt(0));
}
-void MarkCompactCollector::ProcessAndClearTransitionArrays() {
- HeapObject* undefined = heap()->undefined_value();
- Object* obj = heap()->encountered_transition_arrays();
- while (obj != Smi::FromInt(0)) {
- TransitionArray* array = TransitionArray::cast(obj);
- // TODO(ulan): move logic from ClearMapTransitions here.
- obj = array->next_link();
- array->set_next_link(undefined, SKIP_WRITE_BARRIER);
- }
- heap()->set_encountered_transition_arrays(Smi::FromInt(0));
-}
-
-
void MarkCompactCollector::AbortTransitionArrays() {
HeapObject* undefined = heap()->undefined_value();
Object* obj = heap()->encountered_transition_arrays();
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/objects-visiting.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698