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 
16 namespace cppgc {
17 
18 class HeapHandle;
19 
20 namespace 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  */
28 class 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    */
GetWriteBarrierType( const void* slot, const void* value, WriteBarrierParams& params)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>
GetWriteBarrierType( const internal::BasicMember<T, WeaknessTag, WriteBarrierPolicy, CheckingPolicy, StorageType>& value, WriteBarrierParams& params)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
GetWriteBarrierType(const void* slot, WriteBarrierParams& params, HeapHandleCallback callback)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
GetWriteBarrierType(const void* value, WriteBarrierParams& params)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    */
DijkstraWriteBarrier(const WriteBarrierParams& params, const void* object)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    */
DijkstraWriteBarrierRange( const WriteBarrierParams& params, const void* first_element, size_t element_size, size_t number_of_elements, TraceCallback trace_callback)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    */
SteeleWriteBarrier(const WriteBarrierParams& params, const void* object)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    */
GenerationalBarrier(const WriteBarrierParams& params, const void* slot)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    */
GenerationalBarrierForUncompressedSlot( const WriteBarrierParams& params, const void* uncompressed_slot)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    */
GenerationalBarrierForSourceObject( const WriteBarrierParams& params, const void* inner_pointer)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  */
220 class 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  */
270 class 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