v8  9.4.146 (node 16.13.0)
V8 is Google's open source JavaScript engine
allocation.h
Go to the documentation of this file.
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_ALLOCATION_H_
6 #define INCLUDE_CPPGC_ALLOCATION_H_
7 
8 #include <atomic>
9 #include <cstddef>
10 #include <cstdint>
11 #include <new>
12 #include <type_traits>
13 #include <utility>
14 
15 #include "cppgc/custom-space.h"
16 #include "cppgc/internal/api-constants.h"
17 #include "cppgc/internal/gc-info.h"
18 #include "cppgc/type-traits.h"
19 #include "v8config.h" // NOLINT(build/include_directory)
20 
21 namespace cppgc {
22 
23 /**
24  * AllocationHandle is used to allocate garbage-collected objects.
25  */
26 class AllocationHandle;
27 
28 namespace internal {
29 
31  protected:
32  static inline void MarkObjectAsFullyConstructed(const void* payload) {
33  // See api_constants for an explanation of the constants.
34  std::atomic<uint16_t>* atomic_mutable_bitfield =
35  reinterpret_cast<std::atomic<uint16_t>*>(
36  const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
37  reinterpret_cast<const uint8_t*>(payload) -
38  api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
39  atomic_mutable_bitfield->fetch_or(api_constants::kFullyConstructedBitMask,
40  std::memory_order_release);
41  }
42 
43  template <typename U, typename CustomSpace>
44  struct SpacePolicy {
45  static void* Allocate(AllocationHandle& handle, size_t size) {
46  // Custom space.
47  static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
48  "Custom space must inherit from CustomSpaceBase.");
49  return MakeGarbageCollectedTraitInternal::Allocate(
50  handle, size, internal::GCInfoTrait<U>::Index(),
51  CustomSpace::kSpaceIndex);
52  }
53  };
54 
55  template <typename U>
56  struct SpacePolicy<U, void> {
57  static void* Allocate(AllocationHandle& handle, size_t size) {
58  // Default space.
59  return MakeGarbageCollectedTraitInternal::Allocate(
60  handle, size, internal::GCInfoTrait<U>::Index());
61  }
62  };
63 
64  private:
65  static void* Allocate(cppgc::AllocationHandle& handle, size_t size,
66  GCInfoIndex index);
67  static void* Allocate(cppgc::AllocationHandle& handle, size_t size,
68  GCInfoIndex index, CustomSpaceIndex space_index);
69 
70  friend class HeapObjectHeader;
71 };
72 
73 } // namespace internal
74 
75 /**
76  * Base trait that provides utilities for advancers users that have custom
77  * allocation needs (e.g., overriding size). It's expected that users override
78  * MakeGarbageCollectedTrait (see below) and inherit from
79  * MakeGarbageCollectedTraitBase and make use of the low-level primitives
80  * offered to allocate and construct an object.
81  */
82 template <typename T>
85  private:
86  static_assert(internal::IsGarbageCollectedType<T>::value,
87  "T needs to be a garbage collected object");
88  static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
89  sizeof(T) <=
90  internal::api_constants::kLargeObjectSizeThreshold,
91  "GarbageCollectedMixin may not be a large object");
92 
93  protected:
94  /**
95  * Allocates memory for an object of type T.
96  *
97  * \param handle AllocationHandle identifying the heap to allocate the object
98  * on.
99  * \param size The size that should be reserved for the object.
100  * \returns the memory to construct an object of type T on.
101  */
102  V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
103  static_assert(
104  std::is_base_of<typename T::ParentMostGarbageCollectedType, T>::value,
105  "U of GarbageCollected<U> must be a base of T. Check "
106  "GarbageCollected<T> base class inheritance.");
107  return SpacePolicy<
108  typename internal::GCInfoFolding<
109  T, typename T::ParentMostGarbageCollectedType>::ResultType,
110  typename SpaceTrait<T>::Space>::Allocate(handle, size);
111  }
112 
113  /**
114  * Marks an object as fully constructed, resulting in precise handling by the
115  * garbage collector.
116  *
117  * \param payload The base pointer the object is allocated at.
118  */
119  V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
121  payload);
122  }
123 };
124 
125 /**
126  * Passed to MakeGarbageCollected to specify how many bytes should be appended
127  * to the allocated object.
128  *
129  * Example:
130  * \code
131  * class InlinedArray final : public GarbageCollected<InlinedArray> {
132  * public:
133  * explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
134  * void Trace(Visitor*) const {}
135 
136  * size_t size;
137  * char* byte_array;
138  * };
139  *
140  * auto* inlined_array = MakeGarbageCollected<InlinedArray(
141  * GetAllocationHandle(), AdditionalBytes(4), 4);
142  * for (size_t i = 0; i < 4; i++) {
143  * Process(inlined_array->byte_array[i]);
144  * }
145  * \endcode
146  */
148  constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
149  const size_t value;
150 };
151 
152 /**
153  * Default trait class that specifies how to construct an object of type T.
154  * Advanced users may override how an object is constructed using the utilities
155  * that are provided through MakeGarbageCollectedTraitBase.
156  *
157  * Any trait overriding construction must
158  * - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
159  * - mark the object as fully constructed using
160  * `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
161  */
162 template <typename T>
164  public:
165  template <typename... Args>
166  static T* Call(AllocationHandle& handle, Args&&... args) {
167  void* memory =
168  MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
169  T* object = ::new (memory) T(std::forward<Args>(args)...);
170  MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
171  return object;
172  }
173 
174  template <typename... Args>
175  static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
176  Args&&... args) {
177  void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
178  handle, sizeof(T) + additional_bytes.value);
179  T* object = ::new (memory) T(std::forward<Args>(args)...);
180  MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
181  return object;
182  }
183 };
184 
185 /**
186  * Allows users to specify a post-construction callback for specific types. The
187  * callback is invoked on the instance of type T right after it has been
188  * constructed. This can be useful when the callback requires a
189  * fully-constructed object to be able to dispatch to virtual methods.
190  */
191 template <typename T, typename = void>
193  static void Call(T*) {}
194 };
195 
196 /**
197  * Constructs a managed object of type T where T transitively inherits from
198  * GarbageCollected.
199  *
200  * \param args List of arguments with which an instance of T will be
201  * constructed.
202  * \returns an instance of type T.
203  */
204 template <typename T, typename... Args>
205 T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
206  T* object =
207  MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
208  PostConstructionCallbackTrait<T>::Call(object);
209  return object;
210 }
211 
212 /**
213  * Constructs a managed object of type T where T transitively inherits from
214  * GarbageCollected. Created objects will have additional bytes appended to
215  * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
216  *
217  * \param additional_bytes Denotes how many bytes to append to T.
218  * \param args List of arguments with which an instance of T will be
219  * constructed.
220  * \returns an instance of type T.
221  */
222 template <typename T, typename... Args>
223 T* MakeGarbageCollected(AllocationHandle& handle,
224  AdditionalBytes additional_bytes, Args&&... args) {
225  T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
226  std::forward<Args>(args)...);
227  PostConstructionCallbackTrait<T>::Call(object);
228  return object;
229 }
230 
231 } // namespace cppgc
232 
233 #endif // INCLUDE_CPPGC_ALLOCATION_H_