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