4040namespace node {
4141
4242BaseObject::BaseObject (Environment* env, v8::Local<v8::Object> object)
43- : persistent_handle_(env->isolate (), object),
44- env_(env) {
43+ : persistent_handle_(env->isolate (), object), env_(env) {
4544 CHECK_EQ (false , object.IsEmpty ());
4645 CHECK_GT (object->InternalFieldCount (), 0 );
4746 object->SetAlignedPointerInInternalField (0 , static_cast <void *>(this ));
48- env_->AddCleanupHook (DeleteMe, static_cast <void *>(this ));
47+ env->AddCleanupHook (DeleteMe, static_cast <void *>(this ));
48+ env->modify_base_object_count (1 );
4949}
5050
5151BaseObject::~BaseObject () {
52- RemoveCleanupHook ();
52+ env ()->modify_base_object_count (-1 );
53+ env ()->RemoveCleanupHook (DeleteMe, static_cast <void *>(this ));
54+
55+ if (UNLIKELY (has_pointer_data ())) {
56+ PointerData* metadata = pointer_data ();
57+ CHECK_EQ (metadata->strong_ptr_count , 0 );
58+ metadata->self = nullptr ;
59+ if (metadata->weak_ptr_count == 0 )
60+ delete metadata;
61+ }
5362
5463 if (persistent_handle_.IsEmpty ()) {
5564 // This most likely happened because the weak callback below cleared it.
5665 return ;
5766 }
5867
5968 {
60- v8::HandleScope handle_scope (env_ ->isolate ());
69+ v8::HandleScope handle_scope (env () ->isolate ());
6170 object ()->SetAlignedPointerInInternalField (0 , nullptr );
6271 }
6372}
@@ -66,20 +75,25 @@ void BaseObject::RemoveCleanupHook() {
6675 env_->RemoveCleanupHook (DeleteMe, static_cast <void *>(this ));
6776}
6877
78+ void BaseObject::Detach () {
79+ CHECK_GT (pointer_data ()->strong_ptr_count , 0 );
80+ pointer_data ()->is_detached = true ;
81+ }
82+
6983v8::Global<v8::Object>& BaseObject::persistent () {
7084 return persistent_handle_;
7185}
7286
7387
7488v8::Local<v8::Object> BaseObject::object () const {
75- return PersistentToLocal::Default (env_ ->isolate (), persistent_handle_);
89+ return PersistentToLocal::Default (env () ->isolate (), persistent_handle_);
7690}
7791
7892v8::Local<v8::Object> BaseObject::object (v8::Isolate* isolate) const {
7993 v8::Local<v8::Object> handle = object ();
8094
8195 DCHECK_EQ (handle->CreationContext ()->GetIsolate (), isolate);
82- DCHECK_EQ (env_ ->isolate (), isolate);
96+ DCHECK_EQ (env () ->isolate (), isolate);
8397
8498 return handle;
8599}
@@ -88,7 +102,6 @@ Environment* BaseObject::env() const {
88102 return env_;
89103}
90104
91-
92105BaseObject* BaseObject::FromJSObject (v8::Local<v8::Object> obj) {
93106 CHECK_GT (obj->InternalFieldCount (), 0 );
94107 return static_cast <BaseObject*>(obj->GetAlignedPointerFromInternalField (0 ));
@@ -102,20 +115,34 @@ T* BaseObject::FromJSObject(v8::Local<v8::Object> object) {
102115
103116
104117void BaseObject::MakeWeak () {
118+ if (has_pointer_data ()) {
119+ pointer_data ()->wants_weak_jsobj = true ;
120+ if (pointer_data ()->strong_ptr_count > 0 ) return ;
121+ }
122+
105123 persistent_handle_.SetWeak (
106124 this ,
107125 [](const v8::WeakCallbackInfo<BaseObject>& data) {
108- std::unique_ptr< BaseObject> obj ( data.GetParameter () );
126+ BaseObject* obj = data.GetParameter ();
109127 // Clear the persistent handle so that ~BaseObject() doesn't attempt
110128 // to mess with internal fields, since the JS object may have
111129 // transitioned into an invalid state.
112130 // Refs: https://github.com/nodejs/node/issues/18897
113131 obj->persistent_handle_ .Reset ();
132+ CHECK_IMPLIES (obj->has_pointer_data (),
133+ obj->pointer_data ()->strong_ptr_count == 0 );
134+ obj->OnGCCollect ();
114135 }, v8::WeakCallbackType::kParameter );
115136}
116137
138+ void BaseObject::OnGCCollect () {
139+ delete this ;
140+ }
117141
118142void BaseObject::ClearWeak () {
143+ if (has_pointer_data ())
144+ pointer_data ()->wants_weak_jsobj = false ;
145+
119146 persistent_handle_.ClearWeak ();
120147}
121148
@@ -149,6 +176,176 @@ void BaseObject::InternalFieldSet(v8::Local<v8::String> property,
149176 info.This ()->SetInternalField (Field, value);
150177}
151178
179+ bool BaseObject::has_pointer_data () const {
180+ return pointer_data_ != nullptr ;
181+ }
182+
183+ BaseObject::PointerData* BaseObject::pointer_data () {
184+ if (!has_pointer_data ()) {
185+ PointerData* metadata = new PointerData ();
186+ metadata->wants_weak_jsobj = persistent_handle_.IsWeak ();
187+ metadata->self = this ;
188+ pointer_data_ = metadata;
189+ }
190+ CHECK (has_pointer_data ());
191+ return pointer_data_;
192+ }
193+
194+ void BaseObject::decrease_refcount () {
195+ CHECK (has_pointer_data ());
196+ PointerData* metadata = pointer_data ();
197+ CHECK_GT (metadata->strong_ptr_count , 0 );
198+ unsigned int new_refcount = --metadata->strong_ptr_count ;
199+ if (new_refcount == 0 ) {
200+ if (metadata->is_detached ) {
201+ delete this ;
202+ } else if (metadata->wants_weak_jsobj && !persistent_handle_.IsEmpty ()) {
203+ MakeWeak ();
204+ }
205+ }
206+ }
207+
208+ void BaseObject::increase_refcount () {
209+ unsigned int prev_refcount = pointer_data ()->strong_ptr_count ++;
210+ if (prev_refcount == 0 && !persistent_handle_.IsEmpty ())
211+ persistent_handle_.ClearWeak ();
212+ }
213+
214+ template <typename T, bool kIsWeak >
215+ BaseObject::PointerData*
216+ BaseObjectPtrImpl<T, kIsWeak >::pointer_data() const {
217+ if (kIsWeak ) {
218+ return data_.pointer_data ;
219+ } else {
220+ if (get_base_object () == nullptr ) return nullptr ;
221+ return get_base_object ()->pointer_data ();
222+ }
223+ }
224+
225+ template <typename T, bool kIsWeak >
226+ BaseObject* BaseObjectPtrImpl<T, kIsWeak >::get_base_object() const {
227+ if (kIsWeak ) {
228+ if (pointer_data () == nullptr ) return nullptr ;
229+ return pointer_data ()->self ;
230+ } else {
231+ return data_.target ;
232+ }
233+ }
234+
235+ template <typename T, bool kIsWeak >
236+ BaseObjectPtrImpl<T, kIsWeak >::~BaseObjectPtrImpl () {
237+ if (get () == nullptr ) return ;
238+ if (kIsWeak ) {
239+ if (--pointer_data ()->weak_ptr_count == 0 &&
240+ pointer_data ()->self == nullptr ) {
241+ delete pointer_data ();
242+ }
243+ } else {
244+ get ()->decrease_refcount ();
245+ }
246+ }
247+
248+ template <typename T, bool kIsWeak >
249+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl() {
250+ data_.target = nullptr ;
251+ }
252+
253+ template <typename T, bool kIsWeak >
254+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(T* target)
255+ : BaseObjectPtrImpl() {
256+ if (target == nullptr ) return ;
257+ if (kIsWeak ) {
258+ data_.pointer_data = target->pointer_data ();
259+ CHECK_NOT_NULL (pointer_data ());
260+ pointer_data ()->weak_ptr_count ++;
261+ } else {
262+ data_.target = target;
263+ CHECK_NOT_NULL (pointer_data ());
264+ get ()->increase_refcount ();
265+ }
266+ }
267+
268+ template <typename T, bool kIsWeak >
269+ template <typename U, bool kW >
270+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(
271+ const BaseObjectPtrImpl<U, kW >& other)
272+ : BaseObjectPtrImpl(other.get()) {}
273+
274+ template <typename T, bool kIsWeak >
275+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(const BaseObjectPtrImpl& other)
276+ : BaseObjectPtrImpl(other.get()) {}
277+
278+ template <typename T, bool kIsWeak >
279+ template <typename U, bool kW >
280+ BaseObjectPtrImpl<T, kIsWeak >& BaseObjectPtrImpl<T, kIsWeak >::operator =(
281+ const BaseObjectPtrImpl<U, kW >& other) {
282+ if (other.get () == get ()) return *this ;
283+ this ->~BaseObjectPtrImpl ();
284+ return *new (this ) BaseObjectPtrImpl (other);
285+ }
286+
287+ template <typename T, bool kIsWeak >
288+ BaseObjectPtrImpl<T, kIsWeak >& BaseObjectPtrImpl<T, kIsWeak >::operator =(
289+ const BaseObjectPtrImpl& other) {
290+ if (other.get () == get ()) return *this ;
291+ this ->~BaseObjectPtrImpl ();
292+ return *new (this ) BaseObjectPtrImpl (other);
293+ }
294+
295+ template <typename T, bool kIsWeak >
296+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(BaseObjectPtrImpl&& other)
297+ : data_(other.data_) {
298+ if (kIsWeak )
299+ other.data_ .target = nullptr ;
300+ else
301+ other.data_ .pointer_data = nullptr ;
302+ }
303+
304+ template <typename T, bool kIsWeak >
305+ BaseObjectPtrImpl<T, kIsWeak >& BaseObjectPtrImpl<T, kIsWeak >::operator =(
306+ BaseObjectPtrImpl&& other) {
307+ if (&other == this ) return *this ;
308+ this ->~BaseObjectPtrImpl ();
309+ return *new (this ) BaseObjectPtrImpl (std::move (other));
310+ }
311+
312+ template <typename T, bool kIsWeak >
313+ void BaseObjectPtrImpl<T, kIsWeak >::reset(T* ptr) {
314+ *this = BaseObjectPtrImpl (ptr);
315+ }
316+
317+ template <typename T, bool kIsWeak >
318+ T* BaseObjectPtrImpl<T, kIsWeak >::get() const {
319+ return static_cast <T*>(get_base_object ());
320+ }
321+
322+ template <typename T, bool kIsWeak >
323+ T& BaseObjectPtrImpl<T, kIsWeak >::operator *() const {
324+ return *get ();
325+ }
326+
327+ template <typename T, bool kIsWeak >
328+ T* BaseObjectPtrImpl<T, kIsWeak >::operator ->() const {
329+ return get ();
330+ }
331+
332+ template <typename T, bool kIsWeak >
333+ BaseObjectPtrImpl<T, kIsWeak >::operator bool () const {
334+ return get () != nullptr ;
335+ }
336+
337+ template <typename T, typename ... Args>
338+ BaseObjectPtr<T> MakeBaseObject (Args&&... args) {
339+ return BaseObjectPtr<T>(new T (std::forward<Args>(args)...));
340+ }
341+
342+ template <typename T, typename ... Args>
343+ BaseObjectPtr<T> MakeDetachedBaseObject (Args&&... args) {
344+ BaseObjectPtr<T> target = MakeBaseObject<T>(std::forward<Args>(args)...);
345+ target->Detach ();
346+ return target;
347+ }
348+
152349} // namespace node
153350
154351#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
0 commit comments