Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-02 08:54:42

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 // Similar to C++17 std::align_val_t;
0048 enum class AlignVal : size_t {};
0049 
0050 class V8_EXPORT MakeGarbageCollectedTraitInternal {
0051  protected:
0052   static inline void MarkObjectAsFullyConstructed(const void* payload) {
0053     // See api_constants for an explanation of the constants.
0054     std::atomic<uint16_t>* atomic_mutable_bitfield =
0055         reinterpret_cast<std::atomic<uint16_t>*>(
0056             const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>(
0057                 reinterpret_cast<const uint8_t*>(payload) -
0058                 api_constants::kFullyConstructedBitFieldOffsetFromPayload)));
0059     // It's safe to split use load+store here (instead of a read-modify-write
0060     // operation), since it's guaranteed that this 16-bit bitfield is only
0061     // modified by a single thread. This is cheaper in terms of code bloat (on
0062     // ARM) and performance.
0063     uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed);
0064     value |= api_constants::kFullyConstructedBitMask;
0065     atomic_mutable_bitfield->store(value, std::memory_order_release);
0066   }
0067 
0068   // Dispatch based on compile-time information.
0069   //
0070   // Default implementation is for a custom space with >`kDefaultAlignment` byte
0071   // alignment.
0072   template <typename GCInfoType, typename CustomSpace, size_t alignment>
0073   struct AllocationDispatcher final {
0074     static void* Invoke(AllocationHandle& handle, size_t size) {
0075       static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
0076                     "Custom space must inherit from CustomSpaceBase.");
0077       static_assert(
0078           !CustomSpace::kSupportsCompaction,
0079           "Custom spaces that support compaction do not support allocating "
0080           "objects with non-default (i.e. word-sized) alignment.");
0081       return MakeGarbageCollectedTraitInternal::Allocate(
0082           handle, size, static_cast<AlignVal>(alignment),
0083           internal::GCInfoTrait<GCInfoType>::Index(), CustomSpace::kSpaceIndex);
0084     }
0085   };
0086 
0087   // Fast path for regular allocations for the default space with
0088   // `kDefaultAlignment` byte alignment.
0089   template <typename GCInfoType>
0090   struct AllocationDispatcher<GCInfoType, void,
0091                               api_constants::kDefaultAlignment>
0092       final {
0093     static void* Invoke(AllocationHandle& handle, size_t size) {
0094       return MakeGarbageCollectedTraitInternal::Allocate(
0095           handle, size, internal::GCInfoTrait<GCInfoType>::Index());
0096     }
0097   };
0098 
0099   // Default space with >`kDefaultAlignment` byte alignment.
0100   template <typename GCInfoType, size_t alignment>
0101   struct AllocationDispatcher<GCInfoType, void, alignment> final {
0102     static void* Invoke(AllocationHandle& handle, size_t size) {
0103       return MakeGarbageCollectedTraitInternal::Allocate(
0104           handle, size, static_cast<AlignVal>(alignment),
0105           internal::GCInfoTrait<GCInfoType>::Index());
0106     }
0107   };
0108 
0109   // Custom space with `kDefaultAlignment` byte alignment.
0110   template <typename GCInfoType, typename CustomSpace>
0111   struct AllocationDispatcher<GCInfoType, CustomSpace,
0112                               api_constants::kDefaultAlignment>
0113       final {
0114     static void* Invoke(AllocationHandle& handle, size_t size) {
0115       static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value,
0116                     "Custom space must inherit from CustomSpaceBase.");
0117       return MakeGarbageCollectedTraitInternal::Allocate(
0118           handle, size, internal::GCInfoTrait<GCInfoType>::Index(),
0119           CustomSpace::kSpaceIndex);
0120     }
0121   };
0122 
0123  private:
0124   static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t,
0125                                               GCInfoIndex);
0126   static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&,
0127                                                   size_t, AlignVal,
0128                                                   GCInfoIndex);
0129   static void* CPPGC_DEFAULT_ALIGNED Allocate(cppgc::AllocationHandle&, size_t,
0130                                               GCInfoIndex, CustomSpaceIndex);
0131   static void* CPPGC_DOUBLE_WORD_ALIGNED Allocate(cppgc::AllocationHandle&,
0132                                                   size_t, AlignVal, GCInfoIndex,
0133                                                   CustomSpaceIndex);
0134 
0135   friend class HeapObjectHeader;
0136 };
0137 
0138 }  // namespace internal
0139 
0140 /**
0141  * Base trait that provides utilities for advancers users that have custom
0142  * allocation needs (e.g., overriding size). It's expected that users override
0143  * MakeGarbageCollectedTrait (see below) and inherit from
0144  * MakeGarbageCollectedTraitBase and make use of the low-level primitives
0145  * offered to allocate and construct an object.
0146  */
0147 template <typename T>
0148 class MakeGarbageCollectedTraitBase
0149     : private internal::MakeGarbageCollectedTraitInternal {
0150  private:
0151   static_assert(internal::IsGarbageCollectedType<T>::value,
0152                 "T needs to be a garbage collected object");
0153   static_assert(!IsGarbageCollectedWithMixinTypeV<T> ||
0154                     sizeof(T) <=
0155                         internal::api_constants::kLargeObjectSizeThreshold,
0156                 "GarbageCollectedMixin may not be a large object");
0157 
0158  protected:
0159   /**
0160    * Allocates memory for an object of type T.
0161    *
0162    * \param handle AllocationHandle identifying the heap to allocate the object
0163    *   on.
0164    * \param size The size that should be reserved for the object.
0165    * \returns the memory to construct an object of type T on.
0166    */
0167   V8_INLINE static void* Allocate(AllocationHandle& handle, size_t size) {
0168     static_assert(
0169         std::is_base_of<typename T::ParentMostGarbageCollectedType, T>::value,
0170         "U of GarbageCollected<U> must be a base of T. Check "
0171         "GarbageCollected<T> base class inheritance.");
0172     static constexpr size_t kWantedAlignment =
0173         alignof(T) < internal::api_constants::kDefaultAlignment
0174             ? internal::api_constants::kDefaultAlignment
0175             : alignof(T);
0176     static_assert(
0177         kWantedAlignment <= internal::api_constants::kMaxSupportedAlignment,
0178         "Requested alignment larger than alignof(std::max_align_t) bytes. "
0179         "Please file a bug to possibly get this restriction lifted.");
0180     return AllocationDispatcher<
0181         typename internal::GCInfoFolding<
0182             T, typename T::ParentMostGarbageCollectedType>::ResultType,
0183         typename SpaceTrait<T>::Space, kWantedAlignment>::Invoke(handle, size);
0184   }
0185 
0186   /**
0187    * Marks an object as fully constructed, resulting in precise handling by the
0188    * garbage collector.
0189    *
0190    * \param payload The base pointer the object is allocated at.
0191    */
0192   V8_INLINE static void MarkObjectAsFullyConstructed(const void* payload) {
0193     internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed(
0194         payload);
0195   }
0196 };
0197 
0198 /**
0199  * Passed to MakeGarbageCollected to specify how many bytes should be appended
0200  * to the allocated object.
0201  *
0202  * Example:
0203  * \code
0204  * class InlinedArray final : public GarbageCollected<InlinedArray> {
0205  *  public:
0206  *   explicit InlinedArray(size_t bytes) : size(bytes), byte_array(this + 1) {}
0207  *   void Trace(Visitor*) const {}
0208 
0209  *   size_t size;
0210  *   char* byte_array;
0211  * };
0212  *
0213  * auto* inlined_array = MakeGarbageCollected<InlinedArray(
0214  *    GetAllocationHandle(), AdditionalBytes(4), 4);
0215  * for (size_t i = 0; i < 4; i++) {
0216  *   Process(inlined_array->byte_array[i]);
0217  * }
0218  * \endcode
0219  */
0220 struct AdditionalBytes {
0221   constexpr explicit AdditionalBytes(size_t bytes) : value(bytes) {}
0222   const size_t value;
0223 };
0224 
0225 /**
0226  * Default trait class that specifies how to construct an object of type T.
0227  * Advanced users may override how an object is constructed using the utilities
0228  * that are provided through MakeGarbageCollectedTraitBase.
0229  *
0230  * Any trait overriding construction must
0231  * - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`;
0232  * - mark the object as fully constructed using
0233  *   `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`;
0234  */
0235 template <typename T>
0236 class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> {
0237  public:
0238   template <typename... Args>
0239   static T* Call(AllocationHandle& handle, Args&&... args) {
0240     void* memory =
0241         MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T));
0242     T* object = ::new (memory) T(std::forward<Args>(args)...);
0243     MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
0244     return object;
0245   }
0246 
0247   template <typename... Args>
0248   static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes,
0249                  Args&&... args) {
0250     void* memory = MakeGarbageCollectedTraitBase<T>::Allocate(
0251         handle, sizeof(T) + additional_bytes.value);
0252     T* object = ::new (memory) T(std::forward<Args>(args)...);
0253     MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object);
0254     return object;
0255   }
0256 };
0257 
0258 /**
0259  * Allows users to specify a post-construction callback for specific types. The
0260  * callback is invoked on the instance of type T right after it has been
0261  * constructed. This can be useful when the callback requires a
0262  * fully-constructed object to be able to dispatch to virtual methods.
0263  */
0264 template <typename T, typename = void>
0265 struct PostConstructionCallbackTrait {
0266   static void Call(T*) {}
0267 };
0268 
0269 /**
0270  * Constructs a managed object of type T where T transitively inherits from
0271  * GarbageCollected.
0272  *
0273  * \param args List of arguments with which an instance of T will be
0274  *   constructed.
0275  * \returns an instance of type T.
0276  */
0277 template <typename T, typename... Args>
0278 V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) {
0279   T* object =
0280       MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...);
0281   PostConstructionCallbackTrait<T>::Call(object);
0282   return object;
0283 }
0284 
0285 /**
0286  * Constructs a managed object of type T where T transitively inherits from
0287  * GarbageCollected. Created objects will have additional bytes appended to
0288  * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`.
0289  *
0290  * \param additional_bytes Denotes how many bytes to append to T.
0291  * \param args List of arguments with which an instance of T will be
0292  *   constructed.
0293  * \returns an instance of type T.
0294  */
0295 template <typename T, typename... Args>
0296 V8_INLINE T* MakeGarbageCollected(AllocationHandle& handle,
0297                                   AdditionalBytes additional_bytes,
0298                                   Args&&... args) {
0299   T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes,
0300                                                  std::forward<Args>(args)...);
0301   PostConstructionCallbackTrait<T>::Call(object);
0302   return object;
0303 }
0304 
0305 }  // namespace cppgc
0306 
0307 #undef CPPGC_DEFAULT_ALIGNED
0308 #undef CPPGC_DOUBLE_WORD_ALIGNED
0309 
0310 #endif  // INCLUDE_CPPGC_ALLOCATION_H_