File indexing completed on 2026-09-09 09:13:43
0001
0002
0003
0004
0005 #ifndef INCLUDE_CPPGC_ALLOCATION_H_
0006 #define INCLUDE_CPPGC_ALLOCATION_H_
0007
0008 #include <atomic>
0009 #include <cstddef>
0010 #include <cstdint>
0011 #include <new>
0012 #include <type_traits>
0013 #include <utility>
0014
0015 #include "cppgc/custom-space.h"
0016 #include "cppgc/internal/api-constants.h"
0017 #include "cppgc/internal/gc-info.h"
0018 #include "cppgc/type-traits.h"
0019 #include "v8config.h" // NOLINT(build/include_directory)
0020
0021 #if defined(__has_attribute)
0022 #if __has_attribute(assume_aligned)
0023 #define CPPGC_DEFAULT_ALIGNED \
0024 __attribute__((assume_aligned(api_constants::kDefaultAlignment)))
0025 #define CPPGC_DOUBLE_WORD_ALIGNED \
0026 __attribute__((assume_aligned(2 * api_constants::kDefaultAlignment)))
0027 #endif
0028 #endif
0029
0030 #if !defined(CPPGC_DEFAULT_ALIGNED)
0031 #define CPPGC_DEFAULT_ALIGNED
0032 #endif
0033
0034 #if !defined(CPPGC_DOUBLE_WORD_ALIGNED)
0035 #define CPPGC_DOUBLE_WORD_ALIGNED
0036 #endif
0037
0038 namespace cppgc {
0039
0040
0041
0042
0043 class AllocationHandle;
0044
0045 namespace internal {
0046
0047 using AlignVal = std::align_val_t;
0048
0049 class MakeGarbageCollectedTraitInternal {
0050 protected:
0051 static inline void MarkObjectAsFullyConstructed(const void* payload) {
0052
0053 std::atomic_ref<uint16_t> atomic_mutable_bitfield(
0054 *const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
0055 reinterpret_cast<const uint8_t*>(payload) -
0056 api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
0057
0058
0059
0060
0061 uint16_t value = atomic_mutable_bitfield.load(std::memory_order_relaxed);
0062 value |= api_constants::kFullyConstructedBitMask;
0063 atomic_mutable_bitfield.store(value, std::memory_order_release);
0064 }
0065
0066
0067
0068
0069
0070 template <typename GCInfoType, typename CustomSpace, size_t alignment>
0071 struct AllocationDispatcher final {
0072 static void* Invoke(AllocationHandle& handle, size_t size) {
0073 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
0074 "Custom space must inherit from CustomSpaceBase.");
0075 static_assert(
0076 !CustomSpace::kSupportsCompaction,
0077 "Custom spaces that support compaction do not support allocating "
0078 "objects with non-default (i.e. word-sized) alignment.");
0079 return MakeGarbageCollectedTraitInternal::Allocate(
0080 handle, size, static_cast<AlignVal>(alignment),
0081 internal::GCInfoTrait<GCInfoType>::Index(), CustomSpace::kSpaceIndex);
0082 }
0083 };
0084
0085
0086
0087 template <typename GCInfoType>
0088 struct AllocationDispatcher<GCInfoType, void,
0089 api_constants::kDefaultAlignment>
0090 final {
0091 static void* Invoke(AllocationHandle& handle, size_t size) {
0092 return MakeGarbageCollectedTraitInternal::Allocate(
0093 handle, size, internal::GCInfoTrait<GCInfoType>::Index());
0094 }
0095 };
0096
0097
0098 template <typename GCInfoType, size_t alignment>
0099 struct AllocationDispatcher<GCInfoType, void, alignment> final {
0100 static void* Invoke(AllocationHandle& handle, size_t size) {
0101 return MakeGarbageCollectedTraitInternal::Allocate(
0102 handle, size, static_cast<AlignVal>(alignment),
0103 internal::GCInfoTrait<GCInfoType>::Index());
0104 }
0105 };
0106
0107
0108 template <typename GCInfoType, typename CustomSpace>
0109 struct AllocationDispatcher<GCInfoType, CustomSpace,
0110 api_constants::kDefaultAlignment>
0111 final {
0112 static void* Invoke(AllocationHandle& handle, size_t size) {
0113 static_assert(std::is_base_of_v<CustomSpaceBase, CustomSpace>,
0114 "Custom space must inherit from CustomSpaceBase.");
0115 return MakeGarbageCollectedTraitInternal::Allocate(
0116 handle, size, internal::GCInfoTrait<GCInfoType>::Index(),
0117 CustomSpace::kSpaceIndex);
0118 }
0119 };
0120
0121 private:
0122 V8_EXPORT static void* CPPGC_DEFAULT_ALIGNED
0123 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex);
0124 V8_EXPORT static void* CPPGC_DOUBLE_WORD_ALIGNED
0125 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex);
0126 V8_EXPORT static void* CPPGC_DEFAULT_ALIGNED
0127 Allocate(cppgc::AllocationHandle&, size_t, GCInfoIndex, CustomSpaceIndex);
0128 V8_EXPORT static void* CPPGC_DOUBLE_WORD_ALIGNED
0129 Allocate(cppgc::AllocationHandle&, size_t, AlignVal, GCInfoIndex,
0130 CustomSpaceIndex);
0131
0132 friend class HeapObjectHeader;
0133 };
0134
0135 }
0136
0137
0138
0139
0140
0141
0142
0143
0144 template <typename T>
0145 class MakeGarbageCollectedTraitBase
0146 : private internal::MakeGarbageCollectedTraitInternal {
0147 private:
0148 static_assert(internal::IsGarbageCollectedType<T>::value,
0149 "T needs to be a garbage collected object");
0150 static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
0151 sizeof(T) <=
0152 internal::api_constants::kLargeObjectSizeThreshold,
0153 "GarbageCollectedMixin may not be a large object");
0154
0155 protected:
0156
0157
0158
0159
0160
0161
0162
0163
0164 V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
0165 static_assert(
0166 std::is_base_of_v<typename T::ParentMostGarbageCollectedType, T>,
0167 "U of GarbageCollected<U> must be a base of T. Check "
0168 "GarbageCollected<T> base class inheritance.");
0169 static constexpr size_t kWantedAlignment =
0170 alignof(T) < internal::api_constants::kDefaultAlignment
0171 ? internal::api_constants::kDefaultAlignment
0172 : alignof(T);
0173 static_assert(
0174 kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
0175 "Requested alignment larger than alignof(std::max_align_t) bytes. "
0176 "Please file a bug to possibly get this restriction lifted.");
0177 return AllocationDispatcher<
0178 typename internal::GCInfoFolding<
0179 T, typename T::ParentMostGarbageCollectedType>::ResultType,
0180 typename SpaceTrait<T>::Space, kWantedAlignment>::Invoke(handle, size);
0181 }
0182
0183
0184
0185
0186
0187
0188
0189 V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
0190 internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
0191 payload);
0192 }
0193 };
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 struct AdditionalBytes {
0218 constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
0219 const size_t value;
0220 };
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 template <typename T>
0233 class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> {
0234 public:
0235 template <typename... Args>
0236 static T* Call(AllocationHandle& handle, Args&&... args) {
0237 void* memory =
0238 MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
0239 T* object = ::new (memory) T(std::forward<Args>(args)...);
0240 MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
0241 return object;
0242 }
0243
0244 template <typename... Args>
0245 static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
0246 Args&&... args) {
0247 void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
0248 handle, sizeof(T) + additional_bytes.value);
0249 T* object = ::new (memory) T(std::forward<Args>(args)...);
0250 MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
0251 return object;
0252 }
0253 };
0254
0255
0256
0257
0258
0259
0260
0261 template <typename T, typename = void>
0262 struct PostConstructionCallbackTrait {
0263 static void Call(T*) {}
0264 };
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 template <typename T, typename... Args>
0275 V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
0276 T* object =
0277 MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
0278 PostConstructionCallbackTrait<T>::Call(object);
0279 return object;
0280 }
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292 template <typename T, typename... Args>
0293 V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
0294 AdditionalBytes additional_bytes,
0295 Args&&... args) {
0296 T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
0297 std::forward<Args>(args)...);
0298 PostConstructionCallbackTrait<T>::Call(object);
0299 return object;
0300 }
0301
0302 }
0303
0304 #undef CPPGC_DEFAULT_ALIGNED
0305 #undef CPPGC_DOUBLE_WORD_ALIGNED
0306
0307 #endif