| 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" |
| 11 #include "src/compilation-cache.h" | 11 #include "src/compilation-cache.h" |
| 12 #include "src/deoptimizer.h" | 12 #include "src/deoptimizer.h" |
| 13 #include "src/execution.h" | 13 #include "src/execution.h" |
| 14 #include "src/frames-inl.h" | 14 #include "src/frames-inl.h" |
| 15 #include "src/gdb-jit.h" | 15 #include "src/gdb-jit.h" |
| 16 #include "src/global-handles.h" | 16 #include "src/global-handles.h" |
| 17 #include "src/heap/array-buffer-tracker.h" | 17 #include "src/heap/array-buffer-tracker.h" |
| 18 #include "src/heap/gc-tracer.h" | 18 #include "src/heap/gc-tracer.h" |
| 19 #include "src/heap/incremental-marking.h" | 19 #include "src/heap/incremental-marking.h" |
| 20 #include "src/heap/mark-compact-inl.h" | 20 #include "src/heap/mark-compact-inl.h" |
| 21 #include "src/heap/object-stats.h" | 21 #include "src/heap/object-stats.h" |
| 22 #include "src/heap/objects-visiting-inl.h" | 22 #include "src/heap/objects-visiting-inl.h" |
| 23 #include "src/heap/objects-visiting.h" | 23 #include "src/heap/objects-visiting.h" |
| 24 #include "src/heap/slots-buffer.h" | |
| 25 #include "src/heap/spaces-inl.h" | 24 #include "src/heap/spaces-inl.h" |
| 26 #include "src/ic/ic.h" | 25 #include "src/ic/ic.h" |
| 27 #include "src/ic/stub-cache.h" | 26 #include "src/ic/stub-cache.h" |
| 28 #include "src/profiler/cpu-profiler.h" | 27 #include "src/profiler/cpu-profiler.h" |
| 29 #include "src/utils-inl.h" | 28 #include "src/utils-inl.h" |
| 30 #include "src/v8.h" | 29 #include "src/v8.h" |
| 31 | 30 |
| 32 namespace v8 { | 31 namespace v8 { |
| 33 namespace internal { | 32 namespace internal { |
| 34 | 33 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 48 // MarkCompactCollector | 47 // MarkCompactCollector |
| 49 | 48 |
| 50 MarkCompactCollector::MarkCompactCollector(Heap* heap) | 49 MarkCompactCollector::MarkCompactCollector(Heap* heap) |
| 51 : // NOLINT | 50 : // NOLINT |
| 52 #ifdef DEBUG | 51 #ifdef DEBUG |
| 53 state_(IDLE), | 52 state_(IDLE), |
| 54 #endif | 53 #endif |
| 55 marking_parity_(ODD_MARKING_PARITY), | 54 marking_parity_(ODD_MARKING_PARITY), |
| 56 was_marked_incrementally_(false), | 55 was_marked_incrementally_(false), |
| 57 evacuation_(false), | 56 evacuation_(false), |
| 58 slots_buffer_allocator_(nullptr), | |
| 59 migration_slots_buffer_(nullptr), | |
| 60 heap_(heap), | 57 heap_(heap), |
| 61 marking_deque_memory_(NULL), | 58 marking_deque_memory_(NULL), |
| 62 marking_deque_memory_committed_(0), | 59 marking_deque_memory_committed_(0), |
| 63 code_flusher_(nullptr), | 60 code_flusher_(nullptr), |
| 64 have_code_to_deoptimize_(false), | 61 have_code_to_deoptimize_(false), |
| 65 compacting_(false), | 62 compacting_(false), |
| 66 sweeping_in_progress_(false), | 63 sweeping_in_progress_(false), |
| 67 compaction_in_progress_(false), | 64 compaction_in_progress_(false), |
| 68 pending_sweeper_tasks_semaphore_(0), | 65 pending_sweeper_tasks_semaphore_(0), |
| 69 pending_compaction_tasks_semaphore_(0) { | 66 pending_compaction_tasks_semaphore_(0) { |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); | 239 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
| 243 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); | 240 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0); |
| 244 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); | 241 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0); |
| 245 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); | 242 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
| 246 | 243 |
| 247 free_list_old_space_.Reset(new FreeList(heap_->old_space())); | 244 free_list_old_space_.Reset(new FreeList(heap_->old_space())); |
| 248 free_list_code_space_.Reset(new FreeList(heap_->code_space())); | 245 free_list_code_space_.Reset(new FreeList(heap_->code_space())); |
| 249 free_list_map_space_.Reset(new FreeList(heap_->map_space())); | 246 free_list_map_space_.Reset(new FreeList(heap_->map_space())); |
| 250 EnsureMarkingDequeIsReserved(); | 247 EnsureMarkingDequeIsReserved(); |
| 251 EnsureMarkingDequeIsCommitted(kMinMarkingDequeSize); | 248 EnsureMarkingDequeIsCommitted(kMinMarkingDequeSize); |
| 252 slots_buffer_allocator_ = new SlotsBufferAllocator(); | |
| 253 | 249 |
| 254 if (FLAG_flush_code) { | 250 if (FLAG_flush_code) { |
| 255 code_flusher_ = new CodeFlusher(isolate()); | 251 code_flusher_ = new CodeFlusher(isolate()); |
| 256 if (FLAG_trace_code_flushing) { | 252 if (FLAG_trace_code_flushing) { |
| 257 PrintF("[code-flushing is now on]\n"); | 253 PrintF("[code-flushing is now on]\n"); |
| 258 } | 254 } |
| 259 } | 255 } |
| 260 } | 256 } |
| 261 | 257 |
| 262 | 258 |
| 263 void MarkCompactCollector::TearDown() { | 259 void MarkCompactCollector::TearDown() { |
| 264 AbortCompaction(); | 260 AbortCompaction(); |
| 265 delete marking_deque_memory_; | 261 delete marking_deque_memory_; |
| 266 delete slots_buffer_allocator_; | |
| 267 delete code_flusher_; | 262 delete code_flusher_; |
| 268 } | 263 } |
| 269 | 264 |
| 270 | 265 |
| 271 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { | 266 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { |
| 272 DCHECK(!p->NeverEvacuate()); | 267 DCHECK(!p->NeverEvacuate()); |
| 273 p->MarkEvacuationCandidate(); | 268 p->MarkEvacuationCandidate(); |
| 274 evacuation_candidates_.Add(p); | 269 evacuation_candidates_.Add(p); |
| 275 } | 270 } |
| 276 | 271 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 303 | 298 |
| 304 heap()->old_space()->EvictEvacuationCandidatesFromLinearAllocationArea(); | 299 heap()->old_space()->EvictEvacuationCandidatesFromLinearAllocationArea(); |
| 305 heap()->code_space()->EvictEvacuationCandidatesFromLinearAllocationArea(); | 300 heap()->code_space()->EvictEvacuationCandidatesFromLinearAllocationArea(); |
| 306 | 301 |
| 307 compacting_ = evacuation_candidates_.length() > 0; | 302 compacting_ = evacuation_candidates_.length() > 0; |
| 308 } | 303 } |
| 309 | 304 |
| 310 return compacting_; | 305 return compacting_; |
| 311 } | 306 } |
| 312 | 307 |
| 313 | 308 void MarkCompactCollector::ClearInvalidRememberedSetSlots() { |
| 314 void MarkCompactCollector::ClearInvalidStoreAndSlotsBufferEntries() { | |
| 315 { | 309 { |
| 316 GCTracer::Scope gc_scope(heap()->tracer(), | 310 GCTracer::Scope gc_scope(heap()->tracer(), |
| 317 GCTracer::Scope::MC_CLEAR_STORE_BUFFER); | 311 GCTracer::Scope::MC_CLEAR_STORE_BUFFER); |
| 318 RememberedSet<OLD_TO_NEW>::ClearInvalidSlots(heap()); | 312 RememberedSet<OLD_TO_NEW>::ClearInvalidSlots(heap()); |
| 319 } | 313 } |
| 314 // There is not need to filter the old to old set because |
| 315 // it is completely cleared after the mark-compact GC. |
| 316 // The slots that become invalid due to runtime transitions are |
| 317 // cleared eagerly immediately after the transition. |
| 320 | 318 |
| 321 { | |
| 322 GCTracer::Scope gc_scope(heap()->tracer(), | |
| 323 GCTracer::Scope::MC_CLEAR_SLOTS_BUFFER); | |
| 324 for (Page* p : evacuation_candidates_) { | |
| 325 SlotsBuffer::RemoveInvalidSlots(heap_, p->slots_buffer()); | |
| 326 } | |
| 327 } | |
| 328 #ifdef VERIFY_HEAP | 319 #ifdef VERIFY_HEAP |
| 329 if (FLAG_verify_heap) { | 320 if (FLAG_verify_heap) { |
| 330 VerifyValidStoreAndSlotsBufferEntries(); | 321 RememberedSet<OLD_TO_NEW>::VerifyValidSlots(heap()); |
| 322 RememberedSet<OLD_TO_OLD>::VerifyValidSlots(heap()); |
| 331 } | 323 } |
| 332 #endif | 324 #endif |
| 333 } | 325 } |
| 334 | 326 |
| 335 | 327 |
| 336 #ifdef VERIFY_HEAP | |
| 337 static void VerifyValidSlotsBufferEntries(Heap* heap, PagedSpace* space) { | |
| 338 PageIterator it(space); | |
| 339 while (it.has_next()) { | |
| 340 Page* p = it.next(); | |
| 341 SlotsBuffer::VerifySlots(heap, p->slots_buffer()); | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 | |
| 346 void MarkCompactCollector::VerifyValidStoreAndSlotsBufferEntries() { | |
| 347 RememberedSet<OLD_TO_NEW>::VerifyValidSlots(heap()); | |
| 348 | |
| 349 VerifyValidSlotsBufferEntries(heap(), heap()->old_space()); | |
| 350 VerifyValidSlotsBufferEntries(heap(), heap()->code_space()); | |
| 351 VerifyValidSlotsBufferEntries(heap(), heap()->map_space()); | |
| 352 | |
| 353 LargeObjectIterator it(heap()->lo_space()); | |
| 354 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) { | |
| 355 MemoryChunk* chunk = MemoryChunk::FromAddress(object->address()); | |
| 356 SlotsBuffer::VerifySlots(heap(), chunk->slots_buffer()); | |
| 357 } | |
| 358 } | |
| 359 #endif | |
| 360 | |
| 361 | |
| 362 void MarkCompactCollector::CollectGarbage() { | 328 void MarkCompactCollector::CollectGarbage() { |
| 363 // Make sure that Prepare() has been called. The individual steps below will | 329 // Make sure that Prepare() has been called. The individual steps below will |
| 364 // update the state as they proceed. | 330 // update the state as they proceed. |
| 365 DCHECK(state_ == PREPARE_GC); | 331 DCHECK(state_ == PREPARE_GC); |
| 366 | 332 |
| 367 MarkLiveObjects(); | 333 MarkLiveObjects(); |
| 368 | 334 |
| 369 DCHECK(heap_->incremental_marking()->IsStopped()); | 335 DCHECK(heap_->incremental_marking()->IsStopped()); |
| 370 | 336 |
| 371 ClearNonLiveReferences(); | 337 ClearNonLiveReferences(); |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 if (p->IsFlagSet(Page::POPULAR_PAGE)) { | 667 if (p->IsFlagSet(Page::POPULAR_PAGE)) { |
| 702 // This page had slots buffer overflow on previous GC, skip it. | 668 // This page had slots buffer overflow on previous GC, skip it. |
| 703 p->ClearFlag(Page::POPULAR_PAGE); | 669 p->ClearFlag(Page::POPULAR_PAGE); |
| 704 continue; | 670 continue; |
| 705 } | 671 } |
| 706 // Invariant: Evacuation candidates are just created when marking is | 672 // Invariant: Evacuation candidates are just created when marking is |
| 707 // started. This means that sweeping has finished. Furthermore, at the end | 673 // started. This means that sweeping has finished. Furthermore, at the end |
| 708 // of a GC all evacuation candidates are cleared and their slot buffers are | 674 // of a GC all evacuation candidates are cleared and their slot buffers are |
| 709 // released. | 675 // released. |
| 710 CHECK(!p->IsEvacuationCandidate()); | 676 CHECK(!p->IsEvacuationCandidate()); |
| 711 CHECK(p->slots_buffer() == nullptr); | 677 CHECK_NULL(p->old_to_old_slots()); |
| 678 CHECK_NULL(p->typed_old_to_old_slots()); |
| 712 CHECK(p->SweepingDone()); | 679 CHECK(p->SweepingDone()); |
| 713 DCHECK(p->area_size() == area_size); | 680 DCHECK(p->area_size() == area_size); |
| 714 pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p)); | 681 pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p)); |
| 715 } | 682 } |
| 716 | 683 |
| 717 int candidate_count = 0; | 684 int candidate_count = 0; |
| 718 int total_live_bytes = 0; | 685 int total_live_bytes = 0; |
| 719 | 686 |
| 720 const bool reduce_memory = heap()->ShouldReduceMemory(); | 687 const bool reduce_memory = heap()->ShouldReduceMemory(); |
| 721 if (FLAG_manual_evacuation_candidates_selection) { | 688 if (FLAG_manual_evacuation_candidates_selection) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 807 "compaction-selection: space=%s reduce_memory=%d pages=%d " | 774 "compaction-selection: space=%s reduce_memory=%d pages=%d " |
| 808 "total_live_bytes=%d\n", | 775 "total_live_bytes=%d\n", |
| 809 AllocationSpaceName(space->identity()), reduce_memory, | 776 AllocationSpaceName(space->identity()), reduce_memory, |
| 810 candidate_count, total_live_bytes / KB); | 777 candidate_count, total_live_bytes / KB); |
| 811 } | 778 } |
| 812 } | 779 } |
| 813 | 780 |
| 814 | 781 |
| 815 void MarkCompactCollector::AbortCompaction() { | 782 void MarkCompactCollector::AbortCompaction() { |
| 816 if (compacting_) { | 783 if (compacting_) { |
| 784 RememberedSet<OLD_TO_OLD>::ClearAll(heap()); |
| 817 for (Page* p : evacuation_candidates_) { | 785 for (Page* p : evacuation_candidates_) { |
| 818 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); | |
| 819 p->ClearEvacuationCandidate(); | 786 p->ClearEvacuationCandidate(); |
| 820 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); | 787 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); |
| 821 } | 788 } |
| 822 compacting_ = false; | 789 compacting_ = false; |
| 823 evacuation_candidates_.Rewind(0); | 790 evacuation_candidates_.Rewind(0); |
| 824 } | 791 } |
| 825 DCHECK_EQ(0, evacuation_candidates_.length()); | 792 DCHECK_EQ(0, evacuation_candidates_.length()); |
| 826 } | 793 } |
| 827 | 794 |
| 828 | 795 |
| (...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1523 public: | 1490 public: |
| 1524 virtual ~HeapObjectVisitor() {} | 1491 virtual ~HeapObjectVisitor() {} |
| 1525 virtual bool Visit(HeapObject* object) = 0; | 1492 virtual bool Visit(HeapObject* object) = 0; |
| 1526 }; | 1493 }; |
| 1527 | 1494 |
| 1528 | 1495 |
| 1529 class MarkCompactCollector::EvacuateVisitorBase | 1496 class MarkCompactCollector::EvacuateVisitorBase |
| 1530 : public MarkCompactCollector::HeapObjectVisitor { | 1497 : public MarkCompactCollector::HeapObjectVisitor { |
| 1531 public: | 1498 public: |
| 1532 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces, | 1499 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces, |
| 1533 SlotsBuffer** evacuation_slots_buffer, | 1500 LocalSlotsBuffer* old_to_old_slots, |
| 1534 LocalStoreBuffer* local_store_buffer) | 1501 LocalSlotsBuffer* old_to_new_slots) |
| 1535 : heap_(heap), | 1502 : heap_(heap), |
| 1536 evacuation_slots_buffer_(evacuation_slots_buffer), | |
| 1537 compaction_spaces_(compaction_spaces), | 1503 compaction_spaces_(compaction_spaces), |
| 1538 local_store_buffer_(local_store_buffer) {} | 1504 old_to_old_slots_(old_to_old_slots), |
| 1505 old_to_new_slots_(old_to_new_slots) {} |
| 1539 | 1506 |
| 1540 bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, | 1507 bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, |
| 1541 HeapObject** target_object) { | 1508 HeapObject** target_object) { |
| 1542 int size = object->Size(); | 1509 int size = object->Size(); |
| 1543 AllocationAlignment alignment = object->RequiredAlignment(); | 1510 AllocationAlignment alignment = object->RequiredAlignment(); |
| 1544 AllocationResult allocation = target_space->AllocateRaw(size, alignment); | 1511 AllocationResult allocation = target_space->AllocateRaw(size, alignment); |
| 1545 if (allocation.To(target_object)) { | 1512 if (allocation.To(target_object)) { |
| 1546 heap_->mark_compact_collector()->MigrateObject( | 1513 heap_->mark_compact_collector()->MigrateObject( |
| 1547 *target_object, object, size, target_space->identity(), | 1514 *target_object, object, size, target_space->identity(), |
| 1548 evacuation_slots_buffer_, local_store_buffer_); | 1515 old_to_old_slots_, old_to_new_slots_); |
| 1549 return true; | 1516 return true; |
| 1550 } | 1517 } |
| 1551 return false; | 1518 return false; |
| 1552 } | 1519 } |
| 1553 | 1520 |
| 1554 protected: | 1521 protected: |
| 1555 Heap* heap_; | 1522 Heap* heap_; |
| 1556 SlotsBuffer** evacuation_slots_buffer_; | |
| 1557 CompactionSpaceCollection* compaction_spaces_; | 1523 CompactionSpaceCollection* compaction_spaces_; |
| 1558 LocalStoreBuffer* local_store_buffer_; | 1524 LocalSlotsBuffer* old_to_old_slots_; |
| 1525 LocalSlotsBuffer* old_to_new_slots_; |
| 1559 }; | 1526 }; |
| 1560 | 1527 |
| 1561 | 1528 |
| 1562 class MarkCompactCollector::EvacuateNewSpaceVisitor final | 1529 class MarkCompactCollector::EvacuateNewSpaceVisitor final |
| 1563 : public MarkCompactCollector::EvacuateVisitorBase { | 1530 : public MarkCompactCollector::EvacuateVisitorBase { |
| 1564 public: | 1531 public: |
| 1565 static const intptr_t kLabSize = 4 * KB; | 1532 static const intptr_t kLabSize = 4 * KB; |
| 1566 static const intptr_t kMaxLabObjectSize = 256; | 1533 static const intptr_t kMaxLabObjectSize = 256; |
| 1567 | 1534 |
| 1568 explicit EvacuateNewSpaceVisitor(Heap* heap, | 1535 explicit EvacuateNewSpaceVisitor(Heap* heap, |
| 1569 CompactionSpaceCollection* compaction_spaces, | 1536 CompactionSpaceCollection* compaction_spaces, |
| 1570 SlotsBuffer** evacuation_slots_buffer, | 1537 LocalSlotsBuffer* old_to_old_slots, |
| 1571 LocalStoreBuffer* local_store_buffer, | 1538 LocalSlotsBuffer* old_to_new_slots, |
| 1572 HashMap* local_pretenuring_feedback) | 1539 HashMap* local_pretenuring_feedback) |
| 1573 : EvacuateVisitorBase(heap, compaction_spaces, evacuation_slots_buffer, | 1540 : EvacuateVisitorBase(heap, compaction_spaces, old_to_old_slots, |
| 1574 local_store_buffer), | 1541 old_to_new_slots), |
| 1575 buffer_(LocalAllocationBuffer::InvalidBuffer()), | 1542 buffer_(LocalAllocationBuffer::InvalidBuffer()), |
| 1576 space_to_allocate_(NEW_SPACE), | 1543 space_to_allocate_(NEW_SPACE), |
| 1577 promoted_size_(0), | 1544 promoted_size_(0), |
| 1578 semispace_copied_size_(0), | 1545 semispace_copied_size_(0), |
| 1579 local_pretenuring_feedback_(local_pretenuring_feedback) {} | 1546 local_pretenuring_feedback_(local_pretenuring_feedback) {} |
| 1580 | 1547 |
| 1581 bool Visit(HeapObject* object) override { | 1548 bool Visit(HeapObject* object) override { |
| 1582 heap_->UpdateAllocationSite<Heap::kCached>(object, | 1549 heap_->UpdateAllocationSite<Heap::kCached>(object, |
| 1583 local_pretenuring_feedback_); | 1550 local_pretenuring_feedback_); |
| 1584 int size = object->Size(); | 1551 int size = object->Size(); |
| 1585 HeapObject* target_object = nullptr; | 1552 HeapObject* target_object = nullptr; |
| 1586 if (heap_->ShouldBePromoted(object->address(), size) && | 1553 if (heap_->ShouldBePromoted(object->address(), size) && |
| 1587 TryEvacuateObject(compaction_spaces_->Get(OLD_SPACE), object, | 1554 TryEvacuateObject(compaction_spaces_->Get(OLD_SPACE), object, |
| 1588 &target_object)) { | 1555 &target_object)) { |
| 1589 // If we end up needing more special cases, we should factor this out. | 1556 // If we end up needing more special cases, we should factor this out. |
| 1590 if (V8_UNLIKELY(target_object->IsJSArrayBuffer())) { | 1557 if (V8_UNLIKELY(target_object->IsJSArrayBuffer())) { |
| 1591 heap_->array_buffer_tracker()->Promote( | 1558 heap_->array_buffer_tracker()->Promote( |
| 1592 JSArrayBuffer::cast(target_object)); | 1559 JSArrayBuffer::cast(target_object)); |
| 1593 } | 1560 } |
| 1594 promoted_size_ += size; | 1561 promoted_size_ += size; |
| 1595 return true; | 1562 return true; |
| 1596 } | 1563 } |
| 1597 HeapObject* target = nullptr; | 1564 HeapObject* target = nullptr; |
| 1598 AllocationSpace space = AllocateTargetObject(object, &target); | 1565 AllocationSpace space = AllocateTargetObject(object, &target); |
| 1599 heap_->mark_compact_collector()->MigrateObject( | 1566 heap_->mark_compact_collector()->MigrateObject( |
| 1600 HeapObject::cast(target), object, size, space, | 1567 HeapObject::cast(target), object, size, space, |
| 1601 (space == NEW_SPACE) ? nullptr : evacuation_slots_buffer_, | 1568 (space == NEW_SPACE) ? nullptr : old_to_old_slots_, |
| 1602 (space == NEW_SPACE) ? nullptr : local_store_buffer_); | 1569 (space == NEW_SPACE) ? nullptr : old_to_new_slots_); |
| 1603 if (V8_UNLIKELY(target->IsJSArrayBuffer())) { | 1570 if (V8_UNLIKELY(target->IsJSArrayBuffer())) { |
| 1604 heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target)); | 1571 heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target)); |
| 1605 } | 1572 } |
| 1606 semispace_copied_size_ += size; | 1573 semispace_copied_size_ += size; |
| 1607 return true; | 1574 return true; |
| 1608 } | 1575 } |
| 1609 | 1576 |
| 1610 intptr_t promoted_size() { return promoted_size_; } | 1577 intptr_t promoted_size() { return promoted_size_; } |
| 1611 intptr_t semispace_copied_size() { return semispace_copied_size_; } | 1578 intptr_t semispace_copied_size() { return semispace_copied_size_; } |
| 1612 | 1579 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1712 intptr_t semispace_copied_size_; | 1679 intptr_t semispace_copied_size_; |
| 1713 HashMap* local_pretenuring_feedback_; | 1680 HashMap* local_pretenuring_feedback_; |
| 1714 }; | 1681 }; |
| 1715 | 1682 |
| 1716 | 1683 |
| 1717 class MarkCompactCollector::EvacuateOldSpaceVisitor final | 1684 class MarkCompactCollector::EvacuateOldSpaceVisitor final |
| 1718 : public MarkCompactCollector::EvacuateVisitorBase { | 1685 : public MarkCompactCollector::EvacuateVisitorBase { |
| 1719 public: | 1686 public: |
| 1720 EvacuateOldSpaceVisitor(Heap* heap, | 1687 EvacuateOldSpaceVisitor(Heap* heap, |
| 1721 CompactionSpaceCollection* compaction_spaces, | 1688 CompactionSpaceCollection* compaction_spaces, |
| 1722 SlotsBuffer** evacuation_slots_buffer, | 1689 LocalSlotsBuffer* old_to_old_slots, |
| 1723 LocalStoreBuffer* local_store_buffer) | 1690 LocalSlotsBuffer* old_to_new_slots) |
| 1724 : EvacuateVisitorBase(heap, compaction_spaces, evacuation_slots_buffer, | 1691 : EvacuateVisitorBase(heap, compaction_spaces, old_to_old_slots, |
| 1725 local_store_buffer) {} | 1692 old_to_new_slots) {} |
| 1726 | 1693 |
| 1727 bool Visit(HeapObject* object) override { | 1694 bool Visit(HeapObject* object) override { |
| 1728 CompactionSpace* target_space = compaction_spaces_->Get( | 1695 CompactionSpace* target_space = compaction_spaces_->Get( |
| 1729 Page::FromAddress(object->address())->owner()->identity()); | 1696 Page::FromAddress(object->address())->owner()->identity()); |
| 1730 HeapObject* target_object = nullptr; | 1697 HeapObject* target_object = nullptr; |
| 1731 if (TryEvacuateObject(target_space, object, &target_object)) { | 1698 if (TryEvacuateObject(target_space, object, &target_object)) { |
| 1732 DCHECK(object->map_word().IsForwardingAddress()); | 1699 DCHECK(object->map_word().IsForwardingAddress()); |
| 1733 return true; | 1700 return true; |
| 1734 } | 1701 } |
| 1735 return false; | 1702 return false; |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2172 { | 2139 { |
| 2173 GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_CLEAR_MAPS); | 2140 GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_CLEAR_MAPS); |
| 2174 ClearSimpleMapTransitions(non_live_map_list); | 2141 ClearSimpleMapTransitions(non_live_map_list); |
| 2175 ClearFullMapTransitions(); | 2142 ClearFullMapTransitions(); |
| 2176 } | 2143 } |
| 2177 | 2144 |
| 2178 MarkDependentCodeForDeoptimization(dependent_code_list); | 2145 MarkDependentCodeForDeoptimization(dependent_code_list); |
| 2179 | 2146 |
| 2180 ClearWeakCollections(); | 2147 ClearWeakCollections(); |
| 2181 | 2148 |
| 2182 ClearInvalidStoreAndSlotsBufferEntries(); | 2149 ClearInvalidRememberedSetSlots(); |
| 2183 } | 2150 } |
| 2184 | 2151 |
| 2185 | 2152 |
| 2186 void MarkCompactCollector::MarkDependentCodeForDeoptimization( | 2153 void MarkCompactCollector::MarkDependentCodeForDeoptimization( |
| 2187 DependentCode* list_head) { | 2154 DependentCode* list_head) { |
| 2188 GCTracer::Scope gc_scope(heap()->tracer(), | 2155 GCTracer::Scope gc_scope(heap()->tracer(), |
| 2189 GCTracer::Scope::MC_CLEAR_DEPENDENT_CODE); | 2156 GCTracer::Scope::MC_CLEAR_DEPENDENT_CODE); |
| 2190 Isolate* isolate = this->isolate(); | 2157 Isolate* isolate = this->isolate(); |
| 2191 DependentCode* current = list_head; | 2158 DependentCode* current = list_head; |
| 2192 while (current->length() > 0) { | 2159 while (current->length() > 0) { |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2535 Object* obj = heap()->encountered_transition_arrays(); | 2502 Object* obj = heap()->encountered_transition_arrays(); |
| 2536 while (obj != Smi::FromInt(0)) { | 2503 while (obj != Smi::FromInt(0)) { |
| 2537 TransitionArray* array = TransitionArray::cast(obj); | 2504 TransitionArray* array = TransitionArray::cast(obj); |
| 2538 obj = array->next_link(); | 2505 obj = array->next_link(); |
| 2539 array->set_next_link(undefined, SKIP_WRITE_BARRIER); | 2506 array->set_next_link(undefined, SKIP_WRITE_BARRIER); |
| 2540 } | 2507 } |
| 2541 heap()->set_encountered_transition_arrays(Smi::FromInt(0)); | 2508 heap()->set_encountered_transition_arrays(Smi::FromInt(0)); |
| 2542 } | 2509 } |
| 2543 | 2510 |
| 2544 void MarkCompactCollector::RecordMigratedSlot( | 2511 void MarkCompactCollector::RecordMigratedSlot( |
| 2545 Object* value, Address slot, SlotsBuffer** evacuation_slots_buffer, | 2512 Object* value, Address slot, LocalSlotsBuffer* old_to_old_slots, |
| 2546 LocalStoreBuffer* local_store_buffer) { | 2513 LocalSlotsBuffer* old_to_new_slots) { |
| 2547 // When parallel compaction is in progress, store and slots buffer entries | 2514 // When parallel compaction is in progress, store and slots buffer entries |
| 2548 // require synchronization. | 2515 // require synchronization. |
| 2549 if (heap_->InNewSpace(value)) { | 2516 if (heap_->InNewSpace(value)) { |
| 2550 if (compaction_in_progress_) { | 2517 if (compaction_in_progress_) { |
| 2551 local_store_buffer->Record(slot); | 2518 old_to_new_slots->Record(slot); |
| 2552 } else { | 2519 } else { |
| 2553 Page* page = Page::FromAddress(slot); | 2520 Page* page = Page::FromAddress(slot); |
| 2554 RememberedSet<OLD_TO_NEW>::Insert(page, slot); | 2521 RememberedSet<OLD_TO_NEW>::Insert(page, slot); |
| 2555 } | 2522 } |
| 2556 } else if (value->IsHeapObject() && IsOnEvacuationCandidate(value)) { | 2523 } else if (value->IsHeapObject() && IsOnEvacuationCandidate(value)) { |
| 2557 SlotsBuffer::AddTo(slots_buffer_allocator_, evacuation_slots_buffer, | 2524 old_to_old_slots->Record(slot); |
| 2558 reinterpret_cast<Object**>(slot), | |
| 2559 SlotsBuffer::IGNORE_OVERFLOW); | |
| 2560 } | 2525 } |
| 2561 } | 2526 } |
| 2562 | 2527 |
| 2563 | 2528 static inline SlotType SlotTypeForRMode(RelocInfo::Mode rmode) { |
| 2564 void MarkCompactCollector::RecordMigratedCodeEntrySlot( | 2529 if (RelocInfo::IsCodeTarget(rmode)) { |
| 2565 Address code_entry, Address code_entry_slot, | 2530 return CODE_TARGET_SLOT; |
| 2566 SlotsBuffer** evacuation_slots_buffer) { | 2531 } else if (RelocInfo::IsCell(rmode)) { |
| 2567 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { | 2532 return CELL_TARGET_SLOT; |
| 2568 SlotsBuffer::AddTo(slots_buffer_allocator_, evacuation_slots_buffer, | 2533 } else if (RelocInfo::IsEmbeddedObject(rmode)) { |
| 2569 SlotsBuffer::CODE_ENTRY_SLOT, code_entry_slot, | 2534 return EMBEDDED_OBJECT_SLOT; |
| 2570 SlotsBuffer::IGNORE_OVERFLOW); | 2535 } else if (RelocInfo::IsDebugBreakSlot(rmode)) { |
| 2536 return DEBUG_TARGET_SLOT; |
| 2571 } | 2537 } |
| 2538 UNREACHABLE(); |
| 2539 return NUMBER_OF_SLOT_TYPES; |
| 2572 } | 2540 } |
| 2573 | 2541 |
| 2574 | 2542 void MarkCompactCollector::RecordRelocSlot(Code* host, RelocInfo* rinfo, |
| 2575 void MarkCompactCollector::RecordMigratedCodeObjectSlot( | 2543 Object* target) { |
| 2576 Address code_object, SlotsBuffer** evacuation_slots_buffer) { | |
| 2577 SlotsBuffer::AddTo(slots_buffer_allocator_, evacuation_slots_buffer, | |
| 2578 SlotsBuffer::RELOCATED_CODE_OBJECT, code_object, | |
| 2579 SlotsBuffer::IGNORE_OVERFLOW); | |
| 2580 } | |
| 2581 | |
| 2582 | |
| 2583 static inline SlotsBuffer::SlotType SlotTypeForRMode(RelocInfo::Mode rmode) { | |
| 2584 if (RelocInfo::IsCodeTarget(rmode)) { | |
| 2585 return SlotsBuffer::CODE_TARGET_SLOT; | |
| 2586 } else if (RelocInfo::IsCell(rmode)) { | |
| 2587 return SlotsBuffer::CELL_TARGET_SLOT; | |
| 2588 } else if (RelocInfo::IsEmbeddedObject(rmode)) { | |
| 2589 return SlotsBuffer::EMBEDDED_OBJECT_SLOT; | |
| 2590 } else if (RelocInfo::IsDebugBreakSlot(rmode)) { | |
| 2591 return SlotsBuffer::DEBUG_TARGET_SLOT; | |
| 2592 } | |
| 2593 UNREACHABLE(); | |
| 2594 return SlotsBuffer::NUMBER_OF_SLOT_TYPES; | |
| 2595 } | |
| 2596 | |
| 2597 | |
| 2598 static inline SlotsBuffer::SlotType DecodeSlotType( | |
| 2599 SlotsBuffer::ObjectSlot slot) { | |
| 2600 return static_cast<SlotsBuffer::SlotType>(reinterpret_cast<intptr_t>(slot)); | |
| 2601 } | |
| 2602 | |
| 2603 | |
| 2604 void MarkCompactCollector::RecordRelocSlot(RelocInfo* rinfo, Object* target) { | |
| 2605 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); | 2544 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); |
| 2545 Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host)); |
| 2606 RelocInfo::Mode rmode = rinfo->rmode(); | 2546 RelocInfo::Mode rmode = rinfo->rmode(); |
| 2607 if (target_page->IsEvacuationCandidate() && | 2547 if (target_page->IsEvacuationCandidate() && |
| 2608 (rinfo->host() == NULL || | 2548 (rinfo->host() == NULL || |
| 2609 !ShouldSkipEvacuationSlotRecording(rinfo->host()))) { | 2549 !ShouldSkipEvacuationSlotRecording(rinfo->host()))) { |
| 2610 Address addr = rinfo->pc(); | 2550 Address addr = rinfo->pc(); |
| 2611 SlotsBuffer::SlotType slot_type = SlotTypeForRMode(rmode); | 2551 SlotType slot_type = SlotTypeForRMode(rmode); |
| 2612 if (rinfo->IsInConstantPool()) { | 2552 if (rinfo->IsInConstantPool()) { |
| 2613 addr = rinfo->constant_pool_entry_address(); | 2553 addr = rinfo->constant_pool_entry_address(); |
| 2614 if (RelocInfo::IsCodeTarget(rmode)) { | 2554 if (RelocInfo::IsCodeTarget(rmode)) { |
| 2615 slot_type = SlotsBuffer::CODE_ENTRY_SLOT; | 2555 slot_type = CODE_ENTRY_SLOT; |
| 2616 } else { | 2556 } else { |
| 2617 DCHECK(RelocInfo::IsEmbeddedObject(rmode)); | 2557 DCHECK(RelocInfo::IsEmbeddedObject(rmode)); |
| 2618 slot_type = SlotsBuffer::OBJECT_SLOT; | 2558 slot_type = OBJECT_SLOT; |
| 2619 } | 2559 } |
| 2620 } | 2560 } |
| 2621 bool success = SlotsBuffer::AddTo( | 2561 RememberedSet<OLD_TO_OLD>::InsertTyped(source_page, slot_type, addr); |
| 2622 slots_buffer_allocator_, target_page->slots_buffer_address(), slot_type, | |
| 2623 addr, SlotsBuffer::FAIL_ON_OVERFLOW); | |
| 2624 if (!success) { | |
| 2625 EvictPopularEvacuationCandidate(target_page); | |
| 2626 } | |
| 2627 } | 2562 } |
| 2628 } | 2563 } |
| 2629 | 2564 |
| 2630 | 2565 |
| 2631 class RecordMigratedSlotVisitor final : public ObjectVisitor { | 2566 class RecordMigratedSlotVisitor final : public ObjectVisitor { |
| 2632 public: | 2567 public: |
| 2633 RecordMigratedSlotVisitor(MarkCompactCollector* collector, | 2568 RecordMigratedSlotVisitor(MarkCompactCollector* collector, |
| 2634 SlotsBuffer** evacuation_slots_buffer, | 2569 LocalSlotsBuffer* old_to_old_slots, |
| 2635 LocalStoreBuffer* local_store_buffer) | 2570 LocalSlotsBuffer* old_to_new_slots) |
| 2636 : collector_(collector), | 2571 : collector_(collector), |
| 2637 evacuation_slots_buffer_(evacuation_slots_buffer), | 2572 old_to_old_slots_(old_to_old_slots), |
| 2638 local_store_buffer_(local_store_buffer) {} | 2573 old_to_new_slots_(old_to_new_slots) {} |
| 2639 | 2574 |
| 2640 V8_INLINE void VisitPointer(Object** p) override { | 2575 V8_INLINE void VisitPointer(Object** p) override { |
| 2641 collector_->RecordMigratedSlot(*p, reinterpret_cast<Address>(p), | 2576 collector_->RecordMigratedSlot(*p, reinterpret_cast<Address>(p), |
| 2642 evacuation_slots_buffer_, | 2577 old_to_old_slots_, old_to_new_slots_); |
| 2643 local_store_buffer_); | |
| 2644 } | 2578 } |
| 2645 | 2579 |
| 2646 V8_INLINE void VisitPointers(Object** start, Object** end) override { | 2580 V8_INLINE void VisitPointers(Object** start, Object** end) override { |
| 2647 while (start < end) { | 2581 while (start < end) { |
| 2648 collector_->RecordMigratedSlot(*start, reinterpret_cast<Address>(start), | 2582 collector_->RecordMigratedSlot(*start, reinterpret_cast<Address>(start), |
| 2649 evacuation_slots_buffer_, | 2583 old_to_old_slots_, old_to_new_slots_); |
| 2650 local_store_buffer_); | |
| 2651 ++start; | 2584 ++start; |
| 2652 } | 2585 } |
| 2653 } | 2586 } |
| 2654 | 2587 |
| 2655 V8_INLINE void VisitCodeEntry(Address code_entry_slot) override { | 2588 V8_INLINE void VisitCodeEntry(Address code_entry_slot) override { |
| 2656 if (collector_->compacting_) { | 2589 if (collector_->compacting_) { |
| 2657 Address code_entry = Memory::Address_at(code_entry_slot); | 2590 Address code_entry = Memory::Address_at(code_entry_slot); |
| 2658 collector_->RecordMigratedCodeEntrySlot(code_entry, code_entry_slot, | 2591 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { |
| 2659 evacuation_slots_buffer_); | 2592 old_to_old_slots_->Record(CODE_ENTRY_SLOT, code_entry_slot); |
| 2593 } |
| 2660 } | 2594 } |
| 2661 } | 2595 } |
| 2662 | 2596 |
| 2663 private: | 2597 private: |
| 2664 MarkCompactCollector* collector_; | 2598 MarkCompactCollector* collector_; |
| 2665 SlotsBuffer** evacuation_slots_buffer_; | 2599 LocalSlotsBuffer* old_to_old_slots_; |
| 2666 LocalStoreBuffer* local_store_buffer_; | 2600 LocalSlotsBuffer* old_to_new_slots_; |
| 2667 }; | 2601 }; |
| 2668 | 2602 |
| 2669 | 2603 |
| 2670 // We scavenge new space simultaneously with sweeping. This is done in two | 2604 // We scavenge new space simultaneously with sweeping. This is done in two |
| 2671 // passes. | 2605 // passes. |
| 2672 // | 2606 // |
| 2673 // The first pass migrates all alive objects from one semispace to another or | 2607 // The first pass migrates all alive objects from one semispace to another or |
| 2674 // promotes them to old space. Forwarding address is written directly into | 2608 // promotes them to old space. Forwarding address is written directly into |
| 2675 // first word of object without any encoding. If object is dead we write | 2609 // first word of object without any encoding. If object is dead we write |
| 2676 // NULL as a forwarding address. | 2610 // NULL as a forwarding address. |
| 2677 // | 2611 // |
| 2678 // The second pass updates pointers to new space in all spaces. It is possible | 2612 // The second pass updates pointers to new space in all spaces. It is possible |
| 2679 // to encounter pointers to dead new space objects during traversal of pointers | 2613 // to encounter pointers to dead new space objects during traversal of pointers |
| 2680 // to new space. We should clear them to avoid encountering them during next | 2614 // to new space. We should clear them to avoid encountering them during next |
| 2681 // pointer iteration. This is an issue if the store buffer overflows and we | 2615 // pointer iteration. This is an issue if the store buffer overflows and we |
| 2682 // have to scan the entire old space, including dead objects, looking for | 2616 // have to scan the entire old space, including dead objects, looking for |
| 2683 // pointers to new space. | 2617 // pointers to new space. |
| 2684 void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src, | 2618 void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src, |
| 2685 int size, AllocationSpace dest, | 2619 int size, AllocationSpace dest, |
| 2686 SlotsBuffer** evacuation_slots_buffer, | 2620 LocalSlotsBuffer* old_to_old_slots, |
| 2687 LocalStoreBuffer* local_store_buffer) { | 2621 LocalSlotsBuffer* old_to_new_slots) { |
| 2688 Address dst_addr = dst->address(); | 2622 Address dst_addr = dst->address(); |
| 2689 Address src_addr = src->address(); | 2623 Address src_addr = src->address(); |
| 2690 DCHECK(heap()->AllowedToBeMigrated(src, dest)); | 2624 DCHECK(heap()->AllowedToBeMigrated(src, dest)); |
| 2691 DCHECK(dest != LO_SPACE); | 2625 DCHECK(dest != LO_SPACE); |
| 2692 if (dest == OLD_SPACE) { | 2626 if (dest == OLD_SPACE) { |
| 2693 DCHECK_OBJECT_SIZE(size); | 2627 DCHECK_OBJECT_SIZE(size); |
| 2694 DCHECK(evacuation_slots_buffer != nullptr); | |
| 2695 DCHECK(IsAligned(size, kPointerSize)); | 2628 DCHECK(IsAligned(size, kPointerSize)); |
| 2696 | 2629 |
| 2697 heap()->MoveBlock(dst->address(), src->address(), size); | 2630 heap()->MoveBlock(dst->address(), src->address(), size); |
| 2698 RecordMigratedSlotVisitor visitor(this, evacuation_slots_buffer, | 2631 RecordMigratedSlotVisitor visitor(this, old_to_old_slots, old_to_new_slots); |
| 2699 local_store_buffer); | |
| 2700 dst->IterateBody(&visitor); | 2632 dst->IterateBody(&visitor); |
| 2701 } else if (dest == CODE_SPACE) { | 2633 } else if (dest == CODE_SPACE) { |
| 2702 DCHECK_CODEOBJECT_SIZE(size, heap()->code_space()); | 2634 DCHECK_CODEOBJECT_SIZE(size, heap()->code_space()); |
| 2703 DCHECK(evacuation_slots_buffer != nullptr); | |
| 2704 PROFILE(isolate(), CodeMoveEvent(src_addr, dst_addr)); | 2635 PROFILE(isolate(), CodeMoveEvent(src_addr, dst_addr)); |
| 2705 heap()->MoveBlock(dst_addr, src_addr, size); | 2636 heap()->MoveBlock(dst_addr, src_addr, size); |
| 2706 RecordMigratedCodeObjectSlot(dst_addr, evacuation_slots_buffer); | 2637 old_to_old_slots->Record(RELOCATED_CODE_OBJECT, dst_addr); |
| 2707 Code::cast(dst)->Relocate(dst_addr - src_addr); | 2638 Code::cast(dst)->Relocate(dst_addr - src_addr); |
| 2708 } else { | 2639 } else { |
| 2709 DCHECK_OBJECT_SIZE(size); | 2640 DCHECK_OBJECT_SIZE(size); |
| 2710 DCHECK(evacuation_slots_buffer == nullptr); | 2641 DCHECK(old_to_old_slots == nullptr); |
| 2711 DCHECK(dest == NEW_SPACE); | 2642 DCHECK(dest == NEW_SPACE); |
| 2712 heap()->MoveBlock(dst_addr, src_addr, size); | 2643 heap()->MoveBlock(dst_addr, src_addr, size); |
| 2713 } | 2644 } |
| 2714 heap()->OnMoveEvent(dst, src, size); | 2645 heap()->OnMoveEvent(dst, src, size); |
| 2715 Memory::Address_at(src_addr) = dst_addr; | 2646 Memory::Address_at(src_addr) = dst_addr; |
| 2716 } | 2647 } |
| 2717 | 2648 |
| 2718 | 2649 static inline void UpdateTypedSlot(Isolate* isolate, ObjectVisitor* v, |
| 2719 static inline void UpdateSlot(Isolate* isolate, ObjectVisitor* v, | 2650 SlotType slot_type, Address addr) { |
| 2720 SlotsBuffer::SlotType slot_type, Address addr) { | |
| 2721 switch (slot_type) { | 2651 switch (slot_type) { |
| 2722 case SlotsBuffer::CODE_TARGET_SLOT: { | 2652 case CODE_TARGET_SLOT: { |
| 2723 RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); | 2653 RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); |
| 2724 rinfo.Visit(isolate, v); | 2654 rinfo.Visit(isolate, v); |
| 2725 break; | 2655 break; |
| 2726 } | 2656 } |
| 2727 case SlotsBuffer::CELL_TARGET_SLOT: { | 2657 case CELL_TARGET_SLOT: { |
| 2728 RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); | 2658 RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); |
| 2729 rinfo.Visit(isolate, v); | 2659 rinfo.Visit(isolate, v); |
| 2730 break; | 2660 break; |
| 2731 } | 2661 } |
| 2732 case SlotsBuffer::CODE_ENTRY_SLOT: { | 2662 case CODE_ENTRY_SLOT: { |
| 2733 v->VisitCodeEntry(addr); | 2663 v->VisitCodeEntry(addr); |
| 2734 break; | 2664 break; |
| 2735 } | 2665 } |
| 2736 case SlotsBuffer::RELOCATED_CODE_OBJECT: { | 2666 case RELOCATED_CODE_OBJECT: { |
| 2737 HeapObject* obj = HeapObject::FromAddress(addr); | 2667 HeapObject* obj = HeapObject::FromAddress(addr); |
| 2738 Code::BodyDescriptor::IterateBody(obj, v); | 2668 Code::BodyDescriptor::IterateBody(obj, v); |
| 2739 break; | 2669 break; |
| 2740 } | 2670 } |
| 2741 case SlotsBuffer::DEBUG_TARGET_SLOT: { | 2671 case DEBUG_TARGET_SLOT: { |
| 2742 RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION, 0, | 2672 RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION, 0, |
| 2743 NULL); | 2673 NULL); |
| 2744 if (rinfo.IsPatchedDebugBreakSlotSequence()) rinfo.Visit(isolate, v); | 2674 if (rinfo.IsPatchedDebugBreakSlotSequence()) rinfo.Visit(isolate, v); |
| 2745 break; | 2675 break; |
| 2746 } | 2676 } |
| 2747 case SlotsBuffer::EMBEDDED_OBJECT_SLOT: { | 2677 case EMBEDDED_OBJECT_SLOT: { |
| 2748 RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL); | 2678 RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL); |
| 2749 rinfo.Visit(isolate, v); | 2679 rinfo.Visit(isolate, v); |
| 2750 break; | 2680 break; |
| 2751 } | 2681 } |
| 2752 case SlotsBuffer::OBJECT_SLOT: { | 2682 case OBJECT_SLOT: { |
| 2753 v->VisitPointer(reinterpret_cast<Object**>(addr)); | 2683 v->VisitPointer(reinterpret_cast<Object**>(addr)); |
| 2754 break; | 2684 break; |
| 2755 } | 2685 } |
| 2756 default: | 2686 default: |
| 2757 UNREACHABLE(); | 2687 UNREACHABLE(); |
| 2758 break; | 2688 break; |
| 2759 } | 2689 } |
| 2760 } | 2690 } |
| 2761 | 2691 |
| 2762 | 2692 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2847 } | 2777 } |
| 2848 } | 2778 } |
| 2849 | 2779 |
| 2850 private: | 2780 private: |
| 2851 inline void UpdatePointer(Object** p) { UpdateSlot(heap_, p); } | 2781 inline void UpdatePointer(Object** p) { UpdateSlot(heap_, p); } |
| 2852 | 2782 |
| 2853 Heap* heap_; | 2783 Heap* heap_; |
| 2854 }; | 2784 }; |
| 2855 | 2785 |
| 2856 | 2786 |
| 2857 void MarkCompactCollector::UpdateSlots(SlotsBuffer* buffer) { | |
| 2858 PointersUpdatingVisitor v(heap_); | |
| 2859 size_t buffer_size = buffer->Size(); | |
| 2860 | |
| 2861 for (size_t slot_idx = 0; slot_idx < buffer_size; ++slot_idx) { | |
| 2862 SlotsBuffer::ObjectSlot slot = buffer->Get(slot_idx); | |
| 2863 if (!SlotsBuffer::IsTypedSlot(slot)) { | |
| 2864 PointersUpdatingVisitor::UpdateSlot(heap_, slot); | |
| 2865 } else { | |
| 2866 ++slot_idx; | |
| 2867 DCHECK(slot_idx < buffer_size); | |
| 2868 UpdateSlot(heap_->isolate(), &v, DecodeSlotType(slot), | |
| 2869 reinterpret_cast<Address>(buffer->Get(slot_idx))); | |
| 2870 } | |
| 2871 } | |
| 2872 } | |
| 2873 | |
| 2874 | |
| 2875 void MarkCompactCollector::UpdateSlotsRecordedIn(SlotsBuffer* buffer) { | |
| 2876 while (buffer != NULL) { | |
| 2877 UpdateSlots(buffer); | |
| 2878 buffer = buffer->next(); | |
| 2879 } | |
| 2880 } | |
| 2881 | |
| 2882 | |
| 2883 static void UpdatePointer(HeapObject** address, HeapObject* object) { | 2787 static void UpdatePointer(HeapObject** address, HeapObject* object) { |
| 2884 MapWord map_word = object->map_word(); | 2788 MapWord map_word = object->map_word(); |
| 2885 // Since we only filter invalid slots in old space, the store buffer can | 2789 // Since we only filter invalid slots in old space, the store buffer can |
| 2886 // still contain stale pointers in large object and in map spaces. Ignore | 2790 // still contain stale pointers in large object and in map spaces. Ignore |
| 2887 // these pointers here. | 2791 // these pointers here. |
| 2888 DCHECK(map_word.IsForwardingAddress() || | 2792 DCHECK(map_word.IsForwardingAddress() || |
| 2889 !object->GetHeap()->old_space()->Contains( | 2793 !object->GetHeap()->old_space()->Contains( |
| 2890 reinterpret_cast<Address>(address))); | 2794 reinterpret_cast<Address>(address))); |
| 2891 if (map_word.IsForwardingAddress()) { | 2795 if (map_word.IsForwardingAddress()) { |
| 2892 // Update the corresponding slot. | 2796 // Update the corresponding slot. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2994 // If the slot is within the last found object in the cell, the slot is | 2898 // If the slot is within the last found object in the cell, the slot is |
| 2995 // in a live object. | 2899 // in a live object. |
| 2996 // Slots pointing to the first word of an object are invalid and removed. | 2900 // Slots pointing to the first word of an object are invalid and removed. |
| 2997 // This can happen when we move the object header while left trimming. | 2901 // This can happen when we move the object header while left trimming. |
| 2998 *out_object = object; | 2902 *out_object = object; |
| 2999 return true; | 2903 return true; |
| 3000 } | 2904 } |
| 3001 return false; | 2905 return false; |
| 3002 } | 2906 } |
| 3003 | 2907 |
| 3004 | 2908 HeapObject* MarkCompactCollector::FindBlackObjectBySlotSlow(Address slot) { |
| 3005 bool MarkCompactCollector::IsSlotInBlackObjectSlow(Page* p, Address slot) { | 2909 Page* p = Page::FromAddress(slot); |
| 3006 // This function does not support large objects right now. | 2910 // This function does not support large objects right now. |
| 3007 Space* owner = p->owner(); | 2911 Space* owner = p->owner(); |
| 3008 if (owner == heap_->lo_space() || owner == NULL) { | 2912 if (owner == heap_->lo_space() || owner == nullptr) { |
| 3009 Object* large_object = heap_->lo_space()->FindObject(slot); | 2913 Object* large_object = heap_->lo_space()->FindObject(slot); |
| 3010 // This object has to exist, otherwise we would not have recorded a slot | 2914 // This object has to exist, otherwise we would not have recorded a slot |
| 3011 // for it. | 2915 // for it. |
| 3012 CHECK(large_object->IsHeapObject()); | 2916 CHECK(large_object->IsHeapObject()); |
| 3013 HeapObject* large_heap_object = HeapObject::cast(large_object); | 2917 HeapObject* large_heap_object = HeapObject::cast(large_object); |
| 2918 |
| 3014 if (IsMarked(large_heap_object)) { | 2919 if (IsMarked(large_heap_object)) { |
| 3015 return true; | 2920 return large_heap_object; |
| 3016 } | 2921 } |
| 3017 return false; | 2922 return nullptr; |
| 3018 } | 2923 } |
| 3019 | 2924 |
| 3020 LiveObjectIterator<kBlackObjects> it(p); | 2925 LiveObjectIterator<kBlackObjects> it(p); |
| 3021 HeapObject* object = NULL; | 2926 HeapObject* object = nullptr; |
| 3022 while ((object = it.Next()) != NULL) { | 2927 while ((object = it.Next()) != nullptr) { |
| 3023 int size = object->Size(); | 2928 int size = object->Size(); |
| 3024 | 2929 if (object->address() > slot) return nullptr; |
| 3025 if (object->address() > slot) return false; | |
| 3026 if (object->address() <= slot && slot < (object->address() + size)) { | 2930 if (object->address() <= slot && slot < (object->address() + size)) { |
| 3027 return true; | 2931 return object; |
| 3028 } | 2932 } |
| 3029 } | 2933 } |
| 3030 return false; | 2934 return nullptr; |
| 3031 } | 2935 } |
| 3032 | 2936 |
| 3033 | 2937 |
| 3034 bool MarkCompactCollector::IsSlotInLiveObject(Address slot) { | 2938 bool MarkCompactCollector::IsSlotInLiveObject(Address slot) { |
| 3035 HeapObject* object = NULL; | 2939 HeapObject* object = NULL; |
| 3036 // The target object is black but we don't know if the source slot is black. | 2940 // The target object is black but we don't know if the source slot is black. |
| 3037 // The source object could have died and the slot could be part of a free | 2941 // The source object could have died and the slot could be part of a free |
| 3038 // space. Find out based on mark bits if the slot is part of a live object. | 2942 // space. Find out based on mark bits if the slot is part of a live object. |
| 3039 if (!IsSlotInBlackObject(Page::FromAddress(slot), slot, &object)) { | 2943 if (!IsSlotInBlackObject(Page::FromAddress(slot), slot, &object)) { |
| 3040 return false; | 2944 return false; |
| 3041 } | 2945 } |
| 3042 | 2946 |
| 3043 DCHECK(object != NULL); | 2947 DCHECK(object != NULL); |
| 3044 int offset = static_cast<int>(slot - object->address()); | 2948 int offset = static_cast<int>(slot - object->address()); |
| 3045 return object->IsValidSlot(offset); | 2949 return object->IsValidSlot(offset); |
| 3046 } | 2950 } |
| 3047 | 2951 |
| 3048 | 2952 |
| 3049 void MarkCompactCollector::VerifyIsSlotInLiveObject(Address slot, | |
| 3050 HeapObject* object) { | |
| 3051 // The target object has to be black. | |
| 3052 CHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); | |
| 3053 | |
| 3054 // The target object is black but we don't know if the source slot is black. | |
| 3055 // The source object could have died and the slot could be part of a free | |
| 3056 // space. Use the mark bit iterator to find out about liveness of the slot. | |
| 3057 CHECK(IsSlotInBlackObjectSlow(Page::FromAddress(slot), slot)); | |
| 3058 } | |
| 3059 | |
| 3060 | |
| 3061 void MarkCompactCollector::EvacuateNewSpacePrologue() { | 2953 void MarkCompactCollector::EvacuateNewSpacePrologue() { |
| 3062 NewSpace* new_space = heap()->new_space(); | 2954 NewSpace* new_space = heap()->new_space(); |
| 3063 NewSpacePageIterator it(new_space->bottom(), new_space->top()); | 2955 NewSpacePageIterator it(new_space->bottom(), new_space->top()); |
| 3064 // Append the list of new space pages to be processed. | 2956 // Append the list of new space pages to be processed. |
| 3065 while (it.has_next()) { | 2957 while (it.has_next()) { |
| 3066 newspace_evacuation_candidates_.Add(it.next()); | 2958 newspace_evacuation_candidates_.Add(it.next()); |
| 3067 } | 2959 } |
| 3068 new_space->Flip(); | 2960 new_space->Flip(); |
| 3069 new_space->ResetAllocationInfo(); | 2961 new_space->ResetAllocationInfo(); |
| 3070 } | 2962 } |
| 3071 | 2963 |
| 3072 void MarkCompactCollector::EvacuateNewSpaceEpilogue() { | 2964 void MarkCompactCollector::EvacuateNewSpaceEpilogue() { |
| 3073 newspace_evacuation_candidates_.Rewind(0); | 2965 newspace_evacuation_candidates_.Rewind(0); |
| 3074 } | 2966 } |
| 3075 | 2967 |
| 3076 | 2968 |
| 3077 void MarkCompactCollector::AddEvacuationSlotsBufferSynchronized( | |
| 3078 SlotsBuffer* evacuation_slots_buffer) { | |
| 3079 base::LockGuard<base::Mutex> lock_guard(&evacuation_slots_buffers_mutex_); | |
| 3080 evacuation_slots_buffers_.Add(evacuation_slots_buffer); | |
| 3081 } | |
| 3082 | |
| 3083 class MarkCompactCollector::Evacuator : public Malloced { | 2969 class MarkCompactCollector::Evacuator : public Malloced { |
| 3084 public: | 2970 public: |
| 3085 Evacuator(MarkCompactCollector* collector, | 2971 Evacuator(MarkCompactCollector* collector, |
| 3086 const List<Page*>& evacuation_candidates, | 2972 const List<Page*>& evacuation_candidates, |
| 3087 const List<NewSpacePage*>& newspace_evacuation_candidates) | 2973 const List<NewSpacePage*>& newspace_evacuation_candidates) |
| 3088 : collector_(collector), | 2974 : collector_(collector), |
| 3089 evacuation_candidates_(evacuation_candidates), | 2975 evacuation_candidates_(evacuation_candidates), |
| 3090 newspace_evacuation_candidates_(newspace_evacuation_candidates), | 2976 newspace_evacuation_candidates_(newspace_evacuation_candidates), |
| 3091 compaction_spaces_(collector->heap()), | 2977 compaction_spaces_(collector->heap()), |
| 3092 local_slots_buffer_(nullptr), | |
| 3093 local_store_buffer_(collector->heap()), | |
| 3094 local_pretenuring_feedback_(HashMap::PointersMatch, | 2978 local_pretenuring_feedback_(HashMap::PointersMatch, |
| 3095 kInitialLocalPretenuringFeedbackCapacity), | 2979 kInitialLocalPretenuringFeedbackCapacity), |
| 3096 new_space_visitor_(collector->heap(), &compaction_spaces_, | 2980 new_space_visitor_(collector->heap(), &compaction_spaces_, |
| 3097 &local_slots_buffer_, &local_store_buffer_, | 2981 &old_to_old_slots_, &old_to_new_slots_, |
| 3098 &local_pretenuring_feedback_), | 2982 &local_pretenuring_feedback_), |
| 3099 old_space_visitor_(collector->heap(), &compaction_spaces_, | 2983 old_space_visitor_(collector->heap(), &compaction_spaces_, |
| 3100 &local_slots_buffer_, &local_store_buffer_), | 2984 &old_to_old_slots_, &old_to_new_slots_), |
| 3101 duration_(0.0), | 2985 duration_(0.0), |
| 3102 bytes_compacted_(0), | 2986 bytes_compacted_(0), |
| 3103 task_id_(0) {} | 2987 task_id_(0) {} |
| 3104 | 2988 |
| 3105 // Evacuate the configured set of pages in parallel. | 2989 // Evacuate the configured set of pages in parallel. |
| 3106 inline void EvacuatePages(); | 2990 inline void EvacuatePages(); |
| 3107 | 2991 |
| 3108 // Merge back locally cached info sequentially. Note that this method needs | 2992 // Merge back locally cached info sequentially. Note that this method needs |
| 3109 // to be called from the main thread. | 2993 // to be called from the main thread. |
| 3110 inline void Finalize(); | 2994 inline void Finalize(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3127 inline bool EvacuateSinglePage(MemoryChunk* p, HeapObjectVisitor* visitor); | 3011 inline bool EvacuateSinglePage(MemoryChunk* p, HeapObjectVisitor* visitor); |
| 3128 | 3012 |
| 3129 MarkCompactCollector* collector_; | 3013 MarkCompactCollector* collector_; |
| 3130 | 3014 |
| 3131 // Pages to process. | 3015 // Pages to process. |
| 3132 const List<Page*>& evacuation_candidates_; | 3016 const List<Page*>& evacuation_candidates_; |
| 3133 const List<NewSpacePage*>& newspace_evacuation_candidates_; | 3017 const List<NewSpacePage*>& newspace_evacuation_candidates_; |
| 3134 | 3018 |
| 3135 // Locally cached collector data. | 3019 // Locally cached collector data. |
| 3136 CompactionSpaceCollection compaction_spaces_; | 3020 CompactionSpaceCollection compaction_spaces_; |
| 3137 SlotsBuffer* local_slots_buffer_; | 3021 LocalSlotsBuffer old_to_old_slots_; |
| 3138 LocalStoreBuffer local_store_buffer_; | 3022 LocalSlotsBuffer old_to_new_slots_; |
| 3139 HashMap local_pretenuring_feedback_; | 3023 HashMap local_pretenuring_feedback_; |
| 3140 | 3024 |
| 3141 // Vistors for the corresponding spaces. | 3025 // Vistors for the corresponding spaces. |
| 3142 EvacuateNewSpaceVisitor new_space_visitor_; | 3026 EvacuateNewSpaceVisitor new_space_visitor_; |
| 3143 EvacuateOldSpaceVisitor old_space_visitor_; | 3027 EvacuateOldSpaceVisitor old_space_visitor_; |
| 3144 | 3028 |
| 3145 // Book keeping info. | 3029 // Book keeping info. |
| 3146 double duration_; | 3030 double duration_; |
| 3147 intptr_t bytes_compacted_; | 3031 intptr_t bytes_compacted_; |
| 3148 | 3032 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3206 heap()->code_space()->MergeCompactionSpace( | 3090 heap()->code_space()->MergeCompactionSpace( |
| 3207 compaction_spaces_.Get(CODE_SPACE)); | 3091 compaction_spaces_.Get(CODE_SPACE)); |
| 3208 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); | 3092 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); |
| 3209 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size()); | 3093 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size()); |
| 3210 heap()->IncrementSemiSpaceCopiedObjectSize( | 3094 heap()->IncrementSemiSpaceCopiedObjectSize( |
| 3211 new_space_visitor_.semispace_copied_size()); | 3095 new_space_visitor_.semispace_copied_size()); |
| 3212 heap()->IncrementYoungSurvivorsCounter( | 3096 heap()->IncrementYoungSurvivorsCounter( |
| 3213 new_space_visitor_.promoted_size() + | 3097 new_space_visitor_.promoted_size() + |
| 3214 new_space_visitor_.semispace_copied_size()); | 3098 new_space_visitor_.semispace_copied_size()); |
| 3215 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_); | 3099 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_); |
| 3216 local_store_buffer_.Process(heap()->store_buffer()); | 3100 // Move locally recorded slots to the global remembered sets. |
| 3217 collector_->AddEvacuationSlotsBufferSynchronized(local_slots_buffer_); | 3101 old_to_new_slots_.Iterate( |
| 3102 [](Address slot) { |
| 3103 Page* page = Page::FromAddress(slot); |
| 3104 RememberedSet<OLD_TO_NEW>::Insert(page, slot); |
| 3105 }, |
| 3106 [](SlotType type, Address slot) { UNREACHABLE(); }); |
| 3107 old_to_old_slots_.Iterate( |
| 3108 [](Address slot) { |
| 3109 Page* page = Page::FromAddress(slot); |
| 3110 RememberedSet<OLD_TO_OLD>::Insert(page, slot); |
| 3111 }, |
| 3112 [](SlotType type, Address slot) { |
| 3113 Page* page = Page::FromAddress(slot); |
| 3114 RememberedSet<OLD_TO_OLD>::InsertTyped(page, type, slot); |
| 3115 }); |
| 3218 } | 3116 } |
| 3219 | 3117 |
| 3220 class MarkCompactCollector::CompactionTask : public CancelableTask { | 3118 class MarkCompactCollector::CompactionTask : public CancelableTask { |
| 3221 public: | 3119 public: |
| 3222 explicit CompactionTask(Heap* heap, Evacuator* evacuator) | 3120 explicit CompactionTask(Heap* heap, Evacuator* evacuator) |
| 3223 : CancelableTask(heap->isolate()), heap_(heap), evacuator_(evacuator) { | 3121 : CancelableTask(heap->isolate()), heap_(heap), evacuator_(evacuator) { |
| 3224 evacuator->set_task_id(id()); | 3122 evacuator->set_task_id(id()); |
| 3225 } | 3123 } |
| 3226 | 3124 |
| 3227 virtual ~CompactionTask() {} | 3125 virtual ~CompactionTask() {} |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3514 !ShouldSkipEvacuationSlotRecording(code)) { | 3412 !ShouldSkipEvacuationSlotRecording(code)) { |
| 3515 DCHECK(compacting_); | 3413 DCHECK(compacting_); |
| 3516 | 3414 |
| 3517 // If the object is white than no slots were recorded on it yet. | 3415 // If the object is white than no slots were recorded on it yet. |
| 3518 MarkBit mark_bit = Marking::MarkBitFrom(code); | 3416 MarkBit mark_bit = Marking::MarkBitFrom(code); |
| 3519 if (Marking::IsWhite(mark_bit)) return; | 3417 if (Marking::IsWhite(mark_bit)) return; |
| 3520 | 3418 |
| 3521 // Ignore all slots that might have been recorded in the body of the | 3419 // Ignore all slots that might have been recorded in the body of the |
| 3522 // deoptimized code object. Assumption: no slots will be recorded for | 3420 // deoptimized code object. Assumption: no slots will be recorded for |
| 3523 // this object after invalidating it. | 3421 // this object after invalidating it. |
| 3524 RemoveObjectSlots(code->instruction_start(), | 3422 Page* page = Page::FromAddress(code->address()); |
| 3525 code->address() + code->Size()); | 3423 Address start = code->instruction_start(); |
| 3424 Address end = code->address() + code->Size(); |
| 3425 RememberedSet<OLD_TO_OLD>::RemoveRangeTyped(page, start, end); |
| 3526 } | 3426 } |
| 3527 } | 3427 } |
| 3528 | 3428 |
| 3529 | 3429 |
| 3530 // Return true if the given code is deoptimized or will be deoptimized. | 3430 // Return true if the given code is deoptimized or will be deoptimized. |
| 3531 bool MarkCompactCollector::WillBeDeoptimized(Code* code) { | 3431 bool MarkCompactCollector::WillBeDeoptimized(Code* code) { |
| 3532 return code->is_optimized_code() && code->marked_for_deoptimization(); | 3432 return code->is_optimized_code() && code->marked_for_deoptimization(); |
| 3533 } | 3433 } |
| 3534 | 3434 |
| 3535 | 3435 |
| 3536 void MarkCompactCollector::RemoveObjectSlots(Address start_slot, | |
| 3537 Address end_slot) { | |
| 3538 // Remove entries by replacing them with an old-space slot containing a smi | |
| 3539 // that is located in an unmovable page. | |
| 3540 for (Page* p : evacuation_candidates_) { | |
| 3541 DCHECK(p->IsEvacuationCandidate() || | |
| 3542 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | |
| 3543 if (p->IsEvacuationCandidate()) { | |
| 3544 SlotsBuffer::RemoveObjectSlots(heap_, p->slots_buffer(), start_slot, | |
| 3545 end_slot); | |
| 3546 } | |
| 3547 } | |
| 3548 } | |
| 3549 | |
| 3550 | |
| 3551 #ifdef VERIFY_HEAP | 3436 #ifdef VERIFY_HEAP |
| 3552 static void VerifyAllBlackObjects(MemoryChunk* page) { | 3437 static void VerifyAllBlackObjects(MemoryChunk* page) { |
| 3553 LiveObjectIterator<kAllLiveObjects> it(page); | 3438 LiveObjectIterator<kAllLiveObjects> it(page); |
| 3554 HeapObject* object = NULL; | 3439 HeapObject* object = NULL; |
| 3555 while ((object = it.Next()) != NULL) { | 3440 while ((object = it.Next()) != NULL) { |
| 3556 CHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); | 3441 CHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); |
| 3557 } | 3442 } |
| 3558 } | 3443 } |
| 3559 #endif // VERIFY_HEAP | 3444 #endif // VERIFY_HEAP |
| 3560 | 3445 |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3692 if (FLAG_verify_heap && !sweeping_in_progress_) { | 3577 if (FLAG_verify_heap && !sweeping_in_progress_) { |
| 3693 VerifyEvacuation(heap()); | 3578 VerifyEvacuation(heap()); |
| 3694 } | 3579 } |
| 3695 #endif | 3580 #endif |
| 3696 } | 3581 } |
| 3697 | 3582 |
| 3698 | 3583 |
| 3699 void MarkCompactCollector::UpdatePointersAfterEvacuation() { | 3584 void MarkCompactCollector::UpdatePointersAfterEvacuation() { |
| 3700 GCTracer::Scope gc_scope(heap()->tracer(), | 3585 GCTracer::Scope gc_scope(heap()->tracer(), |
| 3701 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS); | 3586 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS); |
| 3702 { | |
| 3703 GCTracer::Scope gc_scope( | |
| 3704 heap()->tracer(), | |
| 3705 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED); | |
| 3706 UpdateSlotsRecordedIn(migration_slots_buffer_); | |
| 3707 if (FLAG_trace_fragmentation_verbose) { | |
| 3708 PrintF(" migration slots buffer: %d\n", | |
| 3709 SlotsBuffer::SizeOfChain(migration_slots_buffer_)); | |
| 3710 } | |
| 3711 slots_buffer_allocator_->DeallocateChain(&migration_slots_buffer_); | |
| 3712 DCHECK(migration_slots_buffer_ == NULL); | |
| 3713 | 3587 |
| 3714 // TODO(hpayer): Process the slots buffers in parallel. This has to be done | |
| 3715 // after evacuation of all pages finishes. | |
| 3716 int buffers = evacuation_slots_buffers_.length(); | |
| 3717 for (int i = 0; i < buffers; i++) { | |
| 3718 SlotsBuffer* buffer = evacuation_slots_buffers_[i]; | |
| 3719 UpdateSlotsRecordedIn(buffer); | |
| 3720 slots_buffer_allocator_->DeallocateChain(&buffer); | |
| 3721 } | |
| 3722 evacuation_slots_buffers_.Rewind(0); | |
| 3723 } | |
| 3724 | |
| 3725 // Second pass: find pointers to new space and update them. | |
| 3726 PointersUpdatingVisitor updating_visitor(heap()); | 3588 PointersUpdatingVisitor updating_visitor(heap()); |
| 3727 | 3589 |
| 3728 { | 3590 { |
| 3729 GCTracer::Scope gc_scope( | 3591 GCTracer::Scope gc_scope( |
| 3730 heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW); | 3592 heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW); |
| 3731 // Update pointers in to space. | 3593 // Update pointers in to space. |
| 3732 SemiSpaceIterator to_it(heap()->new_space()); | 3594 SemiSpaceIterator to_it(heap()->new_space()); |
| 3733 for (HeapObject* object = to_it.Next(); object != NULL; | 3595 for (HeapObject* object = to_it.Next(); object != NULL; |
| 3734 object = to_it.Next()) { | 3596 object = to_it.Next()) { |
| 3735 Map* map = object->map(); | 3597 Map* map = object->map(); |
| 3736 object->IterateBody(map->instance_type(), object->SizeFromMap(map), | 3598 object->IterateBody(map->instance_type(), object->SizeFromMap(map), |
| 3737 &updating_visitor); | 3599 &updating_visitor); |
| 3738 } | 3600 } |
| 3739 // Update roots. | 3601 // Update roots. |
| 3740 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); | 3602 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); |
| 3741 | 3603 |
| 3742 RememberedSet<OLD_TO_NEW>::IterateWithWrapper(heap_, UpdatePointer); | 3604 RememberedSet<OLD_TO_NEW>::IterateWithWrapper(heap_, UpdatePointer); |
| 3743 } | 3605 } |
| 3744 | 3606 |
| 3745 { | 3607 { |
| 3608 Heap* heap = this->heap(); |
| 3609 GCTracer::Scope gc_scope( |
| 3610 heap->tracer(), |
| 3611 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED); |
| 3612 |
| 3613 RememberedSet<OLD_TO_OLD>::Iterate(heap, [heap](Address slot) { |
| 3614 PointersUpdatingVisitor::UpdateSlot(heap, |
| 3615 reinterpret_cast<Object**>(slot)); |
| 3616 return REMOVE_SLOT; |
| 3617 }); |
| 3618 Isolate* isolate = heap->isolate(); |
| 3619 PointersUpdatingVisitor* visitor = &updating_visitor; |
| 3620 RememberedSet<OLD_TO_OLD>::IterateTyped( |
| 3621 heap, [isolate, visitor](SlotType type, Address slot) { |
| 3622 UpdateTypedSlot(isolate, visitor, type, slot); |
| 3623 return REMOVE_SLOT; |
| 3624 }); |
| 3625 } |
| 3626 |
| 3627 { |
| 3746 GCTracer::Scope gc_scope( | 3628 GCTracer::Scope gc_scope( |
| 3747 heap()->tracer(), | 3629 heap()->tracer(), |
| 3748 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_BETWEEN_EVACUATED); | 3630 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_BETWEEN_EVACUATED); |
| 3749 for (Page* p : evacuation_candidates_) { | 3631 for (Page* p : evacuation_candidates_) { |
| 3750 DCHECK(p->IsEvacuationCandidate() || | 3632 DCHECK(p->IsEvacuationCandidate() || |
| 3751 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | 3633 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); |
| 3752 | 3634 |
| 3753 if (p->IsEvacuationCandidate()) { | 3635 if (p->IsEvacuationCandidate()) { |
| 3754 UpdateSlotsRecordedIn(p->slots_buffer()); | |
| 3755 if (FLAG_trace_fragmentation_verbose) { | |
| 3756 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), | |
| 3757 SlotsBuffer::SizeOfChain(p->slots_buffer())); | |
| 3758 } | |
| 3759 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); | |
| 3760 | |
| 3761 // Important: skip list should be cleared only after roots were updated | 3636 // Important: skip list should be cleared only after roots were updated |
| 3762 // because root iteration traverses the stack and might have to find | 3637 // because root iteration traverses the stack and might have to find |
| 3763 // code objects from non-updated pc pointing into evacuation candidate. | 3638 // code objects from non-updated pc pointing into evacuation candidate. |
| 3764 SkipList* list = p->skip_list(); | 3639 SkipList* list = p->skip_list(); |
| 3765 if (list != NULL) list->Clear(); | 3640 if (list != NULL) list->Clear(); |
| 3766 | 3641 |
| 3767 // First pass on aborted pages, fixing up all live objects. | 3642 // First pass on aborted pages, fixing up all live objects. |
| 3768 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { | 3643 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { |
| 3769 p->ClearEvacuationCandidate(); | 3644 p->ClearEvacuationCandidate(); |
| 3770 VisitLiveObjectsBody(p, &updating_visitor); | 3645 VisitLiveObjectsBody(p, &updating_visitor); |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4012 | 3887 |
| 4013 | 3888 |
| 4014 Isolate* MarkCompactCollector::isolate() const { return heap_->isolate(); } | 3889 Isolate* MarkCompactCollector::isolate() const { return heap_->isolate(); } |
| 4015 | 3890 |
| 4016 | 3891 |
| 4017 void MarkCompactCollector::Initialize() { | 3892 void MarkCompactCollector::Initialize() { |
| 4018 MarkCompactMarkingVisitor::Initialize(); | 3893 MarkCompactMarkingVisitor::Initialize(); |
| 4019 IncrementalMarking::Initialize(); | 3894 IncrementalMarking::Initialize(); |
| 4020 } | 3895 } |
| 4021 | 3896 |
| 4022 | 3897 void MarkCompactCollector::RecordCodeEntrySlot(HeapObject* host, Address slot, |
| 4023 void MarkCompactCollector::EvictPopularEvacuationCandidate(Page* page) { | |
| 4024 if (FLAG_trace_fragmentation) { | |
| 4025 PrintF("Page %p is too popular. Disabling evacuation.\n", | |
| 4026 reinterpret_cast<void*>(page)); | |
| 4027 } | |
| 4028 | |
| 4029 isolate()->CountUsage(v8::Isolate::UseCounterFeature::kSlotsBufferOverflow); | |
| 4030 | |
| 4031 // TODO(gc) If all evacuation candidates are too popular we | |
| 4032 // should stop slots recording entirely. | |
| 4033 page->ClearEvacuationCandidate(); | |
| 4034 | |
| 4035 DCHECK(!page->IsFlagSet(Page::POPULAR_PAGE)); | |
| 4036 page->SetFlag(Page::POPULAR_PAGE); | |
| 4037 | |
| 4038 // We were not collecting slots on this page that point | |
| 4039 // to other evacuation candidates thus we have to | |
| 4040 // rescan the page after evacuation to discover and update all | |
| 4041 // pointers to evacuated objects. | |
| 4042 page->SetFlag(Page::RESCAN_ON_EVACUATION); | |
| 4043 } | |
| 4044 | |
| 4045 | |
| 4046 void MarkCompactCollector::RecordCodeEntrySlot(HeapObject* object, Address slot, | |
| 4047 Code* target) { | 3898 Code* target) { |
| 4048 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); | 3899 Page* target_page = Page::FromAddress(reinterpret_cast<Address>(target)); |
| 3900 Page* source_page = Page::FromAddress(reinterpret_cast<Address>(host)); |
| 4049 if (target_page->IsEvacuationCandidate() && | 3901 if (target_page->IsEvacuationCandidate() && |
| 4050 !ShouldSkipEvacuationSlotRecording(object)) { | 3902 !ShouldSkipEvacuationSlotRecording(host)) { |
| 4051 if (!SlotsBuffer::AddTo(slots_buffer_allocator_, | 3903 RememberedSet<OLD_TO_OLD>::InsertTyped(source_page, CODE_ENTRY_SLOT, slot); |
| 4052 target_page->slots_buffer_address(), | |
| 4053 SlotsBuffer::CODE_ENTRY_SLOT, slot, | |
| 4054 SlotsBuffer::FAIL_ON_OVERFLOW)) { | |
| 4055 EvictPopularEvacuationCandidate(target_page); | |
| 4056 } | |
| 4057 } | 3904 } |
| 4058 } | 3905 } |
| 4059 | 3906 |
| 4060 | 3907 |
| 4061 void MarkCompactCollector::RecordCodeTargetPatch(Address pc, Code* target) { | 3908 void MarkCompactCollector::RecordCodeTargetPatch(Address pc, Code* target) { |
| 4062 DCHECK(heap()->gc_state() == Heap::MARK_COMPACT); | 3909 DCHECK(heap()->gc_state() == Heap::MARK_COMPACT); |
| 4063 if (is_compacting()) { | 3910 if (is_compacting()) { |
| 4064 Code* host = | 3911 Code* host = |
| 4065 isolate()->inner_pointer_to_code_cache()->GcSafeFindCodeForInnerPointer( | 3912 isolate()->inner_pointer_to_code_cache()->GcSafeFindCodeForInnerPointer( |
| 4066 pc); | 3913 pc); |
| 4067 MarkBit mark_bit = Marking::MarkBitFrom(host); | 3914 MarkBit mark_bit = Marking::MarkBitFrom(host); |
| 4068 if (Marking::IsBlack(mark_bit)) { | 3915 if (Marking::IsBlack(mark_bit)) { |
| 4069 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); | 3916 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); |
| 4070 RecordRelocSlot(&rinfo, target); | 3917 RecordRelocSlot(host, &rinfo, target); |
| 4071 } | 3918 } |
| 4072 } | 3919 } |
| 4073 } | 3920 } |
| 4074 | 3921 |
| 4075 } // namespace internal | 3922 } // namespace internal |
| 4076 } // namespace v8 | 3923 } // namespace v8 |
| OLD | NEW |