v8 14.1.146 (node 25.0.0)
V8 is Google's open source JavaScript engine
Loading...
Searching...
No Matches
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#if defined(__has_attribute)
22#if __has_attribute(assume_aligned)
23#define CPPGC_DEFAULT_ALIGNED
24 __attribute__((assume_aligned(api_constants::kDefaultAlignment)))
25#define CPPGC_DOUBLE_WORD_ALIGNED
26 __attribute__((assume_aligned(2 * api_constants::kDefaultAlignment)))
27#endif // __has_attribute(assume_aligned)
28#endif // defined(__has_attribute)
29
30#if !defined(CPPGC_DEFAULT_ALIGNED)
31#define CPPGC_DEFAULT_ALIGNED
32#endif
33
34#if !defined(CPPGC_DOUBLE_WORD_ALIGNED)
35#define CPPGC_DOUBLE_WORD_ALIGNED
36#endif
37
38namespace cppgc {
39
40/**
41 * AllocationHandle is used to allocate garbage-collected objects.
42 */
43class AllocationHandle;
44
45namespace internal {
46
47using AlignVal = std::align_val_t;
48
50 protected:
51 static inline void MarkObjectAsFullyConstructed(const void* payload) {
52 // See api_constants for an explanation of the constants.
53 std::atomic<uint16_t>* atomic_mutable_bitfield =
54 reinterpret_cast<std::atomic<uint16_t>*>(
55 const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
56 reinterpret_cast<const uint8_t*>(payload) -
57 api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
58 // It's safe to split use load+store here (instead of a read-modify-write
59 // operation), since it's guaranteed that this 16-bit bitfield is only
60 // modified by a single thread. This is cheaper in terms of code bloat (on
61 // ARM) and performance.
62 uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed);
63 value |= api_constants::kFullyConstructedBitMask;
64 atomic_mutable_bitfield->store(value, std::memory_order_release);
65 }
66
67 // Dispatch based on compile-time information.
68 //
69 // Default implementation is for a custom space with >`kDefaultAlignment` byte
70 // alignment.
71 template <typename GCInfoType, typename CustomSpace, size_t alignment>
72 struct AllocationDispatcher final {
73 static void* Invoke(AllocationHandle& handle, size_t size) {
74 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
75 "Custom space must inherit from CustomSpaceBase.");
76 static_assert(
77 !CustomSpace::kSupportsCompaction,
78 "Custom spaces that support compaction do not support allocating "
79 "objects with non-default (i.e. word-sized) alignment.");
80 return MakeGarbageCollectedTraitInternal::Allocate(
81 handle, size, static_cast<AlignVal>(alignment),
82 internal::GCInfoTrait<GCInfoType>::Index(), CustomSpace::kSpaceIndex);
83 }
84 };
85
86 // Fast path for regular allocations for the default space with
87 // `kDefaultAlignment` byte alignment.
88 template <typename GCInfoType>
91 final {
95 }
96 };
97
98 // Default space with >`kDefaultAlignment` byte alignment.
99 template <typename GCInfoType, size_t alignment>
100 struct AllocationDispatcher<GCInfoType, void, alignment> final {
101 static void* Invoke(AllocationHandle& handle, size_t size) {
102 return MakeGarbageCollectedTraitInternal::Allocate(
103 handle, size, static_cast<AlignVal>(alignment),
104 internal::GCInfoTrait<GCInfoType>::Index());
105 }
106 };
107
108 // Custom space with `kDefaultAlignment` byte alignment.
109 template <typename GCInfoType, typename CustomSpace>
112 final {
115 "Custom space must inherit from CustomSpaceBase.");
119 }
120 };
121
122 private:
124 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex);
126 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex);
128 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex);
130 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
132
133 friend class HeapObjectHeader;
134};
135
136} // namespace internal
137
138/**
139 * Base trait that provides utilities for advancers users that have custom
140 * allocation needs (e.g., overriding size). It's expected that users override
141 * MakeGarbageCollectedTrait (see below) and inherit from
142 * MakeGarbageCollectedTraitBase and make use of the low-level primitives
143 * offered to allocate and construct an object.
144 */
145template <typename T>
148 private:
149 static_assert(internal::IsGarbageCollectedType<T>::value,
150 "T needs to be a garbage collected object");
151 static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
152 sizeof(T) <=
153 internal::api_constants::kLargeObjectSizeThreshold,
154 "GarbageCollectedMixin may not be a large object");
155
156 protected:
157 /**
158 * Allocates memory for an object of type T.
159 *
160 * \param handle AllocationHandle identifying the heap to allocate the object
161 * on.
162 * \param size The size that should be reserved for the object.
163 * \returns the memory to construct an object of type T on.
164 */
165 V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
166 static_assert(
167 std::is_base_of_v<typename T::ParentMostGarbageCollectedType, T>,
168 "U of GarbageCollected<U> must be a base of T. Check "
169 "GarbageCollected<T> base class inheritance.");
170 static constexpr size_t kWantedAlignment =
171 alignof(T) < internal::api_constants::kDefaultAlignment
172 ? internal::api_constants::kDefaultAlignment
173 : alignof(T);
174 static_assert(
175 kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
176 "Requested alignment larger than alignof(std::max_align_t) bytes. "
177 "Please file a bug to possibly get this restriction lifted.");
178 return AllocationDispatcher<
179 typename internal::GCInfoFolding<
180 T, typename T::ParentMostGarbageCollectedType>::ResultType,
181 typename SpaceTrait<T>::Space, kWantedAlignment>::Invoke(handle, size);
182 }
183
184 /**
185 * Marks an object as fully constructed, resulting in precise handling by the
186 * garbage collector.
187 *
188 * \param payload The base pointer the object is allocated at.
189 */
190 V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
192 payload);
193 }
194};
195
196/**
197 * Passed to MakeGarbageCollected to specify how many bytes should be appended
198 * to the allocated object.
199 *
200 * Example:
201 * \code
202 * class InlinedArray final : public GarbageCollected<InlinedArray> {
203 * public:
204 * explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
205 * void Trace(Visitor*) const {}
206
207 * size_t size;
208 * char* byte_array;
209 * };
210 *
211 * auto* inlined_array = MakeGarbageCollected<InlinedArray(
212 * GetAllocationHandle(), AdditionalBytes(4), 4);
213 * for (size_t i = 0; i < 4; i++) {
214 * Process(inlined_array->byte_array[i]);
215 * }
216 * \endcode
217 */
219 constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
221};
222
223/**
224 * Default trait class that specifies how to construct an object of type T.
225 * Advanced users may override how an object is constructed using the utilities
226 * that are provided through MakeGarbageCollectedTraitBase.
227 *
228 * Any trait overriding construction must
229 * - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
230 * - mark the object as fully constructed using
231 * `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
232 */
233template <typename T>
235 public:
236 template <typename... Args>
237 static T* Call(AllocationHandle& handle, Args&&... args) {
238 void* memory =
239 MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
240 T* object = ::new (memory) T(std::forward<Args>(args)...);
241 MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
242 return object;
243 }
244
245 template <typename... Args>
246 static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
247 Args&&... args) {
248 void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
249 handle, sizeof(T) + additional_bytes.value);
250 T* object = ::new (memory) T(std::forward<Args>(args)...);
251 MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
252 return object;
253 }
254};
255
256/**
257 * Allows users to specify a post-construction callback for specific types. The
258 * callback is invoked on the instance of type T right after it has been
259 * constructed. This can be useful when the callback requires a
260 * fully-constructed object to be able to dispatch to virtual methods.
261 */
262template <typename T, typename = void>
264 static void Call(T*) {}
265};
266
267/**
268 * Constructs a managed object of type T where T transitively inherits from
269 * GarbageCollected.
270 *
271 * \param args List of arguments with which an instance of T will be
272 * constructed.
273 * \returns an instance of type T.
274 */
275template <typename T, typename... Args>
276V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
277 T* object =
278 MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
279 PostConstructionCallbackTrait<T>::Call(object);
280 return object;
281}
282
283/**
284 * Constructs a managed object of type T where T transitively inherits from
285 * GarbageCollected. Created objects will have additional bytes appended to
286 * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
287 *
288 * \param additional_bytes Denotes how many bytes to append to T.
289 * \param args List of arguments with which an instance of T will be
290 * constructed.
291 * \returns an instance of type T.
292 */
293template <typename T, typename... Args>
294V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
295 AdditionalBytes additional_bytes,
296 Args&&... args) {
297 T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
298 std::forward<Args>(args)...);
299 PostConstructionCallbackTrait<T>::Call(object);
300 return object;
301}
302
303} // namespace cppgc
304
305#undef CPPGC_DEFAULT_ALIGNED
306#undef CPPGC_DOUBLE_WORD_ALIGNED
307
308#endif // INCLUDE_CPPGC_ALLOCATION_H_
#define CPPGC_DEFAULT_ALIGNED
Definition allocation.h:31
#define CPPGC_DOUBLE_WORD_ALIGNED
Definition allocation.h:35
static V8_INLINE void MarkObjectAsFullyConstructed(const void *payload)
Definition allocation.h:190
static V8_INLINE void * Allocate(AllocationHandle &handle, size_t size)
Definition allocation.h:165
static T * Call(AllocationHandle &handle, AdditionalBytes additional_bytes, Args &&... args)
Definition allocation.h:246
static T * Call(AllocationHandle &handle, Args &&... args)
Definition allocation.h:237
static void MarkObjectAsFullyConstructed(const void *payload)
Definition allocation.h:51
V8_INLINE T * MakeGarbageCollected(AllocationHandle &handle, Args &&... args)
Definition allocation.h:276
V8_INLINE T * MakeGarbageCollected(AllocationHandle &handle, AdditionalBytes additional_bytes, Args &&... args)
Definition allocation.h:294
constexpr AdditionalBytes(size_t bytes)
Definition allocation.h:219
Definition allocation.h:263
static void Call(T *)
Definition allocation.h:264
static void * Invoke(AllocationHandle &handle, size_t size)
Definition allocation.h:73
#define V8_EXPORT
Definition v8config.h:860
#define V8_INLINE
Definition v8config.h:513