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 18 namespace cppgc { 19 namespace internal { 20 21 class HeapBase; 22 class PersistentRegion; 23 class CrossThreadPersistentRegion; 24 25 // Tags to distinguish between strong and weak member types. 26 class StrongMemberTag; 27 class WeakMemberTag; 28 class UntracedMemberTag; 29 30 struct DijkstraWriteBarrierPolicy { InitializingBarriercppgc::internal::DijkstraWriteBarrierPolicy31 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> AssigningBarriercppgc::internal::DijkstraWriteBarrierPolicy37 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> AssigningBarriercppgc::internal::DijkstraWriteBarrierPolicy50 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> AssigningBarriercppgc::internal::DijkstraWriteBarrierPolicy67 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: WriteBarriercppgc::internal::DijkstraWriteBarrierPolicy85 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 102 struct NoWriteBarrierPolicy { InitializingBarriercppgc::internal::NoWriteBarrierPolicy103 V8_INLINE static void InitializingBarrier(const void*, const void*) {} 104 template <WriteBarrierSlotType> AssigningBarriercppgc::internal::NoWriteBarrierPolicy105 V8_INLINE static void AssigningBarrier(const void*, const void*) {} 106 template <WriteBarrierSlotType, typename MemberStorage> AssigningBarriercppgc::internal::NoWriteBarrierPolicy107 V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {} 108 }; 109 110 class 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 118 template <bool kCheckOffHeapAssignments> 119 class V8_EXPORT SameThreadEnabledCheckingPolicy 120 : private SameThreadEnabledCheckingPolicyBase { 121 protected: 122 template <typename T> CheckPointer(const T* ptr)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 { Callcppgc::internal::SameThreadEnabledCheckingPolicy::CheckPointersImplTrampoline132 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> { Callcppgc::internal::SameThreadEnabledCheckingPolicy::CheckPointersImplTrampoline139 static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) { 140 policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV<T>, 141 kCheckOffHeapAssignments); 142 } 143 }; 144 }; 145 146 class DisabledCheckingPolicy { 147 protected: CheckPointer(const void*)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. 154 using DefaultMemberCheckingPolicy = 155 SameThreadEnabledCheckingPolicy<false /* kCheckOffHeapAssignments*/>; 156 using DefaultPersistentCheckingPolicy = 157 SameThreadEnabledCheckingPolicy<true /* kCheckOffHeapAssignments*/>; 158 #else // !DEBUG 159 using DefaultMemberCheckingPolicy = DisabledCheckingPolicy; 160 using 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. 165 using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy; 166 167 class KeepLocationPolicy { 168 public: Location() const169 constexpr const SourceLocation& Location() const { return location_; } 170 171 protected: 172 constexpr KeepLocationPolicy() = default; KeepLocationPolicy(const SourceLocation& location)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 188 class IgnoreLocationPolicy { 189 public: Location() const190 constexpr SourceLocation Location() const { return {}; } 191 192 protected: 193 constexpr IgnoreLocationPolicy() = default; IgnoreLocationPolicy(const SourceLocation&)194 constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {} 195 }; 196 197 #if CPPGC_SUPPORTS_OBJECT_NAMES 198 using DefaultLocationPolicy = KeepLocationPolicy; 199 #else 200 using DefaultLocationPolicy = IgnoreLocationPolicy; 201 #endif 202 203 struct StrongPersistentPolicy { 204 using IsStrongPersistent = std::true_type; 205 static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); 206 }; 207 208 struct WeakPersistentPolicy { 209 using IsStrongPersistent = std::false_type; 210 static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object); 211 }; 212 213 struct StrongCrossThreadPersistentPolicy { 214 using IsStrongPersistent = std::true_type; 215 static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion( 216 const void* object); 217 }; 218 219 struct 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. 226 template <typename T, typename WeaknessPolicy, 227 typename LocationPolicy = DefaultLocationPolicy, 228 typename CheckingPolicy = DefaultCrossThreadPersistentCheckingPolicy> 229 class BasicCrossThreadPersistent; 230 template <typename T, typename WeaknessPolicy, 231 typename LocationPolicy = DefaultLocationPolicy, 232 typename CheckingPolicy = DefaultPersistentCheckingPolicy> 233 class BasicPersistent; 234 template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 235 typename CheckingPolicy = DefaultMemberCheckingPolicy, 236 typename StorageType = DefaultMemberStorage> 237 class BasicMember; 238 239 } // namespace internal 240 241 } // namespace cppgc 242 243 #endif // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_ 244