// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include "src/objects/managed.h" #include "src/objects/objects-inl.h" #include "test/cctest/cctest.h" namespace v8 { namespace internal { class DeleteCounter { public: explicit DeleteCounter(int* deleted) : deleted_(deleted) { *deleted_ = 0; } ~DeleteCounter() { (*deleted_)++; } static void Deleter(void* arg) { delete reinterpret_cast(arg); } private: int* deleted_; }; TEST(GCCausesDestruction) { Isolate* isolate = CcTest::InitIsolateOnce(); int deleted1 = 0; int deleted2 = 0; DeleteCounter* d1 = new DeleteCounter(&deleted1); DeleteCounter* d2 = new DeleteCounter(&deleted2); { HandleScope scope(isolate); auto handle = Managed::FromRawPtr(isolate, 0, d1); USE(handle); } CcTest::CollectAllAvailableGarbage(); CHECK_EQ(1, deleted1); CHECK_EQ(0, deleted2); delete d2; CHECK_EQ(1, deleted2); } TEST(DisposeCausesDestruction1) { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::InitIsolateOnce()->array_buffer_allocator(); v8::Isolate* isolate = v8::Isolate::New(create_params); Isolate* i_isolate = reinterpret_cast(isolate); isolate->Enter(); int deleted1 = 0; DeleteCounter* d1 = new DeleteCounter(&deleted1); { HandleScope scope(i_isolate); auto handle = Managed::FromRawPtr(i_isolate, 0, d1); USE(handle); } isolate->Exit(); isolate->Dispose(); CHECK_EQ(1, deleted1); } TEST(DisposeCausesDestruction2) { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::InitIsolateOnce()->array_buffer_allocator(); v8::Isolate* isolate = v8::Isolate::New(create_params); Isolate* i_isolate = reinterpret_cast(isolate); isolate->Enter(); int deleted1 = 0; int deleted2 = 0; DeleteCounter* d1 = new DeleteCounter(&deleted1); DeleteCounter* d2 = new DeleteCounter(&deleted2); { HandleScope scope(i_isolate); auto handle = Managed::FromRawPtr(i_isolate, 0, d1); USE(handle); } ManagedPtrDestructor* destructor = new ManagedPtrDestructor(0, d2, DeleteCounter::Deleter); i_isolate->RegisterManagedPtrDestructor(destructor); isolate->Exit(); isolate->Dispose(); CHECK_EQ(1, deleted1); CHECK_EQ(1, deleted2); } TEST(DisposeWithAnotherSharedPtr) { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::InitIsolateOnce()->array_buffer_allocator(); v8::Isolate* isolate = v8::Isolate::New(create_params); Isolate* i_isolate = reinterpret_cast(isolate); isolate->Enter(); int deleted1 = 0; DeleteCounter* d1 = new DeleteCounter(&deleted1); { std::shared_ptr shared1(d1); { HandleScope scope(i_isolate); auto handle = Managed::FromSharedPtr(i_isolate, 0, shared1); USE(handle); } isolate->Exit(); isolate->Dispose(); CHECK_EQ(0, deleted1); } // Should be deleted after the second shared pointer is destroyed. CHECK_EQ(1, deleted1); } TEST(DisposeAcrossIsolates) { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::InitIsolateOnce()->array_buffer_allocator(); int deleted = 0; DeleteCounter* delete_counter = new DeleteCounter(&deleted); v8::Isolate* isolate1 = v8::Isolate::New(create_params); Isolate* i_isolate1 = reinterpret_cast(isolate1); isolate1->Enter(); { HandleScope scope1(i_isolate1); auto handle1 = Managed::FromRawPtr(i_isolate1, 0, delete_counter); v8::Isolate* isolate2 = v8::Isolate::New(create_params); Isolate* i_isolate2 = reinterpret_cast(isolate2); isolate2->Enter(); { HandleScope scope(i_isolate2); auto handle2 = Managed::FromSharedPtr(i_isolate2, 0, handle1->get()); USE(handle2); } isolate2->Exit(); isolate2->Dispose(); CHECK_EQ(0, deleted); } // Should be deleted after the first isolate is destroyed. isolate1->Exit(); isolate1->Dispose(); CHECK_EQ(1, deleted); } TEST(CollectAcrossIsolates) { v8::Isolate::CreateParams create_params; create_params.array_buffer_allocator = CcTest::InitIsolateOnce()->array_buffer_allocator(); int deleted = 0; DeleteCounter* delete_counter = new DeleteCounter(&deleted); v8::Isolate* isolate1 = v8::Isolate::New(create_params); Isolate* i_isolate1 = reinterpret_cast(isolate1); isolate1->Enter(); { HandleScope scope1(i_isolate1); auto handle1 = Managed::FromRawPtr(i_isolate1, 0, delete_counter); v8::Isolate* isolate2 = v8::Isolate::New(create_params); Isolate* i_isolate2 = reinterpret_cast(isolate2); isolate2->Enter(); { HandleScope scope(i_isolate2); auto handle2 = Managed::FromSharedPtr(i_isolate2, 0, handle1->get()); USE(handle2); } i_isolate2->heap()->CollectAllAvailableGarbage( i::GarbageCollectionReason::kTesting); CHECK_EQ(0, deleted); isolate2->Exit(); isolate2->Dispose(); CHECK_EQ(0, deleted); } // Should be deleted after the first isolate is destroyed. i_isolate1->heap()->CollectAllAvailableGarbage( i::GarbageCollectionReason::kTesting); CHECK_EQ(1, deleted); isolate1->Exit(); isolate1->Dispose(); CHECK_EQ(1, deleted); } } // namespace internal } // namespace v8