1// Copyright 2020 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ 6#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ 7 8#include <cstdint> 9#include <type_traits> 10 11#include "cppgc/internal/member-storage.h" 12#include "cppgc/internal/write-barrier.h" 13#include "cppgc/sentinel-pointer.h" 14#include "cppgc/source-location.h" 15#include "cppgc/type-traits.h" 16#include "v8config.h" // NOLINT(build/include_directory) 17 18namespace cppgc { 19namespace internal { 20 21class HeapBase; 22class PersistentRegion; 23class CrossThreadPersistentRegion; 24 25// Tags to distinguish between strong and weak member types. 26class StrongMemberTag; 27class WeakMemberTag; 28class UntracedMemberTag; 29 30struct DijkstraWriteBarrierPolicy { 31 V8_INLINE static void InitializingBarrier(const void*, const void*) { 32 // Since in initializing writes the source object is always white, having no 33 // barrier doesn't break the tri-color invariant. 34 } 35 36 template <WriteBarrierSlotType SlotType> 37 V8_INLINE static void AssigningBarrier(const void* slot, const void* value) { 38#ifdef CPPGC_SLIM_WRITE_BARRIER 39 if (V8_UNLIKELY(WriteBarrier::IsEnabled())) 40 WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot); 41#else // !CPPGC_SLIM_WRITE_BARRIER 42 WriteBarrier::Params params; 43 const WriteBarrier::Type type = 44 WriteBarrier::GetWriteBarrierType(slot, value, params); 45 WriteBarrier(type, params, slot, value); 46#endif // !CPPGC_SLIM_WRITE_BARRIER 47 } 48 49 template <WriteBarrierSlotType SlotType> 50 V8_INLINE static void AssigningBarrier(const void* slot, RawPointer storage) { 51 static_assert( 52 SlotType == WriteBarrierSlotType::kUncompressed, 53 "Assigning storages of Member and UncompressedMember is not supported"); 54#ifdef CPPGC_SLIM_WRITE_BARRIER 55 if (V8_UNLIKELY(WriteBarrier::IsEnabled())) 56 WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot); 57#else // !CPPGC_SLIM_WRITE_BARRIER 58 WriteBarrier::Params params; 59 const WriteBarrier::Type type = 60 WriteBarrier::GetWriteBarrierType(slot, storage, params); 61 WriteBarrier(type, params, slot, storage.Load()); 62#endif // !CPPGC_SLIM_WRITE_BARRIER 63 } 64 65#if defined(CPPGC_POINTER_COMPRESSION) 66 template <WriteBarrierSlotType SlotType> 67 V8_INLINE static void AssigningBarrier(const void* slot, 68 CompressedPointer storage) { 69 static_assert( 70 SlotType == WriteBarrierSlotType::kCompressed, 71 "Assigning storages of Member and UncompressedMember is not supported"); 72#ifdef CPPGC_SLIM_WRITE_BARRIER 73 if (V8_UNLIKELY(WriteBarrier::IsEnabled())) 74 WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot); 75#else // !CPPGC_SLIM_WRITE_BARRIER 76 WriteBarrier::Params params; 77 const WriteBarrier::Type type = 78 WriteBarrier::GetWriteBarrierType(slot, storage, params); 79 WriteBarrier(type, params, slot, storage.Load()); 80#endif // !CPPGC_SLIM_WRITE_BARRIER 81 } 82#endif // defined(CPPGC_POINTER_COMPRESSION) 83 84 private: 85 V8_INLINE static void WriteBarrier(WriteBarrier::Type type, 86 const WriteBarrier::Params& params, 87 const void* slot, const void* value) { 88 switch (type) { 89 case WriteBarrier::Type::kGenerational: 90 WriteBarrier::GenerationalBarrier< 91 WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, slot); 92 break; 93 case WriteBarrier::Type::kMarking: 94 WriteBarrier::DijkstraMarkingBarrier(params, value); 95 break; 96 case WriteBarrier::Type::kNone: 97 break; 98 } 99 } 100}; 101 102struct NoWriteBarrierPolicy { 103 V8_INLINE static void InitializingBarrier(const void*, const void*) {} 104 template <WriteBarrierSlotType> 105 V8_INLINE static void AssigningBarrier(const void*, const void*) {} 106 template <WriteBarrierSlotType, typename MemberStorage> 107 V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {} 108}; 109 110class V8_EXPORT SameThreadEnabledCheckingPolicyBase { 111 protected: 112 void CheckPointerImpl(const void* ptr, bool points_to_payload, 113 bool check_off_heap_assignments); 114 115 const HeapBase* heap_ = nullptr; 116}; 117 118template <bool kCheckOffHeapAssignments> 119class V8_EXPORT SameThreadEnabledCheckingPolicy 120 : private SameThreadEnabledCheckingPolicyBase { 121 protected: 122 template <typename T> 123 void CheckPointer(const T* ptr) { 124 if (!ptr || (kSentinelPointer == ptr)) return; 125 126 CheckPointersImplTrampoline<T>::Call(this, ptr); 127 } 128 129 private: 130 template <typename T, bool = IsCompleteV<T>> 131 struct CheckPointersImplTrampoline { 132 static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { 133 policy->CheckPointerImpl(ptr, false, kCheckOffHeapAssignments); 134 } 135 }; 136 137 template <typename T> 138 struct CheckPointersImplTrampoline<T, true> { 139 static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { 140 policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV<T>, 141 kCheckOffHeapAssignments); 142 } 143 }; 144}; 145 146class DisabledCheckingPolicy { 147 protected: 148 V8_INLINE void CheckPointer(const void*) {} 149}; 150 151#ifdef DEBUG 152// Off heap members are not connected to object graph and thus cannot ressurect 153// dead objects. 154using DefaultMemberCheckingPolicy = 155 SameThreadEnabledCheckingPolicy<false /* kCheckOffHeapAssignments*/>; 156using DefaultPersistentCheckingPolicy = 157 SameThreadEnabledCheckingPolicy<true /* kCheckOffHeapAssignments*/>; 158#else // !DEBUG 159using DefaultMemberCheckingPolicy = DisabledCheckingPolicy; 160using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy; 161#endif // !DEBUG 162// For CT(W)P neither marking information (for value), nor objectstart bitmap 163// (for slot) are guaranteed to be present because there's no synchronization 164// between heaps after marking. 165using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy; 166 167class KeepLocationPolicy { 168 public: 169 constexpr const SourceLocation& Location() const { return location_; } 170 171 protected: 172 constexpr KeepLocationPolicy() = default; 173 constexpr explicit KeepLocationPolicy(const SourceLocation& location) 174 : location_(location) {} 175 176 // KeepLocationPolicy must not copy underlying source locations. 177 KeepLocationPolicy(const KeepLocationPolicy&) = delete; 178 KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete; 179 180 // Location of the original moved from object should be preserved. 181 KeepLocationPolicy(KeepLocationPolicy&&) = default; 182 KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default; 183 184 private: 185 SourceLocation location_; 186}; 187 188class IgnoreLocationPolicy { 189 public: 190 constexpr SourceLocation Location() const { return {}; } 191 192 protected: 193 constexpr IgnoreLocationPolicy() = default; 194 constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {} 195}; 196 197#if CPPGC_SUPPORTS_OBJECT_NAMES 198using DefaultLocationPolicy = KeepLocationPolicy; 199#else 200using DefaultLocationPolicy = IgnoreLocationPolicy; 201#endif 202 203struct StrongPersistentPolicy { 204 using IsStrongPersistent = std::true_type; 205 static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); 206}; 207 208struct WeakPersistentPolicy { 209 using IsStrongPersistent = std::false_type; 210 static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); 211}; 212 213struct StrongCrossThreadPersistentPolicy { 214 using IsStrongPersistent = std::true_type; 215 static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( 216 const void* object); 217}; 218 219struct WeakCrossThreadPersistentPolicy { 220 using IsStrongPersistent = std::false_type; 221 static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( 222 const void* object); 223}; 224 225// Forward declarations setting up the default policies. 226template <typename T, typename WeaknessPolicy, 227 typename LocationPolicy = DefaultLocationPolicy, 228 typename CheckingPolicy = DefaultCrossThreadPersistentCheckingPolicy> 229class BasicCrossThreadPersistent; 230template <typename T, typename WeaknessPolicy, 231 typename LocationPolicy = DefaultLocationPolicy, 232 typename CheckingPolicy = DefaultPersistentCheckingPolicy> 233class BasicPersistent; 234template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 235 typename CheckingPolicy = DefaultMemberCheckingPolicy, 236 typename StorageType = DefaultMemberStorage> 237class BasicMember; 238 239} // namespace internal 240 241} // namespace cppgc 242 243#endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ 244