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 #ifndef V8_HEAP_MARK_COMPACT_H_ | 5 #ifndef V8_HEAP_MARK_COMPACT_H_ |
6 #define V8_HEAP_MARK_COMPACT_H_ | 6 #define V8_HEAP_MARK_COMPACT_H_ |
7 | 7 |
8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
9 #include "src/heap/spaces.h" | 9 #include "src/heap/spaces.h" |
10 #include "src/heap/store-buffer.h" | 10 #include "src/heap/store-buffer.h" |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 Address cell_base_; | 393 Address cell_base_; |
394 MarkBit::CellType current_cell_; | 394 MarkBit::CellType current_cell_; |
395 }; | 395 }; |
396 | 396 |
397 // ------------------------------------------------------------------------- | 397 // ------------------------------------------------------------------------- |
398 // Mark-Compact collector | 398 // Mark-Compact collector |
399 class MarkCompactCollector { | 399 class MarkCompactCollector { |
400 public: | 400 public: |
401 class Evacuator; | 401 class Evacuator; |
402 | 402 |
| 403 class Sweeper { |
| 404 public: |
| 405 class SweeperTask; |
| 406 |
| 407 enum SweepingMode { SWEEP_ONLY, SWEEP_AND_VISIT_LIVE_OBJECTS }; |
| 408 enum SkipListRebuildingMode { REBUILD_SKIP_LIST, IGNORE_SKIP_LIST }; |
| 409 enum FreeSpaceTreatmentMode { IGNORE_FREE_SPACE, ZAP_FREE_SPACE }; |
| 410 enum SweepingParallelism { SWEEP_ON_MAIN_THREAD, SWEEP_IN_PARALLEL }; |
| 411 |
| 412 typedef std::vector<Page*> SweepingList; |
| 413 typedef List<Page*> SweptList; |
| 414 |
| 415 enum SweepingSpace { |
| 416 kOldSpace, |
| 417 kCodeSpace, |
| 418 kMapSpace, |
| 419 kNumberOfSweepingSpaces, |
| 420 }; |
| 421 |
| 422 template <SweepingMode sweeping_mode, SweepingParallelism parallelism, |
| 423 SkipListRebuildingMode skip_list_mode, |
| 424 FreeSpaceTreatmentMode free_space_mode> |
| 425 static int UnmanagedSweep(PagedSpace* space, Page* p, ObjectVisitor* v); |
| 426 |
| 427 explicit Sweeper(Heap* heap) |
| 428 : heap_(heap), |
| 429 pending_sweeper_tasks_semaphore_(0), |
| 430 sweeping_in_progress_(false) {} |
| 431 |
| 432 bool sweeping_in_progress() { return sweeping_in_progress_; } |
| 433 |
| 434 void AddPage(PagedSpace* space, Page* page); |
| 435 void AddLatePage(SweepingSpace space, Page* page); |
| 436 void CommitLateList(SweepingSpace space); |
| 437 |
| 438 int HelpSweepInParallel(Page* page, PagedSpace* space); |
| 439 int HelpSweepInParallel(PagedSpace* space, int required_freed_bytes, |
| 440 int max_pages = 0); |
| 441 |
| 442 void StartSweeping(); |
| 443 void SweepOrWaitUntilSweepingCompleted(Page* page); |
| 444 void EnsureCompleted(); |
| 445 bool IsSweepingCompleted(); |
| 446 void ParallelSweepSpacesComplete(); |
| 447 |
| 448 void AddSweptPageSafe(PagedSpace* space, Page* page); |
| 449 Page* GetSweptPage(PagedSpace* space); |
| 450 |
| 451 private: |
| 452 AllocationSpace allocation_space(SweepingSpace space) { |
| 453 switch (space) { |
| 454 case kOldSpace: |
| 455 return OLD_SPACE; |
| 456 case kCodeSpace: |
| 457 return CODE_SPACE; |
| 458 case kMapSpace: |
| 459 return MAP_SPACE; |
| 460 default: |
| 461 UNREACHABLE(); |
| 462 } |
| 463 UNREACHABLE(); |
| 464 return OLD_SPACE; |
| 465 } |
| 466 |
| 467 SweepingSpace sweeping_space(AllocationSpace space) { |
| 468 switch (space) { |
| 469 case OLD_SPACE: |
| 470 return kOldSpace; |
| 471 case CODE_SPACE: |
| 472 return kCodeSpace; |
| 473 case MAP_SPACE: |
| 474 return kMapSpace; |
| 475 default: |
| 476 UNREACHABLE(); |
| 477 } |
| 478 UNREACHABLE(); |
| 479 return kOldSpace; |
| 480 } |
| 481 |
| 482 void PrepareAddPage(SweepingSpace space, Page* page); |
| 483 |
| 484 Heap* heap_; |
| 485 base::Mutex mutex_; |
| 486 base::Semaphore pending_sweeper_tasks_semaphore_; |
| 487 SweptList swept_list_[kNumberOfSweepingSpaces]; |
| 488 SweepingList sweeping_list_[kNumberOfSweepingSpaces]; |
| 489 SweepingList* late_sweeping_list_[kNumberOfSweepingSpaces]; |
| 490 SweepingList* tmp_late_sweeping_list_[kNumberOfSweepingSpaces]; |
| 491 bool sweeping_in_progress_; |
| 492 |
| 493 friend class SweeperTask; |
| 494 }; |
| 495 |
403 enum IterationMode { | 496 enum IterationMode { |
404 kKeepMarking, | 497 kKeepMarking, |
405 kClearMarkbits, | 498 kClearMarkbits, |
406 }; | 499 }; |
407 | 500 |
408 static void Initialize(); | 501 static void Initialize(); |
409 | 502 |
410 void SetUp(); | 503 void SetUp(); |
411 | 504 |
412 void TearDown(); | 505 void TearDown(); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 void UpdateSlotsRecordedIn(SlotsBuffer* buffer); | 576 void UpdateSlotsRecordedIn(SlotsBuffer* buffer); |
484 | 577 |
485 void InvalidateCode(Code* code); | 578 void InvalidateCode(Code* code); |
486 | 579 |
487 void ClearMarkbits(); | 580 void ClearMarkbits(); |
488 | 581 |
489 bool is_compacting() const { return compacting_; } | 582 bool is_compacting() const { return compacting_; } |
490 | 583 |
491 MarkingParity marking_parity() { return marking_parity_; } | 584 MarkingParity marking_parity() { return marking_parity_; } |
492 | 585 |
493 // Concurrent and parallel sweeping support. If required_freed_bytes was set | |
494 // to a value larger than 0, then sweeping returns after a block of at least | |
495 // required_freed_bytes was freed. If required_freed_bytes was set to zero | |
496 // then the whole given space is swept. It returns the size of the maximum | |
497 // continuous freed memory chunk. | |
498 int SweepInParallel(PagedSpace* space, int required_freed_bytes, | |
499 int max_pages = 0); | |
500 | |
501 // Sweeps a given page concurrently to the sweeper threads. It returns the | |
502 // size of the maximum continuous freed memory chunk. | |
503 int SweepInParallel(Page* page, PagedSpace* space); | |
504 | |
505 // Ensures that sweeping is finished. | 586 // Ensures that sweeping is finished. |
506 // | 587 // |
507 // Note: Can only be called safely from main thread. | 588 // Note: Can only be called safely from main thread. |
508 void EnsureSweepingCompleted(); | 589 void EnsureSweepingCompleted(); |
509 | 590 |
510 void SweepOrWaitUntilSweepingCompleted(Page* page); | |
511 | |
512 // Help out in sweeping the corresponding space and refill memory that has | 591 // Help out in sweeping the corresponding space and refill memory that has |
513 // been regained. | 592 // been regained. |
514 // | 593 // |
515 // Note: Thread-safe. | 594 // Note: Thread-safe. |
516 void SweepAndRefill(CompactionSpace* space); | 595 void SweepAndRefill(CompactionSpace* space); |
517 | 596 |
518 // If sweeper threads are not active this method will return true. If | |
519 // this is a latency issue we should be smarter here. Otherwise, it will | |
520 // return true if the sweeper threads are done processing the pages. | |
521 bool IsSweepingCompleted(); | |
522 | |
523 // Checks if sweeping is in progress right now on any space. | 597 // Checks if sweeping is in progress right now on any space. |
524 bool sweeping_in_progress() { return sweeping_in_progress_; } | 598 bool sweeping_in_progress() { return sweeper().sweeping_in_progress(); } |
525 | 599 |
526 void set_evacuation(bool evacuation) { evacuation_ = evacuation; } | 600 void set_evacuation(bool evacuation) { evacuation_ = evacuation; } |
527 | 601 |
528 bool evacuation() const { return evacuation_; } | 602 bool evacuation() const { return evacuation_; } |
529 | 603 |
530 // Special case for processing weak references in a full collection. We need | 604 // Special case for processing weak references in a full collection. We need |
531 // to artificially keep AllocationSites alive for a time. | 605 // to artificially keep AllocationSites alive for a time. |
532 void MarkAllocationSite(AllocationSite* site); | 606 void MarkAllocationSite(AllocationSite* site); |
533 | 607 |
534 // Mark objects in implicit references groups if their parent object | 608 // Mark objects in implicit references groups if their parent object |
(...skipping 20 matching lines...) Expand all Loading... |
555 // The following two methods can just be called after marking, when the | 629 // The following two methods can just be called after marking, when the |
556 // whole transitive closure is known. They must be called before sweeping | 630 // whole transitive closure is known. They must be called before sweeping |
557 // when mark bits are still intact. | 631 // when mark bits are still intact. |
558 bool IsSlotInBlackObject(MemoryChunk* p, Address slot); | 632 bool IsSlotInBlackObject(MemoryChunk* p, Address slot); |
559 HeapObject* FindBlackObjectBySlotSlow(Address slot); | 633 HeapObject* FindBlackObjectBySlotSlow(Address slot); |
560 | 634 |
561 // Removes all the slots in the slot buffers that are within the given | 635 // Removes all the slots in the slot buffers that are within the given |
562 // address range. | 636 // address range. |
563 void RemoveObjectSlots(Address start_slot, Address end_slot); | 637 void RemoveObjectSlots(Address start_slot, Address end_slot); |
564 | 638 |
565 base::Mutex* swept_pages_mutex() { return &swept_pages_mutex_; } | 639 Sweeper& sweeper() { return sweeper_; } |
566 List<Page*>* swept_pages(AllocationSpace id) { | |
567 switch (id) { | |
568 case OLD_SPACE: | |
569 return &swept_old_space_pages_; | |
570 case CODE_SPACE: | |
571 return &swept_code_space_pages_; | |
572 case MAP_SPACE: | |
573 return &swept_map_space_pages_; | |
574 default: | |
575 UNREACHABLE(); | |
576 } | |
577 return nullptr; | |
578 } | |
579 | 640 |
580 private: | 641 private: |
581 class EvacuateNewSpaceVisitor; | 642 class EvacuateNewSpaceVisitor; |
582 class EvacuateOldSpaceVisitor; | 643 class EvacuateOldSpaceVisitor; |
583 class EvacuateVisitorBase; | 644 class EvacuateVisitorBase; |
584 class HeapObjectVisitor; | 645 class HeapObjectVisitor; |
585 class SweeperTask; | |
586 | 646 |
587 typedef std::vector<Page*> SweepingList; | 647 typedef std::vector<Page*> SweepingList; |
588 | 648 |
589 explicit MarkCompactCollector(Heap* heap); | 649 explicit MarkCompactCollector(Heap* heap); |
590 | 650 |
591 bool WillBeDeoptimized(Code* code); | 651 bool WillBeDeoptimized(Code* code); |
592 void ClearInvalidRememberedSetSlots(); | 652 void ClearInvalidRememberedSetSlots(); |
593 | 653 |
594 void StartSweeperThreads(); | |
595 | |
596 void ComputeEvacuationHeuristics(int area_size, | 654 void ComputeEvacuationHeuristics(int area_size, |
597 int* target_fragmentation_percent, | 655 int* target_fragmentation_percent, |
598 int* max_evacuated_bytes); | 656 int* max_evacuated_bytes); |
599 | 657 |
600 #ifdef DEBUG | 658 #ifdef DEBUG |
601 enum CollectorState { | 659 enum CollectorState { |
602 IDLE, | 660 IDLE, |
603 PREPARE_GC, | 661 PREPARE_GC, |
604 MARK_LIVE_OBJECTS, | 662 MARK_LIVE_OBJECTS, |
605 SWEEP_SPACES, | 663 SWEEP_SPACES, |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 // Phase 2: Sweeping to clear mark bits and free non-live objects for | 812 // Phase 2: Sweeping to clear mark bits and free non-live objects for |
755 // a non-compacting collection. | 813 // a non-compacting collection. |
756 // | 814 // |
757 // Before: Live objects are marked and non-live objects are unmarked. | 815 // Before: Live objects are marked and non-live objects are unmarked. |
758 // | 816 // |
759 // After: Live objects are unmarked, non-live regions have been added to | 817 // After: Live objects are unmarked, non-live regions have been added to |
760 // their space's free list. Active eden semispace is compacted by | 818 // their space's free list. Active eden semispace is compacted by |
761 // evacuation. | 819 // evacuation. |
762 // | 820 // |
763 | 821 |
764 inline SweepingList& sweeping_list(Space* space); | |
765 | |
766 // If we are not compacting the heap, we simply sweep the spaces except | 822 // If we are not compacting the heap, we simply sweep the spaces except |
767 // for the large object space, clearing mark bits and adding unmarked | 823 // for the large object space, clearing mark bits and adding unmarked |
768 // regions to each space's free list. | 824 // regions to each space's free list. |
769 void SweepSpaces(); | 825 void SweepSpaces(); |
770 | 826 |
771 void EvacuateNewSpacePrologue(); | 827 void EvacuateNewSpacePrologue(); |
772 void EvacuateNewSpaceEpilogue(); | 828 void EvacuateNewSpaceEpilogue(); |
773 | 829 |
774 void EvacuatePagesInParallel(); | 830 void EvacuatePagesInParallel(); |
775 | 831 |
(...skipping 14 matching lines...) Expand all Loading... |
790 void RecomputeLiveBytes(MemoryChunk* page); | 846 void RecomputeLiveBytes(MemoryChunk* page); |
791 | 847 |
792 void SweepAbortedPages(); | 848 void SweepAbortedPages(); |
793 | 849 |
794 void ReleaseEvacuationCandidates(); | 850 void ReleaseEvacuationCandidates(); |
795 | 851 |
796 // Starts sweeping of a space by contributing on the main thread and setting | 852 // Starts sweeping of a space by contributing on the main thread and setting |
797 // up other pages for sweeping. | 853 // up other pages for sweeping. |
798 void StartSweepSpace(PagedSpace* space); | 854 void StartSweepSpace(PagedSpace* space); |
799 | 855 |
800 // Finalizes the parallel sweeping phase. Marks all the pages that were | |
801 // swept in parallel. | |
802 void ParallelSweepSpacesComplete(); | |
803 | |
804 #ifdef DEBUG | 856 #ifdef DEBUG |
805 friend class MarkObjectVisitor; | 857 friend class MarkObjectVisitor; |
806 static void VisitObject(HeapObject* obj); | 858 static void VisitObject(HeapObject* obj); |
807 | 859 |
808 friend class UnmarkObjectVisitor; | 860 friend class UnmarkObjectVisitor; |
809 static void UnmarkObject(HeapObject* obj); | 861 static void UnmarkObject(HeapObject* obj); |
810 #endif | 862 #endif |
811 | 863 |
812 Heap* heap_; | 864 Heap* heap_; |
813 base::VirtualMemory* marking_deque_memory_; | 865 base::VirtualMemory* marking_deque_memory_; |
814 size_t marking_deque_memory_committed_; | 866 size_t marking_deque_memory_committed_; |
815 MarkingDeque marking_deque_; | 867 MarkingDeque marking_deque_; |
816 CodeFlusher* code_flusher_; | 868 CodeFlusher* code_flusher_; |
817 bool have_code_to_deoptimize_; | 869 bool have_code_to_deoptimize_; |
818 | 870 |
819 List<Page*> evacuation_candidates_; | 871 List<Page*> evacuation_candidates_; |
820 List<NewSpacePage*> newspace_evacuation_candidates_; | 872 List<NewSpacePage*> newspace_evacuation_candidates_; |
821 | 873 |
822 base::Mutex swept_pages_mutex_; | |
823 List<Page*> swept_old_space_pages_; | |
824 List<Page*> swept_code_space_pages_; | |
825 List<Page*> swept_map_space_pages_; | |
826 | |
827 SweepingList sweeping_list_old_space_; | |
828 SweepingList sweeping_list_code_space_; | |
829 SweepingList sweeping_list_map_space_; | |
830 | |
831 // True if we are collecting slots to perform evacuation from evacuation | 874 // True if we are collecting slots to perform evacuation from evacuation |
832 // candidates. | 875 // candidates. |
833 bool compacting_; | 876 bool compacting_; |
834 | 877 |
835 // True if concurrent or parallel sweeping is currently in progress. | |
836 bool sweeping_in_progress_; | |
837 | |
838 // Semaphore used to synchronize sweeper tasks. | |
839 base::Semaphore pending_sweeper_tasks_semaphore_; | |
840 | |
841 // Semaphore used to synchronize compaction tasks. | 878 // Semaphore used to synchronize compaction tasks. |
842 base::Semaphore pending_compaction_tasks_semaphore_; | 879 base::Semaphore pending_compaction_tasks_semaphore_; |
843 | 880 |
844 bool black_allocation_; | 881 bool black_allocation_; |
845 | 882 |
| 883 Sweeper sweeper_; |
| 884 |
846 friend class Heap; | 885 friend class Heap; |
847 friend class StoreBuffer; | 886 friend class StoreBuffer; |
848 }; | 887 }; |
849 | 888 |
850 | 889 |
851 class EvacuationScope BASE_EMBEDDED { | 890 class EvacuationScope BASE_EMBEDDED { |
852 public: | 891 public: |
853 explicit EvacuationScope(MarkCompactCollector* collector) | 892 explicit EvacuationScope(MarkCompactCollector* collector) |
854 : collector_(collector) { | 893 : collector_(collector) { |
855 collector_->set_evacuation(true); | 894 collector_->set_evacuation(true); |
856 } | 895 } |
857 | 896 |
858 ~EvacuationScope() { collector_->set_evacuation(false); } | 897 ~EvacuationScope() { collector_->set_evacuation(false); } |
859 | 898 |
860 private: | 899 private: |
861 MarkCompactCollector* collector_; | 900 MarkCompactCollector* collector_; |
862 }; | 901 }; |
863 | 902 |
864 | 903 |
865 const char* AllocationSpaceName(AllocationSpace space); | 904 const char* AllocationSpaceName(AllocationSpace space); |
866 } // namespace internal | 905 } // namespace internal |
867 } // namespace v8 | 906 } // namespace v8 |
868 | 907 |
869 #endif // V8_HEAP_MARK_COMPACT_H_ | 908 #endif // V8_HEAP_MARK_COMPACT_H_ |
OLD | NEW |