Index: src/heap/mark-compact.cc |
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc |
index 0a8e48387ad7a10eb4cf7476175afdfd00ac413e..c80f837fcd51a340d3e42aaac5b110c63b12eb7b 100644 |
--- a/src/heap/mark-compact.cc |
+++ b/src/heap/mark-compact.cc |
@@ -2123,6 +2123,52 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { |
} |
+void MarkCompactCollector::RetainMaps(ObjectVisitor* visitor) { |
+ if (reduce_memory_footprint_ || abort_incremental_marking_ || |
+ 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; |
+ } |
+ |
+ HeapObjectIterator map_iterator(heap()->map_space()); |
+ // The retaining counter goes from Map::kRetainingCounterStart |
+ // down to Map::kRetainingCounterEnd. This range can be narrowed |
+ // by the FLAG_retain_maps_for_n_gc flag. |
+ int retaining_counter_end = |
+ Max(Map::kRetainingCounterEnd, |
+ Map::kRetainingCounterStart - FLAG_retain_maps_for_n_gc); |
+ for (HeapObject* obj = map_iterator.Next(); obj != NULL; |
+ obj = map_iterator.Next()) { |
+ Map* map = Map::cast(obj); |
+ MarkBit map_mark = Marking::MarkBitFrom(map); |
+ int counter = map->counter(); |
+ if (!map_mark.Get()) { |
+ if (counter > Map::kRetainingCounterStart || |
+ counter <= retaining_counter_end) { |
+ // The counter is outside of retaining range. Do not retain this map. |
+ continue; |
+ } |
+ Object* constructor = map->constructor(); |
+ if (!constructor->IsHeapObject() || |
+ !Marking::MarkBitFrom(HeapObject::cast(constructor)).Get()) { |
+ // The constructor is dead, no new objects with this map can |
+ // be created. Do not retain this map. |
+ continue; |
+ } |
+ map->set_counter(counter - 1); |
+ SetMark(map, map_mark); |
+ MarkCompactMarkingVisitor::IterateBody(map->map(), map); |
+ } else if (counter < Map::kRetainingCounterStart) { |
+ // Reset the counter for live maps. |
+ map->set_counter(Map::kRetainingCounterStart); |
+ } |
+ } |
+ ProcessMarkingDeque(); |
+} |
+ |
+ |
void MarkCompactCollector::EnsureMarkingDequeIsCommittedAndInitialize() { |
if (marking_deque_memory_ == NULL) { |
marking_deque_memory_ = new base::VirtualMemory(4 * MB); |
@@ -2222,6 +2268,11 @@ void MarkCompactCollector::MarkLiveObjects() { |
ProcessTopOptimizedFrame(&root_visitor); |
+ // Retaining dying maps should happen before or during ephemeral marking |
+ // because a map could keep the key of an ephemeron alive. Note that map |
+ // aging is imprecise: maps that are kept alive only by ephemerons will age. |
+ RetainMaps(&root_visitor); |
+ |
{ |
GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_WEAKCLOSURE); |