Chromium Code Reviews| Index: src/heap/spaces.cc |
| diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc |
| index 74ada3deef0c54e4206b7b1d53c7fd7a50ab6d2b..0a02039d99cf66254d427bd31da845613e48442e 100644 |
| --- a/src/heap/spaces.cc |
| +++ b/src/heap/spaces.cc |
| @@ -1031,79 +1031,48 @@ void PagedSpace::TearDown() { |
| accounting_stats_.Clear(); |
| } |
| - |
| -void PagedSpace::AddMemory(Address start, intptr_t size) { |
| - accounting_stats_.ExpandSpace(static_cast<int>(size)); |
| - Free(start, static_cast<int>(size)); |
| -} |
| - |
| - |
| void PagedSpace::RefillFreeList() { |
| - MarkCompactCollector* collector = heap()->mark_compact_collector(); |
| - FreeList* free_list = nullptr; |
| - if (this == heap()->old_space()) { |
| - free_list = collector->free_list_old_space().get(); |
| - } else if (this == heap()->code_space()) { |
| - free_list = collector->free_list_code_space().get(); |
| - } else if (this == heap()->map_space()) { |
| - free_list = collector->free_list_map_space().get(); |
| - } else { |
| - // Any PagedSpace might invoke RefillFreeList. We filter all but our old |
| - // generation spaces out. |
| + // Any PagedSpace might invoke RefillFreeList. We filter all but our old |
| + // generation spaces out. |
| + if (identity() != OLD_SPACE && identity() != CODE_SPACE && |
| + identity() != MAP_SPACE) { |
| return; |
| } |
| - DCHECK(free_list != nullptr); |
| - intptr_t added = free_list_.Concatenate(free_list); |
| - accounting_stats_.IncreaseCapacity(added); |
| -} |
| - |
| - |
| -void CompactionSpace::RefillFreeList() { |
| MarkCompactCollector* collector = heap()->mark_compact_collector(); |
| - FreeList* free_list = nullptr; |
| - if (identity() == OLD_SPACE) { |
| - free_list = collector->free_list_old_space().get(); |
| - } else if (identity() == CODE_SPACE) { |
| - free_list = collector->free_list_code_space().get(); |
| - } else { |
| - // Compaction spaces only represent old or code space. |
| - UNREACHABLE(); |
| - } |
| - DCHECK(free_list != nullptr); |
| - intptr_t refilled = 0; |
| - while (refilled < kCompactionMemoryWanted) { |
| - FreeSpace* node = |
| - free_list->TryRemoveMemory(kCompactionMemoryWanted - refilled); |
| - if (node == nullptr) return; |
| - refilled += node->size(); |
| - AddMemory(node->address(), node->size()); |
| - } |
| -} |
| - |
| -void PagedSpace::MoveOverFreeMemory(PagedSpace* other) { |
| - DCHECK(identity() == other->identity()); |
| - // Destroy the linear allocation space of {other}. This is needed to |
| - // (a) not waste the memory and |
| - // (b) keep the rest of the chunk in an iterable state (filler is needed). |
| - other->EmptyAllocationInfo(); |
| - |
| - // Move over the free list. Concatenate makes sure that the source free list |
| - // gets properly reset after moving over all nodes. |
| - intptr_t added = free_list_.Concatenate(other->free_list()); |
| + List<Page*>* swept_pages = collector->swept_pages(identity()); |
| + intptr_t added = 0; |
| + { |
| + base::LockGuard<base::Mutex> guard(collector->swept_pages_mutex()); |
| + for (Page* p : *swept_pages) { |
| + // Only during compaction, pages can actually change ownership. This is |
| + // safe because there exists no other competing action on the page links |
| + // during compaction. |
| + if (is_local() && (p->owner() != this)) { |
| + base::LockGuard<base::Mutex> guard( |
| + reinterpret_cast<PagedSpace*>(p->owner())->mutex()); |
| + p->Unlink(); |
| + p->set_owner(this); |
| + p->InsertAfter(anchor_.prev_page()); |
| + } |
| - // Moved memory is not recorded as allocated memory, but rather increases and |
| - // decreases capacity of the corresponding spaces. |
| - other->accounting_stats_.DecreaseCapacity(added); |
| + p->ForAllFreeListCategories([this, &added](FreeListCategory* category) { |
| + added += category->available(); |
| + category->Relink(); |
| + }); |
| + added += p->wasted_memory(); |
| + } |
| + swept_pages->Rewind(0); |
| + } |
| accounting_stats_.IncreaseCapacity(added); |
| } |
| - |
| void PagedSpace::MergeCompactionSpace(CompactionSpace* other) { |
| + DCHECK(identity() == other->identity()); |
| // Unmerged fields: |
| // area_size_ |
| // anchor_ |
| - MoveOverFreeMemory(other); |
| + other->EmptyAllocationInfo(); |
| // Update and clear accounting statistics. |
| accounting_stats_.Merge(other->accounting_stats_); |
| @@ -1120,9 +1089,18 @@ void PagedSpace::MergeCompactionSpace(CompactionSpace* other) { |
| Page* p = nullptr; |
| while (it.has_next()) { |
| p = it.next(); |
| + |
| + // Relinking requires the category to be unlinked. |
| + p->ForAllFreeListCategories([this](FreeListCategory* category) { |
|
ulan
2016/03/09 15:03:58
[this] is not needed.
I think the following makes
Michael Lippautz
2016/03/10 10:16:59
Done. I added 2 new calls to PagedSpace.
|
| + category->owner()->RemoveCategory(category); |
| + }); |
| + |
| p->Unlink(); |
| p->set_owner(this); |
| p->InsertAfter(anchor_.prev_page()); |
| + |
| + p->ForAllFreeListCategories( |
| + [this](FreeListCategory* category) { category->Relink(); }); |
|
ulan
2016/03/09 15:03:58
[this] is not needed.
DCHECK_EQ(this, category->o
Michael Lippautz
2016/03/10 10:16:59
Done.
|
| } |
| } |
| @@ -1229,17 +1207,12 @@ void PagedSpace::IncreaseCapacity(int size) { |
| accounting_stats_.ExpandSpace(size); |
| } |
| +void PagedSpace::ReleasePage(Page* page) { |
| + DCHECK_EQ(page->LiveBytes(), 0); |
| + DCHECK_EQ(AreaSize(), page->area_size()); |
| + DCHECK_EQ(page->owner(), this); |
| -void PagedSpace::ReleasePage(Page* page, bool evict_free_list_items) { |
| - DCHECK(page->LiveBytes() == 0); |
| - DCHECK(AreaSize() == page->area_size()); |
| - |
| - if (evict_free_list_items) { |
| - intptr_t size = free_list_.EvictFreeListItems(page); |
| - accounting_stats_.AllocateBytes(size); |
| - DCHECK_EQ(AreaSize(), static_cast<int>(size)); |
| - } |
| - |
| + free_list_.EvictFreeListItems(page); |
| DCHECK(!free_list_.ContainsPageFreeListItems(page)); |
| if (Page::FromAllocationTop(allocation_info_.top()) == page) { |
| @@ -1259,7 +1232,6 @@ void PagedSpace::ReleasePage(Page* page, bool evict_free_list_items) { |
| accounting_stats_.ShrinkSpace(AreaSize()); |
| } |
| - |
| #ifdef DEBUG |
| void PagedSpace::Print() {} |
| #endif |
| @@ -2165,102 +2137,31 @@ size_t NewSpace::CommittedPhysicalMemory() { |
| // ----------------------------------------------------------------------------- |
| // Free lists for old object spaces implementation |
| -intptr_t FreeListCategory::Concatenate(FreeListCategory* category) { |
| - intptr_t free_bytes = 0; |
| - if (category->top() != NULL) { |
| - DCHECK(category->end_ != NULL); |
| - free_bytes = category->available(); |
| - if (end_ == NULL) { |
| - end_ = category->end(); |
| - } else { |
| - category->end()->set_next(top()); |
| - } |
| - set_top(category->top()); |
| - available_ += category->available(); |
| - category->Reset(); |
| - } |
| - return free_bytes; |
| -} |
| - |
| void FreeListCategory::Reset() { |
| set_top(nullptr); |
| - set_end(nullptr); |
| + set_prev(nullptr); |
| + set_next(nullptr); |
| available_ = 0; |
| } |
| - |
| -intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) { |
| - intptr_t sum = 0; |
| - FreeSpace* prev_node = nullptr; |
| - for (FreeSpace* cur_node = top(); cur_node != nullptr; |
| - cur_node = cur_node->next()) { |
| - Page* page_for_node = Page::FromAddress(cur_node->address()); |
| - if (page_for_node == p) { |
| - // FreeSpace node on eviction page found, unlink it. |
| - int size = cur_node->size(); |
| - sum += size; |
| - DCHECK((prev_node != nullptr) || (top() == cur_node)); |
| - if (cur_node == top()) { |
| - set_top(cur_node->next()); |
| - } |
| - if (cur_node == end()) { |
| - set_end(prev_node); |
| - } |
| - if (prev_node != nullptr) { |
| - prev_node->set_next(cur_node->next()); |
| - } |
| - continue; |
| - } |
| - prev_node = cur_node; |
| - } |
| - p->add_available_in_free_list(-sum); |
| - available_ -= sum; |
| - return sum; |
| -} |
| - |
| - |
| -bool FreeListCategory::ContainsPageFreeListItemsInList(Page* p) { |
| - FreeSpace* node = top(); |
| - while (node != NULL) { |
| - if (Page::FromAddress(node->address()) == p) return true; |
| - node = node->next(); |
| - } |
| - return false; |
| -} |
| - |
| - |
| FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) { |
| + DCHECK(page()->CanAllocate()); |
| + |
| FreeSpace* node = top(); |
| if (node == nullptr) return nullptr; |
| - |
| - Page* page = Page::FromAddress(node->address()); |
| - while ((node != nullptr) && !page->CanAllocate()) { |
| - available_ -= node->size(); |
| - page->add_available_in_free_list(-(node->Size())); |
| - node = node->next(); |
| - } |
| - |
| - if (node != nullptr) { |
| - set_top(node->next()); |
| - *node_size = node->Size(); |
| - available_ -= *node_size; |
| - } else { |
| - set_top(nullptr); |
| - } |
| - |
| - if (top() == nullptr) { |
| - set_end(nullptr); |
| - } |
| - |
| + set_top(node->next()); |
| + *node_size = node->Size(); |
| + available_ -= *node_size; |
| return node; |
| } |
| +FreeSpace* FreeListCategory::TryPickNodeFromList(int minimum_size, |
| + int* node_size) { |
| + DCHECK(page()->CanAllocate()); |
| -FreeSpace* FreeListCategory::PickNodeFromList(int size_in_bytes, |
| - int* node_size) { |
| FreeSpace* node = PickNodeFromList(node_size); |
| - if ((node != nullptr) && (*node_size < size_in_bytes)) { |
| + if ((node != nullptr) && (*node_size < minimum_size)) { |
| Free(node, *node_size); |
| *node_size = 0; |
| return nullptr; |
| @@ -2268,34 +2169,22 @@ FreeSpace* FreeListCategory::PickNodeFromList(int size_in_bytes, |
| return node; |
| } |
| - |
| -FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes, |
| +FreeSpace* FreeListCategory::SearchForNodeInList(int minimum_size, |
| int* node_size) { |
| + DCHECK(page()->CanAllocate()); |
| + |
| FreeSpace* prev_non_evac_node = nullptr; |
| for (FreeSpace* cur_node = top(); cur_node != nullptr; |
| cur_node = cur_node->next()) { |
| int size = cur_node->size(); |
| - Page* page_for_node = Page::FromAddress(cur_node->address()); |
| - |
| - if ((size >= size_in_bytes) || !page_for_node->CanAllocate()) { |
| - // The node is either large enough or contained in an evacuation |
| - // candidate. In both cases we need to unlink it from the list. |
| + if (size >= minimum_size) { |
| available_ -= size; |
| if (cur_node == top()) { |
| set_top(cur_node->next()); |
| } |
| - if (cur_node == end()) { |
| - set_end(prev_non_evac_node); |
| - } |
| if (prev_non_evac_node != nullptr) { |
| prev_non_evac_node->set_next(cur_node->next()); |
| } |
| - // For evacuation candidates we continue. |
| - if (!page_for_node->CanAllocate()) { |
| - page_for_node->add_available_in_free_list(-size); |
| - continue; |
| - } |
| - // Otherwise we have a large enough node and can return. |
| *node_size = size; |
| return cur_node; |
| } |
| @@ -2305,14 +2194,17 @@ FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes, |
| return nullptr; |
| } |
| +bool FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes, |
| + bool keep_local) { |
| + if (!page()->CanAllocate()) return false; |
| -void FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes) { |
| free_space->set_next(top()); |
| set_top(free_space); |
| - if (end_ == NULL) { |
| - end_ = free_space; |
| - } |
| available_ += size_in_bytes; |
| + if (!keep_local && prev() == nullptr && next() == nullptr) { |
| + owner()->AddCategory(this); |
| + } |
| + return true; |
| } |
| @@ -2329,49 +2221,35 @@ void FreeListCategory::RepairFreeList(Heap* heap) { |
| } |
| } |
| -FreeList::FreeList(PagedSpace* owner) : owner_(owner), wasted_bytes_(0) { |
| - for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - category_[i].Initialize(this, static_cast<FreeListCategoryType>(i)); |
| - } |
| - Reset(); |
| +void FreeListCategory::Relink() { |
| + DCHECK(!is_linked()); |
| + owner()->AddCategory(this); |
| } |
| +void FreeListCategory::Invalidate() { |
| + page()->add_available_in_free_list(-available()); |
| + Reset(); |
| + type_ = kInvalidCategory; |
| +} |
| -intptr_t FreeList::Concatenate(FreeList* other) { |
| - intptr_t usable_bytes = 0; |
| - intptr_t wasted_bytes = 0; |
| - |
| - // This is safe (not going to deadlock) since Concatenate operations |
| - // are never performed on the same free lists at the same time in |
| - // reverse order. Furthermore, we only lock if the PagedSpace containing |
| - // the free list is know to be globally available, i.e., not local. |
| - if (!owner()->is_local()) mutex_.Lock(); |
| - if (!other->owner()->is_local()) other->mutex()->Lock(); |
| - |
| - wasted_bytes = other->wasted_bytes_; |
| - wasted_bytes_ += wasted_bytes; |
| - other->wasted_bytes_ = 0; |
| - |
| +FreeList::FreeList(PagedSpace* owner) : owner_(owner), wasted_bytes_(0) { |
| for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - usable_bytes += category_[i].Concatenate( |
| - other->GetFreeListCategory(static_cast<FreeListCategoryType>(i))); |
| + categories_[i] = nullptr; |
| } |
| - |
| - if (!other->owner()->is_local()) other->mutex()->Unlock(); |
| - if (!owner()->is_local()) mutex_.Unlock(); |
| - return usable_bytes + wasted_bytes; |
| + Reset(); |
| } |
| void FreeList::Reset() { |
| + ForAllFreeListCategories( |
| + [](FreeListCategory* category) { category->Reset(); }); |
| for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - category_[i].Reset(); |
| + categories_[i] = nullptr; |
| } |
| ResetStats(); |
| } |
| - |
| -int FreeList::Free(Address start, int size_in_bytes) { |
| +int FreeList::Free(Address start, int size_in_bytes, bool keep_local) { |
| if (size_in_bytes == 0) return 0; |
| owner()->heap()->CreateFillerObjectAt(start, size_in_bytes, |
| @@ -2382,7 +2260,7 @@ int FreeList::Free(Address start, int size_in_bytes) { |
| // Blocks have to be a minimum size to hold free list items. |
| if (size_in_bytes < kMinBlockSize) { |
| page->add_wasted_memory(size_in_bytes); |
| - wasted_bytes_ += size_in_bytes; |
| + wasted_bytes_.Increment(size_in_bytes); |
| return size_in_bytes; |
| } |
| @@ -2390,16 +2268,33 @@ int FreeList::Free(Address start, int size_in_bytes) { |
| // Insert other blocks at the head of a free list of the appropriate |
| // magnitude. |
| FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes); |
| - category_[type].Free(free_space, size_in_bytes); |
| - page->add_available_in_free_list(size_in_bytes); |
| - |
| - DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
| + if (page->free_list_category(type)->Free(free_space, size_in_bytes, |
| + keep_local)) { |
| + page->add_available_in_free_list(size_in_bytes); |
| + } |
| return 0; |
| } |
| +FreeSpace* FreeList::FindNodeIn(FreeListCategoryType type, int* node_size) { |
| + FreeListCategoryIterator it(this, type); |
| + FreeSpace* node = nullptr; |
| + while (it.HasNext()) { |
| + FreeListCategory* current = it.Next(); |
| + node = current->PickNodeFromList(node_size); |
| + if (node != nullptr) { |
| + Page::FromAddress(node->address()) |
| + ->add_available_in_free_list(-(*node_size)); |
| + DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
| + return node; |
| + } |
| + } |
| + return node; |
| +} |
| -FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) { |
| - FreeSpace* node = GetFreeListCategory(category)->PickNodeFromList(node_size); |
| +FreeSpace* FreeList::TryFindNodeIn(FreeListCategoryType type, int* node_size, |
| + int minimum_size) { |
| + FreeSpace* node = |
| + categories_[type]->TryPickNodeFromList(minimum_size, node_size); |
| if (node != nullptr) { |
| Page::FromAddress(node->address()) |
| ->add_available_in_free_list(-(*node_size)); |
| @@ -2408,6 +2303,22 @@ FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) { |
| return node; |
| } |
| +FreeSpace* FreeList::SearchForNodeInList(FreeListCategoryType type, |
| + int* node_size, int minimum_size) { |
| + FreeListCategoryIterator it(this, type); |
| + FreeSpace* node = nullptr; |
| + while (it.HasNext()) { |
| + FreeListCategory* current = it.Next(); |
| + node = current->SearchForNodeInList(minimum_size, node_size); |
| + if (node != nullptr) { |
| + Page::FromAddress(node->address()) |
| + ->add_available_in_free_list(-(*node_size)); |
| + DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
| + return node; |
| + } |
| + } |
| + return node; |
| +} |
| FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { |
| FreeSpace* node = nullptr; |
| @@ -2424,10 +2335,8 @@ FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { |
| // Next search the huge list for free list nodes. This takes linear time in |
| // the number of huge elements. |
| - node = category_[kHuge].SearchForNodeInList(size_in_bytes, node_size); |
| + node = SearchForNodeInList(kHuge, node_size, size_in_bytes); |
| if (node != nullptr) { |
| - page = Page::FromAddress(node->address()); |
| - page->add_available_in_free_list(-(*node_size)); |
| DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
| return node; |
| } |
| @@ -2439,7 +2348,7 @@ FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { |
| // Now search the best fitting free list for a node that has at least the |
| // requested size. |
| type = SelectFreeListCategoryType(size_in_bytes); |
| - node = category_[type].PickNodeFromList(size_in_bytes, node_size); |
| + node = TryFindNodeIn(type, node_size, size_in_bytes); |
| if (node != nullptr) { |
| DCHECK(size_in_bytes <= *node_size); |
| page = Page::FromAddress(node->address()); |
| @@ -2450,38 +2359,6 @@ FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { |
| return node; |
| } |
| - |
| -FreeSpace* FreeList::TryRemoveMemory(intptr_t hint_size_in_bytes) { |
| - hint_size_in_bytes = RoundDown(hint_size_in_bytes, kPointerSize); |
| - base::LockGuard<base::Mutex> guard(&mutex_); |
| - FreeSpace* node = nullptr; |
| - int node_size = 0; |
| - // Try to find a node that fits exactly. |
| - node = FindNodeFor(static_cast<int>(hint_size_in_bytes), &node_size); |
| - // If no node could be found get as much memory as possible. |
| - if (node == nullptr) node = FindNodeIn(kHuge, &node_size); |
| - if (node == nullptr) node = FindNodeIn(kLarge, &node_size); |
| - if (node != nullptr) { |
| - // We round up the size to (kMinBlockSize + kPointerSize) to (a) have a |
| - // size larger then the minimum size required for FreeSpace, and (b) to get |
| - // a block that can actually be freed into some FreeList later on. |
| - if (hint_size_in_bytes <= kMinBlockSize) { |
| - hint_size_in_bytes = kMinBlockSize + kPointerSize; |
| - } |
| - // Give back left overs that were not required by {size_in_bytes}. |
| - intptr_t left_over = node_size - hint_size_in_bytes; |
| - |
| - // Do not bother to return anything below {kMinBlockSize} as it would be |
| - // immediately discarded anyways. |
| - if (left_over > kMinBlockSize) { |
| - Free(node->address() + hint_size_in_bytes, static_cast<int>(left_over)); |
| - node->set_size(static_cast<int>(hint_size_in_bytes)); |
| - } |
| - } |
| - return node; |
| -} |
| - |
| - |
| // Allocation on the old space free list. If it succeeds then a new linear |
| // allocation space has been set up with the top and limit of the space. If |
| // the allocation fails then NULL is returned, and the caller can perform a GC |
| @@ -2555,32 +2432,77 @@ HeapObject* FreeList::Allocate(int size_in_bytes) { |
| return new_node; |
| } |
| - |
| -intptr_t FreeList::EvictFreeListItems(Page* p) { |
| - intptr_t sum = category_[kHuge].EvictFreeListItemsInList(p); |
| - if (sum < p->area_size()) { |
| - for (int i = kFirstCategory; i <= kLarge; i++) { |
| - sum += category_[i].EvictFreeListItemsInList(p); |
| - } |
| - } |
| +intptr_t FreeList::EvictFreeListItems(Page* page) { |
| + intptr_t sum = 0; |
| + page->ForAllFreeListCategories( |
| + [this, &sum, page](FreeListCategory* category) { |
| + if (category->owner() == this && category->is_linked()) { |
|
ulan
2016/03/09 15:03:58
Shouldn't this be DCHECK?
Michael Lippautz
2016/03/10 10:16:59
The way we use the method we currently could have
|
| + sum += category->available(); |
| + RemoveCategory(category); |
| + category->Invalidate(); |
| + } |
| + }); |
| return sum; |
| } |
| +bool FreeList::ContainsPageFreeListItems(Page* page) { |
| + bool contained = false; |
| + page->ForAllFreeListCategories( |
| + [this, &contained](FreeListCategory* category) { |
| + if (category->owner() == this && category->is_linked()) { |
| + contained = true; |
| + } |
| + }); |
| + return contained; |
| +} |
| -bool FreeList::ContainsPageFreeListItems(Page* p) { |
| - for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - if (category_[i].EvictFreeListItemsInList(p)) { |
| - return true; |
| - } |
| +void FreeList::RepairLists(Heap* heap) { |
| + ForAllFreeListCategories( |
| + [heap](FreeListCategory* category) { category->RepairFreeList(heap); }); |
| +} |
| + |
| +bool FreeList::AddCategory(FreeListCategory* category) { |
| + FreeListCategoryType type = category->type_; |
| + FreeListCategory* top = categories_[type]; |
| + |
| + if (category->is_empty()) return false; |
| + if (top == category) return false; |
| + |
| + // Common double-linked list insertion. |
| + if (top != nullptr) { |
| + top->set_prev(category); |
| } |
| - return false; |
| + category->set_next(top); |
| + categories_[type] = category; |
| + return true; |
| } |
| +void FreeList::RemoveCategory(FreeListCategory* category) { |
| + FreeListCategoryType type = category->type_; |
| + FreeListCategory* top = categories_[type]; |
| -void FreeList::RepairLists(Heap* heap) { |
| - for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - category_[i].RepairFreeList(heap); |
| + // Common double-linked list removal. |
| + if (top == category) { |
| + categories_[type] = category->next(); |
| + } |
| + if (category->prev() != nullptr) { |
| + category->prev()->set_next(category->next()); |
| + } |
| + if (category->next() != nullptr) { |
| + category->next()->set_prev(category->prev()); |
| + } |
| + category->set_next(nullptr); |
| + category->set_prev(nullptr); |
| +} |
| + |
| +void FreeList::PrintCategories(FreeListCategoryType type) { |
| + FreeListCategoryIterator it(this, type); |
| + PrintF("FreeList[%p, top=%p, %d] ", this, categories_[type], type); |
| + while (it.HasNext()) { |
| + FreeListCategory* current = it.Next(); |
| + PrintF("%p -> ", current); |
| } |
| + PrintF("null\n"); |
| } |
| @@ -2615,12 +2537,11 @@ bool FreeListCategory::IsVeryLong() { |
| bool FreeList::IsVeryLong() { |
| - for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - if (category_[i].IsVeryLong()) { |
| - return true; |
| - } |
| - } |
| - return false; |
| + bool is_very_long = false; |
| + ForAllFreeListCategories([&is_very_long](FreeListCategory* category) { |
| + if (category->IsVeryLong()) is_very_long = true; |
| + }); |
| + return is_very_long; |
| } |
| @@ -2629,9 +2550,8 @@ bool FreeList::IsVeryLong() { |
| // kVeryLongFreeList. |
| intptr_t FreeList::SumFreeLists() { |
| intptr_t sum = 0; |
| - for (int i = kFirstCategory; i < kNumberOfCategories; i++) { |
| - sum += category_[i].SumFreeList(); |
| - } |
| + ForAllFreeListCategories( |
| + [&sum](FreeListCategory* category) { sum += category->SumFreeList(); }); |
| return sum; |
| } |
| #endif |