Chromium Code Reviews| Index: src/heap/spaces.cc |
| diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc |
| index 6d30f31c7ca2c09196716cd64ef1b5183035fcc1..ec8e3eaac3290c6723fe6d000e5fbb54ed3fa498 100644 |
| --- a/src/heap/spaces.cc |
| +++ b/src/heap/spaces.cc |
| @@ -316,14 +316,13 @@ bool MemoryAllocator::SetUp(intptr_t capacity, intptr_t capacity_executable) { |
| void MemoryAllocator::TearDown() { |
| // Check that spaces were torn down before MemoryAllocator. |
| - DCHECK(size_.Value() == 0); |
| + DCHECK_EQ(size_.Value(), 0); |
| // TODO(gc) this will be true again when we fix FreeMemory. |
| // DCHECK(size_executable_ == 0); |
| capacity_ = 0; |
| capacity_executable_ = 0; |
| } |
| - |
| bool MemoryAllocator::CommitMemory(Address base, size_t size, |
| Executability executable) { |
| if (!base::VirtualMemory::CommitRegion(base, size, |
| @@ -335,20 +334,6 @@ bool MemoryAllocator::CommitMemory(Address base, size_t size, |
| } |
| -void MemoryAllocator::FreeNewSpaceMemory(Address addr, |
| - base::VirtualMemory* reservation, |
| - Executability executable) { |
| - LOG(isolate_, DeleteEvent("NewSpace", addr)); |
| - |
| - DCHECK(reservation->IsReserved()); |
| - const intptr_t size = static_cast<intptr_t>(reservation->size()); |
| - DCHECK(size_.Value() >= size); |
| - size_.Increment(-size); |
| - isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(size)); |
| - FreeMemory(reservation, NOT_EXECUTABLE); |
| -} |
| - |
| - |
| void MemoryAllocator::FreeMemory(base::VirtualMemory* reservation, |
| Executability executable) { |
| // TODO(gc) make code_range part of memory allocator? |
| @@ -433,26 +418,6 @@ void Page::InitializeAsAnchor(PagedSpace* owner) { |
| set_next_page(this); |
| } |
| - |
| -NewSpacePage* NewSpacePage::Initialize(Heap* heap, Address start, |
| - SemiSpace* semi_space) { |
| - Address area_start = start + NewSpacePage::kObjectStartOffset; |
| - Address area_end = start + Page::kPageSize; |
| - |
| - MemoryChunk* chunk = |
| - MemoryChunk::Initialize(heap, start, Page::kPageSize, area_start, |
| - area_end, NOT_EXECUTABLE, semi_space, nullptr); |
| - bool in_to_space = (semi_space->id() != kFromSpace); |
| - chunk->SetFlag(in_to_space ? MemoryChunk::IN_TO_SPACE |
| - : MemoryChunk::IN_FROM_SPACE); |
| - DCHECK(!chunk->IsFlagSet(in_to_space ? MemoryChunk::IN_FROM_SPACE |
| - : MemoryChunk::IN_TO_SPACE)); |
| - NewSpacePage* page = static_cast<NewSpacePage*>(chunk); |
| - heap->incremental_marking()->SetNewSpacePageFlags(page); |
| - return page; |
| -} |
| - |
| - |
| void NewSpacePage::InitializeAsAnchor(SemiSpace* semi_space) { |
| set_owner(semi_space); |
| set_next_chunk(this); |
| @@ -715,15 +680,6 @@ void Page::ResetFreeListStatistics() { |
| available_in_free_list_ = 0; |
| } |
| - |
| -Page* MemoryAllocator::AllocatePage(intptr_t size, PagedSpace* owner, |
| - Executability executable) { |
| - MemoryChunk* chunk = AllocateChunk(size, size, executable, owner); |
| - if (chunk == NULL) return NULL; |
| - return Page::Initialize(isolate_->heap(), chunk, executable, owner); |
| -} |
| - |
| - |
| LargePage* MemoryAllocator::AllocateLargePage(intptr_t object_size, |
| Space* owner, |
| Executability executable) { |
| @@ -788,6 +744,35 @@ void MemoryAllocator::Free(MemoryChunk* chunk) { |
| PerformFreeMemory(chunk); |
| } |
| +template <typename SpaceType> |
| +MemoryChunk* MemoryAllocator::AllocatePagePooled(SpaceType* owner, |
| + Executability executable) { |
| + if (chunk_pool_.is_empty()) return nullptr; |
| + MemoryChunk* chunk = chunk_pool_.RemoveLast(); |
| + const intptr_t chunk_size = MemoryChunk::kPageSize; |
| + const Address start = reinterpret_cast<Address>(chunk); |
| + const Address area_start = start + MemoryChunk::kObjectStartOffset; |
| + const Address area_end = start + chunk_size; |
| + CommitBlock(reinterpret_cast<Address>(chunk), chunk_size, executable); |
| + base::VirtualMemory reservation(start, chunk_size); |
| + MemoryChunk::Initialize(isolate_->heap(), start, chunk_size, area_start, |
| + area_end, NOT_EXECUTABLE, owner, &reservation); |
|
ulan
2016/04/05 08:46:25
s/NOT_EXECUTABLE/executable?
Michael Lippautz
2016/04/05 09:42:34
Done.
|
| + if (chunk->executable() == EXECUTABLE) { |
| + size_executable_.Increment(chunk_size); |
| + } |
| + size_.Increment(chunk_size); |
| + return chunk; |
| +} |
| + |
| +void MemoryAllocator::FreePooled(MemoryChunk* chunk) { |
| + chunk_pool_.Add(chunk); |
|
ulan
2016/04/05 08:46:25
Where a pooled page gets actually release?
Michael Lippautz
2016/04/05 09:42:34
This is now done in MemoryAllocator::TearDown.
I
|
| + intptr_t chunk_size = static_cast<intptr_t>(chunk->size()); |
| + if (chunk->executable() == EXECUTABLE) { |
| + size_executable_.Increment(-chunk_size); |
| + } |
| + size_.Increment(-chunk_size); |
| + UncommitBlock(reinterpret_cast<Address>(chunk), MemoryChunk::kPageSize); |
| +} |
| bool MemoryAllocator::CommitBlock(Address start, size_t size, |
| Executability executable) { |
| @@ -1159,8 +1144,8 @@ bool PagedSpace::Expand() { |
| if (!CanExpand(size)) return false; |
| - Page* p = heap()->isolate()->memory_allocator()->AllocatePage(size, this, |
| - executable()); |
| + Page* p = heap()->isolate()->memory_allocator()->AllocatePage<Page>( |
| + size, this, executable()); |
| if (p == NULL) return false; |
| AccountCommitted(static_cast<intptr_t>(p->size())); |
| @@ -1290,53 +1275,28 @@ void PagedSpace::Verify(ObjectVisitor* visitor) { |
| // ----------------------------------------------------------------------------- |
| // NewSpace implementation |
| - |
| -bool NewSpace::SetUp(int reserved_semispace_capacity, |
| +bool NewSpace::SetUp(int initial_semispace_capacity, |
| int maximum_semispace_capacity) { |
| - // Set up new space based on the preallocated memory block defined by |
| - // start and size. The provided space is divided into two semi-spaces. |
| - // To support fast containment testing in the new space, the size of |
| - // this chunk must be a power of two and it must be aligned to its size. |
| - int initial_semispace_capacity = heap()->InitialSemiSpaceSize(); |
| - |
| - size_t size = 2 * reserved_semispace_capacity; |
| - Address base = heap()->isolate()->memory_allocator()->ReserveAlignedMemory( |
| - size, size, &reservation_); |
| - if (base == NULL) return false; |
| - |
| - chunk_base_ = base; |
| - chunk_size_ = static_cast<uintptr_t>(size); |
| - LOG(heap()->isolate(), NewEvent("InitialChunk", chunk_base_, chunk_size_)); |
| - |
| DCHECK(initial_semispace_capacity <= maximum_semispace_capacity); |
| DCHECK(base::bits::IsPowerOfTwo32(maximum_semispace_capacity)); |
| + to_space_.SetUp(initial_semispace_capacity, maximum_semispace_capacity); |
| + from_space_.SetUp(initial_semispace_capacity, maximum_semispace_capacity); |
| + if (!to_space_.Commit()) { |
| + return false; |
| + } |
| + DCHECK(!from_space_.is_committed()); // No need to use memory yet. |
| + ResetAllocationInfo(); |
| + |
| // Allocate and set up the histogram arrays if necessary. |
| allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); |
| promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); |
| - |
| #define SET_NAME(name) \ |
| allocated_histogram_[name].set_name(#name); \ |
| promoted_histogram_[name].set_name(#name); |
| INSTANCE_TYPE_LIST(SET_NAME) |
| #undef SET_NAME |
| - DCHECK(reserved_semispace_capacity == heap()->ReservedSemiSpaceSize()); |
| - DCHECK(static_cast<intptr_t>(chunk_size_) >= |
| - 2 * heap()->ReservedSemiSpaceSize()); |
| - DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0)); |
| - |
| - to_space_.SetUp(chunk_base_, initial_semispace_capacity, |
| - maximum_semispace_capacity); |
| - from_space_.SetUp(chunk_base_ + reserved_semispace_capacity, |
| - initial_semispace_capacity, maximum_semispace_capacity); |
| - if (!to_space_.Commit()) { |
| - return false; |
| - } |
| - DCHECK(!from_space_.is_committed()); // No need to use memory yet. |
| - |
| - ResetAllocationInfo(); |
| - |
| return true; |
| } |
| @@ -1355,12 +1315,6 @@ void NewSpace::TearDown() { |
| to_space_.TearDown(); |
| from_space_.TearDown(); |
| - |
| - heap()->isolate()->memory_allocator()->FreeNewSpaceMemory( |
| - chunk_base_, &reservation_, NOT_EXECUTABLE); |
| - |
| - chunk_base_ = NULL; |
| - chunk_size_ = 0; |
| } |
| @@ -1677,43 +1631,41 @@ void NewSpace::Verify() { |
| // ----------------------------------------------------------------------------- |
| // SemiSpace implementation |
| -void SemiSpace::SetUp(Address start, int initial_capacity, |
| - int maximum_capacity) { |
| +void SemiSpace::SetUp(int initial_capacity, int maximum_capacity) { |
| DCHECK_GE(maximum_capacity, Page::kPageSize); |
| minimum_capacity_ = RoundDown(initial_capacity, Page::kPageSize); |
| current_capacity_ = minimum_capacity_; |
| maximum_capacity_ = RoundDown(maximum_capacity, Page::kPageSize); |
| committed_ = false; |
| - start_ = start; |
| - age_mark_ = start_ + NewSpacePage::kObjectStartOffset; |
| } |
| void SemiSpace::TearDown() { |
| - start_ = nullptr; |
| - current_capacity_ = 0; |
| + // Properly uncommit memory to keep the allocator counters in sync. |
| + if (is_committed()) Uncommit(); |
| + current_capacity_ = maximum_capacity_ = 0; |
| } |
| bool SemiSpace::Commit() { |
| DCHECK(!is_committed()); |
| - if (!heap()->isolate()->memory_allocator()->CommitBlock( |
| - start_, current_capacity_, executable())) { |
| - return false; |
| - } |
| - AccountCommitted(current_capacity_); |
| - |
| NewSpacePage* current = anchor(); |
| const int num_pages = current_capacity_ / Page::kPageSize; |
| for (int i = 0; i < num_pages; i++) { |
| NewSpacePage* new_page = |
| - NewSpacePage::Initialize(heap(), start_ + i * Page::kPageSize, this); |
| + heap() |
| + ->isolate() |
| + ->memory_allocator() |
| + ->AllocatePage<NewSpacePage, MemoryAllocator::kPooled>( |
| + NewSpacePage::kAllocatableMemory, this, executable()); |
|
ulan
2016/04/05 08:46:25
s/executable()/NOT_EXECUTABLE?
or fix SemiSpace::
Michael Lippautz
2016/04/05 09:42:34
Fixed SemiSpace::GrowTo.
|
| new_page->InsertAfter(current); |
| current = new_page; |
| } |
| Reset(); |
| - |
| - set_current_capacity(current_capacity_); |
| + AccountCommitted(current_capacity_); |
| + if (age_mark_ == nullptr) { |
| + age_mark_ = first_page()->area_start(); |
| + } |
| committed_ = true; |
| return true; |
| } |
| @@ -1721,16 +1673,13 @@ bool SemiSpace::Commit() { |
| bool SemiSpace::Uncommit() { |
| DCHECK(is_committed()); |
| - Address start = start_ + maximum_capacity_ - current_capacity_; |
| - if (!heap()->isolate()->memory_allocator()->UncommitBlock( |
| - start, current_capacity_)) { |
| - return false; |
| + NewSpacePageIterator it(this); |
| + while (it.has_next()) { |
| + heap()->isolate()->memory_allocator()->FreePooled(it.next()); |
| } |
| - AccountUncommitted(current_capacity_); |
| - |
| anchor()->set_next_page(anchor()); |
| anchor()->set_prev_page(anchor()); |
| - |
| + AccountUncommitted(current_capacity_); |
| committed_ = false; |
| return true; |
| } |
| @@ -1751,62 +1700,56 @@ bool SemiSpace::GrowTo(int new_capacity) { |
| if (!is_committed()) { |
| if (!Commit()) return false; |
| } |
| - DCHECK_EQ(new_capacity & Page::kPageAlignmentMask, 0); |
| + DCHECK_EQ(new_capacity & NewSpacePage::kPageAlignmentMask, 0); |
| DCHECK_LE(new_capacity, maximum_capacity_); |
| DCHECK_GT(new_capacity, current_capacity_); |
| - int pages_before = current_capacity_ / Page::kPageSize; |
| - int pages_after = new_capacity / Page::kPageSize; |
| - |
| - size_t delta = new_capacity - current_capacity_; |
| - |
| + const int delta = new_capacity - current_capacity_; |
| DCHECK(IsAligned(delta, base::OS::AllocateAlignment())); |
| - if (!heap()->isolate()->memory_allocator()->CommitBlock( |
| - start_ + current_capacity_, delta, executable())) { |
| - return false; |
| - } |
| - AccountCommitted(static_cast<intptr_t>(delta)); |
| - set_current_capacity(new_capacity); |
| + int delta_pages = delta / NewSpacePage::kPageSize; |
| NewSpacePage* last_page = anchor()->prev_page(); |
| DCHECK_NE(last_page, anchor()); |
| - for (int i = pages_before; i < pages_after; i++) { |
| - Address page_address = start_ + i * Page::kPageSize; |
| + while (delta_pages > 0) { |
| NewSpacePage* new_page = |
| - NewSpacePage::Initialize(heap(), page_address, this); |
| + heap() |
| + ->isolate() |
| + ->memory_allocator() |
| + ->AllocatePage<NewSpacePage, MemoryAllocator::kPooled>( |
| + NewSpacePage::kAllocatableMemory, this, NOT_EXECUTABLE); |
| new_page->InsertAfter(last_page); |
| Bitmap::Clear(new_page); |
| // Duplicate the flags that was set on the old page. |
| new_page->SetFlags(last_page->GetFlags(), |
| NewSpacePage::kCopyOnFlipFlagsMask); |
| last_page = new_page; |
| + delta_pages--; |
| } |
| + AccountCommitted(static_cast<intptr_t>(delta)); |
| + current_capacity_ = new_capacity; |
| return true; |
| } |
| bool SemiSpace::ShrinkTo(int new_capacity) { |
| - DCHECK_EQ(new_capacity & Page::kPageAlignmentMask, 0); |
| + DCHECK_EQ(new_capacity & NewSpacePage::kPageAlignmentMask, 0); |
| DCHECK_GE(new_capacity, minimum_capacity_); |
| DCHECK_LT(new_capacity, current_capacity_); |
| if (is_committed()) { |
| - size_t delta = current_capacity_ - new_capacity; |
| + const int delta = current_capacity_ - new_capacity; |
| DCHECK(IsAligned(delta, base::OS::AllocateAlignment())); |
| - |
| - MemoryAllocator* allocator = heap()->isolate()->memory_allocator(); |
| - if (!allocator->UncommitBlock(start_ + new_capacity, delta)) { |
| - return false; |
| + int delta_pages = delta / NewSpacePage::kPageSize; |
| + NewSpacePage* new_last_page; |
| + NewSpacePage* last_page; |
| + while (delta_pages > 0) { |
| + last_page = anchor()->prev_page(); |
| + new_last_page = last_page->prev_page(); |
| + new_last_page->set_next_page(anchor()); |
| + anchor()->set_prev_page(new_last_page); |
| + heap()->isolate()->memory_allocator()->FreePooled(last_page); |
| + delta_pages--; |
| } |
| AccountUncommitted(static_cast<intptr_t>(delta)); |
| - |
| - int pages_after = new_capacity / Page::kPageSize; |
| - NewSpacePage* new_last_page = |
| - NewSpacePage::FromAddress(start_ + (pages_after - 1) * Page::kPageSize); |
| - new_last_page->set_next_page(anchor()); |
| - anchor()->set_prev_page(new_last_page); |
| - DCHECK((current_page_ >= first_page()) && (current_page_ <= new_last_page)); |
| } |
| - |
| - set_current_capacity(new_capacity); |
| - |
| + current_capacity_ = new_capacity; |
| return true; |
| } |
| @@ -1853,7 +1796,6 @@ void SemiSpace::Swap(SemiSpace* from, SemiSpace* to) { |
| std::swap(from->current_capacity_, to->current_capacity_); |
| std::swap(from->maximum_capacity_, to->maximum_capacity_); |
| std::swap(from->minimum_capacity_, to->minimum_capacity_); |
| - std::swap(from->start_, to->start_); |
| std::swap(from->age_mark_, to->age_mark_); |
| std::swap(from->committed_, to->committed_); |
| std::swap(from->anchor_, to->anchor_); |