40
40
namespace node {
41
41
42
42
BaseObject::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) {
45
44
CHECK_EQ (false , object.IsEmpty ());
46
45
CHECK_GT (object->InternalFieldCount (), 0 );
47
46
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 );
49
49
}
50
50
51
51
BaseObject::~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
+ }
53
62
54
63
if (persistent_handle_.IsEmpty ()) {
55
64
// This most likely happened because the weak callback below cleared it.
56
65
return ;
57
66
}
58
67
59
68
{
60
- v8::HandleScope handle_scope (env_ ->isolate ());
69
+ v8::HandleScope handle_scope (env () ->isolate ());
61
70
object ()->SetAlignedPointerInInternalField (0 , nullptr );
62
71
}
63
72
}
@@ -66,20 +75,25 @@ void BaseObject::RemoveCleanupHook() {
66
75
env_->RemoveCleanupHook (DeleteMe, static_cast <void *>(this ));
67
76
}
68
77
78
+ void BaseObject::Detach () {
79
+ CHECK_GT (pointer_data ()->strong_ptr_count , 0 );
80
+ pointer_data ()->is_detached = true ;
81
+ }
82
+
69
83
v8::Global<v8::Object>& BaseObject::persistent () {
70
84
return persistent_handle_;
71
85
}
72
86
73
87
74
88
v8::Local<v8::Object> BaseObject::object () const {
75
- return PersistentToLocal::Default (env_ ->isolate (), persistent_handle_);
89
+ return PersistentToLocal::Default (env () ->isolate (), persistent_handle_);
76
90
}
77
91
78
92
v8::Local<v8::Object> BaseObject::object (v8::Isolate* isolate) const {
79
93
v8::Local<v8::Object> handle = object ();
80
94
81
95
DCHECK_EQ (handle->CreationContext ()->GetIsolate (), isolate);
82
- DCHECK_EQ (env_ ->isolate (), isolate);
96
+ DCHECK_EQ (env () ->isolate (), isolate);
83
97
84
98
return handle;
85
99
}
@@ -88,7 +102,6 @@ Environment* BaseObject::env() const {
88
102
return env_;
89
103
}
90
104
91
-
92
105
BaseObject* BaseObject::FromJSObject (v8::Local<v8::Object> obj) {
93
106
CHECK_GT (obj->InternalFieldCount (), 0 );
94
107
return static_cast <BaseObject*>(obj->GetAlignedPointerFromInternalField (0 ));
@@ -102,20 +115,34 @@ T* BaseObject::FromJSObject(v8::Local<v8::Object> object) {
102
115
103
116
104
117
void 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
+
105
123
persistent_handle_.SetWeak (
106
124
this ,
107
125
[](const v8::WeakCallbackInfo<BaseObject>& data) {
108
- std::unique_ptr< BaseObject> obj ( data.GetParameter () );
126
+ BaseObject* obj = data.GetParameter ();
109
127
// Clear the persistent handle so that ~BaseObject() doesn't attempt
110
128
// to mess with internal fields, since the JS object may have
111
129
// transitioned into an invalid state.
112
130
// Refs: https://github.com/nodejs/node/issues/18897
113
131
obj->persistent_handle_ .Reset ();
132
+ CHECK_IMPLIES (obj->has_pointer_data (),
133
+ obj->pointer_data ()->strong_ptr_count == 0 );
134
+ obj->OnGCCollect ();
114
135
}, v8::WeakCallbackType::kParameter );
115
136
}
116
137
138
+ void BaseObject::OnGCCollect () {
139
+ delete this ;
140
+ }
117
141
118
142
void BaseObject::ClearWeak () {
143
+ if (has_pointer_data ())
144
+ pointer_data ()->wants_weak_jsobj = false ;
145
+
119
146
persistent_handle_.ClearWeak ();
120
147
}
121
148
@@ -149,6 +176,176 @@ void BaseObject::InternalFieldSet(v8::Local<v8::String> property,
149
176
info.This ()->SetInternalField (Field, value);
150
177
}
151
178
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
+
152
349
} // namespace node
153
350
154
351
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
0 commit comments