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){
4544CHECK_EQ (false , object.IsEmpty ());
4645CHECK_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
5463if (persistent_handle_.IsEmpty ()){
5564// This most likely happened because the weak callback below cleared it.
5665return ;
5766 }
5867
5968{
60- v8::HandleScope handle_scope (env_ ->isolate ());
69+ v8::HandleScope handle_scope (env () ->isolate ());
6170object ()->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 (){
7084return 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
8195DCHECK_EQ (handle->CreationContext ()->GetIsolate (), isolate);
82- DCHECK_EQ (env_ ->isolate (), isolate);
96+ DCHECK_EQ (env () ->isolate (), isolate);
8397
8498return handle;
8599}
@@ -88,7 +102,6 @@ Environment* BaseObject::env() const{
88102return env_;
89103}
90104
91-
92105BaseObject* BaseObject::FromJSObject (v8::Local<v8::Object> obj){
93106CHECK_GT (obj->InternalFieldCount (), 0 );
94107return 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 (
106124this ,
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