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/cppgc/write-barrier.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "include/cppgc/heap-consistency.h" 81cb0ef41Sopenharmony_ci#include "include/cppgc/internal/pointer-policies.h" 91cb0ef41Sopenharmony_ci#include "src/heap/cppgc/globals.h" 101cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-object-header.h" 111cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-page.h" 121cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap.h" 131cb0ef41Sopenharmony_ci#include "src/heap/cppgc/marker.h" 141cb0ef41Sopenharmony_ci#include "src/heap/cppgc/marking-visitor.h" 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP) 171cb0ef41Sopenharmony_ci#include "include/cppgc/internal/caged-heap-local-data.h" 181cb0ef41Sopenharmony_ci#endif 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_cinamespace cppgc { 211cb0ef41Sopenharmony_cinamespace internal { 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci// static 241cb0ef41Sopenharmony_ciAtomicEntryFlag WriteBarrier::incremental_or_concurrent_marking_flag_; 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_cinamespace { 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_citemplate <MarkerBase::WriteBarrierType type> 291cb0ef41Sopenharmony_civoid ProcessMarkValue(HeapObjectHeader& header, MarkerBase* marker, 301cb0ef41Sopenharmony_ci const void* value) { 311cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP) 321cb0ef41Sopenharmony_ci DCHECK(reinterpret_cast<CagedHeapLocalData*>( 331cb0ef41Sopenharmony_ci reinterpret_cast<uintptr_t>(value) & 341cb0ef41Sopenharmony_ci ~(kCagedHeapReservationAlignment - 1)) 351cb0ef41Sopenharmony_ci ->is_incremental_marking_in_progress); 361cb0ef41Sopenharmony_ci#endif 371cb0ef41Sopenharmony_ci DCHECK(header.IsMarked<AccessMode::kAtomic>()); 381cb0ef41Sopenharmony_ci DCHECK(marker); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci if (V8_UNLIKELY(header.IsInConstruction<AccessMode::kNonAtomic>())) { 411cb0ef41Sopenharmony_ci // In construction objects are traced only if they are unmarked. If marking 421cb0ef41Sopenharmony_ci // reaches this object again when it is fully constructed, it will re-mark 431cb0ef41Sopenharmony_ci // it and tracing it as a previously not fully constructed object would know 441cb0ef41Sopenharmony_ci // to bail out. 451cb0ef41Sopenharmony_ci header.Unmark<AccessMode::kAtomic>(); 461cb0ef41Sopenharmony_ci marker->WriteBarrierForInConstructionObject(header); 471cb0ef41Sopenharmony_ci return; 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci marker->WriteBarrierForObject<type>(header); 511cb0ef41Sopenharmony_ci} 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci} // namespace 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci// static 561cb0ef41Sopenharmony_civoid WriteBarrier::DijkstraMarkingBarrierSlowWithSentinelCheck( 571cb0ef41Sopenharmony_ci const void* value) { 581cb0ef41Sopenharmony_ci if (!value || value == kSentinelPointer) return; 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci DijkstraMarkingBarrierSlow(value); 611cb0ef41Sopenharmony_ci} 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci// static 641cb0ef41Sopenharmony_civoid WriteBarrier::DijkstraMarkingBarrierSlow(const void* value) { 651cb0ef41Sopenharmony_ci const BasePage* page = BasePage::FromPayload(value); 661cb0ef41Sopenharmony_ci const auto& heap = page->heap(); 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci // GetWriteBarrierType() checks marking state. 691cb0ef41Sopenharmony_ci DCHECK(heap.marker()); 701cb0ef41Sopenharmony_ci // No write barriers should be executed from atomic pause marking. 711cb0ef41Sopenharmony_ci DCHECK(!heap.in_atomic_pause()); 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci auto& header = 741cb0ef41Sopenharmony_ci const_cast<HeapObjectHeader&>(page->ObjectHeaderFromInnerAddress(value)); 751cb0ef41Sopenharmony_ci if (!header.TryMarkAtomic()) return; 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci ProcessMarkValue<MarkerBase::WriteBarrierType::kDijkstra>( 781cb0ef41Sopenharmony_ci header, heap.marker(), value); 791cb0ef41Sopenharmony_ci} 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci// static 821cb0ef41Sopenharmony_civoid WriteBarrier::DijkstraMarkingBarrierRangeSlow( 831cb0ef41Sopenharmony_ci HeapHandle& heap_handle, const void* first_element, size_t element_size, 841cb0ef41Sopenharmony_ci size_t number_of_elements, TraceCallback trace_callback) { 851cb0ef41Sopenharmony_ci auto& heap_base = HeapBase::From(heap_handle); 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci // GetWriteBarrierType() checks marking state. 881cb0ef41Sopenharmony_ci DCHECK(heap_base.marker()); 891cb0ef41Sopenharmony_ci // No write barriers should be executed from atomic pause marking. 901cb0ef41Sopenharmony_ci DCHECK(!heap_base.in_atomic_pause()); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_scope(heap_base); 931cb0ef41Sopenharmony_ci const char* array = static_cast<const char*>(first_element); 941cb0ef41Sopenharmony_ci while (number_of_elements-- > 0) { 951cb0ef41Sopenharmony_ci trace_callback(&heap_base.marker()->Visitor(), array); 961cb0ef41Sopenharmony_ci array += element_size; 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci} 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci// static 1011cb0ef41Sopenharmony_civoid WriteBarrier::SteeleMarkingBarrierSlowWithSentinelCheck( 1021cb0ef41Sopenharmony_ci const void* value) { 1031cb0ef41Sopenharmony_ci if (!value || value == kSentinelPointer) return; 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci SteeleMarkingBarrierSlow(value); 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci// static 1091cb0ef41Sopenharmony_civoid WriteBarrier::SteeleMarkingBarrierSlow(const void* value) { 1101cb0ef41Sopenharmony_ci const BasePage* page = BasePage::FromPayload(value); 1111cb0ef41Sopenharmony_ci const auto& heap = page->heap(); 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci // GetWriteBarrierType() checks marking state. 1141cb0ef41Sopenharmony_ci DCHECK(heap.marker()); 1151cb0ef41Sopenharmony_ci // No write barriers should be executed from atomic pause marking. 1161cb0ef41Sopenharmony_ci DCHECK(!heap.in_atomic_pause()); 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci auto& header = 1191cb0ef41Sopenharmony_ci const_cast<HeapObjectHeader&>(page->ObjectHeaderFromInnerAddress(value)); 1201cb0ef41Sopenharmony_ci if (!header.IsMarked<AccessMode::kAtomic>()) return; 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci ProcessMarkValue<MarkerBase::WriteBarrierType::kSteele>(header, heap.marker(), 1231cb0ef41Sopenharmony_ci value); 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION) 1271cb0ef41Sopenharmony_ci// static 1281cb0ef41Sopenharmony_civoid WriteBarrier::GenerationalBarrierSlow(const CagedHeapLocalData& local_data, 1291cb0ef41Sopenharmony_ci const AgeTable& age_table, 1301cb0ef41Sopenharmony_ci const void* slot, 1311cb0ef41Sopenharmony_ci uintptr_t value_offset) { 1321cb0ef41Sopenharmony_ci DCHECK(slot); 1331cb0ef41Sopenharmony_ci // A write during atomic pause (e.g. pre-finalizer) may trigger the slow path 1341cb0ef41Sopenharmony_ci // of the barrier. This is a result of the order of bailouts where not marking 1351cb0ef41Sopenharmony_ci // results in applying the generational barrier. 1361cb0ef41Sopenharmony_ci if (local_data.heap_base.in_atomic_pause()) return; 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci if (value_offset > 0 && age_table.GetAge(value_offset) == AgeTable::Age::kOld) 1391cb0ef41Sopenharmony_ci return; 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci // Record slot. 1421cb0ef41Sopenharmony_ci local_data.heap_base.remembered_set().AddSlot((const_cast<void*>(slot))); 1431cb0ef41Sopenharmony_ci} 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci// static 1461cb0ef41Sopenharmony_civoid WriteBarrier::GenerationalBarrierForSourceObjectSlow( 1471cb0ef41Sopenharmony_ci const CagedHeapLocalData& local_data, const void* inner_pointer) { 1481cb0ef41Sopenharmony_ci DCHECK(inner_pointer); 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci auto& object_header = 1511cb0ef41Sopenharmony_ci BasePage::FromInnerAddress(&local_data.heap_base, inner_pointer) 1521cb0ef41Sopenharmony_ci ->ObjectHeaderFromInnerAddress<AccessMode::kAtomic>(inner_pointer); 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci // Record the source object. 1551cb0ef41Sopenharmony_ci local_data.heap_base.remembered_set().AddSourceObject( 1561cb0ef41Sopenharmony_ci const_cast<HeapObjectHeader&>(object_header)); 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci#endif // CPPGC_YOUNG_GENERATION 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci#if V8_ENABLE_CHECKS 1611cb0ef41Sopenharmony_ci// static 1621cb0ef41Sopenharmony_civoid WriteBarrier::CheckParams(Type expected_type, const Params& params) { 1631cb0ef41Sopenharmony_ci CHECK_EQ(expected_type, params.type); 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci#endif // V8_ENABLE_CHECKS 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci// static 1681cb0ef41Sopenharmony_cibool WriteBarrierTypeForNonCagedHeapPolicy::IsMarking(const void* object, 1691cb0ef41Sopenharmony_ci HeapHandle** handle) { 1701cb0ef41Sopenharmony_ci // Large objects cannot have mixins, so we are guaranteed to always have 1711cb0ef41Sopenharmony_ci // a pointer on the same page. 1721cb0ef41Sopenharmony_ci const auto* page = BasePage::FromPayload(object); 1731cb0ef41Sopenharmony_ci *handle = &page->heap(); 1741cb0ef41Sopenharmony_ci const MarkerBase* marker = page->heap().marker(); 1751cb0ef41Sopenharmony_ci return marker && marker->IsMarking(); 1761cb0ef41Sopenharmony_ci} 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci// static 1791cb0ef41Sopenharmony_cibool WriteBarrierTypeForNonCagedHeapPolicy::IsMarking(HeapHandle& heap_handle) { 1801cb0ef41Sopenharmony_ci const auto& heap_base = internal::HeapBase::From(heap_handle); 1811cb0ef41Sopenharmony_ci const MarkerBase* marker = heap_base.marker(); 1821cb0ef41Sopenharmony_ci return marker && marker->IsMarking(); 1831cb0ef41Sopenharmony_ci} 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP) 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci// static 1881cb0ef41Sopenharmony_cibool WriteBarrierTypeForCagedHeapPolicy::IsMarking( 1891cb0ef41Sopenharmony_ci const HeapHandle& heap_handle, WriteBarrier::Params& params) { 1901cb0ef41Sopenharmony_ci const auto& heap_base = internal::HeapBase::From(heap_handle); 1911cb0ef41Sopenharmony_ci if (const MarkerBase* marker = heap_base.marker()) { 1921cb0ef41Sopenharmony_ci return marker->IsMarking(); 1931cb0ef41Sopenharmony_ci } 1941cb0ef41Sopenharmony_ci // Also set caged heap start here to avoid another call immediately after 1951cb0ef41Sopenharmony_ci // checking IsMarking(). 1961cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION) 1971cb0ef41Sopenharmony_ci params.start = 1981cb0ef41Sopenharmony_ci reinterpret_cast<uintptr_t>(&heap_base.caged_heap().local_data()); 1991cb0ef41Sopenharmony_ci#endif // !CPPGC_YOUNG_GENERATION 2001cb0ef41Sopenharmony_ci return false; 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci#endif // CPPGC_CAGED_HEAP 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci} // namespace internal 2061cb0ef41Sopenharmony_ci} // namespace cppgc 207