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