blob: 09c9a40fdfdaa4c668497ff659f72d1a152df467 [file]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/handles.h"
#include "platform/assert.h"
#include "vm/class_finalizer.h"
#include "vm/dart_api_state.h"
#include "vm/flags.h"
#include "vm/object.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
#include "vm/zone.h"
namespace dart {
// Unit test for Zone handle allocation.
ISOLATE_UNIT_TEST_CASE(AllocateZoneHandle) {
#if defined(DEBUG)
FLAG_trace_handles = true;
#endif
// The previously run stub code generation may have created zone handles.
int initial_count = VMHandles::ZoneHandleCount();
const int kNumHandles = 65;
// Create some zone handles.
for (int i = 0; i < kNumHandles; i++) {
const Smi& handle = Smi::ZoneHandle(Smi::New(i));
EXPECT(handle.IsSmi());
EXPECT_EQ(i, handle.Value());
}
EXPECT_EQ(kNumHandles + initial_count, VMHandles::ZoneHandleCount());
// Create some more zone handles.
for (int i = kNumHandles; i < (2 * kNumHandles); i++) {
const Smi& handle = Smi::ZoneHandle(Smi::New(i));
EXPECT(handle.IsSmi());
EXPECT_EQ(i, handle.Value());
}
EXPECT_EQ((2 * kNumHandles) + initial_count, VMHandles::ZoneHandleCount());
}
// Unit test for Scope handle allocation.
ISOLATE_UNIT_TEST_CASE(AllocateScopeHandle) {
#if defined(DEBUG)
FLAG_trace_handles = true;
#endif
int32_t handle_count = VMHandles::ScopedHandleCount();
const int kNumHandles = 65;
// Create some scoped handles.
{
Thread* thread = Thread::Current();
HANDLESCOPE(thread);
for (int i = 0; i < kNumHandles; i++) {
const Smi& handle = Smi::Handle(Smi::New(i));
EXPECT(handle.IsSmi());
EXPECT_EQ(i, handle.Value());
}
EXPECT_EQ((handle_count + kNumHandles), VMHandles::ScopedHandleCount());
// Create lots of scoped handles in a loop with a nested scope.
for (int loop = 0; loop < 1000; loop++) {
HANDLESCOPE(thread);
for (int i = 0; i < 2; i++) {
const Smi& handle = Smi::Handle(Smi::New(i + loop));
EXPECT(handle.IsSmi());
EXPECT_EQ(i + loop, handle.Value());
}
EXPECT_EQ((handle_count + kNumHandles + 2),
VMHandles::ScopedHandleCount());
}
EXPECT_EQ((handle_count + kNumHandles), VMHandles::ScopedHandleCount());
for (int i = 0; i < kNumHandles; i++) {
const Smi& handle = Smi::Handle(Smi::New(i));
EXPECT(handle.IsSmi());
EXPECT_EQ(i, handle.Value());
}
EXPECT_EQ((handle_count + (2 * kNumHandles)),
VMHandles::ScopedHandleCount());
}
EXPECT_EQ(handle_count, VMHandles::ScopedHandleCount());
}
static void NoopCallback(void* isolate_callback_data, void* peer) {}
// Unit test for handle validity checks.
TEST_CASE(CheckHandleValidity) {
#if defined(DEBUG)
FLAG_trace_handles = true;
#endif
Dart_Handle handle = nullptr;
// Check validity using zone handles.
{
TransitionNativeToVM transition(thread);
StackZone sz(thread);
handle = reinterpret_cast<Dart_Handle>(&Smi::ZoneHandle(Smi::New(1)));
{
TransitionVMToNative to_native(thread);
EXPECT_VALID(handle);
}
}
EXPECT(!Api::IsValid(handle));
// Check validity using scoped handles.
{
Dart_EnterScope();
{
TransitionNativeToVM transition(thread);
HANDLESCOPE(thread);
handle = reinterpret_cast<Dart_Handle>(&Smi::Handle(Smi::New(1)));
{
TransitionVMToNative to_native(thread);
EXPECT_VALID(handle);
}
}
Dart_ExitScope();
}
EXPECT(!Api::IsValid(handle));
// Check validity using persistent handle.
Dart_Handle scoped_handle;
{
TransitionNativeToVM transition(thread);
scoped_handle = Api::NewHandle(thread, Smi::New(1));
}
Dart_PersistentHandle persistent_handle =
Dart_NewPersistentHandle(scoped_handle);
EXPECT_VALID(persistent_handle);
Dart_DeletePersistentHandle(persistent_handle);
EXPECT(!Api::IsValid(persistent_handle));
// Check validity using weak persistent handle.
handle = reinterpret_cast<Dart_Handle>(Dart_NewWeakPersistentHandle(
Dart_NewStringFromCString("foo"), nullptr, 0, NoopCallback));
EXPECT_NOTNULL(handle);
EXPECT_VALID(handle);
Dart_DeleteWeakPersistentHandle(
reinterpret_cast<Dart_WeakPersistentHandle>(handle));
EXPECT(!Api::IsValid(handle));
}
TEST_CASE(FieldScriptHandleAllocation) {
const char* kScriptChars =
"class Foo {\n"
" var field1;\n"
" var field2 = 123;\n"
" void bar() {}\n"
"}\n";
Dart_Handle lib_handle = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib_handle);
TransitionNativeToVM transition(thread);
EXPECT(ClassFinalizer::ProcessPendingClasses());
const Library& lib =
Library::Handle(Library::RawCast(Api::UnwrapHandle(lib_handle)));
EXPECT(!lib.IsNull());
const Class& cls = Class::Handle(
lib.LookupClass(String::Handle(Symbols::New(thread, "Foo"))));
EXPECT(!cls.IsNull());
const auto& error = cls.EnsureIsFinalized(thread);
EXPECT(error == Error::null());
const Array& fields = Array::Handle(cls.fields());
EXPECT_GT(fields.Length(), 0);
Field& field = Field::Handle();
field ^= fields.At(0);
int32_t handle_count = VMHandles::ScopedHandleCount();
for (int i = 0; i < 100; i++) {
field.Script();
}
// Field::Script() should not allocate scoped handles.
EXPECT_EQ(handle_count, VMHandles::ScopedHandleCount());
}
TEST_CASE(FunctionScriptHandleAllocation) {
const char* kScriptChars =
"class Foo {\n"
" void bar() {}\n"
"}\n";
Dart_Handle lib_handle = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib_handle);
TransitionNativeToVM transition(thread);
EXPECT(ClassFinalizer::ProcessPendingClasses());
const Library& lib =
Library::Handle(Library::RawCast(Api::UnwrapHandle(lib_handle)));
EXPECT(!lib.IsNull());
const Class& cls = Class::Handle(
lib.LookupClass(String::Handle(Symbols::New(thread, "Foo"))));
EXPECT(!cls.IsNull());
const auto& error = cls.EnsureIsFinalized(thread);
EXPECT(error == Error::null());
const Array& functions = Array::Handle(cls.current_functions());
EXPECT_GT(functions.Length(), 0);
Function& function = Function::Handle();
function ^= functions.At(0);
int32_t handle_count = VMHandles::ScopedHandleCount();
for (int i = 0; i < 100; i++) {
function.script();
}
// Function::script() should not allocate scoped handles.
EXPECT_EQ(handle_count, VMHandles::ScopedHandleCount());
}
} // namespace dart