| 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 AllocationInfo; | 22 class AllocationInfo; |
| 23 class AllocationObserver; | 23 class AllocationObserver; |
| 24 class CompactionSpace; | 24 class CompactionSpace; |
| 25 class CompactionSpaceCollection; | 25 class CompactionSpaceCollection; |
| 26 class FreeList; | 26 class FreeList; |
| 27 class Isolate; | 27 class Isolate; |
| 28 class MemoryAllocator; | 28 class MemoryAllocator; |
| 29 class MemoryChunk; | 29 class MemoryChunk; |
| 30 class NewSpacePage; | |
| 31 class Page; | 30 class Page; |
| 32 class PagedSpace; | 31 class PagedSpace; |
| 33 class SemiSpace; | 32 class SemiSpace; |
| 34 class SkipList; | 33 class SkipList; |
| 35 class SlotsBuffer; | 34 class SlotsBuffer; |
| 36 class SlotSet; | 35 class SlotSet; |
| 37 class TypedSlotSet; | 36 class TypedSlotSet; |
| 38 class Space; | 37 class Space; |
| 39 | 38 |
| 40 // ----------------------------------------------------------------------------- | 39 // ----------------------------------------------------------------------------- |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 NEVER_ALLOCATE_ON_PAGE, | 437 NEVER_ALLOCATE_ON_PAGE, |
| 439 | 438 |
| 440 // The memory chunk is already logically freed, however the actual freeing | 439 // The memory chunk is already logically freed, however the actual freeing |
| 441 // still has to be performed. | 440 // still has to be performed. |
| 442 PRE_FREED, | 441 PRE_FREED, |
| 443 | 442 |
| 444 // |COMPACTION_WAS_ABORTED|: Indicates that the compaction in this page | 443 // |COMPACTION_WAS_ABORTED|: Indicates that the compaction in this page |
| 445 // has been aborted and needs special handling by the sweeper. | 444 // has been aborted and needs special handling by the sweeper. |
| 446 COMPACTION_WAS_ABORTED, | 445 COMPACTION_WAS_ABORTED, |
| 447 | 446 |
| 447 // |ANCHOR|: Flag is set if page is an anchor. |
| 448 ANCHOR, |
| 449 |
| 448 // Last flag, keep at bottom. | 450 // Last flag, keep at bottom. |
| 449 NUM_MEMORY_CHUNK_FLAGS | 451 NUM_MEMORY_CHUNK_FLAGS |
| 450 }; | 452 }; |
| 451 | 453 |
| 452 // |kSweepingDone|: The page state when sweeping is complete or sweeping must | 454 // |kSweepingDone|: The page state when sweeping is complete or sweeping must |
| 453 // not be performed on that page. Sweeper threads that are done with their | 455 // not be performed on that page. Sweeper threads that are done with their |
| 454 // work will set this value and not touch the page anymore. | 456 // work will set this value and not touch the page anymore. |
| 455 // |kSweepingPending|: This page is ready for parallel sweeping. | 457 // |kSweepingPending|: This page is ready for parallel sweeping. |
| 456 // |kSweepingInProgress|: This page is currently swept by a sweeper thread. | 458 // |kSweepingInProgress|: This page is currently swept by a sweeper thread. |
| 457 enum ConcurrentSweepingState { | 459 enum ConcurrentSweepingState { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 static intptr_t OffsetInPage(Address a) { | 551 static intptr_t OffsetInPage(Address a) { |
| 550 return reinterpret_cast<intptr_t>(a) & kPageAlignmentMask; | 552 return reinterpret_cast<intptr_t>(a) & kPageAlignmentMask; |
| 551 } | 553 } |
| 552 | 554 |
| 553 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr); | 555 static inline MemoryChunk* FromAnyPointerAddress(Heap* heap, Address addr); |
| 554 | 556 |
| 555 static inline void UpdateHighWaterMark(Address mark) { | 557 static inline void UpdateHighWaterMark(Address mark) { |
| 556 if (mark == nullptr) return; | 558 if (mark == nullptr) return; |
| 557 // Need to subtract one from the mark because when a chunk is full the | 559 // Need to subtract one from the mark because when a chunk is full the |
| 558 // top points to the next address after the chunk, which effectively belongs | 560 // top points to the next address after the chunk, which effectively belongs |
| 559 // to another chunk. See the comment to Page::FromAllocationTop. | 561 // to another chunk. See the comment to Page::FromTopOrLimit. |
| 560 MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); | 562 MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1); |
| 561 intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address()); | 563 intptr_t new_mark = static_cast<intptr_t>(mark - chunk->address()); |
| 562 intptr_t old_mark = 0; | 564 intptr_t old_mark = 0; |
| 563 do { | 565 do { |
| 564 old_mark = chunk->high_water_mark_.Value(); | 566 old_mark = chunk->high_water_mark_.Value(); |
| 565 } while ((new_mark > old_mark) && | 567 } while ((new_mark > old_mark) && |
| 566 !chunk->high_water_mark_.TrySetValue(old_mark, new_mark)); | 568 !chunk->high_water_mark_.TrySetValue(old_mark, new_mark)); |
| 567 } | 569 } |
| 568 | 570 |
| 571 static bool IsValid(MemoryChunk* chunk) { return chunk != nullptr; } |
| 572 |
| 569 Address address() { return reinterpret_cast<Address>(this); } | 573 Address address() { return reinterpret_cast<Address>(this); } |
| 570 | 574 |
| 571 bool is_valid() { return address() != NULL; } | |
| 572 | |
| 573 base::Mutex* mutex() { return mutex_; } | 575 base::Mutex* mutex() { return mutex_; } |
| 574 | 576 |
| 575 bool Contains(Address addr) { | 577 bool Contains(Address addr) { |
| 576 return addr >= area_start() && addr < area_end(); | 578 return addr >= area_start() && addr < area_end(); |
| 577 } | 579 } |
| 578 | 580 |
| 579 // Checks whether |addr| can be a limit of addresses in this page. It's a | 581 // Checks whether |addr| can be a limit of addresses in this page. It's a |
| 580 // limit if it's in the page, or if it's just after the last byte of the page. | 582 // limit if it's in the page, or if it's just after the last byte of the page. |
| 581 bool ContainsLimit(Address addr) { | 583 bool ContainsLimit(Address addr) { |
| 582 return addr >= area_start() && addr <= area_end(); | 584 return addr >= area_start() && addr <= area_end(); |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 818 | 820 |
| 819 friend class MemoryAllocator; | 821 friend class MemoryAllocator; |
| 820 friend class MemoryChunkValidator; | 822 friend class MemoryChunkValidator; |
| 821 }; | 823 }; |
| 822 | 824 |
| 823 // ----------------------------------------------------------------------------- | 825 // ----------------------------------------------------------------------------- |
| 824 // A page is a memory chunk of a size 1MB. Large object pages may be larger. | 826 // A page is a memory chunk of a size 1MB. Large object pages may be larger. |
| 825 // | 827 // |
| 826 // The only way to get a page pointer is by calling factory methods: | 828 // The only way to get a page pointer is by calling factory methods: |
| 827 // Page* p = Page::FromAddress(addr); or | 829 // Page* p = Page::FromAddress(addr); or |
| 828 // Page* p = Page::FromAllocationTop(top); | 830 // Page* p = Page::FromTopOrLimit(top); |
| 829 class Page : public MemoryChunk { | 831 class Page : public MemoryChunk { |
| 830 public: | 832 public: |
| 831 static inline Page* Convert(NewSpacePage* old_page, PagedSpace* new_owner); | 833 static const intptr_t kCopyAllFlags = ~0; |
| 834 |
| 835 // Page flags copied from from-space to to-space when flipping semispaces. |
| 836 static const intptr_t kCopyOnFlipFlagsMask = |
| 837 (1 << MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING) | |
| 838 (1 << MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING); |
| 839 |
| 840 // Maximum object size that gets allocated into regular pages. Objects larger |
| 841 // than that size are allocated in large object space and are never moved in |
| 842 // memory. This also applies to new space allocation, since objects are never |
| 843 // migrated from new space to large object space. Takes double alignment into |
| 844 // account. |
| 845 // TODO(hpayer): This limit should be way smaller but we currently have |
| 846 // short living objects >256K. |
| 847 static const int kMaxRegularHeapObjectSize = 600 * KB; |
| 848 |
| 849 static inline Page* ConvertNewToOld(Page* old_page, PagedSpace* new_owner); |
| 832 | 850 |
| 833 // Returns the page containing a given address. The address ranges | 851 // Returns the page containing a given address. The address ranges |
| 834 // from [page_addr .. page_addr + kPageSize[ | 852 // from [page_addr .. page_addr + kPageSize[. This only works if the object |
| 835 // This only works if the object is in fact in a page. See also MemoryChunk:: | 853 // is in fact in a page. |
| 836 // FromAddress() and FromAnyAddress(). | 854 static Page* FromAddress(Address addr) { |
| 837 INLINE(static Page* FromAddress(Address a)) { | 855 return reinterpret_cast<Page*>(OffsetFrom(addr) & ~kPageAlignmentMask); |
| 838 return reinterpret_cast<Page*>(OffsetFrom(a) & ~kPageAlignmentMask); | |
| 839 } | 856 } |
| 840 | 857 |
| 841 // Only works for addresses in pointer spaces, not code space. | 858 // Returns the page containing the address provided. The address can |
| 859 // potentially point righter after the page. To be also safe for tagged values |
| 860 // we subtract a hole word. The valid address ranges from |
| 861 // [page_addr + kObjectStartOffset .. page_addr + kPageSize + kPointerSize]. |
| 862 static Page* FromAllocationAreaAddress(Address address) { |
| 863 return Page::FromAddress(address - kPointerSize); |
| 864 } |
| 865 |
| 866 // Checks if address1 and address2 are on the same new space page. |
| 867 static bool OnSamePage(Address address1, Address address2) { |
| 868 return Page::FromAddress(address1) == Page::FromAddress(address2); |
| 869 } |
| 870 |
| 871 // Checks whether an address is page aligned. |
| 872 static bool IsAlignedToPageSize(Address addr) { |
| 873 return (OffsetFrom(addr) & kPageAlignmentMask) == 0; |
| 874 } |
| 875 |
| 876 static bool IsAtObjectStart(Address addr) { |
| 877 return (reinterpret_cast<intptr_t>(addr) & kPageAlignmentMask) == |
| 878 kObjectStartOffset; |
| 879 } |
| 880 |
| 842 inline static Page* FromAnyPointerAddress(Heap* heap, Address addr); | 881 inline static Page* FromAnyPointerAddress(Heap* heap, Address addr); |
| 843 | 882 |
| 844 // Returns the page containing an allocation top. Because an allocation | 883 // Create a Page object that is only used as anchor for the doubly-linked |
| 845 // top address can be the upper bound of the page, we need to subtract | 884 // list of real pages. |
| 846 // it with kPointerSize first. The address ranges from | 885 explicit Page(Space* owner) { InitializeAsAnchor(owner); } |
| 847 // [page_addr + kObjectStartOffset .. page_addr + kPageSize]. | |
| 848 INLINE(static Page* FromAllocationTop(Address top)) { | |
| 849 Page* p = FromAddress(top - kPointerSize); | |
| 850 return p; | |
| 851 } | |
| 852 | 886 |
| 853 // Returns the next page in the chain of pages owned by a space. | 887 inline void MarkNeverAllocateForTesting(); |
| 854 inline Page* next_page() { | 888 inline void MarkEvacuationCandidate(); |
| 855 DCHECK(next_chunk()->owner() == owner()); | 889 inline void ClearEvacuationCandidate(); |
| 856 return static_cast<Page*>(next_chunk()); | |
| 857 } | |
| 858 inline Page* prev_page() { | |
| 859 DCHECK(prev_chunk()->owner() == owner()); | |
| 860 return static_cast<Page*>(prev_chunk()); | |
| 861 } | |
| 862 inline void set_next_page(Page* page); | |
| 863 inline void set_prev_page(Page* page); | |
| 864 | 890 |
| 865 // Checks whether an address is page aligned. | 891 Page* next_page() { return static_cast<Page*>(next_chunk()); } |
| 866 static bool IsAlignedToPageSize(Address a) { | 892 Page* prev_page() { return static_cast<Page*>(prev_chunk()); } |
| 867 return 0 == (OffsetFrom(a) & kPageAlignmentMask); | 893 void set_next_page(Page* page) { set_next_chunk(page); } |
| 894 void set_prev_page(Page* page) { set_prev_chunk(page); } |
| 895 |
| 896 template <typename Callback> |
| 897 inline void ForAllFreeListCategories(Callback callback) { |
| 898 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| 899 callback(&categories_[i]); |
| 900 } |
| 868 } | 901 } |
| 869 | 902 |
| 870 // Returns the offset of a given address to this page. | 903 // Returns the offset of a given address to this page. |
| 871 INLINE(int Offset(Address a)) { | 904 inline int Offset(Address a) { |
| 872 int offset = static_cast<int>(a - address()); | 905 int offset = static_cast<int>(a - address()); |
| 873 return offset; | 906 return offset; |
| 874 } | 907 } |
| 875 | 908 |
| 876 // Returns the address for a given offset to the this page. | 909 // Returns the address for a given offset to the this page. |
| 877 Address OffsetToAddress(int offset) { | 910 Address OffsetToAddress(int offset) { |
| 878 DCHECK_PAGE_OFFSET(offset); | 911 DCHECK_PAGE_OFFSET(offset); |
| 879 return address() + offset; | 912 return address() + offset; |
| 880 } | 913 } |
| 881 | 914 |
| 882 // --------------------------------------------------------------------- | |
| 883 | |
| 884 // Maximum object size that gets allocated into regular pages. Objects larger | |
| 885 // than that size are allocated in large object space and are never moved in | |
| 886 // memory. This also applies to new space allocation, since objects are never | |
| 887 // migrated from new space to large object space. Takes double alignment into | |
| 888 // account. | |
| 889 // TODO(hpayer): This limit should be way smaller but we currently have | |
| 890 // short living objects >256K. | |
| 891 static const int kMaxRegularHeapObjectSize = 600 * KB; | |
| 892 | |
| 893 inline void ClearGCFields(); | |
| 894 | |
| 895 void InitializeAsAnchor(PagedSpace* owner); | |
| 896 | |
| 897 // WaitUntilSweepingCompleted only works when concurrent sweeping is in | 915 // WaitUntilSweepingCompleted only works when concurrent sweeping is in |
| 898 // progress. In particular, when we know that right before this call a | 916 // progress. In particular, when we know that right before this call a |
| 899 // sweeper thread was sweeping this page. | 917 // sweeper thread was sweeping this page. |
| 900 void WaitUntilSweepingCompleted() { | 918 void WaitUntilSweepingCompleted() { |
| 901 mutex_->Lock(); | 919 mutex_->Lock(); |
| 902 mutex_->Unlock(); | 920 mutex_->Unlock(); |
| 903 DCHECK(SweepingDone()); | 921 DCHECK(SweepingDone()); |
| 904 } | 922 } |
| 905 | 923 |
| 906 bool SweepingDone() { | 924 bool SweepingDone() { |
| 907 return concurrent_sweeping_state().Value() == kSweepingDone; | 925 return concurrent_sweeping_state().Value() == kSweepingDone; |
| 908 } | 926 } |
| 909 | 927 |
| 910 void ResetFreeListStatistics(); | 928 void ResetFreeListStatistics(); |
| 911 | 929 |
| 912 int LiveBytesFromFreeList() { | 930 int LiveBytesFromFreeList() { |
| 913 return static_cast<int>(area_size() - wasted_memory() - | 931 return static_cast<int>(area_size() - wasted_memory() - |
| 914 available_in_free_list()); | 932 available_in_free_list()); |
| 915 } | 933 } |
| 916 | 934 |
| 917 template <typename Callback> | |
| 918 inline void ForAllFreeListCategories(Callback callback) { | |
| 919 for (int i = kFirstCategory; i < kNumberOfCategories; i++) { | |
| 920 callback(&categories_[i]); | |
| 921 } | |
| 922 } | |
| 923 | |
| 924 FreeListCategory* free_list_category(FreeListCategoryType type) { | 935 FreeListCategory* free_list_category(FreeListCategoryType type) { |
| 925 return &categories_[type]; | 936 return &categories_[type]; |
| 926 } | 937 } |
| 927 | 938 |
| 928 #define FRAGMENTATION_STATS_ACCESSORS(type, name) \ | 939 bool is_anchor() { return IsFlagSet(Page::ANCHOR); } |
| 929 type name() { return name##_.Value(); } \ | |
| 930 void set_##name(type name) { name##_.SetValue(name); } \ | |
| 931 void add_##name(type name) { name##_.Increment(name); } | |
| 932 | 940 |
| 933 FRAGMENTATION_STATS_ACCESSORS(intptr_t, wasted_memory) | 941 intptr_t wasted_memory() { return wasted_memory_.Value(); } |
| 934 FRAGMENTATION_STATS_ACCESSORS(intptr_t, available_in_free_list) | 942 void add_wasted_memory(intptr_t waste) { wasted_memory_.Increment(waste); } |
| 935 | 943 intptr_t available_in_free_list() { return available_in_free_list_.Value(); } |
| 936 #undef FRAGMENTATION_STATS_ACCESSORS | 944 void add_available_in_free_list(intptr_t available) { |
| 945 available_in_free_list_.Increment(available); |
| 946 } |
| 937 | 947 |
| 938 #ifdef DEBUG | 948 #ifdef DEBUG |
| 939 void Print(); | 949 void Print(); |
| 940 #endif // DEBUG | 950 #endif // DEBUG |
| 941 | 951 |
| 942 inline void MarkNeverAllocateForTesting(); | |
| 943 inline void MarkEvacuationCandidate(); | |
| 944 inline void ClearEvacuationCandidate(); | |
| 945 | |
| 946 private: | 952 private: |
| 947 enum InitializationMode { kFreeMemory, kDoNotFreeMemory }; | 953 enum InitializationMode { kFreeMemory, kDoNotFreeMemory }; |
| 948 | 954 |
| 949 template <InitializationMode mode = kFreeMemory> | 955 template <InitializationMode mode = kFreeMemory> |
| 950 static inline Page* Initialize(Heap* heap, MemoryChunk* chunk, | 956 static inline Page* Initialize(Heap* heap, MemoryChunk* chunk, |
| 951 Executability executable, PagedSpace* owner); | 957 Executability executable, PagedSpace* owner); |
| 958 static inline Page* Initialize(Heap* heap, MemoryChunk* chunk, |
| 959 Executability executable, SemiSpace* owner); |
| 952 | 960 |
| 953 inline void InitializeFreeListCategories(); | 961 inline void InitializeFreeListCategories(); |
| 954 | 962 |
| 963 void InitializeAsAnchor(Space* owner); |
| 964 |
| 955 friend class MemoryAllocator; | 965 friend class MemoryAllocator; |
| 956 }; | 966 }; |
| 957 | 967 |
| 958 | |
| 959 class LargePage : public MemoryChunk { | 968 class LargePage : public MemoryChunk { |
| 960 public: | 969 public: |
| 961 HeapObject* GetObject() { return HeapObject::FromAddress(area_start()); } | 970 HeapObject* GetObject() { return HeapObject::FromAddress(area_start()); } |
| 962 | 971 |
| 963 inline LargePage* next_page() { | 972 inline LargePage* next_page() { |
| 964 return static_cast<LargePage*>(next_chunk()); | 973 return static_cast<LargePage*>(next_chunk()); |
| 965 } | 974 } |
| 966 | 975 |
| 967 inline void set_next_page(LargePage* page) { set_next_chunk(page); } | 976 inline void set_next_page(LargePage* page) { set_next_chunk(page); } |
| 968 | 977 |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1268 | 1277 |
| 1269 explicit MemoryAllocator(Isolate* isolate); | 1278 explicit MemoryAllocator(Isolate* isolate); |
| 1270 | 1279 |
| 1271 // Initializes its internal bookkeeping structures. | 1280 // Initializes its internal bookkeeping structures. |
| 1272 // Max capacity of the total space and executable memory limit. | 1281 // Max capacity of the total space and executable memory limit. |
| 1273 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable, | 1282 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable, |
| 1274 intptr_t code_range_size); | 1283 intptr_t code_range_size); |
| 1275 | 1284 |
| 1276 void TearDown(); | 1285 void TearDown(); |
| 1277 | 1286 |
| 1278 // Allocates either Page or NewSpacePage from the allocator. AllocationMode | 1287 // Allocates a Page from the allocator. AllocationMode is used to indicate |
| 1279 // is used to indicate whether pooled allocation, which only works for | 1288 // whether pooled allocation, which only works for MemoryChunk::kPageSize, |
| 1280 // MemoryChunk::kPageSize, should be tried first. | 1289 // should be tried first. |
| 1281 template <typename PageType, MemoryAllocator::AllocationMode mode = kRegular, | 1290 template <MemoryAllocator::AllocationMode alloc_mode = kRegular, |
| 1282 typename SpaceType> | 1291 typename SpaceType> |
| 1283 PageType* AllocatePage(intptr_t size, SpaceType* owner, | 1292 Page* AllocatePage(intptr_t size, SpaceType* owner, Executability executable); |
| 1284 Executability executable); | 1293 |
| 1294 LargePage* AllocateLargePage(intptr_t size, LargeObjectSpace* owner, |
| 1295 Executability executable); |
| 1285 | 1296 |
| 1286 // PreFree logically frees the object, i.e., it takes care of the size | 1297 // PreFree logically frees the object, i.e., it takes care of the size |
| 1287 // bookkeeping and calls the allocation callback. | 1298 // bookkeeping and calls the allocation callback. |
| 1288 void PreFreeMemory(MemoryChunk* chunk); | 1299 void PreFreeMemory(MemoryChunk* chunk); |
| 1289 | 1300 |
| 1290 // FreeMemory can be called concurrently when PreFree was executed before. | 1301 // FreeMemory can be called concurrently when PreFree was executed before. |
| 1291 void PerformFreeMemory(MemoryChunk* chunk); | 1302 void PerformFreeMemory(MemoryChunk* chunk); |
| 1292 | 1303 |
| 1293 // Free is a wrapper method. For kRegular AllocationMode it calls PreFree and | 1304 // Free is a wrapper method. For kRegular AllocationMode it calls PreFree and |
| 1294 // PerformFreeMemory together. For kPooled it will dispatch to pooled free. | 1305 // PerformFreeMemory together. For kPooled it will dispatch to pooled free. |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1585 } | 1596 } |
| 1586 | 1597 |
| 1587 INLINE(Address limit()) const { | 1598 INLINE(Address limit()) const { |
| 1588 return limit_; | 1599 return limit_; |
| 1589 } | 1600 } |
| 1590 | 1601 |
| 1591 Address* limit_address() { return &limit_; } | 1602 Address* limit_address() { return &limit_; } |
| 1592 | 1603 |
| 1593 #ifdef DEBUG | 1604 #ifdef DEBUG |
| 1594 bool VerifyPagedAllocation() { | 1605 bool VerifyPagedAllocation() { |
| 1595 return (Page::FromAllocationTop(top_) == Page::FromAllocationTop(limit_)) && | 1606 return (Page::FromAllocationAreaAddress(top_) == |
| 1607 Page::FromAllocationAreaAddress(limit_)) && |
| 1596 (top_ <= limit_); | 1608 (top_ <= limit_); |
| 1597 } | 1609 } |
| 1598 #endif | 1610 #endif |
| 1599 | 1611 |
| 1600 private: | 1612 private: |
| 1601 // Current allocation top. | 1613 // Current allocation top. |
| 1602 Address top_; | 1614 Address top_; |
| 1603 // Current allocation limit. | 1615 // Current allocation limit. |
| 1604 Address limit_; | 1616 Address limit_; |
| 1605 }; | 1617 }; |
| (...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2296 public: | 2308 public: |
| 2297 HistogramInfo() : NumberAndSizeInfo() {} | 2309 HistogramInfo() : NumberAndSizeInfo() {} |
| 2298 | 2310 |
| 2299 const char* name() { return name_; } | 2311 const char* name() { return name_; } |
| 2300 void set_name(const char* name) { name_ = name; } | 2312 void set_name(const char* name) { name_ = name; } |
| 2301 | 2313 |
| 2302 private: | 2314 private: |
| 2303 const char* name_; | 2315 const char* name_; |
| 2304 }; | 2316 }; |
| 2305 | 2317 |
| 2306 | |
| 2307 enum SemiSpaceId { kFromSpace = 0, kToSpace = 1 }; | 2318 enum SemiSpaceId { kFromSpace = 0, kToSpace = 1 }; |
| 2308 | 2319 |
| 2309 | |
| 2310 class NewSpacePage : public MemoryChunk { | |
| 2311 public: | |
| 2312 static bool IsAtStart(Address addr) { | |
| 2313 return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask) == | |
| 2314 kObjectStartOffset; | |
| 2315 } | |
| 2316 | |
| 2317 static bool IsAtEnd(Address addr) { | |
| 2318 return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask) == 0; | |
| 2319 } | |
| 2320 | |
| 2321 // Finds the NewSpacePage containing the given address. | |
| 2322 static inline NewSpacePage* FromAddress(Address address_in_page) { | |
| 2323 Address page_start = | |
| 2324 reinterpret_cast<Address>(reinterpret_cast<uintptr_t>(address_in_page) & | |
| 2325 ~Page::kPageAlignmentMask); | |
| 2326 NewSpacePage* page = reinterpret_cast<NewSpacePage*>(page_start); | |
| 2327 return page; | |
| 2328 } | |
| 2329 | |
| 2330 // Find the page for a limit address. A limit address is either an address | |
| 2331 // inside a page, or the address right after the last byte of a page. | |
| 2332 static inline NewSpacePage* FromLimit(Address address_limit) { | |
| 2333 return NewSpacePage::FromAddress(address_limit - 1); | |
| 2334 } | |
| 2335 | |
| 2336 // Checks if address1 and address2 are on the same new space page. | |
| 2337 static inline bool OnSamePage(Address address1, Address address2) { | |
| 2338 return NewSpacePage::FromAddress(address1) == | |
| 2339 NewSpacePage::FromAddress(address2); | |
| 2340 } | |
| 2341 | |
| 2342 inline NewSpacePage* next_page() { | |
| 2343 return static_cast<NewSpacePage*>(next_chunk()); | |
| 2344 } | |
| 2345 | |
| 2346 inline void set_next_page(NewSpacePage* page) { set_next_chunk(page); } | |
| 2347 | |
| 2348 inline NewSpacePage* prev_page() { | |
| 2349 return static_cast<NewSpacePage*>(prev_chunk()); | |
| 2350 } | |
| 2351 | |
| 2352 inline void set_prev_page(NewSpacePage* page) { set_prev_chunk(page); } | |
| 2353 | |
| 2354 SemiSpace* semi_space() { return reinterpret_cast<SemiSpace*>(owner()); } | |
| 2355 | |
| 2356 bool is_anchor() { return !this->InNewSpace(); } | |
| 2357 | |
| 2358 private: | |
| 2359 static inline NewSpacePage* Initialize(Heap* heap, MemoryChunk* chunk, | |
| 2360 Executability executable, | |
| 2361 SemiSpace* owner); | |
| 2362 | |
| 2363 // GC related flags copied from from-space to to-space when | |
| 2364 // flipping semispaces. | |
| 2365 static const intptr_t kCopyOnFlipFlagsMask = | |
| 2366 (1 << MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING) | | |
| 2367 (1 << MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING); | |
| 2368 | |
| 2369 static const intptr_t kCopyAllFlags = ~0; | |
| 2370 | |
| 2371 // Create a NewSpacePage object that is only used as anchor | |
| 2372 // for the doubly-linked list of real pages. | |
| 2373 explicit NewSpacePage(SemiSpace* owner) { InitializeAsAnchor(owner); } | |
| 2374 | |
| 2375 // Intialize a fake NewSpacePage used as sentinel at the ends | |
| 2376 // of a doubly-linked list of real NewSpacePages. | |
| 2377 // Only uses the prev/next links, and sets flags to not be in new-space. | |
| 2378 void InitializeAsAnchor(SemiSpace* owner); | |
| 2379 | |
| 2380 friend class MemoryAllocator; | |
| 2381 friend class SemiSpace; | |
| 2382 friend class SemiSpaceIterator; | |
| 2383 }; | |
| 2384 | |
| 2385 | |
| 2386 // ----------------------------------------------------------------------------- | 2320 // ----------------------------------------------------------------------------- |
| 2387 // SemiSpace in young generation | 2321 // SemiSpace in young generation |
| 2388 // | 2322 // |
| 2389 // A SemiSpace is a contiguous chunk of memory holding page-like memory chunks. | 2323 // A SemiSpace is a contiguous chunk of memory holding page-like memory chunks. |
| 2390 // The mark-compact collector uses the memory of the first page in the from | 2324 // The mark-compact collector uses the memory of the first page in the from |
| 2391 // space as a marking stack when tracing live objects. | 2325 // space as a marking stack when tracing live objects. |
| 2392 class SemiSpace : public Space { | 2326 class SemiSpace : public Space { |
| 2393 public: | 2327 public: |
| 2394 static void Swap(SemiSpace* from, SemiSpace* to); | 2328 static void Swap(SemiSpace* from, SemiSpace* to); |
| 2395 | 2329 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2424 // must be more than the amount of used memory in the semispace and less | 2358 // must be more than the amount of used memory in the semispace and less |
| 2425 // than the current capacity. | 2359 // than the current capacity. |
| 2426 bool ShrinkTo(int new_capacity); | 2360 bool ShrinkTo(int new_capacity); |
| 2427 | 2361 |
| 2428 // Returns the start address of the first page of the space. | 2362 // Returns the start address of the first page of the space. |
| 2429 Address space_start() { | 2363 Address space_start() { |
| 2430 DCHECK_NE(anchor_.next_page(), anchor()); | 2364 DCHECK_NE(anchor_.next_page(), anchor()); |
| 2431 return anchor_.next_page()->area_start(); | 2365 return anchor_.next_page()->area_start(); |
| 2432 } | 2366 } |
| 2433 | 2367 |
| 2434 NewSpacePage* first_page() { return anchor_.next_page(); } | 2368 Page* first_page() { return anchor_.next_page(); } |
| 2435 NewSpacePage* current_page() { return current_page_; } | 2369 Page* current_page() { return current_page_; } |
| 2436 | 2370 |
| 2437 // Returns one past the end address of the space. | 2371 // Returns one past the end address of the space. |
| 2438 Address space_end() { return anchor_.prev_page()->area_end(); } | 2372 Address space_end() { return anchor_.prev_page()->area_end(); } |
| 2439 | 2373 |
| 2440 // Returns the start address of the current page of the space. | 2374 // Returns the start address of the current page of the space. |
| 2441 Address page_low() { return current_page_->area_start(); } | 2375 Address page_low() { return current_page_->area_start(); } |
| 2442 | 2376 |
| 2443 // Returns one past the end address of the current page of the space. | 2377 // Returns one past the end address of the current page of the space. |
| 2444 Address page_high() { return current_page_->area_end(); } | 2378 Address page_high() { return current_page_->area_end(); } |
| 2445 | 2379 |
| 2446 bool AdvancePage() { | 2380 bool AdvancePage() { |
| 2447 NewSpacePage* next_page = current_page_->next_page(); | 2381 Page* next_page = current_page_->next_page(); |
| 2448 if (next_page == anchor()) return false; | 2382 if (next_page == anchor()) return false; |
| 2449 current_page_ = next_page; | 2383 current_page_ = next_page; |
| 2450 return true; | 2384 return true; |
| 2451 } | 2385 } |
| 2452 | 2386 |
| 2453 // Resets the space to using the first page. | 2387 // Resets the space to using the first page. |
| 2454 void Reset(); | 2388 void Reset(); |
| 2455 | 2389 |
| 2456 void ReplaceWithEmptyPage(NewSpacePage* page); | 2390 void ReplaceWithEmptyPage(Page* page); |
| 2457 | 2391 |
| 2458 // Age mark accessors. | 2392 // Age mark accessors. |
| 2459 Address age_mark() { return age_mark_; } | 2393 Address age_mark() { return age_mark_; } |
| 2460 void set_age_mark(Address mark); | 2394 void set_age_mark(Address mark); |
| 2461 | 2395 |
| 2462 // Returns the current capacity of the semispace. | 2396 // Returns the current capacity of the semispace. |
| 2463 int current_capacity() { return current_capacity_; } | 2397 int current_capacity() { return current_capacity_; } |
| 2464 | 2398 |
| 2465 // Returns the maximum capacity of the semispace. | 2399 // Returns the maximum capacity of the semispace. |
| 2466 int maximum_capacity() { return maximum_capacity_; } | 2400 int maximum_capacity() { return maximum_capacity_; } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2497 #else | 2431 #else |
| 2498 // Do nothing. | 2432 // Do nothing. |
| 2499 inline static void AssertValidRange(Address from, Address to) {} | 2433 inline static void AssertValidRange(Address from, Address to) {} |
| 2500 #endif | 2434 #endif |
| 2501 | 2435 |
| 2502 #ifdef VERIFY_HEAP | 2436 #ifdef VERIFY_HEAP |
| 2503 virtual void Verify(); | 2437 virtual void Verify(); |
| 2504 #endif | 2438 #endif |
| 2505 | 2439 |
| 2506 private: | 2440 private: |
| 2507 void RewindPages(NewSpacePage* start, int num_pages); | 2441 void RewindPages(Page* start, int num_pages); |
| 2508 | 2442 |
| 2509 inline NewSpacePage* anchor() { return &anchor_; } | 2443 inline Page* anchor() { return &anchor_; } |
| 2510 | 2444 |
| 2511 // Copies the flags into the masked positions on all pages in the space. | 2445 // Copies the flags into the masked positions on all pages in the space. |
| 2512 void FixPagesFlags(intptr_t flags, intptr_t flag_mask); | 2446 void FixPagesFlags(intptr_t flags, intptr_t flag_mask); |
| 2513 | 2447 |
| 2514 // The currently committed space capacity. | 2448 // The currently committed space capacity. |
| 2515 int current_capacity_; | 2449 int current_capacity_; |
| 2516 | 2450 |
| 2517 // The maximum capacity that can be used by this space. | 2451 // The maximum capacity that can be used by this space. |
| 2518 int maximum_capacity_; | 2452 int maximum_capacity_; |
| 2519 | 2453 |
| 2520 // The minimum capacity for the space. A space cannot shrink below this size. | 2454 // The minimum capacity for the space. A space cannot shrink below this size. |
| 2521 int minimum_capacity_; | 2455 int minimum_capacity_; |
| 2522 | 2456 |
| 2523 // Used to govern object promotion during mark-compact collection. | 2457 // Used to govern object promotion during mark-compact collection. |
| 2524 Address age_mark_; | 2458 Address age_mark_; |
| 2525 | 2459 |
| 2526 bool committed_; | 2460 bool committed_; |
| 2527 SemiSpaceId id_; | 2461 SemiSpaceId id_; |
| 2528 | 2462 |
| 2529 NewSpacePage anchor_; | 2463 Page anchor_; |
| 2530 NewSpacePage* current_page_; | 2464 Page* current_page_; |
| 2531 | 2465 |
| 2532 friend class SemiSpaceIterator; | 2466 friend class SemiSpaceIterator; |
| 2533 friend class NewSpacePageIterator; | 2467 friend class NewSpacePageIterator; |
| 2534 }; | 2468 }; |
| 2535 | 2469 |
| 2536 | 2470 |
| 2537 // A SemiSpaceIterator is an ObjectIterator that iterates over the active | 2471 // A SemiSpaceIterator is an ObjectIterator that iterates over the active |
| 2538 // semispace of the heap's new space. It iterates over the objects in the | 2472 // semispace of the heap's new space. It iterates over the objects in the |
| 2539 // semispace from a given start address (defaulting to the bottom of the | 2473 // semispace from a given start address (defaulting to the bottom of the |
| 2540 // semispace) to the top of the semispace. New objects allocated after the | 2474 // semispace) to the top of the semispace. New objects allocated after the |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2568 | 2502 |
| 2569 // Make an iterator that runs over all pages in the given semispace, | 2503 // Make an iterator that runs over all pages in the given semispace, |
| 2570 // even those not used in allocation. | 2504 // even those not used in allocation. |
| 2571 explicit inline NewSpacePageIterator(SemiSpace* space); | 2505 explicit inline NewSpacePageIterator(SemiSpace* space); |
| 2572 | 2506 |
| 2573 // Make iterator that iterates from the page containing start | 2507 // Make iterator that iterates from the page containing start |
| 2574 // to the page that contains limit in the same semispace. | 2508 // to the page that contains limit in the same semispace. |
| 2575 inline NewSpacePageIterator(Address start, Address limit); | 2509 inline NewSpacePageIterator(Address start, Address limit); |
| 2576 | 2510 |
| 2577 inline bool has_next(); | 2511 inline bool has_next(); |
| 2578 inline NewSpacePage* next(); | 2512 inline Page* next(); |
| 2579 | 2513 |
| 2580 private: | 2514 private: |
| 2581 NewSpacePage* prev_page_; // Previous page returned. | 2515 Page* prev_page_; // Previous page returned. |
| 2582 // Next page that will be returned. Cached here so that we can use this | 2516 // Next page that will be returned. Cached here so that we can use this |
| 2583 // iterator for operations that deallocate pages. | 2517 // iterator for operations that deallocate pages. |
| 2584 NewSpacePage* next_page_; | 2518 Page* next_page_; |
| 2585 // Last page returned. | 2519 // Last page returned. |
| 2586 NewSpacePage* last_page_; | 2520 Page* last_page_; |
| 2587 }; | 2521 }; |
| 2588 | 2522 |
| 2589 | 2523 |
| 2590 // ----------------------------------------------------------------------------- | 2524 // ----------------------------------------------------------------------------- |
| 2591 // The young generation space. | 2525 // The young generation space. |
| 2592 // | 2526 // |
| 2593 // The new space consists of a contiguous pair of semispaces. It simply | 2527 // The new space consists of a contiguous pair of semispaces. It simply |
| 2594 // forwards most functions to the appropriate semispace. | 2528 // forwards most functions to the appropriate semispace. |
| 2595 | 2529 |
| 2596 class NewSpace : public Space { | 2530 class NewSpace : public Space { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2626 | 2560 |
| 2627 // Grow the capacity of the semispaces. Assumes that they are not at | 2561 // Grow the capacity of the semispaces. Assumes that they are not at |
| 2628 // their maximum capacity. | 2562 // their maximum capacity. |
| 2629 void Grow(); | 2563 void Grow(); |
| 2630 | 2564 |
| 2631 // Shrink the capacity of the semispaces. | 2565 // Shrink the capacity of the semispaces. |
| 2632 void Shrink(); | 2566 void Shrink(); |
| 2633 | 2567 |
| 2634 // Return the allocated bytes in the active semispace. | 2568 // Return the allocated bytes in the active semispace. |
| 2635 intptr_t Size() override { | 2569 intptr_t Size() override { |
| 2636 return pages_used_ * NewSpacePage::kAllocatableMemory + | 2570 return pages_used_ * Page::kAllocatableMemory + |
| 2637 static_cast<int>(top() - to_space_.page_low()); | 2571 static_cast<int>(top() - to_space_.page_low()); |
| 2638 } | 2572 } |
| 2639 | 2573 |
| 2640 // The same, but returning an int. We have to have the one that returns | 2574 // The same, but returning an int. We have to have the one that returns |
| 2641 // intptr_t because it is inherited, but if we know we are dealing with the | 2575 // intptr_t because it is inherited, but if we know we are dealing with the |
| 2642 // new space, which can't get as big as the other spaces then this is useful: | 2576 // new space, which can't get as big as the other spaces then this is useful: |
| 2643 int SizeAsInt() { return static_cast<int>(Size()); } | 2577 int SizeAsInt() { return static_cast<int>(Size()); } |
| 2644 | 2578 |
| 2645 // Return the allocatable capacity of a semispace. | 2579 // Return the allocatable capacity of a semispace. |
| 2646 intptr_t Capacity() { | 2580 intptr_t Capacity() { |
| 2647 SLOW_DCHECK(to_space_.current_capacity() == from_space_.current_capacity()); | 2581 SLOW_DCHECK(to_space_.current_capacity() == from_space_.current_capacity()); |
| 2648 return (to_space_.current_capacity() / Page::kPageSize) * | 2582 return (to_space_.current_capacity() / Page::kPageSize) * |
| 2649 NewSpacePage::kAllocatableMemory; | 2583 Page::kAllocatableMemory; |
| 2650 } | 2584 } |
| 2651 | 2585 |
| 2652 // Return the current size of a semispace, allocatable and non-allocatable | 2586 // Return the current size of a semispace, allocatable and non-allocatable |
| 2653 // memory. | 2587 // memory. |
| 2654 intptr_t TotalCapacity() { | 2588 intptr_t TotalCapacity() { |
| 2655 DCHECK(to_space_.current_capacity() == from_space_.current_capacity()); | 2589 DCHECK(to_space_.current_capacity() == from_space_.current_capacity()); |
| 2656 return to_space_.current_capacity(); | 2590 return to_space_.current_capacity(); |
| 2657 } | 2591 } |
| 2658 | 2592 |
| 2659 // Committed memory for NewSpace is the committed memory of both semi-spaces | 2593 // Committed memory for NewSpace is the committed memory of both semi-spaces |
| 2660 // combined. | 2594 // combined. |
| 2661 intptr_t CommittedMemory() override { | 2595 intptr_t CommittedMemory() override { |
| 2662 return from_space_.CommittedMemory() + to_space_.CommittedMemory(); | 2596 return from_space_.CommittedMemory() + to_space_.CommittedMemory(); |
| 2663 } | 2597 } |
| 2664 | 2598 |
| 2665 intptr_t MaximumCommittedMemory() override { | 2599 intptr_t MaximumCommittedMemory() override { |
| 2666 return from_space_.MaximumCommittedMemory() + | 2600 return from_space_.MaximumCommittedMemory() + |
| 2667 to_space_.MaximumCommittedMemory(); | 2601 to_space_.MaximumCommittedMemory(); |
| 2668 } | 2602 } |
| 2669 | 2603 |
| 2670 // Approximate amount of physical memory committed for this space. | 2604 // Approximate amount of physical memory committed for this space. |
| 2671 size_t CommittedPhysicalMemory() override; | 2605 size_t CommittedPhysicalMemory() override; |
| 2672 | 2606 |
| 2673 // Return the available bytes without growing. | 2607 // Return the available bytes without growing. |
| 2674 intptr_t Available() override { return Capacity() - Size(); } | 2608 intptr_t Available() override { return Capacity() - Size(); } |
| 2675 | 2609 |
| 2676 inline size_t AllocatedSinceLastGC(); | 2610 inline size_t AllocatedSinceLastGC(); |
| 2677 | 2611 |
| 2678 void ReplaceWithEmptyPage(NewSpacePage* page) { | 2612 void ReplaceWithEmptyPage(Page* page) { |
| 2679 // This method is called after flipping the semispace. | 2613 // This method is called after flipping the semispace. |
| 2680 DCHECK(page->InFromSpace()); | 2614 DCHECK(page->InFromSpace()); |
| 2681 from_space_.ReplaceWithEmptyPage(page); | 2615 from_space_.ReplaceWithEmptyPage(page); |
| 2682 } | 2616 } |
| 2683 | 2617 |
| 2684 // Return the maximum capacity of a semispace. | 2618 // Return the maximum capacity of a semispace. |
| 2685 int MaximumCapacity() { | 2619 int MaximumCapacity() { |
| 2686 DCHECK(to_space_.maximum_capacity() == from_space_.maximum_capacity()); | 2620 DCHECK(to_space_.maximum_capacity() == from_space_.maximum_capacity()); |
| 2687 return to_space_.maximum_capacity(); | 2621 return to_space_.maximum_capacity(); |
| 2688 } | 2622 } |
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3110 count = 0; | 3044 count = 0; |
| 3111 } | 3045 } |
| 3112 // Must be small, since an iteration is used for lookup. | 3046 // Must be small, since an iteration is used for lookup. |
| 3113 static const int kMaxComments = 64; | 3047 static const int kMaxComments = 64; |
| 3114 }; | 3048 }; |
| 3115 #endif | 3049 #endif |
| 3116 } // namespace internal | 3050 } // namespace internal |
| 3117 } // namespace v8 | 3051 } // namespace v8 |
| 3118 | 3052 |
| 3119 #endif // V8_HEAP_SPACES_H_ | 3053 #endif // V8_HEAP_SPACES_H_ |
| OLD | NEW |