Files
sdk/runtime/vm/snapshot_test.cc
T
Tess Strickland 9b06e26620 Reland "[vm] Enforce that entry points must be annotated by default."
This is a reland of commit cb9ecbc363

This reland only turns on the entry point verification flag by
default in AOT mode. After Flutter tests that use native access
in JIT mode have been appropriately updated, a followup CL will
turn this flag on by default in JIT mode as well.

Original change's description:
> [vm] Enforce that entry points must be annotated by default.
>
> Changes the default value of the --verify-entry-points flag
> to true.
>
> Changes the default value for the check_is_entrypoint argument to
> to the Invoke/InvokeGetter/InvokeSetter flags to true. The mirrors
> library implementation and calls via vm-service explicitly pass
> false for this argument now.
>
> Add annotations as needed, such as annotating classes with
> annotated generative constructors. In some cases, the annotations
> were more general than needed (e.g., annotating with a no-argument
> entry point annotation when only the setter is needed), so make
> those annotations more specific.
>
> As this pattern is already common in downstream code, allow
> Dart_Invoke on fields as long as the field is annotated for getter
> access. (That is, calling Dart_Invoke for a field is equivalent to
> retrieving the closure value via Dart_GetField and then calling
> Dart_InvokeClosure.)
>
> TEST=vm/cc/DartAPI_MissingEntryPoints
>      vm/dart/entrypoints_verification_test
>
> Issue: https://github.com/dart-lang/sdk/issues/50649
> Issue: https://github.com/flutter/flutter/issues/118608
>
> Change-Id: Ibb3bf15632ab2958d8791b449af8651d47f871a5
> Cq-Include-Trybots: luci.dart.try:vm-aot-linux-product-x64-try,vm-aot-linux-debug-x64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-product-arm64-try,vm-aot-dwarf-linux-product-x64-try
> CoreLibraryReviewExempt: adding/editing vm-only pragma annotations
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/363566
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Commit-Queue: Tess Strickland <sstrickl@google.com>

TEST=vm/cc/DartAPI_MissingEntryPoints
     vm/dart/entrypoints_verification_test

Change-Id: I24919c32ab4760c7c5435c378879791086256f02
Cq-Include-Trybots: luci.dart.try:vm-aot-linux-product-x64-try,vm-aot-linux-debug-x64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-product-arm64-try,vm-aot-dwarf-linux-product-x64-try,flutter-linux-try,vm-linux-debug-x64-try,vm-linux-release-x64-try,vm-appjit-linux-product-x64-try
CoreLibraryReviewExempt: adding/editing vm-only pragma annotations
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391620
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
2024-12-04 14:36:46 +00:00

2060 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) {
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::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));
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);
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.
MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
FullSnapshotWriter writer(
Snapshot::kFull, /*vm_snapshot_data=*/nullptr, &isolate_snapshot_data,
/*vm_image_writer=*/nullptr, /*iso_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);
HANDLESCOPE(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);
HANDLESCOPE(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);
HANDLESCOPE(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(DART_INT64_C(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);
HANDLESCOPE(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(DART_INT64_C(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);
HANDLESCOPE(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