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 2917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2928 const uintptr_t kBoundary = V8_UINT64_C(1) << 48; | 2928 const uintptr_t kBoundary = V8_UINT64_C(1) << 48; |
2929 STATIC_ASSERT(kBoundary > 0); | 2929 STATIC_ASSERT(kBoundary > 0); |
2930 if (reinterpret_cast<uintptr_t>(heap_obj->address()) >= kBoundary) { | 2930 if (reinterpret_cast<uintptr_t>(heap_obj->address()) >= kBoundary) { |
2931 CheckLayoutDescriptorAndDie(heap, slot); | 2931 CheckLayoutDescriptorAndDie(heap, slot); |
2932 } | 2932 } |
2933 #endif | 2933 #endif |
2934 #endif | 2934 #endif |
2935 MapWord map_word = heap_obj->map_word(); | 2935 MapWord map_word = heap_obj->map_word(); |
2936 if (map_word.IsForwardingAddress()) { | 2936 if (map_word.IsForwardingAddress()) { |
2937 DCHECK(heap->InFromSpace(heap_obj) || | 2937 DCHECK(heap->InFromSpace(heap_obj) || |
2938 MarkCompactCollector::IsOnEvacuationCandidate(heap_obj)); | 2938 MarkCompactCollector::IsOnEvacuationCandidate(heap_obj) || |
| 2939 Page::FromAddress(heap_obj->address()) |
| 2940 ->IsFlagSet(Page::COMPACTION_WAS_ABORTED)); |
2939 HeapObject* target = map_word.ToForwardingAddress(); | 2941 HeapObject* target = map_word.ToForwardingAddress(); |
2940 base::NoBarrier_CompareAndSwap( | 2942 base::NoBarrier_CompareAndSwap( |
2941 reinterpret_cast<base::AtomicWord*>(slot), | 2943 reinterpret_cast<base::AtomicWord*>(slot), |
2942 reinterpret_cast<base::AtomicWord>(obj), | 2944 reinterpret_cast<base::AtomicWord>(obj), |
2943 reinterpret_cast<base::AtomicWord>(target)); | 2945 reinterpret_cast<base::AtomicWord>(target)); |
2944 DCHECK(!heap->InFromSpace(target) && | 2946 DCHECK(!heap->InFromSpace(target) && |
2945 !MarkCompactCollector::IsOnEvacuationCandidate(target)); | 2947 !MarkCompactCollector::IsOnEvacuationCandidate(target)); |
2946 } | 2948 } |
2947 } | 2949 } |
2948 | 2950 |
(...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3456 // We need to: | 3458 // We need to: |
3457 // - Leave the evacuation candidate flag for later processing of | 3459 // - Leave the evacuation candidate flag for later processing of |
3458 // slots buffer entries. | 3460 // slots buffer entries. |
3459 // - Leave the slots buffer there for processing of entries added by | 3461 // - Leave the slots buffer there for processing of entries added by |
3460 // the write barrier. | 3462 // the write barrier. |
3461 // - Rescan the page as slot recording in the migration buffer only | 3463 // - Rescan the page as slot recording in the migration buffer only |
3462 // happens upon moving (which we potentially didn't do). | 3464 // happens upon moving (which we potentially didn't do). |
3463 // - Leave the page in the list of pages of a space since we could not | 3465 // - Leave the page in the list of pages of a space since we could not |
3464 // fully evacuate it. | 3466 // fully evacuate it. |
3465 DCHECK(p->IsEvacuationCandidate()); | 3467 DCHECK(p->IsEvacuationCandidate()); |
3466 p->SetFlag(Page::RESCAN_ON_EVACUATION); | 3468 p->SetFlag(Page::COMPACTION_WAS_ABORTED); |
3467 abandoned_pages++; | 3469 abandoned_pages++; |
3468 break; | 3470 break; |
3469 case MemoryChunk::kCompactingFinalize: | 3471 case MemoryChunk::kCompactingFinalize: |
3470 DCHECK(p->IsEvacuationCandidate()); | 3472 DCHECK(p->IsEvacuationCandidate()); |
3471 p->SetWasSwept(); | 3473 p->SetWasSwept(); |
3472 p->Unlink(); | 3474 p->Unlink(); |
3473 break; | 3475 break; |
3474 case MemoryChunk::kCompactingDone: | 3476 case MemoryChunk::kCompactingDone: |
3475 DCHECK(p->IsFlagSet(Page::POPULAR_PAGE)); | 3477 DCHECK(p->IsFlagSet(Page::POPULAR_PAGE)); |
3476 DCHECK(p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | 3478 DCHECK(p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3694 DCHECK(p->IsEvacuationCandidate() || | 3696 DCHECK(p->IsEvacuationCandidate() || |
3695 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | 3697 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); |
3696 if (p->IsEvacuationCandidate()) { | 3698 if (p->IsEvacuationCandidate()) { |
3697 SlotsBuffer::RemoveObjectSlots(heap_, p->slots_buffer(), start_slot, | 3699 SlotsBuffer::RemoveObjectSlots(heap_, p->slots_buffer(), start_slot, |
3698 end_slot); | 3700 end_slot); |
3699 } | 3701 } |
3700 } | 3702 } |
3701 } | 3703 } |
3702 | 3704 |
3703 | 3705 |
| 3706 void MarkCompactCollector::VisitLiveObjects(Page* page, |
| 3707 ObjectVisitor* visitor) { |
| 3708 // First pass on aborted pages. |
| 3709 int offsets[16]; |
| 3710 for (MarkBitCellIterator it(page); !it.Done(); it.Advance()) { |
| 3711 Address cell_base = it.CurrentCellBase(); |
| 3712 MarkBit::CellType* cell = it.CurrentCell(); |
| 3713 if (*cell == 0) continue; |
| 3714 int live_objects = MarkWordToObjectStarts(*cell, offsets); |
| 3715 for (int i = 0; i < live_objects; i++) { |
| 3716 Address object_addr = cell_base + offsets[i] * kPointerSize; |
| 3717 HeapObject* live_object = HeapObject::FromAddress(object_addr); |
| 3718 DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object))); |
| 3719 Map* map = live_object->synchronized_map(); |
| 3720 int size = live_object->SizeFromMap(map); |
| 3721 live_object->IterateBody(map->instance_type(), size, visitor); |
| 3722 } |
| 3723 } |
| 3724 } |
| 3725 |
| 3726 |
| 3727 void MarkCompactCollector::SweepAbortedPages() { |
| 3728 // Second pass on aborted pages. |
| 3729 for (int i = 0; i < evacuation_candidates_.length(); i++) { |
| 3730 Page* p = evacuation_candidates_[i]; |
| 3731 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { |
| 3732 p->ClearFlag(MemoryChunk::COMPACTION_WAS_ABORTED); |
| 3733 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
| 3734 switch (space->identity()) { |
| 3735 case OLD_SPACE: |
| 3736 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, IGNORE_SKIP_LIST, |
| 3737 IGNORE_FREE_SPACE>(space, nullptr, p, nullptr); |
| 3738 break; |
| 3739 case CODE_SPACE: |
| 3740 if (FLAG_zap_code_space) { |
| 3741 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, REBUILD_SKIP_LIST, |
| 3742 ZAP_FREE_SPACE>(space, NULL, p, nullptr); |
| 3743 } else { |
| 3744 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, REBUILD_SKIP_LIST, |
| 3745 IGNORE_FREE_SPACE>(space, NULL, p, nullptr); |
| 3746 } |
| 3747 break; |
| 3748 default: |
| 3749 UNREACHABLE(); |
| 3750 break; |
| 3751 } |
| 3752 } |
| 3753 } |
| 3754 } |
| 3755 |
| 3756 |
3704 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { | 3757 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { |
3705 Heap::RelocationLock relocation_lock(heap()); | 3758 Heap::RelocationLock relocation_lock(heap()); |
3706 | 3759 |
3707 { | 3760 { |
3708 GCTracer::Scope gc_scope(heap()->tracer(), | 3761 GCTracer::Scope gc_scope(heap()->tracer(), |
3709 GCTracer::Scope::MC_SWEEP_NEWSPACE); | 3762 GCTracer::Scope::MC_SWEEP_NEWSPACE); |
3710 EvacuationScope evacuation_scope(this); | 3763 EvacuationScope evacuation_scope(this); |
3711 EvacuateNewSpace(); | 3764 EvacuateNewSpace(); |
3712 } | 3765 } |
3713 | 3766 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3787 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), | 3840 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), |
3788 SlotsBuffer::SizeOfChain(p->slots_buffer())); | 3841 SlotsBuffer::SizeOfChain(p->slots_buffer())); |
3789 } | 3842 } |
3790 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); | 3843 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); |
3791 | 3844 |
3792 // Important: skip list should be cleared only after roots were updated | 3845 // Important: skip list should be cleared only after roots were updated |
3793 // because root iteration traverses the stack and might have to find | 3846 // because root iteration traverses the stack and might have to find |
3794 // code objects from non-updated pc pointing into evacuation candidate. | 3847 // code objects from non-updated pc pointing into evacuation candidate. |
3795 SkipList* list = p->skip_list(); | 3848 SkipList* list = p->skip_list(); |
3796 if (list != NULL) list->Clear(); | 3849 if (list != NULL) list->Clear(); |
3797 } | |
3798 | 3850 |
3799 if (p->IsEvacuationCandidate() && | 3851 // First pass on aborted pages, fixing up all live objects. |
3800 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { | 3852 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { |
3801 // Case where we've aborted compacting a page. Clear the flag here to | 3853 // Clearing the evacuation candidate flag here has the effect of |
3802 // avoid release the page later on. | 3854 // stopping recording of slots for it in the following pointer |
3803 p->ClearEvacuationCandidate(); | 3855 // update phases. |
| 3856 p->ClearEvacuationCandidate(); |
| 3857 VisitLiveObjects(p, &updating_visitor); |
| 3858 } |
3804 } | 3859 } |
3805 | 3860 |
3806 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { | 3861 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { |
3807 if (FLAG_gc_verbose) { | 3862 if (FLAG_gc_verbose) { |
3808 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", | 3863 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", |
3809 reinterpret_cast<intptr_t>(p)); | 3864 reinterpret_cast<intptr_t>(p)); |
3810 } | 3865 } |
3811 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | 3866 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
3812 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); | 3867 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); |
3813 | 3868 |
(...skipping 15 matching lines...) Expand all Loading... |
3829 } | 3884 } |
3830 break; | 3885 break; |
3831 default: | 3886 default: |
3832 UNREACHABLE(); | 3887 UNREACHABLE(); |
3833 break; | 3888 break; |
3834 } | 3889 } |
3835 } | 3890 } |
3836 } | 3891 } |
3837 } | 3892 } |
3838 | 3893 |
3839 GCTracer::Scope gc_scope(heap()->tracer(), | 3894 { |
3840 GCTracer::Scope::MC_UPDATE_MISC_POINTERS); | 3895 GCTracer::Scope gc_scope(heap()->tracer(), |
| 3896 GCTracer::Scope::MC_UPDATE_MISC_POINTERS); |
| 3897 heap_->string_table()->Iterate(&updating_visitor); |
3841 | 3898 |
3842 heap_->string_table()->Iterate(&updating_visitor); | 3899 // Update pointers from external string table. |
| 3900 heap_->UpdateReferencesInExternalStringTable( |
| 3901 &UpdateReferenceInExternalStringTableEntry); |
3843 | 3902 |
3844 // Update pointers from external string table. | 3903 EvacuationWeakObjectRetainer evacuation_object_retainer; |
3845 heap_->UpdateReferencesInExternalStringTable( | 3904 heap()->ProcessAllWeakReferences(&evacuation_object_retainer); |
3846 &UpdateReferenceInExternalStringTableEntry); | 3905 } |
3847 | 3906 |
3848 EvacuationWeakObjectRetainer evacuation_object_retainer; | 3907 { |
3849 heap()->ProcessAllWeakReferences(&evacuation_object_retainer); | 3908 GCTracer::Scope gc_scope(heap()->tracer(), |
| 3909 GCTracer::Scope::MC_SWEEP_ABORTED); |
| 3910 // After updating all pointers, we can finally sweep the aborted pages, |
| 3911 // effectively overriding any forward pointers. |
| 3912 SweepAbortedPages(); |
| 3913 } |
3850 | 3914 |
3851 heap_->isolate()->inner_pointer_to_code_cache()->Flush(); | 3915 heap_->isolate()->inner_pointer_to_code_cache()->Flush(); |
3852 | 3916 |
3853 // The hashing of weak_object_to_code_table is no longer valid. | 3917 // The hashing of weak_object_to_code_table is no longer valid. |
3854 heap()->weak_object_to_code_table()->Rehash( | 3918 heap()->weak_object_to_code_table()->Rehash( |
3855 heap()->isolate()->factory()->undefined_value()); | 3919 heap()->isolate()->factory()->undefined_value()); |
3856 } | 3920 } |
3857 | 3921 |
3858 | 3922 |
3859 void MarkCompactCollector::MoveEvacuationCandidatesToEndOfPagesList() { | 3923 void MarkCompactCollector::MoveEvacuationCandidatesToEndOfPagesList() { |
(...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4612 MarkBit mark_bit = Marking::MarkBitFrom(host); | 4676 MarkBit mark_bit = Marking::MarkBitFrom(host); |
4613 if (Marking::IsBlack(mark_bit)) { | 4677 if (Marking::IsBlack(mark_bit)) { |
4614 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); | 4678 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); |
4615 RecordRelocSlot(&rinfo, target); | 4679 RecordRelocSlot(&rinfo, target); |
4616 } | 4680 } |
4617 } | 4681 } |
4618 } | 4682 } |
4619 | 4683 |
4620 } // namespace internal | 4684 } // namespace internal |
4621 } // namespace v8 | 4685 } // namespace v8 |
OLD | NEW |