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_HEAP_CONSISTENCY_H_ 6#define INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ 7 8#include <cstddef> 9 10#include "cppgc/internal/write-barrier.h" 11#include "cppgc/macros.h" 12#include "cppgc/member.h" 13#include "cppgc/trace-trait.h" 14#include "v8config.h" // NOLINT(build/include_directory) 15 16namespace cppgc { 17 18class HeapHandle; 19 20namespace subtle { 21 22/** 23 * **DO NOT USE: Use the appropriate managed types.** 24 * 25 * Consistency helpers that aid in maintaining a consistent internal state of 26 * the garbage collector. 27 */ 28class HeapConsistency final { 29 public: 30 using WriteBarrierParams = internal::WriteBarrier::Params; 31 using WriteBarrierType = internal::WriteBarrier::Type; 32 33 /** 34 * Gets the required write barrier type for a specific write. 35 * 36 * \param slot Slot containing the pointer to the object. The slot itself 37 * must reside in an object that has been allocated using 38 * `MakeGarbageCollected()`. 39 * \param value The pointer to the object. May be an interior pointer to an 40 * interface of the actual object. 41 * \param params Parameters that may be used for actual write barrier calls. 42 * Only filled if return value indicates that a write barrier is needed. The 43 * contents of the `params` are an implementation detail. 44 * \returns whether a write barrier is needed and which barrier to invoke. 45 */ 46 static V8_INLINE WriteBarrierType GetWriteBarrierType( 47 const void* slot, const void* value, WriteBarrierParams& params) { 48 return internal::WriteBarrier::GetWriteBarrierType(slot, value, params); 49 } 50 51 /** 52 * Gets the required write barrier type for a specific write. This override is 53 * only used for all the BasicMember types. 54 * 55 * \param slot Slot containing the pointer to the object. The slot itself 56 * must reside in an object that has been allocated using 57 * `MakeGarbageCollected()`. 58 * \param value The pointer to the object held via `BasicMember`. 59 * \param params Parameters that may be used for actual write barrier calls. 60 * Only filled if return value indicates that a write barrier is needed. The 61 * contents of the `params` are an implementation detail. 62 * \returns whether a write barrier is needed and which barrier to invoke. 63 */ 64 template <typename T, typename WeaknessTag, typename WriteBarrierPolicy, 65 typename CheckingPolicy, typename StorageType> 66 static V8_INLINE WriteBarrierType GetWriteBarrierType( 67 const internal::BasicMember<T, WeaknessTag, WriteBarrierPolicy, 68 CheckingPolicy, StorageType>& value, 69 WriteBarrierParams& params) { 70 return internal::WriteBarrier::GetWriteBarrierType( 71 value.GetRawSlot(), value.GetRawStorage(), params); 72 } 73 74 /** 75 * Gets the required write barrier type for a specific write. 76 * 77 * \param slot Slot to some part of an object. The object must not necessarily 78 have been allocated using `MakeGarbageCollected()` but can also live 79 off-heap or on stack. 80 * \param params Parameters that may be used for actual write barrier calls. 81 * Only filled if return value indicates that a write barrier is needed. The 82 * contents of the `params` are an implementation detail. 83 * \param callback Callback returning the corresponding heap handle. The 84 * callback is only invoked if the heap cannot otherwise be figured out. The 85 * callback must not allocate. 86 * \returns whether a write barrier is needed and which barrier to invoke. 87 */ 88 template <typename HeapHandleCallback> 89 static V8_INLINE WriteBarrierType 90 GetWriteBarrierType(const void* slot, WriteBarrierParams& params, 91 HeapHandleCallback callback) { 92 return internal::WriteBarrier::GetWriteBarrierType(slot, params, callback); 93 } 94 95 /** 96 * Gets the required write barrier type for a specific write. 97 * This version is meant to be used in conjunction with with a marking write 98 * barrier barrier which doesn't consider the slot. 99 * 100 * \param value The pointer to the object. May be an interior pointer to an 101 * interface of the actual object. 102 * \param params Parameters that may be used for actual write barrier calls. 103 * Only filled if return value indicates that a write barrier is needed. The 104 * contents of the `params` are an implementation detail. 105 * \returns whether a write barrier is needed and which barrier to invoke. 106 */ 107 static V8_INLINE WriteBarrierType 108 GetWriteBarrierType(const void* value, WriteBarrierParams& params) { 109 return internal::WriteBarrier::GetWriteBarrierType(value, params); 110 } 111 112 /** 113 * Conservative Dijkstra-style write barrier that processes an object if it 114 * has not yet been processed. 115 * 116 * \param params The parameters retrieved from `GetWriteBarrierType()`. 117 * \param object The pointer to the object. May be an interior pointer to a 118 * an interface of the actual object. 119 */ 120 static V8_INLINE void DijkstraWriteBarrier(const WriteBarrierParams& params, 121 const void* object) { 122 internal::WriteBarrier::DijkstraMarkingBarrier(params, object); 123 } 124 125 /** 126 * Conservative Dijkstra-style write barrier that processes a range of 127 * elements if they have not yet been processed. 128 * 129 * \param params The parameters retrieved from `GetWriteBarrierType()`. 130 * \param first_element Pointer to the first element that should be processed. 131 * The slot itself must reside in an object that has been allocated using 132 * `MakeGarbageCollected()`. 133 * \param element_size Size of the element in bytes. 134 * \param number_of_elements Number of elements that should be processed, 135 * starting with `first_element`. 136 * \param trace_callback The trace callback that should be invoked for each 137 * element if necessary. 138 */ 139 static V8_INLINE void DijkstraWriteBarrierRange( 140 const WriteBarrierParams& params, const void* first_element, 141 size_t element_size, size_t number_of_elements, 142 TraceCallback trace_callback) { 143 internal::WriteBarrier::DijkstraMarkingBarrierRange( 144 params, first_element, element_size, number_of_elements, 145 trace_callback); 146 } 147 148 /** 149 * Steele-style write barrier that re-processes an object if it has already 150 * been processed. 151 * 152 * \param params The parameters retrieved from `GetWriteBarrierType()`. 153 * \param object The pointer to the object which must point to an object that 154 * has been allocated using `MakeGarbageCollected()`. Interior pointers are 155 * not supported. 156 */ 157 static V8_INLINE void SteeleWriteBarrier(const WriteBarrierParams& params, 158 const void* object) { 159 internal::WriteBarrier::SteeleMarkingBarrier(params, object); 160 } 161 162 /** 163 * Generational barrier for maintaining consistency when running with multiple 164 * generations. 165 * 166 * \param params The parameters retrieved from `GetWriteBarrierType()`. 167 * \param slot Slot containing the pointer to the object. The slot itself 168 * must reside in an object that has been allocated using 169 * `MakeGarbageCollected()`. 170 */ 171 static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params, 172 const void* slot) { 173 internal::WriteBarrier::GenerationalBarrier< 174 internal::WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, 175 slot); 176 } 177 178 /** 179 * Generational barrier for maintaining consistency when running with multiple 180 * generations. This version is used when slot contains uncompressed pointer. 181 * 182 * \param params The parameters retrieved from `GetWriteBarrierType()`. 183 * \param slot Uncompressed slot containing the direct pointer to the object. 184 * The slot itself must reside in an object that has been allocated using 185 * `MakeGarbageCollected()`. 186 */ 187 static V8_INLINE void GenerationalBarrierForUncompressedSlot( 188 const WriteBarrierParams& params, const void* uncompressed_slot) { 189 internal::WriteBarrier::GenerationalBarrier< 190 internal::WriteBarrier::GenerationalBarrierType:: 191 kPreciseUncompressedSlot>(params, uncompressed_slot); 192 } 193 194 /** 195 * Generational barrier for source object that may contain outgoing pointers 196 * to objects in young generation. 197 * 198 * \param params The parameters retrieved from `GetWriteBarrierType()`. 199 * \param inner_pointer Pointer to the source object. 200 */ 201 static V8_INLINE void GenerationalBarrierForSourceObject( 202 const WriteBarrierParams& params, const void* inner_pointer) { 203 internal::WriteBarrier::GenerationalBarrier< 204 internal::WriteBarrier::GenerationalBarrierType::kImpreciseSlot>( 205 params, inner_pointer); 206 } 207 208 private: 209 HeapConsistency() = delete; 210}; 211 212/** 213 * Disallows garbage collection finalizations. Any garbage collection triggers 214 * result in a crash when in this scope. 215 * 216 * Note that the garbage collector already covers paths that can lead to garbage 217 * collections, so user code does not require checking 218 * `IsGarbageCollectionAllowed()` before allocations. 219 */ 220class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final { 221 CPPGC_STACK_ALLOCATED(); 222 223 public: 224 /** 225 * \returns whether garbage collections are currently allowed. 226 */ 227 static bool IsGarbageCollectionAllowed(HeapHandle& heap_handle); 228 229 /** 230 * Enters a disallow garbage collection scope. Must be paired with `Leave()`. 231 * Prefer a scope instance of `DisallowGarbageCollectionScope`. 232 * 233 * \param heap_handle The corresponding heap. 234 */ 235 static void Enter(HeapHandle& heap_handle); 236 237 /** 238 * Leaves a disallow garbage collection scope. Must be paired with `Enter()`. 239 * Prefer a scope instance of `DisallowGarbageCollectionScope`. 240 * 241 * \param heap_handle The corresponding heap. 242 */ 243 static void Leave(HeapHandle& heap_handle); 244 245 /** 246 * Constructs a scoped object that automatically enters and leaves a disallow 247 * garbage collection scope based on its lifetime. 248 * 249 * \param heap_handle The corresponding heap. 250 */ 251 explicit DisallowGarbageCollectionScope(HeapHandle& heap_handle); 252 ~DisallowGarbageCollectionScope(); 253 254 DisallowGarbageCollectionScope(const DisallowGarbageCollectionScope&) = 255 delete; 256 DisallowGarbageCollectionScope& operator=( 257 const DisallowGarbageCollectionScope&) = delete; 258 259 private: 260 HeapHandle& heap_handle_; 261}; 262 263/** 264 * Avoids invoking garbage collection finalizations. Already running garbage 265 * collection phase are unaffected by this scope. 266 * 267 * Should only be used temporarily as the scope has an impact on memory usage 268 * and follow up garbage collections. 269 */ 270class V8_EXPORT V8_NODISCARD NoGarbageCollectionScope final { 271 CPPGC_STACK_ALLOCATED(); 272 273 public: 274 /** 275 * Enters a no garbage collection scope. Must be paired with `Leave()`. Prefer 276 * a scope instance of `NoGarbageCollectionScope`. 277 * 278 * \param heap_handle The corresponding heap. 279 */ 280 static void Enter(HeapHandle& heap_handle); 281 282 /** 283 * Leaves a no garbage collection scope. Must be paired with `Enter()`. Prefer 284 * a scope instance of `NoGarbageCollectionScope`. 285 * 286 * \param heap_handle The corresponding heap. 287 */ 288 static void Leave(HeapHandle& heap_handle); 289 290 /** 291 * Constructs a scoped object that automatically enters and leaves a no 292 * garbage collection scope based on its lifetime. 293 * 294 * \param heap_handle The corresponding heap. 295 */ 296 explicit NoGarbageCollectionScope(HeapHandle& heap_handle); 297 ~NoGarbageCollectionScope(); 298 299 NoGarbageCollectionScope(const NoGarbageCollectionScope&) = delete; 300 NoGarbageCollectionScope& operator=(const NoGarbageCollectionScope&) = delete; 301 302 private: 303 HeapHandle& heap_handle_; 304}; 305 306} // namespace subtle 307} // namespace cppgc 308 309#endif // INCLUDE_CPPGC_HEAP_CONSISTENCY_H_ 310