Files
sdk/runtime/vm/snapshot_test.cc
T
Ryan Macnak d36adbacaf [vm] Remove the VM isolate.
The former contents of the VM isolate are now included into each isolate group. This makes each isolate group's heap independent, and in particular allows each heap to be allocated to a separate pointer cage (not done in this CL).

The duplicated stubs that allowed PC relative calls are removed, since the originals can now be the target of PC relative calls.

The bootstrapping needing to load an AppJIT or AppAOT snapshot is reduced to allocating the oddballs. The code is entirely dropped in the AOT runtime, but the JIT runtime still has it to allow for flags to affect the compilation of the stub code. Further refactoring might be able to remove this for the JIT runtime too, with only gen_snapshot knowing how to bootstrap.

Class serialization no longer distinguishes predefined classes.

The page containing null is marked as never-evacuate. null, false and true must not move because the compiler relies on their low bits having certain patterns for some optimizations. (Previously, the entire VM isolate heap never moved.)

Compaction is disabled for IA32. Due to register pressure, some stub calls must not use a scratch register and embed the address of Code.

The page containing the call-through-safepoint stub is frozen when running with --write-protect-code and the stub is created at runtime (instead of loaded from an AppJIT or AppAOT snapshot). This stub must remain executable even during a safepoint, as a foreign call might during return during a safepoint and only block after the stub directs it to the runtime.

The snapshot symbols are renamed to kDartSnapshotData and kDartSnapshotText. There is no need to distinguish the VM isolate's snapshot, and snaphots are per isolate group not per isolate. Aliases with the old names are added to ease migration.

Some global flags that were automatically set based on the VM isolate's snapshot are now isolate group flags and automatically set by the isolate group's snapshot.

TEST=ci
Change-Id: Iee82016057d609112e9b021d178fc3d4d18b5044
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/500621
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2026-05-18 11:35:03 -07:00

