| 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 1309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 // decreases to the non-capacity stats. | 1320 // decreases to the non-capacity stats. |
| 1321 class AllocationStats BASE_EMBEDDED { | 1321 class AllocationStats BASE_EMBEDDED { |
| 1322 public: | 1322 public: |
| 1323 AllocationStats() { Clear(); } | 1323 AllocationStats() { Clear(); } |
| 1324 | 1324 |
| 1325 // Zero out all the allocation statistics (i.e., no capacity). | 1325 // Zero out all the allocation statistics (i.e., no capacity). |
| 1326 void Clear() { | 1326 void Clear() { |
| 1327 capacity_ = 0; | 1327 capacity_ = 0; |
| 1328 size_ = 0; | 1328 size_ = 0; |
| 1329 waste_ = 0; | 1329 waste_ = 0; |
| 1330 pretenure_ = 0; |
| 1330 } | 1331 } |
| 1331 | 1332 |
| 1332 void ClearSizeWaste() { | 1333 void ClearSizeWaste() { |
| 1333 size_ = capacity_; | 1334 size_ = capacity_; |
| 1334 waste_ = 0; | 1335 waste_ = 0; |
| 1336 pretenure_ = 0; |
| 1335 } | 1337 } |
| 1336 | 1338 |
| 1337 // Reset the allocation statistics (i.e., available = capacity with no | 1339 // Reset the allocation statistics (i.e., available = capacity with no |
| 1338 // wasted or allocated bytes). | 1340 // wasted or allocated bytes). |
| 1339 void Reset() { | 1341 void Reset() { |
| 1340 size_ = 0; | 1342 size_ = 0; |
| 1341 waste_ = 0; | 1343 waste_ = 0; |
| 1344 pretenure_ = 0; |
| 1342 } | 1345 } |
| 1343 | 1346 |
| 1344 // Accessors for the allocation statistics. | 1347 // Accessors for the allocation statistics. |
| 1345 intptr_t Capacity() { return capacity_; } | 1348 intptr_t Capacity() { return capacity_; } |
| 1346 intptr_t Size() { return size_; } | 1349 intptr_t Size() { return size_; } |
| 1347 intptr_t Waste() { return waste_; } | 1350 intptr_t Waste() { return waste_; } |
| 1351 intptr_t Pretenure() { return pretenure_; } |
| 1348 | 1352 |
| 1349 // Grow the space by adding available bytes. They are initially marked as | 1353 // Grow the space by adding available bytes. They are initially marked as |
| 1350 // being in use (part of the size), but will normally be immediately freed, | 1354 // being in use (part of the size), but will normally be immediately freed, |
| 1351 // putting them on the free list and removing them from size_. | 1355 // putting them on the free list and removing them from size_. |
| 1352 void ExpandSpace(int size_in_bytes) { | 1356 void ExpandSpace(int size_in_bytes) { |
| 1353 capacity_ += size_in_bytes; | 1357 capacity_ += size_in_bytes; |
| 1354 size_ += size_in_bytes; | 1358 size_ += size_in_bytes; |
| 1355 ASSERT(size_ >= 0); | 1359 ASSERT(size_ >= 0); |
| 1356 } | 1360 } |
| 1357 | 1361 |
| 1358 // Shrink the space by removing available bytes. Since shrinking is done | 1362 // Shrink the space by removing available bytes. Since shrinking is done |
| 1359 // during sweeping, bytes have been marked as being in use (part of the size) | 1363 // during sweeping, bytes have been marked as being in use (part of the size) |
| 1360 // and are hereby freed. | 1364 // and are hereby freed. |
| 1361 void ShrinkSpace(int size_in_bytes) { | 1365 void ShrinkSpace(int size_in_bytes) { |
| 1362 capacity_ -= size_in_bytes; | 1366 capacity_ -= size_in_bytes; |
| 1363 size_ -= size_in_bytes; | 1367 size_ -= size_in_bytes; |
| 1364 ASSERT(size_ >= 0); | 1368 ASSERT(size_ >= 0); |
| 1365 } | 1369 } |
| 1366 | 1370 |
| 1367 // Allocate from available bytes (available -> size). | 1371 // Allocate from available bytes (available -> size). |
| 1368 void AllocateBytes(intptr_t size_in_bytes) { | 1372 void AllocateBytes(intptr_t size_in_bytes) { |
| 1369 size_ += size_in_bytes; | 1373 size_ += size_in_bytes; |
| 1370 ASSERT(size_ >= 0); | 1374 ASSERT(size_ >= 0); |
| 1371 } | 1375 } |
| 1372 | 1376 |
| 1377 void AllocatePretenureBytes(intptr_t size_in_bytes) { |
| 1378 pretenure_ += size_in_bytes; |
| 1379 ASSERT(pretenure_ >= 0); |
| 1380 } |
| 1381 |
| 1373 // Free allocated bytes, making them available (size -> available). | 1382 // Free allocated bytes, making them available (size -> available). |
| 1374 void DeallocateBytes(intptr_t size_in_bytes) { | 1383 void DeallocateBytes(intptr_t size_in_bytes) { |
| 1375 size_ -= size_in_bytes; | 1384 size_ -= size_in_bytes; |
| 1376 ASSERT(size_ >= 0); | 1385 ASSERT(size_ >= 0); |
| 1377 } | 1386 } |
| 1378 | 1387 |
| 1379 // Waste free bytes (available -> waste). | 1388 // Waste free bytes (available -> waste). |
| 1380 void WasteBytes(int size_in_bytes) { | 1389 void WasteBytes(int size_in_bytes) { |
| 1381 size_ -= size_in_bytes; | 1390 size_ -= size_in_bytes; |
| 1382 waste_ += size_in_bytes; | 1391 waste_ += size_in_bytes; |
| 1383 ASSERT(size_ >= 0); | 1392 ASSERT(size_ >= 0); |
| 1384 } | 1393 } |
| 1385 | 1394 |
| 1386 private: | 1395 private: |
| 1387 intptr_t capacity_; | 1396 intptr_t capacity_; |
| 1388 intptr_t size_; | 1397 intptr_t size_; |
| 1389 intptr_t waste_; | 1398 intptr_t waste_; |
| 1399 // TODO(hpayer): We can remove the bookkeeping of pretenured objects when |
| 1400 // we provide pretenuring support for all kinds of objects. |
| 1401 intptr_t pretenure_; |
| 1390 }; | 1402 }; |
| 1391 | 1403 |
| 1392 | 1404 |
| 1393 // ----------------------------------------------------------------------------- | 1405 // ----------------------------------------------------------------------------- |
| 1394 // Free lists for old object spaces | 1406 // Free lists for old object spaces |
| 1395 // | 1407 // |
| 1396 // Free-list nodes are free blocks in the heap. They look like heap objects | 1408 // Free-list nodes are free blocks in the heap. They look like heap objects |
| 1397 // (free-list node pointers have the heap object tag, and they have a map like | 1409 // (free-list node pointers have the heap object tag, and they have a map like |
| 1398 // a heap object). They have a size and a next pointer. The next pointer is | 1410 // a heap object). They have a size and a next pointer. The next pointer is |
| 1399 // the raw address of the next free list node (or NULL). | 1411 // the raw address of the next free list node (or NULL). |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1519 | 1531 |
| 1520 // Clear the free list. | 1532 // Clear the free list. |
| 1521 void Reset(); | 1533 void Reset(); |
| 1522 | 1534 |
| 1523 // Return the number of bytes available on the free list. | 1535 // Return the number of bytes available on the free list. |
| 1524 intptr_t available() { | 1536 intptr_t available() { |
| 1525 return small_list_.available() + medium_list_.available() + | 1537 return small_list_.available() + medium_list_.available() + |
| 1526 large_list_.available() + huge_list_.available(); | 1538 large_list_.available() + huge_list_.available(); |
| 1527 } | 1539 } |
| 1528 | 1540 |
| 1541 enum AllocationStrategy { |
| 1542 BEST_FIT, |
| 1543 WORST_FIT |
| 1544 }; |
| 1545 |
| 1529 // Place a node on the free list. The block of size 'size_in_bytes' | 1546 // Place a node on the free list. The block of size 'size_in_bytes' |
| 1530 // starting at 'start' is placed on the free list. The return value is the | 1547 // starting at 'start' is placed on the free list. The return value is the |
| 1531 // number of bytes that have been lost due to internal fragmentation by | 1548 // number of bytes that have been lost due to internal fragmentation by |
| 1532 // freeing the block. Bookkeeping information will be written to the block, | 1549 // freeing the block. Bookkeeping information will be written to the block, |
| 1533 // i.e., its contents will be destroyed. The start address should be word | 1550 // i.e., its contents will be destroyed. The start address should be word |
| 1534 // aligned, and the size should be a non-zero multiple of the word size. | 1551 // aligned, and the size should be a non-zero multiple of the word size. |
| 1535 int Free(Address start, int size_in_bytes); | 1552 int Free(Address start, int size_in_bytes); |
| 1536 | 1553 |
| 1537 // Allocate a block of size 'size_in_bytes' from the free list. The block | 1554 // Allocate a block of size 'size_in_bytes' from the free list. The block |
| 1538 // is unitialized. A failure is returned if no block is available. The | 1555 // is unitialized. A failure is returned if no block is available. The |
| 1539 // number of bytes lost to fragmentation is returned in the output parameter | 1556 // number of bytes lost to fragmentation is returned in the output parameter |
| 1540 // 'wasted_bytes'. The size should be a non-zero multiple of the word size. | 1557 // 'wasted_bytes'. The size should be a non-zero multiple of the word size. |
| 1558 template<AllocationStrategy strategy> |
| 1541 MUST_USE_RESULT HeapObject* Allocate(int size_in_bytes); | 1559 MUST_USE_RESULT HeapObject* Allocate(int size_in_bytes); |
| 1542 | 1560 |
| 1543 #ifdef DEBUG | 1561 #ifdef DEBUG |
| 1544 void Zap(); | 1562 void Zap(); |
| 1545 intptr_t SumFreeLists(); | 1563 intptr_t SumFreeLists(); |
| 1546 bool IsVeryLong(); | 1564 bool IsVeryLong(); |
| 1547 #endif | 1565 #endif |
| 1548 | 1566 |
| 1549 // Used after booting the VM. | 1567 // Used after booting the VM. |
| 1550 void RepairLists(Heap* heap); | 1568 void RepairLists(Heap* heap); |
| 1551 | 1569 |
| 1552 intptr_t EvictFreeListItems(Page* p); | 1570 intptr_t EvictFreeListItems(Page* p); |
| 1553 | 1571 |
| 1554 FreeListCategory* small_list() { return &small_list_; } | 1572 FreeListCategory* small_list() { return &small_list_; } |
| 1555 FreeListCategory* medium_list() { return &medium_list_; } | 1573 FreeListCategory* medium_list() { return &medium_list_; } |
| 1556 FreeListCategory* large_list() { return &large_list_; } | 1574 FreeListCategory* large_list() { return &large_list_; } |
| 1557 FreeListCategory* huge_list() { return &huge_list_; } | 1575 FreeListCategory* huge_list() { return &huge_list_; } |
| 1558 | 1576 |
| 1559 private: | 1577 private: |
| 1560 // The size range of blocks, in bytes. | 1578 // The size range of blocks, in bytes. |
| 1561 static const int kMinBlockSize = 3 * kPointerSize; | 1579 static const int kMinBlockSize = 3 * kPointerSize; |
| 1562 static const int kMaxBlockSize = Page::kMaxNonCodeHeapObjectSize; | 1580 static const int kMaxBlockSize = Page::kMaxNonCodeHeapObjectSize; |
| 1563 | 1581 |
| 1564 FreeListNode* FindNodeFor(int size_in_bytes, int* node_size); | 1582 FreeListNode* FindNodeInHugeList(int size_in_bytes, int* node_size); |
| 1583 |
| 1584 // Finds a node in the free-list using the best-fit allocation strategy. |
| 1585 FreeListNode* FindNodeForBestFit(int size_in_bytes, int* node_size); |
| 1586 |
| 1587 // Finds a node in the free-list using the worst-fit allocation strategy |
| 1588 // and it ignores the smallest category. |
| 1589 FreeListNode* FindNodeForWorstFit(int size_in_bytes, int* node_size); |
| 1565 | 1590 |
| 1566 PagedSpace* owner_; | 1591 PagedSpace* owner_; |
| 1567 Heap* heap_; | 1592 Heap* heap_; |
| 1568 | 1593 |
| 1569 static const int kSmallListMin = 0x20 * kPointerSize; | 1594 static const int kSmallListMin = 0x20 * kPointerSize; |
| 1570 static const int kSmallListMax = 0xff * kPointerSize; | 1595 static const int kSmallListMax = 0xff * kPointerSize; |
| 1571 static const int kMediumListMax = 0x7ff * kPointerSize; | 1596 static const int kMediumListMax = 0x7ff * kPointerSize; |
| 1572 static const int kLargeListMax = 0x3fff * kPointerSize; | 1597 static const int kLargeListMax = 0x3fff * kPointerSize; |
| 1573 static const int kSmallAllocationMax = kSmallListMin - kPointerSize; | 1598 static const int kSmallAllocationMax = kSmallListMin - kPointerSize; |
| 1574 static const int kMediumAllocationMax = kSmallListMax; | 1599 static const int kMediumAllocationMax = kSmallListMax; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1666 // The bytes in the linear allocation area are not included in this total | 1691 // The bytes in the linear allocation area are not included in this total |
| 1667 // because updating the stats would slow down allocation. New pages are | 1692 // because updating the stats would slow down allocation. New pages are |
| 1668 // immediately added to the free list so they show up here. | 1693 // immediately added to the free list so they show up here. |
| 1669 intptr_t Available() { return free_list_.available(); } | 1694 intptr_t Available() { return free_list_.available(); } |
| 1670 | 1695 |
| 1671 // Allocated bytes in this space. Garbage bytes that were not found due to | 1696 // Allocated bytes in this space. Garbage bytes that were not found due to |
| 1672 // lazy sweeping are counted as being allocated! The bytes in the current | 1697 // lazy sweeping are counted as being allocated! The bytes in the current |
| 1673 // linear allocation area (between top and limit) are also counted here. | 1698 // linear allocation area (between top and limit) are also counted here. |
| 1674 virtual intptr_t Size() { return accounting_stats_.Size(); } | 1699 virtual intptr_t Size() { return accounting_stats_.Size(); } |
| 1675 | 1700 |
| 1701 intptr_t Pretenure() { return accounting_stats_.Pretenure(); } |
| 1702 |
| 1676 // As size, but the bytes in lazily swept pages are estimated and the bytes | 1703 // As size, but the bytes in lazily swept pages are estimated and the bytes |
| 1677 // in the current linear allocation area are not included. | 1704 // in the current linear allocation area are not included. |
| 1678 virtual intptr_t SizeOfObjects(); | 1705 virtual intptr_t SizeOfObjects(); |
| 1679 | 1706 |
| 1680 // Wasted bytes in this space. These are just the bytes that were thrown away | 1707 // Wasted bytes in this space. These are just the bytes that were thrown away |
| 1681 // due to being too small to use for allocation. They do not include the | 1708 // due to being too small to use for allocation. They do not include the |
| 1682 // free bytes that were not found at all due to lazy sweeping. | 1709 // free bytes that were not found at all due to lazy sweeping. |
| 1683 virtual intptr_t Waste() { return accounting_stats_.Waste(); } | 1710 virtual intptr_t Waste() { return accounting_stats_.Waste(); } |
| 1684 | 1711 |
| 1685 // Returns the allocation pointer in this space. | 1712 // Returns the allocation pointer in this space. |
| 1686 Address top() { return allocation_info_.top; } | 1713 Address top() { return allocation_info_.top; } |
| 1687 Address limit() { return allocation_info_.limit; } | 1714 Address limit() { return allocation_info_.limit; } |
| 1688 | 1715 |
| 1689 // The allocation top and limit addresses. | 1716 // The allocation top and limit addresses. |
| 1690 Address* allocation_top_address() { return &allocation_info_.top; } | 1717 Address* allocation_top_address() { return &allocation_info_.top; } |
| 1691 Address* allocation_limit_address() { return &allocation_info_.limit; } | 1718 Address* allocation_limit_address() { return &allocation_info_.limit; } |
| 1692 | 1719 |
| 1693 // Allocate the requested number of bytes in the space if possible, return a | 1720 // Allocate the requested number of bytes in the space if possible, return a |
| 1694 // failure object if not. | 1721 // failure object if not. |
| 1722 template<FreeList::AllocationStrategy strategy> |
| 1695 MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes); | 1723 MUST_USE_RESULT inline MaybeObject* AllocateRaw(int size_in_bytes); |
| 1696 | 1724 |
| 1697 virtual bool ReserveSpace(int bytes); | 1725 virtual bool ReserveSpace(int bytes); |
| 1698 | 1726 |
| 1699 // Give a block of memory to the space's free list. It might be added to | 1727 // Give a block of memory to the space's free list. It might be added to |
| 1700 // the free list or accounted as waste. | 1728 // the free list or accounted as waste. |
| 1701 // If add_to_freelist is false then just accounting stats are updated and | 1729 // If add_to_freelist is false then just accounting stats are updated and |
| 1702 // no attempt to add area to free list is made. | 1730 // no attempt to add area to free list is made. |
| 1703 int Free(Address start, int size_in_bytes) { | 1731 int Free(Address start, int size_in_bytes) { |
| 1704 int wasted = free_list_.Free(start, size_in_bytes); | 1732 int wasted = free_list_.Free(start, size_in_bytes); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1716 Page::FromAddress(top) == Page::FromAddress(limit - 1)); | 1744 Page::FromAddress(top) == Page::FromAddress(limit - 1)); |
| 1717 MemoryChunk::UpdateHighWaterMark(allocation_info_.top); | 1745 MemoryChunk::UpdateHighWaterMark(allocation_info_.top); |
| 1718 allocation_info_.top = top; | 1746 allocation_info_.top = top; |
| 1719 allocation_info_.limit = limit; | 1747 allocation_info_.limit = limit; |
| 1720 } | 1748 } |
| 1721 | 1749 |
| 1722 void Allocate(int bytes) { | 1750 void Allocate(int bytes) { |
| 1723 accounting_stats_.AllocateBytes(bytes); | 1751 accounting_stats_.AllocateBytes(bytes); |
| 1724 } | 1752 } |
| 1725 | 1753 |
| 1754 void AllocatePretenure(int bytes) { |
| 1755 accounting_stats_.AllocatePretenureBytes(bytes); |
| 1756 } |
| 1757 |
| 1726 void IncreaseCapacity(int size) { | 1758 void IncreaseCapacity(int size) { |
| 1727 accounting_stats_.ExpandSpace(size); | 1759 accounting_stats_.ExpandSpace(size); |
| 1728 } | 1760 } |
| 1729 | 1761 |
| 1730 // Releases an unused page and shrinks the space. | 1762 // Releases an unused page and shrinks the space. |
| 1731 void ReleasePage(Page* page, bool unlink); | 1763 void ReleasePage(Page* page, bool unlink); |
| 1732 | 1764 |
| 1733 // The dummy page that anchors the linked list of pages. | 1765 // The dummy page that anchors the linked list of pages. |
| 1734 Page* anchor() { return &anchor_; } | 1766 Page* anchor() { return &anchor_; } |
| 1735 | 1767 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1862 // Expands the space by allocating a fixed number of pages. Returns false if | 1894 // Expands the space by allocating a fixed number of pages. Returns false if |
| 1863 // it cannot allocate requested number of pages from OS, or if the hard heap | 1895 // it cannot allocate requested number of pages from OS, or if the hard heap |
| 1864 // size limit has been hit. | 1896 // size limit has been hit. |
| 1865 bool Expand(); | 1897 bool Expand(); |
| 1866 | 1898 |
| 1867 // Generic fast case allocation function that tries linear allocation at the | 1899 // Generic fast case allocation function that tries linear allocation at the |
| 1868 // address denoted by top in allocation_info_. | 1900 // address denoted by top in allocation_info_. |
| 1869 inline HeapObject* AllocateLinearly(int size_in_bytes); | 1901 inline HeapObject* AllocateLinearly(int size_in_bytes); |
| 1870 | 1902 |
| 1871 // Slow path of AllocateRaw. This function is space-dependent. | 1903 // Slow path of AllocateRaw. This function is space-dependent. |
| 1872 MUST_USE_RESULT virtual HeapObject* SlowAllocateRaw(int size_in_bytes); | 1904 template<FreeList::AllocationStrategy strategy> |
| 1905 MUST_USE_RESULT HeapObject* SlowAllocateRaw(int size_in_bytes); |
| 1873 | 1906 |
| 1874 friend class PageIterator; | 1907 friend class PageIterator; |
| 1875 friend class SweeperThread; | 1908 friend class SweeperThread; |
| 1876 }; | 1909 }; |
| 1877 | 1910 |
| 1878 | 1911 |
| 1879 class NumberAndSizeInfo BASE_EMBEDDED { | 1912 class NumberAndSizeInfo BASE_EMBEDDED { |
| 1880 public: | 1913 public: |
| 1881 NumberAndSizeInfo() : number_(0), bytes_(0) {} | 1914 NumberAndSizeInfo() : number_(0), bytes_(0) {} |
| 1882 | 1915 |
| (...skipping 962 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2845 } | 2878 } |
| 2846 // Must be small, since an iteration is used for lookup. | 2879 // Must be small, since an iteration is used for lookup. |
| 2847 static const int kMaxComments = 64; | 2880 static const int kMaxComments = 64; |
| 2848 }; | 2881 }; |
| 2849 #endif | 2882 #endif |
| 2850 | 2883 |
| 2851 | 2884 |
| 2852 } } // namespace v8::internal | 2885 } } // namespace v8::internal |
| 2853 | 2886 |
| 2854 #endif // V8_SPACES_H_ | 2887 #endif // V8_SPACES_H_ |
| OLD | NEW |