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/paged-spaces.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <atomic> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "src/base/optional.h" 101cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h" 111cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 121cb0ef41Sopenharmony_ci#include "src/execution/vm-state-inl.h" 131cb0ef41Sopenharmony_ci#include "src/heap/array-buffer-sweeper.h" 141cb0ef41Sopenharmony_ci#include "src/heap/heap.h" 151cb0ef41Sopenharmony_ci#include "src/heap/incremental-marking.h" 161cb0ef41Sopenharmony_ci#include "src/heap/memory-allocator.h" 171cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk-inl.h" 181cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk-layout.h" 191cb0ef41Sopenharmony_ci#include "src/heap/paged-spaces-inl.h" 201cb0ef41Sopenharmony_ci#include "src/heap/read-only-heap.h" 211cb0ef41Sopenharmony_ci#include "src/heap/safepoint.h" 221cb0ef41Sopenharmony_ci#include "src/logging/runtime-call-stats-scope.h" 231cb0ef41Sopenharmony_ci#include "src/objects/string.h" 241cb0ef41Sopenharmony_ci#include "src/utils/utils.h" 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_cinamespace v8 { 271cb0ef41Sopenharmony_cinamespace internal { 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci// ---------------------------------------------------------------------------- 301cb0ef41Sopenharmony_ci// PagedSpaceObjectIterator 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ciPagedSpaceObjectIterator::PagedSpaceObjectIterator(Heap* heap, 331cb0ef41Sopenharmony_ci PagedSpace* space) 341cb0ef41Sopenharmony_ci : cur_addr_(kNullAddress), 351cb0ef41Sopenharmony_ci cur_end_(kNullAddress), 361cb0ef41Sopenharmony_ci space_(space), 371cb0ef41Sopenharmony_ci page_range_(space->first_page(), nullptr), 381cb0ef41Sopenharmony_ci current_page_(page_range_.begin()) 391cb0ef41Sopenharmony_ci#if V8_COMPRESS_POINTERS 401cb0ef41Sopenharmony_ci , 411cb0ef41Sopenharmony_ci cage_base_(heap->isolate()) 421cb0ef41Sopenharmony_ci#endif // V8_COMPRESS_POINTERS 431cb0ef41Sopenharmony_ci{ 441cb0ef41Sopenharmony_ci heap->MakeHeapIterable(); 451cb0ef41Sopenharmony_ci USE(space_); 461cb0ef41Sopenharmony_ci} 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ciPagedSpaceObjectIterator::PagedSpaceObjectIterator(Heap* heap, 491cb0ef41Sopenharmony_ci PagedSpace* space, 501cb0ef41Sopenharmony_ci Page* page) 511cb0ef41Sopenharmony_ci : cur_addr_(kNullAddress), 521cb0ef41Sopenharmony_ci cur_end_(kNullAddress), 531cb0ef41Sopenharmony_ci space_(space), 541cb0ef41Sopenharmony_ci page_range_(page), 551cb0ef41Sopenharmony_ci current_page_(page_range_.begin()) 561cb0ef41Sopenharmony_ci#if V8_COMPRESS_POINTERS 571cb0ef41Sopenharmony_ci , 581cb0ef41Sopenharmony_ci cage_base_(heap->isolate()) 591cb0ef41Sopenharmony_ci#endif // V8_COMPRESS_POINTERS 601cb0ef41Sopenharmony_ci{ 611cb0ef41Sopenharmony_ci heap->MakeHeapIterable(); 621cb0ef41Sopenharmony_ci#ifdef DEBUG 631cb0ef41Sopenharmony_ci AllocationSpace owner = page->owner_identity(); 641cb0ef41Sopenharmony_ci DCHECK(owner == OLD_SPACE || owner == MAP_SPACE || owner == CODE_SPACE); 651cb0ef41Sopenharmony_ci#endif // DEBUG 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci// We have hit the end of the page and should advance to the next block of 691cb0ef41Sopenharmony_ci// objects. This happens at the end of the page. 701cb0ef41Sopenharmony_cibool PagedSpaceObjectIterator::AdvanceToNextPage() { 711cb0ef41Sopenharmony_ci DCHECK_EQ(cur_addr_, cur_end_); 721cb0ef41Sopenharmony_ci if (current_page_ == page_range_.end()) return false; 731cb0ef41Sopenharmony_ci Page* cur_page = *(current_page_++); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci cur_addr_ = cur_page->area_start(); 761cb0ef41Sopenharmony_ci cur_end_ = cur_page->area_end(); 771cb0ef41Sopenharmony_ci DCHECK(cur_page->SweepingDone()); 781cb0ef41Sopenharmony_ci return true; 791cb0ef41Sopenharmony_ci} 801cb0ef41Sopenharmony_ciPage* PagedSpace::InitializePage(MemoryChunk* chunk) { 811cb0ef41Sopenharmony_ci Page* page = static_cast<Page*>(chunk); 821cb0ef41Sopenharmony_ci DCHECK_EQ( 831cb0ef41Sopenharmony_ci MemoryChunkLayout::AllocatableMemoryInMemoryChunk(page->owner_identity()), 841cb0ef41Sopenharmony_ci page->area_size()); 851cb0ef41Sopenharmony_ci // Make sure that categories are initialized before freeing the area. 861cb0ef41Sopenharmony_ci page->ResetAllocationStatistics(); 871cb0ef41Sopenharmony_ci page->SetOldGenerationPageFlags(heap()->incremental_marking()->IsMarking()); 881cb0ef41Sopenharmony_ci page->AllocateFreeListCategories(); 891cb0ef41Sopenharmony_ci page->InitializeFreeListCategories(); 901cb0ef41Sopenharmony_ci page->list_node().Initialize(); 911cb0ef41Sopenharmony_ci page->InitializationMemoryFence(); 921cb0ef41Sopenharmony_ci return page; 931cb0ef41Sopenharmony_ci} 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ciPagedSpace::PagedSpace(Heap* heap, AllocationSpace space, 961cb0ef41Sopenharmony_ci Executability executable, FreeList* free_list, 971cb0ef41Sopenharmony_ci LinearAllocationArea* allocation_info_, 981cb0ef41Sopenharmony_ci CompactionSpaceKind compaction_space_kind) 991cb0ef41Sopenharmony_ci : SpaceWithLinearArea(heap, space, free_list, allocation_info_), 1001cb0ef41Sopenharmony_ci executable_(executable), 1011cb0ef41Sopenharmony_ci compaction_space_kind_(compaction_space_kind) { 1021cb0ef41Sopenharmony_ci area_size_ = MemoryChunkLayout::AllocatableMemoryInMemoryChunk(space); 1031cb0ef41Sopenharmony_ci accounting_stats_.Clear(); 1041cb0ef41Sopenharmony_ci} 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_civoid PagedSpace::TearDown() { 1071cb0ef41Sopenharmony_ci while (!memory_chunk_list_.Empty()) { 1081cb0ef41Sopenharmony_ci MemoryChunk* chunk = memory_chunk_list_.front(); 1091cb0ef41Sopenharmony_ci memory_chunk_list_.Remove(chunk); 1101cb0ef41Sopenharmony_ci heap()->memory_allocator()->Free(MemoryAllocator::FreeMode::kImmediately, 1111cb0ef41Sopenharmony_ci chunk); 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci accounting_stats_.Clear(); 1141cb0ef41Sopenharmony_ci} 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_civoid PagedSpace::RefillFreeList() { 1171cb0ef41Sopenharmony_ci // Any PagedSpace might invoke RefillFreeList. We filter all but our old 1181cb0ef41Sopenharmony_ci // generation spaces out. 1191cb0ef41Sopenharmony_ci if (identity() != OLD_SPACE && identity() != CODE_SPACE && 1201cb0ef41Sopenharmony_ci identity() != MAP_SPACE) { 1211cb0ef41Sopenharmony_ci return; 1221cb0ef41Sopenharmony_ci } 1231cb0ef41Sopenharmony_ci MarkCompactCollector* collector = heap()->mark_compact_collector(); 1241cb0ef41Sopenharmony_ci size_t added = 0; 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci { 1271cb0ef41Sopenharmony_ci Page* p = nullptr; 1281cb0ef41Sopenharmony_ci while ((p = collector->sweeper()->GetSweptPageSafe(this)) != nullptr) { 1291cb0ef41Sopenharmony_ci // We regularly sweep NEVER_ALLOCATE_ON_PAGE pages. We drop the freelist 1301cb0ef41Sopenharmony_ci // entries here to make them unavailable for allocations. 1311cb0ef41Sopenharmony_ci if (p->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE)) { 1321cb0ef41Sopenharmony_ci p->ForAllFreeListCategories([this](FreeListCategory* category) { 1331cb0ef41Sopenharmony_ci category->Reset(free_list()); 1341cb0ef41Sopenharmony_ci }); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci // Only during compaction pages can actually change ownership. This is 1381cb0ef41Sopenharmony_ci // safe because there exists no other competing action on the page links 1391cb0ef41Sopenharmony_ci // during compaction. 1401cb0ef41Sopenharmony_ci if (is_compaction_space()) { 1411cb0ef41Sopenharmony_ci DCHECK_NE(this, p->owner()); 1421cb0ef41Sopenharmony_ci PagedSpace* owner = reinterpret_cast<PagedSpace*>(p->owner()); 1431cb0ef41Sopenharmony_ci base::MutexGuard guard(owner->mutex()); 1441cb0ef41Sopenharmony_ci owner->RefineAllocatedBytesAfterSweeping(p); 1451cb0ef41Sopenharmony_ci owner->RemovePage(p); 1461cb0ef41Sopenharmony_ci added += AddPage(p); 1471cb0ef41Sopenharmony_ci added += p->wasted_memory(); 1481cb0ef41Sopenharmony_ci } else { 1491cb0ef41Sopenharmony_ci base::MutexGuard guard(mutex()); 1501cb0ef41Sopenharmony_ci DCHECK_EQ(this, p->owner()); 1511cb0ef41Sopenharmony_ci RefineAllocatedBytesAfterSweeping(p); 1521cb0ef41Sopenharmony_ci added += RelinkFreeListCategories(p); 1531cb0ef41Sopenharmony_ci added += p->wasted_memory(); 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci if (is_compaction_space() && (added > kCompactionMemoryWanted)) break; 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci } 1581cb0ef41Sopenharmony_ci} 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_civoid PagedSpace::MergeCompactionSpace(CompactionSpace* other) { 1611cb0ef41Sopenharmony_ci base::MutexGuard guard(mutex()); 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci DCHECK(identity() == other->identity()); 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci // Unmerged fields: 1661cb0ef41Sopenharmony_ci // area_size_ 1671cb0ef41Sopenharmony_ci other->FreeLinearAllocationArea(); 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci for (int i = static_cast<int>(AllocationOrigin::kFirstAllocationOrigin); 1701cb0ef41Sopenharmony_ci i <= static_cast<int>(AllocationOrigin::kLastAllocationOrigin); i++) { 1711cb0ef41Sopenharmony_ci allocations_origins_[i] += other->allocations_origins_[i]; 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci // The linear allocation area of {other} should be destroyed now. 1751cb0ef41Sopenharmony_ci DCHECK_EQ(kNullAddress, other->top()); 1761cb0ef41Sopenharmony_ci DCHECK_EQ(kNullAddress, other->limit()); 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci // Move over pages. 1791cb0ef41Sopenharmony_ci for (auto it = other->begin(); it != other->end();) { 1801cb0ef41Sopenharmony_ci Page* p = *(it++); 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci // Ensure that pages are initialized before objects on it are discovered by 1831cb0ef41Sopenharmony_ci // concurrent markers. 1841cb0ef41Sopenharmony_ci p->InitializationMemoryFence(); 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci // Relinking requires the category to be unlinked. 1871cb0ef41Sopenharmony_ci other->RemovePage(p); 1881cb0ef41Sopenharmony_ci AddPage(p); 1891cb0ef41Sopenharmony_ci DCHECK_IMPLIES( 1901cb0ef41Sopenharmony_ci !p->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE), 1911cb0ef41Sopenharmony_ci p->AvailableInFreeList() == p->AvailableInFreeListFromAllocatedBytes()); 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci // TODO(leszeks): Here we should allocation step, but: 1941cb0ef41Sopenharmony_ci // 1. Allocation groups are currently not handled properly by the sampling 1951cb0ef41Sopenharmony_ci // allocation profiler, and 1961cb0ef41Sopenharmony_ci // 2. Observers might try to take the space lock, which isn't reentrant. 1971cb0ef41Sopenharmony_ci // We'll have to come up with a better solution for allocation stepping 1981cb0ef41Sopenharmony_ci // before shipping, which will likely be using LocalHeap. 1991cb0ef41Sopenharmony_ci } 2001cb0ef41Sopenharmony_ci for (auto p : other->GetNewPages()) { 2011cb0ef41Sopenharmony_ci heap()->NotifyOldGenerationExpansion(identity(), p); 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci DCHECK_EQ(0u, other->Size()); 2051cb0ef41Sopenharmony_ci DCHECK_EQ(0u, other->Capacity()); 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_cisize_t PagedSpace::CommittedPhysicalMemory() const { 2091cb0ef41Sopenharmony_ci if (!base::OS::HasLazyCommits()) { 2101cb0ef41Sopenharmony_ci DCHECK_EQ(0, committed_physical_memory()); 2111cb0ef41Sopenharmony_ci return CommittedMemory(); 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci BasicMemoryChunk::UpdateHighWaterMark(allocation_info_->top()); 2141cb0ef41Sopenharmony_ci return committed_physical_memory(); 2151cb0ef41Sopenharmony_ci} 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_civoid PagedSpace::IncrementCommittedPhysicalMemory(size_t increment_value) { 2181cb0ef41Sopenharmony_ci if (!base::OS::HasLazyCommits() || increment_value == 0) return; 2191cb0ef41Sopenharmony_ci size_t old_value = committed_physical_memory_.fetch_add( 2201cb0ef41Sopenharmony_ci increment_value, std::memory_order_relaxed); 2211cb0ef41Sopenharmony_ci USE(old_value); 2221cb0ef41Sopenharmony_ci DCHECK_LT(old_value, old_value + increment_value); 2231cb0ef41Sopenharmony_ci} 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_civoid PagedSpace::DecrementCommittedPhysicalMemory(size_t decrement_value) { 2261cb0ef41Sopenharmony_ci if (!base::OS::HasLazyCommits() || decrement_value == 0) return; 2271cb0ef41Sopenharmony_ci size_t old_value = committed_physical_memory_.fetch_sub( 2281cb0ef41Sopenharmony_ci decrement_value, std::memory_order_relaxed); 2291cb0ef41Sopenharmony_ci USE(old_value); 2301cb0ef41Sopenharmony_ci DCHECK_GT(old_value, old_value - decrement_value); 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci#if DEBUG 2341cb0ef41Sopenharmony_civoid PagedSpace::VerifyCommittedPhysicalMemory() const { 2351cb0ef41Sopenharmony_ci heap()->safepoint()->AssertActive(); 2361cb0ef41Sopenharmony_ci size_t size = 0; 2371cb0ef41Sopenharmony_ci for (const Page* page : *this) { 2381cb0ef41Sopenharmony_ci DCHECK(page->SweepingDone()); 2391cb0ef41Sopenharmony_ci size += page->CommittedPhysicalMemory(); 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci // Ensure that the space's counter matches the sum of all page counters. 2421cb0ef41Sopenharmony_ci DCHECK_EQ(size, CommittedPhysicalMemory()); 2431cb0ef41Sopenharmony_ci} 2441cb0ef41Sopenharmony_ci#endif // DEBUG 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_cibool PagedSpace::ContainsSlow(Address addr) const { 2471cb0ef41Sopenharmony_ci Page* p = Page::FromAddress(addr); 2481cb0ef41Sopenharmony_ci for (const Page* page : *this) { 2491cb0ef41Sopenharmony_ci if (page == p) return true; 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci return false; 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_civoid PagedSpace::RefineAllocatedBytesAfterSweeping(Page* page) { 2551cb0ef41Sopenharmony_ci CHECK(page->SweepingDone()); 2561cb0ef41Sopenharmony_ci auto marking_state = 2571cb0ef41Sopenharmony_ci heap()->incremental_marking()->non_atomic_marking_state(); 2581cb0ef41Sopenharmony_ci // The live_byte on the page was accounted in the space allocated 2591cb0ef41Sopenharmony_ci // bytes counter. After sweeping allocated_bytes() contains the 2601cb0ef41Sopenharmony_ci // accurate live byte count on the page. 2611cb0ef41Sopenharmony_ci size_t old_counter = marking_state->live_bytes(page); 2621cb0ef41Sopenharmony_ci size_t new_counter = page->allocated_bytes(); 2631cb0ef41Sopenharmony_ci DCHECK_GE(old_counter, new_counter); 2641cb0ef41Sopenharmony_ci if (old_counter > new_counter) { 2651cb0ef41Sopenharmony_ci DecreaseAllocatedBytes(old_counter - new_counter, page); 2661cb0ef41Sopenharmony_ci } 2671cb0ef41Sopenharmony_ci marking_state->SetLiveBytes(page, 0); 2681cb0ef41Sopenharmony_ci} 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ciPage* PagedSpace::RemovePageSafe(int size_in_bytes) { 2711cb0ef41Sopenharmony_ci base::MutexGuard guard(mutex()); 2721cb0ef41Sopenharmony_ci Page* page = free_list()->GetPageForSize(size_in_bytes); 2731cb0ef41Sopenharmony_ci if (!page) return nullptr; 2741cb0ef41Sopenharmony_ci RemovePage(page); 2751cb0ef41Sopenharmony_ci return page; 2761cb0ef41Sopenharmony_ci} 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_cisize_t PagedSpace::AddPage(Page* page) { 2791cb0ef41Sopenharmony_ci CHECK(page->SweepingDone()); 2801cb0ef41Sopenharmony_ci page->set_owner(this); 2811cb0ef41Sopenharmony_ci memory_chunk_list_.PushBack(page); 2821cb0ef41Sopenharmony_ci AccountCommitted(page->size()); 2831cb0ef41Sopenharmony_ci IncreaseCapacity(page->area_size()); 2841cb0ef41Sopenharmony_ci IncreaseAllocatedBytes(page->allocated_bytes(), page); 2851cb0ef41Sopenharmony_ci for (size_t i = 0; i < ExternalBackingStoreType::kNumTypes; i++) { 2861cb0ef41Sopenharmony_ci ExternalBackingStoreType t = static_cast<ExternalBackingStoreType>(i); 2871cb0ef41Sopenharmony_ci IncrementExternalBackingStoreBytes(t, page->ExternalBackingStoreBytes(t)); 2881cb0ef41Sopenharmony_ci } 2891cb0ef41Sopenharmony_ci IncrementCommittedPhysicalMemory(page->CommittedPhysicalMemory()); 2901cb0ef41Sopenharmony_ci return RelinkFreeListCategories(page); 2911cb0ef41Sopenharmony_ci} 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_civoid PagedSpace::RemovePage(Page* page) { 2941cb0ef41Sopenharmony_ci CHECK(page->SweepingDone()); 2951cb0ef41Sopenharmony_ci memory_chunk_list_.Remove(page); 2961cb0ef41Sopenharmony_ci UnlinkFreeListCategories(page); 2971cb0ef41Sopenharmony_ci DecreaseAllocatedBytes(page->allocated_bytes(), page); 2981cb0ef41Sopenharmony_ci DecreaseCapacity(page->area_size()); 2991cb0ef41Sopenharmony_ci AccountUncommitted(page->size()); 3001cb0ef41Sopenharmony_ci for (size_t i = 0; i < ExternalBackingStoreType::kNumTypes; i++) { 3011cb0ef41Sopenharmony_ci ExternalBackingStoreType t = static_cast<ExternalBackingStoreType>(i); 3021cb0ef41Sopenharmony_ci DecrementExternalBackingStoreBytes(t, page->ExternalBackingStoreBytes(t)); 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci DecrementCommittedPhysicalMemory(page->CommittedPhysicalMemory()); 3051cb0ef41Sopenharmony_ci} 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_civoid PagedSpace::SetTopAndLimit(Address top, Address limit) { 3081cb0ef41Sopenharmony_ci DCHECK(top == limit || 3091cb0ef41Sopenharmony_ci Page::FromAddress(top) == Page::FromAddress(limit - 1)); 3101cb0ef41Sopenharmony_ci BasicMemoryChunk::UpdateHighWaterMark(allocation_info_->top()); 3111cb0ef41Sopenharmony_ci allocation_info_->Reset(top, limit); 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci base::Optional<base::SharedMutexGuard<base::kExclusive>> optional_guard; 3141cb0ef41Sopenharmony_ci if (!is_compaction_space()) 3151cb0ef41Sopenharmony_ci optional_guard.emplace(&pending_allocation_mutex_); 3161cb0ef41Sopenharmony_ci original_limit_ = limit; 3171cb0ef41Sopenharmony_ci original_top_ = top; 3181cb0ef41Sopenharmony_ci} 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_cisize_t PagedSpace::ShrinkPageToHighWaterMark(Page* page) { 3211cb0ef41Sopenharmony_ci size_t unused = page->ShrinkToHighWaterMark(); 3221cb0ef41Sopenharmony_ci accounting_stats_.DecreaseCapacity(static_cast<intptr_t>(unused)); 3231cb0ef41Sopenharmony_ci AccountUncommitted(unused); 3241cb0ef41Sopenharmony_ci return unused; 3251cb0ef41Sopenharmony_ci} 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_civoid PagedSpace::ResetFreeList() { 3281cb0ef41Sopenharmony_ci for (Page* page : *this) { 3291cb0ef41Sopenharmony_ci free_list_->EvictFreeListItems(page); 3301cb0ef41Sopenharmony_ci } 3311cb0ef41Sopenharmony_ci DCHECK(free_list_->IsEmpty()); 3321cb0ef41Sopenharmony_ci} 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_civoid PagedSpace::ShrinkImmortalImmovablePages() { 3351cb0ef41Sopenharmony_ci DCHECK(!heap()->deserialization_complete()); 3361cb0ef41Sopenharmony_ci BasicMemoryChunk::UpdateHighWaterMark(allocation_info_->top()); 3371cb0ef41Sopenharmony_ci FreeLinearAllocationArea(); 3381cb0ef41Sopenharmony_ci ResetFreeList(); 3391cb0ef41Sopenharmony_ci for (Page* page : *this) { 3401cb0ef41Sopenharmony_ci DCHECK(page->IsFlagSet(Page::NEVER_EVACUATE)); 3411cb0ef41Sopenharmony_ci ShrinkPageToHighWaterMark(page); 3421cb0ef41Sopenharmony_ci } 3431cb0ef41Sopenharmony_ci} 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ciPage* PagedSpace::Expand() { 3461cb0ef41Sopenharmony_ci Page* page = heap()->memory_allocator()->AllocatePage( 3471cb0ef41Sopenharmony_ci MemoryAllocator::AllocationMode::kRegular, this, executable()); 3481cb0ef41Sopenharmony_ci if (page == nullptr) return nullptr; 3491cb0ef41Sopenharmony_ci ConcurrentAllocationMutex guard(this); 3501cb0ef41Sopenharmony_ci AddPage(page); 3511cb0ef41Sopenharmony_ci Free(page->area_start(), page->area_size(), 3521cb0ef41Sopenharmony_ci SpaceAccountingMode::kSpaceAccounted); 3531cb0ef41Sopenharmony_ci return page; 3541cb0ef41Sopenharmony_ci} 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_cibase::Optional<std::pair<Address, size_t>> PagedSpace::ExpandBackground( 3571cb0ef41Sopenharmony_ci size_t size_in_bytes) { 3581cb0ef41Sopenharmony_ci Page* page = heap()->memory_allocator()->AllocatePage( 3591cb0ef41Sopenharmony_ci MemoryAllocator::AllocationMode::kRegular, this, executable()); 3601cb0ef41Sopenharmony_ci if (page == nullptr) return {}; 3611cb0ef41Sopenharmony_ci base::MutexGuard lock(&space_mutex_); 3621cb0ef41Sopenharmony_ci AddPage(page); 3631cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE || identity() == CODE_LO_SPACE) { 3641cb0ef41Sopenharmony_ci heap()->isolate()->AddCodeMemoryChunk(page); 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci Address object_start = page->area_start(); 3671cb0ef41Sopenharmony_ci CHECK_LE(size_in_bytes, page->area_size()); 3681cb0ef41Sopenharmony_ci Free(page->area_start() + size_in_bytes, page->area_size() - size_in_bytes, 3691cb0ef41Sopenharmony_ci SpaceAccountingMode::kSpaceAccounted); 3701cb0ef41Sopenharmony_ci AddRangeToActiveSystemPages(page, object_start, object_start + size_in_bytes); 3711cb0ef41Sopenharmony_ci return std::make_pair(object_start, size_in_bytes); 3721cb0ef41Sopenharmony_ci} 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ciint PagedSpace::CountTotalPages() const { 3751cb0ef41Sopenharmony_ci int count = 0; 3761cb0ef41Sopenharmony_ci for (const Page* page : *this) { 3771cb0ef41Sopenharmony_ci count++; 3781cb0ef41Sopenharmony_ci USE(page); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci return count; 3811cb0ef41Sopenharmony_ci} 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_civoid PagedSpace::SetLinearAllocationArea(Address top, Address limit) { 3841cb0ef41Sopenharmony_ci SetTopAndLimit(top, limit); 3851cb0ef41Sopenharmony_ci if (top != kNullAddress && top != limit && 3861cb0ef41Sopenharmony_ci heap()->incremental_marking()->black_allocation()) { 3871cb0ef41Sopenharmony_ci Page::FromAllocationAreaAddress(top)->CreateBlackArea(top, limit); 3881cb0ef41Sopenharmony_ci } 3891cb0ef41Sopenharmony_ci} 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_civoid PagedSpace::DecreaseLimit(Address new_limit) { 3921cb0ef41Sopenharmony_ci Address old_limit = limit(); 3931cb0ef41Sopenharmony_ci DCHECK_LE(top(), new_limit); 3941cb0ef41Sopenharmony_ci DCHECK_GE(old_limit, new_limit); 3951cb0ef41Sopenharmony_ci if (new_limit != old_limit) { 3961cb0ef41Sopenharmony_ci base::Optional<CodePageMemoryModificationScope> optional_scope; 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE) { 3991cb0ef41Sopenharmony_ci MemoryChunk* chunk = MemoryChunk::FromAddress(new_limit); 4001cb0ef41Sopenharmony_ci optional_scope.emplace(chunk); 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ci ConcurrentAllocationMutex guard(this); 4041cb0ef41Sopenharmony_ci SetTopAndLimit(top(), new_limit); 4051cb0ef41Sopenharmony_ci Free(new_limit, old_limit - new_limit, 4061cb0ef41Sopenharmony_ci SpaceAccountingMode::kSpaceAccounted); 4071cb0ef41Sopenharmony_ci if (heap()->incremental_marking()->black_allocation()) { 4081cb0ef41Sopenharmony_ci Page::FromAllocationAreaAddress(new_limit)->DestroyBlackArea(new_limit, 4091cb0ef41Sopenharmony_ci old_limit); 4101cb0ef41Sopenharmony_ci } 4111cb0ef41Sopenharmony_ci } 4121cb0ef41Sopenharmony_ci} 4131cb0ef41Sopenharmony_ci 4141cb0ef41Sopenharmony_civoid PagedSpace::MarkLinearAllocationAreaBlack() { 4151cb0ef41Sopenharmony_ci DCHECK(heap()->incremental_marking()->black_allocation()); 4161cb0ef41Sopenharmony_ci Address current_top = top(); 4171cb0ef41Sopenharmony_ci Address current_limit = limit(); 4181cb0ef41Sopenharmony_ci if (current_top != kNullAddress && current_top != current_limit) { 4191cb0ef41Sopenharmony_ci Page::FromAllocationAreaAddress(current_top) 4201cb0ef41Sopenharmony_ci ->CreateBlackArea(current_top, current_limit); 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci} 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_civoid PagedSpace::UnmarkLinearAllocationArea() { 4251cb0ef41Sopenharmony_ci Address current_top = top(); 4261cb0ef41Sopenharmony_ci Address current_limit = limit(); 4271cb0ef41Sopenharmony_ci if (current_top != kNullAddress && current_top != current_limit) { 4281cb0ef41Sopenharmony_ci Page::FromAllocationAreaAddress(current_top) 4291cb0ef41Sopenharmony_ci ->DestroyBlackArea(current_top, current_limit); 4301cb0ef41Sopenharmony_ci } 4311cb0ef41Sopenharmony_ci} 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_civoid PagedSpace::MakeLinearAllocationAreaIterable() { 4341cb0ef41Sopenharmony_ci Address current_top = top(); 4351cb0ef41Sopenharmony_ci Address current_limit = limit(); 4361cb0ef41Sopenharmony_ci if (current_top != kNullAddress && current_top != current_limit) { 4371cb0ef41Sopenharmony_ci base::Optional<CodePageMemoryModificationScope> optional_scope; 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE) { 4401cb0ef41Sopenharmony_ci MemoryChunk* chunk = MemoryChunk::FromAddress(current_top); 4411cb0ef41Sopenharmony_ci optional_scope.emplace(chunk); 4421cb0ef41Sopenharmony_ci } 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci heap_->CreateFillerObjectAt(current_top, 4451cb0ef41Sopenharmony_ci static_cast<int>(current_limit - current_top), 4461cb0ef41Sopenharmony_ci ClearRecordedSlots::kNo); 4471cb0ef41Sopenharmony_ci } 4481cb0ef41Sopenharmony_ci} 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_cisize_t PagedSpace::Available() const { 4511cb0ef41Sopenharmony_ci ConcurrentAllocationMutex guard(this); 4521cb0ef41Sopenharmony_ci return free_list_->Available(); 4531cb0ef41Sopenharmony_ci} 4541cb0ef41Sopenharmony_ci 4551cb0ef41Sopenharmony_cinamespace { 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ciUnprotectMemoryOrigin GetUnprotectMemoryOrigin(bool is_compaction_space) { 4581cb0ef41Sopenharmony_ci return is_compaction_space ? UnprotectMemoryOrigin::kMaybeOffMainThread 4591cb0ef41Sopenharmony_ci : UnprotectMemoryOrigin::kMainThread; 4601cb0ef41Sopenharmony_ci} 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci} // namespace 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_civoid PagedSpace::FreeLinearAllocationArea() { 4651cb0ef41Sopenharmony_ci // Mark the old linear allocation area with a free space map so it can be 4661cb0ef41Sopenharmony_ci // skipped when scanning the heap. 4671cb0ef41Sopenharmony_ci Address current_top = top(); 4681cb0ef41Sopenharmony_ci Address current_limit = limit(); 4691cb0ef41Sopenharmony_ci if (current_top == kNullAddress) { 4701cb0ef41Sopenharmony_ci DCHECK_EQ(kNullAddress, current_limit); 4711cb0ef41Sopenharmony_ci return; 4721cb0ef41Sopenharmony_ci } 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci AdvanceAllocationObservers(); 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ci if (current_top != current_limit && 4771cb0ef41Sopenharmony_ci heap()->incremental_marking()->black_allocation()) { 4781cb0ef41Sopenharmony_ci Page::FromAddress(current_top) 4791cb0ef41Sopenharmony_ci ->DestroyBlackArea(current_top, current_limit); 4801cb0ef41Sopenharmony_ci } 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_ci SetTopAndLimit(kNullAddress, kNullAddress); 4831cb0ef41Sopenharmony_ci DCHECK_GE(current_limit, current_top); 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci // The code page of the linear allocation area needs to be unprotected 4861cb0ef41Sopenharmony_ci // because we are going to write a filler into that memory area below. 4871cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE) { 4881cb0ef41Sopenharmony_ci heap()->UnprotectAndRegisterMemoryChunk( 4891cb0ef41Sopenharmony_ci MemoryChunk::FromAddress(current_top), 4901cb0ef41Sopenharmony_ci GetUnprotectMemoryOrigin(is_compaction_space())); 4911cb0ef41Sopenharmony_ci } 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_ci DCHECK_IMPLIES(current_limit - current_top >= 2 * kTaggedSize, 4941cb0ef41Sopenharmony_ci heap()->incremental_marking()->marking_state()->IsWhite( 4951cb0ef41Sopenharmony_ci HeapObject::FromAddress(current_top))); 4961cb0ef41Sopenharmony_ci Free(current_top, current_limit - current_top, 4971cb0ef41Sopenharmony_ci SpaceAccountingMode::kSpaceAccounted); 4981cb0ef41Sopenharmony_ci} 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_civoid PagedSpace::ReleasePage(Page* page) { 5011cb0ef41Sopenharmony_ci DCHECK_EQ( 5021cb0ef41Sopenharmony_ci 0, heap()->incremental_marking()->non_atomic_marking_state()->live_bytes( 5031cb0ef41Sopenharmony_ci page)); 5041cb0ef41Sopenharmony_ci DCHECK_EQ(page->owner(), this); 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ci free_list_->EvictFreeListItems(page); 5071cb0ef41Sopenharmony_ci 5081cb0ef41Sopenharmony_ci if (Page::FromAllocationAreaAddress(allocation_info_->top()) == page) { 5091cb0ef41Sopenharmony_ci SetTopAndLimit(kNullAddress, kNullAddress); 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE) { 5131cb0ef41Sopenharmony_ci heap()->isolate()->RemoveCodeMemoryChunk(page); 5141cb0ef41Sopenharmony_ci } 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_ci AccountUncommitted(page->size()); 5171cb0ef41Sopenharmony_ci DecrementCommittedPhysicalMemory(page->CommittedPhysicalMemory()); 5181cb0ef41Sopenharmony_ci accounting_stats_.DecreaseCapacity(page->area_size()); 5191cb0ef41Sopenharmony_ci heap()->memory_allocator()->Free(MemoryAllocator::FreeMode::kConcurrently, 5201cb0ef41Sopenharmony_ci page); 5211cb0ef41Sopenharmony_ci} 5221cb0ef41Sopenharmony_ci 5231cb0ef41Sopenharmony_civoid PagedSpace::SetReadable() { 5241cb0ef41Sopenharmony_ci DCHECK(identity() == CODE_SPACE); 5251cb0ef41Sopenharmony_ci for (Page* page : *this) { 5261cb0ef41Sopenharmony_ci DCHECK(heap()->memory_allocator()->IsMemoryChunkExecutable(page)); 5271cb0ef41Sopenharmony_ci page->SetReadable(); 5281cb0ef41Sopenharmony_ci } 5291cb0ef41Sopenharmony_ci} 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_civoid PagedSpace::SetReadAndExecutable() { 5321cb0ef41Sopenharmony_ci DCHECK(identity() == CODE_SPACE); 5331cb0ef41Sopenharmony_ci for (Page* page : *this) { 5341cb0ef41Sopenharmony_ci DCHECK(heap()->memory_allocator()->IsMemoryChunkExecutable(page)); 5351cb0ef41Sopenharmony_ci page->SetReadAndExecutable(); 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci} 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_civoid PagedSpace::SetCodeModificationPermissions() { 5401cb0ef41Sopenharmony_ci DCHECK(identity() == CODE_SPACE); 5411cb0ef41Sopenharmony_ci for (Page* page : *this) { 5421cb0ef41Sopenharmony_ci DCHECK(heap()->memory_allocator()->IsMemoryChunkExecutable(page)); 5431cb0ef41Sopenharmony_ci page->SetCodeModificationPermissions(); 5441cb0ef41Sopenharmony_ci } 5451cb0ef41Sopenharmony_ci} 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_cistd::unique_ptr<ObjectIterator> PagedSpace::GetObjectIterator(Heap* heap) { 5481cb0ef41Sopenharmony_ci return std::unique_ptr<ObjectIterator>( 5491cb0ef41Sopenharmony_ci new PagedSpaceObjectIterator(heap, this)); 5501cb0ef41Sopenharmony_ci} 5511cb0ef41Sopenharmony_ci 5521cb0ef41Sopenharmony_cibool PagedSpace::TryAllocationFromFreeListMain(size_t size_in_bytes, 5531cb0ef41Sopenharmony_ci AllocationOrigin origin) { 5541cb0ef41Sopenharmony_ci ConcurrentAllocationMutex guard(this); 5551cb0ef41Sopenharmony_ci DCHECK(IsAligned(size_in_bytes, kTaggedSize)); 5561cb0ef41Sopenharmony_ci DCHECK_LE(top(), limit()); 5571cb0ef41Sopenharmony_ci#ifdef DEBUG 5581cb0ef41Sopenharmony_ci if (top() != limit()) { 5591cb0ef41Sopenharmony_ci DCHECK_EQ(Page::FromAddress(top()), Page::FromAddress(limit() - 1)); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci#endif 5621cb0ef41Sopenharmony_ci // Don't free list allocate if there is linear space available. 5631cb0ef41Sopenharmony_ci DCHECK_LT(static_cast<size_t>(limit() - top()), size_in_bytes); 5641cb0ef41Sopenharmony_ci 5651cb0ef41Sopenharmony_ci // Mark the old linear allocation area with a free space map so it can be 5661cb0ef41Sopenharmony_ci // skipped when scanning the heap. This also puts it back in the free list 5671cb0ef41Sopenharmony_ci // if it is big enough. 5681cb0ef41Sopenharmony_ci FreeLinearAllocationArea(); 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci size_t new_node_size = 0; 5711cb0ef41Sopenharmony_ci FreeSpace new_node = 5721cb0ef41Sopenharmony_ci free_list_->Allocate(size_in_bytes, &new_node_size, origin); 5731cb0ef41Sopenharmony_ci if (new_node.is_null()) return false; 5741cb0ef41Sopenharmony_ci DCHECK_GE(new_node_size, size_in_bytes); 5751cb0ef41Sopenharmony_ci 5761cb0ef41Sopenharmony_ci // The old-space-step might have finished sweeping and restarted marking. 5771cb0ef41Sopenharmony_ci // Verify that it did not turn the page of the new node into an evacuation 5781cb0ef41Sopenharmony_ci // candidate. 5791cb0ef41Sopenharmony_ci DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(new_node)); 5801cb0ef41Sopenharmony_ci 5811cb0ef41Sopenharmony_ci // Memory in the linear allocation area is counted as allocated. We may free 5821cb0ef41Sopenharmony_ci // a little of this again immediately - see below. 5831cb0ef41Sopenharmony_ci Page* page = Page::FromHeapObject(new_node); 5841cb0ef41Sopenharmony_ci IncreaseAllocatedBytes(new_node_size, page); 5851cb0ef41Sopenharmony_ci 5861cb0ef41Sopenharmony_ci DCHECK_EQ(allocation_info_->start(), allocation_info_->top()); 5871cb0ef41Sopenharmony_ci Address start = new_node.address(); 5881cb0ef41Sopenharmony_ci Address end = new_node.address() + new_node_size; 5891cb0ef41Sopenharmony_ci Address limit = ComputeLimit(start, end, size_in_bytes); 5901cb0ef41Sopenharmony_ci DCHECK_LE(limit, end); 5911cb0ef41Sopenharmony_ci DCHECK_LE(size_in_bytes, limit - start); 5921cb0ef41Sopenharmony_ci if (limit != end) { 5931cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE) { 5941cb0ef41Sopenharmony_ci heap()->UnprotectAndRegisterMemoryChunk( 5951cb0ef41Sopenharmony_ci page, GetUnprotectMemoryOrigin(is_compaction_space())); 5961cb0ef41Sopenharmony_ci } 5971cb0ef41Sopenharmony_ci Free(limit, end - limit, SpaceAccountingMode::kSpaceAccounted); 5981cb0ef41Sopenharmony_ci } 5991cb0ef41Sopenharmony_ci SetLinearAllocationArea(start, limit); 6001cb0ef41Sopenharmony_ci AddRangeToActiveSystemPages(page, start, limit); 6011cb0ef41Sopenharmony_ci 6021cb0ef41Sopenharmony_ci return true; 6031cb0ef41Sopenharmony_ci} 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_cibase::Optional<std::pair<Address, size_t>> PagedSpace::RawRefillLabBackground( 6061cb0ef41Sopenharmony_ci LocalHeap* local_heap, size_t min_size_in_bytes, size_t max_size_in_bytes, 6071cb0ef41Sopenharmony_ci AllocationAlignment alignment, AllocationOrigin origin) { 6081cb0ef41Sopenharmony_ci DCHECK(!is_compaction_space()); 6091cb0ef41Sopenharmony_ci DCHECK(identity() == OLD_SPACE || identity() == CODE_SPACE || 6101cb0ef41Sopenharmony_ci identity() == MAP_SPACE); 6111cb0ef41Sopenharmony_ci DCHECK(origin == AllocationOrigin::kRuntime || 6121cb0ef41Sopenharmony_ci origin == AllocationOrigin::kGC); 6131cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!local_heap, origin == AllocationOrigin::kGC); 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ci base::Optional<std::pair<Address, size_t>> result = 6161cb0ef41Sopenharmony_ci TryAllocationFromFreeListBackground(min_size_in_bytes, max_size_in_bytes, 6171cb0ef41Sopenharmony_ci alignment, origin); 6181cb0ef41Sopenharmony_ci if (result) return result; 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ci MarkCompactCollector* collector = heap()->mark_compact_collector(); 6211cb0ef41Sopenharmony_ci // Sweeping is still in progress. 6221cb0ef41Sopenharmony_ci if (collector->sweeping_in_progress()) { 6231cb0ef41Sopenharmony_ci // First try to refill the free-list, concurrent sweeper threads 6241cb0ef41Sopenharmony_ci // may have freed some objects in the meantime. 6251cb0ef41Sopenharmony_ci RefillFreeList(); 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci // Retry the free list allocation. 6281cb0ef41Sopenharmony_ci result = TryAllocationFromFreeListBackground( 6291cb0ef41Sopenharmony_ci min_size_in_bytes, max_size_in_bytes, alignment, origin); 6301cb0ef41Sopenharmony_ci if (result) return result; 6311cb0ef41Sopenharmony_ci 6321cb0ef41Sopenharmony_ci if (IsSweepingAllowedOnThread(local_heap)) { 6331cb0ef41Sopenharmony_ci // Now contribute to sweeping from background thread and then try to 6341cb0ef41Sopenharmony_ci // reallocate. 6351cb0ef41Sopenharmony_ci const int kMaxPagesToSweep = 1; 6361cb0ef41Sopenharmony_ci int max_freed = collector->sweeper()->ParallelSweepSpace( 6371cb0ef41Sopenharmony_ci identity(), Sweeper::SweepingMode::kLazyOrConcurrent, 6381cb0ef41Sopenharmony_ci static_cast<int>(min_size_in_bytes), kMaxPagesToSweep); 6391cb0ef41Sopenharmony_ci 6401cb0ef41Sopenharmony_ci RefillFreeList(); 6411cb0ef41Sopenharmony_ci 6421cb0ef41Sopenharmony_ci if (static_cast<size_t>(max_freed) >= min_size_in_bytes) { 6431cb0ef41Sopenharmony_ci result = TryAllocationFromFreeListBackground( 6441cb0ef41Sopenharmony_ci min_size_in_bytes, max_size_in_bytes, alignment, origin); 6451cb0ef41Sopenharmony_ci if (result) return result; 6461cb0ef41Sopenharmony_ci } 6471cb0ef41Sopenharmony_ci } 6481cb0ef41Sopenharmony_ci } 6491cb0ef41Sopenharmony_ci 6501cb0ef41Sopenharmony_ci if (heap()->ShouldExpandOldGenerationOnSlowAllocation(local_heap) && 6511cb0ef41Sopenharmony_ci heap()->CanExpandOldGenerationBackground(local_heap, AreaSize())) { 6521cb0ef41Sopenharmony_ci result = ExpandBackground(max_size_in_bytes); 6531cb0ef41Sopenharmony_ci if (result) { 6541cb0ef41Sopenharmony_ci DCHECK_EQ(Heap::GetFillToAlign(result->first, alignment), 0); 6551cb0ef41Sopenharmony_ci return result; 6561cb0ef41Sopenharmony_ci } 6571cb0ef41Sopenharmony_ci } 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci if (collector->sweeping_in_progress()) { 6601cb0ef41Sopenharmony_ci // Complete sweeping for this space. 6611cb0ef41Sopenharmony_ci if (IsSweepingAllowedOnThread(local_heap)) { 6621cb0ef41Sopenharmony_ci collector->DrainSweepingWorklistForSpace(identity()); 6631cb0ef41Sopenharmony_ci } 6641cb0ef41Sopenharmony_ci 6651cb0ef41Sopenharmony_ci RefillFreeList(); 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_ci // Last try to acquire memory from free list. 6681cb0ef41Sopenharmony_ci return TryAllocationFromFreeListBackground( 6691cb0ef41Sopenharmony_ci min_size_in_bytes, max_size_in_bytes, alignment, origin); 6701cb0ef41Sopenharmony_ci } 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ci return {}; 6731cb0ef41Sopenharmony_ci} 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_cibase::Optional<std::pair<Address, size_t>> 6761cb0ef41Sopenharmony_ciPagedSpace::TryAllocationFromFreeListBackground(size_t min_size_in_bytes, 6771cb0ef41Sopenharmony_ci size_t max_size_in_bytes, 6781cb0ef41Sopenharmony_ci AllocationAlignment alignment, 6791cb0ef41Sopenharmony_ci AllocationOrigin origin) { 6801cb0ef41Sopenharmony_ci base::MutexGuard lock(&space_mutex_); 6811cb0ef41Sopenharmony_ci DCHECK_LE(min_size_in_bytes, max_size_in_bytes); 6821cb0ef41Sopenharmony_ci DCHECK(identity() == OLD_SPACE || identity() == CODE_SPACE || 6831cb0ef41Sopenharmony_ci identity() == MAP_SPACE); 6841cb0ef41Sopenharmony_ci 6851cb0ef41Sopenharmony_ci size_t new_node_size = 0; 6861cb0ef41Sopenharmony_ci FreeSpace new_node = 6871cb0ef41Sopenharmony_ci free_list_->Allocate(min_size_in_bytes, &new_node_size, origin); 6881cb0ef41Sopenharmony_ci if (new_node.is_null()) return {}; 6891cb0ef41Sopenharmony_ci DCHECK_GE(new_node_size, min_size_in_bytes); 6901cb0ef41Sopenharmony_ci 6911cb0ef41Sopenharmony_ci // The old-space-step might have finished sweeping and restarted marking. 6921cb0ef41Sopenharmony_ci // Verify that it did not turn the page of the new node into an evacuation 6931cb0ef41Sopenharmony_ci // candidate. 6941cb0ef41Sopenharmony_ci DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(new_node)); 6951cb0ef41Sopenharmony_ci 6961cb0ef41Sopenharmony_ci // Memory in the linear allocation area is counted as allocated. We may free 6971cb0ef41Sopenharmony_ci // a little of this again immediately - see below. 6981cb0ef41Sopenharmony_ci Page* page = Page::FromHeapObject(new_node); 6991cb0ef41Sopenharmony_ci IncreaseAllocatedBytes(new_node_size, page); 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_ci heap()->StartIncrementalMarkingIfAllocationLimitIsReachedBackground(); 7021cb0ef41Sopenharmony_ci 7031cb0ef41Sopenharmony_ci size_t used_size_in_bytes = std::min(new_node_size, max_size_in_bytes); 7041cb0ef41Sopenharmony_ci 7051cb0ef41Sopenharmony_ci Address start = new_node.address(); 7061cb0ef41Sopenharmony_ci Address end = new_node.address() + new_node_size; 7071cb0ef41Sopenharmony_ci Address limit = new_node.address() + used_size_in_bytes; 7081cb0ef41Sopenharmony_ci DCHECK_LE(limit, end); 7091cb0ef41Sopenharmony_ci DCHECK_LE(min_size_in_bytes, limit - start); 7101cb0ef41Sopenharmony_ci if (limit != end) { 7111cb0ef41Sopenharmony_ci if (identity() == CODE_SPACE) { 7121cb0ef41Sopenharmony_ci heap()->UnprotectAndRegisterMemoryChunk( 7131cb0ef41Sopenharmony_ci page, UnprotectMemoryOrigin::kMaybeOffMainThread); 7141cb0ef41Sopenharmony_ci } 7151cb0ef41Sopenharmony_ci Free(limit, end - limit, SpaceAccountingMode::kSpaceAccounted); 7161cb0ef41Sopenharmony_ci } 7171cb0ef41Sopenharmony_ci AddRangeToActiveSystemPages(page, start, limit); 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ci return std::make_pair(start, used_size_in_bytes); 7201cb0ef41Sopenharmony_ci} 7211cb0ef41Sopenharmony_ci 7221cb0ef41Sopenharmony_cibool PagedSpace::IsSweepingAllowedOnThread(LocalHeap* local_heap) const { 7231cb0ef41Sopenharmony_ci // Code space sweeping is only allowed on main thread. 7241cb0ef41Sopenharmony_ci return (local_heap && local_heap->is_main_thread()) || 7251cb0ef41Sopenharmony_ci identity() != CODE_SPACE; 7261cb0ef41Sopenharmony_ci} 7271cb0ef41Sopenharmony_ci 7281cb0ef41Sopenharmony_ci#ifdef DEBUG 7291cb0ef41Sopenharmony_civoid PagedSpace::Print() {} 7301cb0ef41Sopenharmony_ci#endif 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP 7331cb0ef41Sopenharmony_civoid PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) { 7341cb0ef41Sopenharmony_ci bool allocation_pointer_found_in_space = 7351cb0ef41Sopenharmony_ci (allocation_info_->top() == allocation_info_->limit()); 7361cb0ef41Sopenharmony_ci size_t external_space_bytes[kNumTypes]; 7371cb0ef41Sopenharmony_ci size_t external_page_bytes[kNumTypes]; 7381cb0ef41Sopenharmony_ci 7391cb0ef41Sopenharmony_ci for (int i = 0; i < kNumTypes; i++) { 7401cb0ef41Sopenharmony_ci external_space_bytes[static_cast<ExternalBackingStoreType>(i)] = 0; 7411cb0ef41Sopenharmony_ci } 7421cb0ef41Sopenharmony_ci 7431cb0ef41Sopenharmony_ci PtrComprCageBase cage_base(isolate); 7441cb0ef41Sopenharmony_ci for (Page* page : *this) { 7451cb0ef41Sopenharmony_ci CHECK_EQ(page->owner(), this); 7461cb0ef41Sopenharmony_ci 7471cb0ef41Sopenharmony_ci for (int i = 0; i < kNumTypes; i++) { 7481cb0ef41Sopenharmony_ci external_page_bytes[static_cast<ExternalBackingStoreType>(i)] = 0; 7491cb0ef41Sopenharmony_ci } 7501cb0ef41Sopenharmony_ci 7511cb0ef41Sopenharmony_ci if (page == Page::FromAllocationAreaAddress(allocation_info_->top())) { 7521cb0ef41Sopenharmony_ci allocation_pointer_found_in_space = true; 7531cb0ef41Sopenharmony_ci } 7541cb0ef41Sopenharmony_ci CHECK(page->SweepingDone()); 7551cb0ef41Sopenharmony_ci PagedSpaceObjectIterator it(isolate->heap(), this, page); 7561cb0ef41Sopenharmony_ci Address end_of_previous_object = page->area_start(); 7571cb0ef41Sopenharmony_ci Address top = page->area_end(); 7581cb0ef41Sopenharmony_ci 7591cb0ef41Sopenharmony_ci for (HeapObject object = it.Next(); !object.is_null(); object = it.Next()) { 7601cb0ef41Sopenharmony_ci CHECK(end_of_previous_object <= object.address()); 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci // The first word should be a map, and we expect all map pointers to 7631cb0ef41Sopenharmony_ci // be in map space. 7641cb0ef41Sopenharmony_ci Map map = object.map(cage_base); 7651cb0ef41Sopenharmony_ci CHECK(map.IsMap(cage_base)); 7661cb0ef41Sopenharmony_ci CHECK(ReadOnlyHeap::Contains(map) || 7671cb0ef41Sopenharmony_ci isolate->heap()->space_for_maps()->Contains(map)); 7681cb0ef41Sopenharmony_ci 7691cb0ef41Sopenharmony_ci // Perform space-specific object verification. 7701cb0ef41Sopenharmony_ci VerifyObject(object); 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_ci // The object itself should look OK. 7731cb0ef41Sopenharmony_ci object.ObjectVerify(isolate); 7741cb0ef41Sopenharmony_ci 7751cb0ef41Sopenharmony_ci if (identity() != RO_SPACE && !FLAG_verify_heap_skip_remembered_set) { 7761cb0ef41Sopenharmony_ci isolate->heap()->VerifyRememberedSetFor(object); 7771cb0ef41Sopenharmony_ci } 7781cb0ef41Sopenharmony_ci 7791cb0ef41Sopenharmony_ci // All the interior pointers should be contained in the heap. 7801cb0ef41Sopenharmony_ci int size = object.Size(cage_base); 7811cb0ef41Sopenharmony_ci object.IterateBody(map, size, visitor); 7821cb0ef41Sopenharmony_ci CHECK(object.address() + size <= top); 7831cb0ef41Sopenharmony_ci end_of_previous_object = object.address() + size; 7841cb0ef41Sopenharmony_ci 7851cb0ef41Sopenharmony_ci if (object.IsExternalString(cage_base)) { 7861cb0ef41Sopenharmony_ci ExternalString external_string = ExternalString::cast(object); 7871cb0ef41Sopenharmony_ci size_t payload_size = external_string.ExternalPayloadSize(); 7881cb0ef41Sopenharmony_ci external_page_bytes[ExternalBackingStoreType::kExternalString] += 7891cb0ef41Sopenharmony_ci payload_size; 7901cb0ef41Sopenharmony_ci } 7911cb0ef41Sopenharmony_ci } 7921cb0ef41Sopenharmony_ci for (int i = 0; i < kNumTypes; i++) { 7931cb0ef41Sopenharmony_ci ExternalBackingStoreType t = static_cast<ExternalBackingStoreType>(i); 7941cb0ef41Sopenharmony_ci CHECK_EQ(external_page_bytes[t], page->ExternalBackingStoreBytes(t)); 7951cb0ef41Sopenharmony_ci external_space_bytes[t] += external_page_bytes[t]; 7961cb0ef41Sopenharmony_ci } 7971cb0ef41Sopenharmony_ci 7981cb0ef41Sopenharmony_ci CHECK(!page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION)); 7991cb0ef41Sopenharmony_ci CHECK(!page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)); 8001cb0ef41Sopenharmony_ci } 8011cb0ef41Sopenharmony_ci for (int i = 0; i < kNumTypes; i++) { 8021cb0ef41Sopenharmony_ci if (i == ExternalBackingStoreType::kArrayBuffer) continue; 8031cb0ef41Sopenharmony_ci ExternalBackingStoreType t = static_cast<ExternalBackingStoreType>(i); 8041cb0ef41Sopenharmony_ci CHECK_EQ(external_space_bytes[t], ExternalBackingStoreBytes(t)); 8051cb0ef41Sopenharmony_ci } 8061cb0ef41Sopenharmony_ci CHECK(allocation_pointer_found_in_space); 8071cb0ef41Sopenharmony_ci 8081cb0ef41Sopenharmony_ci if (identity() == OLD_SPACE && !FLAG_concurrent_array_buffer_sweeping) { 8091cb0ef41Sopenharmony_ci size_t bytes = heap()->array_buffer_sweeper()->old().BytesSlow(); 8101cb0ef41Sopenharmony_ci CHECK_EQ(bytes, 8111cb0ef41Sopenharmony_ci ExternalBackingStoreBytes(ExternalBackingStoreType::kArrayBuffer)); 8121cb0ef41Sopenharmony_ci } 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci#ifdef DEBUG 8151cb0ef41Sopenharmony_ci VerifyCountersAfterSweeping(isolate->heap()); 8161cb0ef41Sopenharmony_ci#endif 8171cb0ef41Sopenharmony_ci} 8181cb0ef41Sopenharmony_ci 8191cb0ef41Sopenharmony_civoid PagedSpace::VerifyLiveBytes() { 8201cb0ef41Sopenharmony_ci IncrementalMarking::MarkingState* marking_state = 8211cb0ef41Sopenharmony_ci heap()->incremental_marking()->marking_state(); 8221cb0ef41Sopenharmony_ci PtrComprCageBase cage_base(heap()->isolate()); 8231cb0ef41Sopenharmony_ci for (Page* page : *this) { 8241cb0ef41Sopenharmony_ci CHECK(page->SweepingDone()); 8251cb0ef41Sopenharmony_ci PagedSpaceObjectIterator it(heap(), this, page); 8261cb0ef41Sopenharmony_ci int black_size = 0; 8271cb0ef41Sopenharmony_ci for (HeapObject object = it.Next(); !object.is_null(); object = it.Next()) { 8281cb0ef41Sopenharmony_ci // All the interior pointers should be contained in the heap. 8291cb0ef41Sopenharmony_ci if (marking_state->IsBlack(object)) { 8301cb0ef41Sopenharmony_ci black_size += object.Size(cage_base); 8311cb0ef41Sopenharmony_ci } 8321cb0ef41Sopenharmony_ci } 8331cb0ef41Sopenharmony_ci CHECK_LE(black_size, marking_state->live_bytes(page)); 8341cb0ef41Sopenharmony_ci } 8351cb0ef41Sopenharmony_ci} 8361cb0ef41Sopenharmony_ci#endif // VERIFY_HEAP 8371cb0ef41Sopenharmony_ci 8381cb0ef41Sopenharmony_ci#ifdef DEBUG 8391cb0ef41Sopenharmony_civoid PagedSpace::VerifyCountersAfterSweeping(Heap* heap) { 8401cb0ef41Sopenharmony_ci size_t total_capacity = 0; 8411cb0ef41Sopenharmony_ci size_t total_allocated = 0; 8421cb0ef41Sopenharmony_ci PtrComprCageBase cage_base(heap->isolate()); 8431cb0ef41Sopenharmony_ci for (Page* page : *this) { 8441cb0ef41Sopenharmony_ci DCHECK(page->SweepingDone()); 8451cb0ef41Sopenharmony_ci total_capacity += page->area_size(); 8461cb0ef41Sopenharmony_ci PagedSpaceObjectIterator it(heap, this, page); 8471cb0ef41Sopenharmony_ci size_t real_allocated = 0; 8481cb0ef41Sopenharmony_ci for (HeapObject object = it.Next(); !object.is_null(); object = it.Next()) { 8491cb0ef41Sopenharmony_ci if (!object.IsFreeSpaceOrFiller()) { 8501cb0ef41Sopenharmony_ci real_allocated += object.Size(cage_base); 8511cb0ef41Sopenharmony_ci } 8521cb0ef41Sopenharmony_ci } 8531cb0ef41Sopenharmony_ci total_allocated += page->allocated_bytes(); 8541cb0ef41Sopenharmony_ci // The real size can be smaller than the accounted size if array trimming, 8551cb0ef41Sopenharmony_ci // object slack tracking happened after sweeping. 8561cb0ef41Sopenharmony_ci DCHECK_LE(real_allocated, accounting_stats_.AllocatedOnPage(page)); 8571cb0ef41Sopenharmony_ci DCHECK_EQ(page->allocated_bytes(), accounting_stats_.AllocatedOnPage(page)); 8581cb0ef41Sopenharmony_ci } 8591cb0ef41Sopenharmony_ci DCHECK_EQ(total_capacity, accounting_stats_.Capacity()); 8601cb0ef41Sopenharmony_ci DCHECK_EQ(total_allocated, accounting_stats_.Size()); 8611cb0ef41Sopenharmony_ci} 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_civoid PagedSpace::VerifyCountersBeforeConcurrentSweeping() { 8641cb0ef41Sopenharmony_ci // We need to refine the counters on pages that are already swept and have 8651cb0ef41Sopenharmony_ci // not been moved over to the actual space. Otherwise, the AccountingStats 8661cb0ef41Sopenharmony_ci // are just an over approximation. 8671cb0ef41Sopenharmony_ci RefillFreeList(); 8681cb0ef41Sopenharmony_ci 8691cb0ef41Sopenharmony_ci size_t total_capacity = 0; 8701cb0ef41Sopenharmony_ci size_t total_allocated = 0; 8711cb0ef41Sopenharmony_ci auto marking_state = 8721cb0ef41Sopenharmony_ci heap()->incremental_marking()->non_atomic_marking_state(); 8731cb0ef41Sopenharmony_ci for (Page* page : *this) { 8741cb0ef41Sopenharmony_ci size_t page_allocated = 8751cb0ef41Sopenharmony_ci page->SweepingDone() 8761cb0ef41Sopenharmony_ci ? page->allocated_bytes() 8771cb0ef41Sopenharmony_ci : static_cast<size_t>(marking_state->live_bytes(page)); 8781cb0ef41Sopenharmony_ci total_capacity += page->area_size(); 8791cb0ef41Sopenharmony_ci total_allocated += page_allocated; 8801cb0ef41Sopenharmony_ci DCHECK_EQ(page_allocated, accounting_stats_.AllocatedOnPage(page)); 8811cb0ef41Sopenharmony_ci } 8821cb0ef41Sopenharmony_ci DCHECK_EQ(total_capacity, accounting_stats_.Capacity()); 8831cb0ef41Sopenharmony_ci DCHECK_EQ(total_allocated, accounting_stats_.Size()); 8841cb0ef41Sopenharmony_ci} 8851cb0ef41Sopenharmony_ci#endif 8861cb0ef41Sopenharmony_ci 8871cb0ef41Sopenharmony_civoid PagedSpace::UpdateInlineAllocationLimit(size_t min_size) { 8881cb0ef41Sopenharmony_ci // Ensure there are no unaccounted allocations. 8891cb0ef41Sopenharmony_ci DCHECK_EQ(allocation_info_->start(), allocation_info_->top()); 8901cb0ef41Sopenharmony_ci 8911cb0ef41Sopenharmony_ci Address new_limit = ComputeLimit(top(), limit(), min_size); 8921cb0ef41Sopenharmony_ci DCHECK_LE(top(), new_limit); 8931cb0ef41Sopenharmony_ci DCHECK_LE(new_limit, limit()); 8941cb0ef41Sopenharmony_ci DecreaseLimit(new_limit); 8951cb0ef41Sopenharmony_ci} 8961cb0ef41Sopenharmony_ci 8971cb0ef41Sopenharmony_ci// ----------------------------------------------------------------------------- 8981cb0ef41Sopenharmony_ci// OldSpace implementation 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_civoid PagedSpace::PrepareForMarkCompact() { 9011cb0ef41Sopenharmony_ci // Clear the free list before a full GC---it will be rebuilt afterward. 9021cb0ef41Sopenharmony_ci free_list_->Reset(); 9031cb0ef41Sopenharmony_ci} 9041cb0ef41Sopenharmony_ci 9051cb0ef41Sopenharmony_cibool PagedSpace::RefillLabMain(int size_in_bytes, AllocationOrigin origin) { 9061cb0ef41Sopenharmony_ci VMState<GC> state(heap()->isolate()); 9071cb0ef41Sopenharmony_ci RCS_SCOPE(heap()->isolate(), 9081cb0ef41Sopenharmony_ci RuntimeCallCounterId::kGC_Custom_SlowAllocateRaw); 9091cb0ef41Sopenharmony_ci return RawRefillLabMain(size_in_bytes, origin); 9101cb0ef41Sopenharmony_ci} 9111cb0ef41Sopenharmony_ci 9121cb0ef41Sopenharmony_ciPage* CompactionSpace::Expand() { 9131cb0ef41Sopenharmony_ci Page* page = PagedSpace::Expand(); 9141cb0ef41Sopenharmony_ci new_pages_.push_back(page); 9151cb0ef41Sopenharmony_ci return page; 9161cb0ef41Sopenharmony_ci} 9171cb0ef41Sopenharmony_ci 9181cb0ef41Sopenharmony_cibool CompactionSpace::RefillLabMain(int size_in_bytes, 9191cb0ef41Sopenharmony_ci AllocationOrigin origin) { 9201cb0ef41Sopenharmony_ci return RawRefillLabMain(size_in_bytes, origin); 9211cb0ef41Sopenharmony_ci} 9221cb0ef41Sopenharmony_ci 9231cb0ef41Sopenharmony_cibool PagedSpace::TryExpand(int size_in_bytes, AllocationOrigin origin) { 9241cb0ef41Sopenharmony_ci Page* page = Expand(); 9251cb0ef41Sopenharmony_ci if (!page) return false; 9261cb0ef41Sopenharmony_ci if (!is_compaction_space()) { 9271cb0ef41Sopenharmony_ci heap()->NotifyOldGenerationExpansion(identity(), page); 9281cb0ef41Sopenharmony_ci } 9291cb0ef41Sopenharmony_ci DCHECK((CountTotalPages() > 1) || 9301cb0ef41Sopenharmony_ci (static_cast<size_t>(size_in_bytes) <= free_list_->Available())); 9311cb0ef41Sopenharmony_ci return TryAllocationFromFreeListMain(static_cast<size_t>(size_in_bytes), 9321cb0ef41Sopenharmony_ci origin); 9331cb0ef41Sopenharmony_ci} 9341cb0ef41Sopenharmony_ci 9351cb0ef41Sopenharmony_cibool PagedSpace::RawRefillLabMain(int size_in_bytes, AllocationOrigin origin) { 9361cb0ef41Sopenharmony_ci // Allocation in this space has failed. 9371cb0ef41Sopenharmony_ci DCHECK_GE(size_in_bytes, 0); 9381cb0ef41Sopenharmony_ci const int kMaxPagesToSweep = 1; 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_ci if (TryAllocationFromFreeListMain(size_in_bytes, origin)) return true; 9411cb0ef41Sopenharmony_ci 9421cb0ef41Sopenharmony_ci MarkCompactCollector* collector = heap()->mark_compact_collector(); 9431cb0ef41Sopenharmony_ci // Sweeping is still in progress. 9441cb0ef41Sopenharmony_ci if (collector->sweeping_in_progress()) { 9451cb0ef41Sopenharmony_ci // First try to refill the free-list, concurrent sweeper threads 9461cb0ef41Sopenharmony_ci // may have freed some objects in the meantime. 9471cb0ef41Sopenharmony_ci RefillFreeList(); 9481cb0ef41Sopenharmony_ci 9491cb0ef41Sopenharmony_ci // Retry the free list allocation. 9501cb0ef41Sopenharmony_ci if (TryAllocationFromFreeListMain(static_cast<size_t>(size_in_bytes), 9511cb0ef41Sopenharmony_ci origin)) 9521cb0ef41Sopenharmony_ci return true; 9531cb0ef41Sopenharmony_ci 9541cb0ef41Sopenharmony_ci if (ContributeToSweepingMain(size_in_bytes, kMaxPagesToSweep, size_in_bytes, 9551cb0ef41Sopenharmony_ci origin)) 9561cb0ef41Sopenharmony_ci return true; 9571cb0ef41Sopenharmony_ci } 9581cb0ef41Sopenharmony_ci 9591cb0ef41Sopenharmony_ci if (is_compaction_space()) { 9601cb0ef41Sopenharmony_ci // The main thread may have acquired all swept pages. Try to steal from 9611cb0ef41Sopenharmony_ci // it. This can only happen during young generation evacuation. 9621cb0ef41Sopenharmony_ci PagedSpace* main_space = heap()->paged_space(identity()); 9631cb0ef41Sopenharmony_ci Page* page = main_space->RemovePageSafe(size_in_bytes); 9641cb0ef41Sopenharmony_ci if (page != nullptr) { 9651cb0ef41Sopenharmony_ci AddPage(page); 9661cb0ef41Sopenharmony_ci if (TryAllocationFromFreeListMain(static_cast<size_t>(size_in_bytes), 9671cb0ef41Sopenharmony_ci origin)) 9681cb0ef41Sopenharmony_ci return true; 9691cb0ef41Sopenharmony_ci } 9701cb0ef41Sopenharmony_ci } 9711cb0ef41Sopenharmony_ci 9721cb0ef41Sopenharmony_ci if (heap()->ShouldExpandOldGenerationOnSlowAllocation() && 9731cb0ef41Sopenharmony_ci heap()->CanExpandOldGeneration(AreaSize())) { 9741cb0ef41Sopenharmony_ci if (TryExpand(size_in_bytes, origin)) { 9751cb0ef41Sopenharmony_ci return true; 9761cb0ef41Sopenharmony_ci } 9771cb0ef41Sopenharmony_ci } 9781cb0ef41Sopenharmony_ci 9791cb0ef41Sopenharmony_ci // Try sweeping all pages. 9801cb0ef41Sopenharmony_ci if (ContributeToSweepingMain(0, 0, size_in_bytes, origin)) { 9811cb0ef41Sopenharmony_ci return true; 9821cb0ef41Sopenharmony_ci } 9831cb0ef41Sopenharmony_ci 9841cb0ef41Sopenharmony_ci if (heap()->gc_state() != Heap::NOT_IN_GC && !heap()->force_oom()) { 9851cb0ef41Sopenharmony_ci // Avoid OOM crash in the GC in order to invoke NearHeapLimitCallback after 9861cb0ef41Sopenharmony_ci // GC and give it a chance to increase the heap limit. 9871cb0ef41Sopenharmony_ci return TryExpand(size_in_bytes, origin); 9881cb0ef41Sopenharmony_ci } 9891cb0ef41Sopenharmony_ci return false; 9901cb0ef41Sopenharmony_ci} 9911cb0ef41Sopenharmony_ci 9921cb0ef41Sopenharmony_cibool PagedSpace::ContributeToSweepingMain(int required_freed_bytes, 9931cb0ef41Sopenharmony_ci int max_pages, int size_in_bytes, 9941cb0ef41Sopenharmony_ci AllocationOrigin origin) { 9951cb0ef41Sopenharmony_ci // Cleanup invalidated old-to-new refs for compaction space in the 9961cb0ef41Sopenharmony_ci // final atomic pause. 9971cb0ef41Sopenharmony_ci Sweeper::SweepingMode sweeping_mode = 9981cb0ef41Sopenharmony_ci is_compaction_space() ? Sweeper::SweepingMode::kEagerDuringGC 9991cb0ef41Sopenharmony_ci : Sweeper::SweepingMode::kLazyOrConcurrent; 10001cb0ef41Sopenharmony_ci 10011cb0ef41Sopenharmony_ci MarkCompactCollector* collector = heap()->mark_compact_collector(); 10021cb0ef41Sopenharmony_ci if (collector->sweeping_in_progress()) { 10031cb0ef41Sopenharmony_ci collector->sweeper()->ParallelSweepSpace(identity(), sweeping_mode, 10041cb0ef41Sopenharmony_ci required_freed_bytes, max_pages); 10051cb0ef41Sopenharmony_ci RefillFreeList(); 10061cb0ef41Sopenharmony_ci return TryAllocationFromFreeListMain(size_in_bytes, origin); 10071cb0ef41Sopenharmony_ci } 10081cb0ef41Sopenharmony_ci return false; 10091cb0ef41Sopenharmony_ci} 10101cb0ef41Sopenharmony_ci 10111cb0ef41Sopenharmony_civoid PagedSpace::AddRangeToActiveSystemPages(Page* page, Address start, 10121cb0ef41Sopenharmony_ci Address end) { 10131cb0ef41Sopenharmony_ci DCHECK_LE(page->address(), start); 10141cb0ef41Sopenharmony_ci DCHECK_LT(start, end); 10151cb0ef41Sopenharmony_ci DCHECK_LE(end, page->address() + Page::kPageSize); 10161cb0ef41Sopenharmony_ci 10171cb0ef41Sopenharmony_ci const size_t added_pages = page->active_system_pages()->Add( 10181cb0ef41Sopenharmony_ci start - page->address(), end - page->address(), 10191cb0ef41Sopenharmony_ci MemoryAllocator::GetCommitPageSizeBits()); 10201cb0ef41Sopenharmony_ci 10211cb0ef41Sopenharmony_ci IncrementCommittedPhysicalMemory(added_pages * 10221cb0ef41Sopenharmony_ci MemoryAllocator::GetCommitPageSize()); 10231cb0ef41Sopenharmony_ci} 10241cb0ef41Sopenharmony_ci 10251cb0ef41Sopenharmony_civoid PagedSpace::ReduceActiveSystemPages( 10261cb0ef41Sopenharmony_ci Page* page, ActiveSystemPages active_system_pages) { 10271cb0ef41Sopenharmony_ci const size_t reduced_pages = 10281cb0ef41Sopenharmony_ci page->active_system_pages()->Reduce(active_system_pages); 10291cb0ef41Sopenharmony_ci DecrementCommittedPhysicalMemory(reduced_pages * 10301cb0ef41Sopenharmony_ci MemoryAllocator::GetCommitPageSize()); 10311cb0ef41Sopenharmony_ci} 10321cb0ef41Sopenharmony_ci 10331cb0ef41Sopenharmony_cibool PagedSpace::EnsureAllocation(int size_in_bytes, 10341cb0ef41Sopenharmony_ci AllocationAlignment alignment, 10351cb0ef41Sopenharmony_ci AllocationOrigin origin, 10361cb0ef41Sopenharmony_ci int* out_max_aligned_size) { 10371cb0ef41Sopenharmony_ci if (!is_compaction_space()) { 10381cb0ef41Sopenharmony_ci // Start incremental marking before the actual allocation, this allows the 10391cb0ef41Sopenharmony_ci // allocation function to mark the object black when incremental marking is 10401cb0ef41Sopenharmony_ci // running. 10411cb0ef41Sopenharmony_ci heap()->StartIncrementalMarkingIfAllocationLimitIsReached( 10421cb0ef41Sopenharmony_ci heap()->GCFlagsForIncrementalMarking(), 10431cb0ef41Sopenharmony_ci kGCCallbackScheduleIdleGarbageCollection); 10441cb0ef41Sopenharmony_ci } 10451cb0ef41Sopenharmony_ci 10461cb0ef41Sopenharmony_ci // We don't know exactly how much filler we need to align until space is 10471cb0ef41Sopenharmony_ci // allocated, so assume the worst case. 10481cb0ef41Sopenharmony_ci size_in_bytes += Heap::GetMaximumFillToAlign(alignment); 10491cb0ef41Sopenharmony_ci if (out_max_aligned_size) { 10501cb0ef41Sopenharmony_ci *out_max_aligned_size = size_in_bytes; 10511cb0ef41Sopenharmony_ci } 10521cb0ef41Sopenharmony_ci if (allocation_info_->top() + size_in_bytes <= allocation_info_->limit()) { 10531cb0ef41Sopenharmony_ci return true; 10541cb0ef41Sopenharmony_ci } 10551cb0ef41Sopenharmony_ci return RefillLabMain(size_in_bytes, origin); 10561cb0ef41Sopenharmony_ci} 10571cb0ef41Sopenharmony_ci 10581cb0ef41Sopenharmony_ci// ----------------------------------------------------------------------------- 10591cb0ef41Sopenharmony_ci// MapSpace implementation 10601cb0ef41Sopenharmony_ci 10611cb0ef41Sopenharmony_ci// TODO(dmercadier): use a heap instead of sorting like that. 10621cb0ef41Sopenharmony_ci// Using a heap will have multiple benefits: 10631cb0ef41Sopenharmony_ci// - for now, SortFreeList is only called after sweeping, which is somewhat 10641cb0ef41Sopenharmony_ci// late. Using a heap, sorting could be done online: FreeListCategories would 10651cb0ef41Sopenharmony_ci// be inserted in a heap (ie, in a sorted manner). 10661cb0ef41Sopenharmony_ci// - SortFreeList is a bit fragile: any change to FreeListMap (or to 10671cb0ef41Sopenharmony_ci// MapSpace::free_list_) could break it. 10681cb0ef41Sopenharmony_civoid MapSpace::SortFreeList() { 10691cb0ef41Sopenharmony_ci using LiveBytesPagePair = std::pair<size_t, Page*>; 10701cb0ef41Sopenharmony_ci std::vector<LiveBytesPagePair> pages; 10711cb0ef41Sopenharmony_ci pages.reserve(CountTotalPages()); 10721cb0ef41Sopenharmony_ci 10731cb0ef41Sopenharmony_ci for (Page* p : *this) { 10741cb0ef41Sopenharmony_ci free_list()->RemoveCategory(p->free_list_category(kFirstCategory)); 10751cb0ef41Sopenharmony_ci pages.push_back(std::make_pair(p->allocated_bytes(), p)); 10761cb0ef41Sopenharmony_ci } 10771cb0ef41Sopenharmony_ci 10781cb0ef41Sopenharmony_ci // Sorting by least-allocated-bytes first. 10791cb0ef41Sopenharmony_ci std::sort(pages.begin(), pages.end(), 10801cb0ef41Sopenharmony_ci [](const LiveBytesPagePair& a, const LiveBytesPagePair& b) { 10811cb0ef41Sopenharmony_ci return a.first < b.first; 10821cb0ef41Sopenharmony_ci }); 10831cb0ef41Sopenharmony_ci 10841cb0ef41Sopenharmony_ci for (LiveBytesPagePair const& p : pages) { 10851cb0ef41Sopenharmony_ci // Since AddCategory inserts in head position, it reverts the order produced 10861cb0ef41Sopenharmony_ci // by the sort above: least-allocated-bytes will be Added first, and will 10871cb0ef41Sopenharmony_ci // therefore be the last element (and the first one will be 10881cb0ef41Sopenharmony_ci // most-allocated-bytes). 10891cb0ef41Sopenharmony_ci free_list()->AddCategory(p.second->free_list_category(kFirstCategory)); 10901cb0ef41Sopenharmony_ci } 10911cb0ef41Sopenharmony_ci} 10921cb0ef41Sopenharmony_ci 10931cb0ef41Sopenharmony_ci#ifdef VERIFY_HEAP 10941cb0ef41Sopenharmony_civoid MapSpace::VerifyObject(HeapObject object) const { CHECK(object.IsMap()); } 10951cb0ef41Sopenharmony_ci#endif 10961cb0ef41Sopenharmony_ci 10971cb0ef41Sopenharmony_ci} // namespace internal 10981cb0ef41Sopenharmony_ci} // namespace v8 1099