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