GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: base_object.cc Lines: 84 86 97.7 %
Date: 2022-10-02 04:22:39 Branches: 51 62 82.3 %

Line Branch Exec Source
1
#include "base_object.h"
2
#include "env-inl.h"
3
#include "node_realm-inl.h"
4
5
namespace node {
6
7
using v8::FunctionCallbackInfo;
8
using v8::FunctionTemplate;
9
using v8::HandleScope;
10
using v8::Local;
11
using v8::Object;
12
using v8::Value;
13
using v8::WeakCallbackInfo;
14
using v8::WeakCallbackType;
15
16
1460796
BaseObject::BaseObject(Realm* realm, Local<Object> object)
17
2921592
    : persistent_handle_(realm->isolate(), object), realm_(realm) {
18
1460796
  CHECK_EQ(false, object.IsEmpty());
19
1460796
  CHECK_GE(object->InternalFieldCount(), BaseObject::kInternalFieldCount);
20
1460796
  object->SetAlignedPointerInInternalField(BaseObject::kEmbedderType,
21
                                           &kNodeEmbedderId);
22
1460796
  object->SetAlignedPointerInInternalField(BaseObject::kSlot,
23
                                           static_cast<void*>(this));
24
1460796
  realm->AddCleanupHook(DeleteMe, static_cast<void*>(this));
25
1460796
  realm->modify_base_object_count(1);
26
1460796
}
27
28

7945984
BaseObject::~BaseObject() {
29
2895086
  realm()->modify_base_object_count(-1);
30
2895086
  realm()->RemoveCleanupHook(DeleteMe, static_cast<void*>(this));
31
32
2895086
  if (UNLIKELY(has_pointer_data())) {
33
393262
    PointerData* metadata = pointer_data();
34
393262
    CHECK_EQ(metadata->strong_ptr_count, 0);
35
393262
    metadata->self = nullptr;
36
393262
    if (metadata->weak_ptr_count == 0) delete metadata;
37
  }
38
39
2895086
  if (persistent_handle_.IsEmpty()) {
40
    // This most likely happened because the weak callback below cleared it.
41
2155812
    return;
42
  }
43
44
  {
45
739274
    HandleScope handle_scope(realm()->isolate());
46
1478548
    object()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr);
47
  }
48
}
49
50
1324035
void BaseObject::MakeWeak() {
51
1324035
  if (has_pointer_data()) {
52
42644
    pointer_data()->wants_weak_jsobj = true;
53
42644
    if (pointer_data()->strong_ptr_count > 0) return;
54
  }
55
56
2648068
  persistent_handle_.SetWeak(
57
      this,
58
1077905
      [](const WeakCallbackInfo<BaseObject>& data) {
59
1077905
        BaseObject* obj = data.GetParameter();
60
        // Clear the persistent handle so that ~BaseObject() doesn't attempt
61
        // to mess with internal fields, since the JS object may have
62
        // transitioned into an invalid state.
63
        // Refs: https://github.com/nodejs/node/issues/18897
64
1077905
        obj->persistent_handle_.Reset();
65

1077905
        CHECK_IMPLIES(obj->has_pointer_data(),
66
                      obj->pointer_data()->strong_ptr_count == 0);
67
1077905
        obj->OnGCCollect();
68
1077905
      },
69
      WeakCallbackType::kParameter);
70
}
71
72
// This just has to be different from the Chromium ones:
73
// https://source.chromium.org/chromium/chromium/src/+/main:gin/public/gin_embedders.h;l=18-23;drc=5a758a97032f0b656c3c36a3497560762495501a
74
// Otherwise, when Node is loaded in an isolate which uses cppgc, cppgc will
75
// misinterpret the data stored in the embedder fields and try to garbage
76
// collect them.
77
uint16_t kNodeEmbedderId = 0x90de;
78
79
23685
void BaseObject::LazilyInitializedJSTemplateConstructor(
80
    const FunctionCallbackInfo<Value>& args) {
81
  DCHECK(args.IsConstructCall());
82
23685
  CHECK_GE(args.This()->InternalFieldCount(), BaseObject::kInternalFieldCount);
83
23685
  args.This()->SetAlignedPointerInInternalField(BaseObject::kEmbedderType,
84
                                                &kNodeEmbedderId);
85
23685
  args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr);
