11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/heap/free-list.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/base/macros.h"
81cb0ef41Sopenharmony_ci#include "src/common/globals.h"
91cb0ef41Sopenharmony_ci#include "src/heap/free-list-inl.h"
101cb0ef41Sopenharmony_ci#include "src/heap/heap.h"
111cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk-inl.h"
121cb0ef41Sopenharmony_ci#include "src/objects/free-space-inl.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace v8 {
151cb0ef41Sopenharmony_cinamespace internal {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
181cb0ef41Sopenharmony_ci// Free lists for old object spaces implementation
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_civoid FreeListCategory::Reset(FreeList* owner) {
211cb0ef41Sopenharmony_ci  if (is_linked(owner) && !top().is_null()) {
221cb0ef41Sopenharmony_ci    owner->DecreaseAvailableBytes(available_);
231cb0ef41Sopenharmony_ci  }
241cb0ef41Sopenharmony_ci  set_top(FreeSpace());
251cb0ef41Sopenharmony_ci  set_prev(nullptr);
261cb0ef41Sopenharmony_ci  set_next(nullptr);
271cb0ef41Sopenharmony_ci  available_ = 0;
281cb0ef41Sopenharmony_ci}
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciFreeSpace FreeListCategory::PickNodeFromList(size_t minimum_size,
311cb0ef41Sopenharmony_ci                                             size_t* node_size) {
321cb0ef41Sopenharmony_ci  FreeSpace node = top();
331cb0ef41Sopenharmony_ci  DCHECK(!node.is_null());
341cb0ef41Sopenharmony_ci  DCHECK(Page::FromHeapObject(node)->CanAllocate());
351cb0ef41Sopenharmony_ci  if (static_cast<size_t>(node.Size()) < minimum_size) {
361cb0ef41Sopenharmony_ci    *node_size = 0;
371cb0ef41Sopenharmony_ci    return FreeSpace();
381cb0ef41Sopenharmony_ci  }
391cb0ef41Sopenharmony_ci  set_top(node.next());
401cb0ef41Sopenharmony_ci  *node_size = node.Size();
411cb0ef41Sopenharmony_ci  UpdateCountersAfterAllocation(*node_size);
421cb0ef41Sopenharmony_ci  return node;
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ciFreeSpace FreeListCategory::SearchForNodeInList(size_t minimum_size,
461cb0ef41Sopenharmony_ci                                                size_t* node_size) {
471cb0ef41Sopenharmony_ci  FreeSpace prev_non_evac_node;
481cb0ef41Sopenharmony_ci  for (FreeSpace cur_node = top(); !cur_node.is_null();
491cb0ef41Sopenharmony_ci       cur_node = cur_node.next()) {
501cb0ef41Sopenharmony_ci    DCHECK(Page::FromHeapObject(cur_node)->CanAllocate());
511cb0ef41Sopenharmony_ci    size_t size = cur_node.size(kRelaxedLoad);
521cb0ef41Sopenharmony_ci    if (size >= minimum_size) {
531cb0ef41Sopenharmony_ci      DCHECK_GE(available_, size);
541cb0ef41Sopenharmony_ci      UpdateCountersAfterAllocation(size);
551cb0ef41Sopenharmony_ci      if (cur_node == top()) {
561cb0ef41Sopenharmony_ci        set_top(cur_node.next());
571cb0ef41Sopenharmony_ci      }
581cb0ef41Sopenharmony_ci      if (!prev_non_evac_node.is_null()) {
591cb0ef41Sopenharmony_ci        MemoryChunk* chunk = MemoryChunk::FromHeapObject(prev_non_evac_node);
601cb0ef41Sopenharmony_ci        if (chunk->owner_identity() == CODE_SPACE) {
611cb0ef41Sopenharmony_ci          chunk->heap()->UnprotectAndRegisterMemoryChunk(
621cb0ef41Sopenharmony_ci              chunk, UnprotectMemoryOrigin::kMaybeOffMainThread);
631cb0ef41Sopenharmony_ci        }
641cb0ef41Sopenharmony_ci        prev_non_evac_node.set_next(cur_node.next());
651cb0ef41Sopenharmony_ci      }
661cb0ef41Sopenharmony_ci      *node_size = size;
671cb0ef41Sopenharmony_ci      return cur_node;
681cb0ef41Sopenharmony_ci    }
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci    prev_non_evac_node = cur_node;
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci  return FreeSpace();
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_civoid FreeListCategory::Free(Address start, size_t size_in_bytes, FreeMode mode,
761cb0ef41Sopenharmony_ci                            FreeList* owner) {
771cb0ef41Sopenharmony_ci  FreeSpace free_space = FreeSpace::cast(HeapObject::FromAddress(start));
781cb0ef41Sopenharmony_ci  free_space.set_next(top());
791cb0ef41Sopenharmony_ci  set_top(free_space);
801cb0ef41Sopenharmony_ci  available_ += size_in_bytes;
811cb0ef41Sopenharmony_ci  if (mode == kLinkCategory) {
821cb0ef41Sopenharmony_ci    if (is_linked(owner)) {
831cb0ef41Sopenharmony_ci      owner->IncreaseAvailableBytes(size_in_bytes);
841cb0ef41Sopenharmony_ci    } else {
851cb0ef41Sopenharmony_ci      owner->AddCategory(this);
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_civoid FreeListCategory::RepairFreeList(Heap* heap) {
911cb0ef41Sopenharmony_ci  Map free_space_map = ReadOnlyRoots(heap).free_space_map();
921cb0ef41Sopenharmony_ci  FreeSpace n = top();
931cb0ef41Sopenharmony_ci  while (!n.is_null()) {
941cb0ef41Sopenharmony_ci    ObjectSlot map_slot = n.map_slot();
951cb0ef41Sopenharmony_ci    if (map_slot.contains_map_value(kNullAddress)) {
961cb0ef41Sopenharmony_ci      map_slot.store_map(free_space_map);
971cb0ef41Sopenharmony_ci    } else {
981cb0ef41Sopenharmony_ci      DCHECK(map_slot.contains_map_value(free_space_map.ptr()));
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci    n = n.next();
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_civoid FreeListCategory::Relink(FreeList* owner) {
1051cb0ef41Sopenharmony_ci  DCHECK(!is_linked(owner));
1061cb0ef41Sopenharmony_ci  owner->AddCategory(this);
1071cb0ef41Sopenharmony_ci}
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci// ------------------------------------------------
1101cb0ef41Sopenharmony_ci// Generic FreeList methods (alloc/free related)
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ciFreeList* FreeList::CreateFreeList() { return new FreeListManyCachedOrigin(); }
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ciFreeSpace FreeList::TryFindNodeIn(FreeListCategoryType type,
1151cb0ef41Sopenharmony_ci                                  size_t minimum_size, size_t* node_size) {
1161cb0ef41Sopenharmony_ci  FreeListCategory* category = categories_[type];
1171cb0ef41Sopenharmony_ci  if (category == nullptr) return FreeSpace();
1181cb0ef41Sopenharmony_ci  FreeSpace node = category->PickNodeFromList(minimum_size, node_size);
1191cb0ef41Sopenharmony_ci  if (!node.is_null()) {
1201cb0ef41Sopenharmony_ci    DecreaseAvailableBytes(*node_size);
1211cb0ef41Sopenharmony_ci    DCHECK(IsVeryLong() || Available() == SumFreeLists());
1221cb0ef41Sopenharmony_ci  }
1231cb0ef41Sopenharmony_ci  if (category->is_empty()) {
1241cb0ef41Sopenharmony_ci    RemoveCategory(category);
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci  return node;
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ciFreeSpace FreeList::SearchForNodeInList(FreeListCategoryType type,
1301cb0ef41Sopenharmony_ci                                        size_t minimum_size,
1311cb0ef41Sopenharmony_ci                                        size_t* node_size) {
1321cb0ef41Sopenharmony_ci  FreeListCategoryIterator it(this, type);
1331cb0ef41Sopenharmony_ci  FreeSpace node;
1341cb0ef41Sopenharmony_ci  while (it.HasNext()) {
1351cb0ef41Sopenharmony_ci    FreeListCategory* current = it.Next();
1361cb0ef41Sopenharmony_ci    node = current->SearchForNodeInList(minimum_size, node_size);
1371cb0ef41Sopenharmony_ci    if (!node.is_null()) {
1381cb0ef41Sopenharmony_ci      DecreaseAvailableBytes(*node_size);
1391cb0ef41Sopenharmony_ci      DCHECK(IsVeryLong() || Available() == SumFreeLists());
1401cb0ef41Sopenharmony_ci      if (current->is_empty()) {
1411cb0ef41Sopenharmony_ci        RemoveCategory(current);
1421cb0ef41Sopenharmony_ci      }
1431cb0ef41Sopenharmony_ci      return node;
1441cb0ef41Sopenharmony_ci    }
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci  return node;
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_cisize_t FreeList::Free(Address start, size_t size_in_bytes, FreeMode mode) {
1501cb0ef41Sopenharmony_ci  Page* page = Page::FromAddress(start);
1511cb0ef41Sopenharmony_ci  page->DecreaseAllocatedBytes(size_in_bytes);
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  // Blocks have to be a minimum size to hold free list items.
1541cb0ef41Sopenharmony_ci  if (size_in_bytes < min_block_size_) {
1551cb0ef41Sopenharmony_ci    page->add_wasted_memory(size_in_bytes);
1561cb0ef41Sopenharmony_ci    wasted_bytes_ += size_in_bytes;
1571cb0ef41Sopenharmony_ci    return size_in_bytes;
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  // Insert other blocks at the head of a free list of the appropriate
1611cb0ef41Sopenharmony_ci  // magnitude.
1621cb0ef41Sopenharmony_ci  FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
1631cb0ef41Sopenharmony_ci  page->free_list_category(type)->Free(start, size_in_bytes, mode, this);
1641cb0ef41Sopenharmony_ci  DCHECK_EQ(page->AvailableInFreeList(),
1651cb0ef41Sopenharmony_ci            page->AvailableInFreeListFromAllocatedBytes());
1661cb0ef41Sopenharmony_ci  return 0;
1671cb0ef41Sopenharmony_ci}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci// ------------------------------------------------
1701cb0ef41Sopenharmony_ci// FreeListMany implementation
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ciconstexpr unsigned int FreeListMany::categories_min[kNumberOfCategories];
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ciFreeListMany::FreeListMany() {
1751cb0ef41Sopenharmony_ci  // Initializing base (FreeList) fields
1761cb0ef41Sopenharmony_ci  number_of_categories_ = kNumberOfCategories;
1771cb0ef41Sopenharmony_ci  last_category_ = number_of_categories_ - 1;
1781cb0ef41Sopenharmony_ci  min_block_size_ = kMinBlockSize;
1791cb0ef41Sopenharmony_ci  categories_ = new FreeListCategory*[number_of_categories_]();
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  Reset();
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ciFreeListMany::~FreeListMany() { delete[] categories_; }
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_cisize_t FreeListMany::GuaranteedAllocatable(size_t maximum_freed) {
1871cb0ef41Sopenharmony_ci  if (maximum_freed < categories_min[0]) {
1881cb0ef41Sopenharmony_ci    return 0;
1891cb0ef41Sopenharmony_ci  }
1901cb0ef41Sopenharmony_ci  for (int cat = kFirstCategory + 1; cat <= last_category_; cat++) {
1911cb0ef41Sopenharmony_ci    if (maximum_freed < categories_min[cat]) {
1921cb0ef41Sopenharmony_ci      return categories_min[cat - 1];
1931cb0ef41Sopenharmony_ci    }
1941cb0ef41Sopenharmony_ci  }
1951cb0ef41Sopenharmony_ci  return maximum_freed;
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ciPage* FreeListMany::GetPageForSize(size_t size_in_bytes) {
1991cb0ef41Sopenharmony_ci  FreeListCategoryType minimum_category =
2001cb0ef41Sopenharmony_ci      SelectFreeListCategoryType(size_in_bytes);
2011cb0ef41Sopenharmony_ci  Page* page = nullptr;
2021cb0ef41Sopenharmony_ci  for (int cat = minimum_category + 1; !page && cat <= last_category_; cat++) {
2031cb0ef41Sopenharmony_ci    page = GetPageForCategoryType(cat);
2041cb0ef41Sopenharmony_ci  }
2051cb0ef41Sopenharmony_ci  if (!page) {
2061cb0ef41Sopenharmony_ci    // Might return a page in which |size_in_bytes| will not fit.
2071cb0ef41Sopenharmony_ci    page = GetPageForCategoryType(minimum_category);
2081cb0ef41Sopenharmony_ci  }
2091cb0ef41Sopenharmony_ci  return page;
2101cb0ef41Sopenharmony_ci}
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ciFreeSpace FreeListMany::Allocate(size_t size_in_bytes, size_t* node_size,
2131cb0ef41Sopenharmony_ci                                 AllocationOrigin origin) {
2141cb0ef41Sopenharmony_ci  DCHECK_GE(kMaxBlockSize, size_in_bytes);
2151cb0ef41Sopenharmony_ci  FreeSpace node;
2161cb0ef41Sopenharmony_ci  FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
2171cb0ef41Sopenharmony_ci  for (int i = type; i < last_category_ && node.is_null(); i++) {
2181cb0ef41Sopenharmony_ci    node = TryFindNodeIn(static_cast<FreeListCategoryType>(i), size_in_bytes,
2191cb0ef41Sopenharmony_ci                         node_size);
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  if (node.is_null()) {
2231cb0ef41Sopenharmony_ci    // Searching each element of the last category.
2241cb0ef41Sopenharmony_ci    node = SearchForNodeInList(last_category_, size_in_bytes, node_size);
2251cb0ef41Sopenharmony_ci  }
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci  if (!node.is_null()) {
2281cb0ef41Sopenharmony_ci    Page::FromHeapObject(node)->IncreaseAllocatedBytes(*node_size);
2291cb0ef41Sopenharmony_ci  }
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci  DCHECK(IsVeryLong() || Available() == SumFreeLists());
2321cb0ef41Sopenharmony_ci  return node;
2331cb0ef41Sopenharmony_ci}
2341cb0ef41Sopenharmony_ci
2351cb0ef41Sopenharmony_ci// ------------------------------------------------
2361cb0ef41Sopenharmony_ci// FreeListManyCached implementation
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ciFreeListManyCached::FreeListManyCached() { ResetCache(); }
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_civoid FreeListManyCached::Reset() {
2411cb0ef41Sopenharmony_ci  ResetCache();
2421cb0ef41Sopenharmony_ci  FreeListMany::Reset();
2431cb0ef41Sopenharmony_ci}
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_cibool FreeListManyCached::AddCategory(FreeListCategory* category) {
2461cb0ef41Sopenharmony_ci  bool was_added = FreeList::AddCategory(category);
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  // Updating cache
2491cb0ef41Sopenharmony_ci  if (was_added) {
2501cb0ef41Sopenharmony_ci    UpdateCacheAfterAddition(category->type_);
2511cb0ef41Sopenharmony_ci  }
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci#ifdef DEBUG
2541cb0ef41Sopenharmony_ci  CheckCacheIntegrity();
2551cb0ef41Sopenharmony_ci#endif
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  return was_added;
2581cb0ef41Sopenharmony_ci}
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_civoid FreeListManyCached::RemoveCategory(FreeListCategory* category) {
2611cb0ef41Sopenharmony_ci  FreeList::RemoveCategory(category);
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  // Updating cache
2641cb0ef41Sopenharmony_ci  int type = category->type_;
2651cb0ef41Sopenharmony_ci  if (categories_[type] == nullptr) {
2661cb0ef41Sopenharmony_ci    UpdateCacheAfterRemoval(type);
2671cb0ef41Sopenharmony_ci  }
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci#ifdef DEBUG
2701cb0ef41Sopenharmony_ci  CheckCacheIntegrity();
2711cb0ef41Sopenharmony_ci#endif
2721cb0ef41Sopenharmony_ci}
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_cisize_t FreeListManyCached::Free(Address start, size_t size_in_bytes,
2751cb0ef41Sopenharmony_ci                                FreeMode mode) {
2761cb0ef41Sopenharmony_ci  Page* page = Page::FromAddress(start);
2771cb0ef41Sopenharmony_ci  page->DecreaseAllocatedBytes(size_in_bytes);
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci  // Blocks have to be a minimum size to hold free list items.
2801cb0ef41Sopenharmony_ci  if (size_in_bytes < min_block_size_) {
2811cb0ef41Sopenharmony_ci    page->add_wasted_memory(size_in_bytes);
2821cb0ef41Sopenharmony_ci    wasted_bytes_ += size_in_bytes;
2831cb0ef41Sopenharmony_ci    return size_in_bytes;
2841cb0ef41Sopenharmony_ci  }
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci  // Insert other blocks at the head of a free list of the appropriate
2871cb0ef41Sopenharmony_ci  // magnitude.
2881cb0ef41Sopenharmony_ci  FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
2891cb0ef41Sopenharmony_ci  page->free_list_category(type)->Free(start, size_in_bytes, mode, this);
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  // Updating cache
2921cb0ef41Sopenharmony_ci  if (mode == kLinkCategory) {
2931cb0ef41Sopenharmony_ci    UpdateCacheAfterAddition(type);
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci#ifdef DEBUG
2961cb0ef41Sopenharmony_ci    CheckCacheIntegrity();
2971cb0ef41Sopenharmony_ci#endif
2981cb0ef41Sopenharmony_ci  }
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  DCHECK_EQ(page->AvailableInFreeList(),
3011cb0ef41Sopenharmony_ci            page->AvailableInFreeListFromAllocatedBytes());
3021cb0ef41Sopenharmony_ci  return 0;
3031cb0ef41Sopenharmony_ci}
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ciFreeSpace FreeListManyCached::Allocate(size_t size_in_bytes, size_t* node_size,
3061cb0ef41Sopenharmony_ci                                       AllocationOrigin origin) {
3071cb0ef41Sopenharmony_ci  USE(origin);
3081cb0ef41Sopenharmony_ci  DCHECK_GE(kMaxBlockSize, size_in_bytes);
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci  FreeSpace node;
3111cb0ef41Sopenharmony_ci  FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes);
3121cb0ef41Sopenharmony_ci  type = next_nonempty_category[type];
3131cb0ef41Sopenharmony_ci  for (; type < last_category_; type = next_nonempty_category[type + 1]) {
3141cb0ef41Sopenharmony_ci    node = TryFindNodeIn(type, size_in_bytes, node_size);
3151cb0ef41Sopenharmony_ci    if (!node.is_null()) break;
3161cb0ef41Sopenharmony_ci  }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  if (node.is_null()) {
3191cb0ef41Sopenharmony_ci    // Searching each element of the last category.
3201cb0ef41Sopenharmony_ci    type = last_category_;
3211cb0ef41Sopenharmony_ci    node = SearchForNodeInList(type, size_in_bytes, node_size);
3221cb0ef41Sopenharmony_ci  }
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci  // Updating cache
3251cb0ef41Sopenharmony_ci  if (!node.is_null() && categories_[type] == nullptr) {
3261cb0ef41Sopenharmony_ci    UpdateCacheAfterRemoval(type);
3271cb0ef41Sopenharmony_ci  }
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci#ifdef DEBUG
3301cb0ef41Sopenharmony_ci  CheckCacheIntegrity();
3311cb0ef41Sopenharmony_ci#endif
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci  if (!node.is_null()) {
3341cb0ef41Sopenharmony_ci    Page::FromHeapObject(node)->IncreaseAllocatedBytes(*node_size);
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  DCHECK(IsVeryLong() || Available() == SumFreeLists());
3381cb0ef41Sopenharmony_ci  return node;
3391cb0ef41Sopenharmony_ci}
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci// ------------------------------------------------
3421cb0ef41Sopenharmony_ci// FreeListManyCachedFastPath implementation
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ciFreeSpace FreeListManyCachedFastPath::Allocate(size_t size_in_bytes,
3451cb0ef41Sopenharmony_ci                                               size_t* node_size,
3461cb0ef41Sopenharmony_ci                                               AllocationOrigin origin) {
3471cb0ef41Sopenharmony_ci  USE(origin);
3481cb0ef41Sopenharmony_ci  DCHECK_GE(kMaxBlockSize, size_in_bytes);
3491cb0ef41Sopenharmony_ci  FreeSpace node;
3501cb0ef41Sopenharmony_ci
3511cb0ef41Sopenharmony_ci  // Fast path part 1: searching the last categories
3521cb0ef41Sopenharmony_ci  FreeListCategoryType first_category =
3531cb0ef41Sopenharmony_ci      SelectFastAllocationFreeListCategoryType(size_in_bytes);
3541cb0ef41Sopenharmony_ci  FreeListCategoryType type = first_category;
3551cb0ef41Sopenharmony_ci  for (type = next_nonempty_category[type]; type <= last_category_;
3561cb0ef41Sopenharmony_ci       type = next_nonempty_category[type + 1]) {
3571cb0ef41Sopenharmony_ci    node = TryFindNodeIn(type, size_in_bytes, node_size);
3581cb0ef41Sopenharmony_ci    if (!node.is_null()) break;
3591cb0ef41Sopenharmony_ci  }
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  // Fast path part 2: searching the medium categories for tiny objects
3621cb0ef41Sopenharmony_ci  if (node.is_null()) {
3631cb0ef41Sopenharmony_ci    if (size_in_bytes <= kTinyObjectMaxSize) {
3641cb0ef41Sopenharmony_ci      for (type = next_nonempty_category[kFastPathFallBackTiny];
3651cb0ef41Sopenharmony_ci           type < kFastPathFirstCategory;
3661cb0ef41Sopenharmony_ci           type = next_nonempty_category[type + 1]) {
3671cb0ef41Sopenharmony_ci        node = TryFindNodeIn(type, size_in_bytes, node_size);
3681cb0ef41Sopenharmony_ci        if (!node.is_null()) break;
3691cb0ef41Sopenharmony_ci      }
3701cb0ef41Sopenharmony_ci    }
3711cb0ef41Sopenharmony_ci  }
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ci  // Searching the last category
3741cb0ef41Sopenharmony_ci  if (node.is_null()) {
3751cb0ef41Sopenharmony_ci    // Searching each element of the last category.
3761cb0ef41Sopenharmony_ci    type = last_category_;
3771cb0ef41Sopenharmony_ci    node = SearchForNodeInList(type, size_in_bytes, node_size);
3781cb0ef41Sopenharmony_ci  }
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ci  // Finally, search the most precise category
3811cb0ef41Sopenharmony_ci  if (node.is_null()) {
3821cb0ef41Sopenharmony_ci    type = SelectFreeListCategoryType(size_in_bytes);
3831cb0ef41Sopenharmony_ci    for (type = next_nonempty_category[type]; type < first_category;
3841cb0ef41Sopenharmony_ci         type = next_nonempty_category[type + 1]) {
3851cb0ef41Sopenharmony_ci      node = TryFindNodeIn(type, size_in_bytes, node_size);
3861cb0ef41Sopenharmony_ci      if (!node.is_null()) break;
3871cb0ef41Sopenharmony_ci    }
3881cb0ef41Sopenharmony_ci  }
3891cb0ef41Sopenharmony_ci
3901cb0ef41Sopenharmony_ci  // Updating cache
3911cb0ef41Sopenharmony_ci  if (!node.is_null() && categories_[type] == nullptr) {
3921cb0ef41Sopenharmony_ci    UpdateCacheAfterRemoval(type);
3931cb0ef41Sopenharmony_ci  }
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ci#ifdef DEBUG
3961cb0ef41Sopenharmony_ci  CheckCacheIntegrity();
3971cb0ef41Sopenharmony_ci#endif
3981cb0ef41Sopenharmony_ci
3991cb0ef41Sopenharmony_ci  if (!node.is_null()) {
4001cb0ef41Sopenharmony_ci    Page::FromHeapObject(node)->IncreaseAllocatedBytes(*node_size);
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  DCHECK(IsVeryLong() || Available() == SumFreeLists());
4041cb0ef41Sopenharmony_ci  return node;
4051cb0ef41Sopenharmony_ci}
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci// ------------------------------------------------
4081cb0ef41Sopenharmony_ci// FreeListManyCachedOrigin implementation
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ciFreeSpace FreeListManyCachedOrigin::Allocate(size_t size_in_bytes,
4111cb0ef41Sopenharmony_ci                                             size_t* node_size,
4121cb0ef41Sopenharmony_ci                                             AllocationOrigin origin) {
4131cb0ef41Sopenharmony_ci  if (origin == AllocationOrigin::kGC) {
4141cb0ef41Sopenharmony_ci    return FreeListManyCached::Allocate(size_in_bytes, node_size, origin);
4151cb0ef41Sopenharmony_ci  } else {
4161cb0ef41Sopenharmony_ci    return FreeListManyCachedFastPath::Allocate(size_in_bytes, node_size,
4171cb0ef41Sopenharmony_ci                                                origin);
4181cb0ef41Sopenharmony_ci  }
4191cb0ef41Sopenharmony_ci}
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci// ------------------------------------------------
4221cb0ef41Sopenharmony_ci// Generic FreeList methods (non alloc/free related)
4231cb0ef41Sopenharmony_ci
4241cb0ef41Sopenharmony_civoid FreeList::Reset() {
4251cb0ef41Sopenharmony_ci  ForAllFreeListCategories(
4261cb0ef41Sopenharmony_ci      [this](FreeListCategory* category) { category->Reset(this); });
4271cb0ef41Sopenharmony_ci  for (int i = kFirstCategory; i < number_of_categories_; i++) {
4281cb0ef41Sopenharmony_ci    categories_[i] = nullptr;
4291cb0ef41Sopenharmony_ci  }
4301cb0ef41Sopenharmony_ci  wasted_bytes_ = 0;
4311cb0ef41Sopenharmony_ci  available_ = 0;
4321cb0ef41Sopenharmony_ci}
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_cisize_t FreeList::EvictFreeListItems(Page* page) {
4351cb0ef41Sopenharmony_ci  size_t sum = 0;
4361cb0ef41Sopenharmony_ci  page->ForAllFreeListCategories([this, &sum](FreeListCategory* category) {
4371cb0ef41Sopenharmony_ci    sum += category->available();
4381cb0ef41Sopenharmony_ci    RemoveCategory(category);
4391cb0ef41Sopenharmony_ci    category->Reset(this);
4401cb0ef41Sopenharmony_ci  });
4411cb0ef41Sopenharmony_ci  return sum;
4421cb0ef41Sopenharmony_ci}
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_civoid FreeList::RepairLists(Heap* heap) {
4451cb0ef41Sopenharmony_ci  ForAllFreeListCategories(
4461cb0ef41Sopenharmony_ci      [heap](FreeListCategory* category) { category->RepairFreeList(heap); });
4471cb0ef41Sopenharmony_ci}
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_cibool FreeList::AddCategory(FreeListCategory* category) {
4501cb0ef41Sopenharmony_ci  FreeListCategoryType type = category->type_;
4511cb0ef41Sopenharmony_ci  DCHECK_LT(type, number_of_categories_);
4521cb0ef41Sopenharmony_ci  FreeListCategory* top = categories_[type];
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci  if (category->is_empty()) return false;
4551cb0ef41Sopenharmony_ci  DCHECK_NE(top, category);
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci  // Common double-linked list insertion.
4581cb0ef41Sopenharmony_ci  if (top != nullptr) {
4591cb0ef41Sopenharmony_ci    top->set_prev(category);
4601cb0ef41Sopenharmony_ci  }
4611cb0ef41Sopenharmony_ci  category->set_next(top);
4621cb0ef41Sopenharmony_ci  categories_[type] = category;
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  IncreaseAvailableBytes(category->available());
4651cb0ef41Sopenharmony_ci  return true;
4661cb0ef41Sopenharmony_ci}
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_civoid FreeList::RemoveCategory(FreeListCategory* category) {
4691cb0ef41Sopenharmony_ci  FreeListCategoryType type = category->type_;
4701cb0ef41Sopenharmony_ci  DCHECK_LT(type, number_of_categories_);
4711cb0ef41Sopenharmony_ci  FreeListCategory* top = categories_[type];
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci  if (category->is_linked(this)) {
4741cb0ef41Sopenharmony_ci    DecreaseAvailableBytes(category->available());
4751cb0ef41Sopenharmony_ci  }
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_ci  // Common double-linked list removal.
4781cb0ef41Sopenharmony_ci  if (top == category) {
4791cb0ef41Sopenharmony_ci    categories_[type] = category->next();
4801cb0ef41Sopenharmony_ci  }
4811cb0ef41Sopenharmony_ci  if (category->prev() != nullptr) {
4821cb0ef41Sopenharmony_ci    category->prev()->set_next(category->next());
4831cb0ef41Sopenharmony_ci  }
4841cb0ef41Sopenharmony_ci  if (category->next() != nullptr) {
4851cb0ef41Sopenharmony_ci    category->next()->set_prev(category->prev());
4861cb0ef41Sopenharmony_ci  }
4871cb0ef41Sopenharmony_ci  category->set_next(nullptr);
4881cb0ef41Sopenharmony_ci  category->set_prev(nullptr);
4891cb0ef41Sopenharmony_ci}
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_civoid FreeList::PrintCategories(FreeListCategoryType type) {
4921cb0ef41Sopenharmony_ci  FreeListCategoryIterator it(this, type);
4931cb0ef41Sopenharmony_ci  PrintF("FreeList[%p, top=%p, %d] ", static_cast<void*>(this),
4941cb0ef41Sopenharmony_ci         static_cast<void*>(categories_[type]), type);
4951cb0ef41Sopenharmony_ci  while (it.HasNext()) {
4961cb0ef41Sopenharmony_ci    FreeListCategory* current = it.Next();
4971cb0ef41Sopenharmony_ci    PrintF("%p -> ", static_cast<void*>(current));
4981cb0ef41Sopenharmony_ci  }
4991cb0ef41Sopenharmony_ci  PrintF("null\n");
5001cb0ef41Sopenharmony_ci}
5011cb0ef41Sopenharmony_ci
5021cb0ef41Sopenharmony_cisize_t FreeListCategory::SumFreeList() {
5031cb0ef41Sopenharmony_ci  size_t sum = 0;
5041cb0ef41Sopenharmony_ci  FreeSpace cur = top();
5051cb0ef41Sopenharmony_ci  while (!cur.is_null()) {
5061cb0ef41Sopenharmony_ci    // We can't use "cur->map()" here because both cur's map and the
5071cb0ef41Sopenharmony_ci    // root can be null during bootstrapping.
5081cb0ef41Sopenharmony_ci    DCHECK(
5091cb0ef41Sopenharmony_ci        cur.map_slot().contains_map_value(Page::FromHeapObject(cur)
5101cb0ef41Sopenharmony_ci                                              ->heap()
5111cb0ef41Sopenharmony_ci                                              ->isolate()
5121cb0ef41Sopenharmony_ci                                              ->root(RootIndex::kFreeSpaceMap)
5131cb0ef41Sopenharmony_ci                                              .ptr()));
5141cb0ef41Sopenharmony_ci    sum += cur.size(kRelaxedLoad);
5151cb0ef41Sopenharmony_ci    cur = cur.next();
5161cb0ef41Sopenharmony_ci  }
5171cb0ef41Sopenharmony_ci  return sum;
5181cb0ef41Sopenharmony_ci}
5191cb0ef41Sopenharmony_ciint FreeListCategory::FreeListLength() {
5201cb0ef41Sopenharmony_ci  int length = 0;
5211cb0ef41Sopenharmony_ci  FreeSpace cur = top();
5221cb0ef41Sopenharmony_ci  while (!cur.is_null()) {
5231cb0ef41Sopenharmony_ci    length++;
5241cb0ef41Sopenharmony_ci    cur = cur.next();
5251cb0ef41Sopenharmony_ci  }
5261cb0ef41Sopenharmony_ci  return length;
5271cb0ef41Sopenharmony_ci}
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ci#ifdef DEBUG
5301cb0ef41Sopenharmony_cibool FreeList::IsVeryLong() {
5311cb0ef41Sopenharmony_ci  int len = 0;
5321cb0ef41Sopenharmony_ci  for (int i = kFirstCategory; i < number_of_categories_; i++) {
5331cb0ef41Sopenharmony_ci    FreeListCategoryIterator it(this, static_cast<FreeListCategoryType>(i));
5341cb0ef41Sopenharmony_ci    while (it.HasNext()) {
5351cb0ef41Sopenharmony_ci      len += it.Next()->FreeListLength();
5361cb0ef41Sopenharmony_ci      if (len >= FreeListCategory::kVeryLongFreeList) return true;
5371cb0ef41Sopenharmony_ci    }
5381cb0ef41Sopenharmony_ci  }
5391cb0ef41Sopenharmony_ci  return false;
5401cb0ef41Sopenharmony_ci}
5411cb0ef41Sopenharmony_ci
5421cb0ef41Sopenharmony_ci// This can take a very long time because it is linear in the number of entries
5431cb0ef41Sopenharmony_ci// on the free list, so it should not be called if FreeListLength returns
5441cb0ef41Sopenharmony_ci// kVeryLongFreeList.
5451cb0ef41Sopenharmony_cisize_t FreeList::SumFreeLists() {
5461cb0ef41Sopenharmony_ci  size_t sum = 0;
5471cb0ef41Sopenharmony_ci  ForAllFreeListCategories(
5481cb0ef41Sopenharmony_ci      [&sum](FreeListCategory* category) { sum += category->SumFreeList(); });
5491cb0ef41Sopenharmony_ci  return sum;
5501cb0ef41Sopenharmony_ci}
5511cb0ef41Sopenharmony_ci#endif
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci}  // namespace internal
5541cb0ef41Sopenharmony_ci}  // namespace v8
555