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 |