11cb0ef41Sopenharmony_ci// Copyright 2015 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#ifndef V8_HEAP_SCAVENGER_INL_H_
61cb0ef41Sopenharmony_ci#define V8_HEAP_SCAVENGER_INL_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/heap/evacuation-allocator-inl.h"
91cb0ef41Sopenharmony_ci#include "src/heap/incremental-marking-inl.h"
101cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk.h"
111cb0ef41Sopenharmony_ci#include "src/heap/scavenger.h"
121cb0ef41Sopenharmony_ci#include "src/objects/map.h"
131cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
141cb0ef41Sopenharmony_ci#include "src/objects/slots-inl.h"
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cinamespace v8 {
171cb0ef41Sopenharmony_cinamespace internal {
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_civoid Scavenger::PromotionList::Local::PushRegularObject(HeapObject object,
201cb0ef41Sopenharmony_ci                                                        int size) {
211cb0ef41Sopenharmony_ci  regular_object_promotion_list_local_.Push({object, size});
221cb0ef41Sopenharmony_ci}
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_civoid Scavenger::PromotionList::Local::PushLargeObject(HeapObject object,
251cb0ef41Sopenharmony_ci                                                      Map map, int size) {
261cb0ef41Sopenharmony_ci  large_object_promotion_list_local_.Push({object, map, size});
271cb0ef41Sopenharmony_ci}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cisize_t Scavenger::PromotionList::Local::LocalPushSegmentSize() const {
301cb0ef41Sopenharmony_ci  return regular_object_promotion_list_local_.PushSegmentSize() +
311cb0ef41Sopenharmony_ci         large_object_promotion_list_local_.PushSegmentSize();
321cb0ef41Sopenharmony_ci}
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_cibool Scavenger::PromotionList::Local::Pop(struct PromotionListEntry* entry) {
351cb0ef41Sopenharmony_ci  ObjectAndSize regular_object;
361cb0ef41Sopenharmony_ci  if (regular_object_promotion_list_local_.Pop(&regular_object)) {
371cb0ef41Sopenharmony_ci    entry->heap_object = regular_object.first;
381cb0ef41Sopenharmony_ci    entry->size = regular_object.second;
391cb0ef41Sopenharmony_ci    entry->map = entry->heap_object.map();
401cb0ef41Sopenharmony_ci    return true;
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci  return large_object_promotion_list_local_.Pop(entry);
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_civoid Scavenger::PromotionList::Local::Publish() {
461cb0ef41Sopenharmony_ci  regular_object_promotion_list_local_.Publish();
471cb0ef41Sopenharmony_ci  large_object_promotion_list_local_.Publish();
481cb0ef41Sopenharmony_ci}
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_cibool Scavenger::PromotionList::Local::IsGlobalPoolEmpty() const {
511cb0ef41Sopenharmony_ci  return regular_object_promotion_list_local_.IsGlobalEmpty() &&
521cb0ef41Sopenharmony_ci         large_object_promotion_list_local_.IsGlobalEmpty();
531cb0ef41Sopenharmony_ci}
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cibool Scavenger::PromotionList::Local::ShouldEagerlyProcessPromotionList()
561cb0ef41Sopenharmony_ci    const {
571cb0ef41Sopenharmony_ci  // Threshold when to prioritize processing of the promotion list. Right
581cb0ef41Sopenharmony_ci  // now we only look into the regular object list.
591cb0ef41Sopenharmony_ci  const int kProcessPromotionListThreshold =
601cb0ef41Sopenharmony_ci      kRegularObjectPromotionListSegmentSize / 2;
611cb0ef41Sopenharmony_ci  return LocalPushSegmentSize() < kProcessPromotionListThreshold;
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cibool Scavenger::PromotionList::IsEmpty() const {
651cb0ef41Sopenharmony_ci  return regular_object_promotion_list_.IsEmpty() &&
661cb0ef41Sopenharmony_ci         large_object_promotion_list_.IsEmpty();
671cb0ef41Sopenharmony_ci}
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_cisize_t Scavenger::PromotionList::Size() const {
701cb0ef41Sopenharmony_ci  return regular_object_promotion_list_.Size() +
711cb0ef41Sopenharmony_ci         large_object_promotion_list_.Size();
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_civoid Scavenger::PageMemoryFence(MaybeObject object) {
751cb0ef41Sopenharmony_ci#ifdef THREAD_SANITIZER
761cb0ef41Sopenharmony_ci  // Perform a dummy acquire load to tell TSAN that there is no data race
771cb0ef41Sopenharmony_ci  // with  page initialization.
781cb0ef41Sopenharmony_ci  HeapObject heap_object;
791cb0ef41Sopenharmony_ci  if (object->GetHeapObject(&heap_object)) {
801cb0ef41Sopenharmony_ci    BasicMemoryChunk::FromHeapObject(heap_object)->SynchronizedHeapLoad();
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci#endif
831cb0ef41Sopenharmony_ci}
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_cibool Scavenger::MigrateObject(Map map, HeapObject source, HeapObject target,
861cb0ef41Sopenharmony_ci                              int size,
871cb0ef41Sopenharmony_ci                              PromotionHeapChoice promotion_heap_choice) {
881cb0ef41Sopenharmony_ci  // Copy the content of source to target.
891cb0ef41Sopenharmony_ci  target.set_map_word(MapWord::FromMap(map), kRelaxedStore);
901cb0ef41Sopenharmony_ci  heap()->CopyBlock(target.address() + kTaggedSize,
911cb0ef41Sopenharmony_ci                    source.address() + kTaggedSize, size - kTaggedSize);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  // This release CAS is paired with the load acquire in ScavengeObject.
941cb0ef41Sopenharmony_ci  if (!source.release_compare_and_swap_map_word(
951cb0ef41Sopenharmony_ci          MapWord::FromMap(map), MapWord::FromForwardingAddress(target))) {
961cb0ef41Sopenharmony_ci    // Other task migrated the object.
971cb0ef41Sopenharmony_ci    return false;
981cb0ef41Sopenharmony_ci  }
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(is_logging_)) {
1011cb0ef41Sopenharmony_ci    heap()->OnMoveEvent(target, source, size);
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  if (is_incremental_marking_ &&
1051cb0ef41Sopenharmony_ci      promotion_heap_choice != kPromoteIntoSharedHeap) {
1061cb0ef41Sopenharmony_ci    heap()->incremental_marking()->TransferColor(source, target);
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci  heap()->UpdateAllocationSite(map, source, &local_pretenuring_feedback_);
1091cb0ef41Sopenharmony_ci  return true;
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot>
1131cb0ef41Sopenharmony_ciCopyAndForwardResult Scavenger::SemiSpaceCopyObject(
1141cb0ef41Sopenharmony_ci    Map map, THeapObjectSlot slot, HeapObject object, int object_size,
1151cb0ef41Sopenharmony_ci    ObjectFields object_fields) {
1161cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
1171cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
1181cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
1191cb0ef41Sopenharmony_ci  DCHECK(heap()->AllowedToBeMigrated(map, object, NEW_SPACE));
1201cb0ef41Sopenharmony_ci  AllocationAlignment alignment = HeapObject::RequiredAlignment(map);
1211cb0ef41Sopenharmony_ci  AllocationResult allocation = allocator_.Allocate(
1221cb0ef41Sopenharmony_ci      NEW_SPACE, object_size, AllocationOrigin::kGC, alignment);
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  HeapObject target;
1251cb0ef41Sopenharmony_ci  if (allocation.To(&target)) {
1261cb0ef41Sopenharmony_ci    DCHECK(heap()->incremental_marking()->non_atomic_marking_state()->IsWhite(
1271cb0ef41Sopenharmony_ci        target));
1281cb0ef41Sopenharmony_ci    const bool self_success =
1291cb0ef41Sopenharmony_ci        MigrateObject(map, object, target, object_size, kPromoteIntoLocalHeap);
1301cb0ef41Sopenharmony_ci    if (!self_success) {
1311cb0ef41Sopenharmony_ci      allocator_.FreeLast(NEW_SPACE, target, object_size);
1321cb0ef41Sopenharmony_ci      MapWord map_word = object.map_word(kAcquireLoad);
1331cb0ef41Sopenharmony_ci      HeapObjectReference::Update(slot, map_word.ToForwardingAddress());
1341cb0ef41Sopenharmony_ci      DCHECK(!Heap::InFromPage(*slot));
1351cb0ef41Sopenharmony_ci      return Heap::InToPage(*slot)
1361cb0ef41Sopenharmony_ci                 ? CopyAndForwardResult::SUCCESS_YOUNG_GENERATION
1371cb0ef41Sopenharmony_ci                 : CopyAndForwardResult::SUCCESS_OLD_GENERATION;
1381cb0ef41Sopenharmony_ci    }
1391cb0ef41Sopenharmony_ci    HeapObjectReference::Update(slot, target);
1401cb0ef41Sopenharmony_ci    if (object_fields == ObjectFields::kMaybePointers) {
1411cb0ef41Sopenharmony_ci      copied_list_local_.Push(ObjectAndSize(target, object_size));
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci    copied_size_ += object_size;
1441cb0ef41Sopenharmony_ci    return CopyAndForwardResult::SUCCESS_YOUNG_GENERATION;
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci  return CopyAndForwardResult::FAILURE;
1471cb0ef41Sopenharmony_ci}
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot,
1501cb0ef41Sopenharmony_ci          Scavenger::PromotionHeapChoice promotion_heap_choice>
1511cb0ef41Sopenharmony_ciCopyAndForwardResult Scavenger::PromoteObject(Map map, THeapObjectSlot slot,
1521cb0ef41Sopenharmony_ci                                              HeapObject object,
1531cb0ef41Sopenharmony_ci                                              int object_size,
1541cb0ef41Sopenharmony_ci                                              ObjectFields object_fields) {
1551cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
1561cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
1571cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
1581cb0ef41Sopenharmony_ci  DCHECK_GE(object_size, Heap::kMinObjectSizeInTaggedWords * kTaggedSize);
1591cb0ef41Sopenharmony_ci  AllocationAlignment alignment = HeapObject::RequiredAlignment(map);
1601cb0ef41Sopenharmony_ci  AllocationResult allocation;
1611cb0ef41Sopenharmony_ci  switch (promotion_heap_choice) {
1621cb0ef41Sopenharmony_ci    case kPromoteIntoLocalHeap:
1631cb0ef41Sopenharmony_ci      allocation = allocator_.Allocate(OLD_SPACE, object_size,
1641cb0ef41Sopenharmony_ci                                       AllocationOrigin::kGC, alignment);
1651cb0ef41Sopenharmony_ci      break;
1661cb0ef41Sopenharmony_ci    case kPromoteIntoSharedHeap:
1671cb0ef41Sopenharmony_ci      DCHECK_NOT_NULL(shared_old_allocator_);
1681cb0ef41Sopenharmony_ci      allocation = shared_old_allocator_->AllocateRaw(object_size, alignment,
1691cb0ef41Sopenharmony_ci                                                      AllocationOrigin::kGC);
1701cb0ef41Sopenharmony_ci      break;
1711cb0ef41Sopenharmony_ci  }
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  HeapObject target;
1741cb0ef41Sopenharmony_ci  if (allocation.To(&target)) {
1751cb0ef41Sopenharmony_ci    DCHECK(heap()->incremental_marking()->non_atomic_marking_state()->IsWhite(
1761cb0ef41Sopenharmony_ci        target));
1771cb0ef41Sopenharmony_ci    const bool self_success =
1781cb0ef41Sopenharmony_ci        MigrateObject(map, object, target, object_size, promotion_heap_choice);
1791cb0ef41Sopenharmony_ci    if (!self_success) {
1801cb0ef41Sopenharmony_ci      allocator_.FreeLast(OLD_SPACE, target, object_size);
1811cb0ef41Sopenharmony_ci      MapWord map_word = object.map_word(kAcquireLoad);
1821cb0ef41Sopenharmony_ci      HeapObjectReference::Update(slot, map_word.ToForwardingAddress());
1831cb0ef41Sopenharmony_ci      DCHECK(!Heap::InFromPage(*slot));
1841cb0ef41Sopenharmony_ci      return Heap::InToPage(*slot)
1851cb0ef41Sopenharmony_ci                 ? CopyAndForwardResult::SUCCESS_YOUNG_GENERATION
1861cb0ef41Sopenharmony_ci                 : CopyAndForwardResult::SUCCESS_OLD_GENERATION;
1871cb0ef41Sopenharmony_ci    }
1881cb0ef41Sopenharmony_ci    HeapObjectReference::Update(slot, target);
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci    // During incremental marking we want to push every object in order to
1911cb0ef41Sopenharmony_ci    // record slots for map words. Necessary for map space compaction.
1921cb0ef41Sopenharmony_ci    if (object_fields == ObjectFields::kMaybePointers ||
1931cb0ef41Sopenharmony_ci        is_compacting_including_map_space_) {
1941cb0ef41Sopenharmony_ci      promotion_list_local_.PushRegularObject(target, object_size);
1951cb0ef41Sopenharmony_ci    }
1961cb0ef41Sopenharmony_ci    promoted_size_ += object_size;
1971cb0ef41Sopenharmony_ci    return CopyAndForwardResult::SUCCESS_OLD_GENERATION;
1981cb0ef41Sopenharmony_ci  }
1991cb0ef41Sopenharmony_ci  return CopyAndForwardResult::FAILURE;
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::RememberedSetEntryNeeded(
2031cb0ef41Sopenharmony_ci    CopyAndForwardResult result) {
2041cb0ef41Sopenharmony_ci  DCHECK_NE(CopyAndForwardResult::FAILURE, result);
2051cb0ef41Sopenharmony_ci  return result == CopyAndForwardResult::SUCCESS_YOUNG_GENERATION ? KEEP_SLOT
2061cb0ef41Sopenharmony_ci                                                                  : REMOVE_SLOT;
2071cb0ef41Sopenharmony_ci}
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_cibool Scavenger::HandleLargeObject(Map map, HeapObject object, int object_size,
2101cb0ef41Sopenharmony_ci                                  ObjectFields object_fields) {
2111cb0ef41Sopenharmony_ci  // TODO(hpayer): Make this check size based, i.e.
2121cb0ef41Sopenharmony_ci  // object_size > kMaxRegularHeapObjectSize
2131cb0ef41Sopenharmony_ci  if (V8_UNLIKELY(
2141cb0ef41Sopenharmony_ci          BasicMemoryChunk::FromHeapObject(object)->InNewLargeObjectSpace())) {
2151cb0ef41Sopenharmony_ci    DCHECK_EQ(NEW_LO_SPACE,
2161cb0ef41Sopenharmony_ci              MemoryChunk::FromHeapObject(object)->owner_identity());
2171cb0ef41Sopenharmony_ci    if (object.release_compare_and_swap_map_word(
2181cb0ef41Sopenharmony_ci            MapWord::FromMap(map), MapWord::FromForwardingAddress(object))) {
2191cb0ef41Sopenharmony_ci      surviving_new_large_objects_.insert({object, map});
2201cb0ef41Sopenharmony_ci      promoted_size_ += object_size;
2211cb0ef41Sopenharmony_ci      if (object_fields == ObjectFields::kMaybePointers) {
2221cb0ef41Sopenharmony_ci        promotion_list_local_.PushLargeObject(object, map, object_size);
2231cb0ef41Sopenharmony_ci      }
2241cb0ef41Sopenharmony_ci    }
2251cb0ef41Sopenharmony_ci    return true;
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci  return false;
2281cb0ef41Sopenharmony_ci}
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot,
2311cb0ef41Sopenharmony_ci          Scavenger::PromotionHeapChoice promotion_heap_choice>
2321cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::EvacuateObjectDefault(
2331cb0ef41Sopenharmony_ci    Map map, THeapObjectSlot slot, HeapObject object, int object_size,
2341cb0ef41Sopenharmony_ci    ObjectFields object_fields) {
2351cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
2361cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
2371cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
2381cb0ef41Sopenharmony_ci  SLOW_DCHECK(object.SizeFromMap(map) == object_size);
2391cb0ef41Sopenharmony_ci  CopyAndForwardResult result;
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci  if (HandleLargeObject(map, object, object_size, object_fields)) {
2421cb0ef41Sopenharmony_ci    return KEEP_SLOT;
2431cb0ef41Sopenharmony_ci  }
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  SLOW_DCHECK(static_cast<size_t>(object_size) <=
2461cb0ef41Sopenharmony_ci              MemoryChunkLayout::AllocatableMemoryInDataPage());
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  if (!heap()->ShouldBePromoted(object.address())) {
2491cb0ef41Sopenharmony_ci    // A semi-space copy may fail due to fragmentation. In that case, we
2501cb0ef41Sopenharmony_ci    // try to promote the object.
2511cb0ef41Sopenharmony_ci    result = SemiSpaceCopyObject(map, slot, object, object_size, object_fields);
2521cb0ef41Sopenharmony_ci    if (result != CopyAndForwardResult::FAILURE) {
2531cb0ef41Sopenharmony_ci      return RememberedSetEntryNeeded(result);
2541cb0ef41Sopenharmony_ci    }
2551cb0ef41Sopenharmony_ci  }
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci  // We may want to promote this object if the object was already semi-space
2581cb0ef41Sopenharmony_ci  // copied in a previous young generation GC or if the semi-space copy above
2591cb0ef41Sopenharmony_ci  // failed.
2601cb0ef41Sopenharmony_ci  result = PromoteObject<THeapObjectSlot, promotion_heap_choice>(
2611cb0ef41Sopenharmony_ci      map, slot, object, object_size, object_fields);
2621cb0ef41Sopenharmony_ci  if (result != CopyAndForwardResult::FAILURE) {
2631cb0ef41Sopenharmony_ci    return RememberedSetEntryNeeded(result);
2641cb0ef41Sopenharmony_ci  }
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci  // If promotion failed, we try to copy the object to the other semi-space.
2671cb0ef41Sopenharmony_ci  result = SemiSpaceCopyObject(map, slot, object, object_size, object_fields);
2681cb0ef41Sopenharmony_ci  if (result != CopyAndForwardResult::FAILURE) {
2691cb0ef41Sopenharmony_ci    return RememberedSetEntryNeeded(result);
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  heap()->FatalProcessOutOfMemory("Scavenger: semi-space copy");
2731cb0ef41Sopenharmony_ci  UNREACHABLE();
2741cb0ef41Sopenharmony_ci}
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot>
2771cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::EvacuateThinString(Map map, THeapObjectSlot slot,
2781cb0ef41Sopenharmony_ci                                                 ThinString object,
2791cb0ef41Sopenharmony_ci                                                 int object_size) {
2801cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
2811cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
2821cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
2831cb0ef41Sopenharmony_ci  if (!is_incremental_marking_) {
2841cb0ef41Sopenharmony_ci    // The ThinString should die after Scavenge, so avoid writing the proper
2851cb0ef41Sopenharmony_ci    // forwarding pointer and instead just signal the actual object as forwarded
2861cb0ef41Sopenharmony_ci    // reference.
2871cb0ef41Sopenharmony_ci    String actual = object.actual();
2881cb0ef41Sopenharmony_ci    // ThinStrings always refer to internalized strings, which are always in old
2891cb0ef41Sopenharmony_ci    // space.
2901cb0ef41Sopenharmony_ci    DCHECK(!Heap::InYoungGeneration(actual));
2911cb0ef41Sopenharmony_ci    HeapObjectReference::Update(slot, actual);
2921cb0ef41Sopenharmony_ci    return REMOVE_SLOT;
2931cb0ef41Sopenharmony_ci  }
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci  DCHECK_EQ(ObjectFields::kMaybePointers,
2961cb0ef41Sopenharmony_ci            Map::ObjectFieldsFrom(map.visitor_id()));
2971cb0ef41Sopenharmony_ci  return EvacuateObjectDefault(map, slot, object, object_size,
2981cb0ef41Sopenharmony_ci                               ObjectFields::kMaybePointers);
2991cb0ef41Sopenharmony_ci}
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot>
3021cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::EvacuateShortcutCandidate(Map map,
3031cb0ef41Sopenharmony_ci                                                        THeapObjectSlot slot,
3041cb0ef41Sopenharmony_ci                                                        ConsString object,
3051cb0ef41Sopenharmony_ci                                                        int object_size) {
3061cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
3071cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
3081cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
3091cb0ef41Sopenharmony_ci  DCHECK(IsShortcutCandidate(map.instance_type()));
3101cb0ef41Sopenharmony_ci  if (!is_incremental_marking_ &&
3111cb0ef41Sopenharmony_ci      object.unchecked_second() == ReadOnlyRoots(heap()).empty_string()) {
3121cb0ef41Sopenharmony_ci    HeapObject first = HeapObject::cast(object.unchecked_first());
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci    HeapObjectReference::Update(slot, first);
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_ci    if (!Heap::InYoungGeneration(first)) {
3171cb0ef41Sopenharmony_ci      object.set_map_word(MapWord::FromForwardingAddress(first), kReleaseStore);
3181cb0ef41Sopenharmony_ci      return REMOVE_SLOT;
3191cb0ef41Sopenharmony_ci    }
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci    MapWord first_word = first.map_word(kAcquireLoad);
3221cb0ef41Sopenharmony_ci    if (first_word.IsForwardingAddress()) {
3231cb0ef41Sopenharmony_ci      HeapObject target = first_word.ToForwardingAddress();
3241cb0ef41Sopenharmony_ci
3251cb0ef41Sopenharmony_ci      HeapObjectReference::Update(slot, target);
3261cb0ef41Sopenharmony_ci      object.set_map_word(MapWord::FromForwardingAddress(target),
3271cb0ef41Sopenharmony_ci                          kReleaseStore);
3281cb0ef41Sopenharmony_ci      return Heap::InYoungGeneration(target) ? KEEP_SLOT : REMOVE_SLOT;
3291cb0ef41Sopenharmony_ci    }
3301cb0ef41Sopenharmony_ci    Map first_map = first_word.ToMap();
3311cb0ef41Sopenharmony_ci    SlotCallbackResult result = EvacuateObjectDefault(
3321cb0ef41Sopenharmony_ci        first_map, slot, first, first.SizeFromMap(first_map),
3331cb0ef41Sopenharmony_ci        Map::ObjectFieldsFrom(first_map.visitor_id()));
3341cb0ef41Sopenharmony_ci    object.set_map_word(MapWord::FromForwardingAddress(slot.ToHeapObject()),
3351cb0ef41Sopenharmony_ci                        kReleaseStore);
3361cb0ef41Sopenharmony_ci    return result;
3371cb0ef41Sopenharmony_ci  }
3381cb0ef41Sopenharmony_ci  DCHECK_EQ(ObjectFields::kMaybePointers,
3391cb0ef41Sopenharmony_ci            Map::ObjectFieldsFrom(map.visitor_id()));
3401cb0ef41Sopenharmony_ci  return EvacuateObjectDefault(map, slot, object, object_size,
3411cb0ef41Sopenharmony_ci                               ObjectFields::kMaybePointers);
3421cb0ef41Sopenharmony_ci}
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot>
3451cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::EvacuateInPlaceInternalizableString(
3461cb0ef41Sopenharmony_ci    Map map, THeapObjectSlot slot, String object, int object_size,
3471cb0ef41Sopenharmony_ci    ObjectFields object_fields) {
3481cb0ef41Sopenharmony_ci  DCHECK(String::IsInPlaceInternalizable(map.instance_type()));
3491cb0ef41Sopenharmony_ci  DCHECK_EQ(object_fields, Map::ObjectFieldsFrom(map.visitor_id()));
3501cb0ef41Sopenharmony_ci  if (shared_string_table_) {
3511cb0ef41Sopenharmony_ci    return EvacuateObjectDefault<THeapObjectSlot, kPromoteIntoSharedHeap>(
3521cb0ef41Sopenharmony_ci        map, slot, object, object_size, object_fields);
3531cb0ef41Sopenharmony_ci  }
3541cb0ef41Sopenharmony_ci  return EvacuateObjectDefault(map, slot, object, object_size, object_fields);
3551cb0ef41Sopenharmony_ci}
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot>
3581cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::EvacuateObject(THeapObjectSlot slot, Map map,
3591cb0ef41Sopenharmony_ci                                             HeapObject source) {
3601cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
3611cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
3621cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
3631cb0ef41Sopenharmony_ci  SLOW_DCHECK(Heap::InFromPage(source));
3641cb0ef41Sopenharmony_ci  SLOW_DCHECK(!MapWord::FromMap(map).IsForwardingAddress());
3651cb0ef41Sopenharmony_ci  int size = source.SizeFromMap(map);
3661cb0ef41Sopenharmony_ci  // Cannot use ::cast() below because that would add checks in debug mode
3671cb0ef41Sopenharmony_ci  // that require re-reading the map.
3681cb0ef41Sopenharmony_ci  VisitorId visitor_id = map.visitor_id();
3691cb0ef41Sopenharmony_ci  switch (visitor_id) {
3701cb0ef41Sopenharmony_ci    case kVisitThinString:
3711cb0ef41Sopenharmony_ci      // At the moment we don't allow weak pointers to thin strings.
3721cb0ef41Sopenharmony_ci      DCHECK(!(*slot)->IsWeak());
3731cb0ef41Sopenharmony_ci      return EvacuateThinString(map, slot, ThinString::unchecked_cast(source),
3741cb0ef41Sopenharmony_ci                                size);
3751cb0ef41Sopenharmony_ci    case kVisitShortcutCandidate:
3761cb0ef41Sopenharmony_ci      DCHECK(!(*slot)->IsWeak());
3771cb0ef41Sopenharmony_ci      // At the moment we don't allow weak pointers to cons strings.
3781cb0ef41Sopenharmony_ci      return EvacuateShortcutCandidate(
3791cb0ef41Sopenharmony_ci          map, slot, ConsString::unchecked_cast(source), size);
3801cb0ef41Sopenharmony_ci    case kVisitSeqOneByteString:
3811cb0ef41Sopenharmony_ci    case kVisitSeqTwoByteString:
3821cb0ef41Sopenharmony_ci      DCHECK(String::IsInPlaceInternalizable(map.instance_type()));
3831cb0ef41Sopenharmony_ci      return EvacuateInPlaceInternalizableString(
3841cb0ef41Sopenharmony_ci          map, slot, String::unchecked_cast(source), size,
3851cb0ef41Sopenharmony_ci          ObjectFields::kMaybePointers);
3861cb0ef41Sopenharmony_ci    case kVisitDataObject:  // External strings have kVisitDataObject.
3871cb0ef41Sopenharmony_ci      if (String::IsInPlaceInternalizableExcludingExternal(
3881cb0ef41Sopenharmony_ci              map.instance_type())) {
3891cb0ef41Sopenharmony_ci        return EvacuateInPlaceInternalizableString(
3901cb0ef41Sopenharmony_ci            map, slot, String::unchecked_cast(source), size,
3911cb0ef41Sopenharmony_ci            ObjectFields::kDataOnly);
3921cb0ef41Sopenharmony_ci      }
3931cb0ef41Sopenharmony_ci      V8_FALLTHROUGH;
3941cb0ef41Sopenharmony_ci    default:
3951cb0ef41Sopenharmony_ci      return EvacuateObjectDefault(map, slot, source, size,
3961cb0ef41Sopenharmony_ci                                   Map::ObjectFieldsFrom(visitor_id));
3971cb0ef41Sopenharmony_ci  }
3981cb0ef41Sopenharmony_ci}
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_citemplate <typename THeapObjectSlot>
4011cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::ScavengeObject(THeapObjectSlot p,
4021cb0ef41Sopenharmony_ci                                             HeapObject object) {
4031cb0ef41Sopenharmony_ci  static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
4041cb0ef41Sopenharmony_ci                    std::is_same<THeapObjectSlot, HeapObjectSlot>::value,
4051cb0ef41Sopenharmony_ci                "Only FullHeapObjectSlot and HeapObjectSlot are expected here");
4061cb0ef41Sopenharmony_ci  DCHECK(Heap::InFromPage(object));
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  // Synchronized load that consumes the publishing CAS of MigrateObject. We
4091cb0ef41Sopenharmony_ci  // need memory ordering in order to read the page header of the forwarded
4101cb0ef41Sopenharmony_ci  // object (using Heap::InYoungGeneration).
4111cb0ef41Sopenharmony_ci  MapWord first_word = object.map_word(kAcquireLoad);
4121cb0ef41Sopenharmony_ci
4131cb0ef41Sopenharmony_ci  // If the first word is a forwarding address, the object has already been
4141cb0ef41Sopenharmony_ci  // copied.
4151cb0ef41Sopenharmony_ci  if (first_word.IsForwardingAddress()) {
4161cb0ef41Sopenharmony_ci    HeapObject dest = first_word.ToForwardingAddress();
4171cb0ef41Sopenharmony_ci    HeapObjectReference::Update(p, dest);
4181cb0ef41Sopenharmony_ci    DCHECK_IMPLIES(Heap::InYoungGeneration(dest),
4191cb0ef41Sopenharmony_ci                   Heap::InToPage(dest) || Heap::IsLargeObject(dest));
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci    // This load forces us to have memory ordering for the map load above. We
4221cb0ef41Sopenharmony_ci    // need to have the page header properly initialized.
4231cb0ef41Sopenharmony_ci    return Heap::InYoungGeneration(dest) ? KEEP_SLOT : REMOVE_SLOT;
4241cb0ef41Sopenharmony_ci  }
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci  Map map = first_word.ToMap();
4271cb0ef41Sopenharmony_ci  // AllocationMementos are unrooted and shouldn't survive a scavenge
4281cb0ef41Sopenharmony_ci  DCHECK_NE(ReadOnlyRoots(heap()).allocation_memento_map(), map);
4291cb0ef41Sopenharmony_ci  // Call the slow part of scavenge object.
4301cb0ef41Sopenharmony_ci  return EvacuateObject(p, map, object);
4311cb0ef41Sopenharmony_ci}
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_citemplate <typename TSlot>
4341cb0ef41Sopenharmony_ciSlotCallbackResult Scavenger::CheckAndScavengeObject(Heap* heap, TSlot slot) {
4351cb0ef41Sopenharmony_ci  static_assert(
4361cb0ef41Sopenharmony_ci      std::is_same<TSlot, FullMaybeObjectSlot>::value ||
4371cb0ef41Sopenharmony_ci          std::is_same<TSlot, MaybeObjectSlot>::value,
4381cb0ef41Sopenharmony_ci      "Only FullMaybeObjectSlot and MaybeObjectSlot are expected here");
4391cb0ef41Sopenharmony_ci  using THeapObjectSlot = typename TSlot::THeapObjectSlot;
4401cb0ef41Sopenharmony_ci  MaybeObject object = *slot;
4411cb0ef41Sopenharmony_ci  if (Heap::InFromPage(object)) {
4421cb0ef41Sopenharmony_ci    HeapObject heap_object = object->GetHeapObject();
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci    SlotCallbackResult result =
4451cb0ef41Sopenharmony_ci        ScavengeObject(THeapObjectSlot(slot), heap_object);
4461cb0ef41Sopenharmony_ci    DCHECK_IMPLIES(result == REMOVE_SLOT,
4471cb0ef41Sopenharmony_ci                   !heap->InYoungGeneration((*slot)->GetHeapObject()));
4481cb0ef41Sopenharmony_ci    return result;
4491cb0ef41Sopenharmony_ci  } else if (Heap::InToPage(object)) {
4501cb0ef41Sopenharmony_ci    // Already updated slot. This can happen when processing of the work list
4511cb0ef41Sopenharmony_ci    // is interleaved with processing roots.
4521cb0ef41Sopenharmony_ci    return KEEP_SLOT;
4531cb0ef41Sopenharmony_ci  }
4541cb0ef41Sopenharmony_ci  // Slots can point to "to" space if the slot has been recorded multiple
4551cb0ef41Sopenharmony_ci  // times in the remembered set. We remove the redundant slot now.
4561cb0ef41Sopenharmony_ci  return REMOVE_SLOT;
4571cb0ef41Sopenharmony_ci}
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitPointers(HeapObject host, ObjectSlot start,
4601cb0ef41Sopenharmony_ci                                    ObjectSlot end) {
4611cb0ef41Sopenharmony_ci  return VisitPointersImpl(host, start, end);
4621cb0ef41Sopenharmony_ci}
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitPointers(HeapObject host, MaybeObjectSlot start,
4651cb0ef41Sopenharmony_ci                                    MaybeObjectSlot end) {
4661cb0ef41Sopenharmony_ci  return VisitPointersImpl(host, start, end);
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitCodePointer(HeapObject host, CodeObjectSlot slot) {
4701cb0ef41Sopenharmony_ci  CHECK(V8_EXTERNAL_CODE_SPACE_BOOL);
4711cb0ef41Sopenharmony_ci  // Code slots never appear in new space because CodeDataContainers, the
4721cb0ef41Sopenharmony_ci  // only object that can contain code pointers, are always allocated in
4731cb0ef41Sopenharmony_ci  // the old space.
4741cb0ef41Sopenharmony_ci  UNREACHABLE();
4751cb0ef41Sopenharmony_ci}
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitCodeTarget(Code host, RelocInfo* rinfo) {
4781cb0ef41Sopenharmony_ci  Code target = Code::GetCodeFromTargetAddress(rinfo->target_address());
4791cb0ef41Sopenharmony_ci#ifdef DEBUG
4801cb0ef41Sopenharmony_ci  Code old_target = target;
4811cb0ef41Sopenharmony_ci#endif
4821cb0ef41Sopenharmony_ci  FullObjectSlot slot(&target);
4831cb0ef41Sopenharmony_ci  VisitHeapObjectImpl(slot, target);
4841cb0ef41Sopenharmony_ci  // Code objects are never in new-space, so the slot contents must not change.
4851cb0ef41Sopenharmony_ci  DCHECK_EQ(old_target, target);
4861cb0ef41Sopenharmony_ci}
4871cb0ef41Sopenharmony_ci
4881cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitEmbeddedPointer(Code host, RelocInfo* rinfo) {
4891cb0ef41Sopenharmony_ci  HeapObject heap_object = rinfo->target_object(cage_base());
4901cb0ef41Sopenharmony_ci#ifdef DEBUG
4911cb0ef41Sopenharmony_ci  HeapObject old_heap_object = heap_object;
4921cb0ef41Sopenharmony_ci#endif
4931cb0ef41Sopenharmony_ci  FullObjectSlot slot(&heap_object);
4941cb0ef41Sopenharmony_ci  VisitHeapObjectImpl(slot, heap_object);
4951cb0ef41Sopenharmony_ci  // We don't embed new-space objects into code, so the slot contents must not
4961cb0ef41Sopenharmony_ci  // change.
4971cb0ef41Sopenharmony_ci  DCHECK_EQ(old_heap_object, heap_object);
4981cb0ef41Sopenharmony_ci}
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_citemplate <typename TSlot>
5011cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitHeapObjectImpl(TSlot slot, HeapObject heap_object) {
5021cb0ef41Sopenharmony_ci  if (Heap::InYoungGeneration(heap_object)) {
5031cb0ef41Sopenharmony_ci    using THeapObjectSlot = typename TSlot::THeapObjectSlot;
5041cb0ef41Sopenharmony_ci    scavenger_->ScavengeObject(THeapObjectSlot(slot), heap_object);
5051cb0ef41Sopenharmony_ci  }
5061cb0ef41Sopenharmony_ci}
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_citemplate <typename TSlot>
5091cb0ef41Sopenharmony_civoid ScavengeVisitor::VisitPointersImpl(HeapObject host, TSlot start,
5101cb0ef41Sopenharmony_ci                                        TSlot end) {
5111cb0ef41Sopenharmony_ci  for (TSlot slot = start; slot < end; ++slot) {
5121cb0ef41Sopenharmony_ci    typename TSlot::TObject object = *slot;
5131cb0ef41Sopenharmony_ci    HeapObject heap_object;
5141cb0ef41Sopenharmony_ci    // Treat weak references as strong.
5151cb0ef41Sopenharmony_ci    if (object.GetHeapObject(&heap_object)) {
5161cb0ef41Sopenharmony_ci      VisitHeapObjectImpl(slot, heap_object);
5171cb0ef41Sopenharmony_ci    }
5181cb0ef41Sopenharmony_ci  }
5191cb0ef41Sopenharmony_ci}
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ciint ScavengeVisitor::VisitJSArrayBuffer(Map map, JSArrayBuffer object) {
5221cb0ef41Sopenharmony_ci  object.YoungMarkExtension();
5231cb0ef41Sopenharmony_ci  int size = JSArrayBuffer::BodyDescriptor::SizeOf(map, object);
5241cb0ef41Sopenharmony_ci  JSArrayBuffer::BodyDescriptor::IterateBody(map, object, size, this);
5251cb0ef41Sopenharmony_ci  return size;
5261cb0ef41Sopenharmony_ci}
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ciint ScavengeVisitor::VisitEphemeronHashTable(Map map,
5291cb0ef41Sopenharmony_ci                                             EphemeronHashTable table) {
5301cb0ef41Sopenharmony_ci  // Register table with the scavenger, so it can take care of the weak keys
5311cb0ef41Sopenharmony_ci  // later. This allows to only iterate the tables' values, which are treated
5321cb0ef41Sopenharmony_ci  // as strong independetly of whether the key is live.
5331cb0ef41Sopenharmony_ci  scavenger_->AddEphemeronHashTable(table);
5341cb0ef41Sopenharmony_ci  for (InternalIndex i : table.IterateEntries()) {
5351cb0ef41Sopenharmony_ci    ObjectSlot value_slot =
5361cb0ef41Sopenharmony_ci        table.RawFieldOfElementAt(EphemeronHashTable::EntryToValueIndex(i));
5371cb0ef41Sopenharmony_ci    VisitPointer(table, value_slot);
5381cb0ef41Sopenharmony_ci  }
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ci  return table.SizeFromMap(map);
5411cb0ef41Sopenharmony_ci}
5421cb0ef41Sopenharmony_ci
5431cb0ef41Sopenharmony_ci}  // namespace internal
5441cb0ef41Sopenharmony_ci}  // namespace v8
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ci#endif  // V8_HEAP_SCAVENGER_INL_H_
547