Files
sdk/runtime/vm/dart_api_impl_test.cc
T
turnidge@google.com a70b90933a Add a missing arity check for top-level methods in Dart_Invoke.
Add a new EXPECT_ERROR macro to make it easier to verify meaningful
error messages in tests.
Review URL: https://chromiumcodereview.appspot.com//10115034

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@6705 260f80e4-7a28-3924-810f-c04153c831b5
2012-04-18 18:11:55 +00:00

4981 lines
161 KiB
C++

// 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 "include/dart_api.h"
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/class_finalizer.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_api_state.h"
#include "vm/thread.h"
#include "vm/unit_test.h"
#include "vm/verifier.h"
namespace dart {
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(ErrorHandles) {
const char* kScriptChars =
"class TestClass {\n"
" static void testMain() {\n"
" throw new Exception(\"bad news\");\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle instance = Dart_True();
Dart_Handle error = Api::NewError("myerror");
Dart_Handle exception = Dart_InvokeStatic(lib,
Dart_NewString("TestClass"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT(!Dart_IsError(instance));
EXPECT(Dart_IsError(error));
EXPECT(Dart_IsError(exception));
EXPECT(!Dart_ErrorHasException(instance));
EXPECT(!Dart_ErrorHasException(error));
EXPECT(Dart_ErrorHasException(exception));
EXPECT_STREQ("", Dart_GetError(instance));
EXPECT_STREQ("myerror", Dart_GetError(error));
EXPECT_STREQ(
"Unhandled exception:\n"
"Exception: bad news\n"
" 0. Function: 'TestClass.testMain' url: 'dart:test-lib' line:3 col:5\n",
Dart_GetError(exception));
EXPECT(Dart_IsError(Dart_ErrorGetException(instance)));
EXPECT(Dart_IsError(Dart_ErrorGetException(error)));
EXPECT_VALID(Dart_ErrorGetException(exception));
EXPECT(Dart_IsError(Dart_ErrorGetStacktrace(instance)));
EXPECT(Dart_IsError(Dart_ErrorGetStacktrace(error)));
EXPECT_VALID(Dart_ErrorGetStacktrace(exception));
}
void PropagateErrorNative(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle closure = Dart_GetNativeArgument(args, 0);
EXPECT(Dart_IsClosure(closure));
Dart_Handle result = Dart_InvokeClosure(closure, 0, NULL);
EXPECT(Dart_IsError(result));
result = Dart_PropagateError(result);
EXPECT_VALID(result); // We do not expect to reach here.
UNREACHABLE();
}
static Dart_NativeFunction PropagateError_native_lookup(
Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&PropagateErrorNative);
}
TEST_CASE(Dart_PropagateError) {
const char* kScriptChars =
"class Test {\n"
" static void raiseCompileError() {\n"
" return badIdent;\n"
" }\n"
"\n"
" static void throwException() {\n"
" throw new Exception('myException');\n"
" }\n"
" static void nativeFunc(closure) native 'Test_nativeFunc';\n"
"\n"
" static void Func1() {\n"
" nativeFunc(() => raiseCompileError());\n"
" }\n"
"\n"
" static void Func2() {\n"
" nativeFunc(() => throwException());\n"
" }\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars, &PropagateError_native_lookup);
Dart_Handle result;
result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("Func1"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT(!Dart_ErrorHasException(result));
EXPECT_SUBSTRING("badIdent", Dart_GetError(result));
result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("Func2"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("myException", Dart_GetError(result));
}
#endif
TEST_CASE(Dart_Error) {
Dart_Handle error = Dart_Error("An %s", "error");
EXPECT(Dart_IsError(error));
EXPECT_STREQ("An error", Dart_GetError(error));
}
TEST_CASE(Null) {
Dart_Handle null = Dart_Null();
EXPECT_VALID(null);
EXPECT(Dart_IsNull(null));
Dart_Handle str = Dart_NewString("test");
EXPECT_VALID(str);
EXPECT(!Dart_IsNull(str));
}
TEST_CASE(IsSame) {
bool same = false;
Dart_Handle five = Dart_NewString("5");
Dart_Handle five_again = Dart_NewString("5");
Dart_Handle seven = Dart_NewString("7");
// Same objects.
EXPECT_VALID(Dart_IsSame(five, five, &same));
EXPECT(same);
// Equal objects.
EXPECT_VALID(Dart_IsSame(five, five_again, &same));
EXPECT(!same);
// Different objects.
EXPECT_VALID(Dart_IsSame(five, seven, &same));
EXPECT(!same);
// Non-instance objects.
{
Isolate* isolate = Isolate::Current();
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle class1 = Api::NewHandle(isolate, Object::null_class());
Dart_Handle class2 = Api::NewHandle(isolate, Object::class_class());
EXPECT_VALID(Dart_IsSame(class1, class1, &same));
EXPECT(same);
EXPECT_VALID(Dart_IsSame(class1, class2, &same));
EXPECT(!same);
}
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(ObjectEquals) {
bool equal = false;
Dart_Handle five = Dart_NewString("5");
Dart_Handle five_again = Dart_NewString("5");
Dart_Handle seven = Dart_NewString("7");
// Same objects.
EXPECT_VALID(Dart_ObjectEquals(five, five, &equal));
EXPECT(equal);
// Equal objects.
EXPECT_VALID(Dart_ObjectEquals(five, five_again, &equal));
EXPECT(equal);
// Different objects.
EXPECT_VALID(Dart_ObjectEquals(five, seven, &equal));
EXPECT(!equal);
}
#endif
TEST_CASE(BooleanValues) {
Dart_Handle str = Dart_NewString("test");
EXPECT(!Dart_IsBoolean(str));
bool value = false;
Dart_Handle result = Dart_BooleanValue(str, &value);
EXPECT(Dart_IsError(result));
Dart_Handle val1 = Dart_NewBoolean(true);
EXPECT(Dart_IsBoolean(val1));
result = Dart_BooleanValue(val1, &value);
EXPECT_VALID(result);
EXPECT(value);
Dart_Handle val2 = Dart_NewBoolean(false);
EXPECT(Dart_IsBoolean(val2));
result = Dart_BooleanValue(val2, &value);
EXPECT_VALID(result);
EXPECT(!value);
}
TEST_CASE(BooleanConstants) {
Dart_Handle true_handle = Dart_True();
EXPECT_VALID(true_handle);
EXPECT(Dart_IsBoolean(true_handle));
bool value = false;
Dart_Handle result = Dart_BooleanValue(true_handle, &value);
EXPECT_VALID(result);
EXPECT(value);
Dart_Handle false_handle = Dart_False();
EXPECT_VALID(false_handle);
EXPECT(Dart_IsBoolean(false_handle));
result = Dart_BooleanValue(false_handle, &value);
EXPECT_VALID(result);
EXPECT(!value);
}
TEST_CASE(DoubleValues) {
const double kDoubleVal1 = 201.29;
const double kDoubleVal2 = 101.19;
Dart_Handle val1 = Dart_NewDouble(kDoubleVal1);
EXPECT(Dart_IsDouble(val1));
Dart_Handle val2 = Dart_NewDouble(kDoubleVal2);
EXPECT(Dart_IsDouble(val2));
double out1, out2;
Dart_Handle result = Dart_DoubleValue(val1, &out1);
EXPECT_VALID(result);
EXPECT_EQ(kDoubleVal1, out1);
result = Dart_DoubleValue(val2, &out2);
EXPECT_VALID(result);
EXPECT_EQ(kDoubleVal2, out2);
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(NumberValues) {
// TODO(antonm): add various kinds of ints (smi, mint, bigint).
const char* kScriptChars =
"class NumberValuesHelper {\n"
" static int getInt() { return 1; }\n"
" static double getDouble() { return 1.0; }\n"
" static bool getBool() { return false; }\n"
" static getNull() { return null; }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle class_name = Dart_NewString("NumberValuesHelper");
// Check int case.
result = Dart_InvokeStatic(lib,
class_name,
Dart_NewString("getInt"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsNumber(result));
// Check double case.
result = Dart_InvokeStatic(lib,
class_name,
Dart_NewString("getDouble"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsNumber(result));
// Check bool case.
result = Dart_InvokeStatic(lib,
class_name,
Dart_NewString("getBool"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(!Dart_IsNumber(result));
// Check null case.
result = Dart_InvokeStatic(lib,
class_name,
Dart_NewString("getNull"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(!Dart_IsNumber(result));
}
#endif
TEST_CASE(IntegerValues) {
const int64_t kIntegerVal1 = 100;
const int64_t kIntegerVal2 = 0xffffffff;
const char* kIntegerVal3 = "0x123456789123456789123456789";
Dart_Handle val1 = Dart_NewInteger(kIntegerVal1);
EXPECT(Dart_IsInteger(val1));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoInt64(val1, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle val2 = Dart_NewInteger(kIntegerVal2);
EXPECT(Dart_IsInteger(val2));
result = Dart_IntegerFitsIntoInt64(val2, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle val3 = Dart_NewIntegerFromHexCString(kIntegerVal3);
EXPECT(Dart_IsInteger(val3));
result = Dart_IntegerFitsIntoInt64(val3, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
int64_t out = 0;
result = Dart_IntegerToInt64(val1, &out);
EXPECT_VALID(result);
EXPECT_EQ(kIntegerVal1, out);
result = Dart_IntegerToInt64(val2, &out);
EXPECT_VALID(result);
EXPECT_EQ(kIntegerVal2, out);
const char* chars = NULL;
result = Dart_IntegerToHexCString(val3, &chars);
EXPECT_VALID(result);
EXPECT(!strcmp(kIntegerVal3, chars));
}
TEST_CASE(IntegerFitsIntoInt64) {
Dart_Handle max = Dart_NewInteger(kMaxInt64);
EXPECT(Dart_IsInteger(max));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoInt64(max, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle above_max = Dart_NewIntegerFromHexCString("0x8000000000000000");
EXPECT(Dart_IsInteger(above_max));
fits = true;
result = Dart_IntegerFitsIntoInt64(above_max, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
Dart_Handle min = Dart_NewInteger(kMaxInt64);
EXPECT(Dart_IsInteger(min));
fits = false;
result = Dart_IntegerFitsIntoInt64(min, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle below_min = Dart_NewIntegerFromHexCString("-0x8000000000000001");
EXPECT(Dart_IsInteger(below_min));
fits = true;
result = Dart_IntegerFitsIntoInt64(below_min, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
}
TEST_CASE(IntegerFitsIntoUint64) {
Dart_Handle max = Dart_NewIntegerFromHexCString("0xFFFFFFFFFFFFFFFF");
EXPECT(Dart_IsInteger(max));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoUint64(max, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle above_max = Dart_NewIntegerFromHexCString("0x10000000000000000");
EXPECT(Dart_IsInteger(above_max));
fits = true;
result = Dart_IntegerFitsIntoUint64(above_max, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
Dart_Handle min = Dart_NewInteger(0);
EXPECT(Dart_IsInteger(min));
fits = false;
result = Dart_IntegerFitsIntoUint64(min, &fits);
EXPECT_VALID(result);
EXPECT(fits);
Dart_Handle below_min = Dart_NewIntegerFromHexCString("-1");
EXPECT(Dart_IsInteger(below_min));
fits = true;
result = Dart_IntegerFitsIntoUint64(below_min, &fits);
EXPECT_VALID(result);
EXPECT(!fits);
}
TEST_CASE(ArrayValues) {
const int kArrayLength = 10;
Dart_Handle str = Dart_NewString("test");
EXPECT(!Dart_IsList(str));
Dart_Handle val = Dart_NewList(kArrayLength);
EXPECT(Dart_IsList(val));
intptr_t len = 0;
Dart_Handle result = Dart_ListLength(val, &len);
EXPECT_VALID(result);
EXPECT_EQ(kArrayLength, len);
// Check invalid array access.
result = Dart_ListSetAt(val, (kArrayLength + 10), Dart_NewInteger(10));
EXPECT(Dart_IsError(result));
result = Dart_ListSetAt(val, -10, Dart_NewInteger(10));
EXPECT(Dart_IsError(result));
result = Dart_ListGetAt(val, (kArrayLength + 10));
EXPECT(Dart_IsError(result));
result = Dart_ListGetAt(val, -10);
EXPECT(Dart_IsError(result));
for (int i = 0; i < kArrayLength; i++) {
result = Dart_ListSetAt(val, i, Dart_NewInteger(i));
EXPECT_VALID(result);
}
for (int i = 0; i < kArrayLength; i++) {
result = Dart_ListGetAt(val, i);
EXPECT_VALID(result);
int64_t value;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(i, value);
}
}
TEST_CASE(IsString) {
uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
Dart_Handle str8 = Dart_NewString8(data8, ARRAY_SIZE(data8));
EXPECT_VALID(str8);
EXPECT(Dart_IsString(str8));
EXPECT(Dart_IsString8(str8));
EXPECT(Dart_IsString16(str8));
EXPECT(!Dart_IsExternalString(str8));
Dart_Handle ext8 = Dart_NewExternalString8(data8, ARRAY_SIZE(data8),
NULL, NULL);
EXPECT_VALID(ext8);
EXPECT(Dart_IsString(ext8));
EXPECT(Dart_IsString8(ext8));
EXPECT(Dart_IsString16(ext8));
EXPECT(Dart_IsExternalString(ext8));
uint16_t data16[] = { 't', 'w', 'o', 0xFFFF };
Dart_Handle str16 = Dart_NewString16(data16, ARRAY_SIZE(data16));
EXPECT_VALID(str16);
EXPECT(Dart_IsString(str16));
EXPECT(!Dart_IsString8(str16));
EXPECT(Dart_IsString16(str16));
EXPECT(!Dart_IsExternalString(str16));
Dart_Handle ext16 = Dart_NewExternalString16(data16, ARRAY_SIZE(data16),
NULL, NULL);
EXPECT_VALID(ext16);
EXPECT(Dart_IsString(ext16));
EXPECT(!Dart_IsString8(ext16));
EXPECT(Dart_IsString16(ext16));
EXPECT(Dart_IsExternalString(ext16));
uint32_t data32[] = { 'f', 'o', 'u', 'r', 0x10FFFF };
Dart_Handle str32 = Dart_NewString32(data32, ARRAY_SIZE(data32));
EXPECT_VALID(str32);
EXPECT(Dart_IsString(str32));
EXPECT(!Dart_IsString8(str32));
EXPECT(!Dart_IsString16(str32));
EXPECT(!Dart_IsExternalString(str32));
Dart_Handle ext32 = Dart_NewExternalString32(data32, ARRAY_SIZE(data32),
NULL, NULL);
EXPECT_VALID(ext32);
EXPECT(Dart_IsString(ext32));
EXPECT(!Dart_IsString8(ext32));
EXPECT(!Dart_IsString16(ext32));
EXPECT(Dart_IsExternalString(ext32));
}
TEST_CASE(ExternalStringGetPeer) {
Dart_Handle result;
uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
int peer_data = 123;
void* peer = NULL;
// Success.
Dart_Handle ext8 = Dart_NewExternalString8(data8, ARRAY_SIZE(data8),
&peer_data, NULL);
EXPECT_VALID(ext8);
result = Dart_ExternalStringGetPeer(ext8, &peer);
EXPECT_VALID(result);
EXPECT_EQ(&peer_data, peer);
// NULL peer.
result = Dart_ExternalStringGetPeer(ext8, NULL);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'peer' to be "
"non-null.", Dart_GetError(result));
// String is not external.
peer = NULL;
Dart_Handle str8 = Dart_NewString8(data8, ARRAY_SIZE(data8));
EXPECT_VALID(str8);
result = Dart_ExternalStringGetPeer(str8, &peer);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
"an external String.", Dart_GetError(result));
EXPECT(peer == NULL);
// Not a String.
peer = NULL;
result = Dart_ExternalStringGetPeer(Dart_True(), &peer);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
"of type String.", Dart_GetError(result));
EXPECT(peer == NULL);
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
static void ExternalStringCallbackFinalizer(void* peer) {
*static_cast<int*>(peer) *= 2;
}
TEST_CASE(ExternalStringCallback) {
int peer8 = 40;
int peer16 = 41;
int peer32 = 42;
{
Dart_EnterScope();
uint8_t data8[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj8 = Dart_NewExternalString8(
data8,
ARRAY_SIZE(data8),
&peer8,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj8);
void* api_peer8 = NULL;
EXPECT_VALID(Dart_ExternalStringGetPeer(obj8, &api_peer8));
EXPECT_EQ(api_peer8, &peer8);
uint16_t data16[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj16 = Dart_NewExternalString16(
data16,
ARRAY_SIZE(data16),
&peer16,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj16);
void* api_peer16 = NULL;
EXPECT_VALID(Dart_ExternalStringGetPeer(obj16, &api_peer16));
EXPECT_EQ(api_peer16, &peer16);
uint32_t data32[] = { 'h', 'e', 'l', 'l', 'o' };
Dart_Handle obj32 = Dart_NewExternalString32(
data32,
ARRAY_SIZE(data32),
&peer32,
ExternalStringCallbackFinalizer);
EXPECT_VALID(obj32);
void* api_peer32 = NULL;
EXPECT_VALID(Dart_ExternalStringGetPeer(obj32, &api_peer32));
EXPECT_EQ(api_peer32, &peer32);
Dart_ExitScope();
}
EXPECT_EQ(peer8, 40);
EXPECT_EQ(peer16, 41);
EXPECT_EQ(peer32, 42);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(peer8, 40);
EXPECT_EQ(peer16, 41);
EXPECT_EQ(peer32, 42);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(peer8, 80);
EXPECT_EQ(peer16, 82);
EXPECT_EQ(peer32, 84);
}
TEST_CASE(ListAccess) {
const char* kScriptChars =
"class ListAccessTest {"
" ListAccessTest() {}"
" static List testMain() {"
" List a = new List();"
" a.add(10);"
" a.add(20);"
" a.add(30);"
" return a;"
" }"
"}";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type InstanceOf..
result = Dart_InvokeStatic(lib,
Dart_NewString("ListAccessTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(result);
// First ensure that the returned object is an array.
Dart_Handle ListAccessTestObj = result;
EXPECT(Dart_IsList(ListAccessTestObj));
// Get length of array object.
intptr_t len = 0;
result = Dart_ListLength(ListAccessTestObj, &len);
EXPECT_VALID(result);
EXPECT_EQ(3, len);
// Access elements in the array.
int64_t value;
result = Dart_ListGetAt(ListAccessTestObj, 0);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(10, value);
result = Dart_ListGetAt(ListAccessTestObj, 1);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(20, value);
result = Dart_ListGetAt(ListAccessTestObj, 2);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(30, value);
// Set some elements in the array.
result = Dart_ListSetAt(ListAccessTestObj, 0, Dart_NewInteger(0));
EXPECT_VALID(result);
result = Dart_ListSetAt(ListAccessTestObj, 1, Dart_NewInteger(1));
EXPECT_VALID(result);
result = Dart_ListSetAt(ListAccessTestObj, 2, Dart_NewInteger(2));
EXPECT_VALID(result);
// Get length of array object.
result = Dart_ListLength(ListAccessTestObj, &len);
EXPECT_VALID(result);
EXPECT_EQ(3, len);
// Now try and access these elements in the array.
result = Dart_ListGetAt(ListAccessTestObj, 0);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(0, value);
result = Dart_ListGetAt(ListAccessTestObj, 1);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(1, value);
result = Dart_ListGetAt(ListAccessTestObj, 2);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(2, value);
uint8_t native_array[3];
result = Dart_ListGetAsBytes(ListAccessTestObj, 0, native_array, 3);
EXPECT_VALID(result);
EXPECT_EQ(0, native_array[0]);
EXPECT_EQ(1, native_array[1]);
EXPECT_EQ(2, native_array[2]);
native_array[0] = 10;
native_array[1] = 20;
native_array[2] = 30;
result = Dart_ListSetAsBytes(ListAccessTestObj, 0, native_array, 3);
EXPECT_VALID(result);
result = Dart_ListGetAsBytes(ListAccessTestObj, 0, native_array, 3);
EXPECT_VALID(result);
EXPECT_EQ(10, native_array[0]);
EXPECT_EQ(20, native_array[1]);
EXPECT_EQ(30, native_array[2]);
result = Dart_ListGetAt(ListAccessTestObj, 2);
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(30, value);
// Check if we get an exception when accessing beyond limit.
result = Dart_ListGetAt(ListAccessTestObj, 4);
EXPECT(Dart_IsError(result));
}
TEST_CASE(ByteArrayAccess) {
Dart_Handle byte_array1 = Dart_NewByteArray(10);
EXPECT_VALID(byte_array1);
EXPECT(Dart_IsByteArray(byte_array1));
EXPECT(Dart_IsList(byte_array1));
intptr_t length = 0;
Dart_Handle result = Dart_ListLength(byte_array1, &length);
EXPECT_VALID(result);
EXPECT_EQ(10, length);
result = Dart_ListSetAt(byte_array1, -1, Dart_NewInteger(1));
EXPECT(Dart_IsError(result));
result = Dart_ByteArraySetUint8At(byte_array1, -1, 1);
EXPECT(Dart_IsError(result));
result = Dart_ListSetAt(byte_array1, 10, Dart_NewInteger(1));
EXPECT(Dart_IsError(result));
result = Dart_ByteArraySetUint8At(byte_array1, 10, 1);
EXPECT(Dart_IsError(result));
// Set through the List API.
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ListSetAt(byte_array1, i, Dart_NewInteger(i + 1)));
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(i + 1, int64_t_value);
// Get through the ByteArray API.
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(i + 1, uint8_t_value);
}
// Set through the ByteArray API.
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ByteArraySetUint8At(byte_array1, i, i + 2));
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(i + 2, int64_t_value);
// Get through the ByteArray API.
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(i + 2, uint8_t_value);
}
Dart_Handle byte_array2 = Dart_NewByteArray(10);
bool is_equal = false;
Dart_ObjectEquals(byte_array1, byte_array2, &is_equal);
EXPECT(!is_equal);
// Set through the List API.
for (intptr_t i = 0; i < 10; ++i) {
result = Dart_ListSetAt(byte_array2, i, Dart_NewInteger(i + 2));
EXPECT_VALID(result);
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle e1 = Dart_ListGetAt(byte_array1, i);
Dart_Handle e2 = Dart_ListGetAt(byte_array2, i);
is_equal = false;
Dart_ObjectEquals(e1, e2, &is_equal);
EXPECT(is_equal);
// Get through the ByteArray API.
uint8_t v1 = 0xFF;
uint8_t v2 = 0XFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &v1));
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array2, i, &v2));
EXPECT_NE(v1, 0xFF);
EXPECT_NE(v2, 0xFF);
EXPECT_EQ(v1, v2);
}
byte_array2 = Dart_NewByteArray(10);
is_equal = false;
Dart_ObjectEquals(byte_array1, byte_array2, &is_equal);
EXPECT(!is_equal);
// Set through the ByteArray API.
for (intptr_t i = 0; i < 10; ++i) {
result = Dart_ByteArraySetUint8At(byte_array2, i, i + 2);
EXPECT_VALID(result);
}
for (intptr_t i = 0; i < 10; ++i) {
// Get through the List API.
Dart_Handle e1 = Dart_ListGetAt(byte_array1, i);
Dart_Handle e2 = Dart_ListGetAt(byte_array2, i);
is_equal = false;
Dart_ObjectEquals(e1, e2, &is_equal);
EXPECT(is_equal);
// Get through the ByteArray API.
uint8_t v1 = 0xFF;
uint8_t v2 = 0XFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &v1));
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array2, i, &v2));
EXPECT_NE(v1, 0xFF);
EXPECT_NE(v2, 0xFF);
EXPECT_EQ(v1, v2);
}
uint8_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
result = Dart_ListSetAsBytes(byte_array1, 0, data, 10);
EXPECT_VALID(result);
for (intptr_t i = 0; i < 10; ++i) {
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(i, int64_t_value);
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(i, uint8_t_value);
}
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ListSetAt(byte_array1, i, Dart_NewInteger(10 - i)));
}
Dart_ListGetAsBytes(byte_array1, 0, data, 10);
for (intptr_t i = 0; i < 10; ++i) {
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(10 - i, int64_t_value);
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(10 - i, uint8_t_value);
}
for (intptr_t i = 0; i < 10; ++i) {
EXPECT_VALID(Dart_ByteArraySetUint8At(byte_array1, i, 10 + i));
}
Dart_ListGetAsBytes(byte_array1, 0, data, 10);
for (intptr_t i = 0; i < 10; ++i) {
Dart_Handle integer_obj = Dart_ListGetAt(byte_array1, i);
EXPECT_VALID(integer_obj);
int64_t int64_t_value = -1;
EXPECT_VALID(Dart_IntegerToInt64(integer_obj, &int64_t_value));
EXPECT_EQ(10 + i, int64_t_value);
uint8_t uint8_t_value = 0xFF;
EXPECT_VALID(Dart_ByteArrayGetUint8At(byte_array1, i, &uint8_t_value));
EXPECT_EQ(10 + i, uint8_t_value);
}
}
TEST_CASE(ByteArrayAlignedMultiByteAccess) {
intptr_t length = 16;
Dart_Handle byte_array = Dart_NewByteArray(length);
intptr_t api_length = 0;
EXPECT_VALID(Dart_ListLength(byte_array, &api_length));
EXPECT_EQ(length, api_length);
// 4-byte aligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 0, FLT_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 4, FLT_MAX));
float float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 0, &float_value));
EXPECT_EQ(FLT_MIN, float_value);
float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 4, &float_value));
EXPECT_EQ(FLT_MAX, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 0, 0.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 0, &float_value));
EXPECT_EQ(0.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 4, 1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 4, &float_value));
EXPECT_EQ(1.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 0, -1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 0, &float_value));
EXPECT_EQ(-1.0f, float_value);
// 8-byte aligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 0, DBL_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 8, DBL_MAX));
double double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 0, &double_value));
EXPECT_EQ(DBL_MIN, double_value);
double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 8, &double_value));
EXPECT_EQ(DBL_MAX, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 0, 0.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 0, &double_value));
EXPECT_EQ(0.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 8, 1.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 8, &double_value));
EXPECT_EQ(1.0, double_value);
}
TEST_CASE(ByteArrayMisalignedMultiByteAccess) {
intptr_t length = 17;
Dart_Handle byte_array = Dart_NewByteArray(length);
intptr_t api_length = 0;
EXPECT_VALID(Dart_ListLength(byte_array, &api_length));
EXPECT_EQ(length, api_length);
// 4-byte misaligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 1, FLT_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 5, FLT_MAX));
float float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 1, &float_value));
EXPECT_EQ(FLT_MIN, float_value);
float_value = 0.0f;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 5, &float_value));
EXPECT_EQ(FLT_MAX, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 1, 0.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 1, &float_value));
EXPECT_EQ(0.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 5, -0.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 5, &float_value));
EXPECT_EQ(-0.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 5, 1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 5, &float_value));
EXPECT_EQ(1.0f, float_value);
EXPECT_VALID(Dart_ByteArraySetFloat32At(byte_array, 1, -1.0f));
float_value = FLT_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat32At(byte_array, 1, &float_value));
EXPECT_EQ(-1.0f, float_value);
// 8-byte misaligned sets.
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 1, DBL_MIN));
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 9, DBL_MAX));
double double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 1, &double_value));
EXPECT_EQ(DBL_MIN, double_value);
double_value = 0.0;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 9, &double_value));
EXPECT_EQ(DBL_MAX, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 1, 0.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 1, &double_value));
EXPECT_EQ(0.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 9, -0.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 9, &double_value));
EXPECT_EQ(-0.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 9, 1.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 9, &double_value));
EXPECT_EQ(1.0, double_value);
EXPECT_VALID(Dart_ByteArraySetFloat64At(byte_array, 1, -1.0));
double_value = DBL_MAX;
EXPECT_VALID(Dart_ByteArrayGetFloat64At(byte_array, 1, &double_value));
EXPECT_EQ(-1.0, double_value);
}
TEST_CASE(ExternalByteArrayAccess) {
uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
intptr_t data_length = ARRAY_SIZE(data);
Dart_Handle obj = Dart_NewExternalByteArray(data, data_length, NULL, NULL);
EXPECT_VALID(obj);
EXPECT(Dart_IsByteArray(obj));
EXPECT(Dart_IsList(obj));
void* peer = &data; // just a non-NULL value
EXPECT_VALID(Dart_ExternalByteArrayGetPeer(obj, &peer));
EXPECT(peer == NULL);
intptr_t list_length = 0;
EXPECT_VALID(Dart_ListLength(obj, &list_length));
EXPECT_EQ(data_length, list_length);
// Load and check values from underlying array and API.
for (intptr_t i = 0; i < list_length; ++i) {
EXPECT_EQ(11 * i, data[i]);
Dart_Handle elt = Dart_ListGetAt(obj, i);
EXPECT_VALID(elt);
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(elt, &value));
EXPECT_EQ(data[i], value);
}
// Write values through the underlying array.
for (intptr_t i = 0; i < data_length; ++i) {
data[i] *= 2;
}
// Read them back through the API.
for (intptr_t i = 0; i < list_length; ++i) {
Dart_Handle elt = Dart_ListGetAt(obj, i);
EXPECT_VALID(elt);
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(elt, &value));
EXPECT_EQ(22 * i, value);
}
// Write values through the API.
for (intptr_t i = 0; i < list_length; ++i) {
Dart_Handle value = Dart_NewInteger(33 * i);
EXPECT_VALID(value);
EXPECT_VALID(Dart_ListSetAt(obj, i, value));
}
// Read them back through the underlying array.
for (intptr_t i = 0; i < data_length; ++i) {
EXPECT_EQ(33 * i, data[i]);
}
}
static void ExternalByteArrayCallbackFinalizer(void* peer) {
*static_cast<int*>(peer) = 42;
}
TEST_CASE(ExternalByteArrayCallback) {
int peer = 0;
{
Dart_EnterScope();
uint8_t data[] = { 1, 2, 3, 4 };
Dart_Handle obj = Dart_NewExternalByteArray(
data,
ARRAY_SIZE(data),
&peer,
ExternalByteArrayCallbackFinalizer);
EXPECT_VALID(obj);
void* api_peer = NULL;
EXPECT_VALID(Dart_ExternalByteArrayGetPeer(obj, &api_peer));
EXPECT_EQ(api_peer, &peer);
Dart_ExitScope();
}
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT(peer == 42);
}
#endif
// Unit test for entering a scope, creating a local handle and exiting
// the scope.
UNIT_TEST_CASE(EnterExitScope) {
TestIsolateScope __test_isolate__;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
Dart_EnterScope();
{
EXPECT(state->top_scope() != NULL);
DARTSCOPE_NOCHECKS(isolate);
const String& str1 = String::Handle(String::New("Test String"));
Dart_Handle ref = Api::NewHandle(isolate, str1.raw());
String& str2 = String::Handle();
str2 ^= Api::UnwrapHandle(ref);
EXPECT(str1.Equals(str2));
}
Dart_ExitScope();
EXPECT(scope == state->top_scope());
}
// Unit test for creating and deleting persistent handles.
UNIT_TEST_CASE(PersistentHandles) {
const char* kTestString1 = "Test String1";
const char* kTestString2 = "Test String2";
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
Dart_Handle handles[2000];
Dart_EnterScope();
{
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
for (int i = 0; i < 1000; i++) {
handles[i] = Dart_NewPersistentHandle(ref1);
}
Dart_EnterScope();
Dart_Handle ref2 = Api::NewHandle(isolate, String::New(kTestString2));
for (int i = 1000; i < 2000; i++) {
handles[i] = Dart_NewPersistentHandle(ref2);
}
for (int i = 500; i < 1500; i++) {
Dart_DeletePersistentHandle(handles[i]);
}
for (int i = 500; i < 1000; i++) {
handles[i] = Dart_NewPersistentHandle(ref2);
}
for (int i = 1000; i < 1500; i++) {
handles[i] = Dart_NewPersistentHandle(ref1);
}
VERIFY_ON_TRANSITION;
Dart_ExitScope();
}
Dart_ExitScope();
{
DARTSCOPE_NOCHECKS(isolate);
for (int i = 0; i < 500; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString1));
}
for (int i = 500; i < 1000; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString2));
}
for (int i = 1000; i < 1500; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString1));
}
for (int i = 1500; i < 2000; i++) {
String& str = String::Handle();
str ^= Api::UnwrapHandle(handles[i]);
EXPECT(str.Equals(kTestString2));
}
}
EXPECT(scope == state->top_scope());
EXPECT_EQ(2000, state->CountPersistentHandles());
Dart_ShutdownIsolate();
}
// Test that we are able to create a persistent handle from a
// persistent handle.
UNIT_TEST_CASE(NewPersistentHandle_FromPersistentHandle) {
TestIsolateScope __test_isolate__;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
// Start with a known persistent handle.
Dart_Handle obj1 = Dart_True();
EXPECT(state->IsValidPersistentHandle(obj1));
// And use it to allocate a second persistent handle.
Dart_Handle obj2 = Dart_NewPersistentHandle(obj1);
EXPECT(state->IsValidPersistentHandle(obj2));
// Make sure that the value transferred.
EXPECT(Dart_IsBoolean(obj2));
bool value = false;
Dart_Handle result = Dart_BooleanValue(obj2, &value);
EXPECT_VALID(result);
EXPECT(value);
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
TEST_CASE(WeakPersistentHandle) {
Dart_Handle weak_new_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_new_ref));
Dart_Handle weak_old_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_old_ref));
bool is_same;
{
Dart_EnterScope();
// create an object in new space
Dart_Handle new_ref = Dart_NewString("new string");
EXPECT_VALID(new_ref);
// create an object in old space
Dart_Handle old_ref;
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
old_ref = Api::NewHandle(isolate, String::New("old string", Heap::kOld));
EXPECT_VALID(old_ref);
}
// create a weak ref to the new space object
weak_new_ref = Dart_NewWeakPersistentHandle(new_ref, NULL, NULL);
EXPECT_VALID(weak_new_ref);
EXPECT(!Dart_IsNull(weak_new_ref));
// create a weak ref to the old space object
weak_old_ref = Dart_NewWeakPersistentHandle(old_ref, NULL, NULL);
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
// garbage collect new space
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
// nothing should be invalidated or cleared
EXPECT_VALID(new_ref);
EXPECT(!Dart_IsNull(new_ref));
EXPECT_VALID(old_ref);
EXPECT(!Dart_IsNull(old_ref));
EXPECT_VALID(weak_new_ref);
EXPECT(!Dart_IsNull(weak_new_ref));
is_same = false;
EXPECT_VALID(Dart_IsSame(new_ref, weak_new_ref, &is_same));
EXPECT(is_same);
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
is_same = false;
EXPECT_VALID(Dart_IsSame(old_ref, weak_old_ref, &is_same));
EXPECT(is_same);
// garbage collect old space
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// nothing should be invalidated or cleared
EXPECT_VALID(new_ref);
EXPECT(!Dart_IsNull(new_ref));
EXPECT_VALID(old_ref);
EXPECT(!Dart_IsNull(old_ref));
EXPECT_VALID(weak_new_ref);
EXPECT(!Dart_IsNull(weak_new_ref));
is_same = false;
EXPECT_VALID(Dart_IsSame(new_ref, weak_new_ref, &is_same));
EXPECT(is_same);
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
is_same = false;
EXPECT_VALID(Dart_IsSame(old_ref, weak_old_ref, &is_same));
EXPECT(is_same);
// delete local (strong) references
Dart_ExitScope();
}
// garbage collect new space again
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
// weak ref to new space object should now be cleared
EXPECT_VALID(weak_new_ref);
EXPECT(Dart_IsNull(weak_new_ref));
EXPECT_VALID(weak_old_ref);
EXPECT(!Dart_IsNull(weak_old_ref));
// garbage collect old space again
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// weak ref to old space object should now be cleared
EXPECT_VALID(weak_new_ref);
EXPECT(Dart_IsNull(weak_new_ref));
EXPECT_VALID(weak_old_ref);
EXPECT(Dart_IsNull(weak_old_ref));
Dart_DeletePersistentHandle(weak_new_ref);
Dart_DeletePersistentHandle(weak_old_ref);
// garbage collect one last time to revisit deleted handles
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
static void WeakPersistentHandlePeerFinalizer(Dart_Handle handle, void* peer) {
*static_cast<int*>(peer) = 42;
}
TEST_CASE(WeakPersistentHandleCallback) {
Dart_Handle weak_ref = Dart_Null();
EXPECT(Dart_IsNull(weak_ref));
int* peer = new int();
{
Dart_EnterScope();
Dart_Handle obj = Dart_NewString("new string");
EXPECT_VALID(obj);
weak_ref = Dart_NewWeakPersistentHandle(obj, peer,
WeakPersistentHandlePeerFinalizer);
Dart_ExitScope();
}
EXPECT_VALID(weak_ref);
EXPECT(*peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(*peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT(*peer == 42);
delete peer;
Dart_DeletePersistentHandle(weak_ref);
}
TEST_CASE(ObjectGroups) {
Dart_Handle strong = Dart_Null();
EXPECT(Dart_IsNull(strong));
Dart_Handle weak1 = Dart_Null();
EXPECT(Dart_IsNull(weak1));
Dart_Handle weak2 = Dart_Null();
EXPECT(Dart_IsNull(weak2));
Dart_Handle weak3 = Dart_Null();
EXPECT(Dart_IsNull(weak3));
Dart_Handle weak4 = Dart_Null();
EXPECT(Dart_IsNull(weak4));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
strong = Dart_NewPersistentHandle(
Api::NewHandle(isolate, String::New("strongly reachable", Heap::kOld)));
EXPECT_VALID(strong);
EXPECT(!Dart_IsNull(strong));
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak1);
EXPECT(!Dart_IsNull(weak1));
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak2);
EXPECT(!Dart_IsNull(weak2));
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak3);
EXPECT(!Dart_IsNull(weak3));
weak4 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 4", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(weak4);
EXPECT(!Dart_IsNull(weak4));
}
Dart_ExitScope();
EXPECT_VALID(strong);
EXPECT_VALID(weak1);
EXPECT_VALID(weak2);
EXPECT_VALID(weak3);
EXPECT_VALID(weak4);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
// New space collection should not affect old space objects
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
EXPECT(!Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
Dart_Handle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Dart_Handle array3[] = { weak3, weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
Dart_Handle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
EXPECT(!Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
Dart_Handle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Dart_Handle array3[] = { weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
// Strong reference to weak3 to retain weak3 and weak4.
Dart_Handle weak3_strong_ref = Dart_NewPersistentHandle(weak3);
EXPECT_VALID(weak3_strong_ref);
Dart_Handle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// Delete strong reference to weak3.
Dart_DeletePersistentHandle(weak3_strong_ref);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
EXPECT(!Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
Dart_Handle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Dart_Handle array3[] = { weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
Dart_Handle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// Only weak1 and weak2 should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
EXPECT(Dart_IsNull(weak4));
{
Dart_Handle array1[] = { weak1, strong };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
// weak3 is cleared so weak2 is unreferenced and should be cleared
Dart_Handle array2[] = { weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// Only weak1 should be preserved, weak3 should not preserve weak2.
EXPECT(!Dart_IsNull(weak1));
EXPECT(Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3)); // was cleared, should remain cleared
EXPECT(Dart_IsNull(weak4)); // was cleared, should remain cleared
{
// weak{2,3,4} are cleared and should have no effect on weak1
Dart_Handle array1[] = { strong, weak2, weak3, weak4 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
// weak1 is weakly reachable and should be cleared
Dart_Handle array2[] = { weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references should now be cleared.
EXPECT(Dart_IsNull(weak1));
EXPECT(Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
EXPECT(Dart_IsNull(weak4));
}
TEST_CASE(PrologueWeakPersistentHandles) {
Dart_Handle old_pwph = Dart_Null();
EXPECT(Dart_IsNull(old_pwph));
Dart_Handle new_pwph = Dart_Null();
EXPECT(Dart_IsNull(new_pwph));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
new_pwph = Dart_NewPrologueWeakPersistentHandle(
Api::NewHandle(isolate,
String::New("new space prologue weak", Heap::kNew)),
NULL, NULL);
EXPECT_VALID(new_pwph);
EXPECT(!Dart_IsNull(new_pwph));
old_pwph = Dart_NewPrologueWeakPersistentHandle(
Api::NewHandle(isolate,
String::New("old space prologue weak", Heap::kOld)),
NULL, NULL);
EXPECT_VALID(old_pwph);
EXPECT(!Dart_IsNull(old_pwph));
}
Dart_ExitScope();
EXPECT_VALID(new_pwph);
EXPECT(!Dart_IsNull(new_pwph));
EXPECT(Dart_IsPrologueWeakPersistentHandle(new_pwph));
EXPECT_VALID(old_pwph);
EXPECT(!Dart_IsNull(old_pwph));
EXPECT(Dart_IsPrologueWeakPersistentHandle(old_pwph));
// Garbage collect new space without invoking API callbacks.
Isolate::Current()->heap()->CollectGarbage(Heap::kNew,
Heap::kIgnoreApiCallbacks);
// Both prologue weak handles should be preserved.
EXPECT(!Dart_IsNull(new_pwph));
EXPECT(!Dart_IsNull(old_pwph));
// Garbage collect old space without invoking API callbacks.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
// Both prologue weak handles should be preserved.
EXPECT(!Dart_IsNull(new_pwph));
EXPECT(!Dart_IsNull(old_pwph));
// Garbage collect new space invoking API callbacks.
Isolate::Current()->heap()->CollectGarbage(Heap::kNew,
Heap::kInvokeApiCallbacks);
// The prologue weak handle with a new space referent should now be
// cleared. The old space referent should be preserved.
EXPECT(Dart_IsNull(new_pwph));
EXPECT(!Dart_IsNull(old_pwph));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kInvokeApiCallbacks);
// The prologue weak handle with an old space referent should now be
// cleared. The new space referent should remain cleared.
EXPECT(Dart_IsNull(new_pwph));
EXPECT(Dart_IsNull(old_pwph));
}
TEST_CASE(ImplicitReferencesOldSpace) {
Dart_Handle strong = Dart_Null();
EXPECT(Dart_IsNull(strong));
Dart_Handle weak1 = Dart_Null();
EXPECT(Dart_IsNull(weak1));
Dart_Handle weak2 = Dart_Null();
EXPECT(Dart_IsNull(weak2));
Dart_Handle weak3 = Dart_Null();
EXPECT(Dart_IsNull(weak3));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
strong = Dart_NewPersistentHandle(
Api::NewHandle(isolate, String::New("strongly reachable", Heap::kOld)));
EXPECT(!Dart_IsNull(strong));
EXPECT_VALID(strong);
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak1));
EXPECT_VALID(weak1);
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak2));
EXPECT_VALID(weak2);
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak3));
EXPECT_VALID(weak3);
}
Dart_ExitScope();
EXPECT_VALID(strong);
EXPECT_VALID(weak1);
EXPECT_VALID(weak2);
EXPECT_VALID(weak3);
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
// New space collection should not affect old space objects
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
// A strongly referenced key should preserve all the values.
{
Dart_Handle keys[] = { strong };
Dart_Handle values[] = { weak1, weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
// Key membership does not imply a strong reference.
{
Dart_Handle keys[] = { strong, weak3 };
Dart_Handle values[] = { weak1, weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
// All weak references except weak3 should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
}
TEST_CASE(ImplicitReferencesNewSpace) {
Dart_Handle strong = Dart_Null();
EXPECT(Dart_IsNull(strong));
Dart_Handle weak1 = Dart_Null();
EXPECT(Dart_IsNull(weak1));
Dart_Handle weak2 = Dart_Null();
EXPECT(Dart_IsNull(weak2));
Dart_Handle weak3 = Dart_Null();
EXPECT(Dart_IsNull(weak3));
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
strong = Dart_NewPersistentHandle(
Api::NewHandle(isolate, String::New("strongly reachable", Heap::kNew)));
EXPECT(!Dart_IsNull(strong));
EXPECT_VALID(strong);
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kNew)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak1));
EXPECT_VALID(weak1);
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kNew)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak2));
EXPECT_VALID(weak2);
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kNew)),
NULL, NULL);
EXPECT(!Dart_IsNull(weak3));
EXPECT_VALID(weak3);
}
Dart_ExitScope();
EXPECT_VALID(strong);
EXPECT_VALID(weak1);
EXPECT_VALID(weak2);
EXPECT_VALID(weak3);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
// Old space collection should not affect old space objects.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
// A strongly referenced key should preserve all the values.
{
Dart_Handle keys[] = { strong };
Dart_Handle values[] = { weak1, weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kNew,
Heap::kInvokeApiCallbacks);
}
// All weak references should be preserved.
EXPECT(!Dart_IsNull(weak1));
EXPECT(!Dart_IsNull(weak2));
EXPECT(!Dart_IsNull(weak3));
Isolate::Current()->heap()->CollectGarbage(Heap::kNew,
Heap::kIgnoreApiCallbacks);
// No weak references should be preserved.
EXPECT(Dart_IsNull(weak1));
EXPECT(Dart_IsNull(weak2));
EXPECT(Dart_IsNull(weak3));
}
static int global_prologue_callback_status;
static void PrologueCallbackTimes2() {
global_prologue_callback_status *= 2;
}
static void PrologueCallbackTimes3() {
global_prologue_callback_status *= 3;
}
static int global_epilogue_callback_status;
static void EpilogueCallbackTimes4() {
global_epilogue_callback_status *= 4;
}
static void EpilogueCallbackTimes5() {
global_epilogue_callback_status *= 5;
}
TEST_CASE(AddGarbageCollectionCallbacks) {
// Add a prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
// Add the same prologue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2)));
// Add another prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3));
// Add the same prologue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3)));
// Add an epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Add the same epilogue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4)));
// Add annother epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5));
// Add the same epilogue callback again. This is an error.
EXPECT(Dart_IsError(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5)));
}
TEST_CASE(RemoveGarbageCollectionCallbacks) {
// Remove a prologue callback that has not been added. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2)));
// Add a prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
// Remove a prologue callback.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
// Remove a prologue callback again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2)));
// Add two prologue callbacks.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3));
// Remove two prologue callbacks.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes3));
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
// Remove epilogue callbacks again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4)));
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5)));
// Remove a epilogue callback that has not been added. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5)));
// Add a epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Remove a epilogue callback.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Remove a epilogue callback again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4)));
// Add two epilogue callbacks.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5));
// Remove two epilogue callbacks.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5));
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Remove epilogue callbacks again. This is an error.
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4)));
EXPECT(Dart_IsError(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5)));
}
TEST_CASE(SingleGarbageCollectionCallback) {
// Add a prologue callback.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
// Garbage collect new space ignoring callbacks. This should not
// invoke the prologue callback. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect new space invoking callbacks. This should
// invoke the prologue callback. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kNew,
Heap::kInvokeApiCallbacks);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space ignoring callbacks. This should invoke
// the prologue callback. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space. This should invoke the prologue
// callback. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space again. Callbacks are persistent so the
// prolog status value should change again.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(12, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Add an epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect new space. This should not invoke the prologue
// or the epilogue callback. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect new space. This should invoke the prologue and
// the epilogue callback. The prologue and epilogue status values
// should change.
Isolate::Current()->heap()->CollectGarbage(Heap::kNew,
Heap::kInvokeApiCallbacks);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Garbage collect old space. This should invoke the prologue and
// the epilogue callbacks. The prologue and epilogue status values
// should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Garbage collect old space again without invoking callbacks.
// Nothing should change.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Garbage collect old space again. Callbacks are persistent so the
// prologue and epilogue status values should change again.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(12, global_prologue_callback_status);
EXPECT_EQ(112, global_epilogue_callback_status);
// Remove the prologue and epilogue callbacks
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect old space. No callbacks should be invoked. No
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
}
TEST_CASE(MultipleGarbageCollectionCallbacks) {
// Add prologue callbacks.
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes2));
EXPECT_VALID(Dart_AddGcPrologueCallback(&PrologueCallbackTimes3));
// Add an epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect new space. This should not invoke the prologue
// or epilogue callbacks. No status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Garbage collect old space. This should invoke both prologue
// callbacks and the epilogue callback. The prologue and epilogue
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(28, global_epilogue_callback_status);
// Add another GC epilogue callback.
EXPECT_VALID(Dart_AddGcEpilogueCallback(&EpilogueCallbackTimes5));
// Garbage collect old space. This should invoke both prologue
// callbacks and both epilogue callbacks. The prologue and epilogue
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(140, global_epilogue_callback_status);
// Remove an epilogue callback.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes4));
// Garbage collect old space. This should invoke both prologue
// callbacks and the remaining epilogue callback. The prologue and
// epilogue status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(35, global_epilogue_callback_status);
// Remove the remaining epilogue callback.
EXPECT_VALID(Dart_RemoveGcEpilogueCallback(&EpilogueCallbackTimes5));
// Garbage collect old space. This should invoke both prologue
// callbacks. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(18, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Remove a prologue callback.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes3));
// Garbage collect old space. This should invoke the remaining
// prologue callback. The prologue status value should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(6, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
// Remove the remaining prologue callback.
EXPECT_VALID(Dart_RemoveGcPrologueCallback(&PrologueCallbackTimes2));
// Garbage collect old space. No callbacks should be invoked. No
// status values should change.
global_prologue_callback_status = 3;
global_epilogue_callback_status = 7;
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT_EQ(3, global_prologue_callback_status);
EXPECT_EQ(7, global_epilogue_callback_status);
}
#endif
// Unit test for creating multiple scopes and local handles within them.
// Ensure that the local handles get all cleaned out when exiting the
// scope.
UNIT_TEST_CASE(LocalHandles) {
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
Dart_Handle handles[300];
{
DARTSCOPE_NOCHECKS(isolate);
Smi& val = Smi::Handle();
// Start a new scope and allocate some local handles.
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
handles[i] = Api::NewHandle(isolate, Smi::New(i));
}
EXPECT_EQ(100, state->CountLocalHandles());
for (int i = 0; i < 100; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
// Start another scope and allocate some more local handles.
{
Dart_EnterScope();
for (int i = 100; i < 200; i++) {
handles[i] = Api::NewHandle(isolate, Smi::New(i));
}
EXPECT_EQ(200, state->CountLocalHandles());
for (int i = 100; i < 200; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
// Start another scope and allocate some more local handles.
{
Dart_EnterScope();
for (int i = 200; i < 300; i++) {
handles[i] = Api::NewHandle(isolate, Smi::New(i));
}
EXPECT_EQ(300, state->CountLocalHandles());
for (int i = 200; i < 300; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
EXPECT_EQ(300, state->CountLocalHandles());
VERIFY_ON_TRANSITION;
Dart_ExitScope();
}
EXPECT_EQ(200, state->CountLocalHandles());
Dart_ExitScope();
}
EXPECT_EQ(100, state->CountLocalHandles());
Dart_ExitScope();
}
EXPECT_EQ(0, state->CountLocalHandles());
EXPECT(scope == state->top_scope());
Dart_ShutdownIsolate();
}
// Unit test for creating multiple scopes and allocating objects in the
// zone for the scope. Ensure that the memory is freed when the scope
// exits.
UNIT_TEST_CASE(LocalZoneMemory) {
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
{
// Start a new scope and allocate some memory.
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
Api::Allocate(isolate, 16);
}
EXPECT_EQ(1600, state->ZoneSizeInBytes());
// Start another scope and allocate some more memory.
{
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
Api::Allocate(isolate, 16);
}
EXPECT_EQ(3200, state->ZoneSizeInBytes());
{
// Start another scope and allocate some more memory.
{
Dart_EnterScope();
for (int i = 0; i < 200; i++) {
Api::Allocate(isolate, 16);
}
EXPECT_EQ(6400, state->ZoneSizeInBytes());
Dart_ExitScope();
}
}
EXPECT_EQ(3200, state->ZoneSizeInBytes());
Dart_ExitScope();
}
EXPECT_EQ(1600, state->ZoneSizeInBytes());
Dart_ExitScope();
}
EXPECT_EQ(0, state->ZoneSizeInBytes());
EXPECT(scope == state->top_scope());
Dart_ShutdownIsolate();
}
UNIT_TEST_CASE(Isolates) {
// This test currently assumes that the Dart_Isolate type is an opaque
// representation of Isolate*.
Dart_Isolate iso_1 = TestCase::CreateTestIsolate();
EXPECT_EQ(iso_1, Api::CastIsolate(Isolate::Current()));
Dart_Isolate isolate = Dart_CurrentIsolate();
EXPECT_EQ(iso_1, isolate);
Dart_ExitIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
Dart_Isolate iso_2 = TestCase::CreateTestIsolate();
EXPECT_EQ(iso_2, Dart_CurrentIsolate());
Dart_ExitIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
Dart_EnterIsolate(iso_2);
EXPECT_EQ(iso_2, Dart_CurrentIsolate());
Dart_ShutdownIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
Dart_EnterIsolate(iso_1);
EXPECT_EQ(iso_1, Dart_CurrentIsolate());
Dart_ShutdownIsolate();
EXPECT(NULL == Dart_CurrentIsolate());
}
static void MyMessageNotifyCallback(Dart_Isolate dest_isolate) {
}
UNIT_TEST_CASE(SetMessageCallbacks) {
Dart_Isolate dart_isolate = TestCase::CreateTestIsolate();
Dart_SetMessageNotifyCallback(&MyMessageNotifyCallback);
Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate);
EXPECT_EQ(&MyMessageNotifyCallback, isolate->message_notify_callback());
Dart_ShutdownIsolate();
}
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
static void TestFieldOk(Dart_Handle container,
Dart_Handle name,
bool final,
const char* initial_value) {
Dart_Handle result;
// Make sure we have the right initial value.
result = Dart_GetField(container, name);
EXPECT_VALID(result);
const char* value = "";
EXPECT_VALID(Dart_StringToCString(result, &value));
EXPECT_STREQ(initial_value, value);
// Use a unique expected value.
static int counter = 0;
char buffer[256];
OS::SNPrint(buffer, 256, "Expected%d", ++counter);
// Try to change the field value.
result = Dart_SetField(container, name, Dart_NewString(buffer));
if (final) {
EXPECT(Dart_IsError(result));
} else {
EXPECT_VALID(result);
}
// Make sure we have the right final value.
result = Dart_GetField(container, name);
EXPECT_VALID(result);
EXPECT_VALID(Dart_StringToCString(result, &value));
if (final) {
EXPECT_STREQ(initial_value, value);
} else {
EXPECT_STREQ(buffer, value);
}
}
static void TestFieldNotFound(Dart_Handle container,
Dart_Handle name) {
EXPECT(Dart_IsError(Dart_GetField(container, name)));
EXPECT(Dart_IsError(Dart_SetField(container, name, Dart_Null())));
}
TEST_CASE(FieldAccess) {
const char* kScriptChars =
"class BaseFields {\n"
" BaseFields()\n"
" : this.inherited_fld = 'inherited' {\n"
" }\n"
" var inherited_fld;\n"
" static var non_inherited_fld;\n"
"}\n"
"\n"
"class Fields extends BaseFields {\n"
" Fields()\n"
" : this.instance_fld = 'instance',\n"
" this._instance_fld = 'hidden instance',\n"
" this.final_instance_fld = 'final instance',\n"
" this._final_instance_fld = 'hidden final instance' {\n"
" instance_getset_fld = 'instance getset';\n"
" _instance_getset_fld = 'hidden instance getset';\n"
" }\n"
"\n"
" static Init() {\n"
" static_fld = 'static';\n"
" _static_fld = 'hidden static';\n"
" static_getset_fld = 'static getset';\n"
" _static_getset_fld = 'hidden static getset';\n"
" }\n"
"\n"
" var instance_fld;\n"
" var _instance_fld;\n"
" final final_instance_fld;\n"
" final _final_instance_fld;\n"
" static var static_fld;\n"
" static var _static_fld;\n"
" static final final_static_fld = 'final static';\n"
" static final _final_static_fld = 'hidden final static';\n"
"\n"
" get instance_getset_fld() { return _gs_fld1; }\n"
" void set instance_getset_fld(var value) { _gs_fld1 = value; }\n"
" get _instance_getset_fld() { return _gs_fld2; }\n"
" void set _instance_getset_fld(var value) { _gs_fld2 = value; }\n"
" var _gs_fld1;\n"
" var _gs_fld2;\n"
"\n"
" static get static_getset_fld() { return _gs_fld3; }\n"
" static void set static_getset_fld(var value) { _gs_fld3 = value; }\n"
" static get _static_getset_fld() { return _gs_fld4; }\n"
" static void set _static_getset_fld(var value) { _gs_fld4 = value; }\n"
" static var _gs_fld3;\n"
" static var _gs_fld4;\n"
"}\n"
"var top_fld;\n"
"var _top_fld;\n"
"final final_top_fld = 'final top';\n"
"final _final_top_fld = 'hidden final top';\n"
"\n"
"get top_getset_fld() { return _gs_fld5; }\n"
"void set top_getset_fld(var value) { _gs_fld5 = value; }\n"
"get _top_getset_fld() { return _gs_fld6; }\n"
"void set _top_getset_fld(var value) { _gs_fld6 = value; }\n"
"var _gs_fld5;\n"
"var _gs_fld6;\n"
"\n"
"Fields test() {\n"
" Fields.Init();\n"
" top_fld = 'top';\n"
" _top_fld = 'hidden top';\n"
" top_getset_fld = 'top getset';\n"
" _top_getset_fld = 'hidden top getset';\n"
" return new Fields();\n"
"}\n";
// Shared setup.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Fields"));
EXPECT_VALID(cls);
Dart_Handle instance = Dart_InvokeStatic(lib,
Dart_Null(),
Dart_NewString("test"),
0,
NULL);
EXPECT_VALID(instance);
Dart_Handle name;
// Instance field.
name = Dart_NewString("instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "instance");
// Hidden instance field.
name = Dart_NewString("_instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "hidden instance");
// Final instance field.
name = Dart_NewString("final_instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, true, "final instance");
// Hidden final instance field.
name = Dart_NewString("_final_instance_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, true, "hidden final instance");
// Inherited field.
name = Dart_NewString("inherited_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "inherited");
// Instance get/set field.
name = Dart_NewString("instance_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "instance getset");
// Hidden instance get/set field.
name = Dart_NewString("_instance_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(cls, name);
TestFieldOk(instance, name, false, "hidden instance getset");
// Static field.
name = Dart_NewString("static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "static");
// Hidden static field.
name = Dart_NewString("_static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "hidden static");
// Static final field.
name = Dart_NewString("final_static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, true, "final static");
// Hidden static final field.
name = Dart_NewString("_final_static_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, true, "hidden final static");
// Static non-inherited field. Not found at any level.
name = Dart_NewString("non_inherited_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldNotFound(cls, name);
// Static get/set field.
name = Dart_NewString("static_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "static getset");
// Hidden static get/set field.
name = Dart_NewString("_static_getset_fld");
TestFieldNotFound(lib, name);
TestFieldNotFound(instance, name);
TestFieldOk(cls, name, false, "hidden static getset");
// Top-Level field.
name = Dart_NewString("top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "top");
// Hidden top-level field.
name = Dart_NewString("_top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "hidden top");
// Top-Level final field.
name = Dart_NewString("final_top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, true, "final top");
// Hidden top-level final field.
name = Dart_NewString("_final_top_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, true, "hidden final top");
// Top-Level get/set field.
name = Dart_NewString("top_getset_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "top getset");
// Hidden top-level get/set field.
name = Dart_NewString("_top_getset_fld");
TestFieldNotFound(cls, name);
TestFieldNotFound(instance, name);
TestFieldOk(lib, name, false, "hidden top getset");
}
TEST_CASE(SetField_FunnyValue) {
const char* kScriptChars =
"var top;\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle name = Dart_NewString("top");
bool value;
// Test that you can set the field to a good value.
EXPECT_VALID(Dart_SetField(lib, name, Dart_True()));
Dart_Handle result = Dart_GetField(lib, name);
EXPECT_VALID(result);
EXPECT(Dart_IsBoolean(result));
EXPECT_VALID(Dart_BooleanValue(result, &value));
EXPECT(value);
// Test that you can set the field to null
EXPECT_VALID(Dart_SetField(lib, name, Dart_Null()));
result = Dart_GetField(lib, name);
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
// Pass a non-instance handle.
result = Dart_SetField(lib, name, lib);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_SetField expects argument 'value' to be of type Instance.",
Dart_GetError(result));
// Pass an error handle. The error is contagious.
result = Dart_SetField(lib, name, Api::NewError("myerror"));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
TEST_CASE(FieldAccessOld) {
const char* kScriptChars =
"class Fields {\n"
" Fields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class FieldsTest {\n"
" static Fields testMain() {\n"
" Fields obj = new Fields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("FieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(retobj);
// Now access and set various static fields of Fields class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Fields"));
EXPECT_VALID(cls);
result = Dart_GetStaticField(cls, Dart_NewString("fld1"));
EXPECT(Dart_IsError(result));
result = Dart_GetInstanceField(retobj, Dart_NewString("fld3"));
EXPECT(Dart_IsError(result));
result = Dart_GetStaticField(cls, Dart_NewString("fld4"));
EXPECT_VALID(result);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(10, value);
result = Dart_SetStaticField(cls,
Dart_NewString("fld4"),
Dart_NewInteger(20));
EXPECT(Dart_IsError(result));
result = Dart_GetStaticField(cls, Dart_NewString("fld3"));
EXPECT_VALID(result);
result = Dart_SetStaticField(cls,
Dart_NewString("fld3"),
Dart_NewInteger(200));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(200, value);
// Now access and set various instance fields of the returned object.
result = Dart_GetInstanceField(retobj, Dart_NewString("fld3"));
EXPECT(Dart_IsError(result));
result = Dart_GetInstanceField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(10, value);
result = Dart_GetInstanceField(retobj, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(20, value);
result = Dart_SetInstanceField(retobj,
Dart_NewString("fld2"),
Dart_NewInteger(40));
EXPECT(Dart_IsError(result));
result = Dart_SetInstanceField(retobj,
Dart_NewString("fld1"),
Dart_NewInteger(40));
EXPECT_VALID(result);
result = Dart_GetInstanceField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(40, value);
}
TEST_CASE(HiddenFieldAccess) {
const char* kScriptChars =
"class HiddenFields {\n"
" HiddenFields(int i, int j) : _fld1 = i, _fld2 = j {}\n"
" int _fld1;\n"
" final int _fld2;\n"
" static int _fld3;\n"
" static final int _fld4 = 10;\n"
"}\n"
"class HiddenFieldsTest {\n"
" static HiddenFields testMain() {\n"
" HiddenFields obj = new HiddenFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
// Load up a test script which extends the native wrapper class.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("HiddenFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(retobj);
// Now access and set various static fields of HiddenFields class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("HiddenFields"));
EXPECT_VALID(cls);
result = Dart_GetStaticField(cls, Dart_NewString("_fld1"));
EXPECT(Dart_IsError(result));
result = Dart_GetInstanceField(retobj, Dart_NewString("_fld3"));
EXPECT(Dart_IsError(result));
result = Dart_GetStaticField(cls, Dart_NewString("_fld4"));
EXPECT_VALID(result);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(10, value);
result = Dart_SetStaticField(cls,
Dart_NewString("_fld4"),
Dart_NewInteger(20));
EXPECT(Dart_IsError(result));
result = Dart_GetStaticField(cls, Dart_NewString("_fld3"));
EXPECT_VALID(result);
result = Dart_SetStaticField(cls,
Dart_NewString("_fld3"),
Dart_NewInteger(200));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(200, value);
// Now access and set various instance fields of the returned object.
result = Dart_GetInstanceField(retobj, Dart_NewString("_fld3"));
EXPECT(Dart_IsError(result));
result = Dart_GetInstanceField(retobj, Dart_NewString("_fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(10, value);
result = Dart_GetInstanceField(retobj, Dart_NewString("_fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(20, value);
result = Dart_SetInstanceField(retobj,
Dart_NewString("_fld2"),
Dart_NewInteger(40));
EXPECT(Dart_IsError(result));
result = Dart_SetInstanceField(retobj,
Dart_NewString("_fld1"),
Dart_NewInteger(40));
EXPECT_VALID(result);
result = Dart_GetInstanceField(retobj, Dart_NewString("_fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(40, value);
}
void NativeFieldLookup(Dart_NativeArguments args) {
UNREACHABLE();
}
static Dart_NativeFunction native_field_lookup(Dart_Handle name,
int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&NativeFieldLookup);
}
TEST_CASE(InjectNativeFields1) {
const char* kScriptChars =
"class NativeFields extends NativeFieldsWrapper {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
const int kNumNativeFields = 4;
// Create a test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Create a native wrapper class with native fields.
result = Dart_CreateNativeWrapperClass(
lib,
Dart_NewString("NativeFieldsWrapper"),
kNumNativeFields);
// Load up a test script in the test library.
// Invoke a function which returns an object of type NativeFields.
result = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(result);
DARTSCOPE_NOCHECKS(Isolate::Current());
Instance& obj = Instance::Handle();
obj ^= Api::UnwrapHandle(result);
const Class& cls = Class::Handle(obj.clazz());
// We expect the newly created "NativeFields" object to have
// 2 dart instance fields (fld1, fld2) and kNumNativeFields native fields.
// Hence the size of an instance of "NativeFields" should be
// (kNumNativeFields + 2) * kWordSize + size of object header.
// We check to make sure the instance size computed by the VM matches
// our expectations.
intptr_t header_size = sizeof(RawObject);
EXPECT_EQ(Utils::RoundUp(((kNumNativeFields + 2) * kWordSize) + header_size,
kObjectAlignment),
cls.instance_size());
}
TEST_CASE(InjectNativeFields2) {
const char* kScriptChars =
"class NativeFields extends NativeFieldsWrapper {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type NativeFields.
result = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
// We expect this to fail as class "NativeFields" extends
// "NativeFieldsWrapper" and there is no definition of it either
// in the dart code or through the native field injection mechanism.
EXPECT(Dart_IsError(result));
}
TEST_CASE(InjectNativeFields3) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFields extends NativeFieldWrapperClass2 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
const int kNumNativeFields = 2;
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Invoke a function which returns an object of type NativeFields.
result = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(result);
DARTSCOPE_NOCHECKS(Isolate::Current());
Instance& obj = Instance::Handle();
obj ^= Api::UnwrapHandle(result);
const Class& cls = Class::Handle(obj.clazz());
// We expect the newly created "NativeFields" object to have
// 2 dart instance fields (fld1, fld2) and kNumNativeFields native fields.
// Hence the size of an instance of "NativeFields" should be
// (kNumNativeFields + 2) * kWordSize + size of object header.
// We check to make sure the instance size computed by the VM matches
// our expectations.
intptr_t header_size = sizeof(RawObject);
EXPECT_EQ(Utils::RoundUp(((kNumNativeFields + 2) * kWordSize) + header_size,
kObjectAlignment),
cls.instance_size());
}
TEST_CASE(InjectNativeFields4) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFields extends NativeFieldWrapperClass2 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type NativeFields.
result = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
// We expect the test script to fail finalization with the error below:
EXPECT(Dart_IsError(result));
Dart_Handle expected_error = Dart_Error(
"'dart:test-lib': Error: line 1 pos 38: "
"class 'NativeFields' is trying to extend a native fields class, "
"but library '%s' has no native resolvers",
TestCase::url());
EXPECT_SUBSTRING(Dart_GetError(expected_error), Dart_GetError(result));
}
static void TestNativeFields(Dart_Handle retobj) {
// Access and set various instance fields of the object.
Dart_Handle result = Dart_GetInstanceField(retobj, Dart_NewString("fld3"));
EXPECT(Dart_IsError(result));
result = Dart_GetInstanceField(retobj, Dart_NewString("fld0"));
EXPECT_VALID(result);
EXPECT(Dart_IsNull(result));
result = Dart_GetInstanceField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(10, value);
result = Dart_GetInstanceField(retobj, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(20, value);
result = Dart_SetInstanceField(retobj,
Dart_NewString("fld2"),
Dart_NewInteger(40));
EXPECT(Dart_IsError(result));
result = Dart_SetInstanceField(retobj,
Dart_NewString("fld1"),
Dart_NewInteger(40));
EXPECT_VALID(result);
result = Dart_GetInstanceField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(40, value);
// Now access and set various native instance fields of the returned object.
const int kNativeFld0 = 0;
const int kNativeFld1 = 1;
const int kNativeFld2 = 2;
const int kNativeFld3 = 3;
const int kNativeFld4 = 4;
intptr_t field_value = 0;
result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &field_value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_GetNativeInstanceField(retobj, kNativeFld1, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_GetNativeInstanceField(retobj, kNativeFld2, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_GetNativeInstanceField(retobj, kNativeFld3, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(0, field_value);
result = Dart_SetNativeInstanceField(retobj, kNativeFld4, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld0, 4);
EXPECT_VALID(result);
result = Dart_SetNativeInstanceField(retobj, kNativeFld1, 40);
EXPECT_VALID(result);
result = Dart_SetNativeInstanceField(retobj, kNativeFld2, 400);
EXPECT_VALID(result);
result = Dart_SetNativeInstanceField(retobj, kNativeFld3, 4000);
EXPECT_VALID(result);
result = Dart_GetNativeInstanceField(retobj, kNativeFld3, &field_value);
EXPECT_VALID(result);
EXPECT_EQ(4000, field_value);
// Now re-access various dart instance fields of the returned object
// to ensure that there was no corruption while setting native fields.
result = Dart_GetInstanceField(retobj, Dart_NewString("fld1"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(40, value);
result = Dart_GetInstanceField(retobj, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(20, value);
}
TEST_CASE(NativeFieldAccess) {
const char* kScriptChars =
"class NativeFields extends NativeFieldsWrapper {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld0;\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
const int kNumNativeFields = 4;
// Create a test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Create a native wrapper class with native fields.
Dart_Handle result = Dart_CreateNativeWrapperClass(
lib,
Dart_NewString("NativeFieldsWrapper"),
kNumNativeFields);
EXPECT_VALID(result);
// Load up a test script in it.
// Invoke a function which returns an object of type NativeFields.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(retobj);
// Now access and set various instance fields of the returned object.
TestNativeFields(retobj);
}
TEST_CASE(ImplicitNativeFieldAccess) {
const char* kScriptChars =
"#import('dart:nativewrappers');"
"class NativeFields extends NativeFieldWrapperClass4 {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld0;\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
// Load up a test script in the test library.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
native_field_lookup);
// Invoke a function which returns an object of type NativeFields.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(retobj);
// Now access and set various instance fields of the returned object.
TestNativeFields(retobj);
}
TEST_CASE(NegativeNativeFieldAccess) {
const char* kScriptChars =
"class NativeFields {\n"
" NativeFields(int i, int j) : fld1 = i, fld2 = j {}\n"
" int fld1;\n"
" final int fld2;\n"
" static int fld3;\n"
" static final int fld4 = 10;\n"
"}\n"
"class NativeFieldsTest {\n"
" static NativeFields testMain1() {\n"
" NativeFields obj = new NativeFields(10, 20);\n"
" return obj;\n"
" }\n"
" static Function testMain2() {\n"
" return function() {};\n"
" }\n"
"}\n";
Dart_Handle result;
DARTSCOPE_NOCHECKS(Isolate::Current());
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type NativeFields.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain1"),
0,
NULL);
EXPECT_VALID(retobj);
// Now access and set various native instance fields of the returned object.
// All of these tests are expected to return failure as there are no
// native fields in an instance of NativeFields.
const int kNativeFld0 = 0;
const int kNativeFld1 = 1;
const int kNativeFld2 = 2;
const int kNativeFld3 = 3;
const int kNativeFld4 = 4;
intptr_t value = 0;
result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld1, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld2, &value);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld4, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld3, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld0, 400);
EXPECT(Dart_IsError(result));
// Invoke a function which returns a closure object.
retobj = Dart_InvokeStatic(lib,
Dart_NewString("NativeFieldsTest"),
Dart_NewString("testMain2"),
0,
NULL);
EXPECT_VALID(retobj);
result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld1, &value);
EXPECT(Dart_IsError(result));
result = Dart_GetNativeInstanceField(retobj, kNativeFld2, &value);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld4, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld3, 40);
EXPECT(Dart_IsError(result));
result = Dart_SetNativeInstanceField(retobj, kNativeFld0, 400);
EXPECT(Dart_IsError(result));
}
TEST_CASE(GetStaticField_RunsInitializer) {
const char* kScriptChars =
"class TestClass {\n"
" static final int fld1 = 7;\n"
" static int fld2 = 11;\n"
" static void testMain() {\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object.
result = Dart_InvokeStatic(lib,
Dart_NewString("TestClass"),
Dart_NewString("testMain"),
0,
NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("TestClass"));
EXPECT_VALID(cls);
// For uninitialized fields, the getter is returned
result = Dart_GetStaticField(cls, Dart_NewString("fld1"));
EXPECT_VALID(result);
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(7, value);
result = Dart_GetStaticField(cls, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(11, value);
// Overwrite fld2
result = Dart_SetStaticField(cls,
Dart_NewString("fld2"),
Dart_NewInteger(13));
EXPECT_VALID(result);
// We now get the new value for fld2, not the initializer
result = Dart_GetStaticField(cls, Dart_NewString("fld2"));
EXPECT_VALID(result);
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(13, value);
}
TEST_CASE(StaticFieldNotFound) {
const char* kScriptChars =
"class TestClass {\n"
" static void testMain() {\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function.
result = Dart_InvokeStatic(lib,
Dart_NewString("TestClass"),
Dart_NewString("testMain"),
0,
NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("TestClass"));
EXPECT_VALID(cls);
result = Dart_GetStaticField(cls, Dart_NewString("not_found"));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Specified field is not found in the class",
Dart_GetError(result));
result = Dart_SetStaticField(cls,
Dart_NewString("not_found"),
Dart_NewInteger(13));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Specified field is not found in the class",
Dart_GetError(result));
}
TEST_CASE(Invoke) {
const char* kScriptChars =
"class BaseMethods {\n"
" inheritedMethod(arg) => 'inherited $arg';\n"
" static nonInheritedMethod(arg) => 'noninherited $arg';\n"
"}\n"
"\n"
"class Methods extends BaseMethods {\n"
" instanceMethod(arg) => 'instance $arg';\n"
" _instanceMethod(arg) => 'hidden instance $arg';\n"
" static staticMethod(arg) => 'static $arg';\n"
" static _staticMethod(arg) => 'hidden static $arg';\n"
"}\n"
"\n"
"topMethod(arg) => 'top $arg';\n"
"_topMethod(arg) => 'hidden top $arg';\n"
"\n"
"Methods test() {\n"
" return new Methods();\n"
"}\n";
// Shared setup.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("Methods"));
EXPECT_VALID(cls);
Dart_Handle instance = Dart_Invoke(lib, Dart_NewString("test"), 0, NULL);
EXPECT_VALID(instance);
Dart_Handle args[1];
args[0] = Dart_NewString("!!!");
Dart_Handle bad_args[2];
bad_args[0] = Dart_NewString("bad1");
bad_args[1] = Dart_NewString("bad2");
Dart_Handle result;
Dart_Handle name;
const char* str;
// Instance method.
name = Dart_NewString("instanceMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("instance !!!", str);
// Instance method, wrong arg count.
EXPECT_ERROR(Dart_Invoke(instance, name, 2, bad_args),
"did not find instance method 'Methods.instanceMethod'");
// Hidden instance method.
name = Dart_NewString("_instanceMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden instance !!!", str);
// Inherited method.
name = Dart_NewString("inheritedMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
result = Dart_Invoke(instance, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("inherited !!!", str);
// Static method.
name = Dart_NewString("staticMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(cls, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("static !!!", str);
// Static method, wrong arg count.
EXPECT_ERROR(Dart_Invoke(cls, name, 2, bad_args),
"did not find static method 'Methods.staticMethod'");
// Hidden static method.
name = Dart_NewString("_staticMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(cls, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden static !!!", str);
// Static non-inherited method. Not found at any level.
name = Dart_NewString("non_inheritedMethod");
EXPECT(Dart_IsError(Dart_Invoke(lib, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
// Top-Level method.
name = Dart_NewString("topMethod");
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(lib, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("top !!!", str);
// Top-level method, wrong arg count.
EXPECT_ERROR(Dart_Invoke(lib, name, 2, bad_args),
"did not find top-level function 'topMethod'");
// Hidden top-level method.
name = Dart_NewString("_topMethod");
EXPECT(Dart_IsError(Dart_Invoke(cls, name, 1, args)));
EXPECT(Dart_IsError(Dart_Invoke(instance, name, 1, args)));
result = Dart_Invoke(lib, name, 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hidden top !!!", str);
}
TEST_CASE(Invoke_FunnyArgs) {
const char* kScriptChars =
"test(arg) => 'hello $arg';\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_Handle args[1];
const char* str;
// Make sure that valid args yield valid results.
args[0] = Dart_NewString("!!!");
Dart_Handle result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hello !!!", str);
// Make sure that null is legal.
args[0] = Dart_Null();
result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT_VALID(result);
result = Dart_StringToCString(result, &str);
EXPECT_STREQ("hello null", str);
// Pass a non-instance handle.
args[0] = lib;
result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_Invoke expects argument 0 to be an instance of Object.",
Dart_GetError(result));
// Pass an error handle. The error is contagious.
args[0] = Api::NewError("myerror");
result = Dart_Invoke(lib, Dart_NewString("test"), 1, args);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("myerror", Dart_GetError(result));
}
TEST_CASE(InvokeDynamic) {
const char* kScriptChars =
"class InvokeDynamic {\n"
" InvokeDynamic(int i, int j) : fld1 = i, fld2 = j {}\n"
" int method1(int i) { return i + fld1 + fld2 + fld4; }\n"
" static int method2(int i) { return i + fld4; }\n"
" int fld1;\n"
" final int fld2;\n"
" static final int fld4 = 10;\n"
"}\n"
"class InvokeDynamicTest {\n"
" static InvokeDynamic testMain() {\n"
" InvokeDynamic obj = new InvokeDynamic(10, 20);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
DARTSCOPE_NOCHECKS(Isolate::Current());
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type InvokeDynamic.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("InvokeDynamicTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(retobj);
// Now invoke a dynamic method and check the result.
Dart_Handle dart_arguments[1];
dart_arguments[0] = Dart_NewInteger(1);
result = Dart_InvokeDynamic(retobj,
Dart_NewString("method1"),
1,
dart_arguments);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(41, value);
result = Dart_InvokeDynamic(retobj, Dart_NewString("method2"), 0, NULL);
EXPECT(Dart_IsError(result));
result = Dart_InvokeDynamic(retobj, Dart_NewString("method1"), 0, NULL);
EXPECT(Dart_IsError(result));
}
TEST_CASE(InvokeClosure) {
const char* kScriptChars =
"class InvokeClosure {\n"
" InvokeClosure(int i, int j) : fld1 = i, fld2 = j {}\n"
" Function method1(int i) {\n"
" f(int j) => j + i + fld1 + fld2 + fld4; \n"
" return f;\n"
" }\n"
" static Function method2(int i) {\n"
" n(int j) => true + i + fld4; \n"
" return n;\n"
" }\n"
" int fld1;\n"
" final int fld2;\n"
" static final int fld4 = 10;\n"
"}\n"
"class InvokeClosureTest {\n"
" static Function testMain1() {\n"
" InvokeClosure obj = new InvokeClosure(10, 20);\n"
" return obj.method1(10);\n"
" }\n"
" static Function testMain2() {\n"
" return InvokeClosure.method2(10);\n"
" }\n"
"}\n";
Dart_Handle result;
DARTSCOPE_NOCHECKS(Isolate::Current());
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns a closure.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("InvokeClosureTest"),
Dart_NewString("testMain1"),
0,
NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
EXPECT(!Dart_IsClosure(Dart_NewInteger(101)));
// Now invoke the closure and check the result.
Dart_Handle dart_arguments[1];
dart_arguments[0] = Dart_NewInteger(1);
result = Dart_InvokeClosure(retobj, 1, dart_arguments);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(51, value);
// Invoke closure with wrong number of args, should result in exception.
result = Dart_InvokeClosure(retobj, 0, NULL);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
// Invoke a function which returns a closure.
retobj = Dart_InvokeStatic(lib,
Dart_NewString("InvokeClosureTest"),
Dart_NewString("testMain2"),
0,
NULL);
EXPECT_VALID(retobj);
EXPECT(Dart_IsClosure(retobj));
EXPECT(!Dart_IsClosure(Dart_NewString("abcdef")));
// Now invoke the closure and check the result (should be an exception).
dart_arguments[0] = Dart_NewInteger(1);
result = Dart_InvokeClosure(retobj, 1, dart_arguments);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
}
void ExceptionNative(Dart_NativeArguments args) {
Dart_Handle param = Dart_GetNativeArgument(args, 0);
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
Dart_ThrowException(param);
UNREACHABLE();
}
static Dart_NativeFunction native_lookup(Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&ExceptionNative);
}
TEST_CASE(ThrowException) {
const char* kScriptChars =
"class ThrowException {\n"
" ThrowException(int i) : fld1 = i {}\n"
" int method1(int i) native \"ThrowException_native\";"
" int method2() {\n"
" try { method1(10); } catch(var a) { return 5; } return 10;\n"
" }\n"
" int fld1;\n"
"}\n"
"class ThrowExceptionTest {\n"
" static ThrowException testMain() {\n"
" ThrowException obj = new ThrowException(10);\n"
" return obj;\n"
" }\n"
"}\n";
Dart_Handle result;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
intptr_t size = state->ZoneSizeInBytes();
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Load up a test script which extends the native wrapper class.
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars,
reinterpret_cast<Dart_NativeEntryResolver>(native_lookup));
// Invoke a function which returns an object of type ThrowException.
Dart_Handle retobj = Dart_InvokeStatic(lib,
Dart_NewString("ThrowExceptionTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(retobj);
// Throwing an exception here should result in an error.
result = Dart_ThrowException(retobj);
EXPECT(Dart_IsError(result));
// Now invoke method2 which invokes a natve method where it is
// ok to throw an exception, check the result which would indicate
// if an exception was thrown or not.
result = Dart_InvokeDynamic(retobj, Dart_NewString("method2"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_EQ(5, value);
Dart_ExitScope(); // Exit the Dart API scope.
EXPECT_EQ(size, state->ZoneSizeInBytes());
}
void NativeArgumentCounter(Dart_NativeArguments args) {
Dart_EnterScope();
int count = Dart_GetNativeArgumentCount(args);
Dart_SetReturnValue(args, Dart_NewInteger(count));
Dart_ExitScope();
}
static Dart_NativeFunction gnac_lookup(Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentCounter);
}
TEST_CASE(GetNativeArgumentCount) {
const char* kScriptChars =
"class MyObject {"
" int method1(int i, int j) native 'Name_Does_Not_Matter';"
"}"
"class Test {"
" static testMain() {"
" MyObject obj = new MyObject();"
" return obj.method1(77, 125);"
" }"
"}";
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars,
reinterpret_cast<Dart_NativeEntryResolver>(gnac_lookup));
Dart_Handle result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
result = Dart_IntegerToInt64(result, &value);
EXPECT_VALID(result);
EXPECT_EQ(3, value);
}
TEST_CASE(GetClass) {
const char* kScriptChars =
"class DoesExist {"
"}";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Lookup a class that does exist.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("DoesExist"));
EXPECT_VALID(cls);
// Lookup a class that does not exist.
cls = Dart_GetClass(lib, Dart_NewString("DoesNotExist"));
EXPECT(Dart_IsError(cls));
EXPECT_STREQ("Class 'DoesNotExist' not found in library 'dart:test-lib'.",
Dart_GetError(cls));
}
TEST_CASE(InstanceOf) {
const char* kScriptChars =
"class OtherClass {\n"
" static returnNull() { return null; }\n"
"}\n"
"class InstanceOfTest {\n"
" InstanceOfTest() {}\n"
" static InstanceOfTest testMain() {\n"
" return new InstanceOfTest();\n"
" }\n"
"}\n";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke a function which returns an object of type InstanceOf..
Dart_Handle instanceOfTestObj =
Dart_InvokeStatic(lib,
Dart_NewString("InstanceOfTest"),
Dart_NewString("testMain"),
0,
NULL);
EXPECT_VALID(instanceOfTestObj);
// Fetch InstanceOfTest class.
Dart_Handle cls = Dart_GetClass(lib, Dart_NewString("InstanceOfTest"));
EXPECT_VALID(cls);
// Now check instanceOfTestObj reported as an instance of
// InstanceOfTest class.
bool is_instance = false;
result = Dart_ObjectIsType(instanceOfTestObj, cls, &is_instance);
EXPECT_VALID(result);
EXPECT(is_instance);
// Fetch OtherClass and check if instanceOfTestObj is instance of it.
Dart_Handle otherClass = Dart_GetClass(lib, Dart_NewString("OtherClass"));
EXPECT_VALID(otherClass);
result = Dart_ObjectIsType(instanceOfTestObj, otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
// Check that primitives are not instances of InstanceOfTest class.
result = Dart_ObjectIsType(Dart_NewString("a string"), otherClass,
&is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
result = Dart_ObjectIsType(Dart_NewInteger(42), otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
result = Dart_ObjectIsType(Dart_NewBoolean(true), otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
// Check that null is not an instance of InstanceOfTest class.
Dart_Handle null = Dart_InvokeStatic(lib,
Dart_NewString("OtherClass"),
Dart_NewString("returnNull"),
0,
NULL);
EXPECT_VALID(null);
result = Dart_ObjectIsType(null, otherClass, &is_instance);
EXPECT_VALID(result);
EXPECT(!is_instance);
// Check that error is returned if null is passed as a class argument.
result = Dart_ObjectIsType(null, null, &is_instance);
EXPECT(Dart_IsError(result));
}
TEST_CASE(NullReceiver) {
Isolate* isolate = Isolate::Current();
DARTSCOPE_NOCHECKS(isolate);
Dart_Handle function_name = Dart_NewString("toString");
const int number_of_arguments = 0;
Dart_Handle result = Dart_InvokeDynamic(Dart_Null(),
function_name,
number_of_arguments,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
// Should throw a NullPointerException. Disabled due to bug 5415268.
/*
Dart_Handle function_name2 = Dart_NewString("NoNoNo");
result = Dart_InvokeDynamic(null_receiver,
function_name2,
number_of_arguments,
dart_arguments);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result)); */
}
static Dart_Handle library_handler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url,
Dart_Handle import_url_map) {
if (tag == kCanonicalizeUrl) {
return url;
}
return Api::Success(Isolate::Current());
}
TEST_CASE(LoadScript) {
const char* kScriptChars =
"main() {"
" return 12345;"
"}";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
Dart_Handle import_map = Dart_NewList(0);
result = Dart_LoadScript(Dart_Null(), source, library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LoadScript(Dart_True(), source, library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LoadScript(error, source, library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadScript(url, Dart_Null(), library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript expects argument 'source' to be non-null.",
Dart_GetError(result));
result = Dart_LoadScript(url, Dart_True(), library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadScript expects argument 'source' to be of type String.",
Dart_GetError(result));
result = Dart_LoadScript(url, error, library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Load a script successfully.
result = Dart_LoadScript(url, source, library_handler, import_map);
EXPECT_VALID(result);
result = Dart_InvokeStatic(result,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(12345, value);
// Further calls to LoadScript are errors.
result = Dart_LoadScript(url, source, library_handler, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadScript: "
"A script has already been loaded from 'dart:test-lib'.",
Dart_GetError(result));
}
static const char* var_mapping[] = {
"GOOGLE3", ".",
"ABC", "lala",
"var1", "",
"var2", "winner",
};
static int index = 0;
static Dart_Handle import_library_handler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url,
Dart_Handle import_url_map) {
if (tag == kCanonicalizeUrl) {
return url;
}
EXPECT(Dart_IsString(url));
const char* cstr = NULL;
EXPECT_VALID(Dart_StringToCString(url, &cstr));
switch (index) {
case 0:
EXPECT_STREQ("./weird.dart", cstr);
break;
case 1:
EXPECT_STREQ("abclaladef", cstr);
break;
case 2:
EXPECT_STREQ("winner", cstr);
break;
case 3:
EXPECT_STREQ("abclaladef/extra_weird.dart", cstr);
break;
case 4:
EXPECT_STREQ("winnerwinner", cstr);
break;
default:
EXPECT(false);
return Api::NewError("invalid callback");
}
index += 1;
return Api::Success(Isolate::Current());
}
TEST_CASE(LoadImportScript) {
const char* kScriptChars =
"#import('$GOOGLE3/weird.dart');"
"#import('abc${ABC}def');"
"#import('${var1}$var2');"
"#import('abc${ABC}def/extra_weird.dart');"
"#import('$var2$var2');"
"main() {"
" return 12345;"
"}";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
intptr_t length = (sizeof(var_mapping) / sizeof(var_mapping[0]));
Dart_Handle import_map = Dart_NewList(length);
for (intptr_t i = 0; i < length; i++) {
Dart_ListSetAt(import_map, i, Dart_NewString(var_mapping[i]));
}
Dart_Handle result = Dart_LoadScript(url,
source,
import_library_handler,
import_map);
EXPECT(!Dart_IsError(result));
}
TEST_CASE(LoadImportScriptError1) {
const char* kScriptChars =
"#import('abc${DEF}def/extra_weird.dart');"
"main() {"
" return 12345;"
"}";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle result = Dart_LoadScript(url,
source,
import_library_handler,
import_map);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result),
"import variable 'DEF' has not been defined"));
}
TEST_CASE(LoadImportScriptError2) {
const char* kScriptChars =
"#import('abc${ABC/extra_weird.dart');"
"main() {"
" return 12345;"
"}";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
intptr_t length = (sizeof(var_mapping) / sizeof(var_mapping[0]));
Dart_Handle import_map = Dart_NewList(length);
for (intptr_t i = 0; i < length; i++) {
Dart_ListSetAt(import_map, i, Dart_NewString(var_mapping[i]));
}
Dart_Handle result = Dart_LoadScript(url,
source,
import_library_handler,
import_map);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result), "'}' expected"));
}
TEST_CASE(LoadScript_CompileError) {
const char* kScriptChars =
")";
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle result = Dart_LoadScript(url,
source,
library_handler,
import_map);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result), "unexpected token ')'"));
}
TEST_CASE(LookupLibrary) {
const char* kScriptChars =
"#import('library1.dart');"
"main() {}";
const char* kLibrary1Chars =
"#library('library1.dart');"
"#import('library2.dart');";
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle result = Dart_LoadScript(url,
source,
library_handler,
import_map);
EXPECT_VALID(result);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
result = Dart_LoadLibrary(url, source, import_map);
EXPECT_VALID(result);
result = Dart_LookupLibrary(url);
EXPECT_VALID(result);
result = Dart_LookupLibrary(Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LookupLibrary expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LookupLibrary(Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LookupLibrary expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LookupLibrary(Dart_Error("incoming error"));
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
url = Dart_NewString("noodles.dart");
result = Dart_LookupLibrary(url);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LookupLibrary: library 'noodles.dart' not found.",
Dart_GetError(result));
}
TEST_CASE(LibraryUrl) {
const char* kLibrary1Chars =
"#library('library1_name');";
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle lib = Dart_LoadLibrary(url, source, Dart_Null());
Dart_Handle error = Dart_Error("incoming error");
EXPECT_VALID(lib);
Dart_Handle result = Dart_LibraryUrl(Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryUrl expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryUrl(Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryUrl expects argument 'library' to be of type Library.",
Dart_GetError(result));
result = Dart_LibraryUrl(error);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryUrl(lib);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* cstr = NULL;
EXPECT_VALID(Dart_StringToCString(result, &cstr));
EXPECT_STREQ("library1_url", cstr);
}
TEST_CASE(LibraryImportLibrary) {
const char* kLibrary1Chars =
"#library('library1_name');";
const char* kLibrary2Chars =
"#library('library2_name');";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle lib1 = Dart_LoadLibrary(url, source, import_map);
EXPECT_VALID(lib1);
url = Dart_NewString("library2_url");
source = Dart_NewString(kLibrary2Chars);
Dart_Handle lib2 = Dart_LoadLibrary(url, source, import_map);
EXPECT_VALID(lib2);
result = Dart_LibraryImportLibrary(Dart_Null(), lib2);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryImportLibrary expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(Dart_True(), lib2);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryImportLibrary expects argument 'library' to be of "
"type Library.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(error, lib2);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LibraryImportLibrary expects argument 'import' to be non-null.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LibraryImportLibrary expects argument 'import' to be of "
"type Library.",
Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, error);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LibraryImportLibrary(lib1, lib2);
EXPECT_VALID(result);
}
TEST_CASE(LoadLibrary) {
const char* kLibrary1Chars =
"#library('library1_name');";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle import_map = Dart_NewList(0);
result = Dart_LoadLibrary(Dart_Null(), source, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadLibrary expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LoadLibrary(Dart_True(), source, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadLibrary expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LoadLibrary(error, source, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadLibrary(url, Dart_Null(), import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadLibrary expects argument 'source' to be non-null.",
Dart_GetError(result));
result = Dart_LoadLibrary(url, Dart_True(), import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadLibrary expects argument 'source' to be of type String.",
Dart_GetError(result));
result = Dart_LoadLibrary(url, error, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Success.
result = Dart_LoadLibrary(url, source, import_map);
EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(result));
// Duplicate library load fails.
result = Dart_LoadLibrary(url, source, import_map);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadLibrary: library 'library1_url' has already been loaded.",
Dart_GetError(result));
}
TEST_CASE(LoadLibrary_CompileError) {
const char* kLibrary1Chars =
"#library('library1_name');"
")";
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle result = Dart_LoadLibrary(url, source, import_map);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result), "unexpected token ')'"));
}
TEST_CASE(LoadSource) {
const char* kLibrary1Chars =
"#library('library1_name');";
const char* kSourceChars =
"// Something innocuous";
const char* kBadSourceChars =
")";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
// Load up a library.
Dart_Handle url = Dart_NewString("library1_url");
Dart_Handle source = Dart_NewString(kLibrary1Chars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle lib = Dart_LoadLibrary(url, source, import_map);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
url = Dart_NewString("source_url");
source = Dart_NewString(kSourceChars);
result = Dart_LoadSource(Dart_Null(), url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_LoadSource(Dart_True(), url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadSource expects argument 'library' to be of type Library.",
Dart_GetError(result));
result = Dart_LoadSource(error, url, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadSource(lib, Dart_Null(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'url' to be non-null.",
Dart_GetError(result));
result = Dart_LoadSource(lib, Dart_True(), source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'url' to be of type String.",
Dart_GetError(result));
result = Dart_LoadSource(lib, error, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_LoadSource(lib, url, Dart_Null());
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_LoadSource expects argument 'source' to be non-null.",
Dart_GetError(result));
result = Dart_LoadSource(lib, url, Dart_True());
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_LoadSource expects argument 'source' to be of type String.",
Dart_GetError(result));
result = Dart_LoadSource(lib, error, source);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
// Success.
result = Dart_LoadSource(lib, url, source);
EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(result));
bool same = false;
EXPECT_VALID(Dart_IsSame(lib, result, &same));
EXPECT(same);
// Duplicate calls are okay.
result = Dart_LoadSource(lib, url, source);
EXPECT_VALID(result);
EXPECT(Dart_IsLibrary(result));
same = false;
EXPECT_VALID(Dart_IsSame(lib, result, &same));
EXPECT(same);
// Language errors are detected.
source = Dart_NewString(kBadSourceChars);
result = Dart_LoadSource(lib, url, source);
EXPECT(Dart_IsError(result));
}
static void MyNativeFunction1(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_SetReturnValue(args, Dart_NewInteger(654321));
Dart_ExitScope();
}
static void MyNativeFunction2(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_SetReturnValue(args, Dart_NewInteger(123456));
Dart_ExitScope();
}
static Dart_NativeFunction MyNativeResolver1(Dart_Handle name,
int arg_count) {
return &MyNativeFunction1;
}
static Dart_NativeFunction MyNativeResolver2(Dart_Handle name,
int arg_count) {
return &MyNativeFunction2;
}
TEST_CASE(SetNativeResolver) {
const char* kScriptChars =
"class Test {"
" static foo() native \"SomeNativeFunction\";"
" static bar() native \"SomeNativeFunction2\";"
" static baz() native \"SomeNativeFunction3\";"
"}";
Dart_Handle error = Dart_Error("incoming error");
Dart_Handle result;
// Load a test script.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle lib = Dart_LoadScript(url, source, library_handler, import_map);
EXPECT_VALID(lib);
EXPECT(Dart_IsLibrary(lib));
result = Dart_SetNativeResolver(Dart_Null(), &MyNativeResolver1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ(
"Dart_SetNativeResolver expects argument 'library' to be non-null.",
Dart_GetError(result));
result = Dart_SetNativeResolver(Dart_True(), &MyNativeResolver1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Dart_SetNativeResolver expects argument 'library' to be of "
"type Library.",
Dart_GetError(result));
result = Dart_SetNativeResolver(error, &MyNativeResolver1);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("incoming error", Dart_GetError(result));
result = Dart_SetNativeResolver(lib, &MyNativeResolver1);
EXPECT_VALID(result);
// Call a function and make sure native resolution works.
result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("foo"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
int64_t value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(654321, value);
// A second call succeeds.
result = Dart_SetNativeResolver(lib, &MyNativeResolver2);
EXPECT_VALID(result);
// 'foo' has already been resolved so gets the old value.
result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("foo"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(654321, value);
// 'bar' has not yet been resolved so gets the new value.
result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("bar"),
0,
NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsInteger(result));
value = 0;
EXPECT_VALID(Dart_IntegerToInt64(result, &value));
EXPECT_EQ(123456, value);
// A NULL resolver is okay, but resolution will fail.
result = Dart_SetNativeResolver(lib, NULL);
EXPECT_VALID(result);
result = Dart_InvokeStatic(lib,
Dart_NewString("Test"),
Dart_NewString("baz"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT(strstr(Dart_GetError(result),
"native function 'SomeNativeFunction3' cannot be found"));
}
TEST_CASE(ImportLibrary1) {
const char* kScriptChars =
"#import('library1.dart');"
"#import('library2.dart');"
"var foo; // library2 defines foo, so should be error."
"main() {}";
const char* kLibrary1Chars =
"#library('library1.dart');"
"#import('library2.dart');"
"var foo1;";
const char* kLibrary2Chars =
"#library('library2.dart');"
"var foo;";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
result = Dart_LoadScript(url, source, library_handler, Dart_Null());
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source, Dart_Null());
url = Dart_NewString("library2.dart");
source = Dart_NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source, Dart_Null());
result = Dart_InvokeStatic(result,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Duplicate definition : 'foo' is defined in"
" 'library2.dart' and 'dart:test-lib'\n",
Dart_GetError(result));
}
TEST_CASE(ImportLibrary2) {
const char* kScriptChars =
"#import('library1.dart');"
"var foo;"
"main() {}";
const char* kLibrary1Chars =
"#library('library1.dart');"
"#import('library2.dart');"
"var foo1;";
const char* kLibrary2Chars =
"#library('library2.dart');"
"#import('library1.dart');"
"var foo;";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
result = Dart_LoadScript(url, source, library_handler, import_map);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("library2.dart");
source = Dart_NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source, import_map);
result = Dart_InvokeStatic(result,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT_VALID(result);
}
TEST_CASE(ImportLibrary3) {
const char* kScriptChars =
"#import('library2.dart');"
"#import('library1.dart');"
"var foo_top = 10; // foo has dup def. So should be an error."
"main() {}";
const char* kLibrary1Chars =
"#library('library1.dart');"
"var foo;";
const char* kLibrary2Chars =
"#library('library2.dart');"
"var foo;";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
result = Dart_LoadScript(url, source, library_handler, import_map);
url = Dart_NewString("library2.dart");
source = Dart_NewString(kLibrary2Chars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("library1.dart");
source = Dart_NewString(kLibrary1Chars);
Dart_LoadLibrary(url, source, import_map);
result = Dart_InvokeStatic(result,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Duplicate definition : 'foo' is defined in"
" 'library1.dart' and 'library2.dart'\n",
Dart_GetError(result));
}
TEST_CASE(ImportLibrary4) {
const char* kScriptChars =
"#import('libraryA.dart');"
"#import('libraryB.dart');"
"#import('libraryD.dart');"
"#import('libraryE.dart');"
"var fooApp;"
"main() {}";
const char* kLibraryAChars =
"#library('libraryA.dart');"
"#import('libraryC.dart');"
"var fooA;";
const char* kLibraryBChars =
"#library('libraryB.dart');"
"#import('libraryC.dart');"
"var fooB;";
const char* kLibraryCChars =
"#library('libraryC.dart');"
"var fooC;";
const char* kLibraryDChars =
"#library('libraryD.dart');"
"#import('libraryF.dart');"
"var fooD;";
const char* kLibraryEChars =
"#library('libraryE.dart');"
"#import('libraryC.dart');"
"#import('libraryF.dart');"
"var fooE = 10; //fooC has duplicate def. so should be an error.";
const char* kLibraryFChars =
"#library('libraryF.dart');"
"var fooC;";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
result = Dart_LoadScript(url, source, library_handler, import_map);
url = Dart_NewString("libraryA.dart");
source = Dart_NewString(kLibraryAChars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("libraryC.dart");
source = Dart_NewString(kLibraryCChars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("libraryB.dart");
source = Dart_NewString(kLibraryBChars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("libraryD.dart");
source = Dart_NewString(kLibraryDChars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("libraryF.dart");
source = Dart_NewString(kLibraryFChars);
Dart_LoadLibrary(url, source, import_map);
url = Dart_NewString("libraryE.dart");
source = Dart_NewString(kLibraryEChars);
Dart_LoadLibrary(url, source, import_map);
result = Dart_InvokeStatic(result,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT_STREQ("Duplicate definition : 'fooC' is defined in"
" 'libraryF.dart' and 'libraryC.dart'\n",
Dart_GetError(result));
}
TEST_CASE(ImportLibrary5) {
const char* kScriptChars =
"#import('lib.dart');"
"interface Y {"
" void set handler(void callback(List<int> x));"
"}"
"void main() {}";
const char* kLibraryChars =
"#library('lib.dart');"
"interface X {"
" void set handler(void callback(List<int> x));"
"}";
Dart_Handle result;
// Create a test library and Load up a test script in it.
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
result = Dart_LoadScript(url, source, library_handler, import_map);
url = Dart_NewString("lib.dart");
source = Dart_NewString(kLibraryChars);
Dart_LoadLibrary(url, source, import_map);
result = Dart_InvokeStatic(result,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT_VALID(result);
}
void NewNativePort_send123(Dart_Port dest_port_id,
Dart_Port reply_port_id,
Dart_CObject *message) {
// Gets a null message.
EXPECT_NOTNULL(message);
EXPECT_EQ(Dart_CObject::kNull, message->type);
// Post integer value.
Dart_CObject* response =
reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate(sizeof(Dart_CObject)));
response->type = Dart_CObject::kInt32;
response->value.as_int32 = 123;
Dart_PostCObject(reply_port_id, response);
}
void NewNativePort_send321(Dart_Port dest_port_id,
Dart_Port reply_port_id,
Dart_CObject* message) {
// Gets a null message.
EXPECT_NOTNULL(message);
EXPECT_EQ(Dart_CObject::kNull, message->type);
// Post integer value.
Dart_CObject* response =
reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate(sizeof(Dart_CObject)));
response->type = Dart_CObject::kInt32;
response->value.as_int32 = 321;
Dart_PostCObject(reply_port_id, response);
}
UNIT_TEST_CASE(NewNativePort) {
// Create a port with a bogus handler.
Dart_Port error_port = Dart_NewNativePort("Foo", NULL, true);
EXPECT_EQ(kIllegalPort, error_port);
// Create the port w/o a current isolate, just to make sure that works.
Dart_Port port_id1 =
Dart_NewNativePort("Port123", NewNativePort_send123, true);
TestIsolateScope __test_isolate__;
const char* kScriptChars =
"#import('dart:isolate');\n"
"void callPort(SendPort port) {\n"
" port.call(null).then((message) {\n"
" throw new Exception(message);\n"
" });\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_EnterScope();
// Create a port w/ a current isolate, to make sure that works too.
Dart_Port port_id2 =
Dart_NewNativePort("Port321", NewNativePort_send321, true);
Dart_Handle send_port1 = Dart_NewSendPort(port_id1);
EXPECT_VALID(send_port1);
Dart_Handle send_port2 = Dart_NewSendPort(port_id2);
EXPECT_VALID(send_port2);
// Test first port.
Dart_Handle dart_args[1];
dart_args[0] = send_port1;
Dart_Handle result = Dart_InvokeStatic(lib,
Dart_NewString(""),
Dart_NewString("callPort"),
1,
dart_args);
EXPECT_VALID(result);
result = Dart_RunLoop();
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("Exception: 123\n", Dart_GetError(result));
// result second port.
dart_args[0] = send_port2;
result = Dart_InvokeStatic(lib,
Dart_NewString(""),
Dart_NewString("callPort"),
1,
dart_args);
EXPECT_VALID(result);
result = Dart_RunLoop();
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("Exception: 321\n", Dart_GetError(result));
Dart_ExitScope();
// Delete the native ports.
EXPECT(Dart_CloseNativePort(port_id1));
EXPECT(Dart_CloseNativePort(port_id2));
}
static bool RunLoopTestCallback(const char* name_prefix,
void* data, char** error) {
const char* kScriptChars =
"#import('builtin');\n"
"#import('dart:isolate');\n"
"class MyIsolate extends Isolate {\n"
" MyIsolate() : super() { }\n"
" void main() {\n"
" port.receive((message, replyTo) {\n"
" if (message) {\n"
" throw new Exception('MakeChildExit');\n"
" } else {\n"
" replyTo.call('hello');\n"
" port.close();\n"
" }\n"
" });\n"
" }\n"
"}\n"
"\n"
"void main(exc_child, exc_parent) {\n"
" new MyIsolate().spawn().then((port) {\n"
" port.call(exc_child).then((message) {\n"
" if (message != 'hello') throw new Exception('ShouldNotHappen');\n"
" if (exc_parent) throw new Exception('MakeParentExit');\n"
" });\n"
" });\n"
"}\n";
if (Dart_CurrentIsolate() != NULL) {
Dart_ExitIsolate();
}
Dart_Isolate isolate = TestCase::CreateTestIsolate();
ASSERT(isolate != NULL);
Dart_EnterScope();
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
Dart_Handle lib = Dart_LoadScript(url,
source,
TestCase::library_handler,
import_map);
EXPECT_VALID(lib);
Dart_ExitScope();
return true;
}
// Common code for RunLoop_Success/RunLoop_Failure.
static void RunLoopTest(bool throw_exception_child,
bool throw_exception_parent) {
Dart_IsolateCreateCallback saved = Isolate::CreateCallback();
Isolate::SetCreateCallback(RunLoopTestCallback);
RunLoopTestCallback(NULL, NULL, NULL);
Dart_EnterScope();
Dart_Handle lib = Dart_LookupLibrary(Dart_NewString(TestCase::url()));
EXPECT_VALID(lib);
Dart_Handle result;
Dart_Handle args[2];
args[0] = (throw_exception_child ? Dart_True() : Dart_False());
args[1] = (throw_exception_parent ? Dart_True() : Dart_False());
result = Dart_InvokeStatic(lib,
Dart_NewString(""),
Dart_NewString("main"),
2,
args);
EXPECT_VALID(result);
result = Dart_RunLoop();
if (throw_exception_parent) {
EXPECT(Dart_IsError(result));
// TODO(turnidge): Once EXPECT_SUBSTRING is submitted use it here.
} else {
EXPECT_VALID(result);
}
Dart_ExitScope();
Dart_ShutdownIsolate();
Isolate::SetCreateCallback(saved);
}
UNIT_TEST_CASE(RunLoop_Success) {
RunLoopTest(false, false);
}
// This test exits the vm. Listed as FAIL in vm.status.
UNIT_TEST_CASE(RunLoop_ExceptionChild) {
RunLoopTest(true, false);
}
UNIT_TEST_CASE(RunLoop_ExceptionParent) {
RunLoopTest(false, true);
}
// Utility functions and variables for test case IsolateInterrupt starts here.
static Monitor* sync = NULL;
static Dart_Isolate shared_isolate = NULL;
static bool main_entered = false;
void MarkMainEntered(Dart_NativeArguments args) {
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Indicate that main has been entered.
{
MonitorLocker ml(sync);
main_entered = true;
ml.Notify();
}
Dart_SetReturnValue(args, Dart_Null());
Dart_ExitScope();
}
static Dart_NativeFunction IsolateInterruptTestNativeLookup(
Dart_Handle name, int argument_count) {
return reinterpret_cast<Dart_NativeFunction>(&MarkMainEntered);
}
void BusyLoop_start(uword unused) {
const char* kScriptChars =
"class Native {\n"
" static void markMainEntered() native 'MarkMainEntered';\n"
"}\n"
"\n"
"void main() {\n"
" Native.markMainEntered();\n"
" while (true) {\n" // Infinite empty loop.
" }\n"
"}\n";
// Tell the other thread that shared_isolate is created.
Dart_Handle lib;
{
sync->Enter();
char* error = NULL;
shared_isolate = Dart_CreateIsolate(NULL, NULL, NULL, &error);
EXPECT(shared_isolate != NULL);
Dart_EnterScope();
Dart_Handle url = Dart_NewString(TestCase::url());
Dart_Handle source = Dart_NewString(kScriptChars);
Dart_Handle import_map = Dart_NewList(0);
lib = Dart_LoadScript(url, source, TestCase::library_handler, import_map);
EXPECT_VALID(lib);
Dart_Handle result = Dart_SetNativeResolver(
lib, &IsolateInterruptTestNativeLookup);
DART_CHECK_VALID(result);
sync->Notify();
sync->Exit();
}
Dart_Handle result = Dart_InvokeStatic(lib,
Dart_NewString(""),
Dart_NewString("main"),
0,
NULL);
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING("Unhandled exception:\nfoo\n",
Dart_GetError(result));
Dart_ExitScope();
Dart_ShutdownIsolate();
// Tell the other thread that we are done (don't use MonitorLocker
// as there is no current isolate any more).
sync->Enter();
shared_isolate = NULL;
sync->Notify();
sync->Exit();
}
// This callback handles isolate interrupts for the IsolateInterrupt
// test. It ignores the first two interrupts and throws an exception
// on the third interrupt.
const int kInterruptCount = 10;
static int interrupt_count = 0;
static bool IsolateInterruptTestCallback() {
OS::Print(" ========== Interrupt callback called #%d\n", interrupt_count + 1);
{
MonitorLocker ml(sync);
interrupt_count++;
ml.Notify();
}
if (interrupt_count == kInterruptCount) {
Dart_EnterScope();
Dart_Handle lib = Dart_LookupLibrary(Dart_NewString(TestCase::url()));
EXPECT_VALID(lib);
Dart_Handle exc = Dart_NewString("foo");
EXPECT_VALID(exc);
Dart_Handle result = Dart_ThrowException(exc);
EXPECT_VALID(result);
UNREACHABLE(); // Dart_ThrowException only returns if it gets an error.
return false;
}
ASSERT(interrupt_count < kInterruptCount);
return true;
}
TEST_CASE(IsolateInterrupt) {
Dart_IsolateInterruptCallback saved = Isolate::InterruptCallback();
Isolate::SetInterruptCallback(IsolateInterruptTestCallback);
sync = new Monitor();
int result = Thread::Start(BusyLoop_start, 0);
EXPECT_EQ(0, result);
{
MonitorLocker ml(sync);
// Wait for the other isolate to enter main.
while (!main_entered) {
ml.Wait();
}
}
// Send a number of interrupts to the other isolate. All but the
// last allow execution to continue. The last causes an exception in
// the isolate.
for (int i = 0; i < kInterruptCount; i++) {
// Space out the interrupts a bit.
OS::Sleep(i + 1);
Dart_InterruptIsolate(shared_isolate);
{
MonitorLocker ml(sync);
// Wait for interrupt_count to be increased.
while (interrupt_count == i) {
ml.Wait();
}
OS::Print(" ========== Interrupt processed #%d\n", interrupt_count);
}
}
{
MonitorLocker ml(sync);
// Wait for our isolate to finish.
while (shared_isolate != NULL) {
ml.Wait();
}
}
// We should have received the expected number of interrupts.
EXPECT_EQ(kInterruptCount, interrupt_count);
// Give the spawned thread enough time to properly exit.
Isolate::SetInterruptCallback(saved);
}
void InitNativeFields(Dart_NativeArguments args) {
Dart_EnterScope();
int count = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(1, count);
Dart_Handle recv = Dart_GetNativeArgument(args, 0);
EXPECT(!Dart_IsError(recv));
Dart_Handle result = Dart_SetNativeInstanceField(recv, 0, 7);
EXPECT(!Dart_IsError(result));
Dart_ExitScope();
}
// The specific api functions called here are a bit arbitrary. We are
// trying to get a sense of the overhead for using the dart api.
void UseDartApi(Dart_NativeArguments args) {
Dart_EnterScope();
int count = Dart_GetNativeArgumentCount(args);
EXPECT_EQ(3, count);
// Get the receiver.
Dart_Handle recv = Dart_GetNativeArgument(args, 0);
EXPECT(!Dart_IsError(recv));
// Get param1.
Dart_Handle param1 = Dart_GetNativeArgument(args, 1);
EXPECT(!Dart_IsError(param1));
EXPECT(Dart_IsInteger(param1));
bool fits = false;
Dart_Handle result = Dart_IntegerFitsIntoInt64(param1, &fits);
EXPECT(!Dart_IsError(result) && fits);
int64_t value1;
result = Dart_IntegerToInt64(param1, &value1);
EXPECT(!Dart_IsError(result));
EXPECT_LE(0, value1);
EXPECT_LE(value1, 1000000);
// Get native field from receiver.
intptr_t value2;
result = Dart_GetNativeInstanceField(recv, 0, &value2);
EXPECT(!Dart_IsError(result));
EXPECT_EQ(7, value2);
// Return param + receiver.field.
Dart_SetReturnValue(args, Dart_NewInteger(value1 * value2));
Dart_ExitScope();
}
static Dart_NativeFunction bm_uda_lookup(Dart_Handle name, int argument_count) {
const char* cstr = NULL;
Dart_Handle result = Dart_StringToCString(name, &cstr);
EXPECT(!Dart_IsError(result));
if (strcmp(cstr, "init") == 0) {
return InitNativeFields;
} else {
return UseDartApi;
}
}
TEST_CASE(Benchmark_UseDartApi) {
const char* kScriptChars =
"class Class extends NativeFieldsWrapper{\n"
" int init() native 'init';\n"
" int method(int param1, int param2) native 'method';\n"
"}\n"
"\n"
"double benchmark(int count) {\n"
" Class c = new Class();\n"
" c.init();\n"
" Stopwatch sw = new Stopwatch.start();\n"
" for (int i = 0; i < count; i++) {\n"
" c.method(i,7);\n"
" }\n"
" sw.stop();\n"
" return sw.elapsedInUs() / count;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(
kScriptChars,
reinterpret_cast<Dart_NativeEntryResolver>(bm_uda_lookup));
// Create a native wrapper class with native fields.
Dart_Handle result = Dart_CreateNativeWrapperClass(
lib,
Dart_NewString("NativeFieldsWrapper"),
1);
EXPECT_VALID(result);
Dart_Handle args[1];
args[0] = Dart_NewInteger(100000);
result = Dart_Invoke(lib,
Dart_NewString("benchmark"),
1,
args);
EXPECT_VALID(result);
EXPECT(Dart_IsDouble(result));
double out;
result = Dart_DoubleValue(result, &out);
fprintf(stderr, "Benchmark_UseDartApi: %f us per iteration\n", out);
}
#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
} // namespace dart