1 #include "base_object-inl.h"
2 #include "gtest/gtest.h"
3 #include "node.h"
4 #include "node_realm-inl.h"
5 #include "node_test_fixture.h"
6
7 using node::BaseObject;
8 using node::BaseObjectPtr;
9 using node::BaseObjectWeakPtr;
10 using node::Environment;
11 using node::MakeBaseObject;
12 using node::MakeDetachedBaseObject;
13 using node::Realm;
14 using v8::HandleScope;
15 using v8::Isolate;
16 using v8::Local;
17 using v8::Object;
18
19 class BaseObjectPtrTest : public EnvironmentTestFixture {};
20
21 class DummyBaseObject : public BaseObject {
22 public:
DummyBaseObject(Environment * env,Local<Object> obj)23 DummyBaseObject(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
24
MakeJSObject(Environment * env)25 static Local<Object> MakeJSObject(Environment* env) {
26 return BaseObject::MakeLazilyInitializedJSTemplate(env)
27 ->GetFunction(env->context()).ToLocalChecked()
28 ->NewInstance(env->context()).ToLocalChecked();
29 }
30
NewDetached(Environment * env)31 static BaseObjectPtr<DummyBaseObject> NewDetached(Environment* env) {
32 Local<Object> obj = MakeJSObject(env);
33 return MakeDetachedBaseObject<DummyBaseObject>(env, obj);
34 }
35
New(Environment * env)36 static BaseObjectPtr<DummyBaseObject> New(Environment* env) {
37 Local<Object> obj = MakeJSObject(env);
38 return MakeBaseObject<DummyBaseObject>(env, obj);
39 }
40
41 SET_NO_MEMORY_INFO()
42 SET_MEMORY_INFO_NAME(DummyBaseObject)
43 SET_SELF_SIZE(DummyBaseObject)
44 };
45
TEST_F(BaseObjectPtrTest,ScopedDetached)46 TEST_F(BaseObjectPtrTest, ScopedDetached) {
47 const HandleScope handle_scope(isolate_);
48 const Argv argv;
49 Env env_{handle_scope, argv};
50 Environment* env = *env_;
51 Realm* realm = env->principal_realm();
52
53 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0);
54 {
55 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
56 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
57 }
58 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0);
59 }
60
TEST_F(BaseObjectPtrTest,ScopedDetachedWithWeak)61 TEST_F(BaseObjectPtrTest, ScopedDetachedWithWeak) {
62 const HandleScope handle_scope(isolate_);
63 const Argv argv;
64 Env env_{handle_scope, argv};
65 Environment* env = *env_;
66 Realm* realm = env->principal_realm();
67
68 BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
69
70 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0);
71 {
72 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
73 weak_ptr = ptr;
74 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
75 }
76 EXPECT_EQ(weak_ptr.get(), nullptr);
77 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0);
78 }
79
TEST_F(BaseObjectPtrTest,Undetached)80 TEST_F(BaseObjectPtrTest, Undetached) {
81 const HandleScope handle_scope(isolate_);
82 const Argv argv;
83 Env env_{handle_scope, argv};
84 Environment* env = *env_;
85 Realm* realm = env->principal_realm();
86
87 node::AddEnvironmentCleanupHook(
88 isolate_,
89 [](void* arg) {
90 EXPECT_EQ(static_cast<Realm*>(arg)->base_object_count(), 0);
91 },
92 realm);
93
94 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
95 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
96 }
97
TEST_F(BaseObjectPtrTest,GCWeak)98 TEST_F(BaseObjectPtrTest, GCWeak) {
99 const HandleScope handle_scope(isolate_);
100 const Argv argv;
101 Env env_{handle_scope, argv};
102 Environment* env = *env_;
103 Realm* realm = env->principal_realm();
104
105 BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
106
107 {
108 const HandleScope handle_scope(isolate_);
109 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
110 weak_ptr = ptr;
111 ptr->MakeWeak();
112
113 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
114 EXPECT_EQ(weak_ptr.get(), ptr.get());
115 EXPECT_EQ(weak_ptr->persistent().IsWeak(), false);
116
117 ptr.reset();
118 }
119
120 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
121 EXPECT_NE(weak_ptr.get(), nullptr);
122 EXPECT_EQ(weak_ptr->persistent().IsWeak(), true);
123
124 v8::V8::SetFlagsFromString("--expose-gc");
125 isolate_->RequestGarbageCollectionForTesting(Isolate::kFullGarbageCollection);
126
127 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0);
128 EXPECT_EQ(weak_ptr.get(), nullptr);
129 }
130
TEST_F(BaseObjectPtrTest,Moveable)131 TEST_F(BaseObjectPtrTest, Moveable) {
132 const HandleScope handle_scope(isolate_);
133 const Argv argv;
134 Env env_{handle_scope, argv};
135 Environment* env = *env_;
136 Realm* realm = env->principal_realm();
137
138 BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
139 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
140 BaseObjectWeakPtr<DummyBaseObject> weak_ptr { ptr };
141 EXPECT_EQ(weak_ptr.get(), ptr.get());
142
143 BaseObjectPtr<DummyBaseObject> ptr2 = std::move(ptr);
144 EXPECT_EQ(weak_ptr.get(), ptr2.get());
145 EXPECT_EQ(ptr.get(), nullptr);
146
147 BaseObjectWeakPtr<DummyBaseObject> weak_ptr2 = std::move(weak_ptr);
148 EXPECT_EQ(weak_ptr2.get(), ptr2.get());
149 EXPECT_EQ(weak_ptr.get(), nullptr);
150 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 1);
151
152 ptr2.reset();
153
154 EXPECT_EQ(weak_ptr2.get(), nullptr);
155 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 0);
156 }
157
TEST_F(BaseObjectPtrTest,NestedClasses)158 TEST_F(BaseObjectPtrTest, NestedClasses) {
159 class ObjectWithPtr : public BaseObject {
160 public:
161 ObjectWithPtr(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
162
163 BaseObjectPtr<BaseObject> ptr1;
164 BaseObjectPtr<BaseObject> ptr2;
165
166 SET_NO_MEMORY_INFO()
167 SET_MEMORY_INFO_NAME(ObjectWithPtr)
168 SET_SELF_SIZE(ObjectWithPtr)
169 };
170
171 const HandleScope handle_scope(isolate_);
172 const Argv argv;
173 Env env_{handle_scope, argv};
174 Environment* env = *env_;
175 Realm* realm = env->principal_realm();
176
177 node::AddEnvironmentCleanupHook(
178 isolate_,
179 [](void* arg) {
180 EXPECT_EQ(static_cast<Realm*>(arg)->base_object_count(), 0);
181 },
182 realm);
183
184 ObjectWithPtr* obj =
185 new ObjectWithPtr(env, DummyBaseObject::MakeJSObject(env));
186 obj->ptr1 = DummyBaseObject::NewDetached(env);
187 obj->ptr2 = DummyBaseObject::New(env);
188
189 EXPECT_EQ(realm->base_object_created_after_bootstrap(), 3);
190 }
191