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 <limits>
12#include <new>
13#include <type_traits>
14#include <utility>
15
16#include "cppgc/custom-space.h"
19#include "cppgc/type-traits.h"
20#include "v8config.h" // NOLINT(build/include_directory)
21
22#if defined(__has_attribute)
23#if __has_attribute(assume_aligned)
24#define CPPGC_DEFAULT_ALIGNED \
25 __attribute__((assume_aligned(api_constants::kDefaultAlignment)))
26#define CPPGC_DOUBLE_WORD_ALIGNED \
27 __attribute__((assume_aligned(2 * api_constants::kDefaultAlignment)))
28#endif // __has_attribute(assume_aligned)
29#endif // defined(__has_attribute)
30
31#if !defined(CPPGC_DEFAULT_ALIGNED)
32#define CPPGC_DEFAULT_ALIGNED
33#endif
34
35#if !defined(CPPGC_DOUBLE_WORD_ALIGNED)
36#define CPPGC_DOUBLE_WORD_ALIGNED
37#endif
38
39namespace cppgc {
40
44class AllocationHandle;
45
47
48namespace internal {
49
50using AlignVal = std::align_val_t;
51
53 protected:
54 enum class CanContainMixins { kNo, kYes };
55
56 static inline void MarkObjectAsFullyConstructed(const void* payload) {
57 // See api_constants for an explanation of the constants.
58 std::atomic_ref<uint16_t> atomic_mutable_bitfield(
59 *const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
60 reinterpret_cast<const uint8_t*>(payload) -
61 api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
62 // It's safe to split use load+store here (instead of a read-modify-write
63 // operation), since it's guaranteed that this 16-bit bitfield is only
64 // modified by a single thread. This is cheaper in terms of code bloat (on
65 // ARM) and performance.
66 uint16_t value = atomic_mutable_bitfield.load(std::memory_order_relaxed);
67 value |= api_constants::kFullyConstructedBitMask;
68 atomic_mutable_bitfield.store(value, std::memory_order_release);
69 }
70
71 // Dispatch based on compile-time information.
72 //
73 // Default implementation is for a custom space with >`kDefaultAlignment` byte
74 // alignment.
75 template <typename GCInfoType, typename CustomSpace, size_t alignment,
76 CanContainMixins contain_mixins>
77 struct AllocationDispatcher final {
78 static void* Invoke(AllocationHandle& handle, size_t size) {
79 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
80 "Custom space must inherit from CustomSpaceBase.");
81 static_assert(
83 "Custom spaces that support compaction do not support allocating "
84 "objects with non-default (i.e. word-sized) alignment.");
85 if constexpr (contain_mixins == CanContainMixins::kYes) {
86 return MakeGarbageCollectedTraitInternal::Allocate(
87 handle, size, static_cast<AlignVal>(alignment),
89 CustomSpace::kSpaceIndex, kMixinTag);
90 } else {
91 return MakeGarbageCollectedTraitInternal::Allocate(
92 handle, size, static_cast<AlignVal>(alignment),
94 CustomSpace::kSpaceIndex);
95 }
96 }
97 };
98
99 // Fast path for regular allocations for the default space with
100 // `kDefaultAlignment` byte alignment.
101 template <typename GCInfoType, CanContainMixins contain_mixins>
102 struct AllocationDispatcher<GCInfoType, void,
103 api_constants::kDefaultAlignment, contain_mixins>
104 final {
105 static void* Invoke(AllocationHandle& handle, size_t size) {
106 if constexpr (contain_mixins == CanContainMixins::kYes) {
107 return MakeGarbageCollectedTraitInternal::Allocate(
109 kMixinTag);
110 } else {
111 return MakeGarbageCollectedTraitInternal::Allocate(
113 }
114 }
115 };
116
117 // Default space with >`kDefaultAlignment` byte alignment.
118 template <typename GCInfoType, size_t alignment,
119 CanContainMixins contain_mixins>
120 struct AllocationDispatcher<GCInfoType, void, alignment, contain_mixins>
121 final {
122 static void* Invoke(AllocationHandle& handle, size_t size) {
123 if constexpr (contain_mixins == CanContainMixins::kYes) {
124 return MakeGarbageCollectedTraitInternal::Allocate(
125 handle, size, static_cast<AlignVal>(alignment),
127 } else {
128 return MakeGarbageCollectedTraitInternal::Allocate(
129 handle, size, static_cast<AlignVal>(alignment),
131 }
132 }
133 };
134
135 // Custom space with `kDefaultAlignment` byte alignment.
136 template <typename GCInfoType, typename CustomSpace,
137 CanContainMixins contain_mixins>
139 api_constants::kDefaultAlignment, contain_mixins>
140 final {
141 static void* Invoke(AllocationHandle& handle, size_t size) {
142 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
143 "Custom space must inherit from CustomSpaceBase.");
144 if constexpr (contain_mixins == CanContainMixins::kYes) {
145 return MakeGarbageCollectedTraitInternal::Allocate(
147 CustomSpace::kSpaceIndex, kMixinTag);
148 } else {
149 return MakeGarbageCollectedTraitInternal::Allocate(
151 CustomSpace::kSpaceIndex);
152 }
153 }
154 };
155
156 private:
157 inline const static struct MixinTag {
158 } kMixinTag;
159
161 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex);
163 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex);
165 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex);
167 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
170 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, MixinTag);
172 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex, MixinTag);
174 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex,
175 MixinTag);
177 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
178 CustomSpaceIndex, MixinTag);
179
180 friend class HeapObjectHeader;
181};
182
183} // namespace internal
184
192template <typename T>
195 private:
197 "T needs to be a garbage collected object");
198 static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
199 sizeof(T) <=
200 internal::api_constants::kLargeObjectSizeThreshold,
201 "GarbageCollectedMixin may not be a large object");
202
203 protected:
212 V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
213 static_assert(
214 std::is_base_of_v<typename T::ParentMostGarbageCollectedType, T>,
215 "U of GarbageCollected<U> must be a base of T. Check "
216 "GarbageCollected<T> base class inheritance.");
217 static constexpr size_t kWantedAlignment =
218 alignof(T) < internal::api_constants::kDefaultAlignment
219 ? internal::api_constants::kDefaultAlignment
220 : alignof(T);
221 constexpr CanContainMixins kMayContainMixins =
222 std::is_base_of_v<GarbageCollectedMixin, T> ? CanContainMixins::kYes
223 : CanContainMixins::kNo;
224 static_assert(
225 kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
226 "Requested alignment larger than alignof(std::max_align_t) bytes. "
227 "Please file a bug to possibly get this restriction lifted.");
230 T, typename T::ParentMostGarbageCollectedType>::ResultType,
231 typename SpaceTrait<T>::Space, kWantedAlignment,
232 kMayContainMixins>::Invoke(handle, size);
233 }
234
241 V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
243 payload);
244 }
245};
246
270 constexpr explicit AdditionalBytes(uint32_t bytes) : value(bytes) {}
271 const uint32_t value;
272};
273
284template <typename T>
286 public:
287 template <typename... Args>
288 static T* Call(AllocationHandle& handle, Args&&... args) {
289 static_assert(sizeof(T) <= std::numeric_limits<uint32_t>::max());
290 void* memory =
292 T* object = ::new (memory) T(std::forward<Args>(args)...);
294 return object;
295 }
296
297 template <typename... Args>
298 static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
299 Args&&... args) {
300 static_assert(sizeof(T) <= std::numeric_limits<uint32_t>::max());
301 const size_t size_to_allocate = sizeof(T) + additional_bytes.value;
302 // On 64-bit systems, since sizeof(T) and additional_bytes.value are both at
303 // most 32 bits, we know that their sum can't overflow. On 32-bit systems,
304 // we need to check it.
305#if !defined(V8_HOST_ARCH_64_BIT)
306 CPPGC_CHECK(size_to_allocate > additional_bytes.value);
307#endif
308 void* memory =
309 MakeGarbageCollectedTraitBase<T>::Allocate(handle, size_to_allocate);
310 T* object = ::new (memory) T(std::forward<Args>(args)...);
312 return object;
313 }
314};
315
322template <typename T, typename = void>
324 static void Call(T*) {}
325};
326
335template <typename T, typename... Args>
336V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
337 T* object =
338 MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
340 return object;
341}
342
353template <typename T, typename... Args>
354V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
355 AdditionalBytes additional_bytes,
356 Args&&... args) {
357 T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
358 std::forward<Args>(args)...);
360 return object;
361}
362
363} // namespace cppgc
364
365#undef CPPGC_DEFAULT_ALIGNED
366#undef CPPGC_DOUBLE_WORD_ALIGNED
367
368#endif // INCLUDE_CPPGC_ALLOCATION_H_
#define CPPGC_DEFAULT_ALIGNED
Definition: allocation.h:32
#define CPPGC_DOUBLE_WORD_ALIGNED
Definition: allocation.h:36
Definition: custom-space.h:49
static constexpr bool kSupportsCompaction
Definition: custom-space.h:55
Definition: garbage-collected.h:93
Definition: allocation.h:194
static void * Allocate(AllocationHandle &handle, size_t size)
Definition: allocation.h:212
static void MarkObjectAsFullyConstructed(const void *payload)
Definition: allocation.h:241
Definition: allocation.h:285
static T * Call(AllocationHandle &handle, Args &&... args)
Definition: allocation.h:288
static T * Call(AllocationHandle &handle, AdditionalBytes additional_bytes, Args &&... args)
Definition: allocation.h:298
friend class HeapObjectHeader
Definition: allocation.h:180
static void MarkObjectAsFullyConstructed(const void *payload)
Definition: allocation.h:56
#define CPPGC_CHECK(condition)
Definition: logging.h:45
uint16_t GCInfoIndex
Definition: gc-info.h:20
std::align_val_t AlignVal
Definition: allocation.h:50
Definition: allocation.h:39
T * MakeGarbageCollected(AllocationHandle &handle, Args &&... args)
Definition: allocation.h:336
Definition: allocation.h:269
const uint32_t value
Definition: allocation.h:271
constexpr AdditionalBytes(uint32_t bytes)
Definition: allocation.h:270
Definition: custom-space.h:15
Definition: allocation.h:323
static void Call(T *)
Definition: allocation.h:324
void Space
Definition: custom-space.h:70
Definition: gc-info.h:179
Definition: gc-info.h:145
Definition: type-traits.h:99
static void * Invoke(AllocationHandle &handle, size_t size)
Definition: allocation.h:122
static void * Invoke(AllocationHandle &handle, size_t size)
Definition: allocation.h:78
#define V8_EXPORT
Definition: v8config.h:874
#define V8_INLINE
Definition: v8config.h:518