| Index: src/heap/spaces.cc
|
| diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
|
| index f7cce1430e55eee5e436f9b49639efcfaebb858b..1e0ed9c8fd10dbefc3e1646de6fd1c979ada6b38 100644
|
| --- a/src/heap/spaces.cc
|
| +++ b/src/heap/spaces.cc
|
| @@ -1030,79 +1030,46 @@ 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());
|
| + List<Page*>* swept_pages = collector->swept_pages(identity());
|
| + intptr_t added = 0;
|
| + {
|
| + base::LockGuard<base::Mutex> guard(collector->swept_pages_mutex());
|
| + for (int i = swept_pages->length() - 1; i >= 0; --i) {
|
| + Page* p = (*swept_pages)[i];
|
| + // 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)) {
|
| + if (added > kCompactionMemoryWanted) break;
|
| + base::LockGuard<base::Mutex> guard(
|
| + reinterpret_cast<PagedSpace*>(p->owner())->mutex());
|
| + p->Unlink();
|
| + p->set_owner(this);
|
| + p->InsertAfter(anchor_.prev_page());
|
| + }
|
| + added += RelinkFreeListCategories(p);
|
| + added += p->wasted_memory();
|
| + swept_pages->Remove(i);
|
| + }
|
| }
|
| -}
|
| -
|
| -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());
|
| -
|
| - // Moved memory is not recorded as allocated memory, but rather increases and
|
| - // decreases capacity of the corresponding spaces.
|
| - other->accounting_stats_.DecreaseCapacity(added);
|
| 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_);
|
| @@ -1119,9 +1086,14 @@ void PagedSpace::MergeCompactionSpace(CompactionSpace* other) {
|
| Page* p = nullptr;
|
| while (it.has_next()) {
|
| p = it.next();
|
| +
|
| + // Relinking requires the category to be unlinked.
|
| + other->UnlinkFreeListCategories(p);
|
| +
|
| p->Unlink();
|
| p->set_owner(this);
|
| p->InsertAfter(anchor_.prev_page());
|
| + RelinkFreeListCategories(p);
|
| }
|
| }
|
|
|
| @@ -1238,17 +1210,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) {
|
| @@ -1268,7 +1235,6 @@ void PagedSpace::ReleasePage(Page* page, bool evict_free_list_items) {
|
| accounting_stats_.ShrinkSpace(AreaSize());
|
| }
|
|
|
| -
|
| #ifdef DEBUG
|
| void PagedSpace::Print() {}
|
| #endif
|
| @@ -2175,137 +2141,54 @@ 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)) {
|
| - Free(node, *node_size);
|
| + if ((node != nullptr) && (*node_size < minimum_size)) {
|
| + Free(node, *node_size, kLinkCategory);
|
| *node_size = 0;
|
| return nullptr;
|
| }
|
| 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;
|
| }
|
| @@ -2315,14 +2198,17 @@ FreeSpace* FreeListCategory::SearchForNodeInList(int size_in_bytes,
|
| return nullptr;
|
| }
|
|
|
| +bool FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes,
|
| + FreeMode mode) {
|
| + 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 ((mode == kLinkCategory) && (prev() == nullptr) && (next() == nullptr)) {
|
| + owner()->AddCategory(this);
|
| + }
|
| + return true;
|
| }
|
|
|
|
|
| @@ -2339,49 +2225,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, FreeMode mode) {
|
| if (size_in_bytes == 0) return 0;
|
|
|
| owner()->heap()->CreateFillerObjectAt(start, size_in_bytes,
|
| @@ -2392,7 +2264,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;
|
| }
|
|
|
| @@ -2400,16 +2272,34 @@ 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, mode)) {
|
| + 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;
|
| + }
|
| + RemoveCategory(current);
|
| + }
|
| + 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) {
|
| + if (categories_[type] == nullptr) return nullptr;
|
| + FreeSpace* node =
|
| + categories_[type]->TryPickNodeFromList(minimum_size, node_size);
|
| if (node != nullptr) {
|
| Page::FromAddress(node->address())
|
| ->add_available_in_free_list(-(*node_size));
|
| @@ -2418,6 +2308,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;
|
| @@ -2434,10 +2340,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;
|
| }
|
| @@ -2449,7 +2353,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());
|
| @@ -2460,38 +2364,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
|
| @@ -2565,32 +2437,76 @@ 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) {
|
| + DCHECK_EQ(this, category->owner());
|
| + 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");
|
| }
|
|
|
|
|
| @@ -2606,7 +2522,6 @@ intptr_t FreeListCategory::SumFreeList() {
|
| return sum;
|
| }
|
|
|
| -
|
| int FreeListCategory::FreeListLength() {
|
| int length = 0;
|
| FreeSpace* cur = top();
|
| @@ -2618,16 +2533,13 @@ int FreeListCategory::FreeListLength() {
|
| return length;
|
| }
|
|
|
| -
|
| -bool FreeListCategory::IsVeryLong() {
|
| - return FreeListLength() == kVeryLongFreeList;
|
| -}
|
| -
|
| -
|
| bool FreeList::IsVeryLong() {
|
| + int len = 0;
|
| for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
|
| - if (category_[i].IsVeryLong()) {
|
| - return true;
|
| + FreeListCategoryIterator it(this, static_cast<FreeListCategoryType>(i));
|
| + while (it.HasNext()) {
|
| + len += it.Next()->FreeListLength();
|
| + if (len >= FreeListCategory::kVeryLongFreeList) return true;
|
| }
|
| }
|
| return false;
|
| @@ -2639,9 +2551,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
|
|
|