blob: 8d9185faa76ee74ab3f275a80984a063989b521d [file] [log] [blame]
// 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