aboutsummaryrefslogtreecommitdiff
path: root/test/cctest/test_base_object_ptr.cc
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-09-29 01:29:07 +0200
committerAnna Henningsen <anna@addaleax.net>2019-11-19 13:47:29 +0100
commit7e6104f1bb63a07885b08f277c3b708caa6b8a23 (patch)
tree32d76e6f055d3bfacd849633db3a8af3868a328c /test/cctest/test_base_object_ptr.cc
parentefce655c0f1671d0e86b5c89092ac93db983ef94 (diff)
downloadandroid-node-v8-7e6104f1bb63a07885b08f277c3b708caa6b8a23.tar.gz
android-node-v8-7e6104f1bb63a07885b08f277c3b708caa6b8a23.tar.bz2
android-node-v8-7e6104f1bb63a07885b08f277c3b708caa6b8a23.zip
src: introduce custom smart pointers for `BaseObject`s
Referring to `BaseObject` instances using standard C++ smart pointers can interfere with BaseObject’s own cleanup mechanisms (explicit delete, delete-on-GC and delete-on-cleanup). Introducing custom smart pointers allows referring to `BaseObject`s safely while keeping those mechanisms intact. Refs: https://github.com/nodejs/quic/pull/141 Refs: https://github.com/nodejs/quic/pull/149 Reviewed-By: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/30374 Refs: https://github.com/nodejs/quic/pull/165 Reviewed-By: David Carlier <devnexen@gmail.com>
Diffstat (limited to 'test/cctest/test_base_object_ptr.cc')
-rw-r--r--test/cctest/test_base_object_ptr.cc176
1 files changed, 176 insertions, 0 deletions
diff --git a/test/cctest/test_base_object_ptr.cc b/test/cctest/test_base_object_ptr.cc
new file mode 100644
index 0000000000..18e27edba8
--- /dev/null
+++ b/test/cctest/test_base_object_ptr.cc
@@ -0,0 +1,176 @@
+#include "gtest/gtest.h"
+#include "node.h"
+#include "base_object-inl.h"
+#include "node_test_fixture.h"
+
+using node::BaseObject;
+using node::BaseObjectPtr;
+using node::BaseObjectWeakPtr;
+using node::Environment;
+using node::MakeBaseObject;
+using node::MakeDetachedBaseObject;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+
+class BaseObjectPtrTest : public EnvironmentTestFixture {};
+
+class DummyBaseObject : public BaseObject {
+ public:
+ DummyBaseObject(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
+
+ static Local<Object> MakeJSObject(Environment* env) {
+ return BaseObject::MakeLazilyInitializedJSTemplate(env)
+ ->GetFunction(env->context()).ToLocalChecked()
+ ->NewInstance(env->context()).ToLocalChecked();
+ }
+
+ static BaseObjectPtr<DummyBaseObject> NewDetached(Environment* env) {
+ Local<Object> obj = MakeJSObject(env);
+ return MakeDetachedBaseObject<DummyBaseObject>(env, obj);
+ }
+
+ static BaseObjectPtr<DummyBaseObject> New(Environment* env) {
+ Local<Object> obj = MakeJSObject(env);
+ return MakeBaseObject<DummyBaseObject>(env, obj);
+ }
+
+ SET_NO_MEMORY_INFO()
+ SET_MEMORY_INFO_NAME(DummyBaseObject)
+ SET_SELF_SIZE(DummyBaseObject)
+};
+
+TEST_F(BaseObjectPtrTest, ScopedDetached) {
+ const HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env_{handle_scope, argv};
+ Environment* env = *env_;
+
+ EXPECT_EQ(env->base_object_count(), 0);
+ {
+ BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
+ EXPECT_EQ(env->base_object_count(), 1);
+ }
+ EXPECT_EQ(env->base_object_count(), 0);
+}
+
+TEST_F(BaseObjectPtrTest, ScopedDetachedWithWeak) {
+ const HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env_{handle_scope, argv};
+ Environment* env = *env_;
+
+ BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
+
+ EXPECT_EQ(env->base_object_count(), 0);
+ {
+ BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
+ weak_ptr = ptr;
+ EXPECT_EQ(env->base_object_count(), 1);
+ }
+ EXPECT_EQ(weak_ptr.get(), nullptr);
+ EXPECT_EQ(env->base_object_count(), 0);
+}
+
+TEST_F(BaseObjectPtrTest, Undetached) {
+ const HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env_{handle_scope, argv};
+ Environment* env = *env_;
+
+ node::AddEnvironmentCleanupHook(isolate_, [](void* arg) {
+ EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(), 0);
+ }, env);
+
+ BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
+ EXPECT_EQ(env->base_object_count(), 1);
+}
+
+TEST_F(BaseObjectPtrTest, GCWeak) {
+ const HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env_{handle_scope, argv};
+ Environment* env = *env_;
+
+ BaseObjectWeakPtr<DummyBaseObject> weak_ptr;
+
+ {
+ const HandleScope handle_scope(isolate_);
+ BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::New(env);
+ weak_ptr = ptr;
+ ptr->MakeWeak();
+
+ EXPECT_EQ(env->base_object_count(), 1);
+ EXPECT_EQ(weak_ptr.get(), ptr.get());
+ EXPECT_EQ(weak_ptr->persistent().IsWeak(), false);
+
+ ptr.reset();
+ }
+
+ EXPECT_EQ(env->base_object_count(), 1);
+ EXPECT_NE(weak_ptr.get(), nullptr);
+ EXPECT_EQ(weak_ptr->persistent().IsWeak(), true);
+
+ v8::V8::SetFlagsFromString("--expose-gc");
+ isolate_->RequestGarbageCollectionForTesting(Isolate::kFullGarbageCollection);
+
+ EXPECT_EQ(env->base_object_count(), 0);
+ EXPECT_EQ(weak_ptr.get(), nullptr);
+}
+
+TEST_F(BaseObjectPtrTest, Moveable) {
+ const HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env_{handle_scope, argv};
+ Environment* env = *env_;
+
+ BaseObjectPtr<DummyBaseObject> ptr = DummyBaseObject::NewDetached(env);
+ EXPECT_EQ(env->base_object_count(), 1);
+ BaseObjectWeakPtr<DummyBaseObject> weak_ptr { ptr };
+ EXPECT_EQ(weak_ptr.get(), ptr.get());
+
+ BaseObjectPtr<DummyBaseObject> ptr2 = std::move(ptr);
+ EXPECT_EQ(weak_ptr.get(), ptr2.get());
+ EXPECT_EQ(ptr.get(), nullptr);
+
+ BaseObjectWeakPtr<DummyBaseObject> weak_ptr2 = std::move(weak_ptr);
+ EXPECT_EQ(weak_ptr2.get(), ptr2.get());
+ EXPECT_EQ(weak_ptr.get(), nullptr);
+ EXPECT_EQ(env->base_object_count(), 1);
+
+ ptr2.reset();
+
+ EXPECT_EQ(weak_ptr2.get(), nullptr);
+ EXPECT_EQ(env->base_object_count(), 0);
+}
+
+TEST_F(BaseObjectPtrTest, NestedClasses) {
+ class ObjectWithPtr : public BaseObject {
+ public:
+ ObjectWithPtr(Environment* env, Local<Object> obj) : BaseObject(env, obj) {}
+
+ BaseObjectPtr<BaseObject> ptr1;
+ BaseObjectPtr<BaseObject> ptr2;
+
+ SET_NO_MEMORY_INFO()
+ SET_MEMORY_INFO_NAME(ObjectWithPtr)
+ SET_SELF_SIZE(ObjectWithPtr)
+ };
+
+ const HandleScope handle_scope(isolate_);
+ const Argv argv;
+ Env env_{handle_scope, argv};
+ Environment* env = *env_;
+
+ node::AddEnvironmentCleanupHook(isolate_, [](void* arg) {
+ EXPECT_EQ(static_cast<Environment*>(arg)->base_object_count(), 0);
+ }, env);
+
+ ObjectWithPtr* obj =
+ new ObjectWithPtr(env, DummyBaseObject::MakeJSObject(env));
+ obj->ptr1 = DummyBaseObject::NewDetached(env);
+ obj->ptr2 = DummyBaseObject::New(env);
+
+ EXPECT_EQ(env->base_object_count(), 3);
+}