Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1599 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1610 ASSERT(size_in_bytes > 0); | 1610 ASSERT(size_in_bytes > 0); |
| 1611 ASSERT(IsAligned(size_in_bytes, kPointerSize)); | 1611 ASSERT(IsAligned(size_in_bytes, kPointerSize)); |
| 1612 | 1612 |
| 1613 // We write a map and possibly size information to the block. If the block | 1613 // We write a map and possibly size information to the block. If the block |
| 1614 // is big enough to be a FreeSpace with at least one extra word (the next | 1614 // is big enough to be a FreeSpace with at least one extra word (the next |
| 1615 // pointer), we set its map to be the free space map and its size to an | 1615 // pointer), we set its map to be the free space map and its size to an |
| 1616 // appropriate array length for the desired size from HeapObject::Size(). | 1616 // appropriate array length for the desired size from HeapObject::Size(). |
| 1617 // If the block is too small (eg, one or two words), to hold both a size | 1617 // If the block is too small (eg, one or two words), to hold both a size |
| 1618 // field and a next pointer, we give it a filler map that gives it the | 1618 // field and a next pointer, we give it a filler map that gives it the |
| 1619 // correct size. | 1619 // correct size. |
| 1620 // TODO(gc) ISOLATES MERGE cleanup HEAP macro usage | |
| 1621 if (size_in_bytes > FreeSpace::kHeaderSize) { | 1620 if (size_in_bytes > FreeSpace::kHeaderSize) { |
| 1622 set_map(heap->raw_unchecked_free_space_map()); | 1621 set_map(heap->raw_unchecked_free_space_map()); |
| 1623 // Can't use FreeSpace::cast because it fails during deserialization. | 1622 // Can't use FreeSpace::cast because it fails during deserialization. |
| 1624 FreeSpace* this_as_free_space = reinterpret_cast<FreeSpace*>(this); | 1623 FreeSpace* this_as_free_space = reinterpret_cast<FreeSpace*>(this); |
| 1625 this_as_free_space->set_size(size_in_bytes); | 1624 this_as_free_space->set_size(size_in_bytes); |
| 1626 } else if (size_in_bytes == kPointerSize) { | 1625 } else if (size_in_bytes == kPointerSize) { |
| 1627 set_map(heap->raw_unchecked_one_pointer_filler_map()); | 1626 set_map(heap->raw_unchecked_one_pointer_filler_map()); |
| 1628 } else if (size_in_bytes == 2 * kPointerSize) { | 1627 } else if (size_in_bytes == 2 * kPointerSize) { |
| 1629 set_map(heap->raw_unchecked_two_pointer_filler_map()); | 1628 set_map(heap->raw_unchecked_two_pointer_filler_map()); |
| 1630 } else { | 1629 } else { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1731 } else { | 1730 } else { |
| 1732 node->set_next(huge_list_); | 1731 node->set_next(huge_list_); |
| 1733 huge_list_ = node; | 1732 huge_list_ = node; |
| 1734 } | 1733 } |
| 1735 available_ += size_in_bytes; | 1734 available_ += size_in_bytes; |
| 1736 ASSERT(IsVeryLong() || available_ == SumFreeLists()); | 1735 ASSERT(IsVeryLong() || available_ == SumFreeLists()); |
| 1737 return 0; | 1736 return 0; |
| 1738 } | 1737 } |
| 1739 | 1738 |
| 1740 | 1739 |
| 1740 FreeListNode* FreeList::PickNodeFromList(FreeListNode** list, int* node_size) { | |
| 1741 FreeListNode* node = *list; | |
| 1742 | |
| 1743 if (node == NULL) return NULL; | |
| 1744 | |
| 1745 while (node != NULL && | |
| 1746 Page::FromAddress(node->address())->IsEvacuationCandidate()) { | |
|
Erik Corry
2011/07/04 11:04:11
It would be nicer to not put the free list entries
Vyacheslav Egorov (Chromium)
2011/08/05 12:50:28
Evacuation decision is made late.
| |
| 1747 available_ -= node->Size(); | |
| 1748 node = node->next(); | |
| 1749 } | |
| 1750 | |
| 1751 if (node != NULL) { | |
| 1752 *node_size = node->Size(); | |
| 1753 *list = node->next(); | |
| 1754 } else { | |
| 1755 *list = NULL; | |
| 1756 } | |
| 1757 | |
| 1758 return node; | |
| 1759 } | |
| 1760 | |
| 1761 | |
| 1762 FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { | |
| 1763 FreeListNode* node = NULL; | |
| 1764 | |
| 1765 if (size_in_bytes <= kSmallAllocationMax) { | |
| 1766 node = PickNodeFromList(&small_list_, node_size); | |
| 1767 if (node != NULL) return node; | |
| 1768 } | |
| 1769 | |
| 1770 if (size_in_bytes <= kMediumAllocationMax) { | |
| 1771 node = PickNodeFromList(&medium_list_, node_size); | |
| 1772 if (node != NULL) return node; | |
| 1773 } | |
| 1774 | |
| 1775 if (size_in_bytes <= kLargeAllocationMax) { | |
| 1776 node = PickNodeFromList(&large_list_, node_size); | |
| 1777 if (node != NULL) return node; | |
| 1778 } | |
| 1779 | |
| 1780 for (FreeListNode** cur = &huge_list_; | |
| 1781 *cur != NULL; | |
| 1782 cur = (*cur)->next_address()) { | |
| 1783 | |
| 1784 FreeListNode* cur_node = *cur; | |
| 1785 while (cur_node != NULL && | |
| 1786 Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) { | |
| 1787 available_ -= reinterpret_cast<FreeSpace*>(cur_node)->Size(); | |
| 1788 cur_node = cur_node->next(); | |
| 1789 } | |
| 1790 | |
| 1791 *cur = cur_node; | |
| 1792 if (cur_node == NULL) break; | |
| 1793 | |
| 1794 ASSERT((*cur)->map() == HEAP->raw_unchecked_free_space_map()); | |
| 1795 FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(*cur); | |
| 1796 int size = cur_as_free_space->Size(); | |
| 1797 if (size >= size_in_bytes) { | |
| 1798 // Large enough node found. Unlink it from the list. | |
| 1799 node = *cur; | |
| 1800 *node_size = size; | |
| 1801 *cur = node->next(); | |
| 1802 break; | |
| 1803 } | |
| 1804 } | |
| 1805 | |
| 1806 return node; | |
| 1807 } | |
| 1808 | |
|
Erik Corry
2011/07/04 11:04:11
Missing blank line
Vyacheslav Egorov (Chromium)
2011/08/05 12:50:28
Done.
| |
| 1741 // Allocation on the old space free list. If it succeeds then a new linear | 1809 // Allocation on the old space free list. If it succeeds then a new linear |
| 1742 // allocation space has been set up with the top and limit of the space. If | 1810 // allocation space has been set up with the top and limit of the space. If |
| 1743 // the allocation fails then NULL is returned, and the caller can perform a GC | 1811 // the allocation fails then NULL is returned, and the caller can perform a GC |
| 1744 // or allocate a new page before retrying. | 1812 // or allocate a new page before retrying. |
| 1745 HeapObject* FreeList::Allocate(int size_in_bytes) { | 1813 HeapObject* FreeList::Allocate(int size_in_bytes) { |
| 1746 ASSERT(0 < size_in_bytes); | 1814 ASSERT(0 < size_in_bytes); |
| 1747 ASSERT(size_in_bytes <= kMaxBlockSize); | 1815 ASSERT(size_in_bytes <= kMaxBlockSize); |
| 1748 ASSERT(IsAligned(size_in_bytes, kPointerSize)); | 1816 ASSERT(IsAligned(size_in_bytes, kPointerSize)); |
| 1749 // Don't free list allocate if there is linear space available. | 1817 // Don't free list allocate if there is linear space available. |
| 1750 ASSERT(owner_->limit() - owner_->top() < size_in_bytes); | 1818 ASSERT(owner_->limit() - owner_->top() < size_in_bytes); |
| 1751 | 1819 |
| 1752 FreeListNode* new_node = NULL; | |
| 1753 int new_node_size = 0; | 1820 int new_node_size = 0; |
| 1754 | 1821 FreeListNode* new_node = FindNodeFor(size_in_bytes, &new_node_size); |
| 1755 if (size_in_bytes <= kSmallAllocationMax && small_list_ != NULL) { | 1822 if (new_node == NULL) return NULL; |
| 1756 new_node = small_list_; | |
| 1757 new_node_size = new_node->Size(); | |
| 1758 small_list_ = new_node->next(); | |
| 1759 } else if (size_in_bytes <= kMediumAllocationMax && medium_list_ != NULL) { | |
| 1760 new_node = medium_list_; | |
| 1761 new_node_size = new_node->Size(); | |
| 1762 medium_list_ = new_node->next(); | |
| 1763 } else if (size_in_bytes <= kLargeAllocationMax && large_list_ != NULL) { | |
| 1764 new_node = large_list_; | |
| 1765 new_node_size = new_node->Size(); | |
| 1766 large_list_ = new_node->next(); | |
| 1767 } else { | |
| 1768 for (FreeListNode** cur = &huge_list_; | |
| 1769 *cur != NULL; | |
| 1770 cur = (*cur)->next_address()) { | |
| 1771 ASSERT((*cur)->map() == HEAP->raw_unchecked_free_space_map()); | |
| 1772 FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(*cur); | |
| 1773 int size = cur_as_free_space->Size(); | |
| 1774 if (size >= size_in_bytes) { | |
| 1775 // Large enough node found. Unlink it from the list. | |
| 1776 new_node = *cur; | |
| 1777 new_node_size = size; | |
| 1778 *cur = new_node->next(); | |
| 1779 break; | |
| 1780 } | |
| 1781 } | |
| 1782 if (new_node == NULL) return NULL; | |
| 1783 } | |
| 1784 | 1823 |
| 1785 available_ -= new_node_size; | 1824 available_ -= new_node_size; |
| 1786 ASSERT(IsVeryLong() || available_ == SumFreeLists()); | 1825 ASSERT(IsVeryLong() || available_ == SumFreeLists()); |
| 1787 | 1826 |
| 1788 int old_linear_size = owner_->limit() - owner_->top(); | 1827 int old_linear_size = owner_->limit() - owner_->top(); |
| 1789 // Mark the old linear allocation area with a free space map so it can be | 1828 // Mark the old linear allocation area with a free space map so it can be |
| 1790 // skipped when scanning the heap. This also puts it back in the free list | 1829 // skipped when scanning the heap. This also puts it back in the free list |
| 1791 // if it is big enough. | 1830 // if it is big enough. |
| 1792 owner_->Free(owner_->top(), old_linear_size); | 1831 owner_->Free(owner_->top(), old_linear_size); |
| 1793 // TODO(gc) ISOLATES MERGE | 1832 owner_->heap()->incremental_marking()->Step(size_in_bytes - old_linear_size); |
| 1794 HEAP->incremental_marking()->Step(size_in_bytes - old_linear_size); | |
| 1795 | 1833 |
| 1796 ASSERT(new_node_size - size_in_bytes >= 0); // New linear size. | 1834 ASSERT(new_node_size - size_in_bytes >= 0); // New linear size. |
| 1797 | 1835 |
| 1798 const int kThreshold = IncrementalMarking::kAllocatedThreshold; | 1836 const int kThreshold = IncrementalMarking::kAllocatedThreshold; |
| 1799 | 1837 |
| 1800 // Memory in the linear allocation area is counted as allocated. We may free | 1838 // Memory in the linear allocation area is counted as allocated. We may free |
| 1801 // a little of this again immediately - see below. | 1839 // a little of this again immediately - see below. |
| 1802 owner_->Allocate(new_node_size); | 1840 owner_->Allocate(new_node_size); |
| 1803 | 1841 |
| 1804 if (new_node_size - size_in_bytes > kThreshold && | 1842 int bytes_left = new_node_size - size_in_bytes; |
| 1805 HEAP->incremental_marking()->IsMarkingIncomplete() && | 1843 if (bytes_left > kThreshold && |
| 1844 owner_->heap()->incremental_marking()->IsMarkingIncomplete() && | |
| 1806 FLAG_incremental_marking_steps) { | 1845 FLAG_incremental_marking_steps) { |
| 1807 int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold); | 1846 int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold); |
| 1808 // We don't want to give too large linear areas to the allocator while | 1847 // We don't want to give too large linear areas to the allocator while |
| 1809 // incremental marking is going on, because we won't check again whether | 1848 // incremental marking is going on, because we won't check again whether |
| 1810 // we want to do another increment until the linear area is used up. | 1849 // we want to do another increment until the linear area is used up. |
| 1811 owner_->Free(new_node->address() + size_in_bytes + linear_size, | 1850 owner_->Free(new_node->address() + size_in_bytes + linear_size, |
| 1812 new_node_size - size_in_bytes - linear_size); | 1851 new_node_size - size_in_bytes - linear_size); |
| 1813 owner_->SetTop(new_node->address() + size_in_bytes, | 1852 owner_->SetTop(new_node->address() + size_in_bytes, |
| 1814 new_node->address() + size_in_bytes + linear_size); | 1853 new_node->address() + size_in_bytes + linear_size); |
| 1815 } else { | 1854 } else if (bytes_left > 0) { |
| 1816 // Normally we give the rest of the node to the allocator as its new | 1855 // Normally we give the rest of the node to the allocator as its new |
| 1817 // linear allocation area. | 1856 // linear allocation area. |
| 1818 owner_->SetTop(new_node->address() + size_in_bytes, | 1857 owner_->SetTop(new_node->address() + size_in_bytes, |
| 1819 new_node->address() + new_node_size); | 1858 new_node->address() + new_node_size); |
| 1820 } | 1859 } |
| 1821 | 1860 |
| 1822 return new_node; | 1861 return new_node; |
| 1823 } | 1862 } |
| 1824 | 1863 |
| 1825 | 1864 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1888 sum += SumFreeList(large_list_); | 1927 sum += SumFreeList(large_list_); |
| 1889 sum += SumFreeList(huge_list_); | 1928 sum += SumFreeList(huge_list_); |
| 1890 return sum; | 1929 return sum; |
| 1891 } | 1930 } |
| 1892 #endif | 1931 #endif |
| 1893 | 1932 |
| 1894 | 1933 |
| 1895 // ----------------------------------------------------------------------------- | 1934 // ----------------------------------------------------------------------------- |
| 1896 // OldSpace implementation | 1935 // OldSpace implementation |
| 1897 | 1936 |
| 1898 void OldSpace::PrepareForMarkCompact() { | |
| 1899 // Call prepare of the super class. | |
| 1900 PagedSpace::PrepareForMarkCompact(); | |
| 1901 | |
| 1902 // Stop lazy sweeping for this space. | |
| 1903 first_unswept_page_ = last_unswept_page_ = Page::FromAddress(NULL); | |
| 1904 | |
| 1905 // Clear the free list before a full GC---it will be rebuilt afterward. | |
| 1906 free_list_.Reset(); | |
| 1907 } | |
| 1908 | |
| 1909 | |
| 1910 bool NewSpace::ReserveSpace(int bytes) { | 1937 bool NewSpace::ReserveSpace(int bytes) { |
| 1911 // We can't reliably unpack a partial snapshot that needs more new space | 1938 // We can't reliably unpack a partial snapshot that needs more new space |
| 1912 // space than the minimum NewSpace size. | 1939 // space than the minimum NewSpace size. |
| 1913 ASSERT(bytes <= InitialCapacity()); | 1940 ASSERT(bytes <= InitialCapacity()); |
| 1914 Address limit = allocation_info_.limit; | 1941 Address limit = allocation_info_.limit; |
| 1915 Address top = allocation_info_.top; | 1942 Address top = allocation_info_.top; |
| 1916 return limit - top >= bytes; | 1943 return limit - top >= bytes; |
| 1917 } | 1944 } |
| 1918 | 1945 |
| 1919 | 1946 |
| 1920 void PagedSpace::PrepareForMarkCompact() { | 1947 void PagedSpace::PrepareForMarkCompact() { |
| 1921 // We don't have a linear allocation area while sweeping. It will be restored | 1948 // We don't have a linear allocation area while sweeping. It will be restored |
| 1922 // on the first allocation after the sweep. | 1949 // on the first allocation after the sweep. |
| 1923 // Mark the old linear allocation area with a free space map so it can be | 1950 // Mark the old linear allocation area with a free space map so it can be |
| 1924 // skipped when scanning the heap. | 1951 // skipped when scanning the heap. |
| 1925 int old_linear_size = limit() - top(); | 1952 int old_linear_size = limit() - top(); |
| 1926 Free(top(), old_linear_size); | 1953 Free(top(), old_linear_size); |
| 1927 SetTop(NULL, NULL); | 1954 SetTop(NULL, NULL); |
| 1955 | |
| 1956 // Stop lazy sweeping for the space. | |
| 1957 first_unswept_page_ = last_unswept_page_ = Page::FromAddress(NULL); | |
| 1958 | |
| 1959 // Clear the free list before a full GC---it will be rebuilt afterward. | |
| 1960 free_list_.Reset(); | |
| 1961 | |
| 1962 // Clear EVACUATED flag from all pages. | |
| 1963 PageIterator it(this); | |
| 1964 while (it.has_next()) { | |
| 1965 Page* page = it.next(); | |
| 1966 page->ClearFlag(MemoryChunk::EVACUATED); | |
| 1967 } | |
| 1928 } | 1968 } |
| 1929 | 1969 |
| 1930 | 1970 |
| 1931 bool PagedSpace::ReserveSpace(int size_in_bytes) { | 1971 bool PagedSpace::ReserveSpace(int size_in_bytes) { |
| 1932 ASSERT(size_in_bytes <= Page::kMaxHeapObjectSize); | 1972 ASSERT(size_in_bytes <= Page::kMaxHeapObjectSize); |
| 1933 ASSERT(size_in_bytes == RoundSizeDownToObjectAlignment(size_in_bytes)); | 1973 ASSERT(size_in_bytes == RoundSizeDownToObjectAlignment(size_in_bytes)); |
| 1934 Address current_top = allocation_info_.top; | 1974 Address current_top = allocation_info_.top; |
| 1935 Address new_top = current_top + size_in_bytes; | 1975 Address new_top = current_top + size_in_bytes; |
| 1936 if (new_top <= allocation_info_.limit) return true; | 1976 if (new_top <= allocation_info_.limit) return true; |
| 1937 | 1977 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1959 | 1999 |
| 1960 | 2000 |
| 1961 bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) { | 2001 bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) { |
| 1962 if (IsSweepingComplete()) return true; | 2002 if (IsSweepingComplete()) return true; |
| 1963 | 2003 |
| 1964 int freed_bytes = 0; | 2004 int freed_bytes = 0; |
| 1965 Page* last = last_unswept_page_->next_page(); | 2005 Page* last = last_unswept_page_->next_page(); |
| 1966 Page* p = first_unswept_page_; | 2006 Page* p = first_unswept_page_; |
| 1967 do { | 2007 do { |
| 1968 Page* next_page = p->next_page(); | 2008 Page* next_page = p->next_page(); |
| 1969 freed_bytes += MarkCompactCollector::SweepConservatively(this, p); | 2009 // Evacuation candidates were swept by evacuator. |
| 2010 if (!p->WasEvacuated()) { | |
| 2011 freed_bytes += MarkCompactCollector::SweepConservatively(this, p); | |
| 2012 } | |
| 1970 p = next_page; | 2013 p = next_page; |
| 1971 } while (p != last && freed_bytes < bytes_to_sweep); | 2014 } while (p != last && freed_bytes < bytes_to_sweep); |
| 1972 | 2015 |
| 1973 if (p == last) { | 2016 if (p == last) { |
| 1974 last_unswept_page_ = first_unswept_page_ = Page::FromAddress(NULL); | 2017 last_unswept_page_ = first_unswept_page_ = Page::FromAddress(NULL); |
| 1975 } else { | 2018 } else { |
| 1976 first_unswept_page_ = p; | 2019 first_unswept_page_ = p; |
| 1977 } | 2020 } |
| 1978 | 2021 |
| 1979 heap()->LowerOldGenLimits(freed_bytes); | 2022 heap()->LowerOldGenLimits(freed_bytes); |
| 1980 | 2023 |
| 1981 heap()->FreeQueuedChunks(); | 2024 heap()->FreeQueuedChunks(); |
| 1982 | 2025 |
| 1983 return IsSweepingComplete(); | 2026 return IsSweepingComplete(); |
| 1984 } | 2027 } |
| 1985 | 2028 |
| 1986 | 2029 |
| 2030 void PagedSpace::EvictEvacuationCandidatesFromFreeLists() { | |
| 2031 if (allocation_info_.top >= allocation_info_.limit) return; | |
| 2032 | |
| 2033 if (Page::FromAddress(allocation_info_.top)->IsEvacuationCandidate()) { | |
| 2034 allocation_info_.top = NULL; | |
| 2035 allocation_info_.limit = NULL; | |
| 2036 } | |
| 2037 } | |
| 2038 | |
| 2039 | |
| 1987 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) { | 2040 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) { |
| 1988 // Allocation in this space has failed. | 2041 // Allocation in this space has failed. |
| 1989 | 2042 |
| 1990 // Free list allocation failed and there is no next page. Fail if we have | 2043 // Free list allocation failed and there is no next page. Fail if we have |
| 1991 // hit the old generation size limit that should cause a garbage | 2044 // hit the old generation size limit that should cause a garbage |
| 1992 // collection. | 2045 // collection. |
| 1993 if (!heap()->always_allocate() && | 2046 if (!heap()->always_allocate() && |
| 1994 heap()->OldGenerationAllocationLimitReached()) { | 2047 heap()->OldGenerationAllocationLimitReached()) { |
| 1995 return NULL; | 2048 return NULL; |
| 1996 } | 2049 } |
| (...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2497 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { | 2550 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) { |
| 2498 if (obj->IsCode()) { | 2551 if (obj->IsCode()) { |
| 2499 Code* code = Code::cast(obj); | 2552 Code* code = Code::cast(obj); |
| 2500 isolate->code_kind_statistics()[code->kind()] += code->Size(); | 2553 isolate->code_kind_statistics()[code->kind()] += code->Size(); |
| 2501 } | 2554 } |
| 2502 } | 2555 } |
| 2503 } | 2556 } |
| 2504 #endif // DEBUG | 2557 #endif // DEBUG |
| 2505 | 2558 |
| 2506 } } // namespace v8::internal | 2559 } } // namespace v8::internal |
| OLD | NEW |