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#ifndef INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
61cb0ef41Sopenharmony_ci#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include <cstddef>
91cb0ef41Sopenharmony_ci#include <cstdint>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "cppgc/heap-handle.h"
121cb0ef41Sopenharmony_ci#include "cppgc/heap-state.h"
131cb0ef41Sopenharmony_ci#include "cppgc/internal/api-constants.h"
141cb0ef41Sopenharmony_ci#include "cppgc/internal/atomic-entry-flag.h"
151cb0ef41Sopenharmony_ci#include "cppgc/internal/base-page-handle.h"
161cb0ef41Sopenharmony_ci#include "cppgc/internal/member-storage.h"
171cb0ef41Sopenharmony_ci#include "cppgc/platform.h"
181cb0ef41Sopenharmony_ci#include "cppgc/sentinel-pointer.h"
191cb0ef41Sopenharmony_ci#include "cppgc/trace-trait.h"
201cb0ef41Sopenharmony_ci#include "v8config.h"  // NOLINT(build/include_directory)
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
231cb0ef41Sopenharmony_ci#include "cppgc/internal/caged-heap-local-data.h"
241cb0ef41Sopenharmony_ci#include "cppgc/internal/caged-heap.h"
251cb0ef41Sopenharmony_ci#endif
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_cinamespace cppgc {
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciclass HeapHandle;
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cinamespace internal {
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
341cb0ef41Sopenharmony_ciclass WriteBarrierTypeForCagedHeapPolicy;
351cb0ef41Sopenharmony_ci#else   // !CPPGC_CAGED_HEAP
361cb0ef41Sopenharmony_ciclass WriteBarrierTypeForNonCagedHeapPolicy;
371cb0ef41Sopenharmony_ci#endif  // !CPPGC_CAGED_HEAP
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ciclass V8_EXPORT WriteBarrier final {
401cb0ef41Sopenharmony_ci public:
411cb0ef41Sopenharmony_ci  enum class Type : uint8_t {
421cb0ef41Sopenharmony_ci    kNone,
431cb0ef41Sopenharmony_ci    kMarking,
441cb0ef41Sopenharmony_ci    kGenerational,
451cb0ef41Sopenharmony_ci  };
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  enum class GenerationalBarrierType : uint8_t {
481cb0ef41Sopenharmony_ci    kPreciseSlot,
491cb0ef41Sopenharmony_ci    kPreciseUncompressedSlot,
501cb0ef41Sopenharmony_ci    kImpreciseSlot,
511cb0ef41Sopenharmony_ci  };
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  struct Params {
541cb0ef41Sopenharmony_ci    HeapHandle* heap = nullptr;
551cb0ef41Sopenharmony_ci#if V8_ENABLE_CHECKS
561cb0ef41Sopenharmony_ci    Type type = Type::kNone;
571cb0ef41Sopenharmony_ci#endif  // !V8_ENABLE_CHECKS
581cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
591cb0ef41Sopenharmony_ci    uintptr_t slot_offset = 0;
601cb0ef41Sopenharmony_ci    uintptr_t value_offset = 0;
611cb0ef41Sopenharmony_ci#endif  // CPPGC_CAGED_HEAP
621cb0ef41Sopenharmony_ci  };
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  enum class ValueMode {
651cb0ef41Sopenharmony_ci    kValuePresent,
661cb0ef41Sopenharmony_ci    kNoValuePresent,
671cb0ef41Sopenharmony_ci  };
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  // Returns the required write barrier for a given `slot` and `value`.
701cb0ef41Sopenharmony_ci  static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value,
711cb0ef41Sopenharmony_ci                                            Params& params);
721cb0ef41Sopenharmony_ci  // Returns the required write barrier for a given `slot` and `value`.
731cb0ef41Sopenharmony_ci  template <typename MemberStorage>
741cb0ef41Sopenharmony_ci  static V8_INLINE Type GetWriteBarrierType(const void* slot, MemberStorage,
751cb0ef41Sopenharmony_ci                                            Params& params);
761cb0ef41Sopenharmony_ci  // Returns the required write barrier for a given `slot`.
771cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback>
781cb0ef41Sopenharmony_ci  static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params,
791cb0ef41Sopenharmony_ci                                            HeapHandleCallback callback);
801cb0ef41Sopenharmony_ci  // Returns the required write barrier for a given  `value`.
811cb0ef41Sopenharmony_ci  static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params);
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci#ifdef CPPGC_SLIM_WRITE_BARRIER
841cb0ef41Sopenharmony_ci  // A write barrier that combines `GenerationalBarrier()` and
851cb0ef41Sopenharmony_ci  // `DijkstraMarkingBarrier()`. We only pass a single parameter here to clobber
861cb0ef41Sopenharmony_ci  // as few registers as possible.
871cb0ef41Sopenharmony_ci  template <WriteBarrierSlotType>
881cb0ef41Sopenharmony_ci  static V8_NOINLINE void V8_PRESERVE_MOST
891cb0ef41Sopenharmony_ci  CombinedWriteBarrierSlow(const void* slot);
901cb0ef41Sopenharmony_ci#endif  // CPPGC_SLIM_WRITE_BARRIER
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  static V8_INLINE void DijkstraMarkingBarrier(const Params& params,
931cb0ef41Sopenharmony_ci                                               const void* object);
941cb0ef41Sopenharmony_ci  static V8_INLINE void DijkstraMarkingBarrierRange(
951cb0ef41Sopenharmony_ci      const Params& params, const void* first_element, size_t element_size,
961cb0ef41Sopenharmony_ci      size_t number_of_elements, TraceCallback trace_callback);
971cb0ef41Sopenharmony_ci  static V8_INLINE void SteeleMarkingBarrier(const Params& params,
981cb0ef41Sopenharmony_ci                                             const void* object);
991cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION)
1001cb0ef41Sopenharmony_ci  template <GenerationalBarrierType>
1011cb0ef41Sopenharmony_ci  static V8_INLINE void GenerationalBarrier(const Params& params,
1021cb0ef41Sopenharmony_ci                                            const void* slot);
1031cb0ef41Sopenharmony_ci#else  // !CPPGC_YOUNG_GENERATION
1041cb0ef41Sopenharmony_ci  template <GenerationalBarrierType>
1051cb0ef41Sopenharmony_ci  static V8_INLINE void GenerationalBarrier(const Params& params,
1061cb0ef41Sopenharmony_ci                                            const void* slot){}
1071cb0ef41Sopenharmony_ci#endif  // CPPGC_YOUNG_GENERATION
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci#if V8_ENABLE_CHECKS
1101cb0ef41Sopenharmony_ci  static void CheckParams(Type expected_type, const Params& params);
1111cb0ef41Sopenharmony_ci#else   // !V8_ENABLE_CHECKS
1121cb0ef41Sopenharmony_ci  static void CheckParams(Type expected_type, const Params& params) {}
1131cb0ef41Sopenharmony_ci#endif  // !V8_ENABLE_CHECKS
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  // The FlagUpdater class allows cppgc internal to update
1161cb0ef41Sopenharmony_ci  // |write_barrier_enabled_|.
1171cb0ef41Sopenharmony_ci  class FlagUpdater;
1181cb0ef41Sopenharmony_ci  static bool IsEnabled() { return write_barrier_enabled_.MightBeEntered(); }
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci private:
1211cb0ef41Sopenharmony_ci  WriteBarrier() = delete;
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
1241cb0ef41Sopenharmony_ci  using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy;
1251cb0ef41Sopenharmony_ci#else   // !CPPGC_CAGED_HEAP
1261cb0ef41Sopenharmony_ci  using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy;
1271cb0ef41Sopenharmony_ci#endif  // !CPPGC_CAGED_HEAP
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  static void DijkstraMarkingBarrierSlow(const void* value);
1301cb0ef41Sopenharmony_ci  static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value);
1311cb0ef41Sopenharmony_ci  static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle,
1321cb0ef41Sopenharmony_ci                                              const void* first_element,
1331cb0ef41Sopenharmony_ci                                              size_t element_size,
1341cb0ef41Sopenharmony_ci                                              size_t number_of_elements,
1351cb0ef41Sopenharmony_ci                                              TraceCallback trace_callback);
1361cb0ef41Sopenharmony_ci  static void SteeleMarkingBarrierSlow(const void* value);
1371cb0ef41Sopenharmony_ci  static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value);
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION)
1401cb0ef41Sopenharmony_ci  static CagedHeapLocalData& GetLocalData(HeapHandle&);
1411cb0ef41Sopenharmony_ci  static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data,
1421cb0ef41Sopenharmony_ci                                      const AgeTable& age_table,
1431cb0ef41Sopenharmony_ci                                      const void* slot, uintptr_t value_offset,
1441cb0ef41Sopenharmony_ci                                      HeapHandle* heap_handle);
1451cb0ef41Sopenharmony_ci  static void GenerationalBarrierForUncompressedSlotSlow(
1461cb0ef41Sopenharmony_ci      const CagedHeapLocalData& local_data, const AgeTable& age_table,
1471cb0ef41Sopenharmony_ci      const void* slot, uintptr_t value_offset, HeapHandle* heap_handle);
1481cb0ef41Sopenharmony_ci  static void GenerationalBarrierForSourceObjectSlow(
1491cb0ef41Sopenharmony_ci      const CagedHeapLocalData& local_data, const void* object,
1501cb0ef41Sopenharmony_ci      HeapHandle* heap_handle);
1511cb0ef41Sopenharmony_ci#endif  // CPPGC_YOUNG_GENERATION
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  static AtomicEntryFlag write_barrier_enabled_;
1541cb0ef41Sopenharmony_ci};
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_citemplate <WriteBarrier::Type type>
1571cb0ef41Sopenharmony_ciV8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) {
1581cb0ef41Sopenharmony_ci  if constexpr (type == WriteBarrier::Type::kNone)
1591cb0ef41Sopenharmony_ci    return WriteBarrier::Type::kNone;
1601cb0ef41Sopenharmony_ci#if V8_ENABLE_CHECKS
1611cb0ef41Sopenharmony_ci  params.type = type;
1621cb0ef41Sopenharmony_ci#endif  // !V8_ENABLE_CHECKS
1631cb0ef41Sopenharmony_ci  return type;
1641cb0ef41Sopenharmony_ci}
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
1671cb0ef41Sopenharmony_ciclass V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final {
1681cb0ef41Sopenharmony_ci public:
1691cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
1701cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
1711cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
1721cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
1731cb0ef41Sopenharmony_ci    return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback,
1771cb0ef41Sopenharmony_ci            typename MemberStorage>
1781cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value,
1791cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
1801cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
1811cb0ef41Sopenharmony_ci    return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
1851cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* value,
1861cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
1871cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
1881cb0ef41Sopenharmony_ci    return GetNoSlot(value, params, callback);
1891cb0ef41Sopenharmony_ci  }
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci private:
1921cb0ef41Sopenharmony_ci  WriteBarrierTypeForCagedHeapPolicy() = delete;
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback>
1951cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value,
1961cb0ef41Sopenharmony_ci                                                WriteBarrier::Params& params,
1971cb0ef41Sopenharmony_ci                                                HeapHandleCallback) {
1981cb0ef41Sopenharmony_ci    const bool within_cage = CagedHeapBase::IsWithinCage(value);
1991cb0ef41Sopenharmony_ci    if (!within_cage) return WriteBarrier::Type::kNone;
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci    // We know that |value| points either within the normal page or to the
2021cb0ef41Sopenharmony_ci    // beginning of large-page, so extract the page header by bitmasking.
2031cb0ef41Sopenharmony_ci    BasePageHandle* page =
2041cb0ef41Sopenharmony_ci        BasePageHandle::FromPayload(const_cast<void*>(value));
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci    HeapHandle& heap_handle = page->heap_handle();
2071cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(heap_handle.is_incremental_marking_in_progress())) {
2081cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
2091cb0ef41Sopenharmony_ci    }
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci    return SetAndReturnType<WriteBarrier::Type::kNone>(params);
2121cb0ef41Sopenharmony_ci  }
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode>
2151cb0ef41Sopenharmony_ci  struct ValueModeDispatch;
2161cb0ef41Sopenharmony_ci};
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_citemplate <>
2191cb0ef41Sopenharmony_cistruct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
2201cb0ef41Sopenharmony_ci    WriteBarrier::ValueMode::kValuePresent> {
2211cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback, typename MemberStorage>
2221cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot,
2231cb0ef41Sopenharmony_ci                                          MemberStorage storage,
2241cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
2251cb0ef41Sopenharmony_ci                                          HeapHandleCallback) {
2261cb0ef41Sopenharmony_ci    if (V8_LIKELY(!WriteBarrier::IsEnabled()))
2271cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci    return BarrierEnabledGet(slot, storage.Load(), params);
2301cb0ef41Sopenharmony_ci  }
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback>
2331cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
2341cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
2351cb0ef41Sopenharmony_ci                                          HeapHandleCallback) {
2361cb0ef41Sopenharmony_ci    if (V8_LIKELY(!WriteBarrier::IsEnabled()))
2371cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci    return BarrierEnabledGet(slot, value, params);
2401cb0ef41Sopenharmony_ci  }
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci private:
2431cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type BarrierEnabledGet(
2441cb0ef41Sopenharmony_ci      const void* slot, const void* value, WriteBarrier::Params& params) {
2451cb0ef41Sopenharmony_ci    const bool within_cage = CagedHeapBase::AreWithinCage(slot, value);
2461cb0ef41Sopenharmony_ci    if (!within_cage) return WriteBarrier::Type::kNone;
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci    // We know that |value| points either within the normal page or to the
2491cb0ef41Sopenharmony_ci    // beginning of large-page, so extract the page header by bitmasking.
2501cb0ef41Sopenharmony_ci    BasePageHandle* page =
2511cb0ef41Sopenharmony_ci        BasePageHandle::FromPayload(const_cast<void*>(value));
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci    HeapHandle& heap_handle = page->heap_handle();
2541cb0ef41Sopenharmony_ci    if (V8_LIKELY(!heap_handle.is_incremental_marking_in_progress())) {
2551cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION)
2561cb0ef41Sopenharmony_ci      if (!heap_handle.is_young_generation_enabled())
2571cb0ef41Sopenharmony_ci        return WriteBarrier::Type::kNone;
2581cb0ef41Sopenharmony_ci      params.heap = &heap_handle;
2591cb0ef41Sopenharmony_ci      params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
2601cb0ef41Sopenharmony_ci      params.value_offset = CagedHeapBase::OffsetFromAddress(value);
2611cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
2621cb0ef41Sopenharmony_ci#else   // !CPPGC_YOUNG_GENERATION
2631cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
2641cb0ef41Sopenharmony_ci#endif  // !CPPGC_YOUNG_GENERATION
2651cb0ef41Sopenharmony_ci    }
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci    // Use marking barrier.
2681cb0ef41Sopenharmony_ci    params.heap = &heap_handle;
2691cb0ef41Sopenharmony_ci    return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci};
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_citemplate <>
2741cb0ef41Sopenharmony_cistruct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
2751cb0ef41Sopenharmony_ci    WriteBarrier::ValueMode::kNoValuePresent> {
2761cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback>
2771cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*,
2781cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
2791cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
2801cb0ef41Sopenharmony_ci    if (V8_LIKELY(!WriteBarrier::IsEnabled()))
2811cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci    HeapHandle& handle = callback();
2841cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION)
2851cb0ef41Sopenharmony_ci    if (V8_LIKELY(!handle.is_incremental_marking_in_progress())) {
2861cb0ef41Sopenharmony_ci      if (!handle.is_young_generation_enabled()) {
2871cb0ef41Sopenharmony_ci        return WriteBarrier::Type::kNone;
2881cb0ef41Sopenharmony_ci      }
2891cb0ef41Sopenharmony_ci      params.heap = &handle;
2901cb0ef41Sopenharmony_ci      // Check if slot is on stack.
2911cb0ef41Sopenharmony_ci      if (V8_UNLIKELY(!CagedHeapBase::IsWithinCage(slot))) {
2921cb0ef41Sopenharmony_ci        return SetAndReturnType<WriteBarrier::Type::kNone>(params);
2931cb0ef41Sopenharmony_ci      }
2941cb0ef41Sopenharmony_ci      params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
2951cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
2961cb0ef41Sopenharmony_ci    }
2971cb0ef41Sopenharmony_ci#else   // !defined(CPPGC_YOUNG_GENERATION)
2981cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(!handle.is_incremental_marking_in_progress())) {
2991cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
3001cb0ef41Sopenharmony_ci    }
3011cb0ef41Sopenharmony_ci#endif  // !defined(CPPGC_YOUNG_GENERATION)
3021cb0ef41Sopenharmony_ci    params.heap = &handle;
3031cb0ef41Sopenharmony_ci    return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
3041cb0ef41Sopenharmony_ci  }
3051cb0ef41Sopenharmony_ci};
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci#endif  // CPPGC_CAGED_HEAP
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ciclass V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final {
3101cb0ef41Sopenharmony_ci public:
3111cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
3121cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
3131cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
3141cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
3151cb0ef41Sopenharmony_ci    return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
3161cb0ef41Sopenharmony_ci  }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
3191cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* slot, RawPointer value,
3201cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
3211cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
3221cb0ef41Sopenharmony_ci    return ValueModeDispatch<value_mode>::Get(slot, value.Load(), params,
3231cb0ef41Sopenharmony_ci                                              callback);
3241cb0ef41Sopenharmony_ci  }
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
3271cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void* value,
3281cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
3291cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
3301cb0ef41Sopenharmony_ci    // The slot will never be used in `Get()` below.
3311cb0ef41Sopenharmony_ci    return Get<WriteBarrier::ValueMode::kValuePresent>(nullptr, value, params,
3321cb0ef41Sopenharmony_ci                                                       callback);
3331cb0ef41Sopenharmony_ci  }
3341cb0ef41Sopenharmony_ci
3351cb0ef41Sopenharmony_ci private:
3361cb0ef41Sopenharmony_ci  template <WriteBarrier::ValueMode value_mode>
3371cb0ef41Sopenharmony_ci  struct ValueModeDispatch;
3381cb0ef41Sopenharmony_ci
3391cb0ef41Sopenharmony_ci  WriteBarrierTypeForNonCagedHeapPolicy() = delete;
3401cb0ef41Sopenharmony_ci};
3411cb0ef41Sopenharmony_ci
3421cb0ef41Sopenharmony_citemplate <>
3431cb0ef41Sopenharmony_cistruct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
3441cb0ef41Sopenharmony_ci    WriteBarrier::ValueMode::kValuePresent> {
3451cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback>
3461cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void*, const void* object,
3471cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
3481cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
3491cb0ef41Sopenharmony_ci    // The following check covers nullptr as well as sentinel pointer.
3501cb0ef41Sopenharmony_ci    if (object <= static_cast<void*>(kSentinelPointer)) {
3511cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
3521cb0ef41Sopenharmony_ci    }
3531cb0ef41Sopenharmony_ci    if (V8_LIKELY(!WriteBarrier::IsEnabled())) {
3541cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
3551cb0ef41Sopenharmony_ci    }
3561cb0ef41Sopenharmony_ci    // We know that |object| is within the normal page or in the beginning of a
3571cb0ef41Sopenharmony_ci    // large page, so extract the page header by bitmasking.
3581cb0ef41Sopenharmony_ci    BasePageHandle* page =
3591cb0ef41Sopenharmony_ci        BasePageHandle::FromPayload(const_cast<void*>(object));
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci    HeapHandle& heap_handle = page->heap_handle();
3621cb0ef41Sopenharmony_ci    if (V8_LIKELY(heap_handle.is_incremental_marking_in_progress())) {
3631cb0ef41Sopenharmony_ci      return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
3641cb0ef41Sopenharmony_ci    }
3651cb0ef41Sopenharmony_ci    return SetAndReturnType<WriteBarrier::Type::kNone>(params);
3661cb0ef41Sopenharmony_ci  }
3671cb0ef41Sopenharmony_ci};
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_citemplate <>
3701cb0ef41Sopenharmony_cistruct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
3711cb0ef41Sopenharmony_ci    WriteBarrier::ValueMode::kNoValuePresent> {
3721cb0ef41Sopenharmony_ci  template <typename HeapHandleCallback>
3731cb0ef41Sopenharmony_ci  static V8_INLINE WriteBarrier::Type Get(const void*, const void*,
3741cb0ef41Sopenharmony_ci                                          WriteBarrier::Params& params,
3751cb0ef41Sopenharmony_ci                                          HeapHandleCallback callback) {
3761cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(WriteBarrier::IsEnabled())) {
3771cb0ef41Sopenharmony_ci      HeapHandle& handle = callback();
3781cb0ef41Sopenharmony_ci      if (V8_LIKELY(handle.is_incremental_marking_in_progress())) {
3791cb0ef41Sopenharmony_ci        params.heap = &handle;
3801cb0ef41Sopenharmony_ci        return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
3811cb0ef41Sopenharmony_ci      }
3821cb0ef41Sopenharmony_ci    }
3831cb0ef41Sopenharmony_ci    return WriteBarrier::Type::kNone;
3841cb0ef41Sopenharmony_ci  }
3851cb0ef41Sopenharmony_ci};
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci// static
3881cb0ef41Sopenharmony_ciWriteBarrier::Type WriteBarrier::GetWriteBarrierType(
3891cb0ef41Sopenharmony_ci    const void* slot, const void* value, WriteBarrier::Params& params) {
3901cb0ef41Sopenharmony_ci  return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
3911cb0ef41Sopenharmony_ci                                                               params, []() {});
3921cb0ef41Sopenharmony_ci}
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci// static
3951cb0ef41Sopenharmony_citemplate <typename MemberStorage>
3961cb0ef41Sopenharmony_ciWriteBarrier::Type WriteBarrier::GetWriteBarrierType(
3971cb0ef41Sopenharmony_ci    const void* slot, MemberStorage value, WriteBarrier::Params& params) {
3981cb0ef41Sopenharmony_ci  return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
3991cb0ef41Sopenharmony_ci                                                               params, []() {});
4001cb0ef41Sopenharmony_ci}
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci// static
4031cb0ef41Sopenharmony_citemplate <typename HeapHandleCallback>
4041cb0ef41Sopenharmony_ciWriteBarrier::Type WriteBarrier::GetWriteBarrierType(
4051cb0ef41Sopenharmony_ci    const void* slot, WriteBarrier::Params& params,
4061cb0ef41Sopenharmony_ci    HeapHandleCallback callback) {
4071cb0ef41Sopenharmony_ci  return WriteBarrierTypePolicy::Get<ValueMode::kNoValuePresent>(
4081cb0ef41Sopenharmony_ci      slot, nullptr, params, callback);
4091cb0ef41Sopenharmony_ci}
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci// static
4121cb0ef41Sopenharmony_ciWriteBarrier::Type WriteBarrier::GetWriteBarrierType(
4131cb0ef41Sopenharmony_ci    const void* value, WriteBarrier::Params& params) {
4141cb0ef41Sopenharmony_ci  return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(value, params,
4151cb0ef41Sopenharmony_ci                                                               []() {});
4161cb0ef41Sopenharmony_ci}
4171cb0ef41Sopenharmony_ci
4181cb0ef41Sopenharmony_ci// static
4191cb0ef41Sopenharmony_civoid WriteBarrier::DijkstraMarkingBarrier(const Params& params,
4201cb0ef41Sopenharmony_ci                                          const void* object) {
4211cb0ef41Sopenharmony_ci  CheckParams(Type::kMarking, params);
4221cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
4231cb0ef41Sopenharmony_ci  // Caged heap already filters out sentinels.
4241cb0ef41Sopenharmony_ci  DijkstraMarkingBarrierSlow(object);
4251cb0ef41Sopenharmony_ci#else   // !CPPGC_CAGED_HEAP
4261cb0ef41Sopenharmony_ci  DijkstraMarkingBarrierSlowWithSentinelCheck(object);
4271cb0ef41Sopenharmony_ci#endif  // !CPPGC_CAGED_HEAP
4281cb0ef41Sopenharmony_ci}
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci// static
4311cb0ef41Sopenharmony_civoid WriteBarrier::DijkstraMarkingBarrierRange(const Params& params,
4321cb0ef41Sopenharmony_ci                                               const void* first_element,
4331cb0ef41Sopenharmony_ci                                               size_t element_size,
4341cb0ef41Sopenharmony_ci                                               size_t number_of_elements,
4351cb0ef41Sopenharmony_ci                                               TraceCallback trace_callback) {
4361cb0ef41Sopenharmony_ci  CheckParams(Type::kMarking, params);
4371cb0ef41Sopenharmony_ci  DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size,
4381cb0ef41Sopenharmony_ci                                  number_of_elements, trace_callback);
4391cb0ef41Sopenharmony_ci}
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_ci// static
4421cb0ef41Sopenharmony_civoid WriteBarrier::SteeleMarkingBarrier(const Params& params,
4431cb0ef41Sopenharmony_ci                                        const void* object) {
4441cb0ef41Sopenharmony_ci  CheckParams(Type::kMarking, params);
4451cb0ef41Sopenharmony_ci#if defined(CPPGC_CAGED_HEAP)
4461cb0ef41Sopenharmony_ci  // Caged heap already filters out sentinels.
4471cb0ef41Sopenharmony_ci  SteeleMarkingBarrierSlow(object);
4481cb0ef41Sopenharmony_ci#else   // !CPPGC_CAGED_HEAP
4491cb0ef41Sopenharmony_ci  SteeleMarkingBarrierSlowWithSentinelCheck(object);
4501cb0ef41Sopenharmony_ci#endif  // !CPPGC_CAGED_HEAP
4511cb0ef41Sopenharmony_ci}
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci#if defined(CPPGC_YOUNG_GENERATION)
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci// static
4561cb0ef41Sopenharmony_citemplate <WriteBarrier::GenerationalBarrierType type>
4571cb0ef41Sopenharmony_civoid WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) {
4581cb0ef41Sopenharmony_ci  CheckParams(Type::kGenerational, params);
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci  const CagedHeapLocalData& local_data = CagedHeapLocalData::Get();
4611cb0ef41Sopenharmony_ci  const AgeTable& age_table = local_data.age_table;
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci  // Bail out if the slot (precise or imprecise) is in young generation.
4641cb0ef41Sopenharmony_ci  if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung))
4651cb0ef41Sopenharmony_ci    return;
4661cb0ef41Sopenharmony_ci
4671cb0ef41Sopenharmony_ci  // Dispatch between different types of barriers.
4681cb0ef41Sopenharmony_ci  // TODO(chromium:1029379): Consider reload local_data in the slow path to
4691cb0ef41Sopenharmony_ci  // reduce register pressure.
4701cb0ef41Sopenharmony_ci  if constexpr (type == GenerationalBarrierType::kPreciseSlot) {
4711cb0ef41Sopenharmony_ci    GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset,
4721cb0ef41Sopenharmony_ci                            params.heap);
4731cb0ef41Sopenharmony_ci  } else if constexpr (type ==
4741cb0ef41Sopenharmony_ci                       GenerationalBarrierType::kPreciseUncompressedSlot) {
4751cb0ef41Sopenharmony_ci    GenerationalBarrierForUncompressedSlotSlow(
4761cb0ef41Sopenharmony_ci        local_data, age_table, slot, params.value_offset, params.heap);
4771cb0ef41Sopenharmony_ci  } else {
4781cb0ef41Sopenharmony_ci    GenerationalBarrierForSourceObjectSlow(local_data, slot, params.heap);
4791cb0ef41Sopenharmony_ci  }
4801cb0ef41Sopenharmony_ci}
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci#endif  // !CPPGC_YOUNG_GENERATION
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci}  // namespace internal
4851cb0ef41Sopenharmony_ci}  // namespace cppgc
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci#endif  // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
488