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(®ular_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