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 <stdint.h> 9 10 #include <atomic> 11 12 #include "cppgc/custom-space.h" 13 #include "cppgc/garbage-collected.h" 14 #include "cppgc/internal/api-constants.h" 15 #include "cppgc/internal/gc-info.h" 16 17 namespace cppgc { 18 19 template <typename T> 20 class MakeGarbageCollectedTraitBase; 21 22 namespace internal { 23 class ObjectAllocator; 24 } // namespace internal 25 26 /** 27 * AllocationHandle is used to allocate garbage-collected objects. 28 */ 29 class AllocationHandle; 30 31 namespace internal { 32 33 class V8_EXPORT MakeGarbageCollectedTraitInternal { 34 protected: MarkObjectAsFullyConstructed(const void * payload)35 static inline void MarkObjectAsFullyConstructed(const void* payload) { 36 // See api_constants for an explanation of the constants. 37 std::atomic<uint16_t>* atomic_mutable_bitfield = 38 reinterpret_cast<std::atomic<uint16_t>*>( 39 const_cast<uint16_t*>(reinterpret_cast<const uint16_t*>( 40 reinterpret_cast<const uint8_t*>(payload) - 41 api_constants::kFullyConstructedBitFieldOffsetFromPayload))); 42 uint16_t value = atomic_mutable_bitfield->load(std::memory_order_relaxed); 43 value = value | api_constants::kFullyConstructedBitMask; 44 atomic_mutable_bitfield->store(value, std::memory_order_release); 45 } 46 47 static void* Allocate(cppgc::AllocationHandle& handle, size_t size, 48 GCInfoIndex index); 49 static void* Allocate(cppgc::AllocationHandle& handle, size_t size, 50 GCInfoIndex index, CustomSpaceIndex space_index); 51 52 friend class HeapObjectHeader; 53 }; 54 55 } // namespace internal 56 57 /** 58 * Base trait that provides utilities for advancers users that have custom 59 * allocation needs (e.g., overriding size). It's expected that users override 60 * MakeGarbageCollectedTrait (see below) and inherit from 61 * MakeGarbageCollectedTraitBase and make use of the low-level primitives 62 * offered to allocate and construct an object. 63 */ 64 template <typename T> 65 class MakeGarbageCollectedTraitBase 66 : private internal::MakeGarbageCollectedTraitInternal { 67 private: 68 template <typename U, typename CustomSpace> 69 struct SpacePolicy { AllocateSpacePolicy70 static void* Allocate(AllocationHandle& handle, size_t size) { 71 // Custom space. 72 static_assert(std::is_base_of<CustomSpaceBase, CustomSpace>::value, 73 "Custom space must inherit from CustomSpaceBase."); 74 return internal::MakeGarbageCollectedTraitInternal::Allocate( 75 handle, size, internal::GCInfoTrait<T>::Index(), 76 CustomSpace::kSpaceIndex); 77 } 78 }; 79 80 template <typename U> 81 struct SpacePolicy<U, void> { 82 static void* Allocate(AllocationHandle& handle, size_t size) { 83 // Default space. 84 return internal::MakeGarbageCollectedTraitInternal::Allocate( 85 handle, size, internal::GCInfoTrait<T>::Index()); 86 } 87 }; 88 89 protected: 90 /** 91 * Allocates memory for an object of type T. 92 * 93 * \param handle AllocationHandle identifying the heap to allocate the object 94 * on. 95 * \param size The size that should be reserved for the object. 96 * \returns the memory to construct an object of type T on. 97 */ 98 static void* Allocate(AllocationHandle& handle, size_t size) { 99 return SpacePolicy<T, typename SpaceTrait<T>::Space>::Allocate(handle, 100 size); 101 } 102 103 /** 104 * Marks an object as fully constructed, resulting in precise handling by the 105 * garbage collector. 106 * 107 * \param payload The base pointer the object is allocated at. 108 */ 109 static void MarkObjectAsFullyConstructed(const void* payload) { 110 internal::MakeGarbageCollectedTraitInternal::MarkObjectAsFullyConstructed( 111 payload); 112 } 113 }; 114 115 /** 116 * struct used specify to MakeGarbageCollected how many bytes should be 117 * appended to the allocated object. 118 */ 119 struct AdditionalBytes { 120 explicit AdditionalBytes(size_t bytes) : value(bytes) {} 121 const size_t value; 122 }; 123 124 /** 125 * Default trait class that specifies how to construct an object of type T. 126 * Advanced users may override how an object is constructed using the utilities 127 * that are provided through MakeGarbageCollectedTraitBase. 128 * 129 * Any trait overriding construction must 130 * - allocate through `MakeGarbageCollectedTraitBase<T>::Allocate`; 131 * - mark the object as fully constructed using 132 * `MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed`; 133 */ 134 template <typename T> 135 class MakeGarbageCollectedTrait : public MakeGarbageCollectedTraitBase<T> { 136 public: 137 template <typename... Args> 138 static T* Call(AllocationHandle& handle, Args&&... args) { 139 static_assert(internal::IsGarbageCollectedType<T>::value, 140 "T needs to be a garbage collected object"); 141 static_assert( 142 !internal::IsGarbageCollectedMixinType<T>::value || 143 sizeof(T) <= internal::api_constants::kLargeObjectSizeThreshold, 144 "GarbageCollectedMixin may not be a large object"); 145 void* memory = 146 MakeGarbageCollectedTraitBase<T>::Allocate(handle, sizeof(T)); 147 T* object = ::new (memory) T(std::forward<Args>(args)...); 148 MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object); 149 return object; 150 } 151 152 template <typename... Args> 153 static T* Call(AllocationHandle& handle, AdditionalBytes additional_bytes, 154 Args&&... args) { 155 static_assert(internal::IsGarbageCollectedType<T>::value, 156 "T needs to be a garbage collected object"); 157 static_assert( 158 !internal::IsGarbageCollectedMixinType<T>::value || 159 sizeof(T) <= internal::api_constants::kLargeObjectSizeThreshold, 160 "GarbageCollectedMixin may not be a large object"); 161 void* memory = MakeGarbageCollectedTraitBase<T>::Allocate( 162 handle, sizeof(T) + additional_bytes.value); 163 T* object = ::new (memory) T(std::forward<Args>(args)...); 164 MakeGarbageCollectedTraitBase<T>::MarkObjectAsFullyConstructed(object); 165 return object; 166 } 167 }; 168 169 /** 170 * Allows users to specify a post-construction callback for specific types. The 171 * callback is invoked on the instance of type T right after it has been 172 * constructed. This can be useful when the callback requires a 173 * fully-constructed object to be able to dispatch to virtual methods. 174 */ 175 template <typename T, typename = void> 176 struct PostConstructionCallbackTrait { 177 static void Call(T*) {} 178 }; 179 180 /** 181 * Constructs a managed object of type T where T transitively inherits from 182 * GarbageCollected. 183 * 184 * \param args List of arguments with which an instance of T will be 185 * constructed. 186 * \returns an instance of type T. 187 */ 188 template <typename T, typename... Args> 189 T* MakeGarbageCollected(AllocationHandle& handle, Args&&... args) { 190 T* object = 191 MakeGarbageCollectedTrait<T>::Call(handle, std::forward<Args>(args)...); 192 PostConstructionCallbackTrait<T>::Call(object); 193 return object; 194 } 195 196 /** 197 * Constructs a managed object of type T where T transitively inherits from 198 * GarbageCollected. Created objects will have additional bytes appended to 199 * it. Allocated memory would suffice for `sizeof(T) + additional_bytes`. 200 * 201 * \param additional_bytes Denotes how many bytes to append to T. 202 * \param args List of arguments with which an instance of T will be 203 * constructed. 204 * \returns an instance of type T. 205 */ 206 template <typename T, typename... Args> 207 T* MakeGarbageCollected(AllocationHandle& handle, 208 AdditionalBytes additional_bytes, Args&&... args) { 209 T* object = MakeGarbageCollectedTrait<T>::Call(handle, additional_bytes, 210 std::forward<Args>(args)...); 211 PostConstructionCallbackTrait<T>::Call(object); 212 return object; 213 } 214 215 } // namespace cppgc 216 217 #endif // INCLUDE_CPPGC_ALLOCATION_H_ 218