Chromium Code Reviews| 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 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3765 | 3767 |
| 3766 { | 3768 { |
| 3767 GCTracer::Scope gc_scope(heap()->tracer(), | 3769 GCTracer::Scope gc_scope(heap()->tracer(), |
| 3768 GCTracer::Scope::MC_UPDATE_OLD_TO_NEW_POINTERS); | 3770 GCTracer::Scope::MC_UPDATE_OLD_TO_NEW_POINTERS); |
| 3769 StoreBufferRebuildScope scope(heap_, heap_->store_buffer(), | 3771 StoreBufferRebuildScope scope(heap_, heap_->store_buffer(), |
| 3770 &Heap::ScavengeStoreBufferCallback); | 3772 &Heap::ScavengeStoreBufferCallback); |
| 3771 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); | 3773 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); |
| 3772 } | 3774 } |
| 3773 | 3775 |
| 3774 int npages = evacuation_candidates_.length(); | 3776 int npages = evacuation_candidates_.length(); |
| 3775 { | 3777 { |
|
Hannes Payer (out of office)
2015/10/23 13:09:18
This function is getting super long (and complicat
Michael Lippautz
2015/10/23 13:27:05
Factored out a few pieces.
| |
| 3776 GCTracer::Scope gc_scope( | 3778 GCTracer::Scope gc_scope( |
| 3777 heap()->tracer(), | 3779 heap()->tracer(), |
| 3778 GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED); | 3780 GCTracer::Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED); |
| 3779 for (int i = 0; i < npages; i++) { | 3781 for (int i = 0; i < npages; i++) { |
| 3780 Page* p = evacuation_candidates_[i]; | 3782 Page* p = evacuation_candidates_[i]; |
| 3781 DCHECK(p->IsEvacuationCandidate() || | 3783 DCHECK(p->IsEvacuationCandidate() || |
| 3782 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | 3784 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); |
| 3783 | 3785 |
| 3784 if (p->IsEvacuationCandidate()) { | 3786 if (p->IsEvacuationCandidate()) { |
| 3785 UpdateSlotsRecordedIn(p->slots_buffer()); | 3787 UpdateSlotsRecordedIn(p->slots_buffer()); |
| 3786 if (FLAG_trace_fragmentation_verbose) { | 3788 if (FLAG_trace_fragmentation_verbose) { |
| 3787 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), | 3789 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), |
| 3788 SlotsBuffer::SizeOfChain(p->slots_buffer())); | 3790 SlotsBuffer::SizeOfChain(p->slots_buffer())); |
| 3789 } | 3791 } |
| 3790 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); | 3792 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); |
| 3791 | 3793 |
| 3792 // Important: skip list should be cleared only after roots were updated | 3794 // Important: skip list should be cleared only after roots were updated |
| 3793 // because root iteration traverses the stack and might have to find | 3795 // because root iteration traverses the stack and might have to find |
| 3794 // code objects from non-updated pc pointing into evacuation candidate. | 3796 // code objects from non-updated pc pointing into evacuation candidate. |
| 3795 SkipList* list = p->skip_list(); | 3797 SkipList* list = p->skip_list(); |
| 3796 if (list != NULL) list->Clear(); | 3798 if (list != NULL) list->Clear(); |
| 3797 } | |
| 3798 | 3799 |
| 3799 if (p->IsEvacuationCandidate() && | 3800 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { |
| 3800 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { | 3801 p->ClearEvacuationCandidate(); |
| 3801 // Case where we've aborted compacting a page. Clear the flag here to | 3802 // First pass on aborted pages. |
| 3802 // avoid release the page later on. | 3803 int offsets[16]; |
| 3803 p->ClearEvacuationCandidate(); | 3804 for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { |
| 3805 Address cell_base = it.CurrentCellBase(); | |
| 3806 MarkBit::CellType* cell = it.CurrentCell(); | |
| 3807 if (*cell == 0) continue; | |
| 3808 int live_objects = MarkWordToObjectStarts(*cell, offsets); | |
| 3809 for (int i = 0; i < live_objects; i++) { | |
| 3810 Address object_addr = cell_base + offsets[i] * kPointerSize; | |
| 3811 HeapObject* live_object = HeapObject::FromAddress(object_addr); | |
| 3812 DCHECK(Marking::IsBlack(Marking::MarkBitFrom(live_object))); | |
| 3813 Map* map = live_object->synchronized_map(); | |
| 3814 int size = live_object->SizeFromMap(map); | |
| 3815 live_object->IterateBody(map->instance_type(), size, | |
| 3816 &updating_visitor); | |
| 3817 } | |
| 3818 } | |
| 3819 } | |
| 3804 } | 3820 } |
| 3805 | 3821 |
| 3806 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { | 3822 if (p->IsFlagSet(Page::RESCAN_ON_EVACUATION)) { |
| 3807 if (FLAG_gc_verbose) { | 3823 if (FLAG_gc_verbose) { |
| 3808 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", | 3824 PrintF("Sweeping 0x%" V8PRIxPTR " during evacuation.\n", |
| 3809 reinterpret_cast<intptr_t>(p)); | 3825 reinterpret_cast<intptr_t>(p)); |
| 3810 } | 3826 } |
| 3811 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | 3827 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
| 3812 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); | 3828 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); |
| 3813 | 3829 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 3829 } | 3845 } |
| 3830 break; | 3846 break; |
| 3831 default: | 3847 default: |
| 3832 UNREACHABLE(); | 3848 UNREACHABLE(); |
| 3833 break; | 3849 break; |
| 3834 } | 3850 } |
| 3835 } | 3851 } |
| 3836 } | 3852 } |
| 3837 } | 3853 } |
| 3838 | 3854 |
| 3839 GCTracer::Scope gc_scope(heap()->tracer(), | 3855 GCTracer::Scope gc_scope(heap()->tracer(), |
|
Hannes Payer (out of office)
2015/10/23 13:09:18
This timer scope now also covers the sweeping.
Michael Lippautz
2015/10/23 13:27:05
Fixed to only track updating the pointers.
| |
| 3840 GCTracer::Scope::MC_UPDATE_MISC_POINTERS); | 3856 GCTracer::Scope::MC_UPDATE_MISC_POINTERS); |
| 3841 | 3857 |
| 3842 heap_->string_table()->Iterate(&updating_visitor); | 3858 heap_->string_table()->Iterate(&updating_visitor); |
| 3843 | 3859 |
| 3844 // Update pointers from external string table. | 3860 // Update pointers from external string table. |
| 3845 heap_->UpdateReferencesInExternalStringTable( | 3861 heap_->UpdateReferencesInExternalStringTable( |
| 3846 &UpdateReferenceInExternalStringTableEntry); | 3862 &UpdateReferenceInExternalStringTableEntry); |
| 3847 | 3863 |
| 3848 EvacuationWeakObjectRetainer evacuation_object_retainer; | 3864 EvacuationWeakObjectRetainer evacuation_object_retainer; |
| 3849 heap()->ProcessAllWeakReferences(&evacuation_object_retainer); | 3865 heap()->ProcessAllWeakReferences(&evacuation_object_retainer); |
| 3850 | 3866 |
| 3867 // Second pass on aborted pages. | |
|
Hannes Payer (out of office)
2015/10/23 13:09:18
Please add a separate timer scope here.
Michael Lippautz
2015/10/23 13:27:05
Done.
| |
| 3868 for (int i = 0; i < npages; i++) { | |
| 3869 Page* p = evacuation_candidates_[i]; | |
| 3870 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { | |
| 3871 p->ClearFlag(MemoryChunk::COMPACTION_WAS_ABORTED); | |
| 3872 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | |
| 3873 switch (space->identity()) { | |
| 3874 case OLD_SPACE: | |
| 3875 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, IGNORE_SKIP_LIST, | |
| 3876 IGNORE_FREE_SPACE>(space, nullptr, p, nullptr); | |
| 3877 break; | |
| 3878 case CODE_SPACE: | |
| 3879 if (FLAG_zap_code_space) { | |
| 3880 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, REBUILD_SKIP_LIST, | |
| 3881 ZAP_FREE_SPACE>(space, NULL, p, nullptr); | |
| 3882 } else { | |
| 3883 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, REBUILD_SKIP_LIST, | |
| 3884 IGNORE_FREE_SPACE>(space, NULL, p, nullptr); | |
| 3885 } | |
| 3886 break; | |
| 3887 default: | |
| 3888 UNREACHABLE(); | |
| 3889 break; | |
| 3890 } | |
| 3891 } | |
| 3892 } | |
| 3893 | |
| 3851 heap_->isolate()->inner_pointer_to_code_cache()->Flush(); | 3894 heap_->isolate()->inner_pointer_to_code_cache()->Flush(); |
| 3852 | 3895 |
| 3853 // The hashing of weak_object_to_code_table is no longer valid. | 3896 // The hashing of weak_object_to_code_table is no longer valid. |
| 3854 heap()->weak_object_to_code_table()->Rehash( | 3897 heap()->weak_object_to_code_table()->Rehash( |
| 3855 heap()->isolate()->factory()->undefined_value()); | 3898 heap()->isolate()->factory()->undefined_value()); |
| 3856 } | 3899 } |
| 3857 | 3900 |
| 3858 | 3901 |
| 3859 void MarkCompactCollector::MoveEvacuationCandidatesToEndOfPagesList() { | 3902 void MarkCompactCollector::MoveEvacuationCandidatesToEndOfPagesList() { |
| 3860 int npages = evacuation_candidates_.length(); | 3903 int npages = evacuation_candidates_.length(); |
| (...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4612 MarkBit mark_bit = Marking::MarkBitFrom(host); | 4655 MarkBit mark_bit = Marking::MarkBitFrom(host); |
| 4613 if (Marking::IsBlack(mark_bit)) { | 4656 if (Marking::IsBlack(mark_bit)) { |
| 4614 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); | 4657 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); |
| 4615 RecordRelocSlot(&rinfo, target); | 4658 RecordRelocSlot(&rinfo, target); |
| 4616 } | 4659 } |
| 4617 } | 4660 } |
| 4618 } | 4661 } |
| 4619 | 4662 |
| 4620 } // namespace internal | 4663 } // namespace internal |
| 4621 } // namespace v8 | 4664 } // namespace v8 |
| OLD | NEW |