86
23685
}
87
88
21851
Local<FunctionTemplate> BaseObject::MakeLazilyInitializedJSTemplate(
89
    Environment* env) {
90
  Local<FunctionTemplate> t = NewFunctionTemplate(
91
21851
      env->isolate(), LazilyInitializedJSTemplateConstructor);
92
21851
  t->Inherit(BaseObject::GetConstructorTemplate(env));
93
43702
  t->InstanceTemplate()->SetInternalFieldCount(BaseObject::kInternalFieldCount);
94
21851
  return t;
95
}
96
97
3351250
BaseObject::PointerData* BaseObject::pointer_data() {
98
3351250
  if (!has_pointer_data()) {
99
199090
    PointerData* metadata = new PointerData();
100
199090
    metadata->wants_weak_jsobj = persistent_handle_.IsWeak();
101
199090
    metadata->self = this;
102
199090
    pointer_data_ = metadata;
103
  }
104
3351250
  CHECK(has_pointer_data());
105
3351250
  return pointer_data_;
106
}
107
108
835631
void BaseObject::decrease_refcount() {
109
835631
  CHECK(has_pointer_data());
110
835631
  PointerData* metadata = pointer_data();
111
835631
  CHECK_GT(metadata->strong_ptr_count, 0);
112
835631
  unsigned int new_refcount = --metadata->strong_ptr_count;
113
835631
  if (new_refcount == 0) {
114
263962
    if (metadata->is_detached) {
115
190677
      OnGCCollect();
116

73285
    } else if (metadata->wants_weak_jsobj && !persistent_handle_.IsEmpty()) {
117
42643
      MakeWeak();
118
    }
119
  }
120
835631
}
121
122
838243
void BaseObject::increase_refcount() {
123
838243
  unsigned int prev_refcount = pointer_data()->strong_ptr_count++;
124

838243
  if (prev_refcount == 0 && !persistent_handle_.IsEmpty())
125
266407
    persistent_handle_.ClearWeak();
126
838243
}
127
128
169907
void BaseObject::DeleteMe(void* data) {
129
169907
  BaseObject* self = static_cast<BaseObject*>(data);
130

169907
  if (self->has_pointer_data() && self->pointer_data()->strong_ptr_count > 0) {
131
903
    return self->Detach();
132
  }
133
169004
  delete self;
134
}
135
136
1178
bool BaseObject::IsDoneInitializing() const {
137
1178
  return true;
138
}
139
140
649
Local<Object> BaseObject::WrappedObject() const {
141
649
  return object();
142
}
143
144
1298
bool BaseObject::IsRootNode() const {
145
2596
  return !persistent_handle_.IsWeak();
146
}
147
148
56284
Local<FunctionTemplate> BaseObject::GetConstructorTemplate(
149
    IsolateData* isolate_data) {
150
56284
  Local<FunctionTemplate> tmpl = isolate_data->base_object_ctor_template();
151
56284
  if (tmpl.IsEmpty()) {
152
791
    tmpl = NewFunctionTemplate(isolate_data->isolate(), nullptr);
153
791
    tmpl->SetClassName(
154
        FIXED_ONE_BYTE_STRING(isolate_data->isolate(), "BaseObject"));
155
791
    isolate_data->set_base_object_ctor_template(tmpl);
156
  }
157
56284
  return tmpl;
158
}
159
160
bool BaseObject::IsNotIndicativeOfMemoryLeakAtExit() const {
161
  return IsWeakOrDetached();
162
}
163
164
}  // namespace node