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 7using node::BaseObject; 8using node::BaseObjectPtr; 9using node::BaseObjectWeakPtr; 10using node::Environment; 11using node::MakeBaseObject; 12using node::MakeDetachedBaseObject; 13using node::Realm; 14using v8::HandleScope; 15using v8::Isolate; 16using v8::Local; 17using v8::Object; 18 19class BaseObjectPtrTest : public EnvironmentTestFixture {}; 20 21class DummyBaseObject : public BaseObject { 22 public: 23 DummyBaseObject(Environment* env, Local<Object> obj) : BaseObject(env, obj) {} 24 25 static Local<Object> MakeJSObject(Environment* env) { 26 return BaseObject::MakeLazilyInitializedJSTemplate(env) 27 ->GetFunction(env->context()).ToLocalChecked() 28 ->NewInstance(env->context()).ToLocalChecked(); 29 } 30 31 static BaseObjectPtr<DummyBaseObject> NewDetached(Environment* env) { 32 Local<Object> obj = MakeJSObject(env); 33 return MakeDetachedBaseObject<DummyBaseObject>(env, obj); 34 } 35 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 46TEST_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 61TEST_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 80TEST_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 98TEST_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 131TEST_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 158TEST_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