32
32
namespace node {
33
33
34
34
BaseObject::BaseObject (Environment* env, v8::Local<v8::Object> object)
35
- : persistent_handle_(env->isolate (), object),
36
- env_(env) {
35
+ : persistent_handle_(env->isolate (), object), env_(env) {
37
36
CHECK_EQ (false , object.IsEmpty ());
38
37
CHECK_GT (object->InternalFieldCount (), 0 );
39
38
object->SetAlignedPointerInInternalField (0 , static_cast <void *>(this ));
40
- env_->AddCleanupHook (DeleteMe, static_cast <void *>(this ));
39
+ env->AddCleanupHook (DeleteMe, static_cast <void *>(this ));
40
+ env->modify_base_object_count (1 );
41
41
}
42
42
43
43
BaseObject::~BaseObject () {
44
- RemoveCleanupHook ();
44
+ env ()->modify_base_object_count (-1 );
45
+ env ()->RemoveCleanupHook (DeleteMe, static_cast <void *>(this ));
46
+
47
+ if (UNLIKELY (has_pointer_data ())) {
48
+ PointerData* metadata = pointer_data ();
49
+ CHECK_EQ (metadata->strong_ptr_count , 0 );
50
+ metadata->self = nullptr ;
51
+ if (metadata->weak_ptr_count == 0 )
52
+ delete metadata;
53
+ }
45
54
46
55
if (persistent_handle_.IsEmpty ()) {
47
56
// This most likely happened because the weak callback below cleared it.
48
57
return ;
49
58
}
50
59
51
60
{
52
- v8::HandleScope handle_scope (env_ ->isolate ());
61
+ v8::HandleScope handle_scope (env () ->isolate ());
53
62
object ()->SetAlignedPointerInInternalField (0 , nullptr );
54
63
}
55
64
}
@@ -58,20 +67,25 @@ void BaseObject::RemoveCleanupHook() {
58
67
env_->RemoveCleanupHook (DeleteMe, static_cast <void *>(this ));
59
68
}
60
69
70
+ void BaseObject::Detach () {
71
+ CHECK_GT (pointer_data ()->strong_ptr_count , 0 );
72
+ pointer_data ()->is_detached = true ;
73
+ }
74
+
61
75
v8::Global<v8::Object>& BaseObject::persistent () {
62
76
return persistent_handle_;
63
77
}
64
78
65
79
66
80
v8::Local<v8::Object> BaseObject::object () const {
67
- return PersistentToLocal::Default (env_ ->isolate (), persistent_handle_);
81
+ return PersistentToLocal::Default (env () ->isolate (), persistent_handle_);
68
82
}
69
83
70
84
v8::Local<v8::Object> BaseObject::object (v8::Isolate* isolate) const {
71
85
v8::Local<v8::Object> handle = object ();
72
86
73
87
DCHECK_EQ (handle->CreationContext ()->GetIsolate (), isolate);
74
- DCHECK_EQ (env_ ->isolate (), isolate);
88
+ DCHECK_EQ (env () ->isolate (), isolate);
75
89
76
90
return handle;
77
91
}
@@ -80,7 +94,6 @@ Environment* BaseObject::env() const {
80
94
return env_;
81
95
}
82
96
83
-
84
97
BaseObject* BaseObject::FromJSObject (v8::Local<v8::Object> obj) {
85
98
CHECK_GT (obj->InternalFieldCount (), 0 );
86
99
return static_cast <BaseObject*>(obj->GetAlignedPointerFromInternalField (0 ));
@@ -94,20 +107,34 @@ T* BaseObject::FromJSObject(v8::Local<v8::Object> object) {
94
107
95
108
96
109
void BaseObject::MakeWeak () {
110
+ if (has_pointer_data ()) {
111
+ pointer_data ()->wants_weak_jsobj = true ;
112
+ if (pointer_data ()->strong_ptr_count > 0 ) return ;
113
+ }
114
+
97
115
persistent_handle_.SetWeak (
98
116
this ,
99
117
[](const v8::WeakCallbackInfo<BaseObject>& data) {
100
- std::unique_ptr< BaseObject> obj ( data.GetParameter () );
118
+ BaseObject* obj = data.GetParameter ();
101
119
// Clear the persistent handle so that ~BaseObject() doesn't attempt
102
120
// to mess with internal fields, since the JS object may have
103
121
// transitioned into an invalid state.
104
122
// Refs: https://github.com/nodejs/node/issues/18897
105
123
obj->persistent_handle_ .Reset ();
124
+ CHECK_IMPLIES (obj->has_pointer_data (),
125
+ obj->pointer_data ()->strong_ptr_count == 0 );
126
+ obj->OnGCCollect ();
106
127
}, v8::WeakCallbackType::kParameter );
107
128
}
108
129
130
+ void BaseObject::OnGCCollect () {
131
+ delete this ;
132
+ }
109
133
110
134
void BaseObject::ClearWeak () {
135
+ if (has_pointer_data ())
136
+ pointer_data ()->wants_weak_jsobj = false ;
137
+
111
138
persistent_handle_.ClearWeak ();
112
139
}
113
140
@@ -141,6 +168,176 @@ void BaseObject::InternalFieldSet(v8::Local<v8::String> property,
141
168
info.This ()->SetInternalField (Field, value);
142
169
}
143
170
171
+ bool BaseObject::has_pointer_data () const {
172
+ return pointer_data_ != nullptr ;
173
+ }
174
+
175
+ BaseObject::PointerData* BaseObject::pointer_data () {
176
+ if (!has_pointer_data ()) {
177
+ PointerData* metadata = new PointerData ();
178
+ metadata->wants_weak_jsobj = persistent_handle_.IsWeak ();
179
+ metadata->self = this ;
180
+ pointer_data_ = metadata;
181
+ }
182
+ CHECK (has_pointer_data ());
183
+ return pointer_data_;
184
+ }
185
+
186
+ void BaseObject::decrease_refcount () {
187
+ CHECK (has_pointer_data ());
188
+ PointerData* metadata = pointer_data ();
189
+ CHECK_GT (metadata->strong_ptr_count , 0 );
190
+ unsigned int new_refcount = --metadata->strong_ptr_count ;
191
+ if (new_refcount == 0 ) {
192
+ if (metadata->is_detached ) {
193
+ delete this ;
194
+ } else if (metadata->wants_weak_jsobj && !persistent_handle_.IsEmpty ()) {
195
+ MakeWeak ();
196
+ }
197
+ }
198
+ }
199
+
200
+ void BaseObject::increase_refcount () {
201
+ unsigned int prev_refcount = pointer_data ()->strong_ptr_count ++;
202
+ if (prev_refcount == 0 && !persistent_handle_.IsEmpty ())
203
+ persistent_handle_.ClearWeak ();
204
+ }
205
+
206
+ template <typename T, bool kIsWeak >
207
+ BaseObject::PointerData*
208
+ BaseObjectPtrImpl<T, kIsWeak >::pointer_data() const {
209
+ if (kIsWeak ) {
210
+ return data_.pointer_data ;
211
+ } else {
212
+ if (get_base_object () == nullptr ) return nullptr ;
213
+ return get_base_object ()->pointer_data ();
214
+ }
215
+ }
216
+
217
+ template <typename T, bool kIsWeak >
218
+ BaseObject* BaseObjectPtrImpl<T, kIsWeak >::get_base_object() const {
219
+ if (kIsWeak ) {
220
+ if (pointer_data () == nullptr ) return nullptr ;
221
+ return pointer_data ()->self ;
222
+ } else {
223
+ return data_.target ;
224
+ }
225
+ }
226
+
227
+ template <typename T, bool kIsWeak >
228
+ BaseObjectPtrImpl<T, kIsWeak >::~BaseObjectPtrImpl () {
229
+ if (get () == nullptr ) return ;
230
+ if (kIsWeak ) {
231
+ if (--pointer_data ()->weak_ptr_count == 0 &&
232
+ pointer_data ()->self == nullptr ) {
233
+ delete pointer_data ();
234
+ }
235
+ } else {
236
+ get ()->decrease_refcount ();
237
+ }
238
+ }
239
+
240
+ template <typename T, bool kIsWeak >
241
+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl() {
242
+ data_.target = nullptr ;
243
+ }
244
+
245
+ template <typename T, bool kIsWeak >
246
+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(T* target)
247
+ : BaseObjectPtrImpl() {
248
+ if (target == nullptr ) return ;
249
+ if (kIsWeak ) {
250
+ data_.pointer_data = target->pointer_data ();
251
+ CHECK_NOT_NULL (pointer_data ());
252
+ pointer_data ()->weak_ptr_count ++;
253
+ } else {
254
+ data_.target = target;
255
+ CHECK_NOT_NULL (pointer_data ());
256
+ get ()->increase_refcount ();
257
+ }
258
+ }
259
+
260
+ template <typename T, bool kIsWeak >
261
+ template <typename U, bool kW >
262
+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(
263
+ const BaseObjectPtrImpl<U, kW >& other)
264
+ : BaseObjectPtrImpl(other.get()) {}
265
+
266
+ template <typename T, bool kIsWeak >
267
+ BaseObjectPtrImpl<T, kIsWeak >::BaseObjectPtrImpl(const BaseObjectPtrImpl& other)
268
+ : BaseObjectPtrImpl(other.get()) {}
269
+
270
+ template <typename T, bool kIsWeak >
271
+ template <typename U, bool kW >
272
+ BaseObjectPtrImpl<T, kIsWeak >& BaseObjectPtrImpl<T, kIsWeak >::operator =(
273
+ const BaseObjectPtrImpl<U, kW >& other) {
274
+ if (other.get () == get ()) return *this ;
275
+ this ->~BaseObjectPtrImpl ();
276
+ return *new (this ) BaseObjectPtrImpl (other);
277
+ }
278
+
279
+ template <typename T, bool kIsWeak >
280
+ BaseObjectPtrImpl<T, kIsWeak >& BaseObjectPtrImpl<T, kIsWeak >::operator =(
281
+ const BaseObjectPtrImpl& 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(BaseObjectPtrImpl&& other)
289
+ : data_(other.data_) {
290
+ if (kIsWeak )
291
+ other.data_ .target = nullptr ;
292
+ else
293
+ other.data_ .pointer_data = nullptr ;
294
+ }
295
+
296
+ template <typename T, bool kIsWeak >
297
+ BaseObjectPtrImpl<T, kIsWeak >& BaseObjectPtrImpl<T, kIsWeak >::operator =(
298
+ BaseObjectPtrImpl&& other) {
299
+ if (&other == this ) return *this ;
300
+ this ->~BaseObjectPtrImpl ();
301
+ return *new (this ) BaseObjectPtrImpl (std::move (other));
302
+ }
303
+
304
+ template <typename T, bool kIsWeak >
305
+ void BaseObjectPtrImpl<T, kIsWeak >::reset(T* ptr) {
306
+ *this = BaseObjectPtrImpl (ptr);
307
+ }
308
+
309
+ template <typename T, bool kIsWeak >
310
+ T* BaseObjectPtrImpl<T, kIsWeak >::get() const {
311
+ return static_cast <T*>(get_base_object ());
312
+ }
313
+
314
+ template <typename T, bool kIsWeak >
315
+ T& BaseObjectPtrImpl<T, kIsWeak >::operator *() const {
316
+ return *get ();
317
+ }
318
+
319
+ template <typename T, bool kIsWeak >
320
+ T* BaseObjectPtrImpl<T, kIsWeak >::operator ->() const {
321
+ return get ();
322
+ }
323
+
324
+ template <typename T, bool kIsWeak >
325
+ BaseObjectPtrImpl<T, kIsWeak >::operator bool () const {
326
+ return get () != nullptr ;
327
+ }
328
+
329
+ template <typename T, typename ... Args>
330
+ BaseObjectPtr<T> MakeBaseObject (Args&&... args) {
331
+ return BaseObjectPtr<T>(new T (std::forward<Args>(args)...));
332
+ }
333
+
334
+ template <typename T, typename ... Args>
335
+ BaseObjectPtr<T> MakeDetachedBaseObject (Args&&... args) {
336
+ BaseObjectPtr<T> target = MakeBaseObject<T>(std::forward<Args>(args)...);
337
+ target->Detach ();
338
+ return target;
339
+ }
340
+
144
341
} // namespace node
145
342
146
343
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
0 commit comments