1 // Copyright 2016 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 V8_OBJECTS_MANAGED_H_ 6 #define V8_OBJECTS_MANAGED_H_ 7 8 #include <memory> 9 #include "src/execution/isolate.h" 10 #include "src/handles/global-handles.h" 11 #include "src/handles/handles.h" 12 #include "src/heap/factory.h" 13 #include "src/objects/foreign.h" 14 15 namespace v8 { 16 namespace internal { 17 18 // Implements a doubly-linked lists of destructors for the isolate. 19 struct ManagedPtrDestructor { 20 // Estimated size of external memory associated with the managed object. 21 // This is used to adjust the garbage collector's heuristics upon 22 // allocation and deallocation of a managed object. 23 size_t estimated_size_ = 0; 24 ManagedPtrDestructor* prev_ = nullptr; 25 ManagedPtrDestructor* next_ = nullptr; 26 void* shared_ptr_ptr_ = nullptr; 27 void (*destructor_)(void* shared_ptr) = nullptr; 28 Address* global_handle_location_ = nullptr; 29 ManagedPtrDestructorManagedPtrDestructor30 ManagedPtrDestructor(size_t estimated_size, void* shared_ptr_ptr, 31 void (*destructor)(void*)) 32 : estimated_size_(estimated_size), 33 shared_ptr_ptr_(shared_ptr_ptr), 34 destructor_(destructor) {} 35 }; 36 37 // The GC finalizer of a managed object, which does not depend on 38 // the template parameter. 39 V8_EXPORT_PRIVATE void ManagedObjectFinalizer( 40 const v8::WeakCallbackInfo<void>& data); 41 42 // {Managed<T>} is essentially a {std::shared_ptr<T>} allocated on the heap 43 // that can be used to manage the lifetime of C++ objects that are shared 44 // across multiple isolates. 45 // When a {Managed<T>} object is garbage collected (or an isolate which 46 // contains {Managed<T>} is torn down), the {Managed<T>} deletes its underlying 47 // {std::shared_ptr<T>}, thereby decrementing its internal reference count, 48 // which will delete the C++ object when the reference count drops to 0. 49 template <class CppType> 50 class Managed : public Foreign { 51 public: Managed()52 Managed() : Foreign() {} Managed(Address ptr)53 explicit Managed(Address ptr) : Foreign(ptr) {} 54 55 // Get a raw pointer to the C++ object. raw()56 V8_INLINE CppType* raw() { return GetSharedPtrPtr()->get(); } 57 58 // Get a reference to the shared pointer to the C++ object. get()59 V8_INLINE const std::shared_ptr<CppType>& get() { return *GetSharedPtrPtr(); } 60 cast(Object obj)61 static Managed cast(Object obj) { return Managed(obj.ptr()); } unchecked_cast(Object obj)62 static Managed unchecked_cast(Object obj) { return bit_cast<Managed>(obj); } 63 64 // Allocate a new {CppType} and wrap it in a {Managed<CppType>}. 65 template <typename... Args> Allocate(Isolate * isolate,size_t estimated_size,Args &&...args)66 static Handle<Managed<CppType>> Allocate(Isolate* isolate, 67 size_t estimated_size, 68 Args&&... args) { 69 return FromSharedPtr( 70 isolate, estimated_size, 71 std::make_shared<CppType>(std::forward<Args>(args)...)); 72 } 73 74 // Create a {Managed<CppType>} from an existing raw {CppType*}. The returned 75 // object will now own the memory pointed to by {CppType}. FromRawPtr(Isolate * isolate,size_t estimated_size,CppType * ptr)76 static Handle<Managed<CppType>> FromRawPtr(Isolate* isolate, 77 size_t estimated_size, 78 CppType* ptr) { 79 return FromSharedPtr(isolate, estimated_size, 80 std::shared_ptr<CppType>{ptr}); 81 } 82 83 // Create a {Managed<CppType>} from an existing {std::unique_ptr<CppType>}. 84 // The returned object will now own the memory pointed to by {CppType}, and 85 // the unique pointer will be released. FromUniquePtr(Isolate * isolate,size_t estimated_size,std::unique_ptr<CppType> unique_ptr)86 static Handle<Managed<CppType>> FromUniquePtr( 87 Isolate* isolate, size_t estimated_size, 88 std::unique_ptr<CppType> unique_ptr) { 89 return FromSharedPtr(isolate, estimated_size, std::move(unique_ptr)); 90 } 91 92 // Create a {Managed<CppType>} from an existing {std::shared_ptr<CppType>}. FromSharedPtr(Isolate * isolate,size_t estimated_size,std::shared_ptr<CppType> shared_ptr)93 static Handle<Managed<CppType>> FromSharedPtr( 94 Isolate* isolate, size_t estimated_size, 95 std::shared_ptr<CppType> shared_ptr) { 96 reinterpret_cast<v8::Isolate*>(isolate) 97 ->AdjustAmountOfExternalAllocatedMemory(estimated_size); 98 auto destructor = new ManagedPtrDestructor( 99 estimated_size, new std::shared_ptr<CppType>{std::move(shared_ptr)}, 100 Destructor); 101 Handle<Managed<CppType>> handle = Handle<Managed<CppType>>::cast( 102 isolate->factory()->NewForeign(reinterpret_cast<Address>(destructor))); 103 Handle<Object> global_handle = isolate->global_handles()->Create(*handle); 104 destructor->global_handle_location_ = global_handle.location(); 105 GlobalHandles::MakeWeak(destructor->global_handle_location_, destructor, 106 &ManagedObjectFinalizer, 107 v8::WeakCallbackType::kParameter); 108 isolate->RegisterManagedPtrDestructor(destructor); 109 return handle; 110 } 111 112 private: 113 // Internally this {Foreign} object stores a pointer to a new 114 // std::shared_ptr<CppType>. GetSharedPtrPtr()115 std::shared_ptr<CppType>* GetSharedPtrPtr() { 116 auto destructor = 117 reinterpret_cast<ManagedPtrDestructor*>(foreign_address()); 118 return reinterpret_cast<std::shared_ptr<CppType>*>( 119 destructor->shared_ptr_ptr_); 120 } 121 122 // Called by either isolate shutdown or the {ManagedObjectFinalizer} in order 123 // to actually delete the shared pointer and decrement the shared refcount. Destructor(void * ptr)124 static void Destructor(void* ptr) { 125 auto shared_ptr_ptr = reinterpret_cast<std::shared_ptr<CppType>*>(ptr); 126 delete shared_ptr_ptr; 127 } 128 }; 129 130 } // namespace internal 131 } // namespace v8 132 133 #endif // V8_OBJECTS_MANAGED_H_ 134