OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_HEAP_SPACES_H_ | 5 #ifndef V8_HEAP_SPACES_H_ |
6 #define V8_HEAP_SPACES_H_ | 6 #define V8_HEAP_SPACES_H_ |
7 | 7 |
8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
9 #include "src/atomic-utils.h" | 9 #include "src/atomic-utils.h" |
10 #include "src/base/atomicops.h" | 10 #include "src/base/atomicops.h" |
11 #include "src/base/bits.h" | 11 #include "src/base/bits.h" |
12 #include "src/base/platform/mutex.h" | 12 #include "src/base/platform/mutex.h" |
13 #include "src/flags.h" | 13 #include "src/flags.h" |
14 #include "src/hashmap.h" | 14 #include "src/hashmap.h" |
15 #include "src/list.h" | 15 #include "src/list.h" |
16 #include "src/objects.h" | 16 #include "src/objects.h" |
17 #include "src/utils.h" | 17 #include "src/utils.h" |
18 | 18 |
19 namespace v8 { | 19 namespace v8 { |
20 namespace internal { | 20 namespace internal { |
21 | 21 |
22 class CompactionSpaceCollection; | |
22 class Isolate; | 23 class Isolate; |
23 | 24 |
24 // ----------------------------------------------------------------------------- | 25 // ----------------------------------------------------------------------------- |
25 // Heap structures: | 26 // Heap structures: |
26 // | 27 // |
27 // A JS heap consists of a young generation, an old generation, and a large | 28 // A JS heap consists of a young generation, an old generation, and a large |
28 // object space. The young generation is divided into two semispaces. A | 29 // object space. The young generation is divided into two semispaces. A |
29 // scavenger implements Cheney's copying algorithm. The old generation is | 30 // scavenger implements Cheney's copying algorithm. The old generation is |
30 // separated into a map space and an old object space. The map space contains | 31 // separated into a map space and an old object space. The map space contains |
31 // all (and only) map objects, the rest of old objects go into the old space. | 32 // all (and only) map objects, the rest of old objects go into the old space. |
(...skipping 1404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1436 class AllocationStats BASE_EMBEDDED { | 1437 class AllocationStats BASE_EMBEDDED { |
1437 public: | 1438 public: |
1438 AllocationStats() { Clear(); } | 1439 AllocationStats() { Clear(); } |
1439 | 1440 |
1440 // Zero out all the allocation statistics (i.e., no capacity). | 1441 // Zero out all the allocation statistics (i.e., no capacity). |
1441 void Clear() { | 1442 void Clear() { |
1442 capacity_ = 0; | 1443 capacity_ = 0; |
1443 max_capacity_ = 0; | 1444 max_capacity_ = 0; |
1444 size_ = 0; | 1445 size_ = 0; |
1445 waste_ = 0; | 1446 waste_ = 0; |
1447 borrowed_ = 0; | |
1446 } | 1448 } |
1447 | 1449 |
1448 void ClearSizeWaste() { | 1450 void ClearSizeWaste() { |
1449 size_ = capacity_; | 1451 size_ = capacity_; |
1450 waste_ = 0; | 1452 waste_ = 0; |
1451 } | 1453 } |
1452 | 1454 |
1453 // Reset the allocation statistics (i.e., available = capacity with no | 1455 // Reset the allocation statistics (i.e., available = capacity with no |
1454 // wasted or allocated bytes). | 1456 // wasted or allocated bytes). |
1455 void Reset() { | 1457 void Reset() { |
1456 size_ = 0; | 1458 size_ = 0; |
1457 waste_ = 0; | 1459 waste_ = 0; |
1458 } | 1460 } |
1459 | 1461 |
1460 // Accessors for the allocation statistics. | 1462 // Accessors for the allocation statistics. |
1461 intptr_t Capacity() { return capacity_; } | 1463 intptr_t Capacity() { return capacity_; } |
1462 intptr_t MaxCapacity() { return max_capacity_; } | 1464 intptr_t MaxCapacity() { return max_capacity_; } |
1463 intptr_t Size() { return size_; } | 1465 intptr_t Size() { return size_; } |
1464 intptr_t Waste() { return waste_; } | 1466 intptr_t Waste() { return waste_; } |
1467 intptr_t Borrowed() { return borrowed_; } | |
1465 | 1468 |
1466 // Grow the space by adding available bytes. They are initially marked as | 1469 // Grow the space by adding available bytes. They are initially marked as |
1467 // being in use (part of the size), but will normally be immediately freed, | 1470 // being in use (part of the size), but will normally be immediately freed, |
1468 // putting them on the free list and removing them from size_. | 1471 // putting them on the free list and removing them from size_. |
1469 void ExpandSpace(int size_in_bytes) { | 1472 void ExpandSpace(int size_in_bytes) { |
1470 capacity_ += size_in_bytes; | 1473 capacity_ += size_in_bytes; |
1471 size_ += size_in_bytes; | 1474 size_ += size_in_bytes; |
1472 if (capacity_ > max_capacity_) { | 1475 if (capacity_ > max_capacity_) { |
1473 max_capacity_ = capacity_; | 1476 max_capacity_ = capacity_; |
1474 } | 1477 } |
1475 DCHECK(size_ >= 0); | 1478 DCHECK(size_ >= 0); |
1476 } | 1479 } |
1477 | 1480 |
1478 // Shrink the space by removing available bytes. Since shrinking is done | 1481 // Shrink the space by removing available bytes. Since shrinking is done |
1479 // during sweeping, bytes have been marked as being in use (part of the size) | 1482 // during sweeping, bytes have been marked as being in use (part of the size) |
1480 // and are hereby freed. | 1483 // and are hereby freed. |
1481 void ShrinkSpace(int size_in_bytes) { | 1484 void ShrinkSpace(int size_in_bytes) { |
1485 DCHECK_GE(size_in_bytes, 0); | |
1482 capacity_ -= size_in_bytes; | 1486 capacity_ -= size_in_bytes; |
1483 size_ -= size_in_bytes; | 1487 size_ -= size_in_bytes; |
1484 DCHECK(size_ >= 0); | 1488 DCHECK_GE(size_, 0); |
1489 DCHECK_GE(capacity_, 0); | |
1485 } | 1490 } |
1486 | 1491 |
1487 // Allocate from available bytes (available -> size). | 1492 // Allocate from available bytes (available -> size). |
1488 void AllocateBytes(intptr_t size_in_bytes) { | 1493 void AllocateBytes(intptr_t size_in_bytes) { |
1494 DCHECK_GE(size_in_bytes, 0); | |
1489 size_ += size_in_bytes; | 1495 size_ += size_in_bytes; |
1490 DCHECK(size_ >= 0); | 1496 DCHECK_GE(size_, 0); |
1497 DCHECK_LE(size_, capacity_); | |
1491 } | 1498 } |
1492 | 1499 |
1493 // Free allocated bytes, making them available (size -> available). | 1500 // Free allocated bytes, making them available (size -> available). |
1494 void DeallocateBytes(intptr_t size_in_bytes) { | 1501 void DeallocateBytes(intptr_t size_in_bytes) { |
1495 size_ -= size_in_bytes; | 1502 size_ -= size_in_bytes; |
1496 DCHECK(size_ >= 0); | 1503 DCHECK(size_ >= 0); |
1497 } | 1504 } |
1498 | 1505 |
1499 // Waste free bytes (available -> waste). | 1506 // Waste free bytes (available -> waste). |
1500 void WasteBytes(int size_in_bytes) { | 1507 void WasteBytes(int size_in_bytes) { |
1501 DCHECK(size_in_bytes >= 0); | 1508 DCHECK(size_in_bytes >= 0); |
1502 waste_ += size_in_bytes; | 1509 waste_ += size_in_bytes; |
1503 } | 1510 } |
1504 | 1511 |
1505 // Merge {other} into {this}. | 1512 // Merge {other} into {this}. |
1506 void Merge(const AllocationStats& other) { | 1513 void Merge(const AllocationStats& other) { |
Hannes Payer (out of office)
2015/09/25 13:15:59
Why don't you reset the borrowed counter?
Michael Lippautz
2015/09/25 13:28:50
The caller needs to make sure that the counters ar
| |
1514 DCHECK_GE(other.capacity_, 0); | |
1515 DCHECK_GE(other.size_, 0); | |
1516 DCHECK_GE(other.waste_, 0); | |
1507 capacity_ += other.capacity_; | 1517 capacity_ += other.capacity_; |
1508 size_ += other.size_; | 1518 size_ += other.size_; |
1519 // Since borrowed memory is accounted as capacity by the space borrowing it, | |
1520 // we need to account for this when merging the stats. | |
1521 capacity_ -= other.borrowed_; | |
Hannes Payer (out of office)
2015/09/25 13:15:59
Why do you subtract it from both? Can you explain
Michael Lippautz
2015/09/25 13:28:50
The reason is:
- The borrowed amount is accounted
Hannes Payer (out of office)
2015/09/25 14:11:07
This is really complicated. Can you make your comm
Michael Lippautz
2015/09/25 14:31:39
I added some more explanation to the actual member
| |
1522 size_ -= other.borrowed_; | |
1509 waste_ += other.waste_; | 1523 waste_ += other.waste_; |
1510 if (other.max_capacity_ > max_capacity_) { | 1524 if (capacity_ > max_capacity_) { |
1511 max_capacity_ = other.max_capacity_; | 1525 max_capacity_ = capacity_; |
1512 } | 1526 } |
1513 } | 1527 } |
1514 | 1528 |
1515 void DecreaseCapacity(intptr_t size_in_bytes) { | 1529 void DecreaseCapacity(intptr_t size_in_bytes) { |
1530 DCHECK_GE(size_in_bytes, 0); | |
1516 capacity_ -= size_in_bytes; | 1531 capacity_ -= size_in_bytes; |
1517 DCHECK_GE(capacity_, 0); | 1532 DCHECK_GE(capacity_, 0); |
Hannes Payer (out of office)
2015/09/25 13:04:51
DCHECK_GE(capacity_, 0); is not needed.
Michael Lippautz
2015/09/25 13:28:50
Done.
| |
1533 DCHECK_GE(capacity_, size_); | |
1518 } | 1534 } |
1519 | 1535 |
1520 void IncreaseCapacity(intptr_t size_in_bytes) { capacity_ += size_in_bytes; } | 1536 void IncreaseCapacity(intptr_t size_in_bytes) { |
1537 DCHECK_GE(size_in_bytes, 0); | |
1538 capacity_ += size_in_bytes; | |
1539 } | |
1540 | |
1541 void BorrowMemory(intptr_t size_in_bytes) { | |
1542 DCHECK_GE(size_in_bytes, 0); | |
1543 borrowed_ += size_in_bytes; | |
1544 } | |
1521 | 1545 |
1522 private: | 1546 private: |
1523 intptr_t capacity_; | 1547 intptr_t capacity_; |
Hannes Payer (out of office)
2015/09/25 13:04:51
Can you add comments that explain these variables?
Michael Lippautz
2015/09/25 13:28:50
The variables are explained on top of the class. S
Hannes Payer (out of office)
2015/09/25 14:11:07
No, that is fine. An explanation of borrowed_ is m
Michael Lippautz
2015/09/25 14:31:39
Changed my mind on this. I moved the descriptions
| |
1524 intptr_t max_capacity_; | 1548 intptr_t max_capacity_; |
1525 intptr_t size_; | 1549 intptr_t size_; |
1526 intptr_t waste_; | 1550 intptr_t waste_; |
1551 intptr_t borrowed_; | |
1527 }; | 1552 }; |
1528 | 1553 |
1529 | 1554 |
1530 // ----------------------------------------------------------------------------- | 1555 // ----------------------------------------------------------------------------- |
1531 // Free lists for old object spaces | 1556 // Free lists for old object spaces |
1532 | 1557 |
1533 // The free list category holds a pointer to the top element and a pointer to | 1558 // The free list category holds a pointer to the top element and a pointer to |
1534 // the end element of the linked list of free memory blocks. | 1559 // the end element of the linked list of free memory blocks. |
1535 class FreeListCategory { | 1560 class FreeListCategory { |
1536 public: | 1561 public: |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1675 bool ContainsPageFreeListItems(Page* p); | 1700 bool ContainsPageFreeListItems(Page* p); |
1676 | 1701 |
1677 FreeListCategory* small_list() { return &small_list_; } | 1702 FreeListCategory* small_list() { return &small_list_; } |
1678 FreeListCategory* medium_list() { return &medium_list_; } | 1703 FreeListCategory* medium_list() { return &medium_list_; } |
1679 FreeListCategory* large_list() { return &large_list_; } | 1704 FreeListCategory* large_list() { return &large_list_; } |
1680 FreeListCategory* huge_list() { return &huge_list_; } | 1705 FreeListCategory* huge_list() { return &huge_list_; } |
1681 | 1706 |
1682 PagedSpace* owner() { return owner_; } | 1707 PagedSpace* owner() { return owner_; } |
1683 | 1708 |
1684 private: | 1709 private: |
1710 enum FreeListCategoryType { kSmall, kMedium, kLarge, kHuge }; | |
1711 | |
1685 // The size range of blocks, in bytes. | 1712 // The size range of blocks, in bytes. |
1686 static const int kMinBlockSize = 3 * kPointerSize; | 1713 static const int kMinBlockSize = 3 * kPointerSize; |
1687 static const int kMaxBlockSize = Page::kMaxRegularHeapObjectSize; | 1714 static const int kMaxBlockSize = Page::kMaxRegularHeapObjectSize; |
1688 | 1715 |
1689 static const int kSmallListMin = 0x1f * kPointerSize; | 1716 static const int kSmallListMin = 0x1f * kPointerSize; |
1690 static const int kSmallListMax = 0xff * kPointerSize; | 1717 static const int kSmallListMax = 0xff * kPointerSize; |
1691 static const int kMediumListMax = 0x7ff * kPointerSize; | 1718 static const int kMediumListMax = 0x7ff * kPointerSize; |
1692 static const int kLargeListMax = 0x3fff * kPointerSize; | 1719 static const int kLargeListMax = 0x3fff * kPointerSize; |
1693 static const int kSmallAllocationMax = kSmallListMin; | 1720 static const int kSmallAllocationMax = kSmallListMin; |
1694 static const int kMediumAllocationMax = kSmallListMax; | 1721 static const int kMediumAllocationMax = kSmallListMax; |
1695 static const int kLargeAllocationMax = kMediumListMax; | 1722 static const int kLargeAllocationMax = kMediumListMax; |
1696 | 1723 |
1697 FreeSpace* FindNodeFor(int size_in_bytes, int* node_size); | 1724 FreeSpace* FindNodeFor(int size_in_bytes, int* node_size); |
1725 FreeSpace* FindNodeIn(FreeListCategoryType category, int* node_size); | |
1726 | |
1727 FreeListCategory* GetFreeListCategory(FreeListCategoryType category) { | |
1728 switch (category) { | |
1729 case kSmall: | |
1730 return &small_list_; | |
1731 case kMedium: | |
1732 return &medium_list_; | |
1733 case kLarge: | |
1734 return &large_list_; | |
1735 case kHuge: | |
1736 return &huge_list_; | |
1737 default: | |
1738 UNREACHABLE(); | |
1739 } | |
1740 UNREACHABLE(); | |
1741 return nullptr; | |
1742 } | |
1743 | |
1744 void UpdateFragmentationStats(FreeListCategoryType category, Address address, | |
1745 int size); | |
1698 | 1746 |
1699 PagedSpace* owner_; | 1747 PagedSpace* owner_; |
1700 Heap* heap_; | 1748 Heap* heap_; |
1701 FreeListCategory small_list_; | 1749 FreeListCategory small_list_; |
1702 FreeListCategory medium_list_; | 1750 FreeListCategory medium_list_; |
1703 FreeListCategory large_list_; | 1751 FreeListCategory large_list_; |
1704 FreeListCategory huge_list_; | 1752 FreeListCategory huge_list_; |
1705 | 1753 |
1754 friend class PagedSpace; | |
1755 | |
1706 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeList); | 1756 DISALLOW_IMPLICIT_CONSTRUCTORS(FreeList); |
1707 }; | 1757 }; |
1708 | 1758 |
1709 | 1759 |
1710 class AllocationResult { | 1760 class AllocationResult { |
1711 public: | 1761 public: |
1712 // Implicit constructor from Object*. | 1762 // Implicit constructor from Object*. |
1713 AllocationResult(Object* object) // NOLINT | 1763 AllocationResult(Object* object) // NOLINT |
1714 : object_(object) { | 1764 : object_(object) { |
1715 // AllocationResults can't return Smis, which are used to represent | 1765 // AllocationResults can't return Smis, which are used to represent |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1978 inline int AreaSize() { return area_size_; } | 2028 inline int AreaSize() { return area_size_; } |
1979 | 2029 |
1980 // Merges {other} into the current space. Note that this modifies {other}, | 2030 // Merges {other} into the current space. Note that this modifies {other}, |
1981 // e.g., removes its bump pointer area and resets statistics. | 2031 // e.g., removes its bump pointer area and resets statistics. |
1982 void MergeCompactionSpace(CompactionSpace* other); | 2032 void MergeCompactionSpace(CompactionSpace* other); |
1983 | 2033 |
1984 void MoveOverFreeMemory(PagedSpace* other); | 2034 void MoveOverFreeMemory(PagedSpace* other); |
1985 | 2035 |
1986 virtual bool is_local() { return false; } | 2036 virtual bool is_local() { return false; } |
1987 | 2037 |
2038 // Divide {this} free lists up among {other} CompactionSpaceCollections | |
2039 // up to some certain {limit} of bytes. Note that this operation eventually | |
2040 // needs to iterate over nodes one-by-one, making it a potentially slow | |
2041 // operation. | |
2042 void DivideMemory(CompactionSpaceCollection** other, int num, intptr_t limit); | |
2043 | |
1988 protected: | 2044 protected: |
2045 // Adds memory starting at {start} of {size_in_bytes} to the space. | |
2046 void AddMemory(Address start, int size_in_bytes) { | |
2047 IncreaseCapacity(size_in_bytes); | |
2048 accounting_stats_.BorrowMemory(size_in_bytes); | |
2049 Free(start, size_in_bytes); | |
2050 } | |
2051 | |
2052 // Tries to remove some memory from {this} free lists. We try to remove | |
2053 // as much memory as possible, i.e., we check the free lists from huge | |
2054 // to small. | |
2055 FreeSpace* TryRemoveMemory(); | |
2056 | |
1989 // PagedSpaces that should be included in snapshots have different, i.e., | 2057 // PagedSpaces that should be included in snapshots have different, i.e., |
1990 // smaller, initial pages. | 2058 // smaller, initial pages. |
1991 virtual bool snapshotable() { return true; } | 2059 virtual bool snapshotable() { return true; } |
1992 | 2060 |
1993 FreeList* free_list() { return &free_list_; } | 2061 FreeList* free_list() { return &free_list_; } |
1994 | 2062 |
1995 bool HasPages() { return anchor_.next_page() != &anchor_; } | 2063 bool HasPages() { return anchor_.next_page() != &anchor_; } |
1996 | 2064 |
1997 // Cleans up the space, frees all pages in this space except those belonging | 2065 // Cleans up the space, frees all pages in this space except those belonging |
1998 // to the initial chunk, uncommits addresses in the initial chunk. | 2066 // to the initial chunk, uncommits addresses in the initial chunk. |
(...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2718 | 2786 |
2719 HistogramInfo* allocated_histogram_; | 2787 HistogramInfo* allocated_histogram_; |
2720 HistogramInfo* promoted_histogram_; | 2788 HistogramInfo* promoted_histogram_; |
2721 | 2789 |
2722 bool EnsureAllocation(int size_in_bytes, AllocationAlignment alignment); | 2790 bool EnsureAllocation(int size_in_bytes, AllocationAlignment alignment); |
2723 | 2791 |
2724 // If we are doing inline allocation in steps, this method performs the 'step' | 2792 // If we are doing inline allocation in steps, this method performs the 'step' |
2725 // operation. Right now incremental marking is the only consumer of inline | 2793 // operation. Right now incremental marking is the only consumer of inline |
2726 // allocation steps. top is the memory address of the bump pointer at the last | 2794 // allocation steps. top is the memory address of the bump pointer at the last |
2727 // inline allocation (i.e. it determines the numbers of bytes actually | 2795 // inline allocation (i.e. it determines the numbers of bytes actually |
2728 // allocated since the last step.) new_top is the address of the bump pointer | 2796 // allocated since the last step.) new_top is the address of the bump pointer |
Hannes Payer (out of office)
2015/09/25 13:04:51
This is not from your cl.
Michael Lippautz
2015/09/25 13:28:50
Ack. The baseline did not contain the fixes. Sorry
| |
2729 // where the next byte is going to be allocated from. top and new_top may be | 2797 // where the next byte is going to be allocated from. top and new_top may be |
2730 // different when we cross a page boundary or reset the space. | 2798 // different when we cross a page boundary or reset the space. |
2731 void InlineAllocationStep(Address top, Address new_top); | 2799 void InlineAllocationStep(Address top, Address new_top); |
2732 | 2800 |
2733 friend class SemiSpaceIterator; | 2801 friend class SemiSpaceIterator; |
2734 }; | 2802 }; |
2735 | 2803 |
2736 // ----------------------------------------------------------------------------- | 2804 // ----------------------------------------------------------------------------- |
2737 // Compaction space that is used temporarily during compaction. | 2805 // Compaction space that is used temporarily during compaction. |
2738 | 2806 |
2739 class CompactionSpace : public PagedSpace { | 2807 class CompactionSpace : public PagedSpace { |
2740 public: | 2808 public: |
2741 CompactionSpace(Heap* heap, AllocationSpace id, Executability executable) | 2809 CompactionSpace(Heap* heap, AllocationSpace id, Executability executable) |
2742 : PagedSpace(heap, id, executable) {} | 2810 : PagedSpace(heap, id, executable) {} |
2743 | 2811 |
2744 // Adds external memory starting at {start} of {size_in_bytes} to the space. | |
2745 void AddExternalMemory(Address start, int size_in_bytes) { | |
2746 IncreaseCapacity(size_in_bytes); | |
2747 Free(start, size_in_bytes); | |
2748 } | |
2749 | |
2750 virtual bool is_local() { return true; } | 2812 virtual bool is_local() { return true; } |
2751 | 2813 |
2752 protected: | 2814 protected: |
2753 // The space is temporary and not included in any snapshots. | 2815 // The space is temporary and not included in any snapshots. |
2754 virtual bool snapshotable() { return false; } | 2816 virtual bool snapshotable() { return false; } |
2755 }; | 2817 }; |
2756 | 2818 |
2757 | 2819 |
2758 // A collection of |CompactionSpace|s used by a single compaction task. | 2820 // A collection of |CompactionSpace|s used by a single compaction task. |
2759 class CompactionSpaceCollection : public Malloced { | 2821 class CompactionSpaceCollection : public Malloced { |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2975 count = 0; | 3037 count = 0; |
2976 } | 3038 } |
2977 // Must be small, since an iteration is used for lookup. | 3039 // Must be small, since an iteration is used for lookup. |
2978 static const int kMaxComments = 64; | 3040 static const int kMaxComments = 64; |
2979 }; | 3041 }; |
2980 #endif | 3042 #endif |
2981 } | 3043 } |
2982 } // namespace v8::internal | 3044 } // namespace v8::internal |
2983 | 3045 |
2984 #endif // V8_HEAP_SPACES_H_ | 3046 #endif // V8_HEAP_SPACES_H_ |
OLD | NEW |