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