Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index 7b3c2a8c6eb75140aa1783353d3ae8b945a35c17..a58b0678b5fae004175fb8935372c8ee9559d7b4 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -349,16 +349,7 @@ void MarkCompactCollector::CollectGarbage() { |
DCHECK(heap_->incremental_marking()->IsStopped()); |
- // ClearNonLiveReferences can deoptimize code in dependent code arrays. |
- // Process weak cells before so that weak cells in dependent code |
- // arrays are cleared or contain only live code objects. |
- ProcessAndClearWeakCells(); |
- |
- ClearNonLiveReferences(); |
- |
- ClearWeakCollections(); |
- |
- heap_->set_encountered_weak_cells(Smi::FromInt(0)); |
+ ProcessWeakReferences(); |
#ifdef VERIFY_HEAP |
if (FLAG_verify_heap) { |
@@ -1821,18 +1812,40 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { |
} |
-void MarkCompactCollector::RetainMaps() { |
- if (heap()->ShouldReduceMemory() || heap()->ShouldAbortIncrementalMarking() || |
- FLAG_retain_maps_for_n_gc == 0) { |
- // Do not retain dead maps if flag disables it or there is |
- // - memory pressure (reduce_memory_footprint_), |
- // - GC is requested by tests or dev-tools (abort_incremental_marking_). |
- return; |
+bool ShouldRetainMap(Map* map, int age) { |
+ if (age == 0) { |
+ // The map has aged. Do not retain this map. |
+ return false; |
} |
+ Object* constructor = map->GetConstructor(); |
+ if (!constructor->IsHeapObject() || |
+ Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(constructor)))) { |
+ // The constructor is dead, no new objects with this map can |
+ // be created. Do not retain this map. |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+ |
+void MarkCompactCollector::RetainMaps() { |
+ // Do not retain dead maps if flag disables it or there is |
+ // - memory pressure (reduce_memory_footprint_), |
+ // - GC is requested by tests or dev-tools (abort_incremental_marking_). |
+ bool map_retaining_is_disabled = heap()->ShouldReduceMemory() || |
+ heap()->ShouldAbortIncrementalMarking() || |
+ FLAG_retain_maps_for_n_gc == 0; |
ArrayList* retained_maps = heap()->retained_maps(); |
int length = retained_maps->Length(); |
int new_length = 0; |
+ // The number_of_disposed_maps separates maps in the retained_maps |
+ // array that were created before and after context disposal. |
+ // We do not age and retain disposed maps to avoid memory leaks. |
+ int number_of_disposed_maps = heap()->number_of_disposed_maps_; |
+ int new_number_of_disposed_maps = 0; |
+ // This loop compacts the array by removing cleared weak cells, |
+ // ages and retains dead maps. |
for (int i = 0; i < length; i += 2) { |
DCHECK(retained_maps->Get(i)->IsWeakCell()); |
WeakCell* cell = WeakCell::cast(retained_maps->Get(i)); |
@@ -1841,20 +1854,13 @@ void MarkCompactCollector::RetainMaps() { |
int new_age; |
Map* map = Map::cast(cell->value()); |
MarkBit map_mark = Marking::MarkBitFrom(map); |
- if (Marking::IsWhite(map_mark)) { |
- if (age == 0) { |
- // The map has aged. Do not retain this map. |
- continue; |
- } |
- Object* constructor = map->GetConstructor(); |
- if (!constructor->IsHeapObject() || Marking::IsWhite(Marking::MarkBitFrom( |
- HeapObject::cast(constructor)))) { |
- // The constructor is dead, no new objects with this map can |
- // be created. Do not retain this map. |
- continue; |
+ if (i >= number_of_disposed_maps && !map_retaining_is_disabled && |
+ Marking::IsWhite(map_mark)) { |
+ if (ShouldRetainMap(map, age)) { |
+ MarkObject(map, map_mark); |
} |
Object* prototype = map->prototype(); |
- if (prototype->IsHeapObject() && |
+ if (age > 0 && prototype->IsHeapObject() && |
Marking::IsWhite(Marking::MarkBitFrom(HeapObject::cast(prototype)))) { |
// The prototype is not marked, age the map. |
new_age = age - 1; |
@@ -1863,10 +1869,10 @@ void MarkCompactCollector::RetainMaps() { |
// transition tree alive, not JSObjects. Do not age the map. |
new_age = age; |
} |
- MarkObject(map, map_mark); |
} else { |
new_age = FLAG_retain_maps_for_n_gc; |
} |
+ // Compact the array and update the age. |
if (i != new_length) { |
retained_maps->Set(new_length, cell); |
Object** slot = retained_maps->Slot(new_length); |
@@ -1875,8 +1881,12 @@ void MarkCompactCollector::RetainMaps() { |
} else if (new_age != age) { |
retained_maps->Set(new_length + 1, Smi::FromInt(new_age)); |
} |
+ if (i < number_of_disposed_maps) { |
+ new_number_of_disposed_maps++; |
+ } |
new_length += 2; |
} |
+ heap()->number_of_disposed_maps_ = new_number_of_disposed_maps; |
Object* undefined = heap()->undefined_value(); |
for (int i = new_length; i < length; i++) { |
retained_maps->Clear(i, undefined); |
@@ -1886,6 +1896,33 @@ 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) { |
@@ -2192,6 +2229,26 @@ 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(); |
+ |
+ MarkDependentCodeListForDeoptimization(dependent_code_list); |
+ |
+ ClearNonLiveReferences(); |
+ |
+ ClearWeakCollections(); |
+ |
+ heap_->set_encountered_weak_cells(Smi::FromInt(0)); |
+} |
+ |
+ |
void MarkCompactCollector::ClearNonLiveReferences() { |
GCTracer::Scope gc_scope(heap()->tracer(), |
GCTracer::Scope::MC_NONLIVEREFERENCES); |
@@ -2209,10 +2266,6 @@ void MarkCompactCollector::ClearNonLiveReferences() { |
ClearNonLivePrototypeTransitions(map); |
} else { |
ClearNonLiveMapTransitions(map); |
- have_code_to_deoptimize_ |= |
- map->dependent_code()->MarkCodeForDeoptimization( |
- isolate(), DependentCode::kWeakCodeGroup); |
- map->set_dependent_code(DependentCode::cast(heap()->empty_fixed_array())); |
} |
} |
@@ -2237,6 +2290,20 @@ 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::ClearNonLivePrototypeTransitions(Map* map) { |
FixedArray* prototype_transitions = |
TransitionArray::GetPrototypeTransitions(map); |