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"
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
43class AllocationHandle;
44
46
47namespace internal {
48
49using AlignVal = std::align_val_t;
50
52 protected:
53 enum class CanContainMixins { kNo, kYes };
54
55 static inline void MarkObjectAsFullyConstructed(const void* payload) {
56 // See api_constants for an explanation of the constants.
57 std::atomic_ref<uint16_t> atomic_mutable_bitfield(
58 *const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
59 reinterpret_cast<const uint8_t*>(payload) -
60 api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
61 // It's safe to split use load+store here (instead of a read-modify-write
62 // operation), since it's guaranteed that this 16-bit bitfield is only
63 // modified by a single thread. This is cheaper in terms of code bloat (on
64 // ARM) and performance.
65 uint16_t value = atomic_mutable_bitfield.load(std::memory_order_relaxed);
66 value |= api_constants::kFullyConstructedBitMask;
67 atomic_mutable_bitfield.store(value, std::memory_order_release);
68 }
69
70 // Dispatch based on compile-time information.
71 //
72 // Default implementation is for a custom space with >`kDefaultAlignment` byte
73 // alignment.
74 template <typename GCInfoType, typename CustomSpace, size_t alignment,
75 CanContainMixins contain_mixins>
76 struct AllocationDispatcher final {
77 static void* Invoke(AllocationHandle& handle, size_t size) {
78 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
79 "Custom space must inherit from CustomSpaceBase.");
80 static_assert(
82 "Custom spaces that support compaction do not support allocating "
83 "objects with non-default (i.e. word-sized) alignment.");
84 if constexpr (contain_mixins == CanContainMixins::kYes) {
85 return MakeGarbageCollectedTraitInternal::Allocate(
86 handle, size, static_cast<AlignVal>(alignment),
88 CustomSpace::kSpaceIndex, kMixinTag);
89 } else {
90 return MakeGarbageCollectedTraitInternal::Allocate(
91 handle, size, static_cast<AlignVal>(alignment),
93 CustomSpace::kSpaceIndex);
94 }
95 }
96 };
97
98 // Fast path for regular allocations for the default space with
99 // `kDefaultAlignment` byte alignment.
100 template <typename GCInfoType, CanContainMixins contain_mixins>
101 struct AllocationDispatcher<GCInfoType, void,
102 api_constants::kDefaultAlignment, contain_mixins>
103 final {
104 static void* Invoke(AllocationHandle& handle, size_t size) {
105 if constexpr (contain_mixins == CanContainMixins::kYes) {
106 return MakeGarbageCollectedTraitInternal::Allocate(
108 kMixinTag);
109 } else {
110 return MakeGarbageCollectedTraitInternal::Allocate(
112 }
113 }
114 };
115
116 // Default space with >`kDefaultAlignment` byte alignment.
117 template <typename GCInfoType, size_t alignment,
118 CanContainMixins contain_mixins>
119 struct AllocationDispatcher<GCInfoType, void, alignment, contain_mixins>
120 final {
121 static void* Invoke(AllocationHandle& handle, size_t size) {
122 if constexpr (contain_mixins == CanContainMixins::kYes) {
123 return MakeGarbageCollectedTraitInternal::Allocate(
124 handle, size, static_cast<AlignVal>(alignment),
126 } else {
127 return MakeGarbageCollectedTraitInternal::Allocate(
128 handle, size, static_cast<AlignVal>(alignment),
130 }
131 }
132 };
133
134 // Custom space with `kDefaultAlignment` byte alignment.
135 template <typename GCInfoType, typename CustomSpace,
136 CanContainMixins contain_mixins>
138 api_constants::kDefaultAlignment, contain_mixins>
139 final {
140 static void* Invoke(AllocationHandle& handle, size_t size) {
141 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
142 "Custom space must inherit from CustomSpaceBase.");
143 if constexpr (contain_mixins == CanContainMixins::kYes) {
144 return MakeGarbageCollectedTraitInternal::Allocate(
146 CustomSpace::kSpaceIndex, kMixinTag);
147 } else {
148 return MakeGarbageCollectedTraitInternal::Allocate(
150 CustomSpace::kSpaceIndex);
151 }
152 }
153 };
154
155 private:
156 inline const static struct MixinTag {
157 } kMixinTag;
158
160 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex);
162 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex);
164 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex);
166 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
169 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, MixinTag);
171 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex, MixinTag);
173 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex,
174 MixinTag);
176 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
177 CustomSpaceIndex, MixinTag);
178
179 friend class HeapObjectHeader;
180};
181
182} // namespace internal
183
191template <typename T>
194 private:
196 "T needs to be a garbage collected object");
197 static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
198 sizeof(T) <=
199 internal::api_constants::kLargeObjectSizeThreshold,
200 "GarbageCollectedMixin may not be a large object");
201
202 protected:
211 V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
212 static_assert(
213 std::is_base_of_v<typename T::ParentMostGarbageCollectedType, T>,
214 "U of GarbageCollected<U> must be a base of T. Check "
215 "GarbageCollected<T> base class inheritance.");
216 static constexpr size_t kWantedAlignment =
217 alignof(T) < internal::api_constants::kDefaultAlignment
218 ? internal::api_constants::kDefaultAlignment
219 : alignof(T);
220 constexpr CanContainMixins kMayContainMixins =
221 std::is_base_of_v<GarbageCollectedMixin, T> ? CanContainMixins::kYes
222 : CanContainMixins::kNo;
223 static_assert(
224 kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
225 "Requested alignment larger than alignof(std::max_align_t) bytes. "
226 "Please file a bug to possibly get this restriction lifted.");
229 T, typename T::ParentMostGarbageCollectedType>::ResultType,
230 typename SpaceTrait<T>::Space, kWantedAlignment,
231 kMayContainMixins>::Invoke(handle, size);
232 }
233
240 V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
242 payload);
243 }
244};
245
269 constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
270 const size_t value;
271};
272
283template <typename T>
285 public:
286 template <typename... Args>
287 static T* Call(AllocationHandle& handle, Args&&... args) {
288 void* memory =
290 T* object = ::new (memory) T(std::forward<Args>(args)...);
292 return object;
293 }
294
295 template <typename... Args>
296 static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
297 Args&&... args) {
299 handle, sizeof(T) + additional_bytes.value);
300 T* object = ::new (memory) T(std::forward<Args>(args)...);
302 return object;
303 }
304};
305
312template <typename T, typename = void>
314 static void Call(T*) {}
315};
316
325template <typename T, typename... Args>
326V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
327 T* object =
328 MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
330 return object;
331}
332
343template <typename T, typename... Args>
344V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
345 AdditionalBytes additional_bytes,
346 Args&&... args) {
347 T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
348 std::forward<Args>(args)...);
350 return object;
351}
352
353} // namespace cppgc
354
355#undef CPPGC_DEFAULT_ALIGNED
356#undef CPPGC_DOUBLE_WORD_ALIGNED
357
358#endif // INCLUDE_CPPGC_ALLOCATION_H_
#define CPPGC_DEFAULT_ALIGNED
Definition: allocation.h:31
#define CPPGC_DOUBLE_WORD_ALIGNED
Definition: allocation.h:35
Definition: custom-space.h:49
static constexpr bool kSupportsCompaction
Definition: custom-space.h:55
Definition: garbage-collected.h:93
Definition: allocation.h:193
static void * Allocate(AllocationHandle &handle, size_t size)
Definition: allocation.h:211
static void MarkObjectAsFullyConstructed(const void *payload)
Definition: allocation.h:240
Definition: allocation.h:284
static T * Call(AllocationHandle &handle, Args &&... args)
Definition: allocation.h:287
static T * Call(AllocationHandle &handle, AdditionalBytes additional_bytes, Args &&... args)
Definition: allocation.h:296
friend class HeapObjectHeader
Definition: allocation.h:179
static void MarkObjectAsFullyConstructed(const void *payload)
Definition: allocation.h:55
uint16_t GCInfoIndex
Definition: gc-info.h:21
std::align_val_t AlignVal
Definition: allocation.h:49
Definition: allocation.h:38
T * MakeGarbageCollected(AllocationHandle &handle, Args &&... args)
Definition: allocation.h:326
Definition: allocation.h:268
constexpr AdditionalBytes(size_t bytes)
Definition: allocation.h:269
const size_t value
Definition: allocation.h:270
Definition: custom-space.h:15
Definition: allocation.h:313
static void Call(T *)
Definition: allocation.h:314
void Space
Definition: custom-space.h:70
Definition: gc-info.h:109
Definition: gc-info.h:83
Definition: type-traits.h:99
static void * Invoke(AllocationHandle &handle, size_t size)
Definition: allocation.h:121
static void * Invoke(AllocationHandle &handle, size_t size)
Definition: allocation.h:77
#define V8_EXPORT
Definition: v8config.h:854
#define V8_INLINE
Definition: v8config.h:508