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 1800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1811 Page::FromAddress(object->address())->owner()->identity()); | 1811 Page::FromAddress(object->address())->owner()->identity()); |
| 1812 HeapObject* target_object = nullptr; | 1812 HeapObject* target_object = nullptr; |
| 1813 if (TryEvacuateObject(target_space, object, &target_object)) { | 1813 if (TryEvacuateObject(target_space, object, &target_object)) { |
| 1814 DCHECK(object->map_word().IsForwardingAddress()); | 1814 DCHECK(object->map_word().IsForwardingAddress()); |
| 1815 return true; | 1815 return true; |
| 1816 } | 1816 } |
| 1817 return false; | 1817 return false; |
| 1818 } | 1818 } |
| 1819 }; | 1819 }; |
| 1820 | 1820 |
| 1821 class MarkCompactCollector::EvacuateRecordOnlyVisitor final | |
| 1822 : public MarkCompactCollector::HeapObjectVisitor { | |
| 1823 public: | |
| 1824 explicit EvacuateRecordOnlyVisitor(AllocationSpace space) : space_(space) {} | |
| 1825 | |
| 1826 inline bool Visit(HeapObject* object) { | |
| 1827 if (space_ == OLD_SPACE) { | |
| 1828 RecordMigratedSlotVisitor visitor; | |
| 1829 object->IterateBody(&visitor); | |
| 1830 } else { | |
| 1831 DCHECK_EQ(space_, CODE_SPACE); | |
| 1832 // Add a typed slot for the whole code object. | |
| 1833 RememberedSet<OLD_TO_OLD>::InsertTyped( | |
|
Michael Lippautz
2016/04/14 07:50:11
We also need to record within CODE_SPACE. I am usi
| |
| 1834 Page::FromAddress(object->address()), RELOCATED_CODE_OBJECT, | |
| 1835 object->address()); | |
| 1836 } | |
| 1837 return true; | |
| 1838 } | |
| 1839 | |
| 1840 private: | |
| 1841 AllocationSpace space_; | |
| 1842 }; | |
| 1821 | 1843 |
| 1822 void MarkCompactCollector::DiscoverGreyObjectsInSpace(PagedSpace* space) { | 1844 void MarkCompactCollector::DiscoverGreyObjectsInSpace(PagedSpace* space) { |
| 1823 PageIterator it(space); | 1845 PageIterator it(space); |
| 1824 while (it.has_next()) { | 1846 while (it.has_next()) { |
| 1825 Page* p = it.next(); | 1847 Page* p = it.next(); |
| 1826 if (!p->IsFlagSet(Page::BLACK_PAGE)) { | 1848 if (!p->IsFlagSet(Page::BLACK_PAGE)) { |
| 1827 DiscoverGreyObjectsOnPage(p); | 1849 DiscoverGreyObjectsOnPage(p); |
| 1828 } | 1850 } |
| 1829 if (marking_deque()->IsFull()) return; | 1851 if (marking_deque()->IsFull()) return; |
| 1830 } | 1852 } |
| (...skipping 1254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3085 if (chunk->InNewSpace()) { | 3107 if (chunk->InNewSpace()) { |
| 3086 DCHECK_EQ(chunk->concurrent_sweeping_state().Value(), | 3108 DCHECK_EQ(chunk->concurrent_sweeping_state().Value(), |
| 3087 NewSpacePage::kSweepingDone); | 3109 NewSpacePage::kSweepingDone); |
| 3088 success = EvacuateSinglePage<kClearMarkbits>(chunk, &new_space_visitor_); | 3110 success = EvacuateSinglePage<kClearMarkbits>(chunk, &new_space_visitor_); |
| 3089 DCHECK(success); | 3111 DCHECK(success); |
| 3090 USE(success); | 3112 USE(success); |
| 3091 } else { | 3113 } else { |
| 3092 DCHECK(chunk->IsEvacuationCandidate()); | 3114 DCHECK(chunk->IsEvacuationCandidate()); |
| 3093 DCHECK_EQ(chunk->concurrent_sweeping_state().Value(), Page::kSweepingDone); | 3115 DCHECK_EQ(chunk->concurrent_sweeping_state().Value(), Page::kSweepingDone); |
| 3094 success = EvacuateSinglePage<kClearMarkbits>(chunk, &old_space_visitor_); | 3116 success = EvacuateSinglePage<kClearMarkbits>(chunk, &old_space_visitor_); |
| 3117 if (!success) { | |
| 3118 // Aborted compaction page. We can record slots here to have them | |
| 3119 // processed in parallel later on. | |
| 3120 EvacuateRecordOnlyVisitor record_visitor(chunk->owner()->identity()); | |
| 3121 success = EvacuateSinglePage<kKeepMarking>(chunk, &record_visitor); | |
| 3122 DCHECK(success); | |
| 3123 USE(success); | |
| 3124 // We need to return failure here to indicate that we want this page added | |
| 3125 // to the sweeper. | |
| 3126 return false; | |
| 3127 } | |
| 3095 } | 3128 } |
| 3096 return success; | 3129 return success; |
| 3097 } | 3130 } |
| 3098 | 3131 |
| 3099 void MarkCompactCollector::Evacuator::Finalize() { | 3132 void MarkCompactCollector::Evacuator::Finalize() { |
| 3100 heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE)); | 3133 heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE)); |
| 3101 heap()->code_space()->MergeCompactionSpace( | 3134 heap()->code_space()->MergeCompactionSpace( |
| 3102 compaction_spaces_.Get(CODE_SPACE)); | 3135 compaction_spaces_.Get(CODE_SPACE)); |
| 3103 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); | 3136 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); |
| 3104 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size()); | 3137 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3145 typedef int* PerPageData; // Pointer to number of aborted pages. | 3178 typedef int* PerPageData; // Pointer to number of aborted pages. |
| 3146 typedef MarkCompactCollector::Evacuator* PerTaskData; | 3179 typedef MarkCompactCollector::Evacuator* PerTaskData; |
| 3147 | 3180 |
| 3148 static const bool NeedSequentialFinalization = true; | 3181 static const bool NeedSequentialFinalization = true; |
| 3149 | 3182 |
| 3150 static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator, | 3183 static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator, |
| 3151 MemoryChunk* chunk, PerPageData) { | 3184 MemoryChunk* chunk, PerPageData) { |
| 3152 return evacuator->EvacuatePage(chunk); | 3185 return evacuator->EvacuatePage(chunk); |
| 3153 } | 3186 } |
| 3154 | 3187 |
| 3155 static void FinalizePageSequentially(Heap*, MemoryChunk* chunk, bool success, | 3188 static void FinalizePageSequentially(Heap* heap, MemoryChunk* chunk, |
| 3156 PerPageData data) { | 3189 bool success, PerPageData data) { |
| 3157 if (chunk->InNewSpace()) { | 3190 if (chunk->InNewSpace()) { |
| 3158 DCHECK(success); | 3191 DCHECK(success); |
| 3159 } else { | 3192 } else { |
| 3160 Page* p = static_cast<Page*>(chunk); | 3193 Page* p = static_cast<Page*>(chunk); |
| 3161 if (success) { | 3194 if (success) { |
| 3162 DCHECK(p->IsEvacuationCandidate()); | 3195 DCHECK(p->IsEvacuationCandidate()); |
| 3163 DCHECK(p->SweepingDone()); | 3196 DCHECK(p->SweepingDone()); |
| 3164 p->Unlink(); | 3197 p->Unlink(); |
| 3165 } else { | 3198 } else { |
| 3166 // We have partially compacted the page, i.e., some objects may have | 3199 // We have partially compacted the page, i.e., some objects may have |
| 3167 // moved, others are still in place. | 3200 // moved, others are still in place. |
| 3168 // We need to: | |
| 3169 // - Leave the evacuation candidate flag for later processing of slots | |
| 3170 // buffer entries. | |
| 3171 // - Leave the slots buffer there for processing of entries added by | |
| 3172 // the write barrier. | |
| 3173 // - Rescan the page as slot recording in the migration buffer only | |
| 3174 // happens upon moving (which we potentially didn't do). | |
| 3175 // - Leave the page in the list of pages of a space since we could not | |
| 3176 // fully evacuate it. | |
| 3177 DCHECK(p->IsEvacuationCandidate()); | |
| 3178 p->SetFlag(Page::COMPACTION_WAS_ABORTED); | 3201 p->SetFlag(Page::COMPACTION_WAS_ABORTED); |
| 3202 p->ClearEvacuationCandidate(); | |
| 3203 // Slots have already been recorded so we just need to add it to the | |
| 3204 // sweeper. | |
|
Michael Lippautz
2016/04/14 07:50:11
We cannot add the page to the sweeper here because
| |
| 3179 *data += 1; | 3205 *data += 1; |
| 3180 } | 3206 } |
| 3181 } | 3207 } |
| 3182 } | 3208 } |
| 3183 }; | 3209 }; |
| 3184 | 3210 |
| 3185 void MarkCompactCollector::EvacuatePagesInParallel() { | 3211 void MarkCompactCollector::EvacuatePagesInParallel() { |
| 3186 PageParallelJob<EvacuationJobTraits> job( | 3212 PageParallelJob<EvacuationJobTraits> job( |
| 3187 heap_, heap_->isolate()->cancelable_task_manager()); | 3213 heap_, heap_->isolate()->cancelable_task_manager()); |
| 3188 | 3214 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3412 object->IterateBody(map->instance_type(), size, visitor); | 3438 object->IterateBody(map->instance_type(), size, visitor); |
| 3413 } | 3439 } |
| 3414 } | 3440 } |
| 3415 | 3441 |
| 3416 void MarkCompactCollector::Sweeper::AddSweptPageSafe(PagedSpace* space, | 3442 void MarkCompactCollector::Sweeper::AddSweptPageSafe(PagedSpace* space, |
| 3417 Page* page) { | 3443 Page* page) { |
| 3418 base::LockGuard<base::Mutex> guard(&mutex_); | 3444 base::LockGuard<base::Mutex> guard(&mutex_); |
| 3419 swept_list_[space->identity()].Add(page); | 3445 swept_list_[space->identity()].Add(page); |
| 3420 } | 3446 } |
| 3421 | 3447 |
| 3422 void MarkCompactCollector::SweepAbortedPages() { | |
| 3423 // Second pass on aborted pages. | |
| 3424 for (Page* p : evacuation_candidates_) { | |
| 3425 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { | |
| 3426 p->ClearFlag(MemoryChunk::COMPACTION_WAS_ABORTED); | |
| 3427 p->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress); | |
| 3428 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | |
| 3429 switch (space->identity()) { | |
| 3430 case OLD_SPACE: | |
| 3431 Sweeper::RawSweep<Sweeper::SWEEP_ONLY, Sweeper::SWEEP_ON_MAIN_THREAD, | |
| 3432 Sweeper::IGNORE_SKIP_LIST, | |
| 3433 Sweeper::IGNORE_FREE_SPACE>(space, p, nullptr); | |
| 3434 break; | |
| 3435 case CODE_SPACE: | |
| 3436 if (FLAG_zap_code_space) { | |
| 3437 Sweeper::RawSweep< | |
| 3438 Sweeper::SWEEP_ONLY, Sweeper::SWEEP_ON_MAIN_THREAD, | |
| 3439 Sweeper::REBUILD_SKIP_LIST, Sweeper::ZAP_FREE_SPACE>(space, p, | |
| 3440 nullptr); | |
| 3441 } else { | |
| 3442 Sweeper::RawSweep< | |
| 3443 Sweeper::SWEEP_ONLY, Sweeper::SWEEP_ON_MAIN_THREAD, | |
| 3444 Sweeper::REBUILD_SKIP_LIST, Sweeper::IGNORE_FREE_SPACE>( | |
| 3445 space, p, nullptr); | |
| 3446 } | |
| 3447 break; | |
| 3448 default: | |
| 3449 UNREACHABLE(); | |
| 3450 break; | |
| 3451 } | |
| 3452 sweeper().AddSweptPageSafe(space, p); | |
| 3453 } | |
| 3454 } | |
| 3455 } | |
| 3456 | |
| 3457 | |
| 3458 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { | 3448 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { |
| 3459 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE); | 3449 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE); |
| 3460 Heap::RelocationLock relocation_lock(heap()); | 3450 Heap::RelocationLock relocation_lock(heap()); |
| 3461 | 3451 |
| 3462 { | 3452 { |
| 3463 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_COPY); | 3453 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_COPY); |
| 3464 EvacuationScope evacuation_scope(this); | 3454 EvacuationScope evacuation_scope(this); |
| 3465 | 3455 |
| 3466 EvacuateNewSpacePrologue(); | 3456 EvacuateNewSpacePrologue(); |
| 3467 EvacuatePagesInParallel(); | 3457 EvacuatePagesInParallel(); |
| 3468 EvacuateNewSpaceEpilogue(); | 3458 EvacuateNewSpaceEpilogue(); |
| 3469 heap()->new_space()->set_age_mark(heap()->new_space()->top()); | 3459 heap()->new_space()->set_age_mark(heap()->new_space()->top()); |
| 3470 } | 3460 } |
| 3471 | 3461 |
| 3472 UpdatePointersAfterEvacuation(); | 3462 UpdatePointersAfterEvacuation(); |
| 3473 | 3463 |
| 3474 // Give pages that are queued to be freed back to the OS. Note that filtering | 3464 // Give pages that are queued to be freed back to the OS. Note that filtering |
| 3475 // slots only handles old space (for unboxed doubles), and thus map space can | 3465 // slots only handles old space (for unboxed doubles), and thus map space can |
| 3476 // still contain stale pointers. We only free the chunks after pointer updates | 3466 // still contain stale pointers. We only free the chunks after pointer updates |
| 3477 // to still have access to page headers. | 3467 // to still have access to page headers. |
| 3478 heap()->FreeQueuedChunks(); | 3468 heap()->FreeQueuedChunks(); |
| 3479 | 3469 |
| 3480 { | 3470 { |
| 3481 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_CLEAN_UP); | 3471 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_CLEAN_UP); |
| 3482 // After updating all pointers, we can finally sweep the aborted pages, | 3472 |
| 3483 // effectively overriding any forward pointers. | 3473 for (Page* p : evacuation_candidates_) { |
|
Michael Lippautz
2016/04/14 07:50:11
Moving this part to MC_EVACUATE_CLEAN_UP as it has
| |
| 3484 SweepAbortedPages(); | 3474 // Important: skip list should be cleared only after roots were updated |
| 3475 // because root iteration traverses the stack and might have to find | |
| 3476 // code objects from non-updated pc pointing into evacuation candidate. | |
| 3477 SkipList* list = p->skip_list(); | |
| 3478 if (list != NULL) list->Clear(); | |
| 3479 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { | |
| 3480 sweeper().AddLatePage(p->owner()->identity(), p); | |
| 3481 p->ClearFlag(Page::COMPACTION_WAS_ABORTED); | |
| 3482 } | |
| 3483 } | |
| 3485 | 3484 |
| 3486 // EvacuateNewSpaceAndCandidates iterates over new space objects and for | 3485 // EvacuateNewSpaceAndCandidates iterates over new space objects and for |
| 3487 // ArrayBuffers either re-registers them as live or promotes them. This is | 3486 // ArrayBuffers either re-registers them as live or promotes them. This is |
| 3488 // needed to properly free them. | 3487 // needed to properly free them. |
| 3489 heap()->array_buffer_tracker()->FreeDead(false); | 3488 heap()->array_buffer_tracker()->FreeDead(false); |
| 3490 | 3489 |
| 3491 // Deallocate evacuated candidate pages. | 3490 // Deallocate evacuated candidate pages. |
| 3492 ReleaseEvacuationCandidates(); | 3491 ReleaseEvacuationCandidates(); |
| 3493 } | 3492 } |
| 3494 | 3493 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3630 | 3629 |
| 3631 { | 3630 { |
| 3632 Heap* heap = this->heap(); | 3631 Heap* heap = this->heap(); |
| 3633 TRACE_GC(heap->tracer(), | 3632 TRACE_GC(heap->tracer(), |
| 3634 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED); | 3633 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED); |
| 3635 UpdatePointersInParallel<OLD_TO_OLD>(heap_); | 3634 UpdatePointersInParallel<OLD_TO_OLD>(heap_); |
| 3636 } | 3635 } |
| 3637 | 3636 |
| 3638 { | 3637 { |
| 3639 TRACE_GC(heap()->tracer(), | 3638 TRACE_GC(heap()->tracer(), |
| 3640 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_BETWEEN_EVACUATED); | |
| 3641 for (Page* p : evacuation_candidates_) { | |
| 3642 DCHECK(p->IsEvacuationCandidate()); | |
| 3643 // Important: skip list should be cleared only after roots were updated | |
| 3644 // because root iteration traverses the stack and might have to find | |
| 3645 // code objects from non-updated pc pointing into evacuation candidate. | |
| 3646 SkipList* list = p->skip_list(); | |
| 3647 if (list != NULL) list->Clear(); | |
| 3648 | |
| 3649 // First pass on aborted pages, fixing up all live objects. | |
| 3650 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { | |
| 3651 p->ClearEvacuationCandidate(); | |
| 3652 VisitLiveObjectsBody(p, &updating_visitor); | |
| 3653 } | |
| 3654 } | |
| 3655 } | |
| 3656 | |
| 3657 { | |
| 3658 TRACE_GC(heap()->tracer(), | |
| 3659 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK); | 3639 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK); |
| 3660 // Update pointers from external string table. | 3640 // Update pointers from external string table. |
| 3661 heap_->UpdateReferencesInExternalStringTable( | 3641 heap_->UpdateReferencesInExternalStringTable( |
| 3662 &UpdateReferenceInExternalStringTableEntry); | 3642 &UpdateReferenceInExternalStringTableEntry); |
| 3663 | 3643 |
| 3664 EvacuationWeakObjectRetainer evacuation_object_retainer; | 3644 EvacuationWeakObjectRetainer evacuation_object_retainer; |
| 3665 heap()->ProcessWeakListRoots(&evacuation_object_retainer); | 3645 heap()->ProcessWeakListRoots(&evacuation_object_retainer); |
| 3666 } | 3646 } |
| 3667 } | 3647 } |
| 3668 | 3648 |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3896 MarkBit mark_bit = Marking::MarkBitFrom(host); | 3876 MarkBit mark_bit = Marking::MarkBitFrom(host); |
| 3897 if (Marking::IsBlack(mark_bit)) { | 3877 if (Marking::IsBlack(mark_bit)) { |
| 3898 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); | 3878 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); |
| 3899 RecordRelocSlot(host, &rinfo, target); | 3879 RecordRelocSlot(host, &rinfo, target); |
| 3900 } | 3880 } |
| 3901 } | 3881 } |
| 3902 } | 3882 } |
| 3903 | 3883 |
| 3904 } // namespace internal | 3884 } // namespace internal |
| 3905 } // namespace v8 | 3885 } // namespace v8 |
| OLD | NEW |