2055 lines
80 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 "platform/unicode.h"
#include "vm/app_snapshot.h"
#include "vm/class_finalizer.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/message_snapshot.h"
#include "vm/snapshot.h"
#include "vm/symbols.h"
#include "vm/timer.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.ptr() == actual.ptr();
}
return false;
}
if (expected.IsDouble()) {
if (actual.IsDouble()) {
Double& dbl1 = Double::Handle();
Double& dbl2 = Double::Handle();
dbl1 ^= expected.ptr();
dbl2 ^= actual.ptr();
return dbl1.value() == dbl2.value();
}
return false;
}
if (expected.IsBool()) {
if (actual.IsBool()) {
return expected.ptr() == actual.ptr();
}
return false;
}
return false;
}
// 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_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(Zone* zone, Dart_CObject* root) {
// Encode and decode the message.
std::unique_ptr<Message> message =
WriteApiMessage(zone, root, ILLEGAL_PORT, Message::kNormalPriority);
Dart_CObject* new_root = ReadApiMessage(zone, message.get());
// Check that the two messages are the same.
CompareDartCObjects(root, new_root);
}
static void ExpectEncodeFail(Zone* zone, Dart_CObject* root) {
std::unique_ptr<Message> message =
WriteApiMessage(zone, root, ILLEGAL_PORT, Message::kNormalPriority);
EXPECT(message == nullptr);
}
ISOLATE_UNIT_TEST_CASE(SerializeNull) {
StackZone zone(thread);
// Write snapshot with object content.
const Object& null_object = Object::Handle();
std::unique_ptr<Message> message =
WriteMessage(/* same_group */ false, null_object, ILLEGAL_PORT,
Message::kNormalPriority);
// Read object back from the snapshot.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
EXPECT(Equals(null_object, serialized_object));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kNull, root->type);
CheckEncodeDecodeMessage(scope.zone(), root);
}
ISOLATE_UNIT_TEST_CASE(SerializeSmi1) {
StackZone zone(thread);
// Write snapshot with object content.
const Smi& smi = Smi::Handle(Smi::New(124));
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, smi, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
EXPECT(Equals(smi, serialized_object));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kInt32, root->type);
EXPECT_EQ(smi.Value(), root->value.as_int32);
CheckEncodeDecodeMessage(scope.zone(), root);
}
ISOLATE_UNIT_TEST_CASE(SerializeSmi2) {
StackZone zone(thread);
// Write snapshot with object content.
const Smi& smi = Smi::Handle(Smi::New(-1));
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, smi, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
EXPECT(Equals(smi, serialized_object));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kInt32, root->type);
EXPECT_EQ(smi.Value(), root->value.as_int32);
CheckEncodeDecodeMessage(scope.zone(), root);
}
Dart_CObject* SerializeAndDeserializeMint(Zone* zone, const Mint& mint) {
// Write snapshot with object content.
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, 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.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
EXPECT(serialized_object.IsMint());
}
// Read object back from the snapshot into a C structure.
Dart_CObject* root = ReadApiMessage(zone, message.get());
EXPECT_NOTNULL(root);
CheckEncodeDecodeMessage(zone, root);
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(zone.GetZone(), 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) && !defined(DART_COMPRESSED_POINTERS)
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));
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, dbl, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
EXPECT(Equals(dbl, serialized_object));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kDouble, root->type);
EXPECT_EQ(dbl.value(), root->value.as_double);
CheckEncodeDecodeMessage(scope.zone(), root);
}
ISOLATE_UNIT_TEST_CASE(SerializeTrue) {
StackZone zone(thread);
// Write snapshot with true object.
const Bool& bl = Bool::True();
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, bl, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
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;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kBool, root->type);
EXPECT_EQ(true, root->value.as_bool);
CheckEncodeDecodeMessage(scope.zone(), root);
}
ISOLATE_UNIT_TEST_CASE(SerializeFalse) {
StackZone zone(thread);
// Write snapshot with false object.
const Bool& bl = Bool::False();
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, bl, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
const Object& serialized_object =
Object::Handle(ReadMessage(thread, message.get()));
EXPECT(Equals(bl, serialized_object));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kBool, root->type);
EXPECT_EQ(false, root->value.as_bool);
CheckEncodeDecodeMessage(scope.zone(), root);
}
ISOLATE_UNIT_TEST_CASE(SerializeCapability) {
// Write snapshot with object content.
const Capability& capability = Capability::Handle(Capability::New(12345));
std::unique_ptr<Message> message =
WriteMessage(/* same_group */ false, capability, ILLEGAL_PORT,
Message::kNormalPriority);
// Read object back from the snapshot.
Capability& obj = Capability::Handle();
obj ^= ReadMessage(thread, message.get());
EXPECT_EQ(static_cast<uint64_t>(12345), obj.Id());
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kCapability, root->type);
int64_t id = root->value.as_capability.id;
EXPECT_EQ(12345, id);
CheckEncodeDecodeMessage(scope.zone(), root);
}
#define TEST_ROUND_TRIP_IDENTICAL(object) \
{ \
const Object& before = Object::Handle(object); \
std::unique_ptr<Message> message = \
WriteMessage(/* same_group */ false, before, ILLEGAL_PORT, \
Message::kNormalPriority); \
const Object& after = Object::Handle(ReadMessage(thread, message.get())); \
EXPECT(before.ptr() == after.ptr()); \
}
ISOLATE_UNIT_TEST_CASE(SerializeSingletons) {
ClassTable* table = IsolateGroup::Current()->class_table();
TEST_ROUND_TRIP_IDENTICAL(table->At(kClassCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kTypeArgumentsCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kFunctionCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kFieldCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kScriptCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kLibraryCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kCodeCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kInstructionsCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kPcDescriptorsCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kExceptionHandlersCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kContextCid));
TEST_ROUND_TRIP_IDENTICAL(table->At(kContextScopeCid));
}
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));
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, str, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
String& serialized_str = String::Handle();
serialized_str ^= ReadMessage(thread, message.get());
EXPECT(str.Equals(serialized_str));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_EQ(Dart_CObject_kString, root->type);
EXPECT_STREQ(cstr, root->value.as_string);
CheckEncodeDecodeMessage(scope.zone(), root);
}
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);
}
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, array, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
Array& serialized_array = Array::Handle();
serialized_array ^= ReadMessage(thread, message.get());
EXPECT(array.CanonicalizeEquals(serialized_array));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
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);
}
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, array, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
Array& serialized_array = Array::Handle();
serialized_array ^= ReadMessage(thread, message.get());
EXPECT(array.CanonicalizeEquals(serialized_array));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
TEST_CASE(FailSerializeLargeArray) {
Dart_CObject root;
root.type = Dart_CObject_kArray;
root.value.as_array.length = Array::kMaxElements + 1;
root.value.as_array.values = nullptr;
ApiNativeScope scope;
ExpectEncodeFail(scope.zone(), &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;
ApiNativeScope scope;
ExpectEncodeFail(scope.zone(), &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;
ApiNativeScope scope;
ExpectEncodeFail(scope.zone(), &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;
ApiNativeScope scope;
ExpectEncodeFail(scope.zone(), &root);
}
TEST_CASE(FailSerializeLargeExternalTypedData) {
Dart_CObject root;
root.type = Dart_CObject_kExternalTypedData;
root.value.as_external_typed_data.type = Dart_TypedData_kUint8;
root.value.as_external_typed_data.length =
ExternalTypedData::MaxElements(kExternalTypedDataUint8ArrayCid) + 1;
ApiNativeScope scope;
ExpectEncodeFail(scope.zone(), &root);
}
TEST_CASE(FailSerializeLargeUnmodifiableExternalTypedData) {
Dart_CObject root;
root.type = Dart_CObject_kUnmodifiableExternalTypedData;
root.value.as_external_typed_data.type = Dart_TypedData_kUint8;
root.value.as_external_typed_data.length =
ExternalTypedData::MaxElements(kExternalTypedDataUint8ArrayCid) + 1;
ApiNativeScope scope;
ExpectEncodeFail(scope.zone(), &root);
}
ISOLATE_UNIT_TEST_CASE(SerializeEmptyArray) {
// Write snapshot with object content.
const int kArrayLength = 0;
Array& array = Array::Handle(Array::New(kArrayLength));
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, array, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot.
Array& serialized_array = Array::Handle();
serialized_array ^= ReadMessage(thread, message.get());
EXPECT(array.CanonicalizeEquals(serialized_array));
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_EQ(Dart_CObject_kArray, root->type);
EXPECT_EQ(kArrayLength, root->value.as_array.length);
EXPECT(root->value.as_array.values == nullptr);
CheckEncodeDecodeMessage(scope.zone(), root);
}
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);
}
std::unique_ptr<Message> message =
WriteMessage(/* same_group */ false, typed_data, ILLEGAL_PORT,
Message::kNormalPriority);
// Read object back from the snapshot.
TypedData& serialized_typed_data = TypedData::Handle();
serialized_typed_data ^= ReadMessage(thread, message.get());
EXPECT(serialized_typed_data.IsTypedData());
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
#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); \
} \
std::unique_ptr<Message> message = \
WriteMessage(/* same_group */ false, array, ILLEGAL_PORT, \
Message::kNormalPriority); \
TypedData& serialized_array = TypedData::Handle(); \
serialized_array ^= ReadMessage(thread, message.get()); \
for (int i = 0; i < kArrayLength; i++) { \
EXPECT_EQ(static_cast<ctype>(i), \
serialized_array.Get##darttype(i * scale)); \
} \
}
#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(); \
std::unique_ptr<Message> message = \
WriteMessage(/* same_group */ false, array, ILLEGAL_PORT, \
Message::kNormalPriority); \
ExternalTypedData& serialized_array = ExternalTypedData::Handle(); \
serialized_array ^= ReadMessage(thread, message.get()); \
for (int i = 0; i < length; i++) { \
EXPECT_EQ(static_cast<ctype>(data[i]), \
serialized_array.Get##darttype(i * scale)); \
} \
}
#define TEST_UNMODIFIABLE_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)); \
TypedDataView& view = TypedDataView::Handle(TypedDataView::New( \
kUnmodifiableTypedData##darttype##ArrayViewCid, array, 0, length)); \
intptr_t scale = array.ElementSizeInBytes(); \
std::unique_ptr<Message> message = WriteMessage( \
/* same_group */ false, view, ILLEGAL_PORT, Message::kNormalPriority); \
TypedDataView& serialized_view = TypedDataView::Handle(); \
serialized_view ^= ReadMessage(thread, message.get()); \
for (int i = 0; i < length; i++) { \
EXPECT_EQ(static_cast<ctype>(data[i]), \
serialized_view.Get##darttype(i * scale)); \
} \
}
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(SerializeUnmodifiableExternalTypedArray) {
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Int8, int8_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Uint8, uint8_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Int16, int16_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Uint16, uint16_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Int32, int32_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Uint32, uint32_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Int64, int64_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Uint64, uint64_t);
TEST_UNMODIFIABLE_EXTERNAL_TYPED_ARRAY(Float32, float);
TEST_UNMODIFIABLE_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));
std::unique_ptr<Message> message =
WriteMessage(/* same_group */ false, typed_data, ILLEGAL_PORT,
Message::kNormalPriority);
// Read object back from the snapshot.
TypedData& serialized_typed_data = TypedData::Handle();
serialized_typed_data ^= ReadMessage(thread, message.get());
EXPECT(serialized_typed_data.IsTypedData());
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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 == nullptr);
CheckEncodeDecodeMessage(scope.zone(), root);
}
VM_UNIT_TEST_CASE(FullSnapshot) {
// clang-format off
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"
"@pragma('vm:entry-point')\n"
"class FieldsTest {\n"
" @pragma('vm:entry-point', 'call')\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";
// clang-format on
Dart_Handle result;
uint8_t* isolate_snapshot_data_buffer;
// Start an Isolate, load a script and create a full snapshot.
Timer timer1;
timer1.Start();
{
TestIsolateScope __test_isolate__;
// Create a test library and Load up a test script in it.
TestCase::LoadTestScript(kScriptChars, nullptr);
Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
StackZone zone(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.
MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
FullSnapshotWriter writer(Snapshot::kFull, &isolate_snapshot_data,
/*image_writer=*/nullptr);
writer.WriteFullSnapshot();
// Take ownership so it doesn't get freed by the stream destructor.
intptr_t unused;
isolate_snapshot_data_buffer = isolate_snapshot_data.Steal(&unused);
}
// Now Create another isolate using the snapshot and execute a method
// from the script.
Timer timer2;
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, nullptr);
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 std::unique_ptr<Message> GetSerialized(Dart_Handle lib,
const char* dart_function) {
Dart_Handle result;
{
TransitionVMToNative transition(Thread::Current());
{
SetFlagScope<bool> sfs(&FLAG_verify_entry_points, false);
result = Dart_Invoke(lib, NewString(dart_function), 0, nullptr);
EXPECT_VALID(result);
}
}
Object& obj = Object::Handle(Api::UnwrapHandle(result));
// Serialize the object into a message.
return WriteMessage(/* same_group */ false, obj, ILLEGAL_PORT,
Message::kNormalPriority);
}
static void CheckString(Dart_Handle dart_string, const char* expected) {
StackZone zone(Thread::Current());
String& str = String::Handle();
str ^= Api::UnwrapHandle(dart_string);
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, str, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(zone.GetZone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kString, root->type);
EXPECT_STREQ(expected, root->value.as_string);
CheckEncodeDecodeMessage(zone.GetZone(), root);
}
static void CheckStringInvalid(Dart_Handle dart_string) {
StackZone zone(Thread::Current());
String& str = String::Handle();
str ^= Api::UnwrapHandle(dart_string);
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, str, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(zone.GetZone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kUnsupported, root->type);
}
VM_UNIT_TEST_CASE(DartGeneratedMessages) {
static const char* kCustomIsolateScriptChars =
"final int kArrayLength = 10;\n"
"@pragma('vm:entry-point', 'call')\n"
"getSmi() {\n"
" return 42;\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getAsciiString() {\n"
" return \"Hello, world!\";\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getNonAsciiString() {\n"
" return \"Blåbærgrød\";\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getNonBMPString() {\n"
" return \"\\u{10000}\\u{1F601}\\u{1F637}\\u{20000}\";\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getLeadSurrogateString() {\n"
" return String.fromCharCodes([0xd800]);\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getTrailSurrogateString() {\n"
" return \"\\u{10000}\".substring(1);\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getSurrogatesString() {\n"
" return String.fromCharCodes([0xdc00, 0xdc00, 0xd800, 0xd800]);\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getCrappyString() {\n"
" return String.fromCharCodes([0xd800, 32, 0xdc00, 32]);\n"
"}\n"
"@pragma('vm:entry-point', 'call')\n"
"getList() {\n"
" return List.filled(kArrayLength, null);\n"
"}\n";
TestCase::CreateTestIsolate();
Isolate* isolate = Isolate::Current();
EXPECT(isolate != nullptr);
Dart_EnterScope();
Dart_Handle lib =
TestCase::LoadTestScript(kCustomIsolateScriptChars, nullptr);
EXPECT_VALID(lib);
Dart_Handle smi_result;
smi_result = Dart_Invoke(lib, NewString("getSmi"), 0, nullptr);
EXPECT_VALID(smi_result);
Dart_Handle ascii_string_result;
ascii_string_result =
Dart_Invoke(lib, NewString("getAsciiString"), 0, nullptr);
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, nullptr);
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, nullptr);
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, nullptr);
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, nullptr);
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, nullptr);
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, nullptr);
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);
std::unique_ptr<Message> message = WriteMessage(
/* same_group */ false, smi, ILLEGAL_PORT, Message::kNormalPriority);
// Read object back from the snapshot into a C structure.
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
EXPECT_NOTNULL(root);
EXPECT_EQ(Dart_CObject_kInt32, root->type);
EXPECT_EQ(42, root->value.as_int32);
CheckEncodeDecodeMessage(scope.zone(), root);
}
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;
const char* kScriptChars =
"final int kArrayLength = 10;\n"
"getList() {\n"
" return List.filled(kArrayLength, null);\n"
"}\n"
"getIntList() {\n"
" var list = List<int>.filled(kArrayLength, 0);\n"
" for (var i = 0; i < kArrayLength; i++) list[i] = i;\n"
" return list;\n"
"}\n"
"getStringList() {\n"
" var list = List<String>.filled(kArrayLength, '');\n"
" for (var i = 0; i < kArrayLength; i++) list[i] = i.toString();\n"
" return list;\n"
"}\n"
"getMixedList() {\n"
" var list = List<dynamic>.filled(kArrayLength, null);\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() != nullptr);
Dart_EnterScope();
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib);
{
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
StackZone zone(thread);
{
// Generate a list of nulls from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
{
// Generate a list of ints from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getIntList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
{
// Generate a list of strings from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
{
// Generate a list of objects of different types from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
}
}
Dart_ExitScope();
Dart_ShutdownIsolate();
}
VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessages) {
const int kArrayLength = 10;
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 <dynamic>[[],"
" [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(<dynamic>[[]]);\n"
" list.add(<dynamic>[<dynamic>[[]]]);\n"
" list.add(<dynamic>[1, <dynamic>[2, [3]]]);\n"
" list.add(<dynamic>[1, <dynamic>[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() != nullptr);
Dart_EnterScope();
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib);
{
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
StackZone zone(thread);
{
// Generate a list of nulls from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
{
// Generate a list of ints from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getIntList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(scope.zone(), root);
}
{
// Generate a list of strings from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
{
// Generate a list of lists from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getListList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
}
{
// Generate a list of objects of different types from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
}
Dart_ExitScope();
Dart_ShutdownIsolate();
}
VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) {
const int kArrayLength = 10;
const char* kScriptChars =
"import 'dart:typed_data';\n"
"final int kArrayLength = 10;\n"
"getStringList() {\n"
" var s = 'Hello, world!';\n"
" var list = List<String>.filled(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 = List.filled(kArrayLength, 0);\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 = List<double>.filled(kArrayLength, 0.0);\n"
" for (var i = 0; i < kArrayLength; i++) list[i] = d;\n"
" return list;\n"
"}\n"
"getTypedDataList() {\n"
" var byte_array = Uint8List(256);\n"
" var list = List<dynamic>.filled(kArrayLength, null);\n"
" for (var i = 0; i < kArrayLength; i++) list[i] = byte_array;\n"
" return list;\n"
"}\n"
"getTypedDataViewList() {\n"
" var uint8_list = Uint8List(256);\n"
" uint8_list[64] = 1;\n"
" var uint8_list_view =\n"
" Uint8List.view(uint8_list.buffer, 64, 128);\n"
" var list = List<dynamic>.filled(kArrayLength, null);\n"
" for (var i = 0; i < kArrayLength; i++) list[i] = uint8_list_view;\n"
" return list;\n"
"}\n"
"getMixedList() {\n"
" var list = List<dynamic>.filled(kArrayLength, null);\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 = List<dynamic>.filled(kArrayLength, null, growable: true);\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() != nullptr);
Dart_EnterScope();
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib);
{
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
StackZone zone(thread);
{
// Generate a list of strings from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
{
// Generate a list of medium ints from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getMintList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(0x7FFFFFFFFFFFFFFF, element->value.as_int64);
}
}
{
// Generate a list of doubles from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getDoubleList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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];
EXPECT_EQ(Dart_CObject_kDouble, element->type);
EXPECT_EQ(3.14, element->value.as_double);
}
}
{
// Generate a list of Uint8Lists from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getTypedDataList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
{
// Generate a list of Uint8List views from Dart code.
std::unique_ptr<Message> message =
GetSerialized(lib, "getTypedDataViewList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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]);
}
}
{
// Generate a list of objects of different types from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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_EQ(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 {
EXPECT_EQ(Dart_CObject_kDouble, element->type);
EXPECT_EQ(2.72, element->value.as_double);
}
}
}
{
// Generate a list of objects of different types from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getSelfRefList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
}
Dart_ExitScope();
Dart_ShutdownIsolate();
}
VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) {
const int kArrayLength = 10;
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() != nullptr);
Dart_EnterScope();
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib);
{
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
StackZone zone(thread);
{
// Generate a list of strings from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
{
// Generate a list of medium ints from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getMintList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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(0x7FFFFFFFFFFFFFFF, element->value.as_int64);
}
}
{
// Generate a list of doubles from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getDoubleList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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];
EXPECT_EQ(Dart_CObject_kDouble, element->type);
EXPECT_EQ(3.14, element->value.as_double);
}
}
{
// Generate a list of Uint8Lists from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getTypedDataList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
{
// Generate a list of Uint8List views from Dart code.
std::unique_ptr<Message> message =
GetSerialized(lib, "getTypedDataViewList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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]);
}
}
{
// Generate a list of objects of different types from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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_EQ(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 {
EXPECT_EQ(Dart_CObject_kDouble, element->type);
EXPECT_EQ(2.72, element->value.as_double);
}
}
}
{
// Generate a list of objects of different types from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getSelfRefList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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);
}
}
}
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 = List<dynamic>.filled(13, null);\n"
" var index = 0;\n"
" list[index++] = Int8List(256);\n"
" list[index++] = Uint8List(256);\n"
" list[index++] = Int16List(256);\n"
" list[index++] = Uint16List(256);\n"
" list[index++] = Int32List(256);\n"
" list[index++] = Uint32List(256);\n"
" list[index++] = Int64List(256);\n"
" list[index++] = Uint64List(256);\n"
" list[index++] = Float32List(256);\n"
" list[index++] = Float64List(256);\n"
" list[index++] = Int32x4List(256);\n"
" list[index++] = Float32x4List(256);\n"
" list[index++] = Float64x2List(256);\n"
" return list;\n"
"}\n"
"getTypedDataViewList() {\n"
" var list = List<dynamic>.filled(45, null);\n"
" var index = 0;\n"
" list[index++] = Int8List.view(Int8List(256).buffer);\n"
" list[index++] = Uint8List.view(Uint8List(256).buffer);\n"
" list[index++] = Int16List.view(new Int16List(256).buffer);\n"
" list[index++] = Uint16List.view(new Uint16List(256).buffer);\n"
" list[index++] = Int32List.view(new Int32List(256).buffer);\n"
" list[index++] = Uint32List.view(new Uint32List(256).buffer);\n"
" list[index++] = Int64List.view(new Int64List(256).buffer);\n"
" list[index++] = Uint64List.view(new Uint64List(256).buffer);\n"
" list[index++] = Float32List.view(new Float32List(256).buffer);\n"
" list[index++] = Float64List.view(new Float64List(256).buffer);\n"
" list[index++] = Int32x4List.view(new Int32x4List(256).buffer);\n"
" list[index++] = Float32x4List.view(new Float32x4List(256).buffer);\n"
" list[index++] = Float64x2List.view(new Float64x2List(256).buffer);\n"
" list[index++] = Int8List.view(new Int16List(256).buffer);\n"
" list[index++] = Uint8List.view(new Uint16List(256).buffer);\n"
" list[index++] = Int8List.view(new Int32List(256).buffer);\n"
" list[index++] = Uint8List.view(new Uint32List(256).buffer);\n"
" list[index++] = Int8List.view(new Int64List(256).buffer);\n"
" list[index++] = Uint8List.view(new Uint64List(256).buffer);\n"
" list[index++] = Int8List.view(new Float32List(256).buffer);\n"
" list[index++] = Uint8List.view(new Float32List(256).buffer);\n"
" list[index++] = Int8List.view(new Float64List(256).buffer);\n"
" list[index++] = Uint8List.view(new Float64List(256).buffer);\n"
" list[index++] = Int8List.view(new Int32x4List(256).buffer);\n"
" list[index++] = Uint8List.view(new Int32x4List(256).buffer);\n"
" list[index++] = Int8List.view(new Float32x4List(256).buffer);\n"
" list[index++] = Uint8List.view(new Float32x4List(256).buffer);\n"
" list[index++] = Int8List.view(new Float64x2List(256).buffer);\n"
" list[index++] = Uint8List.view(new Float64x2List(256).buffer);\n"
" list[index++] = Int16List.view(new Int8List(256).buffer);\n"
" list[index++] = Uint16List.view(new Uint8List(256).buffer);\n"
" list[index++] = Int16List.view(new Int32List(256).buffer);\n"
" list[index++] = Uint16List.view(new Uint32List(256).buffer);\n"
" list[index++] = Int16List.view(new Int64List(256).buffer);\n"
" list[index++] = Uint16List.view(new Uint64List(256).buffer);\n"
" list[index++] = Int16List.view(new Float32List(256).buffer);\n"
" list[index++] = Uint16List.view(new Float32List(256).buffer);\n"
" list[index++] = Int16List.view(new Float64List(256).buffer);\n"
" list[index++] = Uint16List.view(new Float64List(256).buffer);\n"
" list[index++] = Int16List.view(new Int32x4List(256).buffer);\n"
" list[index++] = Uint16List.view(new Int32x4List(256).buffer);\n"
" list[index++] = Int16List.view(new Float32x4List(256).buffer);\n"
" list[index++] = Uint16List.view(new Float32x4List(256).buffer);\n"
" list[index++] = Int16List.view(new Float64x2List(256).buffer);\n"
" list[index++] = Uint16List.view(new Float64x2List(256).buffer);\n"
" return list;\n"
"}\n"
"getMultipleTypedDataViewList() {\n"
" var list = List<dynamic>.filled(13, null);\n"
" var index = 0;\n"
" var data = Uint8List(256).buffer;\n"
" list[index++] = Int8List.view(data);\n"
" list[index++] = Uint8List.view(data);\n"
" list[index++] = Int16List.view(data);\n"
" list[index++] = Uint16List.view(data);\n"
" list[index++] = Int32List.view(data);\n"
" list[index++] = Uint32List.view(data);\n"
" list[index++] = Int64List.view(data);\n"
" list[index++] = Uint64List.view(data);\n"
" list[index++] = Float32List.view(data);\n"
" list[index++] = Float64List.view(data);\n"
" list[index++] = Int32x4List.view(data);\n"
" list[index++] = Float32x4List.view(data);\n"
" list[index++] = Float64x2List.view(data);\n"
" return list;\n"
"}\n";
TestCase::CreateTestIsolate();
Thread* thread = Thread::Current();
EXPECT(thread->isolate() != nullptr);
Dart_EnterScope();
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
EXPECT_VALID(lib);
{
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
StackZone zone(thread);
{
// Generate a list of Uint8Lists from Dart code.
std::unique_ptr<Message> message = GetSerialized(lib, "getTypedDataList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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_kInt32x4, 256}, {Dart_TypedData_kFloat32x4, 256},
{Dart_TypedData_kFloat64x2, 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);
i++;
}
EXPECT_EQ(i, root->value.as_array.length);
}
{
// Generate a list of Uint8List views from Dart code.
std::unique_ptr<Message> message =
GetSerialized(lib, "getTypedDataViewList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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_kInt32x4, 256}, {Dart_TypedData_kFloat32x4, 256},
{Dart_TypedData_kFloat64x2, 256},
{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_kInt8, 4096}, {Dart_TypedData_kUint8, 4096},
{Dart_TypedData_kInt8, 4096}, {Dart_TypedData_kUint8, 4096},
{Dart_TypedData_kInt8, 4096}, {Dart_TypedData_kUint8, 4096},
{Dart_TypedData_kInt16, 128}, {Dart_TypedData_kUint16, 128},
{Dart_TypedData_kInt16, 512}, {Dart_TypedData_kUint16, 512},
{Dart_TypedData_kInt16, 1024}, {Dart_TypedData_kUint16, 1024},
{Dart_TypedData_kInt16, 512}, {Dart_TypedData_kUint16, 512},
{Dart_TypedData_kInt16, 1024}, {Dart_TypedData_kUint16, 1024},
{Dart_TypedData_kInt16, 2048}, {Dart_TypedData_kUint16, 2048},
{Dart_TypedData_kInt16, 2048}, {Dart_TypedData_kUint16, 2048},
{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);
}
{
// Generate a list of Uint8Lists from Dart code.
std::unique_ptr<Message> message =
GetSerialized(lib, "getMultipleTypedDataViewList");
ApiNativeScope scope;
Dart_CObject* root = ReadApiMessage(scope.zone(), message.get());
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, 128}, {Dart_TypedData_kUint16, 128},
{Dart_TypedData_kInt32, 64}, {Dart_TypedData_kUint32, 64},
{Dart_TypedData_kInt64, 32}, {Dart_TypedData_kUint64, 32},
{Dart_TypedData_kFloat32, 64}, {Dart_TypedData_kFloat64, 32},
{Dart_TypedData_kInt32x4, 16}, {Dart_TypedData_kFloat32x4, 16},
{Dart_TypedData_kFloat64x2, 16}, {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);
}
}
Dart_ExitScope();
Dart_ShutdownIsolate();
}
static void MallocFinalizer(void* isolate_callback_data, void* peer) {
free(peer);
}
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
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 == 13) throw new Exception(exception);\n"
" };\n"
" return sendPort;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
Dart_EnterScope();
Dart_Handle send_port = Dart_Invoke(lib, NewString("main"), 0, nullptr);
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));
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));
object.type = Dart_CObject_kTypedData;
object.value.as_typed_data.type = Dart_TypedData_kUint8;
uint8_t data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
object.value.as_typed_data.length = ARRAY_SIZE(data);
object.value.as_typed_data.values = data;
EXPECT(Dart_PostCObject(port_id, &object));
object.type = Dart_CObject_kExternalTypedData;
object.value.as_typed_data.type = Dart_TypedData_kUint8;
uint8_t* external_data = reinterpret_cast<uint8_t*>(malloc(sizeof(data)));
memmove(external_data, data, sizeof(data));
object.value.as_external_typed_data.length = ARRAY_SIZE(data);
object.value.as_external_typed_data.data = external_data;
object.value.as_external_typed_data.peer = external_data;
object.value.as_external_typed_data.callback = MallocFinalizer;
EXPECT(Dart_PostCObject(port_id, &object));
object.type = Dart_CObject_kUnmodifiableExternalTypedData;
object.value.as_typed_data.type = Dart_TypedData_kUint8;
static const uint8_t unmodifiable_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
object.value.as_external_typed_data.length = ARRAY_SIZE(unmodifiable_data);
object.value.as_external_typed_data.data =
const_cast<uint8_t*>(unmodifiable_data);
object.value.as_external_typed_data.peer = nullptr;
object.value.as_external_typed_data.callback = NoopFinalizer;
EXPECT(Dart_PostCObject(port_id, &object));
result = Dart_RunLoop();
EXPECT(Dart_IsError(result));
EXPECT(Dart_ErrorHasException(result));
EXPECT_SUBSTRING(
"Exception: "
"nulltruefalse123456æøå3.14[]"
"100123456789901234567890123456789012345678\n",
Dart_GetError(result));
Dart_ExitScope();
}
TEST_CASE(IsKernelNegative) {
EXPECT(!Dart_IsKernel(nullptr, 0));
uint8_t buffer[4] = {0, 0, 0, 0};
EXPECT(!Dart_IsKernel(buffer, ARRAY_SIZE(buffer)));
}
} // namespace dart