Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 527 | 527 |
| 528 void LargeObject::markUnmarkedObjectsDead() | 528 void LargeObject::markUnmarkedObjectsDead() |
| 529 { | 529 { |
| 530 HeapObjectHeader* header = heapObjectHeader(); | 530 HeapObjectHeader* header = heapObjectHeader(); |
| 531 if (header->isMarked()) | 531 if (header->isMarked()) |
| 532 header->unmark(); | 532 header->unmark(); |
| 533 else | 533 else |
| 534 header->markDead(); | 534 header->markDead(); |
| 535 } | 535 } |
| 536 | 536 |
| 537 void LargeObject::removeFromHeap(ThreadHeap* heap) | 537 void LargeObject::removeFromHeap() |
| 538 { | 538 { |
| 539 heap->freeLargeObject(this); | 539 static_cast<ThreadHeapForLargeObject*>(heap())->freeLargeObject(this); |
| 540 } | |
| 541 | |
| 542 ThreadHeap::ThreadHeap(ThreadState* state, int index) | |
| 543 : m_currentAllocationPoint(nullptr) | |
| 544 , m_remainingAllocationSize(0) | |
| 545 , m_lastRemainingAllocationSize(0) | |
| 546 , m_firstPage(nullptr) | |
| 547 , m_firstLargeObject(nullptr) | |
| 548 , m_firstUnsweptPage(nullptr) | |
| 549 , m_firstUnsweptLargeObject(nullptr) | |
| 550 , m_threadState(state) | |
| 551 , m_index(index) | |
| 552 , m_promptlyFreedSize(0) | |
| 553 { | |
| 554 clearFreeLists(); | |
| 555 } | 540 } |
| 556 | 541 |
| 557 FreeList::FreeList() | 542 FreeList::FreeList() |
| 558 : m_biggestFreeListIndex(0) | 543 : m_biggestFreeListIndex(0) |
| 559 { | 544 { |
| 560 } | 545 } |
| 561 | 546 |
| 547 ThreadHeap::ThreadHeap(ThreadState* state, int index) | |
| 548 : m_firstPage(nullptr) | |
| 549 , m_firstUnsweptPage(nullptr) | |
| 550 , m_threadState(state) | |
| 551 , m_index(index) | |
| 552 { | |
| 553 clearFreeLists(); | |
| 554 } | |
| 555 | |
| 556 ThreadHeapForHeapPage::ThreadHeapForHeapPage(ThreadState* state, int index) | |
| 557 : ThreadHeap(state, index) | |
| 558 , m_currentAllocationPoint(nullptr) | |
| 559 , m_remainingAllocationSize(0) | |
| 560 , m_lastRemainingAllocationSize(0) | |
| 561 , m_promptlyFreedSize(0) | |
| 562 { | |
| 563 } | |
| 564 | |
| 565 ThreadHeapForLargeObject::ThreadHeapForLargeObject(ThreadState* state, int index ) | |
| 566 : ThreadHeap(state, index) | |
| 567 { | |
| 568 } | |
| 569 | |
| 562 ThreadHeap::~ThreadHeap() | 570 ThreadHeap::~ThreadHeap() |
| 563 { | 571 { |
| 564 ASSERT(!m_firstPage); | 572 ASSERT(!m_firstPage); |
| 565 ASSERT(!m_firstLargeObject); | |
| 566 ASSERT(!m_firstUnsweptPage); | 573 ASSERT(!m_firstUnsweptPage); |
| 567 ASSERT(!m_firstUnsweptLargeObject); | |
| 568 } | 574 } |
| 569 | 575 |
| 570 void ThreadHeap::cleanupPages() | 576 void ThreadHeap::cleanupPages() |
| 571 { | 577 { |
| 572 clearFreeLists(); | 578 clearFreeLists(); |
| 573 | 579 |
| 574 ASSERT(!m_firstUnsweptPage); | 580 ASSERT(!m_firstUnsweptPage); |
| 575 ASSERT(!m_firstUnsweptLargeObject); | |
| 576 // Add the ThreadHeap's pages to the orphanedPagePool. | 581 // Add the ThreadHeap's pages to the orphanedPagePool. |
| 577 for (HeapPage* page = m_firstPage; page; page = page->m_next) { | 582 for (BaseHeapPage* page = m_firstPage; page; page = page->next()) { |
| 578 Heap::decreaseAllocatedSpace(blinkPageSize); | 583 Heap::decreaseAllocatedSpace(blinkPageSize); |
| 579 Heap::orphanedPagePool()->addOrphanedPage(m_index, page); | 584 Heap::orphanedPagePool()->addOrphanedPage(heapIndex(), page); |
| 580 } | 585 } |
| 581 m_firstPage = nullptr; | 586 m_firstPage = nullptr; |
| 582 | |
| 583 for (LargeObject* largeObject = m_firstLargeObject; largeObject; largeObject = largeObject->m_next) { | |
| 584 Heap::decreaseAllocatedSpace(largeObject->size()); | |
| 585 Heap::orphanedPagePool()->addOrphanedPage(m_index, largeObject); | |
| 586 } | |
| 587 m_firstLargeObject = nullptr; | |
| 588 } | 587 } |
| 589 | 588 |
| 590 void ThreadHeap::updateRemainingAllocationSize() | 589 void ThreadHeapForHeapPage::updateRemainingAllocationSize() |
| 591 { | 590 { |
| 592 if (m_lastRemainingAllocationSize > remainingAllocationSize()) { | 591 if (m_lastRemainingAllocationSize > remainingAllocationSize()) { |
| 593 Heap::increaseAllocatedObjectSize(m_lastRemainingAllocationSize - remain ingAllocationSize()); | 592 Heap::increaseAllocatedObjectSize(m_lastRemainingAllocationSize - remain ingAllocationSize()); |
| 594 m_lastRemainingAllocationSize = remainingAllocationSize(); | 593 m_lastRemainingAllocationSize = remainingAllocationSize(); |
| 595 } | 594 } |
| 596 ASSERT(m_lastRemainingAllocationSize == remainingAllocationSize()); | 595 ASSERT(m_lastRemainingAllocationSize == remainingAllocationSize()); |
| 597 } | 596 } |
| 598 | 597 |
| 599 void ThreadHeap::setAllocationPoint(Address point, size_t size) | 598 void ThreadHeapForHeapPage::setAllocationPoint(Address point, size_t size) |
| 600 { | 599 { |
| 601 #if ENABLE(ASSERT) | 600 #if ENABLE(ASSERT) |
| 602 if (point) { | 601 if (point) { |
| 603 ASSERT(size); | 602 ASSERT(size); |
| 604 BaseHeapPage* page = pageFromObject(point); | 603 BaseHeapPage* page = pageFromObject(point); |
| 605 ASSERT(!page->isLargeObject()); | 604 ASSERT(!page->isLargeObject()); |
| 606 ASSERT(size <= static_cast<HeapPage*>(page)->payloadSize()); | 605 ASSERT(size <= static_cast<HeapPage*>(page)->payloadSize()); |
| 607 } | 606 } |
| 608 #endif | 607 #endif |
| 609 if (hasCurrentAllocationArea()) | 608 if (hasCurrentAllocationArea()) { |
| 610 addToFreeList(currentAllocationPoint(), remainingAllocationSize()); | 609 addToFreeList(currentAllocationPoint(), remainingAllocationSize()); |
| 610 } | |
| 611 updateRemainingAllocationSize(); | 611 updateRemainingAllocationSize(); |
| 612 m_currentAllocationPoint = point; | 612 m_currentAllocationPoint = point; |
| 613 m_lastRemainingAllocationSize = m_remainingAllocationSize = size; | 613 m_lastRemainingAllocationSize = m_remainingAllocationSize = size; |
| 614 } | 614 } |
| 615 | 615 |
| 616 Address ThreadHeap::outOfLineAllocate(size_t allocationSize, size_t gcInfoIndex) | 616 Address ThreadHeapForHeapPage::outOfLineAllocate(size_t allocationSize, size_t g cInfoIndex) |
| 617 { | 617 { |
| 618 ASSERT(allocationSize > remainingAllocationSize()); | 618 ASSERT(allocationSize > remainingAllocationSize()); |
| 619 ASSERT(allocationSize >= allocationGranularity); | 619 ASSERT(allocationSize >= allocationGranularity); |
| 620 | 620 |
| 621 // 1. If this allocation is big enough, allocate a large object. | 621 // 1. If this allocation is big enough, allocate a large object. |
| 622 if (allocationSize >= largeObjectSizeThreshold) | 622 if (allocationSize >= largeObjectSizeThreshold) |
| 623 return allocateLargeObject(allocationSize, gcInfoIndex); | 623 return static_cast<ThreadHeapForLargeObject*>(threadState()->heap(LargeO bjectHeap))->allocateLargeObject(allocationSize, gcInfoIndex); |
| 624 | 624 |
| 625 // 2. Check if we should trigger a GC. | 625 // 2. Check if we should trigger a GC. |
| 626 updateRemainingAllocationSize(); | 626 updateRemainingAllocationSize(); |
| 627 threadState()->scheduleGCOrForceConservativeGCIfNeeded(); | 627 threadState()->scheduleGCOrForceConservativeGCIfNeeded(); |
| 628 | 628 |
| 629 // 3. Try to allocate from a free list. | 629 // 3. Try to allocate from a free list. |
| 630 Address result = allocateFromFreeList(allocationSize, gcInfoIndex); | 630 Address result = allocateFromFreeList(allocationSize, gcInfoIndex); |
| 631 if (result) | 631 if (result) |
| 632 return result; | 632 return result; |
| 633 | 633 |
| 634 // 4. Reset the allocation point. | 634 // 4. Reset the allocation point. |
| 635 setAllocationPoint(nullptr, 0); | 635 setAllocationPoint(nullptr, 0); |
| 636 | 636 |
| 637 // 5. Lazily sweep pages of this heap until we find a freed area for | 637 // 5. Lazily sweep pages of this heap until we find a freed area for |
| 638 // this allocation or we finish sweeping all pages of this heap. | 638 // this allocation or we finish sweeping all pages of this heap. |
| 639 result = lazySweepPages(allocationSize, gcInfoIndex); | 639 result = lazySweep(allocationSize, gcInfoIndex); |
| 640 if (result) | 640 if (result) |
| 641 return result; | 641 return result; |
| 642 | 642 |
| 643 // 6. Coalesce promptly freed areas and then try to allocate from a free | 643 // 6. Coalesce promptly freed areas and then try to allocate from a free |
| 644 // list. | 644 // list. |
| 645 if (coalesce()) { | 645 if (coalesce()) { |
| 646 result = allocateFromFreeList(allocationSize, gcInfoIndex); | 646 result = allocateFromFreeList(allocationSize, gcInfoIndex); |
| 647 if (result) | 647 if (result) |
| 648 return result; | 648 return result; |
| 649 } | 649 } |
| 650 | 650 |
| 651 // 7. Complete sweeping. | 651 // 7. Complete sweeping. |
| 652 threadState()->completeSweep(); | 652 threadState()->completeSweep(); |
| 653 | 653 |
| 654 // 8. Add a new page to this heap. | 654 // 8. Add a new page to this heap. |
| 655 allocatePage(); | 655 allocatePage(); |
| 656 | 656 |
| 657 // 9. Try to allocate from a free list. This allocation must succeed. | 657 // 9. Try to allocate from a free list. This allocation must succeed. |
| 658 result = allocateFromFreeList(allocationSize, gcInfoIndex); | 658 result = allocateFromFreeList(allocationSize, gcInfoIndex); |
| 659 RELEASE_ASSERT(result); | 659 RELEASE_ASSERT(result); |
| 660 return result; | 660 return result; |
| 661 } | 661 } |
| 662 | 662 |
| 663 Address ThreadHeap::allocateFromFreeList(size_t allocationSize, size_t gcInfoInd ex) | 663 Address ThreadHeapForHeapPage::allocateFromFreeList(size_t allocationSize, size_ t gcInfoIndex) |
| 664 { | 664 { |
| 665 // Try reusing a block from the largest bin. The underlying reasoning | 665 // Try reusing a block from the largest bin. The underlying reasoning |
| 666 // being that we want to amortize this slow allocation call by carving | 666 // being that we want to amortize this slow allocation call by carving |
| 667 // off as a large a free block as possible in one go; a block that will | 667 // off as a large a free block as possible in one go; a block that will |
| 668 // service this block and let following allocations be serviced quickly | 668 // service this block and let following allocations be serviced quickly |
| 669 // by bump allocation. | 669 // by bump allocation. |
| 670 size_t bucketSize = 1 << m_freeList.m_biggestFreeListIndex; | 670 size_t bucketSize = 1 << m_freeList.m_biggestFreeListIndex; |
| 671 int index = m_freeList.m_biggestFreeListIndex; | 671 int index = m_freeList.m_biggestFreeListIndex; |
| 672 for (; index > 0; --index, bucketSize >>= 1) { | 672 for (; index > 0; --index, bucketSize >>= 1) { |
| 673 FreeListEntry* entry = m_freeList.m_freeLists[index]; | 673 FreeListEntry* entry = m_freeList.m_freeLists[index]; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 688 } | 688 } |
| 689 } | 689 } |
| 690 m_freeList.m_biggestFreeListIndex = index; | 690 m_freeList.m_biggestFreeListIndex = index; |
| 691 return nullptr; | 691 return nullptr; |
| 692 } | 692 } |
| 693 | 693 |
| 694 void ThreadHeap::prepareForSweep() | 694 void ThreadHeap::prepareForSweep() |
| 695 { | 695 { |
| 696 ASSERT(!threadState()->isInGC()); | 696 ASSERT(!threadState()->isInGC()); |
| 697 ASSERT(!m_firstUnsweptPage); | 697 ASSERT(!m_firstUnsweptPage); |
| 698 ASSERT(!m_firstUnsweptLargeObject); | |
| 699 | 698 |
| 700 // Move all pages to a list of unswept pages. | 699 // Move all pages to a list of unswept pages. |
| 701 m_firstUnsweptPage = m_firstPage; | 700 m_firstUnsweptPage = m_firstPage; |
| 702 m_firstUnsweptLargeObject = m_firstLargeObject; | |
| 703 m_firstPage = nullptr; | 701 m_firstPage = nullptr; |
| 704 m_firstLargeObject = nullptr; | |
| 705 } | 702 } |
| 706 | 703 |
| 707 Address ThreadHeap::lazySweepPages(size_t allocationSize, size_t gcInfoIndex) | 704 Address ThreadHeap::lazySweep(size_t allocationSize, size_t gcInfoIndex) |
| 708 { | 705 { |
| 709 ASSERT(!hasCurrentAllocationArea()); | |
| 710 ASSERT(allocationSize < largeObjectSizeThreshold); | |
| 711 | |
| 712 // If there are no pages to be swept, return immediately. | 706 // If there are no pages to be swept, return immediately. |
| 713 if (!m_firstUnsweptPage) | 707 if (!m_firstUnsweptPage) |
| 714 return nullptr; | 708 return nullptr; |
| 715 | 709 |
| 716 RELEASE_ASSERT(threadState()->isSweepingInProgress()); | 710 RELEASE_ASSERT(threadState()->isSweepingInProgress()); |
| 717 | 711 |
| 718 // lazySweepPages() can be called recursively if finalizers invoked in | 712 // lazySweepPages() can be called recursively if finalizers invoked in |
| 719 // page->sweep() allocate memory and the allocation triggers | 713 // page->sweep() allocate memory and the allocation triggers |
| 720 // lazySweepPages(). This check prevents the sweeping from being executed | 714 // lazySweepPages(). This check prevents the sweeping from being executed |
| 721 // recursively. | 715 // recursively. |
| 722 if (threadState()->sweepForbidden()) | 716 if (threadState()->sweepForbidden()) |
| 723 return nullptr; | 717 return nullptr; |
| 724 | 718 |
| 725 TRACE_EVENT0("blink_gc", "ThreadHeap::lazySweepPages"); | 719 TRACE_EVENT0("blink_gc", "ThreadHeap::lazySweepPages"); |
| 726 ThreadState::SweepForbiddenScope scope(m_threadState); | 720 ThreadState::SweepForbiddenScope scope(threadState()); |
| 727 | 721 |
| 728 if (threadState()->isMainThread()) | 722 if (threadState()->isMainThread()) |
| 729 ScriptForbiddenScope::enter(); | 723 ScriptForbiddenScope::enter(); |
| 730 | 724 |
| 725 Address result = lazySweepPages(allocationSize, gcInfoIndex); | |
| 726 | |
| 727 if (threadState()->isMainThread()) | |
| 728 ScriptForbiddenScope::exit(); | |
| 729 return result; | |
| 730 } | |
| 731 | |
| 732 Address ThreadHeapForHeapPage::lazySweepPages(size_t allocationSize, size_t gcIn foIndex) | |
| 733 { | |
| 734 ASSERT(!hasCurrentAllocationArea()); | |
| 731 Address result = nullptr; | 735 Address result = nullptr; |
| 732 while (m_firstUnsweptPage) { | 736 while (m_firstUnsweptPage) { |
| 733 HeapPage* page = m_firstUnsweptPage; | 737 BaseHeapPage* page = m_firstUnsweptPage; |
| 734 if (page->isEmpty()) { | 738 if (page->isEmpty()) { |
| 735 page->unlink(&m_firstUnsweptPage); | 739 page->unlink(&m_firstUnsweptPage); |
| 736 page->removeFromHeap(this); | 740 page->removeFromHeap(); |
| 737 } else { | 741 } else { |
| 738 // Sweep a page and move the page from m_firstUnsweptPages to | 742 // Sweep a page and move the page from m_firstUnsweptPages to |
| 739 // m_firstPages. | 743 // m_firstPages. |
| 740 page->sweep(); | 744 page->sweep(); |
| 741 page->unlink(&m_firstUnsweptPage); | 745 page->unlink(&m_firstUnsweptPage); |
| 742 page->link(&m_firstPage); | 746 page->link(&m_firstPage); |
| 743 page->markAsSwept(); | 747 page->markAsSwept(); |
| 744 | 748 |
| 749 // For HeapPage, stop lazy sweeping once we find a slot to | |
| 750 // allocate a new object. | |
| 745 result = allocateFromFreeList(allocationSize, gcInfoIndex); | 751 result = allocateFromFreeList(allocationSize, gcInfoIndex); |
| 746 if (result) | 752 if (result) { |
| 747 break; | 753 break; |
| 754 } | |
| 748 } | 755 } |
| 749 } | 756 } |
| 750 | |
| 751 if (threadState()->isMainThread()) | |
| 752 ScriptForbiddenScope::exit(); | |
| 753 return result; | 757 return result; |
| 754 } | 758 } |
| 755 | 759 |
| 756 bool ThreadHeap::lazySweepLargeObjects(size_t allocationSize) | 760 Address ThreadHeapForLargeObject::lazySweepPages(size_t allocationSize, size_t g cInfoIndex) |
| 757 { | 761 { |
| 758 ASSERT(allocationSize >= largeObjectSizeThreshold); | 762 Address result = nullptr; |
| 759 | |
| 760 // If there are no large objects to be swept, return immediately. | |
| 761 if (!m_firstUnsweptLargeObject) | |
| 762 return false; | |
| 763 | |
| 764 RELEASE_ASSERT(threadState()->isSweepingInProgress()); | |
| 765 | |
| 766 // lazySweepLargeObjects() can be called recursively if finalizers invoked | |
| 767 // in page->sweep() allocate memory and the allocation triggers | |
| 768 // lazySweepLargeObjects(). This check prevents the sweeping from being | |
| 769 // executed recursively. | |
| 770 if (threadState()->sweepForbidden()) | |
| 771 return false; | |
| 772 | |
| 773 TRACE_EVENT0("blink_gc", "ThreadHeap::lazySweepLargeObjects"); | |
| 774 ThreadState::SweepForbiddenScope scope(m_threadState); | |
| 775 | |
| 776 if (threadState()->isMainThread()) | |
| 777 ScriptForbiddenScope::enter(); | |
| 778 | |
| 779 bool result = false; | |
| 780 size_t sweptSize = 0; | 763 size_t sweptSize = 0; |
| 781 while (m_firstUnsweptLargeObject) { | 764 while (m_firstUnsweptPage) { |
| 782 LargeObject* largeObject = m_firstUnsweptLargeObject; | 765 BaseHeapPage* page = m_firstUnsweptPage; |
| 783 if (largeObject->isEmpty()) { | 766 if (page->isEmpty()) { |
| 784 sweptSize += largeObject->size(); | 767 sweptSize += static_cast<LargeObject*>(page)->payloadSize() + sizeof (HeapObjectHeader); |
| 785 largeObject->unlink(&m_firstUnsweptLargeObject); | 768 page->unlink(&m_firstUnsweptPage); |
| 786 largeObject->removeFromHeap(this); | 769 page->removeFromHeap(); |
| 787 | 770 // For LargeObject, stop lazy sweeping once we have swept |
| 788 // If we have swept large objects more than allocationSize, | 771 // more than allocationSize bytes. |
| 789 // we stop the lazy sweeping. | |
| 790 if (sweptSize >= allocationSize) { | 772 if (sweptSize >= allocationSize) { |
| 791 result = true; | 773 result = doAllocateLargeObject(allocationSize, gcInfoIndex); |
| 774 ASSERT(result); | |
| 792 break; | 775 break; |
| 793 } | 776 } |
| 794 } else { | 777 } else { |
| 795 // Sweep a large object and move the large object from | 778 // Sweep a page and move the page from m_firstUnsweptPages to |
| 796 // m_firstUnsweptLargeObjects to m_firstLargeObjects. | 779 // m_firstPages. |
| 797 largeObject->sweep(); | 780 page->sweep(); |
| 798 largeObject->unlink(&m_firstUnsweptLargeObject); | 781 page->unlink(&m_firstUnsweptPage); |
| 799 largeObject->link(&m_firstLargeObject); | 782 page->link(&m_firstPage); |
| 800 largeObject->markAsSwept(); | 783 page->markAsSwept(); |
| 801 } | 784 } |
| 802 } | 785 } |
| 803 | |
| 804 if (threadState()->isMainThread()) | |
| 805 ScriptForbiddenScope::exit(); | |
| 806 return result; | 786 return result; |
| 807 } | 787 } |
| 808 | 788 |
| 809 void ThreadHeap::completeSweep() | 789 void ThreadHeap::completeSweep() |
| 810 { | 790 { |
| 811 RELEASE_ASSERT(threadState()->isSweepingInProgress()); | 791 RELEASE_ASSERT(threadState()->isSweepingInProgress()); |
| 812 ASSERT(threadState()->sweepForbidden()); | 792 ASSERT(threadState()->sweepForbidden()); |
| 813 | 793 |
| 814 if (threadState()->isMainThread()) | 794 if (threadState()->isMainThread()) |
| 815 ScriptForbiddenScope::enter(); | 795 ScriptForbiddenScope::enter(); |
| 816 | 796 |
| 817 // Sweep normal pages. | |
| 818 while (m_firstUnsweptPage) { | 797 while (m_firstUnsweptPage) { |
| 819 HeapPage* page = m_firstUnsweptPage; | 798 BaseHeapPage* page = m_firstUnsweptPage; |
| 820 if (page->isEmpty()) { | 799 if (page->isEmpty()) { |
| 821 page->unlink(&m_firstUnsweptPage); | 800 page->unlink(&m_firstUnsweptPage); |
| 822 page->removeFromHeap(this); | 801 page->removeFromHeap(); |
| 823 } else { | 802 } else { |
| 824 // Sweep a page and move the page from m_firstUnsweptPages to | 803 // Sweep a page and move the page from m_firstUnsweptPages to |
| 825 // m_firstPages. | 804 // m_firstPages. |
| 826 page->sweep(); | 805 page->sweep(); |
| 827 page->unlink(&m_firstUnsweptPage); | 806 page->unlink(&m_firstUnsweptPage); |
| 828 page->link(&m_firstPage); | 807 page->link(&m_firstPage); |
| 829 page->markAsSwept(); | 808 page->markAsSwept(); |
| 830 } | 809 } |
| 831 } | 810 } |
| 832 | 811 |
| 833 // Sweep large objects. | |
| 834 while (m_firstUnsweptLargeObject) { | |
| 835 LargeObject* largeObject = m_firstUnsweptLargeObject; | |
| 836 if (largeObject->isEmpty()) { | |
| 837 largeObject->unlink(&m_firstUnsweptLargeObject); | |
| 838 largeObject->removeFromHeap(this); | |
| 839 } else { | |
| 840 // Sweep a large object and move the large object from | |
| 841 // m_firstUnsweptLargeObjects to m_firstLargeObjects. | |
| 842 largeObject->sweep(); | |
| 843 largeObject->unlink(&m_firstUnsweptLargeObject); | |
| 844 largeObject->link(&m_firstLargeObject); | |
| 845 largeObject->markAsSwept(); | |
| 846 } | |
| 847 } | |
| 848 | |
| 849 if (threadState()->isMainThread()) | 812 if (threadState()->isMainThread()) |
| 850 ScriptForbiddenScope::exit(); | 813 ScriptForbiddenScope::exit(); |
| 851 } | 814 } |
| 852 | 815 |
| 853 #if ENABLE(ASSERT) | 816 #if ENABLE(ASSERT) |
| 854 static bool isLargeObjectAligned(LargeObject* largeObject, Address address) | |
| 855 { | |
| 856 // Check that a large object is blinkPageSize aligned (modulo the osPageSize | |
| 857 // for the guard page). | |
| 858 return reinterpret_cast<Address>(largeObject) - WTF::kSystemPageSize == roun dToBlinkPageStart(reinterpret_cast<Address>(largeObject)); | |
| 859 } | |
| 860 #endif | |
| 861 | |
| 862 #if ENABLE(ASSERT) || ENABLE(GC_PROFILE_MARKING) | |
| 863 BaseHeapPage* ThreadHeap::findPageFromAddress(Address address) | 817 BaseHeapPage* ThreadHeap::findPageFromAddress(Address address) |
| 864 { | 818 { |
| 865 for (HeapPage* page = m_firstPage; page; page = page->next()) { | 819 for (BaseHeapPage* page = m_firstPage; page; page = page->next()) { |
| 866 if (page->contains(address)) | 820 if (page->contains(address)) |
| 867 return page; | 821 return page; |
| 868 } | 822 } |
| 869 for (HeapPage* page = m_firstUnsweptPage; page; page = page->next()) { | 823 for (BaseHeapPage* page = m_firstUnsweptPage; page; page = page->next()) { |
| 870 if (page->contains(address)) | 824 if (page->contains(address)) |
| 871 return page; | 825 return page; |
| 872 } | 826 } |
| 873 for (LargeObject* largeObject = m_firstLargeObject; largeObject; largeObject = largeObject->next()) { | |
| 874 ASSERT(isLargeObjectAligned(largeObject, address)); | |
| 875 if (largeObject->contains(address)) | |
| 876 return largeObject; | |
| 877 } | |
| 878 for (LargeObject* largeObject = m_firstUnsweptLargeObject; largeObject; larg eObject = largeObject->next()) { | |
| 879 ASSERT(isLargeObjectAligned(largeObject, address)); | |
| 880 if (largeObject->contains(address)) | |
| 881 return largeObject; | |
| 882 } | |
| 883 return nullptr; | 827 return nullptr; |
| 884 } | 828 } |
| 885 #endif | 829 #endif |
| 886 | 830 |
| 887 #if ENABLE(GC_PROFILE_HEAP) | 831 #if ENABLE(GC_PROFILE_HEAP) |
| 888 #define GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD 0 | 832 #define GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD 0 |
| 889 void ThreadHeap::snapshot(TracedValue* json, ThreadState::SnapshotInfo* info) | 833 void ThreadHeap::snapshot(TracedValue* json, ThreadState::SnapshotInfo* info) |
| 890 { | 834 { |
| 891 ASSERT(isConsistentForSweeping()); | 835 ASSERT(isConsistentForSweeping()); |
| 892 size_t previousPageCount = info->pageCount; | 836 size_t previousPageCount = info->pageCount; |
| 893 | 837 |
| 894 json->beginArray("pages"); | 838 json->beginArray("pages"); |
| 895 for (HeapPage* page = m_firstPage; page; page = page->next(), ++info->pageCo unt) { | 839 for (BaseHeapPage* page = m_firstPage; page; page = page->next(), ++info->pa geCount) { |
| 896 // FIXME: To limit the size of the snapshot we only output "threshold" m any page snapshots. | 840 // FIXME: To limit the size of the snapshot we only output "threshold" m any page snapshots. |
| 897 if (info->pageCount < GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD) { | 841 if (info->pageCount < GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD) { |
| 898 json->beginArray(); | 842 json->beginArray(); |
| 899 json->pushInteger(reinterpret_cast<intptr_t>(page)); | 843 json->pushInteger(reinterpret_cast<intptr_t>(page)); |
| 900 page->snapshot(json, info); | 844 page->snapshot(json, info); |
| 901 json->endArray(); | 845 json->endArray(); |
| 902 } else { | 846 } else { |
| 903 page->snapshot(0, info); | 847 page->snapshot(0, info); |
| 904 } | 848 } |
| 905 } | 849 } |
| 906 json->endArray(); | 850 json->endArray(); |
| 907 | 851 |
| 908 json->beginArray("largeObjects"); | |
| 909 for (LargeObject* largeObject = m_firstLargeObject; largeObject; largeObject = largeObject->next()) { | |
| 910 json->beginDictionary(); | |
| 911 largeObject->snapshot(json, info); | |
| 912 json->endDictionary(); | |
| 913 } | |
| 914 json->endArray(); | |
| 915 | |
| 916 json->setInteger("pageCount", info->pageCount - previousPageCount); | 852 json->setInteger("pageCount", info->pageCount - previousPageCount); |
| 917 } | 853 } |
| 918 #endif | 854 #endif |
| 919 | 855 |
| 920 void FreeList::addToFreeList(Address address, size_t size) | 856 void FreeList::addToFreeList(Address address, size_t size) |
| 921 { | 857 { |
| 922 ASSERT(size < blinkPagePayloadSize()); | 858 ASSERT(size < blinkPagePayloadSize()); |
| 923 // The free list entries are only pointer aligned (but when we allocate | 859 // The free list entries are only pointer aligned (but when we allocate |
| 924 // from them we are 8 byte aligned due to the header size). | 860 // from them we are 8 byte aligned due to the header size). |
| 925 ASSERT(!((reinterpret_cast<uintptr_t>(address) + sizeof(HeapObjectHeader)) & allocationMask)); | 861 ASSERT(!((reinterpret_cast<uintptr_t>(address) + sizeof(HeapObjectHeader)) & allocationMask)); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 944 // space. | 880 // space. |
| 945 if (static_cast<HeapPage*>(page)->payloadSize() != size && !entry->shouldAdd ToFreeList()) | 881 if (static_cast<HeapPage*>(page)->payloadSize() != size && !entry->shouldAdd ToFreeList()) |
| 946 return; | 882 return; |
| 947 #endif | 883 #endif |
| 948 int index = bucketIndexForSize(size); | 884 int index = bucketIndexForSize(size); |
| 949 entry->link(&m_freeLists[index]); | 885 entry->link(&m_freeLists[index]); |
| 950 if (index > m_biggestFreeListIndex) | 886 if (index > m_biggestFreeListIndex) |
| 951 m_biggestFreeListIndex = index; | 887 m_biggestFreeListIndex = index; |
| 952 } | 888 } |
| 953 | 889 |
| 954 bool ThreadHeap::expandObject(HeapObjectHeader* header, size_t newSize) | 890 bool ThreadHeapForHeapPage::expandObject(HeapObjectHeader* header, size_t newSiz e) |
| 955 { | 891 { |
| 956 // It's possible that Vector requests a smaller expanded size because | 892 // It's possible that Vector requests a smaller expanded size because |
| 957 // Vector::shrinkCapacity can set a capacity smaller than the actual payload | 893 // Vector::shrinkCapacity can set a capacity smaller than the actual payload |
| 958 // size. | 894 // size. |
| 959 if (header->payloadSize() >= newSize) | 895 if (header->payloadSize() >= newSize) |
| 960 return true; | 896 return true; |
| 961 size_t allocationSize = allocationSizeFromSize(newSize); | 897 size_t allocationSize = allocationSizeFromSize(newSize); |
| 962 ASSERT(allocationSize > header->size()); | 898 ASSERT(allocationSize > header->size()); |
| 963 size_t expandSize = allocationSize - header->size(); | 899 size_t expandSize = allocationSize - header->size(); |
| 964 if (header->payloadEnd() == m_currentAllocationPoint && expandSize <= m_rema iningAllocationSize) { | 900 if (header->payloadEnd() == m_currentAllocationPoint && expandSize <= m_rema iningAllocationSize) { |
| 965 m_currentAllocationPoint += expandSize; | 901 m_currentAllocationPoint += expandSize; |
| 966 m_remainingAllocationSize -= expandSize; | 902 m_remainingAllocationSize -= expandSize; |
| 967 | 903 |
| 968 // Unpoison the memory used for the object (payload). | 904 // Unpoison the memory used for the object (payload). |
| 969 ASAN_UNPOISON_MEMORY_REGION(header->payloadEnd(), expandSize); | 905 ASAN_UNPOISON_MEMORY_REGION(header->payloadEnd(), expandSize); |
| 970 FILL_ZERO_IF_NOT_PRODUCTION(header->payloadEnd(), expandSize); | 906 FILL_ZERO_IF_NOT_PRODUCTION(header->payloadEnd(), expandSize); |
| 971 header->setSize(allocationSize); | 907 header->setSize(allocationSize); |
| 972 ASSERT(findPageFromAddress(header->payloadEnd() - 1)); | 908 ASSERT(findPageFromAddress(header->payloadEnd() - 1)); |
| 973 return true; | 909 return true; |
| 974 } | 910 } |
| 975 return false; | 911 return false; |
| 976 } | 912 } |
| 977 | 913 |
| 978 void ThreadHeap::shrinkObject(HeapObjectHeader* header, size_t newSize) | 914 void ThreadHeapForHeapPage::shrinkObject(HeapObjectHeader* header, size_t newSiz e) |
| 979 { | 915 { |
| 980 ASSERT(header->payloadSize() > newSize); | 916 ASSERT(header->payloadSize() > newSize); |
| 981 size_t allocationSize = allocationSizeFromSize(newSize); | 917 size_t allocationSize = allocationSizeFromSize(newSize); |
| 982 ASSERT(header->size() > allocationSize); | 918 ASSERT(header->size() > allocationSize); |
| 983 size_t shrinkSize = header->size() - allocationSize; | 919 size_t shrinkSize = header->size() - allocationSize; |
| 984 if (header->payloadEnd() == m_currentAllocationPoint) { | 920 if (header->payloadEnd() == m_currentAllocationPoint) { |
| 985 m_currentAllocationPoint -= shrinkSize; | 921 m_currentAllocationPoint -= shrinkSize; |
| 986 m_remainingAllocationSize += shrinkSize; | 922 m_remainingAllocationSize += shrinkSize; |
| 987 FILL_ZERO_IF_PRODUCTION(m_currentAllocationPoint, shrinkSize); | 923 FILL_ZERO_IF_PRODUCTION(m_currentAllocationPoint, shrinkSize); |
| 988 ASAN_POISON_MEMORY_REGION(m_currentAllocationPoint, shrinkSize); | 924 ASAN_POISON_MEMORY_REGION(m_currentAllocationPoint, shrinkSize); |
| 989 header->setSize(allocationSize); | 925 header->setSize(allocationSize); |
| 990 } else { | 926 } else { |
| 991 ASSERT(shrinkSize >= sizeof(HeapObjectHeader)); | 927 ASSERT(shrinkSize >= sizeof(HeapObjectHeader)); |
| 992 ASSERT(header->gcInfoIndex() > 0); | 928 ASSERT(header->gcInfoIndex() > 0); |
| 993 HeapObjectHeader* freedHeader = new (NotNull, header->payloadEnd() - shr inkSize) HeapObjectHeader(shrinkSize, header->gcInfoIndex()); | 929 HeapObjectHeader* freedHeader = new (NotNull, header->payloadEnd() - shr inkSize) HeapObjectHeader(shrinkSize, header->gcInfoIndex()); |
| 994 freedHeader->markPromptlyFreed(); | 930 freedHeader->markPromptlyFreed(); |
| 995 ASSERT(pageFromObject(reinterpret_cast<Address>(header)) == findPageFrom Address(reinterpret_cast<Address>(header))); | 931 ASSERT(pageFromObject(reinterpret_cast<Address>(header)) == findPageFrom Address(reinterpret_cast<Address>(header))); |
| 996 m_promptlyFreedSize += shrinkSize; | 932 m_promptlyFreedSize += shrinkSize; |
| 997 header->setSize(allocationSize); | 933 header->setSize(allocationSize); |
| 998 } | 934 } |
| 999 } | 935 } |
| 1000 | 936 |
| 1001 void ThreadHeap::promptlyFreeObject(HeapObjectHeader* header) | 937 void ThreadHeapForHeapPage::promptlyFreeObject(HeapObjectHeader* header) |
| 1002 { | 938 { |
| 1003 ASSERT(!m_threadState->sweepForbidden()); | 939 ASSERT(!threadState()->sweepForbidden()); |
| 1004 header->checkHeader(); | 940 header->checkHeader(); |
| 1005 Address address = reinterpret_cast<Address>(header); | 941 Address address = reinterpret_cast<Address>(header); |
| 1006 Address payload = header->payload(); | 942 Address payload = header->payload(); |
| 1007 size_t size = header->size(); | 943 size_t size = header->size(); |
| 1008 size_t payloadSize = header->payloadSize(); | 944 size_t payloadSize = header->payloadSize(); |
| 1009 ASSERT(size > 0); | 945 ASSERT(size > 0); |
| 1010 ASSERT(pageFromObject(address) == findPageFromAddress(address)); | 946 ASSERT(pageFromObject(address) == findPageFromAddress(address)); |
| 1011 | 947 |
| 1012 { | 948 { |
| 1013 ThreadState::SweepForbiddenScope forbiddenScope(m_threadState); | 949 ThreadState::SweepForbiddenScope forbiddenScope(threadState()); |
| 1014 header->finalize(payload, payloadSize); | 950 header->finalize(payload, payloadSize); |
| 1015 if (address + size == m_currentAllocationPoint) { | 951 if (address + size == m_currentAllocationPoint) { |
| 1016 m_currentAllocationPoint = address; | 952 m_currentAllocationPoint = address; |
| 1017 if (m_lastRemainingAllocationSize == m_remainingAllocationSize) { | 953 if (m_lastRemainingAllocationSize == m_remainingAllocationSize) { |
| 1018 Heap::decreaseAllocatedObjectSize(size); | 954 Heap::decreaseAllocatedObjectSize(size); |
| 1019 m_lastRemainingAllocationSize += size; | 955 m_lastRemainingAllocationSize += size; |
| 1020 } | 956 } |
| 1021 m_remainingAllocationSize += size; | 957 m_remainingAllocationSize += size; |
| 1022 FILL_ZERO_IF_PRODUCTION(address, size); | 958 FILL_ZERO_IF_PRODUCTION(address, size); |
| 1023 ASAN_POISON_MEMORY_REGION(address, size); | 959 ASAN_POISON_MEMORY_REGION(address, size); |
| 1024 return; | 960 return; |
| 1025 } | 961 } |
| 1026 FILL_ZERO_IF_PRODUCTION(payload, payloadSize); | 962 FILL_ZERO_IF_PRODUCTION(payload, payloadSize); |
| 1027 header->markPromptlyFreed(); | 963 header->markPromptlyFreed(); |
| 1028 } | 964 } |
| 1029 | 965 |
| 1030 m_promptlyFreedSize += size; | 966 m_promptlyFreedSize += size; |
| 1031 } | 967 } |
| 1032 | 968 |
| 1033 bool ThreadHeap::coalesce() | 969 bool ThreadHeapForHeapPage::coalesce() |
| 1034 { | 970 { |
| 1035 // Don't coalesce heaps if there are not enough promptly freed entries | 971 // Don't coalesce heaps if there are not enough promptly freed entries |
| 1036 // to be coalesced. | 972 // to be coalesced. |
| 1037 // | 973 // |
| 1038 // FIXME: This threshold is determined just to optimize blink_perf | 974 // FIXME: This threshold is determined just to optimize blink_perf |
| 1039 // benchmarks. Coalescing is very sensitive to the threashold and | 975 // benchmarks. Coalescing is very sensitive to the threashold and |
| 1040 // we need further investigations on the coalescing scheme. | 976 // we need further investigations on the coalescing scheme. |
| 1041 if (m_promptlyFreedSize < 1024 * 1024) | 977 if (m_promptlyFreedSize < 1024 * 1024) |
| 1042 return false; | 978 return false; |
| 1043 | 979 |
| 1044 if (m_threadState->sweepForbidden()) | 980 if (threadState()->sweepForbidden()) |
| 1045 return false; | 981 return false; |
| 1046 | 982 |
| 1047 ASSERT(!hasCurrentAllocationArea()); | 983 ASSERT(!hasCurrentAllocationArea()); |
| 1048 TRACE_EVENT0("blink_gc", "ThreadHeap::coalesce"); | 984 TRACE_EVENT0("blink_gc", "ThreadHeap::coalesce"); |
| 1049 | 985 |
| 1050 // Rebuild free lists. | 986 // Rebuild free lists. |
| 1051 m_freeList.clear(); | 987 m_freeList.clear(); |
| 1052 size_t freedSize = 0; | 988 size_t freedSize = 0; |
| 1053 for (HeapPage* page = m_firstPage; page; page = page->next()) { | 989 for (HeapPage* page = static_cast<HeapPage*>(m_firstPage); page; page = stat ic_cast<HeapPage*>(page->next())) { |
| 1054 page->clearObjectStartBitMap(); | 990 page->clearObjectStartBitMap(); |
| 1055 Address startOfGap = page->payload(); | 991 Address startOfGap = page->payload(); |
| 1056 for (Address headerAddress = startOfGap; headerAddress < page->payloadEn d(); ) { | 992 for (Address headerAddress = startOfGap; headerAddress < page->payloadEn d(); ) { |
| 1057 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(heade rAddress); | 993 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(heade rAddress); |
| 1058 size_t size = header->size(); | 994 size_t size = header->size(); |
| 1059 ASSERT(size > 0); | 995 ASSERT(size > 0); |
| 1060 ASSERT(size < blinkPagePayloadSize()); | 996 ASSERT(size < blinkPagePayloadSize()); |
| 1061 | 997 |
| 1062 if (header->isPromptlyFreed()) { | 998 if (header->isPromptlyFreed()) { |
| 1063 ASSERT(size >= sizeof(HeapObjectHeader)); | 999 ASSERT(size >= sizeof(HeapObjectHeader)); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1084 | 1020 |
| 1085 if (startOfGap != page->payloadEnd()) | 1021 if (startOfGap != page->payloadEnd()) |
| 1086 addToFreeList(startOfGap, page->payloadEnd() - startOfGap); | 1022 addToFreeList(startOfGap, page->payloadEnd() - startOfGap); |
| 1087 } | 1023 } |
| 1088 Heap::decreaseAllocatedObjectSize(freedSize); | 1024 Heap::decreaseAllocatedObjectSize(freedSize); |
| 1089 ASSERT(m_promptlyFreedSize == freedSize); | 1025 ASSERT(m_promptlyFreedSize == freedSize); |
| 1090 m_promptlyFreedSize = 0; | 1026 m_promptlyFreedSize = 0; |
| 1091 return true; | 1027 return true; |
| 1092 } | 1028 } |
| 1093 | 1029 |
| 1094 Address ThreadHeap::allocateLargeObject(size_t size, size_t gcInfoIndex) | 1030 Address ThreadHeapForLargeObject::allocateLargeObject(size_t allocationSize, siz e_t gcInfoIndex) |
| 1095 { | 1031 { |
| 1096 // Caller already added space for object header and rounded up to allocation | 1032 // Caller already added space for object header and rounded up to allocation |
| 1097 // alignment | 1033 // alignment |
| 1098 ASSERT(!(size & allocationMask)); | 1034 ASSERT(!(allocationSize & allocationMask)); |
| 1099 | 1035 |
| 1100 size_t allocationSize = sizeof(LargeObject) + size; | 1036 // 1. Check if we should trigger a GC. |
| 1037 threadState()->scheduleGCOrForceConservativeGCIfNeeded(); | |
| 1101 | 1038 |
| 1102 // Ensure that there is enough space for alignment. If the header | 1039 // 2. Try to sweep large objects more than allocationSize bytes |
| 1103 // is not a multiple of 8 bytes we will allocate an extra | 1040 // before allocating a new large object. |
| 1104 // headerPadding bytes to ensure it 8 byte aligned. | 1041 Address result = lazySweep(allocationSize, gcInfoIndex); |
| 1105 allocationSize += headerPadding(); | 1042 if (result) |
| 1043 return result; | |
| 1106 | 1044 |
| 1045 // 3. If we have failed in sweeping allocationSize bytes, | |
| 1046 // we complete sweeping before allocating this large object. | |
| 1047 threadState()->completeSweep(); | |
| 1048 return doAllocateLargeObject(allocationSize, gcInfoIndex); | |
| 1049 } | |
| 1050 | |
| 1051 Address ThreadHeapForLargeObject::doAllocateLargeObject(size_t allocationSize, s ize_t gcInfoIndex) | |
| 1052 { | |
| 1053 size_t largeObjectSize = sizeof(LargeObject) + headerPadding() + allocationS ize; | |
| 1107 // If ASan is supported we add allocationGranularity bytes to the allocated | 1054 // If ASan is supported we add allocationGranularity bytes to the allocated |
| 1108 // space and poison that to detect overflows | 1055 // space and poison that to detect overflows |
| 1109 #if defined(ADDRESS_SANITIZER) | 1056 #if defined(ADDRESS_SANITIZER) |
| 1110 allocationSize += allocationGranularity; | 1057 largeObjectSize += allocationGranularity; |
| 1111 #endif | 1058 #endif |
| 1112 | 1059 |
| 1113 // 1. Check if we should trigger a GC. | 1060 threadState()->shouldFlushHeapDoesNotContainCache(); |
| 1114 updateRemainingAllocationSize(); | 1061 PageMemory* pageMemory = PageMemory::allocate(largeObjectSize); |
| 1115 m_threadState->scheduleGCOrForceConservativeGCIfNeeded(); | 1062 threadState()->allocatedRegionsSinceLastGC().append(pageMemory->region()); |
| 1116 | |
| 1117 // 2. Try to sweep large objects more than allocationSize bytes | |
| 1118 // before allocating a new large object. | |
| 1119 if (!lazySweepLargeObjects(allocationSize)) { | |
| 1120 // 3. If we have failed in sweeping allocationSize bytes, | |
| 1121 // we complete sweeping before allocating this large object. | |
| 1122 m_threadState->completeSweep(); | |
| 1123 } | |
| 1124 | |
| 1125 m_threadState->shouldFlushHeapDoesNotContainCache(); | |
| 1126 PageMemory* pageMemory = PageMemory::allocate(allocationSize); | |
| 1127 m_threadState->allocatedRegionsSinceLastGC().append(pageMemory->region()); | |
| 1128 Address largeObjectAddress = pageMemory->writableStart(); | 1063 Address largeObjectAddress = pageMemory->writableStart(); |
| 1129 Address headerAddress = largeObjectAddress + sizeof(LargeObject) + headerPad ding(); | 1064 Address headerAddress = largeObjectAddress + sizeof(LargeObject) + headerPad ding(); |
| 1130 #if ENABLE(ASSERT) | 1065 #if ENABLE(ASSERT) |
| 1131 // Verify that the allocated PageMemory is expectedly zeroed. | 1066 // Verify that the allocated PageMemory is expectedly zeroed. |
| 1132 for (size_t i = 0; i < size; ++i) | 1067 for (size_t i = 0; i < largeObjectSize; ++i) |
| 1133 ASSERT(!headerAddress[i]); | 1068 ASSERT(!headerAddress[i]); |
| 1134 #endif | 1069 #endif |
| 1135 ASSERT(gcInfoIndex > 0); | 1070 ASSERT(gcInfoIndex > 0); |
| 1136 HeapObjectHeader* header = new (NotNull, headerAddress) HeapObjectHeader(lar geObjectSizeInHeader, gcInfoIndex); | 1071 HeapObjectHeader* header = new (NotNull, headerAddress) HeapObjectHeader(lar geObjectSizeInHeader, gcInfoIndex); |
| 1137 Address result = headerAddress + sizeof(*header); | 1072 Address result = headerAddress + sizeof(*header); |
| 1138 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); | 1073 ASSERT(!(reinterpret_cast<uintptr_t>(result) & allocationMask)); |
| 1139 LargeObject* largeObject = new (largeObjectAddress) LargeObject(pageMemory, this, size); | 1074 LargeObject* largeObject = new (largeObjectAddress) LargeObject(pageMemory, this, allocationSize); |
| 1140 header->checkHeader(); | 1075 header->checkHeader(); |
| 1141 | 1076 |
| 1142 // Poison the object header and allocationGranularity bytes after the object | 1077 // Poison the object header and allocationGranularity bytes after the object |
| 1143 ASAN_POISON_MEMORY_REGION(header, sizeof(*header)); | 1078 ASAN_POISON_MEMORY_REGION(header, sizeof(*header)); |
| 1144 ASAN_POISON_MEMORY_REGION(largeObject->address() + largeObject->size(), allo cationGranularity); | 1079 ASAN_POISON_MEMORY_REGION(largeObject->address() + largeObject->size(), allo cationGranularity); |
| 1145 | 1080 |
| 1146 largeObject->link(&m_firstLargeObject); | 1081 largeObject->link(&m_firstPage); |
| 1147 | 1082 |
| 1148 Heap::increaseAllocatedSpace(largeObject->size()); | 1083 Heap::increaseAllocatedSpace(largeObject->size()); |
| 1149 Heap::increaseAllocatedObjectSize(largeObject->size()); | 1084 Heap::increaseAllocatedObjectSize(largeObject->size()); |
| 1150 return result; | 1085 return result; |
| 1151 } | 1086 } |
| 1152 | 1087 |
| 1153 void ThreadHeap::freeLargeObject(LargeObject* object) | 1088 void ThreadHeapForLargeObject::freeLargeObject(LargeObject* object) |
| 1154 { | 1089 { |
| 1155 object->heapObjectHeader()->finalize(object->payload(), object->payloadSize( )); | 1090 object->heapObjectHeader()->finalize(object->payload(), object->payloadSize( )); |
| 1156 Heap::decreaseAllocatedSpace(object->size()); | 1091 Heap::decreaseAllocatedSpace(object->size()); |
| 1157 | 1092 |
| 1158 // Unpoison the object header and allocationGranularity bytes after the | 1093 // Unpoison the object header and allocationGranularity bytes after the |
| 1159 // object before freeing. | 1094 // object before freeing. |
| 1160 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(HeapObjectHea der)); | 1095 ASAN_UNPOISON_MEMORY_REGION(object->heapObjectHeader(), sizeof(HeapObjectHea der)); |
| 1161 ASAN_UNPOISON_MEMORY_REGION(object->address() + object->size(), allocationGr anularity); | 1096 ASAN_UNPOISON_MEMORY_REGION(object->address() + object->size(), allocationGr anularity); |
| 1162 | 1097 |
| 1163 if (object->terminating()) { | 1098 if (object->terminating()) { |
| 1164 ASSERT(ThreadState::current()->isTerminating()); | 1099 ASSERT(ThreadState::current()->isTerminating()); |
| 1165 // The thread is shutting down and this page is being removed as a part | 1100 // The thread is shutting down and this page is being removed as a part |
| 1166 // of the thread local GC. In that case the object could be traced in | 1101 // of the thread local GC. In that case the object could be traced in |
| 1167 // the next global GC if there is a dangling pointer from a live thread | 1102 // the next global GC if there is a dangling pointer from a live thread |
| 1168 // heap to this dead thread heap. To guard against this, we put the | 1103 // heap to this dead thread heap. To guard against this, we put the |
| 1169 // page into the orphaned page pool and zap the page memory. This | 1104 // page into the orphaned page pool and zap the page memory. This |
| 1170 // ensures that tracing the dangling pointer in the next global GC just | 1105 // ensures that tracing the dangling pointer in the next global GC just |
| 1171 // crashes instead of causing use-after-frees. After the next global | 1106 // crashes instead of causing use-after-frees. After the next global |
| 1172 // GC, the orphaned pages are removed. | 1107 // GC, the orphaned pages are removed. |
| 1173 Heap::orphanedPagePool()->addOrphanedPage(m_index, object); | 1108 Heap::orphanedPagePool()->addOrphanedPage(heapIndex(), object); |
| 1174 } else { | 1109 } else { |
| 1175 ASSERT(!ThreadState::current()->isTerminating()); | 1110 ASSERT(!ThreadState::current()->isTerminating()); |
| 1176 PageMemory* memory = object->storage(); | 1111 PageMemory* memory = object->storage(); |
| 1177 object->~LargeObject(); | 1112 object->~LargeObject(); |
| 1178 delete memory; | 1113 delete memory; |
| 1179 } | 1114 } |
| 1180 } | 1115 } |
| 1181 | 1116 |
| 1182 template<typename DataType> | 1117 template<typename DataType> |
| 1183 PagePool<DataType>::PagePool() | 1118 PagePool<DataType>::PagePool() |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1224 | 1159 |
| 1225 // We got some memory, but failed to commit it, try again. | 1160 // We got some memory, but failed to commit it, try again. |
| 1226 delete memory; | 1161 delete memory; |
| 1227 } | 1162 } |
| 1228 return nullptr; | 1163 return nullptr; |
| 1229 } | 1164 } |
| 1230 | 1165 |
| 1231 BaseHeapPage::BaseHeapPage(PageMemory* storage, ThreadHeap* heap) | 1166 BaseHeapPage::BaseHeapPage(PageMemory* storage, ThreadHeap* heap) |
| 1232 : m_storage(storage) | 1167 : m_storage(storage) |
| 1233 , m_heap(heap) | 1168 , m_heap(heap) |
| 1169 , m_next(nullptr) | |
| 1234 , m_terminating(false) | 1170 , m_terminating(false) |
| 1235 , m_swept(true) | 1171 , m_swept(true) |
| 1236 { | 1172 { |
| 1237 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | 1173 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 1238 } | 1174 } |
| 1239 | 1175 |
| 1240 void BaseHeapPage::markOrphaned() | 1176 void BaseHeapPage::markOrphaned() |
| 1241 { | 1177 { |
| 1242 m_heap = nullptr; | 1178 m_heap = nullptr; |
| 1243 m_terminating = false; | 1179 m_terminating = false; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1329 for (PoolEntry* entry = m_pool[index]; entry; entry = entry->next) { | 1265 for (PoolEntry* entry = m_pool[index]; entry; entry = entry->next) { |
| 1330 BaseHeapPage* page = entry->data; | 1266 BaseHeapPage* page = entry->data; |
| 1331 if (page->contains(reinterpret_cast<Address>(object))) | 1267 if (page->contains(reinterpret_cast<Address>(object))) |
| 1332 return true; | 1268 return true; |
| 1333 } | 1269 } |
| 1334 } | 1270 } |
| 1335 return false; | 1271 return false; |
| 1336 } | 1272 } |
| 1337 #endif | 1273 #endif |
| 1338 | 1274 |
| 1339 void ThreadHeap::freePage(HeapPage* page) | 1275 void ThreadHeapForHeapPage::freePage(HeapPage* page) |
| 1340 { | 1276 { |
| 1341 Heap::decreaseAllocatedSpace(blinkPageSize); | 1277 Heap::decreaseAllocatedSpace(blinkPageSize); |
| 1342 | 1278 |
| 1343 if (page->terminating()) { | 1279 if (page->terminating()) { |
| 1344 // The thread is shutting down and this page is being removed as a part | 1280 // The thread is shutting down and this page is being removed as a part |
| 1345 // of the thread local GC. In that case the object could be traced in | 1281 // of the thread local GC. In that case the object could be traced in |
| 1346 // the next global GC if there is a dangling pointer from a live thread | 1282 // the next global GC if there is a dangling pointer from a live thread |
| 1347 // heap to this dead thread heap. To guard against this, we put the | 1283 // heap to this dead thread heap. To guard against this, we put the |
| 1348 // page into the orphaned page pool and zap the page memory. This | 1284 // page into the orphaned page pool and zap the page memory. This |
| 1349 // ensures that tracing the dangling pointer in the next global GC just | 1285 // ensures that tracing the dangling pointer in the next global GC just |
| 1350 // crashes instead of causing use-after-frees. After the next global | 1286 // crashes instead of causing use-after-frees. After the next global |
| 1351 // GC, the orphaned pages are removed. | 1287 // GC, the orphaned pages are removed. |
| 1352 Heap::orphanedPagePool()->addOrphanedPage(m_index, page); | 1288 Heap::orphanedPagePool()->addOrphanedPage(heapIndex(), page); |
| 1353 } else { | 1289 } else { |
| 1354 PageMemory* memory = page->storage(); | 1290 PageMemory* memory = page->storage(); |
| 1355 page->~HeapPage(); | 1291 page->~HeapPage(); |
| 1356 Heap::freePagePool()->addFreePage(m_index, memory); | 1292 Heap::freePagePool()->addFreePage(heapIndex(), memory); |
| 1357 } | 1293 } |
| 1358 } | 1294 } |
| 1359 | 1295 |
| 1360 void ThreadHeap::allocatePage() | 1296 void ThreadHeapForHeapPage::allocatePage() |
| 1361 { | 1297 { |
| 1362 m_threadState->shouldFlushHeapDoesNotContainCache(); | 1298 threadState()->shouldFlushHeapDoesNotContainCache(); |
| 1363 PageMemory* pageMemory = Heap::freePagePool()->takeFreePage(m_index); | 1299 PageMemory* pageMemory = Heap::freePagePool()->takeFreePage(heapIndex()); |
| 1364 // We continue allocating page memory until we succeed in committing one. | 1300 // We continue allocating page memory until we succeed in committing one. |
| 1365 while (!pageMemory) { | 1301 while (!pageMemory) { |
| 1366 // Allocate a memory region for blinkPagesPerRegion pages that | 1302 // Allocate a memory region for blinkPagesPerRegion pages that |
| 1367 // will each have the following layout. | 1303 // will each have the following layout. |
| 1368 // | 1304 // |
| 1369 // [ guard os page | ... payload ... | guard os page ] | 1305 // [ guard os page | ... payload ... | guard os page ] |
| 1370 // ^---{ aligned to blink page size } | 1306 // ^---{ aligned to blink page size } |
| 1371 PageMemoryRegion* region = PageMemoryRegion::allocateNormalPages(); | 1307 PageMemoryRegion* region = PageMemoryRegion::allocateNormalPages(); |
| 1372 m_threadState->allocatedRegionsSinceLastGC().append(region); | 1308 threadState()->allocatedRegionsSinceLastGC().append(region); |
| 1373 | 1309 |
| 1374 // Setup the PageMemory object for each of the pages in the region. | 1310 // Setup the PageMemory object for each of the pages in the region. |
| 1375 size_t offset = 0; | 1311 size_t offset = 0; |
| 1376 for (size_t i = 0; i < blinkPagesPerRegion; ++i) { | 1312 for (size_t i = 0; i < blinkPagesPerRegion; ++i) { |
| 1377 PageMemory* memory = PageMemory::setupPageMemoryInRegion(region, off set, blinkPagePayloadSize()); | 1313 PageMemory* memory = PageMemory::setupPageMemoryInRegion(region, off set, blinkPagePayloadSize()); |
| 1378 // Take the first possible page ensuring that this thread actually | 1314 // Take the first possible page ensuring that this thread actually |
| 1379 // gets a page and add the rest to the page pool. | 1315 // gets a page and add the rest to the page pool. |
| 1380 if (!pageMemory) { | 1316 if (!pageMemory) { |
| 1381 if (memory->commit()) | 1317 if (memory->commit()) |
| 1382 pageMemory = memory; | 1318 pageMemory = memory; |
| 1383 else | 1319 else |
| 1384 delete memory; | 1320 delete memory; |
| 1385 } else { | 1321 } else { |
| 1386 Heap::freePagePool()->addFreePage(m_index, memory); | 1322 Heap::freePagePool()->addFreePage(heapIndex(), memory); |
| 1387 } | 1323 } |
| 1388 offset += blinkPageSize; | 1324 offset += blinkPageSize; |
| 1389 } | 1325 } |
| 1390 } | 1326 } |
| 1391 HeapPage* page = new (pageMemory->writableStart()) HeapPage(pageMemory, this ); | 1327 HeapPage* page = new (pageMemory->writableStart()) HeapPage(pageMemory, this ); |
| 1392 | |
| 1393 page->link(&m_firstPage); | 1328 page->link(&m_firstPage); |
| 1394 | 1329 |
| 1395 Heap::increaseAllocatedSpace(blinkPageSize); | 1330 Heap::increaseAllocatedSpace(blinkPageSize); |
| 1396 addToFreeList(page->payload(), page->payloadSize()); | 1331 addToFreeList(page->payload(), page->payloadSize()); |
| 1397 } | 1332 } |
| 1398 | 1333 |
| 1399 #if ENABLE(ASSERT) | 1334 #if ENABLE(ASSERT) |
| 1400 bool ThreadHeap::pagesToBeSweptContains(Address address) | 1335 bool ThreadHeapForHeapPage::pagesToBeSweptContains(Address address) |
| 1401 { | 1336 { |
| 1402 for (HeapPage* page = m_firstUnsweptPage; page; page = page->next()) { | 1337 for (BaseHeapPage* page = m_firstUnsweptPage; page; page = page->next()) { |
| 1403 if (page->contains(address)) | 1338 if (page->contains(address)) |
| 1404 return true; | 1339 return true; |
| 1405 } | 1340 } |
| 1406 return false; | 1341 return false; |
| 1407 } | 1342 } |
| 1408 #endif | 1343 #endif |
| 1409 | 1344 |
| 1410 size_t ThreadHeap::objectPayloadSizeForTesting() | 1345 size_t ThreadHeap::objectPayloadSizeForTesting() |
| 1411 { | 1346 { |
| 1412 ASSERT(isConsistentForSweeping()); | 1347 ASSERT(isConsistentForSweeping()); |
| 1413 ASSERT(!m_firstUnsweptPage); | 1348 ASSERT(!m_firstUnsweptPage); |
| 1414 ASSERT(!m_firstUnsweptLargeObject); | |
| 1415 | 1349 |
| 1416 size_t objectPayloadSize = 0; | 1350 size_t objectPayloadSize = 0; |
| 1417 for (HeapPage* page = m_firstPage; page; page = page->next()) | 1351 for (BaseHeapPage* page = m_firstPage; page; page = page->next()) |
| 1418 objectPayloadSize += page->objectPayloadSizeForTesting(); | 1352 objectPayloadSize += page->objectPayloadSizeForTesting(); |
| 1419 for (LargeObject* largeObject = m_firstLargeObject; largeObject; largeObject = largeObject->next()) | |
| 1420 objectPayloadSize += largeObject->objectPayloadSizeForTesting(); | |
| 1421 return objectPayloadSize; | 1353 return objectPayloadSize; |
| 1422 } | 1354 } |
| 1423 | 1355 |
| 1424 #if ENABLE(ASSERT) | 1356 #if ENABLE(ASSERT) |
| 1425 bool ThreadHeap::isConsistentForSweeping() | 1357 bool ThreadHeapForHeapPage::isConsistentForSweeping() |
| 1426 { | 1358 { |
| 1427 // A thread heap is consistent for sweeping if none of the pages to be swept | 1359 // A thread heap is consistent for sweeping if none of the pages to be swept |
| 1428 // contain a freelist block or the current allocation point. | 1360 // contain a freelist block or the current allocation point. |
| 1429 for (size_t i = 0; i < blinkPageSizeLog2; ++i) { | 1361 for (size_t i = 0; i < blinkPageSizeLog2; ++i) { |
| 1430 for (FreeListEntry* freeListEntry = m_freeList.m_freeLists[i]; freeListE ntry; freeListEntry = freeListEntry->next()) { | 1362 for (FreeListEntry* freeListEntry = m_freeList.m_freeLists[i]; freeListE ntry; freeListEntry = freeListEntry->next()) { |
| 1431 if (pagesToBeSweptContains(freeListEntry->address())) | 1363 if (pagesToBeSweptContains(freeListEntry->address())) |
| 1432 return false; | 1364 return false; |
| 1433 } | 1365 } |
| 1434 } | 1366 } |
| 1435 if (hasCurrentAllocationArea()) { | 1367 if (hasCurrentAllocationArea()) { |
| 1436 if (pagesToBeSweptContains(currentAllocationPoint())) | 1368 if (pagesToBeSweptContains(currentAllocationPoint())) |
| 1437 return false; | 1369 return false; |
| 1438 } | 1370 } |
| 1439 return true; | 1371 return true; |
| 1440 } | 1372 } |
| 1441 #endif | 1373 #endif |
| 1442 | 1374 |
| 1443 void ThreadHeap::makeConsistentForSweeping() | 1375 void ThreadHeap::makeConsistentForSweeping() |
| 1444 { | 1376 { |
| 1445 preparePagesForSweeping(); | |
| 1446 setAllocationPoint(nullptr, 0); | |
| 1447 clearFreeLists(); | 1377 clearFreeLists(); |
| 1448 } | |
| 1449 | |
| 1450 void ThreadHeap::preparePagesForSweeping() | |
| 1451 { | |
| 1452 ASSERT(isConsistentForSweeping()); | 1378 ASSERT(isConsistentForSweeping()); |
| 1453 for (HeapPage* page = m_firstPage; page; page = page->next()) | 1379 for (BaseHeapPage* page = m_firstPage; page; page = page->next()) |
| 1454 page->markAsUnswept(); | 1380 page->markAsUnswept(); |
| 1455 | 1381 |
| 1456 // If a new GC is requested before this thread got around to sweep, | 1382 // If a new GC is requested before this thread got around to sweep, |
| 1457 // ie. due to the thread doing a long running operation, we clear | 1383 // ie. due to the thread doing a long running operation, we clear |
| 1458 // the mark bits and mark any of the dead objects as dead. The latter | 1384 // the mark bits and mark any of the dead objects as dead. The latter |
| 1459 // is used to ensure the next GC marking does not trace already dead | 1385 // is used to ensure the next GC marking does not trace already dead |
| 1460 // objects. If we trace a dead object we could end up tracing into | 1386 // objects. If we trace a dead object we could end up tracing into |
| 1461 // garbage or the middle of another object via the newly conservatively | 1387 // garbage or the middle of another object via the newly conservatively |
| 1462 // found object. | 1388 // found object. |
| 1463 HeapPage* previousPage = nullptr; | 1389 BaseHeapPage* previousPage = nullptr; |
| 1464 for (HeapPage* page = m_firstUnsweptPage; page; previousPage = page, page = page->next()) { | 1390 for (BaseHeapPage* page = m_firstUnsweptPage; page; previousPage = page, pag e = page->next()) { |
| 1465 page->markUnmarkedObjectsDead(); | 1391 page->markUnmarkedObjectsDead(); |
| 1466 ASSERT(!page->hasBeenSwept()); | 1392 ASSERT(!page->hasBeenSwept()); |
| 1467 } | 1393 } |
| 1468 if (previousPage) { | 1394 if (previousPage) { |
| 1469 ASSERT(m_firstUnsweptPage); | 1395 ASSERT(m_firstUnsweptPage); |
| 1470 previousPage->m_next = m_firstPage; | 1396 previousPage->m_next = m_firstPage; |
| 1471 m_firstPage = m_firstUnsweptPage; | 1397 m_firstPage = m_firstUnsweptPage; |
| 1472 m_firstUnsweptPage = nullptr; | 1398 m_firstUnsweptPage = nullptr; |
| 1473 } | 1399 } |
| 1474 ASSERT(!m_firstUnsweptPage); | 1400 ASSERT(!m_firstUnsweptPage); |
| 1475 | |
| 1476 for (LargeObject* largeObject = m_firstLargeObject; largeObject; largeObject = largeObject->next()) | |
| 1477 largeObject->markAsUnswept(); | |
| 1478 | |
| 1479 LargeObject* previousLargeObject = nullptr; | |
| 1480 for (LargeObject* largeObject = m_firstUnsweptLargeObject; largeObject; prev iousLargeObject = largeObject, largeObject = largeObject->next()) { | |
| 1481 largeObject->markUnmarkedObjectsDead(); | |
| 1482 ASSERT(!largeObject->hasBeenSwept()); | |
| 1483 } | |
| 1484 if (previousLargeObject) { | |
| 1485 ASSERT(m_firstUnsweptLargeObject); | |
| 1486 previousLargeObject->m_next = m_firstLargeObject; | |
| 1487 m_firstLargeObject = m_firstUnsweptLargeObject; | |
| 1488 m_firstUnsweptLargeObject = nullptr; | |
| 1489 } | |
| 1490 ASSERT(!m_firstUnsweptLargeObject); | |
| 1491 } | 1401 } |
| 1492 | 1402 |
| 1493 void ThreadHeap::clearFreeLists() | 1403 void ThreadHeapForHeapPage::clearFreeLists() |
| 1494 { | 1404 { |
| 1405 setAllocationPoint(nullptr, 0); | |
|
sof
2015/02/06 09:46:52
Why is this here?
haraken
2015/02/06 09:59:28
Since setAllocationPoint is a method of ThreadHeap
| |
| 1495 m_freeList.clear(); | 1406 m_freeList.clear(); |
| 1496 } | 1407 } |
| 1497 | 1408 |
| 1498 void FreeList::clear() | 1409 void FreeList::clear() |
| 1499 { | 1410 { |
| 1500 m_biggestFreeListIndex = 0; | 1411 m_biggestFreeListIndex = 0; |
| 1501 for (size_t i = 0; i < blinkPageSizeLog2; ++i) | 1412 for (size_t i = 0; i < blinkPageSizeLog2; ++i) |
| 1502 m_freeLists[i] = nullptr; | 1413 m_freeLists[i] = nullptr; |
| 1503 } | 1414 } |
| 1504 | 1415 |
| 1505 int FreeList::bucketIndexForSize(size_t size) | 1416 int FreeList::bucketIndexForSize(size_t size) |
| 1506 { | 1417 { |
| 1507 ASSERT(size > 0); | 1418 ASSERT(size > 0); |
| 1508 int index = -1; | 1419 int index = -1; |
| 1509 while (size) { | 1420 while (size) { |
| 1510 size >>= 1; | 1421 size >>= 1; |
| 1511 index++; | 1422 index++; |
| 1512 } | 1423 } |
| 1513 return index; | 1424 return index; |
| 1514 } | 1425 } |
| 1515 | 1426 |
| 1516 HeapPage::HeapPage(PageMemory* storage, ThreadHeap* heap) | 1427 HeapPage::HeapPage(PageMemory* storage, ThreadHeap* heap) |
| 1517 : BaseHeapPage(storage, heap) | 1428 : BaseHeapPage(storage, heap) |
| 1518 , m_next(nullptr) | |
| 1519 { | 1429 { |
| 1520 m_objectStartBitMapComputed = false; | 1430 m_objectStartBitMapComputed = false; |
| 1521 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); | 1431 ASSERT(isPageHeaderAddress(reinterpret_cast<Address>(this))); |
| 1522 } | 1432 } |
| 1523 | 1433 |
| 1524 size_t HeapPage::objectPayloadSizeForTesting() | 1434 size_t HeapPage::objectPayloadSizeForTesting() |
| 1525 { | 1435 { |
| 1526 size_t objectPayloadSize = 0; | 1436 size_t objectPayloadSize = 0; |
| 1527 Address headerAddress = payload(); | 1437 Address headerAddress = payload(); |
| 1528 markAsSwept(); | 1438 markAsSwept(); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1551 clearObjectStartBitMap(); | 1461 clearObjectStartBitMap(); |
| 1552 | 1462 |
| 1553 size_t markedObjectSize = 0; | 1463 size_t markedObjectSize = 0; |
| 1554 Address startOfGap = payload(); | 1464 Address startOfGap = payload(); |
| 1555 for (Address headerAddress = startOfGap; headerAddress < payloadEnd(); ) { | 1465 for (Address headerAddress = startOfGap; headerAddress < payloadEnd(); ) { |
| 1556 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAdd ress); | 1466 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAdd ress); |
| 1557 ASSERT(header->size() > 0); | 1467 ASSERT(header->size() > 0); |
| 1558 ASSERT(header->size() < blinkPagePayloadSize()); | 1468 ASSERT(header->size() < blinkPagePayloadSize()); |
| 1559 | 1469 |
| 1560 if (header->isPromptlyFreed()) | 1470 if (header->isPromptlyFreed()) |
| 1561 heap()->decreasePromptlyFreedSize(header->size()); | 1471 heapForHeapPage()->decreasePromptlyFreedSize(header->size()); |
| 1562 if (header->isFree()) { | 1472 if (header->isFree()) { |
| 1563 size_t size = header->size(); | 1473 size_t size = header->size(); |
| 1564 // Zero the memory in the free list header to maintain the | 1474 // Zero the memory in the free list header to maintain the |
| 1565 // invariant that memory on the free list is zero filled. | 1475 // invariant that memory on the free list is zero filled. |
| 1566 // The rest of the memory is already on the free list and is | 1476 // The rest of the memory is already on the free list and is |
| 1567 // therefore already zero filled. | 1477 // therefore already zero filled. |
| 1568 FILL_ZERO_IF_PRODUCTION(headerAddress, size < sizeof(FreeListEntry) ? size : sizeof(FreeListEntry)); | 1478 FILL_ZERO_IF_PRODUCTION(headerAddress, size < sizeof(FreeListEntry) ? size : sizeof(FreeListEntry)); |
| 1569 headerAddress += size; | 1479 headerAddress += size; |
| 1570 continue; | 1480 continue; |
| 1571 } | 1481 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1584 header->finalize(payload, payloadSize); | 1494 header->finalize(payload, payloadSize); |
| 1585 // This memory will be added to the freelist. Maintain the invariant | 1495 // This memory will be added to the freelist. Maintain the invariant |
| 1586 // that memory on the freelist is zero filled. | 1496 // that memory on the freelist is zero filled. |
| 1587 FILL_ZERO_IF_PRODUCTION(headerAddress, size); | 1497 FILL_ZERO_IF_PRODUCTION(headerAddress, size); |
| 1588 ASAN_POISON_MEMORY_REGION(payload, payloadSize); | 1498 ASAN_POISON_MEMORY_REGION(payload, payloadSize); |
| 1589 headerAddress += size; | 1499 headerAddress += size; |
| 1590 continue; | 1500 continue; |
| 1591 } | 1501 } |
| 1592 | 1502 |
| 1593 if (startOfGap != headerAddress) | 1503 if (startOfGap != headerAddress) |
| 1594 heap()->addToFreeList(startOfGap, headerAddress - startOfGap); | 1504 heapForHeapPage()->addToFreeList(startOfGap, headerAddress - startOf Gap); |
| 1595 header->unmark(); | 1505 header->unmark(); |
| 1596 headerAddress += header->size(); | 1506 headerAddress += header->size(); |
| 1597 markedObjectSize += header->size(); | 1507 markedObjectSize += header->size(); |
| 1598 startOfGap = headerAddress; | 1508 startOfGap = headerAddress; |
| 1599 } | 1509 } |
| 1600 if (startOfGap != payloadEnd()) | 1510 if (startOfGap != payloadEnd()) |
| 1601 heap()->addToFreeList(startOfGap, payloadEnd() - startOfGap); | 1511 heapForHeapPage()->addToFreeList(startOfGap, payloadEnd() - startOfGap); |
| 1602 | 1512 |
| 1603 if (markedObjectSize) | 1513 if (markedObjectSize) |
| 1604 Heap::increaseMarkedObjectSize(markedObjectSize); | 1514 Heap::increaseMarkedObjectSize(markedObjectSize); |
| 1605 } | 1515 } |
| 1606 | 1516 |
| 1607 void HeapPage::markUnmarkedObjectsDead() | 1517 void HeapPage::markUnmarkedObjectsDead() |
| 1608 { | 1518 { |
| 1609 for (Address headerAddress = payload(); headerAddress < payloadEnd();) { | 1519 for (Address headerAddress = payload(); headerAddress < payloadEnd();) { |
| 1610 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAdd ress); | 1520 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAdd ress); |
| 1611 ASSERT(header->size() < blinkPagePayloadSize()); | 1521 ASSERT(header->size() < blinkPagePayloadSize()); |
| 1612 // Check if a free list entry first since we cannot call | 1522 // Check if a free list entry first since we cannot call |
| 1613 // isMarked on a free list entry. | 1523 // isMarked on a free list entry. |
| 1614 if (header->isFree()) { | 1524 if (header->isFree()) { |
| 1615 headerAddress += header->size(); | 1525 headerAddress += header->size(); |
| 1616 continue; | 1526 continue; |
| 1617 } | 1527 } |
| 1618 header->checkHeader(); | 1528 header->checkHeader(); |
| 1619 if (header->isMarked()) | 1529 if (header->isMarked()) |
| 1620 header->unmark(); | 1530 header->unmark(); |
| 1621 else | 1531 else |
| 1622 header->markDead(); | 1532 header->markDead(); |
| 1623 headerAddress += header->size(); | 1533 headerAddress += header->size(); |
| 1624 } | 1534 } |
| 1625 } | 1535 } |
| 1626 | 1536 |
| 1627 void HeapPage::removeFromHeap(ThreadHeap* heap) | 1537 void HeapPage::removeFromHeap() |
| 1628 { | 1538 { |
| 1629 heap->freePage(this); | 1539 heapForHeapPage()->freePage(this); |
| 1540 } | |
| 1541 | |
| 1542 ThreadHeapForHeapPage* HeapPage::heapForHeapPage() | |
| 1543 { | |
| 1544 return static_cast<ThreadHeapForHeapPage*>(heap()); | |
| 1630 } | 1545 } |
| 1631 | 1546 |
| 1632 void HeapPage::populateObjectStartBitMap() | 1547 void HeapPage::populateObjectStartBitMap() |
| 1633 { | 1548 { |
| 1634 memset(&m_objectStartBitMap, 0, objectStartBitMapSize); | 1549 memset(&m_objectStartBitMap, 0, objectStartBitMapSize); |
| 1635 Address start = payload(); | 1550 Address start = payload(); |
| 1636 for (Address headerAddress = start; headerAddress < payloadEnd();) { | 1551 for (Address headerAddress = start; headerAddress < payloadEnd();) { |
| 1637 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAdd ress); | 1552 HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAdd ress); |
| 1638 size_t objectOffset = headerAddress - start; | 1553 size_t objectOffset = headerAddress - start; |
| 1639 ASSERT(!(objectOffset & allocationMask)); | 1554 ASSERT(!(objectOffset & allocationMask)); |
| (...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2477 // because the hierarchy was not completely moved to the heap and | 2392 // because the hierarchy was not completely moved to the heap and |
| 2478 // some heap allocated objects own objects that contain persistents | 2393 // some heap allocated objects own objects that contain persistents |
| 2479 // pointing to other heap allocated objects. | 2394 // pointing to other heap allocated objects. |
| 2480 for (int i = 0; i < 5; ++i) | 2395 for (int i = 0; i < 5; ++i) |
| 2481 collectGarbage(ThreadState::NoHeapPointersOnStack); | 2396 collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 2482 } | 2397 } |
| 2483 | 2398 |
| 2484 void ThreadHeap::prepareHeapForTermination() | 2399 void ThreadHeap::prepareHeapForTermination() |
| 2485 { | 2400 { |
| 2486 ASSERT(!m_firstUnsweptPage); | 2401 ASSERT(!m_firstUnsweptPage); |
| 2487 ASSERT(!m_firstUnsweptLargeObject); | 2402 for (BaseHeapPage* page = m_firstPage; page; page = page->next()) { |
| 2488 for (HeapPage* page = m_firstPage; page; page = page->next()) { | |
| 2489 page->setTerminating(); | 2403 page->setTerminating(); |
| 2490 } | 2404 } |
| 2491 for (LargeObject* largeObject = m_firstLargeObject; largeObject; largeObject = largeObject->next()) { | |
| 2492 largeObject->setTerminating(); | |
| 2493 } | |
| 2494 } | 2405 } |
| 2495 | 2406 |
| 2496 size_t Heap::objectPayloadSizeForTesting() | 2407 size_t Heap::objectPayloadSizeForTesting() |
| 2497 { | 2408 { |
| 2498 size_t objectPayloadSize = 0; | 2409 size_t objectPayloadSize = 0; |
| 2499 for (ThreadState* state : ThreadState::attachedThreads()) { | 2410 for (ThreadState* state : ThreadState::attachedThreads()) { |
| 2500 state->setGCState(ThreadState::GCRunning); | 2411 state->setGCState(ThreadState::GCRunning); |
| 2501 state->makeConsistentForSweeping(); | 2412 state->makeConsistentForSweeping(); |
| 2502 objectPayloadSize += state->objectPayloadSizeForTesting(); | 2413 objectPayloadSize += state->objectPayloadSizeForTesting(); |
| 2503 state->setGCState(ThreadState::EagerSweepScheduled); | 2414 state->setGCState(ThreadState::EagerSweepScheduled); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 2517 return; | 2428 return; |
| 2518 | 2429 |
| 2519 // Don't promptly free large objects because their page is never reused | 2430 // Don't promptly free large objects because their page is never reused |
| 2520 // and don't free backings allocated on other threads. | 2431 // and don't free backings allocated on other threads. |
| 2521 BaseHeapPage* page = pageFromObject(address); | 2432 BaseHeapPage* page = pageFromObject(address); |
| 2522 if (page->isLargeObject() || page->heap()->threadState() != state) | 2433 if (page->isLargeObject() || page->heap()->threadState() != state) |
| 2523 return; | 2434 return; |
| 2524 | 2435 |
| 2525 HeapObjectHeader* header = HeapObjectHeader::fromPayload(address); | 2436 HeapObjectHeader* header = HeapObjectHeader::fromPayload(address); |
| 2526 header->checkHeader(); | 2437 header->checkHeader(); |
| 2527 static_cast<HeapPage*>(page)->heap()->promptlyFreeObject(header); | 2438 static_cast<HeapPage*>(page)->heapForHeapPage()->promptlyFreeObject(header); |
| 2528 } | 2439 } |
| 2529 | 2440 |
| 2530 void HeapAllocator::freeVectorBacking(void* address) | 2441 void HeapAllocator::freeVectorBacking(void* address) |
| 2531 { | 2442 { |
| 2532 backingFree(address); | 2443 backingFree(address); |
| 2533 } | 2444 } |
| 2534 | 2445 |
| 2535 void HeapAllocator::freeInlineVectorBacking(void* address) | 2446 void HeapAllocator::freeInlineVectorBacking(void* address) |
| 2536 { | 2447 { |
| 2537 backingFree(address); | 2448 backingFree(address); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 2551 if (state->sweepForbidden()) | 2462 if (state->sweepForbidden()) |
| 2552 return false; | 2463 return false; |
| 2553 ASSERT(state->isAllocationAllowed()); | 2464 ASSERT(state->isAllocationAllowed()); |
| 2554 | 2465 |
| 2555 BaseHeapPage* page = pageFromObject(address); | 2466 BaseHeapPage* page = pageFromObject(address); |
| 2556 if (page->isLargeObject() || page->heap()->threadState() != state) | 2467 if (page->isLargeObject() || page->heap()->threadState() != state) |
| 2557 return false; | 2468 return false; |
| 2558 | 2469 |
| 2559 HeapObjectHeader* header = HeapObjectHeader::fromPayload(address); | 2470 HeapObjectHeader* header = HeapObjectHeader::fromPayload(address); |
| 2560 header->checkHeader(); | 2471 header->checkHeader(); |
| 2561 return static_cast<HeapPage*>(page)->heap()->expandObject(header, newSize); | 2472 return static_cast<HeapPage*>(page)->heapForHeapPage()->expandObject(header, newSize); |
| 2562 } | 2473 } |
| 2563 | 2474 |
| 2564 bool HeapAllocator::expandVectorBacking(void* address, size_t newSize) | 2475 bool HeapAllocator::expandVectorBacking(void* address, size_t newSize) |
| 2565 { | 2476 { |
| 2566 return backingExpand(address, newSize); | 2477 return backingExpand(address, newSize); |
| 2567 } | 2478 } |
| 2568 | 2479 |
| 2569 bool HeapAllocator::expandInlineVectorBacking(void* address, size_t newSize) | 2480 bool HeapAllocator::expandInlineVectorBacking(void* address, size_t newSize) |
| 2570 { | 2481 { |
| 2571 return backingExpand(address, newSize); | 2482 return backingExpand(address, newSize); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 2597 // FIXME: This wastes unused memory. If this increases memory | 2508 // FIXME: This wastes unused memory. If this increases memory |
| 2598 // consumption, we should reallocate a new large object and shrink the | 2509 // consumption, we should reallocate a new large object and shrink the |
| 2599 // memory usage. | 2510 // memory usage. |
| 2600 return; | 2511 return; |
| 2601 } | 2512 } |
| 2602 if (page->heap()->threadState() != state) | 2513 if (page->heap()->threadState() != state) |
| 2603 return; | 2514 return; |
| 2604 | 2515 |
| 2605 HeapObjectHeader* header = HeapObjectHeader::fromPayload(address); | 2516 HeapObjectHeader* header = HeapObjectHeader::fromPayload(address); |
| 2606 header->checkHeader(); | 2517 header->checkHeader(); |
| 2607 static_cast<HeapPage*>(page)->heap()->shrinkObject(header, quantizedShrunkSi ze); | 2518 static_cast<HeapPage*>(page)->heapForHeapPage()->shrinkObject(header, quanti zedShrunkSize); |
| 2608 } | 2519 } |
| 2609 | 2520 |
| 2610 void HeapAllocator::shrinkVectorBackingInternal(void* address, size_t quantizedC urrentSize, size_t quantizedShrunkSize) | 2521 void HeapAllocator::shrinkVectorBackingInternal(void* address, size_t quantizedC urrentSize, size_t quantizedShrunkSize) |
| 2611 { | 2522 { |
| 2612 backingShrink(address, quantizedCurrentSize, quantizedShrunkSize); | 2523 backingShrink(address, quantizedCurrentSize, quantizedShrunkSize); |
| 2613 } | 2524 } |
| 2614 | 2525 |
| 2615 void HeapAllocator::shrinkInlineVectorBackingInternal(void* address, size_t quan tizedCurrentSize, size_t quantizedShrunkSize) | 2526 void HeapAllocator::shrinkInlineVectorBackingInternal(void* address, size_t quan tizedCurrentSize, size_t quantizedShrunkSize) |
| 2616 { | 2527 { |
| 2617 backingShrink(address, quantizedCurrentSize, quantizedShrunkSize); | 2528 backingShrink(address, quantizedCurrentSize, quantizedShrunkSize); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2717 bool Heap::s_shutdownCalled = false; | 2628 bool Heap::s_shutdownCalled = false; |
| 2718 bool Heap::s_lastGCWasConservative = false; | 2629 bool Heap::s_lastGCWasConservative = false; |
| 2719 FreePagePool* Heap::s_freePagePool; | 2630 FreePagePool* Heap::s_freePagePool; |
| 2720 OrphanedPagePool* Heap::s_orphanedPagePool; | 2631 OrphanedPagePool* Heap::s_orphanedPagePool; |
| 2721 Heap::RegionTree* Heap::s_regionTree = nullptr; | 2632 Heap::RegionTree* Heap::s_regionTree = nullptr; |
| 2722 size_t Heap::s_allocatedObjectSize = 0; | 2633 size_t Heap::s_allocatedObjectSize = 0; |
| 2723 size_t Heap::s_allocatedSpace = 0; | 2634 size_t Heap::s_allocatedSpace = 0; |
| 2724 size_t Heap::s_markedObjectSize = 0; | 2635 size_t Heap::s_markedObjectSize = 0; |
| 2725 | 2636 |
| 2726 } // namespace blink | 2637 } // namespace blink |
| OLD | NEW |