Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-09 09:13:43

0001 // Copyright 2020 the V8 project authors. All rights reserved.
0002 // Use of this source code is governed by a BSD-style license that can be
0003 // found in the LICENSE file.
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  // __has_attribute(assume_aligned)
0028 #endif  // defined(__has_attribute)
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  * AllocationHandle is used to allocate garbage-collected objects.
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     // See api_constants for an explanation of the constants.
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     // It's safe to split use load+store here (instead of a read-modify-write
0058     // operation), since it's guaranteed that this 16-bit bitfield is only
0059     // modified by a single thread. This is cheaper in terms of code bloat (on
0060     // ARM) and performance.
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   // Dispatch based on compile-time information.
0067   //
0068   // Default implementation is for a custom space with >`kDefaultAlignment` byte
0069   // alignment.
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   // Fast path for regular allocations for the default space with
0086   // `kDefaultAlignment` byte alignment.
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   // Default space with >`kDefaultAlignment` byte alignment.
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   // Custom space with `kDefaultAlignment` byte alignment.
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 }  // namespace internal
0136 
0137 /**
0138  * Base trait that provides utilities for advancers users that have custom
0139  * allocation needs (e.g., overriding size). It's expected that users override
0140  * MakeGarbageCollectedTrait (see below) and inherit from
0141  * MakeGarbageCollectedTraitBase and make use of the low-level primitives
0142  * offered to allocate and construct an object.
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    * Allocates memory for an object of type T.
0158    *
0159    * \param handle AllocationHandle identifying the heap to allocate the object
0160    *   on.
0161    * \param size The size that should be reserved for the object.
0162    * \returns the memory to construct an object of type T on.
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    * Marks an object as fully constructed, resulting in precise handling by the
0185    * garbage collector.
0186    *
0187    * \param payload The base pointer the object is allocated at.
0188    */
0189   V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
0190     internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
0191         payload);
0192   }
0193 };
0194 
0195 /**
0196  * Passed to MakeGarbageCollected to specify how many bytes should be appended
0197  * to the allocated object.
0198  *
0199  * Example:
0200  * \code
0201  * class InlinedArray final : public GarbageCollected<InlinedArray> {
0202  *  public:
0203  *   explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
0204  *   void Trace(Visitor*) const {}
0205 
0206  *   size_t size;
0207  *   char* byte_array;
0208  * };
0209  *
0210  * auto* inlined_array = MakeGarbageCollected<InlinedArray(
0211  *    GetAllocationHandle(), AdditionalBytes(4), 4);
0212  * for (size_t i = 0; i < 4; i++) {
0213  *   Process(inlined_array->byte_array[i]);
0214  * }
0215  * \endcode
0216  */
0217 struct AdditionalBytes {
0218   constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
0219   const size_t value;
0220 };
0221 
0222 /**
0223  * Default trait class that specifies how to construct an object of type T.
0224  * Advanced users may override how an object is constructed using the utilities
0225  * that are provided through MakeGarbageCollectedTraitBase.
0226  *
0227  * Any trait overriding construction must
0228  * - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
0229  * - mark the object as fully constructed using
0230  *   `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
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  * Allows users to specify a post-construction callback for specific types. The
0257  * callback is invoked on the instance of type T right after it has been
0258  * constructed. This can be useful when the callback requires a
0259  * fully-constructed object to be able to dispatch to virtual methods.
0260  */
0261 template <typename T, typename = void>
0262 struct PostConstructionCallbackTrait {
0263   static void Call(T*) {}
0264 };
0265 
0266 /**
0267  * Constructs a managed object of type T where T transitively inherits from
0268  * GarbageCollected.
0269  *
0270  * \param args List of arguments with which an instance of T will be
0271  *   constructed.
0272  * \returns an instance of type T.
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  * Constructs a managed object of type T where T transitively inherits from
0284  * GarbageCollected. Created objects will have additional bytes appended to
0285  * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
0286  *
0287  * \param additional_bytes Denotes how many bytes to append to T.
0288  * \param args List of arguments with which an instance of T will be
0289  *   constructed.
0290  * \returns an instance of type T.
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 }  // namespace cppgc
0303 
0304 #undef CPPGC_DEFAULT_ALIGNED
0305 #undef CPPGC_DOUBLE_WORD_ALIGNED
0306 
0307 #endif  // INCLUDE_CPPGC_ALLOCATION_H_