|  | // 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 = NULL; | 
|  | 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 == NULL); | 
|  | 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 == NULL); | 
|  | CheckEncodeDecodeMessage(scope.zone(), root); | 
|  | } | 
|  |  | 
|  | VM_UNIT_TEST_CASE(FullSnapshot) { | 
|  | // clang-format off | 
|  | auto kScriptChars = Utils::CStringUniquePtr( | 
|  | OS::SCreate( | 
|  | nullptr, | 
|  | "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%s fld3;\n" | 
|  | "  static const int smi_sfld = 10;\n" | 
|  | "  static const int bigint_sfld = 0xfffffffffff;\n" | 
|  | "}\n" | 
|  | "class Expect {\n" | 
|  | "  static void equals(x, y) {\n" | 
|  | "    if (x != y) throw new ArgumentError('not equal');\n" | 
|  | "  }\n" | 
|  | "}\n" | 
|  | "class FieldsTest {\n" | 
|  | "  static Fields testMain() {\n" | 
|  | "    Expect.equals(true, Fields.bigint_sfld == 0xfffffffffff);\n" | 
|  | "    Fields obj = new Fields(10, 20);\n" | 
|  | "    Expect.equals(true, obj.bigint_fld == 0xfffffffffff);\n" | 
|  | "    return obj;\n" | 
|  | "  }\n" | 
|  | "}\n", | 
|  | TestCase::NullableTag()), | 
|  | std::free); | 
|  | // 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.get(), NULL); | 
|  |  | 
|  | Thread* thread = Thread::Current(); | 
|  | TransitionNativeToVM transition(thread); | 
|  | StackZone zone(thread); | 
|  | HandleScope scope(thread); | 
|  |  | 
|  | Dart_Handle result = Api::CheckAndFinalizePendingClasses(thread); | 
|  | { | 
|  | TransitionVMToNative to_native(thread); | 
|  | EXPECT_VALID(result); | 
|  | } | 
|  | timer1.Stop(); | 
|  | OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime()); | 
|  |  | 
|  | // Write snapshot with object content. | 
|  | 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, NULL); | 
|  | 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()); | 
|  | result = Dart_Invoke(lib, NewString(dart_function), 0, NULL); | 
|  | EXPECT_VALID(result); | 
|  | } | 
|  | Object& obj = Object::Handle(Api::UnwrapHandle(result)); | 
|  |  | 
|  | // Serialize the object into a message. | 
|  | 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" | 
|  | "getSmi() {\n" | 
|  | "  return 42;\n" | 
|  | "}\n" | 
|  | "getAsciiString() {\n" | 
|  | "  return \"Hello, world!\";\n" | 
|  | "}\n" | 
|  | "getNonAsciiString() {\n" | 
|  | "  return \"Blåbærgrød\";\n" | 
|  | "}\n" | 
|  | "getNonBMPString() {\n" | 
|  | "  return \"\\u{10000}\\u{1F601}\\u{1F637}\\u{20000}\";\n" | 
|  | "}\n" | 
|  | "getLeadSurrogateString() {\n" | 
|  | "  return String.fromCharCodes([0xd800]);\n" | 
|  | "}\n" | 
|  | "getTrailSurrogateString() {\n" | 
|  | "  return \"\\u{10000}\".substring(1);\n" | 
|  | "}\n" | 
|  | "getSurrogatesString() {\n" | 
|  | "  return String.fromCharCodes([0xdc00, 0xdc00, 0xd800, 0xd800]);\n" | 
|  | "}\n" | 
|  | "getCrappyString() {\n" | 
|  | "  return String.fromCharCodes([0xd800, 32, 0xdc00, 32]);\n" | 
|  | "}\n" | 
|  | "getList() {\n" | 
|  | "  return List.filled(kArrayLength, null);\n" | 
|  | "}\n"; | 
|  |  | 
|  | TestCase::CreateTestIsolate(); | 
|  | Isolate* isolate = Isolate::Current(); | 
|  | EXPECT(isolate != NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  | Dart_Handle smi_result; | 
|  | smi_result = Dart_Invoke(lib, NewString("getSmi"), 0, NULL); | 
|  | EXPECT_VALID(smi_result); | 
|  |  | 
|  | Dart_Handle ascii_string_result; | 
|  | ascii_string_result = Dart_Invoke(lib, NewString("getAsciiString"), 0, NULL); | 
|  | EXPECT_VALID(ascii_string_result); | 
|  | EXPECT(Dart_IsString(ascii_string_result)); | 
|  |  | 
|  | Dart_Handle non_ascii_string_result; | 
|  | non_ascii_string_result = | 
|  | Dart_Invoke(lib, NewString("getNonAsciiString"), 0, NULL); | 
|  | EXPECT_VALID(non_ascii_string_result); | 
|  | EXPECT(Dart_IsString(non_ascii_string_result)); | 
|  |  | 
|  | Dart_Handle non_bmp_string_result; | 
|  | non_bmp_string_result = | 
|  | Dart_Invoke(lib, NewString("getNonBMPString"), 0, NULL); | 
|  | EXPECT_VALID(non_bmp_string_result); | 
|  | EXPECT(Dart_IsString(non_bmp_string_result)); | 
|  |  | 
|  | Dart_Handle lead_surrogate_string_result; | 
|  | lead_surrogate_string_result = | 
|  | Dart_Invoke(lib, NewString("getLeadSurrogateString"), 0, NULL); | 
|  | EXPECT_VALID(lead_surrogate_string_result); | 
|  | EXPECT(Dart_IsString(lead_surrogate_string_result)); | 
|  |  | 
|  | Dart_Handle trail_surrogate_string_result; | 
|  | trail_surrogate_string_result = | 
|  | Dart_Invoke(lib, NewString("getTrailSurrogateString"), 0, NULL); | 
|  | EXPECT_VALID(trail_surrogate_string_result); | 
|  | EXPECT(Dart_IsString(trail_surrogate_string_result)); | 
|  |  | 
|  | Dart_Handle surrogates_string_result; | 
|  | surrogates_string_result = | 
|  | Dart_Invoke(lib, NewString("getSurrogatesString"), 0, NULL); | 
|  | EXPECT_VALID(surrogates_string_result); | 
|  | EXPECT(Dart_IsString(surrogates_string_result)); | 
|  |  | 
|  | Dart_Handle crappy_string_result; | 
|  | crappy_string_result = | 
|  | Dart_Invoke(lib, NewString("getCrappyString"), 0, NULL); | 
|  | EXPECT_VALID(crappy_string_result); | 
|  | EXPECT(Dart_IsString(crappy_string_result)); | 
|  |  | 
|  | { | 
|  | Thread* thread = Thread::Current(); | 
|  | CHECK_API_SCOPE(thread); | 
|  | TransitionNativeToVM transition(thread); | 
|  | HANDLESCOPE(thread); | 
|  |  | 
|  | { | 
|  | StackZone zone(thread); | 
|  | Smi& smi = Smi::Handle(); | 
|  | smi ^= Api::UnwrapHandle(smi_result); | 
|  | 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; | 
|  | static 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() != NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  |  | 
|  | { | 
|  | CHECK_API_SCOPE(thread); | 
|  | TransitionNativeToVM transition(thread); | 
|  | HANDLESCOPE(thread); | 
|  | StackZone zone(thread); | 
|  | { | 
|  | // Generate a list of nulls from Dart code. | 
|  | 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; | 
|  | static const char* kScriptChars = | 
|  | "final int kArrayLength = 10;\n" | 
|  | "getList() {\n" | 
|  | "  return [null, null, null, null, null, null, null, null, null, null];\n" | 
|  | "}\n" | 
|  | "getIntList() {\n" | 
|  | "  return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n" | 
|  | "}\n" | 
|  | "getStringList() {\n" | 
|  | "  return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];\n" | 
|  | "}\n" | 
|  | "getListList() {\n" | 
|  | "  return <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() != NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  |  | 
|  | { | 
|  | CHECK_API_SCOPE(thread); | 
|  | TransitionNativeToVM transition(thread); | 
|  | HANDLESCOPE(thread); | 
|  | StackZone zone(thread); | 
|  | { | 
|  | // Generate a list of nulls from Dart code. | 
|  | 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; | 
|  | static 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() != NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  |  | 
|  | { | 
|  | CHECK_API_SCOPE(thread); | 
|  | TransitionNativeToVM transition(thread); | 
|  | HANDLESCOPE(thread); | 
|  | StackZone zone(thread); | 
|  | { | 
|  | // Generate a list of strings from Dart code. | 
|  | 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; | 
|  | static const char* kScriptChars = | 
|  | "import 'dart:typed_data';\n" | 
|  | "final int kArrayLength = 10;\n" | 
|  | "getStringList() {\n" | 
|  | "  var s = 'Hello, world!';\n" | 
|  | "  var list = [s, s, s, s, s, s, s, s, s, s];\n" | 
|  | "  return list;\n" | 
|  | "}\n" | 
|  | "getMintList() {\n" | 
|  | "  var mint = 0x7FFFFFFFFFFFFFFF;\n" | 
|  | "  var list = [mint, mint, mint, mint, mint,\n" | 
|  | "              mint, mint, mint, mint, mint];\n" | 
|  | "  return list;\n" | 
|  | "}\n" | 
|  | "getDoubleList() {\n" | 
|  | "  var d = 3.14;\n" | 
|  | "  var list = [3.14, 3.14, 3.14, 3.14, 3.14, 3.14];\n" | 
|  | "  list.add(3.14);\n" | 
|  | "  list.add(3.14);\n" | 
|  | "  list.add(3.14);\n" | 
|  | "  list.add(3.14);\n" | 
|  | "  return list;\n" | 
|  | "}\n" | 
|  | "getTypedDataList() {\n" | 
|  | "  var byte_array = new Uint8List(256);\n" | 
|  | "  var list = [];\n" | 
|  | "  for (var i = 0; i < kArrayLength; i++) {\n" | 
|  | "    list.add(byte_array);\n" | 
|  | "  }\n" | 
|  | "  return list;\n" | 
|  | "}\n" | 
|  | "getTypedDataViewList() {\n" | 
|  | "  var uint8_list = new Uint8List(256);\n" | 
|  | "  uint8_list[64] = 1;\n" | 
|  | "  var uint8_list_view =\n" | 
|  | "      new Uint8List.view(uint8_list.buffer, 64, 128);\n" | 
|  | "  var list = [];\n" | 
|  | "  for (var i = 0; i < kArrayLength; i++) {\n" | 
|  | "    list.add(uint8_list_view);\n" | 
|  | "  }\n" | 
|  | "  return list;\n" | 
|  | "}\n" | 
|  | "getMixedList() {\n" | 
|  | "  var list = [];\n" | 
|  | "  for (var i = 0; i < kArrayLength; i++) {\n" | 
|  | "    list.add(((i % 2) == 0) ? '.' : 2.72);\n" | 
|  | "  }\n" | 
|  | "  return list;\n" | 
|  | "}\n" | 
|  | "getSelfRefList() {\n" | 
|  | "  var list = [];\n" | 
|  | "  for (var i = 0; i < kArrayLength; i++) {\n" | 
|  | "    list.add(list);\n" | 
|  | "  }\n" | 
|  | "  return list;\n" | 
|  | "}\n"; | 
|  |  | 
|  | TestCase::CreateTestIsolate(); | 
|  | Thread* thread = Thread::Current(); | 
|  | EXPECT(thread->isolate() != NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  |  | 
|  | { | 
|  | CHECK_API_SCOPE(thread); | 
|  | TransitionNativeToVM transition(thread); | 
|  | HANDLESCOPE(thread); | 
|  | StackZone zone(thread); | 
|  | { | 
|  | // Generate a list of strings from Dart code. | 
|  | 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() != NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  |  | 
|  | { | 
|  | CHECK_API_SCOPE(thread); | 
|  | TransitionNativeToVM transition(thread); | 
|  | HANDLESCOPE(thread); | 
|  | StackZone zone(thread); | 
|  | { | 
|  | // Generate a list of Uint8Lists from Dart code. | 
|  | 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, NULL); | 
|  | Dart_EnterScope(); | 
|  |  | 
|  | Dart_Handle send_port = Dart_Invoke(lib, NewString("main"), 0, NULL); | 
|  | EXPECT_VALID(send_port); | 
|  | Dart_Port port_id; | 
|  | Dart_Handle result = Dart_SendPortGetId(send_port, &port_id); | 
|  | ASSERT(!Dart_IsError(result)); | 
|  |  | 
|  | // Setup single object message. | 
|  | Dart_CObject object; | 
|  |  | 
|  | object.type = Dart_CObject_kNull; | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kBool; | 
|  | object.value.as_bool = true; | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kBool; | 
|  | object.value.as_bool = false; | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kInt32; | 
|  | object.value.as_int32 = 123; | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kString; | 
|  | object.value.as_string = const_cast<char*>("456"); | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kString; | 
|  | object.value.as_string = const_cast<char*>("æøå"); | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kString; | 
|  | object.value.as_string = const_cast<char*>(""); | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kDouble; | 
|  | object.value.as_double = 3.14; | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | object.type = Dart_CObject_kArray; | 
|  | object.value.as_array.length = 0; | 
|  | EXPECT(Dart_PostCObject(port_id, &object)); | 
|  |  | 
|  | static const int kArrayLength = 10; | 
|  | Dart_CObject* array = reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate( | 
|  | sizeof(Dart_CObject) + sizeof(Dart_CObject*) * kArrayLength));  // NOLINT | 
|  | array->type = Dart_CObject_kArray; | 
|  | array->value.as_array.length = kArrayLength; | 
|  | array->value.as_array.values = reinterpret_cast<Dart_CObject**>(array + 1); | 
|  | for (int i = 0; i < kArrayLength; i++) { | 
|  | Dart_CObject* element = reinterpret_cast<Dart_CObject*>( | 
|  | Dart_ScopeAllocate(sizeof(Dart_CObject))); | 
|  | element->type = Dart_CObject_kInt32; | 
|  | element->value.as_int32 = i; | 
|  | array->value.as_array.values[i] = element; | 
|  | } | 
|  | EXPECT(Dart_PostCObject(port_id, array)); | 
|  |  | 
|  | 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(NULL, 0)); | 
|  |  | 
|  | uint8_t buffer[4] = {0, 0, 0, 0}; | 
|  | EXPECT(!Dart_IsKernel(buffer, ARRAY_SIZE(buffer))); | 
|  | } | 
|  |  | 
|  | VM_UNIT_TEST_CASE(LegacyErasureDetectionInFullSnapshot) { | 
|  | const char* kScriptChars = | 
|  | "class Generic<T> {\n" | 
|  | "  const Generic();\n" | 
|  | "  static const Generic<int> g = const Generic<int>();\n" | 
|  | "  static testMain() => g.runtimeType;\n" | 
|  | "}\n"; | 
|  |  | 
|  | // Start an Isolate, load and execute a script and check if legacy erasure is | 
|  | // required, preventing to write a full snapshot. | 
|  | { | 
|  | TestIsolateScope __test_isolate__; | 
|  |  | 
|  | // Create a test library and Load up a test script in it. | 
|  | Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); | 
|  | EXPECT_VALID(lib); | 
|  |  | 
|  | Thread* thread = Thread::Current(); | 
|  | Isolate* isolate = thread->isolate(); | 
|  | ASSERT(isolate == __test_isolate__.isolate()); | 
|  | TransitionNativeToVM transition(thread); | 
|  | StackZone zone(thread); | 
|  | HandleScope scope(thread); | 
|  |  | 
|  | Dart_Handle result = Api::CheckAndFinalizePendingClasses(thread); | 
|  | Dart_Handle cls; | 
|  | { | 
|  | TransitionVMToNative to_native(thread); | 
|  | EXPECT_VALID(result); | 
|  |  | 
|  | // Invoke a function so that the constant is evaluated. | 
|  | cls = Dart_GetClass(TestCase::lib(), NewString("Generic")); | 
|  | result = Dart_Invoke(cls, NewString("testMain"), 0, NULL); | 
|  | EXPECT_VALID(result); | 
|  | } | 
|  | // Verify that legacy erasure is required in strong mode. | 
|  | Type& type = Type::Handle(); | 
|  | type ^= Api::UnwrapHandle(cls);  // Dart_GetClass actually returns a Type. | 
|  | const Class& clazz = Class::Handle(type.type_class()); | 
|  | const bool required = | 
|  | clazz.RequireCanonicalTypeErasureOfConstants(zone.GetZone()); | 
|  | EXPECT(required == isolate->group()->null_safety()); | 
|  |  | 
|  | // Verify that snapshot writing succeeds if erasure is not required. | 
|  | if (!required) { | 
|  | // Write snapshot with object content. | 
|  | MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize); | 
|  | FullSnapshotWriter writer( | 
|  | Snapshot::kFullCore, /*vm_snapshot_data=*/nullptr, | 
|  | &isolate_snapshot_data, | 
|  | /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr); | 
|  | writer.WriteFullSnapshot(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace dart |