| // 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 <stdint.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 |  | 
 | #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<DeleteCounter*>(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<DeleteCounter>::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<i::Isolate*>(isolate); | 
 |   isolate->Enter(); | 
 |   int deleted1 = 0; | 
 |   DeleteCounter* d1 = new DeleteCounter(&deleted1); | 
 |   { | 
 |     HandleScope scope(i_isolate); | 
 |     auto handle = Managed<DeleteCounter>::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<i::Isolate*>(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<DeleteCounter>::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<i::Isolate*>(isolate); | 
 |   isolate->Enter(); | 
 |   int deleted1 = 0; | 
 |   DeleteCounter* d1 = new DeleteCounter(&deleted1); | 
 |   { | 
 |     std::shared_ptr<DeleteCounter> shared1(d1); | 
 |     { | 
 |       HandleScope scope(i_isolate); | 
 |       auto handle = | 
 |           Managed<DeleteCounter>::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<i::Isolate*>(isolate1); | 
 |   isolate1->Enter(); | 
 |   { | 
 |     HandleScope scope1(i_isolate1); | 
 |     auto handle1 = | 
 |         Managed<DeleteCounter>::FromRawPtr(i_isolate1, 0, delete_counter); | 
 |  | 
 |     v8::Isolate* isolate2 = v8::Isolate::New(create_params); | 
 |     Isolate* i_isolate2 = reinterpret_cast<i::Isolate*>(isolate2); | 
 |     isolate2->Enter(); | 
 |     { | 
 |       HandleScope scope(i_isolate2); | 
 |       auto handle2 = | 
 |           Managed<DeleteCounter>::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<i::Isolate*>(isolate1); | 
 |   isolate1->Enter(); | 
 |   { | 
 |     HandleScope scope1(i_isolate1); | 
 |     auto handle1 = | 
 |         Managed<DeleteCounter>::FromRawPtr(i_isolate1, 0, delete_counter); | 
 |  | 
 |     v8::Isolate* isolate2 = v8::Isolate::New(create_params); | 
 |     Isolate* i_isolate2 = reinterpret_cast<i::Isolate*>(isolate2); | 
 |     isolate2->Enter(); | 
 |     { | 
 |       HandleScope scope(i_isolate2); | 
 |       auto handle2 = | 
 |           Managed<DeleteCounter>::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 |