mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 14:32:24 +00:00
1dd4559271
For example setting return value unwraps handles and stores raw pointer values to the stack which might race with GC in another thread. This CL adds assertions in helper methods from Api class which unwrap API handles and fixes all places that were revealed by those assertions. Caveat: we still permit to check whether handle contains Smi or not without entering VM state - because GC does not change this property. Bug: b/127482366 Change-Id: I59f08c2a91935995514fb70607c2777aa2844d94 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95654 Commit-Queue: Siva Annamalai <asiva@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
2117 lines
77 KiB
C++
2117 lines
77 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 "platform/globals.h"
|
|
|
|
#include "include/dart_tools_api.h"
|
|
#include "platform/assert.h"
|
|
#include "vm/class_finalizer.h"
|
|
#include "vm/clustered_snapshot.h"
|
|
#include "vm/dart_api_impl.h"
|
|
#include "vm/dart_api_message.h"
|
|
#include "vm/dart_api_state.h"
|
|
#include "vm/debugger_api_impl_test.h"
|
|
#include "vm/flags.h"
|
|
#include "vm/malloc_hooks.h"
|
|
#include "vm/snapshot.h"
|
|
#include "vm/symbols.h"
|
|
#include "vm/timer.h"
|
|
#include "vm/unicode.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
// Check if serialized and deserialized objects are equal.
|
|
static bool Equals(const Object& expected, const Object& actual) {
|
|
if (expected.IsNull()) {
|
|
return actual.IsNull();
|
|
}
|
|
if (expected.IsSmi()) {
|
|
if (actual.IsSmi()) {
|
|
return expected.raw() == actual.raw();
|
|
}
|
|
return false;
|
|
}
|
|
if (expected.IsDouble()) {
|
|
if (actual.IsDouble()) {
|
|
Double& dbl1 = Double::Handle();
|
|
Double& dbl2 = Double::Handle();
|
|
dbl1 ^= expected.raw();
|
|
dbl2 ^= actual.raw();
|
|
return dbl1.value() == dbl2.value();
|
|
}
|
|
return false;
|
|
}
|
|
if (expected.IsBool()) {
|
|
if (actual.IsBool()) {
|
|
return expected.raw() == actual.raw();
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static uint8_t* malloc_allocator(uint8_t* ptr,
|
|
intptr_t old_size,
|
|
intptr_t new_size) {
|
|
return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
|
|
}
|
|
|
|
// Compare two Dart_CObject object graphs rooted in first and
|
|
// second. The second graph will be destroyed by this operation no matter
|
|
// whether the graphs are equal or not.
|
|
static void CompareDartCObjects(Dart_CObject* first, Dart_CObject* second) {
|
|
// Return immediately if entering a cycle.
|
|
if (second->type == Dart_CObject_kNumberOfTypes) return;
|
|
|
|
EXPECT_NE(first, second);
|
|
EXPECT_EQ(first->type, second->type);
|
|
switch (first->type) {
|
|
case Dart_CObject_kNull:
|
|
// Nothing more to compare.
|
|
break;
|
|
case Dart_CObject_kBool:
|
|
EXPECT_EQ(first->value.as_bool, second->value.as_bool);
|
|
break;
|
|
case Dart_CObject_kInt32:
|
|
EXPECT_EQ(first->value.as_int32, second->value.as_int32);
|
|
break;
|
|
case Dart_CObject_kInt64:
|
|
EXPECT_EQ(first->value.as_int64, second->value.as_int64);
|
|
break;
|
|
case Dart_CObject_kDouble:
|
|
EXPECT_EQ(first->value.as_double, second->value.as_double);
|
|
break;
|
|
case Dart_CObject_kString:
|
|
EXPECT_STREQ(first->value.as_string, second->value.as_string);
|
|
break;
|
|
case Dart_CObject_kTypedData:
|
|
EXPECT_EQ(first->value.as_typed_data.length,
|
|
second->value.as_typed_data.length);
|
|
for (int i = 0; i < first->value.as_typed_data.length; i++) {
|
|
EXPECT_EQ(first->value.as_typed_data.values[i],
|
|
second->value.as_typed_data.values[i]);
|
|
}
|
|
break;
|
|
case Dart_CObject_kArray:
|
|
// Use invalid type as a visited marker to avoid infinite
|
|
// recursion on graphs with cycles.
|
|
second->type = Dart_CObject_kNumberOfTypes;
|
|
EXPECT_EQ(first->value.as_array.length, second->value.as_array.length);
|
|
for (int i = 0; i < first->value.as_array.length; i++) {
|
|
CompareDartCObjects(first->value.as_array.values[i],
|
|
second->value.as_array.values[i]);
|
|
}
|
|
break;
|
|
case Dart_CObject_kCapability:
|
|
EXPECT_EQ(first->value.as_capability.id, second->value.as_capability.id);
|
|
break;
|
|
default:
|
|
EXPECT(false);
|
|
}
|
|
}
|
|
|
|
static void CheckEncodeDecodeMessage(Dart_CObject* root) {
|
|
// Encode and decode the message.
|
|
ApiMessageWriter writer;
|
|
Message* message =
|
|
writer.WriteCMessage(root, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* new_root = api_reader.ReadMessage();
|
|
delete message;
|
|
|
|
// Check that the two messages are the same.
|
|
CompareDartCObjects(root, new_root);
|
|
}
|
|
|
|
static void ExpectEncodeFail(Dart_CObject* root) {
|
|
ApiMessageWriter writer;
|
|
Message* message =
|
|
writer.WriteCMessage(root, ILLEGAL_PORT, Message::kNormalPriority);
|
|
EXPECT(message == NULL);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeNull) {
|
|
StackZone zone(thread);
|
|
|
|
// Write snapshot with object content.
|
|
const Object& null_object = Object::Handle();
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(null_object, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
EXPECT(Equals(null_object, serialized_object));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kNull, root->type);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeSmi1) {
|
|
StackZone zone(thread);
|
|
|
|
// Write snapshot with object content.
|
|
const Smi& smi = Smi::Handle(Smi::New(124));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(smi, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
EXPECT(Equals(smi, serialized_object));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->type);
|
|
EXPECT_EQ(smi.Value(), root->value.as_int32);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeSmi2) {
|
|
StackZone zone(thread);
|
|
|
|
// Write snapshot with object content.
|
|
const Smi& smi = Smi::Handle(Smi::New(-1));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(smi, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
EXPECT(Equals(smi, serialized_object));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->type);
|
|
EXPECT_EQ(smi.Value(), root->value.as_int32);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
Dart_CObject* SerializeAndDeserializeMint(const Mint& mint) {
|
|
// Write snapshot with object content.
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(mint, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
{
|
|
// Switch to a regular zone, where VM handle allocation is allowed.
|
|
Thread* thread = Thread::Current();
|
|
StackZone zone(thread);
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
EXPECT(serialized_object.IsMint());
|
|
}
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
return root;
|
|
}
|
|
|
|
void CheckMint(int64_t value) {
|
|
ApiNativeScope scope;
|
|
StackZone zone(Thread::Current());
|
|
|
|
Mint& mint = Mint::Handle();
|
|
mint ^= Integer::New(value);
|
|
Dart_CObject* mint_cobject = SerializeAndDeserializeMint(mint);
|
|
// On 64-bit platforms mints always require 64-bits as the smi range
|
|
// here covers most of the 64-bit range. On 32-bit platforms the smi
|
|
// range covers most of the 32-bit range and values outside that
|
|
// range are also represented as mints.
|
|
#if defined(ARCH_IS_64_BIT)
|
|
EXPECT_EQ(Dart_CObject_kInt64, mint_cobject->type);
|
|
EXPECT_EQ(value, mint_cobject->value.as_int64);
|
|
#else
|
|
if (kMinInt32 < value && value < kMaxInt32) {
|
|
EXPECT_EQ(Dart_CObject_kInt32, mint_cobject->type);
|
|
EXPECT_EQ(value, mint_cobject->value.as_int32);
|
|
} else {
|
|
EXPECT_EQ(Dart_CObject_kInt64, mint_cobject->type);
|
|
EXPECT_EQ(value, mint_cobject->value.as_int64);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeMints) {
|
|
// Min positive mint.
|
|
CheckMint(Smi::kMaxValue + 1);
|
|
// Min positive mint + 1.
|
|
CheckMint(Smi::kMaxValue + 2);
|
|
// Max negative mint.
|
|
CheckMint(Smi::kMinValue - 1);
|
|
// Max negative mint - 1.
|
|
CheckMint(Smi::kMinValue - 2);
|
|
// Max positive mint.
|
|
CheckMint(kMaxInt64);
|
|
// Max positive mint - 1.
|
|
CheckMint(kMaxInt64 - 1);
|
|
// Min negative mint.
|
|
CheckMint(kMinInt64);
|
|
// Min negative mint + 1.
|
|
CheckMint(kMinInt64 + 1);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeDouble) {
|
|
StackZone zone(thread);
|
|
|
|
// Write snapshot with object content.
|
|
const Double& dbl = Double::Handle(Double::New(101.29));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(dbl, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
EXPECT(Equals(dbl, serialized_object));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kDouble, root->type);
|
|
EXPECT_EQ(dbl.value(), root->value.as_double);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeTrue) {
|
|
StackZone zone(thread);
|
|
|
|
// Write snapshot with true object.
|
|
const Bool& bl = Bool::True();
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(bl, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
fprintf(stderr, "%s / %s\n", bl.ToCString(), serialized_object.ToCString());
|
|
|
|
EXPECT(Equals(bl, serialized_object));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kBool, root->type);
|
|
EXPECT_EQ(true, root->value.as_bool);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeFalse) {
|
|
StackZone zone(thread);
|
|
|
|
// Write snapshot with false object.
|
|
const Bool& bl = Bool::False();
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(bl, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
const Object& serialized_object = Object::Handle(reader.ReadObject());
|
|
EXPECT(Equals(bl, serialized_object));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kBool, root->type);
|
|
EXPECT_EQ(false, root->value.as_bool);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeCapability) {
|
|
// Write snapshot with object content.
|
|
const Capability& capability = Capability::Handle(Capability::New(12345));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(capability, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
Capability& obj = Capability::Handle();
|
|
obj ^= reader.ReadObject();
|
|
|
|
EXPECT_STREQ(12345, obj.Id());
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kCapability, root->type);
|
|
int64_t id = root->value.as_capability.id;
|
|
EXPECT_EQ(12345, id);
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
|
|
#define TEST_ROUND_TRIP_IDENTICAL(object) \
|
|
{ \
|
|
MessageWriter writer(true); \
|
|
Message* message = writer.WriteMessage( \
|
|
Object::Handle(object), ILLEGAL_PORT, Message::kNormalPriority); \
|
|
MessageSnapshotReader reader(message, thread); \
|
|
EXPECT(reader.ReadObject() == object); \
|
|
delete message; \
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeSingletons) {
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::class_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::type_arguments_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::function_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::field_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::script_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::library_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::code_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::bytecode_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::instructions_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::pc_descriptors_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::exception_handlers_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::context_class());
|
|
TEST_ROUND_TRIP_IDENTICAL(Object::context_scope_class());
|
|
}
|
|
|
|
static void TestString(const char* cstr) {
|
|
Thread* thread = Thread::Current();
|
|
EXPECT(Utf8::IsValid(reinterpret_cast<const uint8_t*>(cstr), strlen(cstr)));
|
|
// Write snapshot with object content.
|
|
String& str = String::Handle(String::New(cstr));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(str, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
String& serialized_str = String::Handle();
|
|
serialized_str ^= reader.ReadObject();
|
|
EXPECT(str.Equals(serialized_str));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_EQ(Dart_CObject_kString, root->type);
|
|
EXPECT_STREQ(cstr, root->value.as_string);
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeString) {
|
|
TestString("This string shall be serialized");
|
|
TestString("æøå"); // This file is UTF-8 encoded.
|
|
const char* data =
|
|
"\x01"
|
|
"\x7F"
|
|
"\xC2\x80" // U+0080
|
|
"\xDF\xBF" // U+07FF
|
|
"\xE0\xA0\x80" // U+0800
|
|
"\xEF\xBF\xBF"; // U+FFFF
|
|
|
|
TestString(data);
|
|
// TODO(sgjesse): Add tests with non-BMP characters.
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeArray) {
|
|
// Write snapshot with object content.
|
|
const int kArrayLength = 10;
|
|
Array& array = Array::Handle(Array::New(kArrayLength));
|
|
Smi& smi = Smi::Handle();
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
smi ^= Smi::New(i);
|
|
array.SetAt(i, smi);
|
|
}
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
Array& serialized_array = Array::Handle();
|
|
serialized_array ^= reader.ReadObject();
|
|
EXPECT(array.CanonicalizeEquals(serialized_array));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kInt32, element->type);
|
|
EXPECT_EQ(i, element->value.as_int32);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeArrayWithTypeArgument) {
|
|
// Write snapshot with object content.
|
|
const int kArrayLength = 10;
|
|
Array& array =
|
|
Array::Handle(Array::New(kArrayLength, Type::Handle(Type::ObjectType())));
|
|
|
|
Smi& smi = Smi::Handle();
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
smi ^= Smi::New(i);
|
|
array.SetAt(i, smi);
|
|
}
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
Array& serialized_array = Array::Handle();
|
|
serialized_array ^= reader.ReadObject();
|
|
EXPECT(array.CanonicalizeEquals(serialized_array));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kInt32, element->type);
|
|
EXPECT_EQ(i, element->value.as_int32);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
TEST_CASE(FailSerializeLargeArray) {
|
|
Dart_CObject root;
|
|
root.type = Dart_CObject_kArray;
|
|
root.value.as_array.length = Array::kMaxElements + 1;
|
|
root.value.as_array.values = NULL;
|
|
ExpectEncodeFail(&root);
|
|
}
|
|
|
|
TEST_CASE(FailSerializeLargeNestedArray) {
|
|
Dart_CObject parent;
|
|
Dart_CObject child;
|
|
Dart_CObject* values[1] = {&child};
|
|
|
|
parent.type = Dart_CObject_kArray;
|
|
parent.value.as_array.length = 1;
|
|
parent.value.as_array.values = values;
|
|
child.type = Dart_CObject_kArray;
|
|
child.value.as_array.length = Array::kMaxElements + 1;
|
|
ExpectEncodeFail(&parent);
|
|
}
|
|
|
|
TEST_CASE(FailSerializeLargeTypedDataInt8) {
|
|
Dart_CObject root;
|
|
root.type = Dart_CObject_kTypedData;
|
|
root.value.as_typed_data.type = Dart_TypedData_kInt8;
|
|
root.value.as_typed_data.length =
|
|
TypedData::MaxElements(kTypedDataInt8ArrayCid) + 1;
|
|
ExpectEncodeFail(&root);
|
|
}
|
|
|
|
TEST_CASE(FailSerializeLargeTypedDataUint8) {
|
|
Dart_CObject root;
|
|
root.type = Dart_CObject_kTypedData;
|
|
root.value.as_typed_data.type = Dart_TypedData_kUint8;
|
|
root.value.as_typed_data.length =
|
|
TypedData::MaxElements(kTypedDataUint8ArrayCid) + 1;
|
|
ExpectEncodeFail(&root);
|
|
}
|
|
|
|
TEST_CASE(FailSerializeLargeExternalTypedData) {
|
|
Dart_CObject root;
|
|
root.type = Dart_CObject_kExternalTypedData;
|
|
root.value.as_typed_data.length =
|
|
ExternalTypedData::MaxElements(kExternalTypedDataUint8ArrayCid) + 1;
|
|
ExpectEncodeFail(&root);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeEmptyArray) {
|
|
// Write snapshot with object content.
|
|
const int kArrayLength = 0;
|
|
Array& array = Array::Handle(Array::New(kArrayLength));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
Array& serialized_array = Array::Handle();
|
|
serialized_array ^= reader.ReadObject();
|
|
EXPECT(array.CanonicalizeEquals(serialized_array));
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
EXPECT(root->value.as_array.values == NULL);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeByteArray) {
|
|
// Write snapshot with object content.
|
|
const int kTypedDataLength = 256;
|
|
TypedData& typed_data = TypedData::Handle(
|
|
TypedData::New(kTypedDataUint8ArrayCid, kTypedDataLength));
|
|
for (int i = 0; i < kTypedDataLength; i++) {
|
|
typed_data.SetUint8(i, i);
|
|
}
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(typed_data, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
TypedData& serialized_typed_data = TypedData::Handle();
|
|
serialized_typed_data ^= reader.ReadObject();
|
|
EXPECT(serialized_typed_data.IsTypedData());
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_EQ(Dart_CObject_kTypedData, root->type);
|
|
EXPECT_EQ(kTypedDataLength, root->value.as_typed_data.length);
|
|
for (int i = 0; i < kTypedDataLength; i++) {
|
|
EXPECT(root->value.as_typed_data.values[i] == i);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
#define TEST_TYPED_ARRAY(darttype, ctype) \
|
|
{ \
|
|
StackZone zone(thread); \
|
|
const int kArrayLength = 127; \
|
|
TypedData& array = TypedData::Handle( \
|
|
TypedData::New(kTypedData##darttype##ArrayCid, kArrayLength)); \
|
|
intptr_t scale = array.ElementSizeInBytes(); \
|
|
for (int i = 0; i < kArrayLength; i++) { \
|
|
array.Set##darttype((i * scale), i); \
|
|
} \
|
|
MessageWriter writer(true); \
|
|
Message* message = \
|
|
writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority); \
|
|
MessageSnapshotReader reader(message, thread); \
|
|
TypedData& serialized_array = TypedData::Handle(); \
|
|
serialized_array ^= reader.ReadObject(); \
|
|
for (int i = 0; i < kArrayLength; i++) { \
|
|
EXPECT_EQ(static_cast<ctype>(i), \
|
|
serialized_array.Get##darttype(i* scale)); \
|
|
} \
|
|
delete message; \
|
|
}
|
|
|
|
#define TEST_EXTERNAL_TYPED_ARRAY(darttype, ctype) \
|
|
{ \
|
|
StackZone zone(thread); \
|
|
ctype data[] = {0, 11, 22, 33, 44, 55, 66, 77}; \
|
|
intptr_t length = ARRAY_SIZE(data); \
|
|
ExternalTypedData& array = ExternalTypedData::Handle( \
|
|
ExternalTypedData::New(kExternalTypedData##darttype##ArrayCid, \
|
|
reinterpret_cast<uint8_t*>(data), length)); \
|
|
intptr_t scale = array.ElementSizeInBytes(); \
|
|
MessageWriter writer(true); \
|
|
Message* message = \
|
|
writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority); \
|
|
MessageSnapshotReader reader(message, thread); \
|
|
ExternalTypedData& serialized_array = ExternalTypedData::Handle(); \
|
|
serialized_array ^= reader.ReadObject(); \
|
|
for (int i = 0; i < length; i++) { \
|
|
EXPECT_EQ(static_cast<ctype>(data[i]), \
|
|
serialized_array.Get##darttype(i* scale)); \
|
|
} \
|
|
delete message; \
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeTypedArray) {
|
|
TEST_TYPED_ARRAY(Int8, int8_t);
|
|
TEST_TYPED_ARRAY(Uint8, uint8_t);
|
|
TEST_TYPED_ARRAY(Int16, int16_t);
|
|
TEST_TYPED_ARRAY(Uint16, uint16_t);
|
|
TEST_TYPED_ARRAY(Int32, int32_t);
|
|
TEST_TYPED_ARRAY(Uint32, uint32_t);
|
|
TEST_TYPED_ARRAY(Int64, int64_t);
|
|
TEST_TYPED_ARRAY(Uint64, uint64_t);
|
|
TEST_TYPED_ARRAY(Float32, float);
|
|
TEST_TYPED_ARRAY(Float64, double);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeExternalTypedArray) {
|
|
TEST_EXTERNAL_TYPED_ARRAY(Int8, int8_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Uint8, uint8_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Int16, int16_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Uint16, uint16_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Int32, int32_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Uint32, uint32_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Int64, int64_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Uint64, uint64_t);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Float32, float);
|
|
TEST_EXTERNAL_TYPED_ARRAY(Float64, double);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SerializeEmptyByteArray) {
|
|
// Write snapshot with object content.
|
|
const int kTypedDataLength = 0;
|
|
TypedData& typed_data = TypedData::Handle(
|
|
TypedData::New(kTypedDataUint8ArrayCid, kTypedDataLength));
|
|
MessageWriter writer(true);
|
|
Message* message =
|
|
writer.WriteMessage(typed_data, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot.
|
|
MessageSnapshotReader reader(message, thread);
|
|
TypedData& serialized_typed_data = TypedData::Handle();
|
|
serialized_typed_data ^= reader.ReadObject();
|
|
EXPECT(serialized_typed_data.IsTypedData());
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_EQ(Dart_CObject_kTypedData, root->type);
|
|
EXPECT_EQ(Dart_TypedData_kUint8, root->value.as_typed_data.type);
|
|
EXPECT_EQ(kTypedDataLength, root->value.as_typed_data.length);
|
|
EXPECT(root->value.as_typed_data.values == NULL);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(FullSnapshot) {
|
|
const char* kScriptChars =
|
|
"class Fields {\n"
|
|
" Fields(int i, int j) : fld1 = i, fld2 = j {}\n"
|
|
" int fld1;\n"
|
|
" final int fld2;\n"
|
|
" final int bigint_fld = 0xfffffffffff;\n"
|
|
" static int fld3;\n"
|
|
" static const int smi_sfld = 10;\n"
|
|
" static const int bigint_sfld = 0xfffffffffff;\n"
|
|
"}\n"
|
|
"class Expect {\n"
|
|
" static void equals(x, y) {\n"
|
|
" if (x != y) throw new ArgumentError('not equal');\n"
|
|
" }\n"
|
|
"}\n"
|
|
"class FieldsTest {\n"
|
|
" static Fields testMain() {\n"
|
|
" Expect.equals(true, Fields.bigint_sfld == 0xfffffffffff);\n"
|
|
" Fields obj = new Fields(10, 20);\n"
|
|
" Expect.equals(true, obj.bigint_fld == 0xfffffffffff);\n"
|
|
" return obj;\n"
|
|
" }\n"
|
|
"}\n";
|
|
Dart_Handle result;
|
|
|
|
uint8_t* isolate_snapshot_data_buffer;
|
|
|
|
// Start an Isolate, load a script and create a full snapshot.
|
|
Timer timer1(true, "Snapshot_test");
|
|
timer1.Start();
|
|
{
|
|
TestIsolateScope __test_isolate__;
|
|
|
|
// Create a test library and Load up a test script in it.
|
|
TestCase::LoadTestScript(kScriptChars, NULL);
|
|
|
|
Thread* thread = Thread::Current();
|
|
TransitionNativeToVM transition(thread);
|
|
StackZone zone(thread);
|
|
HandleScope scope(thread);
|
|
|
|
Dart_Handle result = Api::CheckAndFinalizePendingClasses(thread);
|
|
{
|
|
TransitionVMToNative to_native(thread);
|
|
EXPECT_VALID(result);
|
|
}
|
|
timer1.Stop();
|
|
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
|
|
|
|
// Write snapshot with object content.
|
|
FullSnapshotWriter writer(Snapshot::kFull, NULL,
|
|
&isolate_snapshot_data_buffer, &malloc_allocator,
|
|
NULL, /*image_writer*/ nullptr);
|
|
writer.WriteFullSnapshot();
|
|
}
|
|
|
|
// Now Create another isolate using the snapshot and execute a method
|
|
// from the script.
|
|
Timer timer2(true, "Snapshot_test");
|
|
timer2.Start();
|
|
TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
|
|
{
|
|
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
|
|
timer2.Stop();
|
|
OS::PrintErr("From Snapshot: %" Pd64 "us\n", timer2.TotalElapsedTime());
|
|
|
|
// Invoke a function which returns an object.
|
|
Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("FieldsTest"));
|
|
result = Dart_Invoke(cls, NewString("testMain"), 0, NULL);
|
|
EXPECT_VALID(result);
|
|
Dart_ExitScope();
|
|
}
|
|
Dart_ShutdownIsolate();
|
|
free(isolate_snapshot_data_buffer);
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(FullSnapshot1) {
|
|
// This buffer has to be static for this to compile with Visual Studio.
|
|
// If it is not static compilation of this file with Visual Studio takes
|
|
// more than 30 minutes!
|
|
static const char kFullSnapshotScriptChars[] = {
|
|
#include "snapshot_test.dat"
|
|
};
|
|
const char* kScriptChars = kFullSnapshotScriptChars;
|
|
|
|
uint8_t* isolate_snapshot_data_buffer;
|
|
|
|
// Start an Isolate, load a script and create a full snapshot.
|
|
Timer timer1(true, "Snapshot_test");
|
|
timer1.Start();
|
|
{
|
|
TestIsolateScope __test_isolate__;
|
|
|
|
Thread* thread = Thread::Current();
|
|
StackZone zone(thread);
|
|
HandleScope scope(thread);
|
|
|
|
// Create a test library and Load up a test script in it.
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread));
|
|
timer1.Stop();
|
|
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
|
|
|
|
// Write snapshot with object content.
|
|
{
|
|
TransitionNativeToVM transition(thread);
|
|
FullSnapshotWriter writer(
|
|
Snapshot::kFull, NULL, &isolate_snapshot_data_buffer,
|
|
&malloc_allocator, NULL, /*image_writer*/ nullptr);
|
|
writer.WriteFullSnapshot();
|
|
}
|
|
|
|
// Invoke a function which returns an object.
|
|
Dart_Handle cls = Dart_GetClass(lib, NewString("FieldsTest"));
|
|
Dart_Handle result = Dart_Invoke(cls, NewString("testMain"), 0, NULL);
|
|
EXPECT_VALID(result);
|
|
}
|
|
|
|
// Now Create another isolate using the snapshot and execute a method
|
|
// from the script.
|
|
Timer timer2(true, "Snapshot_test");
|
|
timer2.Start();
|
|
TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
|
|
{
|
|
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
|
|
timer2.Stop();
|
|
OS::PrintErr("From Snapshot: %" Pd64 "us\n", timer2.TotalElapsedTime());
|
|
|
|
// Invoke a function which returns an object.
|
|
Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("FieldsTest"));
|
|
Dart_Handle result = Dart_Invoke(cls, NewString("testMain"), 0, NULL);
|
|
if (Dart_IsError(result)) {
|
|
// Print the error. It is probably an unhandled exception.
|
|
fprintf(stderr, "%s\n", Dart_GetError(result));
|
|
}
|
|
EXPECT_VALID(result);
|
|
Dart_ExitScope();
|
|
}
|
|
Dart_ShutdownIsolate();
|
|
free(isolate_snapshot_data_buffer);
|
|
}
|
|
|
|
// Helper function to call a top level Dart function and serialize the result.
|
|
static Message* GetSerialized(Dart_Handle lib, const char* dart_function) {
|
|
Dart_Handle result;
|
|
{
|
|
TransitionVMToNative transition(Thread::Current());
|
|
result = Dart_Invoke(lib, NewString(dart_function), 0, NULL);
|
|
EXPECT_VALID(result);
|
|
}
|
|
Object& obj = Object::Handle(Api::UnwrapHandle(result));
|
|
|
|
// Serialize the object into a message.
|
|
MessageWriter writer(false);
|
|
return writer.WriteMessage(obj, ILLEGAL_PORT, Message::kNormalPriority);
|
|
}
|
|
|
|
// Helper function to deserialize the result into a Dart_CObject structure.
|
|
static Dart_CObject* GetDeserialized(Message* message) {
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiMessageReader api_reader(message);
|
|
return api_reader.ReadMessage();
|
|
}
|
|
|
|
static void CheckString(Dart_Handle dart_string, const char* expected) {
|
|
StackZone zone(Thread::Current());
|
|
String& str = String::Handle();
|
|
str ^= Api::UnwrapHandle(dart_string);
|
|
MessageWriter writer(false);
|
|
Message* message =
|
|
writer.WriteMessage(str, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kString, root->type);
|
|
EXPECT_STREQ(expected, root->value.as_string);
|
|
CheckEncodeDecodeMessage(root);
|
|
|
|
delete message;
|
|
}
|
|
|
|
static void CheckStringInvalid(Dart_Handle dart_string) {
|
|
StackZone zone(Thread::Current());
|
|
String& str = String::Handle();
|
|
str ^= Api::UnwrapHandle(dart_string);
|
|
MessageWriter writer(false);
|
|
Message* message =
|
|
writer.WriteMessage(str, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kUnsupported, root->type);
|
|
|
|
delete message;
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(DartGeneratedMessages) {
|
|
static const char* kCustomIsolateScriptChars =
|
|
"final int kArrayLength = 10;\n"
|
|
"getSmi() {\n"
|
|
" return 42;\n"
|
|
"}\n"
|
|
"getAsciiString() {\n"
|
|
" return \"Hello, world!\";\n"
|
|
"}\n"
|
|
"getNonAsciiString() {\n"
|
|
" return \"Blåbærgrød\";\n"
|
|
"}\n"
|
|
"getNonBMPString() {\n"
|
|
" return \"\\u{10000}\\u{1F601}\\u{1F637}\\u{20000}\";\n"
|
|
"}\n"
|
|
"getLeadSurrogateString() {\n"
|
|
" return new String.fromCharCodes([0xd800]);\n"
|
|
"}\n"
|
|
"getTrailSurrogateString() {\n"
|
|
" return \"\\u{10000}\".substring(1);\n"
|
|
"}\n"
|
|
"getSurrogatesString() {\n"
|
|
" return new String.fromCharCodes([0xdc00, 0xdc00, 0xd800, 0xd800]);\n"
|
|
"}\n"
|
|
"getCrappyString() {\n"
|
|
" return new String.fromCharCodes([0xd800, 32, 0xdc00, 32]);\n"
|
|
"}\n"
|
|
"getList() {\n"
|
|
" return new List(kArrayLength);\n"
|
|
"}\n";
|
|
|
|
TestCase::CreateTestIsolate();
|
|
Isolate* isolate = Isolate::Current();
|
|
EXPECT(isolate != NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
Dart_Handle smi_result;
|
|
smi_result = Dart_Invoke(lib, NewString("getSmi"), 0, NULL);
|
|
EXPECT_VALID(smi_result);
|
|
|
|
Dart_Handle ascii_string_result;
|
|
ascii_string_result = Dart_Invoke(lib, NewString("getAsciiString"), 0, NULL);
|
|
EXPECT_VALID(ascii_string_result);
|
|
EXPECT(Dart_IsString(ascii_string_result));
|
|
|
|
Dart_Handle non_ascii_string_result;
|
|
non_ascii_string_result =
|
|
Dart_Invoke(lib, NewString("getNonAsciiString"), 0, NULL);
|
|
EXPECT_VALID(non_ascii_string_result);
|
|
EXPECT(Dart_IsString(non_ascii_string_result));
|
|
|
|
Dart_Handle non_bmp_string_result;
|
|
non_bmp_string_result =
|
|
Dart_Invoke(lib, NewString("getNonBMPString"), 0, NULL);
|
|
EXPECT_VALID(non_bmp_string_result);
|
|
EXPECT(Dart_IsString(non_bmp_string_result));
|
|
|
|
Dart_Handle lead_surrogate_string_result;
|
|
lead_surrogate_string_result =
|
|
Dart_Invoke(lib, NewString("getLeadSurrogateString"), 0, NULL);
|
|
EXPECT_VALID(lead_surrogate_string_result);
|
|
EXPECT(Dart_IsString(lead_surrogate_string_result));
|
|
|
|
Dart_Handle trail_surrogate_string_result;
|
|
trail_surrogate_string_result =
|
|
Dart_Invoke(lib, NewString("getTrailSurrogateString"), 0, NULL);
|
|
EXPECT_VALID(trail_surrogate_string_result);
|
|
EXPECT(Dart_IsString(trail_surrogate_string_result));
|
|
|
|
Dart_Handle surrogates_string_result;
|
|
surrogates_string_result =
|
|
Dart_Invoke(lib, NewString("getSurrogatesString"), 0, NULL);
|
|
EXPECT_VALID(surrogates_string_result);
|
|
EXPECT(Dart_IsString(surrogates_string_result));
|
|
|
|
Dart_Handle crappy_string_result;
|
|
crappy_string_result =
|
|
Dart_Invoke(lib, NewString("getCrappyString"), 0, NULL);
|
|
EXPECT_VALID(crappy_string_result);
|
|
EXPECT(Dart_IsString(crappy_string_result));
|
|
|
|
{
|
|
Thread* thread = Thread::Current();
|
|
CHECK_API_SCOPE(thread);
|
|
TransitionNativeToVM transition(thread);
|
|
HANDLESCOPE(thread);
|
|
|
|
{
|
|
StackZone zone(thread);
|
|
Smi& smi = Smi::Handle();
|
|
smi ^= Api::UnwrapHandle(smi_result);
|
|
MessageWriter writer(false);
|
|
Message* message =
|
|
writer.WriteMessage(smi, ILLEGAL_PORT, Message::kNormalPriority);
|
|
|
|
// Read object back from the snapshot into a C structure.
|
|
ApiNativeScope scope;
|
|
ApiMessageReader api_reader(message);
|
|
Dart_CObject* root = api_reader.ReadMessage();
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->type);
|
|
EXPECT_EQ(42, root->value.as_int32);
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
CheckString(ascii_string_result, "Hello, world!");
|
|
CheckString(non_ascii_string_result, "Blåbærgrød");
|
|
CheckString(non_bmp_string_result,
|
|
"\xf0\x90\x80\x80"
|
|
"\xf0\x9f\x98\x81"
|
|
"\xf0\x9f\x98\xb7"
|
|
"\xf0\xa0\x80\x80");
|
|
CheckStringInvalid(lead_surrogate_string_result);
|
|
CheckStringInvalid(trail_surrogate_string_result);
|
|
CheckStringInvalid(crappy_string_result);
|
|
CheckStringInvalid(surrogates_string_result);
|
|
}
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(DartGeneratedListMessages) {
|
|
const int kArrayLength = 10;
|
|
static const char* kScriptChars =
|
|
"final int kArrayLength = 10;\n"
|
|
"getList() {\n"
|
|
" return new List(kArrayLength);\n"
|
|
"}\n"
|
|
"getIntList() {\n"
|
|
" var list = new List<int>(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = i;\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getStringList() {\n"
|
|
" var list = new List<String>(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = i.toString();\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getMixedList() {\n"
|
|
" var list = new List(kArrayLength);\n"
|
|
" list[0] = 0;\n"
|
|
" list[1] = '1';\n"
|
|
" list[2] = 2.2;\n"
|
|
" list[3] = true;\n"
|
|
" return list;\n"
|
|
"}\n";
|
|
|
|
TestCase::CreateTestIsolate();
|
|
Thread* thread = Thread::Current();
|
|
EXPECT(thread->isolate() != NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
|
|
{
|
|
CHECK_API_SCOPE(thread);
|
|
TransitionNativeToVM transition(thread);
|
|
HANDLESCOPE(thread);
|
|
StackZone zone(thread);
|
|
{
|
|
// Generate a list of nulls from Dart code.
|
|
Message* message = GetSerialized(lib, "getList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
EXPECT_EQ(Dart_CObject_kNull, root->value.as_array.values[i]->type);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of ints from Dart code.
|
|
Message* message = GetSerialized(lib, "getIntList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[i]->type);
|
|
EXPECT_EQ(i, root->value.as_array.values[i]->value.as_int32);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of strings from Dart code.
|
|
Message* message = GetSerialized(lib, "getStringList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[i]->type);
|
|
char buffer[3];
|
|
snprintf(buffer, sizeof(buffer), "%d", i);
|
|
EXPECT_STREQ(buffer, root->value.as_array.values[i]->value.as_string);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of objects of different types from Dart code.
|
|
Message* message = GetSerialized(lib, "getMixedList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[0]->type);
|
|
EXPECT_EQ(0, root->value.as_array.values[0]->value.as_int32);
|
|
EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[1]->type);
|
|
EXPECT_STREQ("1", root->value.as_array.values[1]->value.as_string);
|
|
EXPECT_EQ(Dart_CObject_kDouble, root->value.as_array.values[2]->type);
|
|
EXPECT_EQ(2.2, root->value.as_array.values[2]->value.as_double);
|
|
EXPECT_EQ(Dart_CObject_kBool, root->value.as_array.values[3]->type);
|
|
EXPECT_EQ(true, root->value.as_array.values[3]->value.as_bool);
|
|
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
if (i > 3) {
|
|
EXPECT_EQ(Dart_CObject_kNull, root->value.as_array.values[i]->type);
|
|
}
|
|
}
|
|
delete message;
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessages) {
|
|
const int kArrayLength = 10;
|
|
static const char* kScriptChars =
|
|
"final int kArrayLength = 10;\n"
|
|
"getList() {\n"
|
|
" return [null, null, null, null, null, null, null, null, null, null];\n"
|
|
"}\n"
|
|
"getIntList() {\n"
|
|
" return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n"
|
|
"}\n"
|
|
"getStringList() {\n"
|
|
" return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];\n"
|
|
"}\n"
|
|
"getListList() {\n"
|
|
" return [[],"
|
|
" [0],"
|
|
" [0, 1],"
|
|
" [0, 1, 2],"
|
|
" [0, 1, 2, 3],"
|
|
" [0, 1, 2, 3, 4],"
|
|
" [0, 1, 2, 3, 4, 5],"
|
|
" [0, 1, 2, 3, 4, 5, 6],"
|
|
" [0, 1, 2, 3, 4, 5, 6, 7],"
|
|
" [0, 1, 2, 3, 4, 5, 6, 7, 8]];\n"
|
|
"}\n"
|
|
"getMixedList() {\n"
|
|
" var list = [];\n"
|
|
" list.add(0);\n"
|
|
" list.add('1');\n"
|
|
" list.add(2.2);\n"
|
|
" list.add(true);\n"
|
|
" list.add([]);\n"
|
|
" list.add([[]]);\n"
|
|
" list.add([[[]]]);\n"
|
|
" list.add([1, [2, [3]]]);\n"
|
|
" list.add([1, [1, 2, [1, 2, 3]]]);\n"
|
|
" list.add([1, 2, 3]);\n"
|
|
" return list;\n"
|
|
"}\n";
|
|
|
|
TestCase::CreateTestIsolate();
|
|
Thread* thread = Thread::Current();
|
|
EXPECT(thread->isolate() != NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
|
|
{
|
|
CHECK_API_SCOPE(thread);
|
|
TransitionNativeToVM transition(thread);
|
|
HANDLESCOPE(thread);
|
|
StackZone zone(thread);
|
|
{
|
|
// Generate a list of nulls from Dart code.
|
|
Message* message = GetSerialized(lib, "getList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
EXPECT_EQ(Dart_CObject_kNull, root->value.as_array.values[i]->type);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of ints from Dart code.
|
|
Message* message = GetSerialized(lib, "getIntList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[i]->type);
|
|
EXPECT_EQ(i, root->value.as_array.values[i]->value.as_int32);
|
|
}
|
|
CheckEncodeDecodeMessage(root);
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of strings from Dart code.
|
|
Message* message = GetSerialized(lib, "getStringList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[i]->type);
|
|
char buffer[3];
|
|
snprintf(buffer, sizeof(buffer), "%d", i);
|
|
EXPECT_STREQ(buffer, root->value.as_array.values[i]->value.as_string);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of lists from Dart code.
|
|
Message* message = GetSerialized(lib, "getListList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(i, element->value.as_array.length);
|
|
for (int j = 0; j < i; j++) {
|
|
EXPECT_EQ(Dart_CObject_kInt32,
|
|
element->value.as_array.values[j]->type);
|
|
EXPECT_EQ(j, element->value.as_array.values[j]->value.as_int32);
|
|
}
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of objects of different types from Dart code.
|
|
Message* message = GetSerialized(lib, "getMixedList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
|
|
EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[0]->type);
|
|
EXPECT_EQ(0, root->value.as_array.values[0]->value.as_int32);
|
|
EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[1]->type);
|
|
EXPECT_STREQ("1", root->value.as_array.values[1]->value.as_string);
|
|
EXPECT_EQ(Dart_CObject_kDouble, root->value.as_array.values[2]->type);
|
|
EXPECT_EQ(2.2, root->value.as_array.values[2]->value.as_double);
|
|
EXPECT_EQ(Dart_CObject_kBool, root->value.as_array.values[3]->type);
|
|
EXPECT_EQ(true, root->value.as_array.values[3]->value.as_bool);
|
|
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
if (i > 3) {
|
|
EXPECT_EQ(Dart_CObject_kArray, root->value.as_array.values[i]->type);
|
|
}
|
|
}
|
|
|
|
Dart_CObject* element;
|
|
Dart_CObject* e;
|
|
|
|
// []
|
|
element = root->value.as_array.values[4];
|
|
EXPECT_EQ(0, element->value.as_array.length);
|
|
|
|
// [[]]
|
|
element = root->value.as_array.values[5];
|
|
EXPECT_EQ(1, element->value.as_array.length);
|
|
element = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(0, element->value.as_array.length);
|
|
|
|
// [[[]]]"
|
|
element = root->value.as_array.values[6];
|
|
EXPECT_EQ(1, element->value.as_array.length);
|
|
element = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(1, element->value.as_array.length);
|
|
element = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(0, element->value.as_array.length);
|
|
|
|
// [1, [2, [3]]]
|
|
element = root->value.as_array.values[7];
|
|
EXPECT_EQ(2, element->value.as_array.length);
|
|
e = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(1, e->value.as_int32);
|
|
element = element->value.as_array.values[1];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(2, element->value.as_array.length);
|
|
e = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(2, e->value.as_int32);
|
|
element = element->value.as_array.values[1];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(1, element->value.as_array.length);
|
|
e = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(3, e->value.as_int32);
|
|
|
|
// [1, [1, 2, [1, 2, 3]]]
|
|
element = root->value.as_array.values[8];
|
|
EXPECT_EQ(2, element->value.as_array.length);
|
|
e = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
e = element->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(1, e->value.as_int32);
|
|
element = element->value.as_array.values[1];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(3, element->value.as_array.length);
|
|
for (int i = 0; i < 2; i++) {
|
|
e = element->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(i + 1, e->value.as_int32);
|
|
}
|
|
element = element->value.as_array.values[2];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(3, element->value.as_array.length);
|
|
for (int i = 0; i < 3; i++) {
|
|
e = element->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(i + 1, e->value.as_int32);
|
|
}
|
|
|
|
// [1, 2, 3]
|
|
element = root->value.as_array.values[9];
|
|
EXPECT_EQ(3, element->value.as_array.length);
|
|
for (int i = 0; i < 3; i++) {
|
|
e = element->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kInt32, e->type);
|
|
EXPECT_EQ(i + 1, e->value.as_int32);
|
|
}
|
|
delete message;
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) {
|
|
const int kArrayLength = 10;
|
|
static const char* kScriptChars =
|
|
"import 'dart:typed_data';\n"
|
|
"final int kArrayLength = 10;\n"
|
|
"getStringList() {\n"
|
|
" var s = 'Hello, world!';\n"
|
|
" var list = new List<String>(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = s;\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getMintList() {\n"
|
|
" var mint = 0x7FFFFFFFFFFFFFFF;\n"
|
|
" var list = new List(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = mint;\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getDoubleList() {\n"
|
|
" var d = 3.14;\n"
|
|
" var list = new List<double>(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = d;\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getTypedDataList() {\n"
|
|
" var byte_array = new Uint8List(256);\n"
|
|
" var list = new List(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = byte_array;\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getTypedDataViewList() {\n"
|
|
" var uint8_list = new Uint8List(256);\n"
|
|
" uint8_list[64] = 1;\n"
|
|
" var uint8_list_view =\n"
|
|
" new Uint8List.view(uint8_list.buffer, 64, 128);\n"
|
|
" var list = new List(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) list[i] = uint8_list_view;\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getMixedList() {\n"
|
|
" var list = new List(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) {\n"
|
|
" list[i] = ((i % 2) == 0) ? 'A' : 2.72;\n"
|
|
" }\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getSelfRefList() {\n"
|
|
" var list = new List(kArrayLength);\n"
|
|
" for (var i = 0; i < kArrayLength; i++) {\n"
|
|
" list[i] = list;\n"
|
|
" }\n"
|
|
" return list;\n"
|
|
"}\n";
|
|
|
|
TestCase::CreateTestIsolate();
|
|
Thread* thread = Thread::Current();
|
|
EXPECT(thread->isolate() != NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
|
|
{
|
|
CHECK_API_SCOPE(thread);
|
|
TransitionNativeToVM transition(thread);
|
|
HANDLESCOPE(thread);
|
|
StackZone zone(thread);
|
|
{
|
|
// Generate a list of strings from Dart code.
|
|
Message* message = GetSerialized(lib, "getStringList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kString, element->type);
|
|
EXPECT_STREQ("Hello, world!", element->value.as_string);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of medium ints from Dart code.
|
|
Message* message = GetSerialized(lib, "getMintList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kInt64, element->type);
|
|
EXPECT_EQ(DART_INT64_C(0x7FFFFFFFFFFFFFFF), element->value.as_int64);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of doubles from Dart code.
|
|
Message* message = GetSerialized(lib, "getDoubleList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
Dart_CObject* element = root->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_EQ(3.14, element->value.as_double);
|
|
for (int i = 1; i < kArrayLength; i++) {
|
|
element = root->value.as_array.values[i];
|
|
// Double values are expected to not be canonicalized in messages.
|
|
EXPECT_NE(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_EQ(3.14, element->value.as_double);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of Uint8Lists from Dart code.
|
|
Message* message = GetSerialized(lib, "getTypedDataList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kTypedData, element->type);
|
|
EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
|
|
EXPECT_EQ(256, element->value.as_typed_data.length);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of Uint8List views from Dart code.
|
|
Message* message = GetSerialized(lib, "getTypedDataViewList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kTypedData, element->type);
|
|
EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
|
|
EXPECT_EQ(128, element->value.as_typed_data.length);
|
|
EXPECT_EQ(1, element->value.as_typed_data.values[0]);
|
|
EXPECT_EQ(0, element->value.as_typed_data.values[1]);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of objects of different types from Dart code.
|
|
Message* message = GetSerialized(lib, "getMixedList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
Dart_CObject* element = root->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kString, element->type);
|
|
EXPECT_STREQ("A", element->value.as_string);
|
|
element = root->value.as_array.values[1];
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_STREQ(2.72, element->value.as_double);
|
|
for (int i = 2; i < kArrayLength; i++) {
|
|
element = root->value.as_array.values[i];
|
|
if ((i % 2) == 0) {
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kString, element->type);
|
|
EXPECT_STREQ("A", element->value.as_string);
|
|
} else {
|
|
// Double values are expected to not be canonicalized in messages.
|
|
EXPECT_NE(root->value.as_array.values[1], element);
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_STREQ(2.72, element->value.as_double);
|
|
}
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of objects of different types from Dart code.
|
|
Message* message = GetSerialized(lib, "getSelfRefList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(root, element);
|
|
}
|
|
delete message;
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) {
|
|
const int kArrayLength = 10;
|
|
static const char* kScriptChars =
|
|
"import 'dart:typed_data';\n"
|
|
"final int kArrayLength = 10;\n"
|
|
"getStringList() {\n"
|
|
" var s = 'Hello, world!';\n"
|
|
" var list = [s, s, s, s, s, s, s, s, s, s];\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getMintList() {\n"
|
|
" var mint = 0x7FFFFFFFFFFFFFFF;\n"
|
|
" var list = [mint, mint, mint, mint, mint,\n"
|
|
" mint, mint, mint, mint, mint];\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getDoubleList() {\n"
|
|
" var d = 3.14;\n"
|
|
" var list = [3.14, 3.14, 3.14, 3.14, 3.14, 3.14];\n"
|
|
" list.add(3.14);\n"
|
|
" list.add(3.14);\n"
|
|
" list.add(3.14);\n"
|
|
" list.add(3.14);\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getTypedDataList() {\n"
|
|
" var byte_array = new Uint8List(256);\n"
|
|
" var list = [];\n"
|
|
" for (var i = 0; i < kArrayLength; i++) {\n"
|
|
" list.add(byte_array);\n"
|
|
" }\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getTypedDataViewList() {\n"
|
|
" var uint8_list = new Uint8List(256);\n"
|
|
" uint8_list[64] = 1;\n"
|
|
" var uint8_list_view =\n"
|
|
" new Uint8List.view(uint8_list.buffer, 64, 128);\n"
|
|
" var list = [];\n"
|
|
" for (var i = 0; i < kArrayLength; i++) {\n"
|
|
" list.add(uint8_list_view);\n"
|
|
" }\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getMixedList() {\n"
|
|
" var list = [];\n"
|
|
" for (var i = 0; i < kArrayLength; i++) {\n"
|
|
" list.add(((i % 2) == 0) ? '.' : 2.72);\n"
|
|
" }\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getSelfRefList() {\n"
|
|
" var list = [];\n"
|
|
" for (var i = 0; i < kArrayLength; i++) {\n"
|
|
" list.add(list);\n"
|
|
" }\n"
|
|
" return list;\n"
|
|
"}\n";
|
|
|
|
TestCase::CreateTestIsolate();
|
|
Thread* thread = Thread::Current();
|
|
EXPECT(thread->isolate() != NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
|
|
{
|
|
CHECK_API_SCOPE(thread);
|
|
TransitionNativeToVM transition(thread);
|
|
HANDLESCOPE(thread);
|
|
StackZone zone(thread);
|
|
{
|
|
// Generate a list of strings from Dart code.
|
|
Message* message = GetSerialized(lib, "getStringList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kString, element->type);
|
|
EXPECT_STREQ("Hello, world!", element->value.as_string);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of medium ints from Dart code.
|
|
Message* message = GetSerialized(lib, "getMintList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kInt64, element->type);
|
|
EXPECT_EQ(DART_INT64_C(0x7FFFFFFFFFFFFFFF), element->value.as_int64);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of doubles from Dart code.
|
|
Message* message = GetSerialized(lib, "getDoubleList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
Dart_CObject* element = root->value.as_array.values[0];
|
|
// Double values are expected to not be canonicalized in messages.
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_EQ(3.14, element->value.as_double);
|
|
for (int i = 1; i < kArrayLength; i++) {
|
|
element = root->value.as_array.values[i];
|
|
// Double values are expected to not be canonicalized in messages.
|
|
EXPECT_NE(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_EQ(3.14, element->value.as_double);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of Uint8Lists from Dart code.
|
|
Message* message = GetSerialized(lib, "getTypedDataList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kTypedData, element->type);
|
|
EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
|
|
EXPECT_EQ(256, element->value.as_typed_data.length);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of Uint8List views from Dart code.
|
|
Message* message = GetSerialized(lib, "getTypedDataViewList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kTypedData, element->type);
|
|
EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
|
|
EXPECT_EQ(128, element->value.as_typed_data.length);
|
|
EXPECT_EQ(1, element->value.as_typed_data.values[0]);
|
|
EXPECT_EQ(0, element->value.as_typed_data.values[1]);
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of objects of different types from Dart code.
|
|
Message* message = GetSerialized(lib, "getMixedList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
Dart_CObject* element = root->value.as_array.values[0];
|
|
EXPECT_EQ(Dart_CObject_kString, element->type);
|
|
EXPECT_STREQ(".", element->value.as_string);
|
|
element = root->value.as_array.values[1];
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_STREQ(2.72, element->value.as_double);
|
|
for (int i = 2; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
if ((i % 2) == 0) {
|
|
EXPECT_EQ(root->value.as_array.values[0], element);
|
|
EXPECT_EQ(Dart_CObject_kString, element->type);
|
|
EXPECT_STREQ(".", element->value.as_string);
|
|
} else {
|
|
// Double values are expected to not be canonicalized in messages.
|
|
EXPECT_NE(root->value.as_array.values[1], element);
|
|
EXPECT_EQ(Dart_CObject_kDouble, element->type);
|
|
EXPECT_STREQ(2.72, element->value.as_double);
|
|
}
|
|
}
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of objects of different types from Dart code.
|
|
Message* message = GetSerialized(lib, "getSelfRefList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
EXPECT_EQ(kArrayLength, root->value.as_array.length);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = root->value.as_array.values[i];
|
|
EXPECT_EQ(Dart_CObject_kArray, element->type);
|
|
EXPECT_EQ(root, element);
|
|
}
|
|
delete message;
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
static void CheckTypedData(Dart_CObject* object,
|
|
Dart_TypedData_Type typed_data_type,
|
|
int len) {
|
|
EXPECT_EQ(Dart_CObject_kTypedData, object->type);
|
|
EXPECT_EQ(typed_data_type, object->value.as_typed_data.type);
|
|
EXPECT_EQ(len, object->value.as_typed_data.length);
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithTypedData) {
|
|
static const char* kScriptChars =
|
|
"import 'dart:typed_data';\n"
|
|
"getTypedDataList() {\n"
|
|
" var list = new List(10);\n"
|
|
" var index = 0;\n"
|
|
" list[index++] = new Int8List(256);\n"
|
|
" list[index++] = new Uint8List(256);\n"
|
|
" list[index++] = new Int16List(256);\n"
|
|
" list[index++] = new Uint16List(256);\n"
|
|
" list[index++] = new Int32List(256);\n"
|
|
" list[index++] = new Uint32List(256);\n"
|
|
" list[index++] = new Int64List(256);\n"
|
|
" list[index++] = new Uint64List(256);\n"
|
|
" list[index++] = new Float32List(256);\n"
|
|
" list[index++] = new Float64List(256);\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getTypedDataViewList() {\n"
|
|
" var list = new List(30);\n"
|
|
" var index = 0;\n"
|
|
" list[index++] = new Int8List.view(new Int8List(256).buffer);\n"
|
|
" list[index++] = new Uint8List.view(new Uint8List(256).buffer);\n"
|
|
" list[index++] = new Int16List.view(new Int16List(256).buffer);\n"
|
|
" list[index++] = new Uint16List.view(new Uint16List(256).buffer);\n"
|
|
" list[index++] = new Int32List.view(new Int32List(256).buffer);\n"
|
|
" list[index++] = new Uint32List.view(new Uint32List(256).buffer);\n"
|
|
" list[index++] = new Int64List.view(new Int64List(256).buffer);\n"
|
|
" list[index++] = new Uint64List.view(new Uint64List(256).buffer);\n"
|
|
" list[index++] = new Float32List.view(new Float32List(256).buffer);\n"
|
|
" list[index++] = new Float64List.view(new Float64List(256).buffer);\n"
|
|
|
|
" list[index++] = new Int8List.view(new Int16List(256).buffer);\n"
|
|
" list[index++] = new Uint8List.view(new Uint16List(256).buffer);\n"
|
|
" list[index++] = new Int8List.view(new Int32List(256).buffer);\n"
|
|
" list[index++] = new Uint8List.view(new Uint32List(256).buffer);\n"
|
|
" list[index++] = new Int8List.view(new Int64List(256).buffer);\n"
|
|
" list[index++] = new Uint8List.view(new Uint64List(256).buffer);\n"
|
|
" list[index++] = new Int8List.view(new Float32List(256).buffer);\n"
|
|
" list[index++] = new Uint8List.view(new Float32List(256).buffer);\n"
|
|
" list[index++] = new Int8List.view(new Float64List(256).buffer);\n"
|
|
" list[index++] = new Uint8List.view(new Float64List(256).buffer);\n"
|
|
|
|
" list[index++] = new Int16List.view(new Int8List(256).buffer);\n"
|
|
" list[index++] = new Uint16List.view(new Uint8List(256).buffer);\n"
|
|
" list[index++] = new Int16List.view(new Int32List(256).buffer);\n"
|
|
" list[index++] = new Uint16List.view(new Uint32List(256).buffer);\n"
|
|
" list[index++] = new Int16List.view(new Int64List(256).buffer);\n"
|
|
" list[index++] = new Uint16List.view(new Uint64List(256).buffer);\n"
|
|
" list[index++] = new Int16List.view(new Float32List(256).buffer);\n"
|
|
" list[index++] = new Uint16List.view(new Float32List(256).buffer);\n"
|
|
" list[index++] = new Int16List.view(new Float64List(256).buffer);\n"
|
|
" list[index++] = new Uint16List.view(new Float64List(256).buffer);\n"
|
|
" return list;\n"
|
|
"}\n"
|
|
"getMultipleTypedDataViewList() {\n"
|
|
" var list = new List(10);\n"
|
|
" var index = 0;\n"
|
|
" var data = new Uint8List(256).buffer;\n"
|
|
" list[index++] = new Int8List.view(data);\n"
|
|
" list[index++] = new Uint8List.view(data);\n"
|
|
" list[index++] = new Int16List.view(data);\n"
|
|
" list[index++] = new Uint16List.view(data);\n"
|
|
" list[index++] = new Int32List.view(data);\n"
|
|
" list[index++] = new Uint32List.view(data);\n"
|
|
" list[index++] = new Int64List.view(data);\n"
|
|
" list[index++] = new Uint64List.view(data);\n"
|
|
" list[index++] = new Float32List.view(data);\n"
|
|
" list[index++] = new Float64List.view(data);\n"
|
|
" return list;\n"
|
|
"}\n";
|
|
|
|
TestCase::CreateTestIsolate();
|
|
Thread* thread = Thread::Current();
|
|
EXPECT(thread->isolate() != NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
|
|
{
|
|
CHECK_API_SCOPE(thread);
|
|
TransitionNativeToVM transition(thread);
|
|
HANDLESCOPE(thread);
|
|
StackZone zone(thread);
|
|
{
|
|
// Generate a list of Uint8Lists from Dart code.
|
|
Message* message = GetSerialized(lib, "getTypedDataList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
struct {
|
|
Dart_TypedData_Type type;
|
|
int size;
|
|
} expected[] = {
|
|
{Dart_TypedData_kInt8, 256}, {Dart_TypedData_kUint8, 256},
|
|
{Dart_TypedData_kInt16, 512}, {Dart_TypedData_kUint16, 512},
|
|
{Dart_TypedData_kInt32, 1024}, {Dart_TypedData_kUint32, 1024},
|
|
{Dart_TypedData_kInt64, 2048}, {Dart_TypedData_kUint64, 2048},
|
|
{Dart_TypedData_kFloat32, 1024}, {Dart_TypedData_kFloat64, 2048},
|
|
{Dart_TypedData_kInvalid, -1}};
|
|
|
|
int i = 0;
|
|
while (expected[i].type != Dart_TypedData_kInvalid) {
|
|
CheckTypedData(root->value.as_array.values[i], expected[i].type,
|
|
expected[i].size);
|
|
i++;
|
|
}
|
|
EXPECT_EQ(i, root->value.as_array.length);
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of Uint8List views from Dart code.
|
|
Message* message = GetSerialized(lib, "getTypedDataViewList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
struct {
|
|
Dart_TypedData_Type type;
|
|
int size;
|
|
} expected[] = {
|
|
{Dart_TypedData_kInt8, 256}, {Dart_TypedData_kUint8, 256},
|
|
{Dart_TypedData_kInt16, 512}, {Dart_TypedData_kUint16, 512},
|
|
{Dart_TypedData_kInt32, 1024}, {Dart_TypedData_kUint32, 1024},
|
|
{Dart_TypedData_kInt64, 2048}, {Dart_TypedData_kUint64, 2048},
|
|
{Dart_TypedData_kFloat32, 1024}, {Dart_TypedData_kFloat64, 2048},
|
|
|
|
{Dart_TypedData_kInt8, 512}, {Dart_TypedData_kUint8, 512},
|
|
{Dart_TypedData_kInt8, 1024}, {Dart_TypedData_kUint8, 1024},
|
|
{Dart_TypedData_kInt8, 2048}, {Dart_TypedData_kUint8, 2048},
|
|
{Dart_TypedData_kInt8, 1024}, {Dart_TypedData_kUint8, 1024},
|
|
{Dart_TypedData_kInt8, 2048}, {Dart_TypedData_kUint8, 2048},
|
|
|
|
{Dart_TypedData_kInt16, 256}, {Dart_TypedData_kUint16, 256},
|
|
{Dart_TypedData_kInt16, 1024}, {Dart_TypedData_kUint16, 1024},
|
|
{Dart_TypedData_kInt16, 2048}, {Dart_TypedData_kUint16, 2048},
|
|
{Dart_TypedData_kInt16, 1024}, {Dart_TypedData_kUint16, 1024},
|
|
{Dart_TypedData_kInt16, 2048}, {Dart_TypedData_kUint16, 2048},
|
|
|
|
{Dart_TypedData_kInvalid, -1}};
|
|
|
|
int i = 0;
|
|
while (expected[i].type != Dart_TypedData_kInvalid) {
|
|
CheckTypedData(root->value.as_array.values[i], expected[i].type,
|
|
expected[i].size);
|
|
i++;
|
|
}
|
|
EXPECT_EQ(i, root->value.as_array.length);
|
|
delete message;
|
|
}
|
|
{
|
|
// Generate a list of Uint8Lists from Dart code.
|
|
Message* message = GetSerialized(lib, "getMultipleTypedDataViewList");
|
|
ApiNativeScope scope;
|
|
Dart_CObject* root = GetDeserialized(message);
|
|
EXPECT_NOTNULL(root);
|
|
EXPECT_EQ(Dart_CObject_kArray, root->type);
|
|
struct {
|
|
Dart_TypedData_Type type;
|
|
int size;
|
|
} expected[] = {
|
|
{Dart_TypedData_kInt8, 256}, {Dart_TypedData_kUint8, 256},
|
|
{Dart_TypedData_kInt16, 256}, {Dart_TypedData_kUint16, 256},
|
|
{Dart_TypedData_kInt32, 256}, {Dart_TypedData_kUint32, 256},
|
|
{Dart_TypedData_kInt64, 256}, {Dart_TypedData_kUint64, 256},
|
|
{Dart_TypedData_kFloat32, 256}, {Dart_TypedData_kFloat64, 256},
|
|
{Dart_TypedData_kInvalid, -1}};
|
|
|
|
int i = 0;
|
|
while (expected[i].type != Dart_TypedData_kInvalid) {
|
|
CheckTypedData(root->value.as_array.values[i], expected[i].type,
|
|
expected[i].size);
|
|
|
|
// All views point to the same data.
|
|
EXPECT_EQ(root->value.as_array.values[0]->value.as_typed_data.values,
|
|
root->value.as_array.values[i]->value.as_typed_data.values);
|
|
i++;
|
|
}
|
|
EXPECT_EQ(i, root->value.as_array.length);
|
|
delete message;
|
|
}
|
|
}
|
|
Dart_ExitScope();
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
VM_UNIT_TEST_CASE(PostCObject) {
|
|
// Create a native port for posting from C to Dart
|
|
TestIsolateScope __test_isolate__;
|
|
const char* kScriptChars =
|
|
"import 'dart:isolate';\n"
|
|
"main() {\n"
|
|
" var messageCount = 0;\n"
|
|
" var exception = '';\n"
|
|
" var port = new RawReceivePort();\n"
|
|
" var sendPort = port.sendPort;\n"
|
|
" port.handler = (message) {\n"
|
|
" if (messageCount < 9) {\n"
|
|
" exception = '$exception${message}';\n"
|
|
" } else {\n"
|
|
" exception = '$exception${message.length}';\n"
|
|
" for (int i = 0; i < message.length; i++) {\n"
|
|
" exception = '$exception${message[i]}';\n"
|
|
" }\n"
|
|
" }\n"
|
|
" messageCount++;\n"
|
|
" if (messageCount == 10) throw new Exception(exception);\n"
|
|
" };\n"
|
|
" return sendPort;\n"
|
|
"}\n";
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle send_port = Dart_Invoke(lib, NewString("main"), 0, NULL);
|
|
EXPECT_VALID(send_port);
|
|
Dart_Port port_id;
|
|
Dart_Handle result = Dart_SendPortGetId(send_port, &port_id);
|
|
ASSERT(!Dart_IsError(result));
|
|
|
|
// Setup single object message.
|
|
Dart_CObject object;
|
|
|
|
object.type = Dart_CObject_kNull;
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kBool;
|
|
object.value.as_bool = true;
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kBool;
|
|
object.value.as_bool = false;
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kInt32;
|
|
object.value.as_int32 = 123;
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kString;
|
|
object.value.as_string = const_cast<char*>("456");
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kString;
|
|
object.value.as_string = const_cast<char*>("æøå");
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kString;
|
|
object.value.as_string = const_cast<char*>("");
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kDouble;
|
|
object.value.as_double = 3.14;
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
object.type = Dart_CObject_kArray;
|
|
object.value.as_array.length = 0;
|
|
EXPECT(Dart_PostCObject(port_id, &object));
|
|
|
|
static const int kArrayLength = 10;
|
|
Dart_CObject* array = reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate(
|
|
sizeof(Dart_CObject) + sizeof(Dart_CObject*) * kArrayLength)); // NOLINT
|
|
array->type = Dart_CObject_kArray;
|
|
array->value.as_array.length = kArrayLength;
|
|
array->value.as_array.values = reinterpret_cast<Dart_CObject**>(array + 1);
|
|
for (int i = 0; i < kArrayLength; i++) {
|
|
Dart_CObject* element = reinterpret_cast<Dart_CObject*>(
|
|
Dart_ScopeAllocate(sizeof(Dart_CObject)));
|
|
element->type = Dart_CObject_kInt32;
|
|
element->value.as_int32 = i;
|
|
array->value.as_array.values[i] = element;
|
|
}
|
|
EXPECT(Dart_PostCObject(port_id, array));
|
|
|
|
result = Dart_RunLoop();
|
|
EXPECT(Dart_IsError(result));
|
|
EXPECT(Dart_ErrorHasException(result));
|
|
EXPECT_SUBSTRING("Exception: nulltruefalse123456æøå3.14[]100123456789\n",
|
|
Dart_GetError(result));
|
|
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
TEST_CASE(OmittedObjectEncodingLength) {
|
|
StackZone zone(Thread::Current());
|
|
MessageWriter writer(true);
|
|
writer.WriteInlinedObjectHeader(kOmittedObjectId);
|
|
// For performance, we'd like single-byte headers when ids are omitted.
|
|
// If this starts failing, consider renumbering the snapshot ids.
|
|
EXPECT_EQ(1, writer.BytesWritten());
|
|
|
|
free(writer.buffer());
|
|
}
|
|
|
|
TEST_CASE(IsKernelNegative) {
|
|
EXPECT(!Dart_IsKernel(NULL, 0));
|
|
|
|
uint8_t buffer[4] = {0, 0, 0, 0};
|
|
EXPECT(!Dart_IsKernel(buffer, ARRAY_SIZE(buffer)));
|
|
}
|
|
|
|
} // namespace dart
|