| Index: src/heap/heap.cc | 
| diff --git a/src/heap/heap.cc b/src/heap/heap.cc | 
| index c231623d52a16243bacdfe9b617916009ab0efe2..e24e345fb57b31bfb4e47680d9092b70ca09846c 100644 | 
| --- a/src/heap/heap.cc | 
| +++ b/src/heap/heap.cc | 
| @@ -4723,35 +4723,12 @@ void Heap::ZapFromSpace() { | 
| } | 
| } | 
|  | 
| -void Heap::IteratePromotedObjectPointers(HeapObject* object, Address start, | 
| -                                         Address end, bool record_slots, | 
| -                                         ObjectSlotCallback callback) { | 
| -  Address slot_address = start; | 
| -  Page* page = Page::FromAddress(start); | 
| - | 
| -  while (slot_address < end) { | 
| -    Object** slot = reinterpret_cast<Object**>(slot_address); | 
| -    Object* target = *slot; | 
| -    if (target->IsHeapObject()) { | 
| -      if (Heap::InFromSpace(target)) { | 
| -        callback(reinterpret_cast<HeapObject**>(slot), | 
| -                 HeapObject::cast(target)); | 
| -        Object* new_target = *slot; | 
| -        if (InNewSpace(new_target)) { | 
| -          SLOW_DCHECK(Heap::InToSpace(new_target)); | 
| -          SLOW_DCHECK(new_target->IsHeapObject()); | 
| -          RememberedSet<OLD_TO_NEW>::Insert(page, slot_address); | 
| -        } | 
| -        SLOW_DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(new_target)); | 
| -      } else if (record_slots && | 
| -                 MarkCompactCollector::IsOnEvacuationCandidate(target)) { | 
| -        mark_compact_collector()->RecordSlot(object, slot, target); | 
| -      } | 
| -    } | 
| -    slot_address += kPointerSize; | 
| -  } | 
| -} | 
| +enum IteratePromotedObjectsMode { | 
| +  RECORD_ONLY, | 
| +  RECORD_AND_SCAVENGE, | 
| +}; | 
|  | 
| +template <IteratePromotedObjectsMode mode> | 
| class IteratePromotedObjectsVisitor final : public ObjectVisitor { | 
| public: | 
| IteratePromotedObjectsVisitor(Heap* heap, HeapObject* target, | 
| @@ -4761,13 +4738,36 @@ class IteratePromotedObjectsVisitor final : public ObjectVisitor { | 
| record_slots_(record_slots), | 
| callback_(callback) {} | 
|  | 
| -  V8_INLINE void VisitPointers(Object** start, Object** end) override { | 
| -    heap_->IteratePromotedObjectPointers( | 
| -        target_, reinterpret_cast<Address>(start), | 
| -        reinterpret_cast<Address>(end), record_slots_, callback_); | 
| +  inline void VisitPointers(Object** start, Object** end) override { | 
| +    Address slot_address = reinterpret_cast<Address>(start); | 
| +    Page* page = Page::FromAddress(slot_address); | 
| + | 
| +    while (slot_address < reinterpret_cast<Address>(end)) { | 
| +      Object** slot = reinterpret_cast<Object**>(slot_address); | 
| +      Object* target = *slot; | 
| + | 
| +      if (mode == RECORD_AND_SCAVENGE && heap_->InNewSpace(target)) { | 
| +        callback_(reinterpret_cast<HeapObject**>(slot), | 
| +                  HeapObject::cast(target)); | 
| +        target = *slot; | 
| +        DCHECK(target->IsHeapObject); | 
| +        SLOW_DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(target)); | 
| +      } | 
| + | 
| +      if (heap_->InNewSpace(target)) { | 
| +        SLOW_DCHECK(Heap::InToSpace(new_target)); | 
| +        SLOW_DCHECK(new_target->IsHeapObject()); | 
| +        RememberedSet<OLD_TO_NEW>::Insert(page, slot_address); | 
| +      } else if (record_slots_ && | 
| +                 MarkCompactCollector::IsOnEvacuationCandidate(target)) { | 
| +        heap_->mark_compact_collector()->RecordSlot(target_, slot, target); | 
| +      } | 
| + | 
| +      slot_address += kPointerSize; | 
| +    } | 
| } | 
|  | 
| -  V8_INLINE void VisitCodeEntry(Address code_entry_slot) override { | 
| +  inline void VisitCodeEntry(Address code_entry_slot) override { | 
| // Black allocation requires us to process objects referenced by | 
| // promoted objects. | 
| if (heap_->incremental_marking()->black_allocation()) { | 
| @@ -4798,8 +4798,21 @@ void Heap::IteratePromotedObject(HeapObject* target, int size, | 
| record_slots = Marking::IsBlack(mark_bit); | 
| } | 
|  | 
| -  IteratePromotedObjectsVisitor visitor(this, target, record_slots, callback); | 
| -  target->IterateBody(target->map()->instance_type(), size, &visitor); | 
| +  IteratePromotedObjectsVisitor<RECORD_AND_SCAVENGE> | 
| +      record_and_scavenge_visitor(this, target, record_slots, callback); | 
| +  if (target->IsJSFunction()) { | 
| +    // JSFunctions reachable through kNextFunctionLinkOffset are weak and should | 
| +    // only trigger recording, not a scavenge. | 
| +    JSFunction::BodyDescriptorWeakCode::IterateBody( | 
| +        target, size, &record_and_scavenge_visitor); | 
| +    IteratePromotedObjectsVisitor<RECORD_ONLY> record_only_visitor( | 
| +        this, target, record_slots, callback); | 
| +    JSFunction::BodyDescriptorWeakFields::IterateBody(target, size, | 
| +                                                      &record_only_visitor); | 
| +  } else { | 
| +    target->IterateBody(target->map()->instance_type(), size, | 
| +                        &record_and_scavenge_visitor); | 
| +  } | 
|  | 
| // When black allocations is on, we have to visit not already marked black | 
| // objects (in new space) promoted to black pages to keep their references | 
|  |