| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/heap/mark-compact.h" | 5 #include "src/heap/mark-compact.h" |
| 6 | 6 |
| 7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
| 8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
| 9 #include "src/base/sys-info.h" | 9 #include "src/base/sys-info.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 1490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1501 HeapObject* object = NULL; | 1501 HeapObject* object = NULL; |
| 1502 while ((object = it.Next()) != NULL) { | 1502 while ((object = it.Next()) != NULL) { |
| 1503 MarkBit markbit = Marking::MarkBitFrom(object); | 1503 MarkBit markbit = Marking::MarkBitFrom(object); |
| 1504 DCHECK(Marking::IsGrey(markbit)); | 1504 DCHECK(Marking::IsGrey(markbit)); |
| 1505 Marking::GreyToBlack(markbit); | 1505 Marking::GreyToBlack(markbit); |
| 1506 PushBlack(object); | 1506 PushBlack(object); |
| 1507 if (marking_deque()->IsFull()) return; | 1507 if (marking_deque()->IsFull()) return; |
| 1508 } | 1508 } |
| 1509 } | 1509 } |
| 1510 | 1510 |
| 1511 class RecordMigratedSlotVisitor final : public ObjectVisitor { |
| 1512 public: |
| 1513 inline void VisitPointer(Object** p) final { |
| 1514 RecordMigratedSlot(*p, reinterpret_cast<Address>(p)); |
| 1515 } |
| 1516 |
| 1517 inline void VisitPointers(Object** start, Object** end) final { |
| 1518 while (start < end) { |
| 1519 RecordMigratedSlot(*start, reinterpret_cast<Address>(start)); |
| 1520 ++start; |
| 1521 } |
| 1522 } |
| 1523 |
| 1524 inline void VisitCodeEntry(Address code_entry_slot) final { |
| 1525 Address code_entry = Memory::Address_at(code_entry_slot); |
| 1526 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { |
| 1527 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot), |
| 1528 CODE_ENTRY_SLOT, code_entry_slot); |
| 1529 } |
| 1530 } |
| 1531 |
| 1532 private: |
| 1533 inline void RecordMigratedSlot(Object* value, Address slot) { |
| 1534 if (value->IsHeapObject()) { |
| 1535 Page* p = Page::FromAddress(reinterpret_cast<Address>(value)); |
| 1536 if (p->InNewSpace()) { |
| 1537 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot); |
| 1538 } else if (p->IsEvacuationCandidate()) { |
| 1539 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot); |
| 1540 } |
| 1541 } |
| 1542 } |
| 1543 }; |
| 1511 | 1544 |
| 1512 class MarkCompactCollector::HeapObjectVisitor { | 1545 class MarkCompactCollector::HeapObjectVisitor { |
| 1513 public: | 1546 public: |
| 1514 virtual ~HeapObjectVisitor() {} | 1547 virtual ~HeapObjectVisitor() {} |
| 1515 virtual bool Visit(HeapObject* object) = 0; | 1548 virtual bool Visit(HeapObject* object) = 0; |
| 1516 }; | 1549 }; |
| 1517 | 1550 |
| 1518 | |
| 1519 class MarkCompactCollector::EvacuateVisitorBase | 1551 class MarkCompactCollector::EvacuateVisitorBase |
| 1520 : public MarkCompactCollector::HeapObjectVisitor { | 1552 : public MarkCompactCollector::HeapObjectVisitor { |
| 1521 public: | 1553 public: |
| 1522 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces) | 1554 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces) |
| 1523 : heap_(heap), compaction_spaces_(compaction_spaces) {} | 1555 : heap_(heap), compaction_spaces_(compaction_spaces) {} |
| 1524 | 1556 |
| 1525 bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, | 1557 inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, |
| 1526 HeapObject** target_object) { | 1558 HeapObject** target_object) { |
| 1527 int size = object->Size(); | 1559 int size = object->Size(); |
| 1528 AllocationAlignment alignment = object->RequiredAlignment(); | 1560 AllocationAlignment alignment = object->RequiredAlignment(); |
| 1529 AllocationResult allocation = target_space->AllocateRaw(size, alignment); | 1561 AllocationResult allocation = target_space->AllocateRaw(size, alignment); |
| 1530 if (allocation.To(target_object)) { | 1562 if (allocation.To(target_object)) { |
| 1531 heap_->mark_compact_collector()->MigrateObject( | 1563 MigrateObject(*target_object, object, size, target_space->identity()); |
| 1532 *target_object, object, size, target_space->identity()); | |
| 1533 return true; | 1564 return true; |
| 1534 } | 1565 } |
| 1535 return false; | 1566 return false; |
| 1536 } | 1567 } |
| 1537 | 1568 |
| 1569 inline void MigrateObject(HeapObject* dst, HeapObject* src, int size, |
| 1570 AllocationSpace dest) { |
| 1571 Address dst_addr = dst->address(); |
| 1572 Address src_addr = src->address(); |
| 1573 DCHECK(heap_->AllowedToBeMigrated(src, dest)); |
| 1574 DCHECK(dest != LO_SPACE); |
| 1575 if (dest == OLD_SPACE) { |
| 1576 DCHECK_OBJECT_SIZE(size); |
| 1577 DCHECK(IsAligned(size, kPointerSize)); |
| 1578 heap_->MoveBlock(dst_addr, src_addr, size); |
| 1579 if (FLAG_ignition && dst->IsBytecodeArray()) { |
| 1580 PROFILE(heap_->isolate(), |
| 1581 CodeMoveEvent(AbstractCode::cast(src), dst_addr)); |
| 1582 } |
| 1583 RecordMigratedSlotVisitor visitor; |
| 1584 dst->IterateBodyFast(dst->map()->instance_type(), size, &visitor); |
| 1585 } else if (dest == CODE_SPACE) { |
| 1586 DCHECK_CODEOBJECT_SIZE(size, heap_->code_space()); |
| 1587 PROFILE(heap_->isolate(), |
| 1588 CodeMoveEvent(AbstractCode::cast(src), dst_addr)); |
| 1589 heap_->MoveBlock(dst_addr, src_addr, size); |
| 1590 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(dst_addr), |
| 1591 RELOCATED_CODE_OBJECT, dst_addr); |
| 1592 Code::cast(dst)->Relocate(dst_addr - src_addr); |
| 1593 } else { |
| 1594 DCHECK_OBJECT_SIZE(size); |
| 1595 DCHECK(dest == NEW_SPACE); |
| 1596 heap_->MoveBlock(dst_addr, src_addr, size); |
| 1597 } |
| 1598 heap_->OnMoveEvent(dst, src, size); |
| 1599 Memory::Address_at(src_addr) = dst_addr; |
| 1600 } |
| 1601 |
| 1538 protected: | 1602 protected: |
| 1539 Heap* heap_; | 1603 Heap* heap_; |
| 1540 CompactionSpaceCollection* compaction_spaces_; | 1604 CompactionSpaceCollection* compaction_spaces_; |
| 1541 }; | 1605 }; |
| 1542 | 1606 |
| 1543 | |
| 1544 class MarkCompactCollector::EvacuateNewSpaceVisitor final | 1607 class MarkCompactCollector::EvacuateNewSpaceVisitor final |
| 1545 : public MarkCompactCollector::EvacuateVisitorBase { | 1608 : public MarkCompactCollector::EvacuateVisitorBase { |
| 1546 public: | 1609 public: |
| 1547 static const intptr_t kLabSize = 4 * KB; | 1610 static const intptr_t kLabSize = 4 * KB; |
| 1548 static const intptr_t kMaxLabObjectSize = 256; | 1611 static const intptr_t kMaxLabObjectSize = 256; |
| 1549 | 1612 |
| 1550 explicit EvacuateNewSpaceVisitor(Heap* heap, | 1613 explicit EvacuateNewSpaceVisitor(Heap* heap, |
| 1551 CompactionSpaceCollection* compaction_spaces, | 1614 CompactionSpaceCollection* compaction_spaces, |
| 1552 HashMap* local_pretenuring_feedback) | 1615 HashMap* local_pretenuring_feedback) |
| 1553 : EvacuateVisitorBase(heap, compaction_spaces), | 1616 : EvacuateVisitorBase(heap, compaction_spaces), |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1568 // If we end up needing more special cases, we should factor this out. | 1631 // If we end up needing more special cases, we should factor this out. |
| 1569 if (V8_UNLIKELY(target_object->IsJSArrayBuffer())) { | 1632 if (V8_UNLIKELY(target_object->IsJSArrayBuffer())) { |
| 1570 heap_->array_buffer_tracker()->Promote( | 1633 heap_->array_buffer_tracker()->Promote( |
| 1571 JSArrayBuffer::cast(target_object)); | 1634 JSArrayBuffer::cast(target_object)); |
| 1572 } | 1635 } |
| 1573 promoted_size_ += size; | 1636 promoted_size_ += size; |
| 1574 return true; | 1637 return true; |
| 1575 } | 1638 } |
| 1576 HeapObject* target = nullptr; | 1639 HeapObject* target = nullptr; |
| 1577 AllocationSpace space = AllocateTargetObject(object, &target); | 1640 AllocationSpace space = AllocateTargetObject(object, &target); |
| 1578 heap_->mark_compact_collector()->MigrateObject(HeapObject::cast(target), | 1641 MigrateObject(HeapObject::cast(target), object, size, space); |
| 1579 object, size, space); | |
| 1580 if (V8_UNLIKELY(target->IsJSArrayBuffer())) { | 1642 if (V8_UNLIKELY(target->IsJSArrayBuffer())) { |
| 1581 heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target)); | 1643 heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target)); |
| 1582 } | 1644 } |
| 1583 semispace_copied_size_ += size; | 1645 semispace_copied_size_ += size; |
| 1584 return true; | 1646 return true; |
| 1585 } | 1647 } |
| 1586 | 1648 |
| 1587 intptr_t promoted_size() { return promoted_size_; } | 1649 intptr_t promoted_size() { return promoted_size_; } |
| 1588 intptr_t semispace_copied_size() { return semispace_copied_size_; } | 1650 intptr_t semispace_copied_size() { return semispace_copied_size_; } |
| 1589 | 1651 |
| (...skipping 959 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2549 slot_type = CODE_ENTRY_SLOT; | 2611 slot_type = CODE_ENTRY_SLOT; |
| 2550 } else { | 2612 } else { |
| 2551 DCHECK(RelocInfo::IsEmbeddedObject(rmode)); | 2613 DCHECK(RelocInfo::IsEmbeddedObject(rmode)); |
| 2552 slot_type = OBJECT_SLOT; | 2614 slot_type = OBJECT_SLOT; |
| 2553 } | 2615 } |
| 2554 } | 2616 } |
| 2555 RememberedSet<OLD_TO_OLD>::InsertTyped(source_page, slot_type, addr); | 2617 RememberedSet<OLD_TO_OLD>::InsertTyped(source_page, slot_type, addr); |
| 2556 } | 2618 } |
| 2557 } | 2619 } |
| 2558 | 2620 |
| 2559 | |
| 2560 class RecordMigratedSlotVisitor final : public ObjectVisitor { | |
| 2561 public: | |
| 2562 explicit RecordMigratedSlotVisitor(MarkCompactCollector* collector) | |
| 2563 : collector_(collector) {} | |
| 2564 | |
| 2565 V8_INLINE void VisitPointer(Object** p) override { | |
| 2566 RecordMigratedSlot(*p, reinterpret_cast<Address>(p)); | |
| 2567 } | |
| 2568 | |
| 2569 V8_INLINE void VisitPointers(Object** start, Object** end) override { | |
| 2570 while (start < end) { | |
| 2571 RecordMigratedSlot(*start, reinterpret_cast<Address>(start)); | |
| 2572 ++start; | |
| 2573 } | |
| 2574 } | |
| 2575 | |
| 2576 V8_INLINE void VisitCodeEntry(Address code_entry_slot) override { | |
| 2577 if (collector_->compacting_) { | |
| 2578 Address code_entry = Memory::Address_at(code_entry_slot); | |
| 2579 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { | |
| 2580 RememberedSet<OLD_TO_OLD>::InsertTyped( | |
| 2581 Page::FromAddress(code_entry_slot), CODE_ENTRY_SLOT, | |
| 2582 code_entry_slot); | |
| 2583 } | |
| 2584 } | |
| 2585 } | |
| 2586 | |
| 2587 private: | |
| 2588 inline void RecordMigratedSlot(Object* value, Address slot) { | |
| 2589 if (collector_->heap()->InNewSpace(value)) { | |
| 2590 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot); | |
| 2591 } else if (value->IsHeapObject() && | |
| 2592 Page::FromAddress(reinterpret_cast<Address>(value)) | |
| 2593 ->IsEvacuationCandidate()) { | |
| 2594 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot); | |
| 2595 } | |
| 2596 } | |
| 2597 | |
| 2598 MarkCompactCollector* collector_; | |
| 2599 }; | |
| 2600 | |
| 2601 | |
| 2602 // We scavenge new space simultaneously with sweeping. This is done in two | |
| 2603 // passes. | |
| 2604 // | |
| 2605 // The first pass migrates all alive objects from one semispace to another or | |
| 2606 // promotes them to old space. Forwarding address is written directly into | |
| 2607 // first word of object without any encoding. If object is dead we write | |
| 2608 // NULL as a forwarding address. | |
| 2609 // | |
| 2610 // The second pass updates pointers to new space in all spaces. It is possible | |
| 2611 // to encounter pointers to dead new space objects during traversal of pointers | |
| 2612 // to new space. We should clear them to avoid encountering them during next | |
| 2613 // pointer iteration. This is an issue if the store buffer overflows and we | |
| 2614 // have to scan the entire old space, including dead objects, looking for | |
| 2615 // pointers to new space. | |
| 2616 void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src, | |
| 2617 int size, AllocationSpace dest) { | |
| 2618 Address dst_addr = dst->address(); | |
| 2619 Address src_addr = src->address(); | |
| 2620 DCHECK(heap()->AllowedToBeMigrated(src, dest)); | |
| 2621 DCHECK(dest != LO_SPACE); | |
| 2622 if (dest == OLD_SPACE) { | |
| 2623 DCHECK_OBJECT_SIZE(size); | |
| 2624 DCHECK(IsAligned(size, kPointerSize)); | |
| 2625 | |
| 2626 heap()->MoveBlock(dst->address(), src->address(), size); | |
| 2627 if (FLAG_ignition && dst->IsBytecodeArray()) { | |
| 2628 PROFILE(isolate(), CodeMoveEvent(AbstractCode::cast(src), dst_addr)); | |
| 2629 } | |
| 2630 RecordMigratedSlotVisitor visitor(this); | |
| 2631 dst->IterateBody(&visitor); | |
| 2632 } else if (dest == CODE_SPACE) { | |
| 2633 DCHECK_CODEOBJECT_SIZE(size, heap()->code_space()); | |
| 2634 PROFILE(isolate(), CodeMoveEvent(AbstractCode::cast(src), dst_addr)); | |
| 2635 heap()->MoveBlock(dst_addr, src_addr, size); | |
| 2636 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(dst_addr), | |
| 2637 RELOCATED_CODE_OBJECT, dst_addr); | |
| 2638 Code::cast(dst)->Relocate(dst_addr - src_addr); | |
| 2639 } else { | |
| 2640 DCHECK_OBJECT_SIZE(size); | |
| 2641 DCHECK(dest == NEW_SPACE); | |
| 2642 heap()->MoveBlock(dst_addr, src_addr, size); | |
| 2643 } | |
| 2644 heap()->OnMoveEvent(dst, src, size); | |
| 2645 Memory::Address_at(src_addr) = dst_addr; | |
| 2646 } | |
| 2647 | |
| 2648 static inline void UpdateTypedSlot(Isolate* isolate, ObjectVisitor* v, | 2621 static inline void UpdateTypedSlot(Isolate* isolate, ObjectVisitor* v, |
| 2649 SlotType slot_type, Address addr) { | 2622 SlotType slot_type, Address addr) { |
| 2650 switch (slot_type) { | 2623 switch (slot_type) { |
| 2651 case CODE_TARGET_SLOT: { | 2624 case CODE_TARGET_SLOT: { |
| 2652 RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); | 2625 RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); |
| 2653 rinfo.Visit(isolate, v); | 2626 rinfo.Visit(isolate, v); |
| 2654 break; | 2627 break; |
| 2655 } | 2628 } |
| 2656 case CELL_TARGET_SLOT: { | 2629 case CELL_TARGET_SLOT: { |
| 2657 RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); | 2630 RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); |
| (...skipping 1160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3818 MarkBit mark_bit = Marking::MarkBitFrom(host); | 3791 MarkBit mark_bit = Marking::MarkBitFrom(host); |
| 3819 if (Marking::IsBlack(mark_bit)) { | 3792 if (Marking::IsBlack(mark_bit)) { |
| 3820 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); | 3793 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); |
| 3821 RecordRelocSlot(host, &rinfo, target); | 3794 RecordRelocSlot(host, &rinfo, target); |
| 3822 } | 3795 } |
| 3823 } | 3796 } |
| 3824 } | 3797 } |
| 3825 | 3798 |
| 3826 } // namespace internal | 3799 } // namespace internal |
| 3827 } // namespace v8 | 3800 } // namespace v8 |
| OLD | NEW |