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