1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6
7#include "include/dart_tools_api.h"
8#include "platform/assert.h"
9#include "platform/unicode.h"
10#include "vm/class_finalizer.h"
11#include "vm/clustered_snapshot.h"
12#include "vm/dart_api_impl.h"
13#include "vm/dart_api_message.h"
14#include "vm/dart_api_state.h"
15#include "vm/debugger_api_impl_test.h"
16#include "vm/flags.h"
17#include "vm/malloc_hooks.h"
18#include "vm/snapshot.h"
19#include "vm/symbols.h"
20#include "vm/timer.h"
21#include "vm/unit_test.h"
22
23namespace dart {
24
25// Check if serialized and deserialized objects are equal.
26static bool Equals(const Object& expected, const Object& actual) {
27 if (expected.IsNull()) {
28 return actual.IsNull();
29 }
30 if (expected.IsSmi()) {
31 if (actual.IsSmi()) {
32 return expected.raw() == actual.raw();
33 }
34 return false;
35 }
36 if (expected.IsDouble()) {
37 if (actual.IsDouble()) {
38 Double& dbl1 = Double::Handle();
39 Double& dbl2 = Double::Handle();
40 dbl1 ^= expected.raw();
41 dbl2 ^= actual.raw();
42 return dbl1.value() == dbl2.value();
43 }
44 return false;
45 }
46 if (expected.IsBool()) {
47 if (actual.IsBool()) {
48 return expected.raw() == actual.raw();
49 }
50 return false;
51 }
52 return false;
53}
54
55static uint8_t* malloc_allocator(uint8_t* ptr,
56 intptr_t old_size,
57 intptr_t new_size) {
58 return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
59}
60
61// Compare two Dart_CObject object graphs rooted in first and
62// second. The second graph will be destroyed by this operation no matter
63// whether the graphs are equal or not.
64static void CompareDartCObjects(Dart_CObject* first, Dart_CObject* second) {
65 // Return immediately if entering a cycle.
66 if (second->type == Dart_CObject_kNumberOfTypes) return;
67
68 EXPECT_NE(first, second);
69 EXPECT_EQ(first->type, second->type);
70 switch (first->type) {
71 case Dart_CObject_kNull:
72 // Nothing more to compare.
73 break;
74 case Dart_CObject_kBool:
75 EXPECT_EQ(first->value.as_bool, second->value.as_bool);
76 break;
77 case Dart_CObject_kInt32:
78 EXPECT_EQ(first->value.as_int32, second->value.as_int32);
79 break;
80 case Dart_CObject_kInt64:
81 EXPECT_EQ(first->value.as_int64, second->value.as_int64);
82 break;
83 case Dart_CObject_kDouble:
84 EXPECT_EQ(first->value.as_double, second->value.as_double);
85 break;
86 case Dart_CObject_kString:
87 EXPECT_STREQ(first->value.as_string, second->value.as_string);
88 break;
89 case Dart_CObject_kTypedData:
90 EXPECT_EQ(first->value.as_typed_data.length,
91 second->value.as_typed_data.length);
92 for (int i = 0; i < first->value.as_typed_data.length; i++) {
93 EXPECT_EQ(first->value.as_typed_data.values[i],
94 second->value.as_typed_data.values[i]);
95 }
96 break;
97 case Dart_CObject_kArray:
98 // Use invalid type as a visited marker to avoid infinite
99 // recursion on graphs with cycles.
100 second->type = Dart_CObject_kNumberOfTypes;
101 EXPECT_EQ(first->value.as_array.length, second->value.as_array.length);
102 for (int i = 0; i < first->value.as_array.length; i++) {
103 CompareDartCObjects(first->value.as_array.values[i],
104 second->value.as_array.values[i]);
105 }
106 break;
107 case Dart_CObject_kCapability:
108 EXPECT_EQ(first->value.as_capability.id, second->value.as_capability.id);
109 break;
110 default:
111 EXPECT(false);
112 }
113}
114
115static void CheckEncodeDecodeMessage(Dart_CObject* root) {
116 // Encode and decode the message.
117 ApiMessageWriter writer;
118 std::unique_ptr<Message> message =
119 writer.WriteCMessage(root, ILLEGAL_PORT, Message::kNormalPriority);
120
121 ApiMessageReader api_reader(message.get());
122 Dart_CObject* new_root = api_reader.ReadMessage();
123
124 // Check that the two messages are the same.
125 CompareDartCObjects(root, new_root);
126}
127
128static void ExpectEncodeFail(Dart_CObject* root) {
129 ApiMessageWriter writer;
130 std::unique_ptr<Message> message =
131 writer.WriteCMessage(root, ILLEGAL_PORT, Message::kNormalPriority);
132 EXPECT(message == nullptr);
133}
134
135ISOLATE_UNIT_TEST_CASE(SerializeNull) {
136 StackZone zone(thread);
137
138 // Write snapshot with object content.
139 const Object& null_object = Object::Handle();
140 MessageWriter writer(true);
141 std::unique_ptr<Message> message =
142 writer.WriteMessage(null_object, ILLEGAL_PORT, Message::kNormalPriority);
143
144 // Read object back from the snapshot.
145 MessageSnapshotReader reader(message.get(), thread);
146 const Object& serialized_object = Object::Handle(reader.ReadObject());
147 EXPECT(Equals(null_object, serialized_object));
148
149 // Read object back from the snapshot into a C structure.
150 ApiNativeScope scope;
151 ApiMessageReader api_reader(message.get());
152 Dart_CObject* root = api_reader.ReadMessage();
153 EXPECT_NOTNULL(root);
154 EXPECT_EQ(Dart_CObject_kNull, root->type);
155 CheckEncodeDecodeMessage(root);
156}
157
158ISOLATE_UNIT_TEST_CASE(SerializeSmi1) {
159 StackZone zone(thread);
160
161 // Write snapshot with object content.
162 const Smi& smi = Smi::Handle(Smi::New(124));
163 MessageWriter writer(true);
164 std::unique_ptr<Message> message =
165 writer.WriteMessage(smi, ILLEGAL_PORT, Message::kNormalPriority);
166
167 // Read object back from the snapshot.
168 MessageSnapshotReader reader(message.get(), thread);
169 const Object& serialized_object = Object::Handle(reader.ReadObject());
170 EXPECT(Equals(smi, serialized_object));
171
172 // Read object back from the snapshot into a C structure.
173 ApiNativeScope scope;
174 ApiMessageReader api_reader(message.get());
175 Dart_CObject* root = api_reader.ReadMessage();
176 EXPECT_NOTNULL(root);
177 EXPECT_EQ(Dart_CObject_kInt32, root->type);
178 EXPECT_EQ(smi.Value(), root->value.as_int32);
179 CheckEncodeDecodeMessage(root);
180}
181
182ISOLATE_UNIT_TEST_CASE(SerializeSmi2) {
183 StackZone zone(thread);
184
185 // Write snapshot with object content.
186 const Smi& smi = Smi::Handle(Smi::New(-1));
187 MessageWriter writer(true);
188 std::unique_ptr<Message> message =
189 writer.WriteMessage(smi, ILLEGAL_PORT, Message::kNormalPriority);
190
191 // Read object back from the snapshot.
192 MessageSnapshotReader reader(message.get(), thread);
193 const Object& serialized_object = Object::Handle(reader.ReadObject());
194 EXPECT(Equals(smi, serialized_object));
195
196 // Read object back from the snapshot into a C structure.
197 ApiNativeScope scope;
198 ApiMessageReader api_reader(message.get());
199 Dart_CObject* root = api_reader.ReadMessage();
200 EXPECT_NOTNULL(root);
201 EXPECT_EQ(Dart_CObject_kInt32, root->type);
202 EXPECT_EQ(smi.Value(), root->value.as_int32);
203 CheckEncodeDecodeMessage(root);
204}
205
206Dart_CObject* SerializeAndDeserializeMint(const Mint& mint) {
207 // Write snapshot with object content.
208 MessageWriter writer(true);
209 std::unique_ptr<Message> message =
210 writer.WriteMessage(mint, ILLEGAL_PORT, Message::kNormalPriority);
211
212 {
213 // Switch to a regular zone, where VM handle allocation is allowed.
214 Thread* thread = Thread::Current();
215 StackZone zone(thread);
216 // Read object back from the snapshot.
217 MessageSnapshotReader reader(message.get(), thread);
218 const Object& serialized_object = Object::Handle(reader.ReadObject());
219 EXPECT(serialized_object.IsMint());
220 }
221
222 // Read object back from the snapshot into a C structure.
223 ApiMessageReader api_reader(message.get());
224 Dart_CObject* root = api_reader.ReadMessage();
225 EXPECT_NOTNULL(root);
226 CheckEncodeDecodeMessage(root);
227 return root;
228}
229
230void CheckMint(int64_t value) {
231 ApiNativeScope scope;
232 StackZone zone(Thread::Current());
233
234 Mint& mint = Mint::Handle();
235 mint ^= Integer::New(value);
236 Dart_CObject* mint_cobject = SerializeAndDeserializeMint(mint);
237// On 64-bit platforms mints always require 64-bits as the smi range
238// here covers most of the 64-bit range. On 32-bit platforms the smi
239// range covers most of the 32-bit range and values outside that
240// range are also represented as mints.
241#if defined(ARCH_IS_64_BIT)
242 EXPECT_EQ(Dart_CObject_kInt64, mint_cobject->type);
243 EXPECT_EQ(value, mint_cobject->value.as_int64);
244#else
245 if (kMinInt32 < value && value < kMaxInt32) {
246 EXPECT_EQ(Dart_CObject_kInt32, mint_cobject->type);
247 EXPECT_EQ(value, mint_cobject->value.as_int32);
248 } else {
249 EXPECT_EQ(Dart_CObject_kInt64, mint_cobject->type);
250 EXPECT_EQ(value, mint_cobject->value.as_int64);
251 }
252#endif
253}
254
255ISOLATE_UNIT_TEST_CASE(SerializeMints) {
256 // Min positive mint.
257 CheckMint(Smi::kMaxValue + 1);
258 // Min positive mint + 1.
259 CheckMint(Smi::kMaxValue + 2);
260 // Max negative mint.
261 CheckMint(Smi::kMinValue - 1);
262 // Max negative mint - 1.
263 CheckMint(Smi::kMinValue - 2);
264 // Max positive mint.
265 CheckMint(kMaxInt64);
266 // Max positive mint - 1.
267 CheckMint(kMaxInt64 - 1);
268 // Min negative mint.
269 CheckMint(kMinInt64);
270 // Min negative mint + 1.
271 CheckMint(kMinInt64 + 1);
272}
273
274ISOLATE_UNIT_TEST_CASE(SerializeDouble) {
275 StackZone zone(thread);
276
277 // Write snapshot with object content.
278 const Double& dbl = Double::Handle(Double::New(101.29));
279 MessageWriter writer(true);
280 std::unique_ptr<Message> message =
281 writer.WriteMessage(dbl, ILLEGAL_PORT, Message::kNormalPriority);
282
283 // Read object back from the snapshot.
284 MessageSnapshotReader reader(message.get(), thread);
285 const Object& serialized_object = Object::Handle(reader.ReadObject());
286 EXPECT(Equals(dbl, serialized_object));
287
288 // Read object back from the snapshot into a C structure.
289 ApiNativeScope scope;
290 ApiMessageReader api_reader(message.get());
291 Dart_CObject* root = api_reader.ReadMessage();
292 EXPECT_NOTNULL(root);
293 EXPECT_EQ(Dart_CObject_kDouble, root->type);
294 EXPECT_EQ(dbl.value(), root->value.as_double);
295 CheckEncodeDecodeMessage(root);
296}
297
298ISOLATE_UNIT_TEST_CASE(SerializeTrue) {
299 StackZone zone(thread);
300
301 // Write snapshot with true object.
302 const Bool& bl = Bool::True();
303 MessageWriter writer(true);
304 std::unique_ptr<Message> message =
305 writer.WriteMessage(bl, ILLEGAL_PORT, Message::kNormalPriority);
306
307 // Read object back from the snapshot.
308 MessageSnapshotReader reader(message.get(), thread);
309 const Object& serialized_object = Object::Handle(reader.ReadObject());
310 fprintf(stderr, "%s / %s\n", bl.ToCString(), serialized_object.ToCString());
311
312 EXPECT(Equals(bl, serialized_object));
313
314 // Read object back from the snapshot into a C structure.
315 ApiNativeScope scope;
316 ApiMessageReader api_reader(message.get());
317 Dart_CObject* root = api_reader.ReadMessage();
318 EXPECT_NOTNULL(root);
319 EXPECT_EQ(Dart_CObject_kBool, root->type);
320 EXPECT_EQ(true, root->value.as_bool);
321 CheckEncodeDecodeMessage(root);
322}
323
324ISOLATE_UNIT_TEST_CASE(SerializeFalse) {
325 StackZone zone(thread);
326
327 // Write snapshot with false object.
328 const Bool& bl = Bool::False();
329 MessageWriter writer(true);
330 std::unique_ptr<Message> message =
331 writer.WriteMessage(bl, ILLEGAL_PORT, Message::kNormalPriority);
332
333 // Read object back from the snapshot.
334 MessageSnapshotReader reader(message.get(), thread);
335 const Object& serialized_object = Object::Handle(reader.ReadObject());
336 EXPECT(Equals(bl, serialized_object));
337
338 // Read object back from the snapshot into a C structure.
339 ApiNativeScope scope;
340 ApiMessageReader api_reader(message.get());
341 Dart_CObject* root = api_reader.ReadMessage();
342 EXPECT_NOTNULL(root);
343 EXPECT_EQ(Dart_CObject_kBool, root->type);
344 EXPECT_EQ(false, root->value.as_bool);
345 CheckEncodeDecodeMessage(root);
346}
347
348ISOLATE_UNIT_TEST_CASE(SerializeCapability) {
349 // Write snapshot with object content.
350 const Capability& capability = Capability::Handle(Capability::New(12345));
351 MessageWriter writer(true);
352 std::unique_ptr<Message> message =
353 writer.WriteMessage(capability, ILLEGAL_PORT, Message::kNormalPriority);
354
355 // Read object back from the snapshot.
356 MessageSnapshotReader reader(message.get(), thread);
357 Capability& obj = Capability::Handle();
358 obj ^= reader.ReadObject();
359
360 EXPECT_EQ(static_cast<uint64_t>(12345), obj.Id());
361
362 // Read object back from the snapshot into a C structure.
363 ApiNativeScope scope;
364 ApiMessageReader api_reader(message.get());
365 Dart_CObject* root = api_reader.ReadMessage();
366 EXPECT_NOTNULL(root);
367 EXPECT_EQ(Dart_CObject_kCapability, root->type);
368 int64_t id = root->value.as_capability.id;
369 EXPECT_EQ(12345, id);
370 CheckEncodeDecodeMessage(root);
371}
372
373#define TEST_ROUND_TRIP_IDENTICAL(object) \
374 { \
375 MessageWriter writer(true); \
376 std::unique_ptr<Message> message = writer.WriteMessage( \
377 Object::Handle(object), ILLEGAL_PORT, Message::kNormalPriority); \
378 MessageSnapshotReader reader(message.get(), thread); \
379 EXPECT(reader.ReadObject() == object); \
380 }
381
382ISOLATE_UNIT_TEST_CASE(SerializeSingletons) {
383 TEST_ROUND_TRIP_IDENTICAL(Object::class_class());
384 TEST_ROUND_TRIP_IDENTICAL(Object::type_arguments_class());
385 TEST_ROUND_TRIP_IDENTICAL(Object::function_class());
386 TEST_ROUND_TRIP_IDENTICAL(Object::field_class());
387 TEST_ROUND_TRIP_IDENTICAL(Object::script_class());
388 TEST_ROUND_TRIP_IDENTICAL(Object::library_class());
389 TEST_ROUND_TRIP_IDENTICAL(Object::code_class());
390 TEST_ROUND_TRIP_IDENTICAL(Object::bytecode_class());
391 TEST_ROUND_TRIP_IDENTICAL(Object::instructions_class());
392 TEST_ROUND_TRIP_IDENTICAL(Object::pc_descriptors_class());
393 TEST_ROUND_TRIP_IDENTICAL(Object::exception_handlers_class());
394 TEST_ROUND_TRIP_IDENTICAL(Object::context_class());
395 TEST_ROUND_TRIP_IDENTICAL(Object::context_scope_class());
396}
397
398static void TestString(const char* cstr) {
399 Thread* thread = Thread::Current();
400 EXPECT(Utf8::IsValid(reinterpret_cast<const uint8_t*>(cstr), strlen(cstr)));
401 // Write snapshot with object content.
402 String& str = String::Handle(String::New(cstr));
403 MessageWriter writer(true);
404 std::unique_ptr<Message> message =
405 writer.WriteMessage(str, ILLEGAL_PORT, Message::kNormalPriority);
406
407 // Read object back from the snapshot.
408 MessageSnapshotReader reader(message.get(), thread);
409 String& serialized_str = String::Handle();
410 serialized_str ^= reader.ReadObject();
411 EXPECT(str.Equals(serialized_str));
412
413 // Read object back from the snapshot into a C structure.
414 ApiNativeScope scope;
415 ApiMessageReader api_reader(message.get());
416 Dart_CObject* root = api_reader.ReadMessage();
417 EXPECT_EQ(Dart_CObject_kString, root->type);
418 EXPECT_STREQ(cstr, root->value.as_string);
419 CheckEncodeDecodeMessage(root);
420}
421
422ISOLATE_UNIT_TEST_CASE(SerializeString) {
423 TestString("This string shall be serialized");
424 TestString("æøå"); // This file is UTF-8 encoded.
425 const char* data =
426 "\x01"
427 "\x7F"
428 "\xC2\x80" // U+0080
429 "\xDF\xBF" // U+07FF
430 "\xE0\xA0\x80" // U+0800
431 "\xEF\xBF\xBF"; // U+FFFF
432
433 TestString(data);
434 // TODO(sgjesse): Add tests with non-BMP characters.
435}
436
437ISOLATE_UNIT_TEST_CASE(SerializeArray) {
438 // Write snapshot with object content.
439 const int kArrayLength = 10;
440 Array& array = Array::Handle(Array::New(kArrayLength));
441 Smi& smi = Smi::Handle();
442 for (int i = 0; i < kArrayLength; i++) {
443 smi ^= Smi::New(i);
444 array.SetAt(i, smi);
445 }
446 MessageWriter writer(true);
447 std::unique_ptr<Message> message =
448 writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority);
449
450 // Read object back from the snapshot.
451 MessageSnapshotReader reader(message.get(), thread);
452 Array& serialized_array = Array::Handle();
453 serialized_array ^= reader.ReadObject();
454 EXPECT(array.CanonicalizeEquals(serialized_array));
455
456 // Read object back from the snapshot into a C structure.
457 ApiNativeScope scope;
458 ApiMessageReader api_reader(message.get());
459 Dart_CObject* root = api_reader.ReadMessage();
460 EXPECT_EQ(Dart_CObject_kArray, root->type);
461 EXPECT_EQ(kArrayLength, root->value.as_array.length);
462 for (int i = 0; i < kArrayLength; i++) {
463 Dart_CObject* element = root->value.as_array.values[i];
464 EXPECT_EQ(Dart_CObject_kInt32, element->type);
465 EXPECT_EQ(i, element->value.as_int32);
466 }
467 CheckEncodeDecodeMessage(root);
468}
469
470ISOLATE_UNIT_TEST_CASE(SerializeArrayWithTypeArgument) {
471 // Write snapshot with object content.
472 const int kArrayLength = 10;
473 Array& array =
474 Array::Handle(Array::New(kArrayLength, Type::Handle(Type::ObjectType())));
475
476 Smi& smi = Smi::Handle();
477 for (int i = 0; i < kArrayLength; i++) {
478 smi ^= Smi::New(i);
479 array.SetAt(i, smi);
480 }
481 MessageWriter writer(true);
482 std::unique_ptr<Message> message =
483 writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority);
484
485 // Read object back from the snapshot.
486 MessageSnapshotReader reader(message.get(), thread);
487 Array& serialized_array = Array::Handle();
488 serialized_array ^= reader.ReadObject();
489 EXPECT(array.CanonicalizeEquals(serialized_array));
490
491 // Read object back from the snapshot into a C structure.
492 ApiNativeScope scope;
493 ApiMessageReader api_reader(message.get());
494 Dart_CObject* root = api_reader.ReadMessage();
495 EXPECT_EQ(Dart_CObject_kArray, root->type);
496 EXPECT_EQ(kArrayLength, root->value.as_array.length);
497 for (int i = 0; i < kArrayLength; i++) {
498 Dart_CObject* element = root->value.as_array.values[i];
499 EXPECT_EQ(Dart_CObject_kInt32, element->type);
500 EXPECT_EQ(i, element->value.as_int32);
501 }
502 CheckEncodeDecodeMessage(root);
503}
504
505TEST_CASE(FailSerializeLargeArray) {
506 Dart_CObject root;
507 root.type = Dart_CObject_kArray;
508 root.value.as_array.length = Array::kMaxElements + 1;
509 root.value.as_array.values = NULL;
510 ExpectEncodeFail(&root);
511}
512
513TEST_CASE(FailSerializeLargeNestedArray) {
514 Dart_CObject parent;
515 Dart_CObject child;
516 Dart_CObject* values[1] = {&child};
517
518 parent.type = Dart_CObject_kArray;
519 parent.value.as_array.length = 1;
520 parent.value.as_array.values = values;
521 child.type = Dart_CObject_kArray;
522 child.value.as_array.length = Array::kMaxElements + 1;
523 ExpectEncodeFail(&parent);
524}
525
526TEST_CASE(FailSerializeLargeTypedDataInt8) {
527 Dart_CObject root;
528 root.type = Dart_CObject_kTypedData;
529 root.value.as_typed_data.type = Dart_TypedData_kInt8;
530 root.value.as_typed_data.length =
531 TypedData::MaxElements(kTypedDataInt8ArrayCid) + 1;
532 ExpectEncodeFail(&root);
533}
534
535TEST_CASE(FailSerializeLargeTypedDataUint8) {
536 Dart_CObject root;
537 root.type = Dart_CObject_kTypedData;
538 root.value.as_typed_data.type = Dart_TypedData_kUint8;
539 root.value.as_typed_data.length =
540 TypedData::MaxElements(kTypedDataUint8ArrayCid) + 1;
541 ExpectEncodeFail(&root);
542}
543
544TEST_CASE(FailSerializeLargeExternalTypedData) {
545 Dart_CObject root;
546 root.type = Dart_CObject_kExternalTypedData;
547 root.value.as_typed_data.length =
548 ExternalTypedData::MaxElements(kExternalTypedDataUint8ArrayCid) + 1;
549 ExpectEncodeFail(&root);
550}
551
552ISOLATE_UNIT_TEST_CASE(SerializeEmptyArray) {
553 // Write snapshot with object content.
554 const int kArrayLength = 0;
555 Array& array = Array::Handle(Array::New(kArrayLength));
556 MessageWriter writer(true);
557 std::unique_ptr<Message> message =
558 writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority);
559
560 // Read object back from the snapshot.
561 MessageSnapshotReader reader(message.get(), thread);
562 Array& serialized_array = Array::Handle();
563 serialized_array ^= reader.ReadObject();
564 EXPECT(array.CanonicalizeEquals(serialized_array));
565
566 // Read object back from the snapshot into a C structure.
567 ApiNativeScope scope;
568 ApiMessageReader api_reader(message.get());
569 Dart_CObject* root = api_reader.ReadMessage();
570 EXPECT_EQ(Dart_CObject_kArray, root->type);
571 EXPECT_EQ(kArrayLength, root->value.as_array.length);
572 EXPECT(root->value.as_array.values == NULL);
573 CheckEncodeDecodeMessage(root);
574}
575
576ISOLATE_UNIT_TEST_CASE(SerializeByteArray) {
577 // Write snapshot with object content.
578 const int kTypedDataLength = 256;
579 TypedData& typed_data = TypedData::Handle(
580 TypedData::New(kTypedDataUint8ArrayCid, kTypedDataLength));
581 for (int i = 0; i < kTypedDataLength; i++) {
582 typed_data.SetUint8(i, i);
583 }
584 MessageWriter writer(true);
585 std::unique_ptr<Message> message =
586 writer.WriteMessage(typed_data, ILLEGAL_PORT, Message::kNormalPriority);
587
588 // Read object back from the snapshot.
589 MessageSnapshotReader reader(message.get(), thread);
590 TypedData& serialized_typed_data = TypedData::Handle();
591 serialized_typed_data ^= reader.ReadObject();
592 EXPECT(serialized_typed_data.IsTypedData());
593
594 // Read object back from the snapshot into a C structure.
595 ApiNativeScope scope;
596 ApiMessageReader api_reader(message.get());
597 Dart_CObject* root = api_reader.ReadMessage();
598 EXPECT_EQ(Dart_CObject_kTypedData, root->type);
599 EXPECT_EQ(kTypedDataLength, root->value.as_typed_data.length);
600 for (int i = 0; i < kTypedDataLength; i++) {
601 EXPECT(root->value.as_typed_data.values[i] == i);
602 }
603 CheckEncodeDecodeMessage(root);
604}
605
606#define TEST_TYPED_ARRAY(darttype, ctype) \
607 { \
608 StackZone zone(thread); \
609 const int kArrayLength = 127; \
610 TypedData& array = TypedData::Handle( \
611 TypedData::New(kTypedData##darttype##ArrayCid, kArrayLength)); \
612 intptr_t scale = array.ElementSizeInBytes(); \
613 for (int i = 0; i < kArrayLength; i++) { \
614 array.Set##darttype((i * scale), i); \
615 } \
616 MessageWriter writer(true); \
617 std::unique_ptr<Message> message = \
618 writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority); \
619 MessageSnapshotReader reader(message.get(), thread); \
620 TypedData& serialized_array = TypedData::Handle(); \
621 serialized_array ^= reader.ReadObject(); \
622 for (int i = 0; i < kArrayLength; i++) { \
623 EXPECT_EQ(static_cast<ctype>(i), \
624 serialized_array.Get##darttype(i* scale)); \
625 } \
626 }
627
628#define TEST_EXTERNAL_TYPED_ARRAY(darttype, ctype) \
629 { \
630 StackZone zone(thread); \
631 ctype data[] = {0, 11, 22, 33, 44, 55, 66, 77}; \
632 intptr_t length = ARRAY_SIZE(data); \
633 ExternalTypedData& array = ExternalTypedData::Handle( \
634 ExternalTypedData::New(kExternalTypedData##darttype##ArrayCid, \
635 reinterpret_cast<uint8_t*>(data), length)); \
636 intptr_t scale = array.ElementSizeInBytes(); \
637 MessageWriter writer(true); \
638 std::unique_ptr<Message> message = \
639 writer.WriteMessage(array, ILLEGAL_PORT, Message::kNormalPriority); \
640 MessageSnapshotReader reader(message.get(), thread); \
641 ExternalTypedData& serialized_array = ExternalTypedData::Handle(); \
642 serialized_array ^= reader.ReadObject(); \
643 for (int i = 0; i < length; i++) { \
644 EXPECT_EQ(static_cast<ctype>(data[i]), \
645 serialized_array.Get##darttype(i* scale)); \
646 } \
647 }
648
649ISOLATE_UNIT_TEST_CASE(SerializeTypedArray) {
650 TEST_TYPED_ARRAY(Int8, int8_t);
651 TEST_TYPED_ARRAY(Uint8, uint8_t);
652 TEST_TYPED_ARRAY(Int16, int16_t);
653 TEST_TYPED_ARRAY(Uint16, uint16_t);
654 TEST_TYPED_ARRAY(Int32, int32_t);
655 TEST_TYPED_ARRAY(Uint32, uint32_t);
656 TEST_TYPED_ARRAY(Int64, int64_t);
657 TEST_TYPED_ARRAY(Uint64, uint64_t);
658 TEST_TYPED_ARRAY(Float32, float);
659 TEST_TYPED_ARRAY(Float64, double);
660}
661
662ISOLATE_UNIT_TEST_CASE(SerializeExternalTypedArray) {
663 TEST_EXTERNAL_TYPED_ARRAY(Int8, int8_t);
664 TEST_EXTERNAL_TYPED_ARRAY(Uint8, uint8_t);
665 TEST_EXTERNAL_TYPED_ARRAY(Int16, int16_t);
666 TEST_EXTERNAL_TYPED_ARRAY(Uint16, uint16_t);
667 TEST_EXTERNAL_TYPED_ARRAY(Int32, int32_t);
668 TEST_EXTERNAL_TYPED_ARRAY(Uint32, uint32_t);
669 TEST_EXTERNAL_TYPED_ARRAY(Int64, int64_t);
670 TEST_EXTERNAL_TYPED_ARRAY(Uint64, uint64_t);
671 TEST_EXTERNAL_TYPED_ARRAY(Float32, float);
672 TEST_EXTERNAL_TYPED_ARRAY(Float64, double);
673}
674
675ISOLATE_UNIT_TEST_CASE(SerializeEmptyByteArray) {
676 // Write snapshot with object content.
677 const int kTypedDataLength = 0;
678 TypedData& typed_data = TypedData::Handle(
679 TypedData::New(kTypedDataUint8ArrayCid, kTypedDataLength));
680 MessageWriter writer(true);
681 std::unique_ptr<Message> message =
682 writer.WriteMessage(typed_data, ILLEGAL_PORT, Message::kNormalPriority);
683
684 // Read object back from the snapshot.
685 MessageSnapshotReader reader(message.get(), thread);
686 TypedData& serialized_typed_data = TypedData::Handle();
687 serialized_typed_data ^= reader.ReadObject();
688 EXPECT(serialized_typed_data.IsTypedData());
689
690 // Read object back from the snapshot into a C structure.
691 ApiNativeScope scope;
692 ApiMessageReader api_reader(message.get());
693 Dart_CObject* root = api_reader.ReadMessage();
694 EXPECT_EQ(Dart_CObject_kTypedData, root->type);
695 EXPECT_EQ(Dart_TypedData_kUint8, root->value.as_typed_data.type);
696 EXPECT_EQ(kTypedDataLength, root->value.as_typed_data.length);
697 EXPECT(root->value.as_typed_data.values == NULL);
698 CheckEncodeDecodeMessage(root);
699}
700
701VM_UNIT_TEST_CASE(FullSnapshot) {
702 // clang-format off
703 auto kScriptChars = Utils::CStringUniquePtr(
704 OS::SCreate(
705 nullptr,
706 "class Fields {\n"
707 " Fields(int i, int j) : fld1 = i, fld2 = j {}\n"
708 " int fld1;\n"
709 " final int fld2;\n"
710 " final int bigint_fld = 0xfffffffffff;\n"
711 " static int%s fld3;\n"
712 " static const int smi_sfld = 10;\n"
713 " static const int bigint_sfld = 0xfffffffffff;\n"
714 "}\n"
715 "class Expect {\n"
716 " static void equals(x, y) {\n"
717 " if (x != y) throw new ArgumentError('not equal');\n"
718 " }\n"
719 "}\n"
720 "class FieldsTest {\n"
721 " static Fields testMain() {\n"
722 " Expect.equals(true, Fields.bigint_sfld == 0xfffffffffff);\n"
723 " Fields obj = new Fields(10, 20);\n"
724 " Expect.equals(true, obj.bigint_fld == 0xfffffffffff);\n"
725 " return obj;\n"
726 " }\n"
727 "}\n",
728 TestCase::NullableTag()),
729 std::free);
730 // clang-format on
731 Dart_Handle result;
732
733 uint8_t* isolate_snapshot_data_buffer;
734
735 // Start an Isolate, load a script and create a full snapshot.
736 Timer timer1(true, "Snapshot_test");
737 timer1.Start();
738 {
739 TestIsolateScope __test_isolate__;
740
741 // Create a test library and Load up a test script in it.
742 TestCase::LoadTestScript(kScriptChars.get(), NULL);
743
744 Thread* thread = Thread::Current();
745 TransitionNativeToVM transition(thread);
746 StackZone zone(thread);
747 HandleScope scope(thread);
748
749 Dart_Handle result = Api::CheckAndFinalizePendingClasses(thread);
750 {
751 TransitionVMToNative to_native(thread);
752 EXPECT_VALID(result);
753 }
754 timer1.Stop();
755 OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
756
757 // Write snapshot with object content.
758 FullSnapshotWriter writer(Snapshot::kFull, NULL,
759 &isolate_snapshot_data_buffer, &malloc_allocator,
760 NULL, /*image_writer*/ nullptr);
761 writer.WriteFullSnapshot();
762 }
763
764 // Now Create another isolate using the snapshot and execute a method
765 // from the script.
766 Timer timer2(true, "Snapshot_test");
767 timer2.Start();
768 TestCase::CreateTestIsolateFromSnapshot(isolate_snapshot_data_buffer);
769 {
770 Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
771 timer2.Stop();
772 OS::PrintErr("From Snapshot: %" Pd64 "us\n", timer2.TotalElapsedTime());
773
774 // Invoke a function which returns an object.
775 Dart_Handle cls = Dart_GetClass(TestCase::lib(), NewString("FieldsTest"));
776 result = Dart_Invoke(cls, NewString("testMain"), 0, NULL);
777 EXPECT_VALID(result);
778 Dart_ExitScope();
779 }
780 Dart_ShutdownIsolate();
781 free(isolate_snapshot_data_buffer);
782}
783
784// Helper function to call a top level Dart function and serialize the result.
785static std::unique_ptr<Message> GetSerialized(Dart_Handle lib,
786 const char* dart_function) {
787 Dart_Handle result;
788 {
789 TransitionVMToNative transition(Thread::Current());
790 result = Dart_Invoke(lib, NewString(dart_function), 0, NULL);
791 EXPECT_VALID(result);
792 }
793 Object& obj = Object::Handle(Api::UnwrapHandle(result));
794
795 // Serialize the object into a message.
796 MessageWriter writer(false);
797 return writer.WriteMessage(obj, ILLEGAL_PORT, Message::kNormalPriority);
798}
799
800// Helper function to deserialize the result into a Dart_CObject structure.
801static Dart_CObject* GetDeserialized(Message* message) {
802 // Read object back from the snapshot into a C structure.
803 ApiMessageReader api_reader(message);
804 return api_reader.ReadMessage();
805}
806
807static void CheckString(Dart_Handle dart_string, const char* expected) {
808 StackZone zone(Thread::Current());
809 String& str = String::Handle();
810 str ^= Api::UnwrapHandle(dart_string);
811 MessageWriter writer(false);
812 std::unique_ptr<Message> message =
813 writer.WriteMessage(str, ILLEGAL_PORT, Message::kNormalPriority);
814
815 // Read object back from the snapshot into a C structure.
816 ApiNativeScope scope;
817 ApiMessageReader api_reader(message.get());
818 Dart_CObject* root = api_reader.ReadMessage();
819 EXPECT_NOTNULL(root);
820 EXPECT_EQ(Dart_CObject_kString, root->type);
821 EXPECT_STREQ(expected, root->value.as_string);
822 CheckEncodeDecodeMessage(root);
823}
824
825static void CheckStringInvalid(Dart_Handle dart_string) {
826 StackZone zone(Thread::Current());
827 String& str = String::Handle();
828 str ^= Api::UnwrapHandle(dart_string);
829 MessageWriter writer(false);
830 std::unique_ptr<Message> message =
831 writer.WriteMessage(str, ILLEGAL_PORT, Message::kNormalPriority);
832
833 // Read object back from the snapshot into a C structure.
834 ApiNativeScope scope;
835 ApiMessageReader api_reader(message.get());
836 Dart_CObject* root = api_reader.ReadMessage();
837 EXPECT_NOTNULL(root);
838 EXPECT_EQ(Dart_CObject_kUnsupported, root->type);
839}
840
841VM_UNIT_TEST_CASE(DartGeneratedMessages) {
842 static const char* kCustomIsolateScriptChars =
843 "final int kArrayLength = 10;\n"
844 "getSmi() {\n"
845 " return 42;\n"
846 "}\n"
847 "getAsciiString() {\n"
848 " return \"Hello, world!\";\n"
849 "}\n"
850 "getNonAsciiString() {\n"
851 " return \"Blåbærgrød\";\n"
852 "}\n"
853 "getNonBMPString() {\n"
854 " return \"\\u{10000}\\u{1F601}\\u{1F637}\\u{20000}\";\n"
855 "}\n"
856 "getLeadSurrogateString() {\n"
857 " return String.fromCharCodes([0xd800]);\n"
858 "}\n"
859 "getTrailSurrogateString() {\n"
860 " return \"\\u{10000}\".substring(1);\n"
861 "}\n"
862 "getSurrogatesString() {\n"
863 " return String.fromCharCodes([0xdc00, 0xdc00, 0xd800, 0xd800]);\n"
864 "}\n"
865 "getCrappyString() {\n"
866 " return String.fromCharCodes([0xd800, 32, 0xdc00, 32]);\n"
867 "}\n"
868 "getList() {\n"
869 " return List.filled(kArrayLength, null);\n"
870 "}\n";
871
872 TestCase::CreateTestIsolate();
873 Isolate* isolate = Isolate::Current();
874 EXPECT(isolate != NULL);
875 Dart_EnterScope();
876
877 Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars, NULL);
878 EXPECT_VALID(lib);
879 Dart_Handle smi_result;
880 smi_result = Dart_Invoke(lib, NewString("getSmi"), 0, NULL);
881 EXPECT_VALID(smi_result);
882
883 Dart_Handle ascii_string_result;
884 ascii_string_result = Dart_Invoke(lib, NewString("getAsciiString"), 0, NULL);
885 EXPECT_VALID(ascii_string_result);
886 EXPECT(Dart_IsString(ascii_string_result));
887
888 Dart_Handle non_ascii_string_result;
889 non_ascii_string_result =
890 Dart_Invoke(lib, NewString("getNonAsciiString"), 0, NULL);
891 EXPECT_VALID(non_ascii_string_result);
892 EXPECT(Dart_IsString(non_ascii_string_result));
893
894 Dart_Handle non_bmp_string_result;
895 non_bmp_string_result =
896 Dart_Invoke(lib, NewString("getNonBMPString"), 0, NULL);
897 EXPECT_VALID(non_bmp_string_result);
898 EXPECT(Dart_IsString(non_bmp_string_result));
899
900 Dart_Handle lead_surrogate_string_result;
901 lead_surrogate_string_result =
902 Dart_Invoke(lib, NewString("getLeadSurrogateString"), 0, NULL);
903 EXPECT_VALID(lead_surrogate_string_result);
904 EXPECT(Dart_IsString(lead_surrogate_string_result));
905
906 Dart_Handle trail_surrogate_string_result;
907 trail_surrogate_string_result =
908 Dart_Invoke(lib, NewString("getTrailSurrogateString"), 0, NULL);
909 EXPECT_VALID(trail_surrogate_string_result);
910 EXPECT(Dart_IsString(trail_surrogate_string_result));
911
912 Dart_Handle surrogates_string_result;
913 surrogates_string_result =
914 Dart_Invoke(lib, NewString("getSurrogatesString"), 0, NULL);
915 EXPECT_VALID(surrogates_string_result);
916 EXPECT(Dart_IsString(surrogates_string_result));
917
918 Dart_Handle crappy_string_result;
919 crappy_string_result =
920 Dart_Invoke(lib, NewString("getCrappyString"), 0, NULL);
921 EXPECT_VALID(crappy_string_result);
922 EXPECT(Dart_IsString(crappy_string_result));
923
924 {
925 Thread* thread = Thread::Current();
926 CHECK_API_SCOPE(thread);
927 TransitionNativeToVM transition(thread);
928 HANDLESCOPE(thread);
929
930 {
931 StackZone zone(thread);
932 Smi& smi = Smi::Handle();
933 smi ^= Api::UnwrapHandle(smi_result);
934 MessageWriter writer(false);
935 std::unique_ptr<Message> message =
936 writer.WriteMessage(smi, ILLEGAL_PORT, Message::kNormalPriority);
937
938 // Read object back from the snapshot into a C structure.
939 ApiNativeScope scope;
940 ApiMessageReader api_reader(message.get());
941 Dart_CObject* root = api_reader.ReadMessage();
942 EXPECT_NOTNULL(root);
943 EXPECT_EQ(Dart_CObject_kInt32, root->type);
944 EXPECT_EQ(42, root->value.as_int32);
945 CheckEncodeDecodeMessage(root);
946 }
947 CheckString(ascii_string_result, "Hello, world!");
948 CheckString(non_ascii_string_result, "Blåbærgrød");
949 CheckString(non_bmp_string_result,
950 "\xf0\x90\x80\x80"
951 "\xf0\x9f\x98\x81"
952 "\xf0\x9f\x98\xb7"
953 "\xf0\xa0\x80\x80");
954 CheckStringInvalid(lead_surrogate_string_result);
955 CheckStringInvalid(trail_surrogate_string_result);
956 CheckStringInvalid(crappy_string_result);
957 CheckStringInvalid(surrogates_string_result);
958 }
959 Dart_ExitScope();
960 Dart_ShutdownIsolate();
961}
962
963VM_UNIT_TEST_CASE(DartGeneratedListMessages) {
964 const int kArrayLength = 10;
965 static const char* kScriptChars =
966 "final int kArrayLength = 10;\n"
967 "getList() {\n"
968 " return List.filled(kArrayLength, null);\n"
969 "}\n"
970 "getIntList() {\n"
971 " var list = List<int>.filled(kArrayLength, 0);\n"
972 " for (var i = 0; i < kArrayLength; i++) list[i] = i;\n"
973 " return list;\n"
974 "}\n"
975 "getStringList() {\n"
976 " var list = List<String>.filled(kArrayLength, '');\n"
977 " for (var i = 0; i < kArrayLength; i++) list[i] = i.toString();\n"
978 " return list;\n"
979 "}\n"
980 "getMixedList() {\n"
981 " var list = List<dynamic>.filled(kArrayLength, null);\n"
982 " list[0] = 0;\n"
983 " list[1] = '1';\n"
984 " list[2] = 2.2;\n"
985 " list[3] = true;\n"
986 " return list;\n"
987 "}\n";
988
989 TestCase::CreateTestIsolate();
990 Thread* thread = Thread::Current();
991 EXPECT(thread->isolate() != NULL);
992 Dart_EnterScope();
993
994 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
995 EXPECT_VALID(lib);
996
997 {
998 CHECK_API_SCOPE(thread);
999 TransitionNativeToVM transition(thread);
1000 HANDLESCOPE(thread);
1001 StackZone zone(thread);
1002 {
1003 // Generate a list of nulls from Dart code.
1004 std::unique_ptr<Message> message = GetSerialized(lib, "getList");
1005 ApiNativeScope scope;
1006 Dart_CObject* root = GetDeserialized(message.get());
1007 EXPECT_NOTNULL(root);
1008 EXPECT_EQ(Dart_CObject_kArray, root->type);
1009 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1010 for (int i = 0; i < kArrayLength; i++) {
1011 EXPECT_EQ(Dart_CObject_kNull, root->value.as_array.values[i]->type);
1012 }
1013 CheckEncodeDecodeMessage(root);
1014 }
1015 {
1016 // Generate a list of ints from Dart code.
1017 std::unique_ptr<Message> message = GetSerialized(lib, "getIntList");
1018 ApiNativeScope scope;
1019 Dart_CObject* root = GetDeserialized(message.get());
1020 EXPECT_NOTNULL(root);
1021 EXPECT_EQ(Dart_CObject_kArray, root->type);
1022 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1023 for (int i = 0; i < kArrayLength; i++) {
1024 EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[i]->type);
1025 EXPECT_EQ(i, root->value.as_array.values[i]->value.as_int32);
1026 }
1027 CheckEncodeDecodeMessage(root);
1028 }
1029 {
1030 // Generate a list of strings from Dart code.
1031 std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
1032 ApiNativeScope scope;
1033 Dart_CObject* root = GetDeserialized(message.get());
1034 EXPECT_NOTNULL(root);
1035 EXPECT_EQ(Dart_CObject_kArray, root->type);
1036 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1037 for (int i = 0; i < kArrayLength; i++) {
1038 EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[i]->type);
1039 char buffer[3];
1040 snprintf(buffer, sizeof(buffer), "%d", i);
1041 EXPECT_STREQ(buffer, root->value.as_array.values[i]->value.as_string);
1042 }
1043 }
1044 {
1045 // Generate a list of objects of different types from Dart code.
1046 std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
1047 ApiNativeScope scope;
1048 Dart_CObject* root = GetDeserialized(message.get());
1049 EXPECT_NOTNULL(root);
1050 EXPECT_EQ(Dart_CObject_kArray, root->type);
1051 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1052
1053 EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[0]->type);
1054 EXPECT_EQ(0, root->value.as_array.values[0]->value.as_int32);
1055 EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[1]->type);
1056 EXPECT_STREQ("1", root->value.as_array.values[1]->value.as_string);
1057 EXPECT_EQ(Dart_CObject_kDouble, root->value.as_array.values[2]->type);
1058 EXPECT_EQ(2.2, root->value.as_array.values[2]->value.as_double);
1059 EXPECT_EQ(Dart_CObject_kBool, root->value.as_array.values[3]->type);
1060 EXPECT_EQ(true, root->value.as_array.values[3]->value.as_bool);
1061
1062 for (int i = 0; i < kArrayLength; i++) {
1063 if (i > 3) {
1064 EXPECT_EQ(Dart_CObject_kNull, root->value.as_array.values[i]->type);
1065 }
1066 }
1067 }
1068 }
1069 Dart_ExitScope();
1070 Dart_ShutdownIsolate();
1071}
1072
1073VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessages) {
1074 const int kArrayLength = 10;
1075 static const char* kScriptChars =
1076 "final int kArrayLength = 10;\n"
1077 "getList() {\n"
1078 " return [null, null, null, null, null, null, null, null, null, null];\n"
1079 "}\n"
1080 "getIntList() {\n"
1081 " return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n"
1082 "}\n"
1083 "getStringList() {\n"
1084 " return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];\n"
1085 "}\n"
1086 "getListList() {\n"
1087 " return <dynamic>[[],"
1088 " [0],"
1089 " [0, 1],"
1090 " [0, 1, 2],"
1091 " [0, 1, 2, 3],"
1092 " [0, 1, 2, 3, 4],"
1093 " [0, 1, 2, 3, 4, 5],"
1094 " [0, 1, 2, 3, 4, 5, 6],"
1095 " [0, 1, 2, 3, 4, 5, 6, 7],"
1096 " [0, 1, 2, 3, 4, 5, 6, 7, 8]];\n"
1097 "}\n"
1098 "getMixedList() {\n"
1099 " var list = [];\n"
1100 " list.add(0);\n"
1101 " list.add('1');\n"
1102 " list.add(2.2);\n"
1103 " list.add(true);\n"
1104 " list.add([]);\n"
1105 " list.add(<dynamic>[[]]);\n"
1106 " list.add(<dynamic>[<dynamic>[[]]]);\n"
1107 " list.add(<dynamic>[1, <dynamic>[2, [3]]]);\n"
1108 " list.add(<dynamic>[1, <dynamic>[1, 2, [1, 2, 3]]]);\n"
1109 " list.add([1, 2, 3]);\n"
1110 " return list;\n"
1111 "}\n";
1112
1113 TestCase::CreateTestIsolate();
1114 Thread* thread = Thread::Current();
1115 EXPECT(thread->isolate() != NULL);
1116 Dart_EnterScope();
1117
1118 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
1119 EXPECT_VALID(lib);
1120
1121 {
1122 CHECK_API_SCOPE(thread);
1123 TransitionNativeToVM transition(thread);
1124 HANDLESCOPE(thread);
1125 StackZone zone(thread);
1126 {
1127 // Generate a list of nulls from Dart code.
1128 std::unique_ptr<Message> message = GetSerialized(lib, "getList");
1129 ApiNativeScope scope;
1130 Dart_CObject* root = GetDeserialized(message.get());
1131 EXPECT_NOTNULL(root);
1132 EXPECT_EQ(Dart_CObject_kArray, root->type);
1133 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1134 for (int i = 0; i < kArrayLength; i++) {
1135 EXPECT_EQ(Dart_CObject_kNull, root->value.as_array.values[i]->type);
1136 }
1137 CheckEncodeDecodeMessage(root);
1138 }
1139 {
1140 // Generate a list of ints from Dart code.
1141 std::unique_ptr<Message> message = GetSerialized(lib, "getIntList");
1142 ApiNativeScope scope;
1143 Dart_CObject* root = GetDeserialized(message.get());
1144 EXPECT_NOTNULL(root);
1145 EXPECT_EQ(Dart_CObject_kArray, root->type);
1146 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1147 for (int i = 0; i < kArrayLength; i++) {
1148 EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[i]->type);
1149 EXPECT_EQ(i, root->value.as_array.values[i]->value.as_int32);
1150 }
1151 CheckEncodeDecodeMessage(root);
1152 }
1153 {
1154 // Generate a list of strings from Dart code.
1155 std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
1156 ApiNativeScope scope;
1157 Dart_CObject* root = GetDeserialized(message.get());
1158 EXPECT_NOTNULL(root);
1159 EXPECT_EQ(Dart_CObject_kArray, root->type);
1160 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1161 for (int i = 0; i < kArrayLength; i++) {
1162 EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[i]->type);
1163 char buffer[3];
1164 snprintf(buffer, sizeof(buffer), "%d", i);
1165 EXPECT_STREQ(buffer, root->value.as_array.values[i]->value.as_string);
1166 }
1167 }
1168 {
1169 // Generate a list of lists from Dart code.
1170 std::unique_ptr<Message> message = GetSerialized(lib, "getListList");
1171 ApiNativeScope scope;
1172 Dart_CObject* root = GetDeserialized(message.get());
1173 EXPECT_NOTNULL(root);
1174 EXPECT_EQ(Dart_CObject_kArray, root->type);
1175 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1176 for (int i = 0; i < kArrayLength; i++) {
1177 Dart_CObject* element = root->value.as_array.values[i];
1178 EXPECT_EQ(Dart_CObject_kArray, element->type);
1179 EXPECT_EQ(i, element->value.as_array.length);
1180 for (int j = 0; j < i; j++) {
1181 EXPECT_EQ(Dart_CObject_kInt32,
1182 element->value.as_array.values[j]->type);
1183 EXPECT_EQ(j, element->value.as_array.values[j]->value.as_int32);
1184 }
1185 }
1186 }
1187 {
1188 // Generate a list of objects of different types from Dart code.
1189 std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
1190 ApiNativeScope scope;
1191 Dart_CObject* root = GetDeserialized(message.get());
1192 EXPECT_NOTNULL(root);
1193 EXPECT_EQ(Dart_CObject_kArray, root->type);
1194 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1195
1196 EXPECT_EQ(Dart_CObject_kInt32, root->value.as_array.values[0]->type);
1197 EXPECT_EQ(0, root->value.as_array.values[0]->value.as_int32);
1198 EXPECT_EQ(Dart_CObject_kString, root->value.as_array.values[1]->type);
1199 EXPECT_STREQ("1", root->value.as_array.values[1]->value.as_string);
1200 EXPECT_EQ(Dart_CObject_kDouble, root->value.as_array.values[2]->type);
1201 EXPECT_EQ(2.2, root->value.as_array.values[2]->value.as_double);
1202 EXPECT_EQ(Dart_CObject_kBool, root->value.as_array.values[3]->type);
1203 EXPECT_EQ(true, root->value.as_array.values[3]->value.as_bool);
1204
1205 for (int i = 0; i < kArrayLength; i++) {
1206 if (i > 3) {
1207 EXPECT_EQ(Dart_CObject_kArray, root->value.as_array.values[i]->type);
1208 }
1209 }
1210
1211 Dart_CObject* element;
1212 Dart_CObject* e;
1213
1214 // []
1215 element = root->value.as_array.values[4];
1216 EXPECT_EQ(0, element->value.as_array.length);
1217
1218 // [[]]
1219 element = root->value.as_array.values[5];
1220 EXPECT_EQ(1, element->value.as_array.length);
1221 element = element->value.as_array.values[0];
1222 EXPECT_EQ(Dart_CObject_kArray, element->type);
1223 EXPECT_EQ(0, element->value.as_array.length);
1224
1225 // [[[]]]"
1226 element = root->value.as_array.values[6];
1227 EXPECT_EQ(1, element->value.as_array.length);
1228 element = element->value.as_array.values[0];
1229 EXPECT_EQ(Dart_CObject_kArray, element->type);
1230 EXPECT_EQ(1, element->value.as_array.length);
1231 element = element->value.as_array.values[0];
1232 EXPECT_EQ(Dart_CObject_kArray, element->type);
1233 EXPECT_EQ(0, element->value.as_array.length);
1234
1235 // [1, [2, [3]]]
1236 element = root->value.as_array.values[7];
1237 EXPECT_EQ(2, element->value.as_array.length);
1238 e = element->value.as_array.values[0];
1239 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1240 EXPECT_EQ(1, e->value.as_int32);
1241 element = element->value.as_array.values[1];
1242 EXPECT_EQ(Dart_CObject_kArray, element->type);
1243 EXPECT_EQ(2, element->value.as_array.length);
1244 e = element->value.as_array.values[0];
1245 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1246 EXPECT_EQ(2, e->value.as_int32);
1247 element = element->value.as_array.values[1];
1248 EXPECT_EQ(Dart_CObject_kArray, element->type);
1249 EXPECT_EQ(1, element->value.as_array.length);
1250 e = element->value.as_array.values[0];
1251 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1252 EXPECT_EQ(3, e->value.as_int32);
1253
1254 // [1, [1, 2, [1, 2, 3]]]
1255 element = root->value.as_array.values[8];
1256 EXPECT_EQ(2, element->value.as_array.length);
1257 e = element->value.as_array.values[0];
1258 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1259 e = element->value.as_array.values[0];
1260 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1261 EXPECT_EQ(1, e->value.as_int32);
1262 element = element->value.as_array.values[1];
1263 EXPECT_EQ(Dart_CObject_kArray, element->type);
1264 EXPECT_EQ(3, element->value.as_array.length);
1265 for (int i = 0; i < 2; i++) {
1266 e = element->value.as_array.values[i];
1267 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1268 EXPECT_EQ(i + 1, e->value.as_int32);
1269 }
1270 element = element->value.as_array.values[2];
1271 EXPECT_EQ(Dart_CObject_kArray, element->type);
1272 EXPECT_EQ(3, element->value.as_array.length);
1273 for (int i = 0; i < 3; i++) {
1274 e = element->value.as_array.values[i];
1275 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1276 EXPECT_EQ(i + 1, e->value.as_int32);
1277 }
1278
1279 // [1, 2, 3]
1280 element = root->value.as_array.values[9];
1281 EXPECT_EQ(3, element->value.as_array.length);
1282 for (int i = 0; i < 3; i++) {
1283 e = element->value.as_array.values[i];
1284 EXPECT_EQ(Dart_CObject_kInt32, e->type);
1285 EXPECT_EQ(i + 1, e->value.as_int32);
1286 }
1287 }
1288 }
1289 Dart_ExitScope();
1290 Dart_ShutdownIsolate();
1291}
1292
1293VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) {
1294 const int kArrayLength = 10;
1295 static const char* kScriptChars =
1296 "import 'dart:typed_data';\n"
1297 "final int kArrayLength = 10;\n"
1298 "getStringList() {\n"
1299 " var s = 'Hello, world!';\n"
1300 " var list = List<String>.filled(kArrayLength, '');\n"
1301 " for (var i = 0; i < kArrayLength; i++) list[i] = s;\n"
1302 " return list;\n"
1303 "}\n"
1304 "getMintList() {\n"
1305 " var mint = 0x7FFFFFFFFFFFFFFF;\n"
1306 " var list = List.filled(kArrayLength, 0);\n"
1307 " for (var i = 0; i < kArrayLength; i++) list[i] = mint;\n"
1308 " return list;\n"
1309 "}\n"
1310 "getDoubleList() {\n"
1311 " var d = 3.14;\n"
1312 " var list = List<double>.filled(kArrayLength, 0.0);\n"
1313 " for (var i = 0; i < kArrayLength; i++) list[i] = d;\n"
1314 " return list;\n"
1315 "}\n"
1316 "getTypedDataList() {\n"
1317 " var byte_array = Uint8List(256);\n"
1318 " var list = List<dynamic>.filled(kArrayLength, null);\n"
1319 " for (var i = 0; i < kArrayLength; i++) list[i] = byte_array;\n"
1320 " return list;\n"
1321 "}\n"
1322 "getTypedDataViewList() {\n"
1323 " var uint8_list = Uint8List(256);\n"
1324 " uint8_list[64] = 1;\n"
1325 " var uint8_list_view =\n"
1326 " Uint8List.view(uint8_list.buffer, 64, 128);\n"
1327 " var list = List<dynamic>.filled(kArrayLength, null);\n"
1328 " for (var i = 0; i < kArrayLength; i++) list[i] = uint8_list_view;\n"
1329 " return list;\n"
1330 "}\n"
1331 "getMixedList() {\n"
1332 " var list = List<dynamic>.filled(kArrayLength, null);\n"
1333 " for (var i = 0; i < kArrayLength; i++) {\n"
1334 " list[i] = ((i % 2) == 0) ? 'A' : 2.72;\n"
1335 " }\n"
1336 " return list;\n"
1337 "}\n"
1338 "getSelfRefList() {\n"
1339 " var list = List<dynamic>.filled(kArrayLength, null, growable: true);\n"
1340 " for (var i = 0; i < kArrayLength; i++) {\n"
1341 " list[i] = list;\n"
1342 " }\n"
1343 " return list;\n"
1344 "}\n";
1345
1346 TestCase::CreateTestIsolate();
1347 Thread* thread = Thread::Current();
1348 EXPECT(thread->isolate() != NULL);
1349 Dart_EnterScope();
1350
1351 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
1352 EXPECT_VALID(lib);
1353
1354 {
1355 CHECK_API_SCOPE(thread);
1356 TransitionNativeToVM transition(thread);
1357 HANDLESCOPE(thread);
1358 StackZone zone(thread);
1359 {
1360 // Generate a list of strings from Dart code.
1361 std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
1362 ApiNativeScope scope;
1363 Dart_CObject* root = GetDeserialized(message.get());
1364 EXPECT_NOTNULL(root);
1365 EXPECT_EQ(Dart_CObject_kArray, root->type);
1366 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1367 for (int i = 0; i < kArrayLength; i++) {
1368 Dart_CObject* element = root->value.as_array.values[i];
1369 EXPECT_EQ(root->value.as_array.values[0], element);
1370 EXPECT_EQ(Dart_CObject_kString, element->type);
1371 EXPECT_STREQ("Hello, world!", element->value.as_string);
1372 }
1373 }
1374 {
1375 // Generate a list of medium ints from Dart code.
1376 std::unique_ptr<Message> message = GetSerialized(lib, "getMintList");
1377 ApiNativeScope scope;
1378 Dart_CObject* root = GetDeserialized(message.get());
1379 EXPECT_NOTNULL(root);
1380 EXPECT_EQ(Dart_CObject_kArray, root->type);
1381 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1382 for (int i = 0; i < kArrayLength; i++) {
1383 Dart_CObject* element = root->value.as_array.values[i];
1384 EXPECT_EQ(root->value.as_array.values[0], element);
1385 EXPECT_EQ(Dart_CObject_kInt64, element->type);
1386 EXPECT_EQ(DART_INT64_C(0x7FFFFFFFFFFFFFFF), element->value.as_int64);
1387 }
1388 }
1389 {
1390 // Generate a list of doubles from Dart code.
1391 std::unique_ptr<Message> message = GetSerialized(lib, "getDoubleList");
1392 ApiNativeScope scope;
1393 Dart_CObject* root = GetDeserialized(message.get());
1394 EXPECT_NOTNULL(root);
1395 EXPECT_EQ(Dart_CObject_kArray, root->type);
1396 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1397 Dart_CObject* element = root->value.as_array.values[0];
1398 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1399 EXPECT_EQ(3.14, element->value.as_double);
1400 for (int i = 1; i < kArrayLength; i++) {
1401 element = root->value.as_array.values[i];
1402 // Double values are expected to not be canonicalized in messages.
1403 EXPECT_NE(root->value.as_array.values[0], element);
1404 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1405 EXPECT_EQ(3.14, element->value.as_double);
1406 }
1407 }
1408 {
1409 // Generate a list of Uint8Lists from Dart code.
1410 std::unique_ptr<Message> message = GetSerialized(lib, "getTypedDataList");
1411 ApiNativeScope scope;
1412 Dart_CObject* root = GetDeserialized(message.get());
1413 EXPECT_NOTNULL(root);
1414 EXPECT_EQ(Dart_CObject_kArray, root->type);
1415 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1416 for (int i = 0; i < kArrayLength; i++) {
1417 Dart_CObject* element = root->value.as_array.values[i];
1418 EXPECT_EQ(root->value.as_array.values[0], element);
1419 EXPECT_EQ(Dart_CObject_kTypedData, element->type);
1420 EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
1421 EXPECT_EQ(256, element->value.as_typed_data.length);
1422 }
1423 }
1424 {
1425 // Generate a list of Uint8List views from Dart code.
1426 std::unique_ptr<Message> message =
1427 GetSerialized(lib, "getTypedDataViewList");
1428 ApiNativeScope scope;
1429 Dart_CObject* root = GetDeserialized(message.get());
1430 EXPECT_NOTNULL(root);
1431 EXPECT_EQ(Dart_CObject_kArray, root->type);
1432 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1433 for (int i = 0; i < kArrayLength; i++) {
1434 Dart_CObject* element = root->value.as_array.values[i];
1435 EXPECT_EQ(root->value.as_array.values[0], element);
1436 EXPECT_EQ(Dart_CObject_kTypedData, element->type);
1437 EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
1438 EXPECT_EQ(128, element->value.as_typed_data.length);
1439 EXPECT_EQ(1, element->value.as_typed_data.values[0]);
1440 EXPECT_EQ(0, element->value.as_typed_data.values[1]);
1441 }
1442 }
1443 {
1444 // Generate a list of objects of different types from Dart code.
1445 std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
1446 ApiNativeScope scope;
1447 Dart_CObject* root = GetDeserialized(message.get());
1448 EXPECT_NOTNULL(root);
1449 EXPECT_EQ(Dart_CObject_kArray, root->type);
1450 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1451 Dart_CObject* element = root->value.as_array.values[0];
1452 EXPECT_EQ(Dart_CObject_kString, element->type);
1453 EXPECT_STREQ("A", element->value.as_string);
1454 element = root->value.as_array.values[1];
1455 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1456 EXPECT_EQ(2.72, element->value.as_double);
1457 for (int i = 2; i < kArrayLength; i++) {
1458 element = root->value.as_array.values[i];
1459 if ((i % 2) == 0) {
1460 EXPECT_EQ(root->value.as_array.values[0], element);
1461 EXPECT_EQ(Dart_CObject_kString, element->type);
1462 EXPECT_STREQ("A", element->value.as_string);
1463 } else {
1464 // Double values are expected to not be canonicalized in messages.
1465 EXPECT_NE(root->value.as_array.values[1], element);
1466 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1467 EXPECT_EQ(2.72, element->value.as_double);
1468 }
1469 }
1470 }
1471 {
1472 // Generate a list of objects of different types from Dart code.
1473 std::unique_ptr<Message> message = GetSerialized(lib, "getSelfRefList");
1474 ApiNativeScope scope;
1475 Dart_CObject* root = GetDeserialized(message.get());
1476 EXPECT_NOTNULL(root);
1477 EXPECT_EQ(Dart_CObject_kArray, root->type);
1478 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1479 for (int i = 0; i < kArrayLength; i++) {
1480 Dart_CObject* element = root->value.as_array.values[i];
1481 EXPECT_EQ(Dart_CObject_kArray, element->type);
1482 EXPECT_EQ(root, element);
1483 }
1484 }
1485 }
1486 Dart_ExitScope();
1487 Dart_ShutdownIsolate();
1488}
1489
1490VM_UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) {
1491 const int kArrayLength = 10;
1492 static const char* kScriptChars =
1493 "import 'dart:typed_data';\n"
1494 "final int kArrayLength = 10;\n"
1495 "getStringList() {\n"
1496 " var s = 'Hello, world!';\n"
1497 " var list = [s, s, s, s, s, s, s, s, s, s];\n"
1498 " return list;\n"
1499 "}\n"
1500 "getMintList() {\n"
1501 " var mint = 0x7FFFFFFFFFFFFFFF;\n"
1502 " var list = [mint, mint, mint, mint, mint,\n"
1503 " mint, mint, mint, mint, mint];\n"
1504 " return list;\n"
1505 "}\n"
1506 "getDoubleList() {\n"
1507 " var d = 3.14;\n"
1508 " var list = [3.14, 3.14, 3.14, 3.14, 3.14, 3.14];\n"
1509 " list.add(3.14);\n"
1510 " list.add(3.14);\n"
1511 " list.add(3.14);\n"
1512 " list.add(3.14);\n"
1513 " return list;\n"
1514 "}\n"
1515 "getTypedDataList() {\n"
1516 " var byte_array = new Uint8List(256);\n"
1517 " var list = [];\n"
1518 " for (var i = 0; i < kArrayLength; i++) {\n"
1519 " list.add(byte_array);\n"
1520 " }\n"
1521 " return list;\n"
1522 "}\n"
1523 "getTypedDataViewList() {\n"
1524 " var uint8_list = new Uint8List(256);\n"
1525 " uint8_list[64] = 1;\n"
1526 " var uint8_list_view =\n"
1527 " new Uint8List.view(uint8_list.buffer, 64, 128);\n"
1528 " var list = [];\n"
1529 " for (var i = 0; i < kArrayLength; i++) {\n"
1530 " list.add(uint8_list_view);\n"
1531 " }\n"
1532 " return list;\n"
1533 "}\n"
1534 "getMixedList() {\n"
1535 " var list = [];\n"
1536 " for (var i = 0; i < kArrayLength; i++) {\n"
1537 " list.add(((i % 2) == 0) ? '.' : 2.72);\n"
1538 " }\n"
1539 " return list;\n"
1540 "}\n"
1541 "getSelfRefList() {\n"
1542 " var list = [];\n"
1543 " for (var i = 0; i < kArrayLength; i++) {\n"
1544 " list.add(list);\n"
1545 " }\n"
1546 " return list;\n"
1547 "}\n";
1548
1549 TestCase::CreateTestIsolate();
1550 Thread* thread = Thread::Current();
1551 EXPECT(thread->isolate() != NULL);
1552 Dart_EnterScope();
1553
1554 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
1555 EXPECT_VALID(lib);
1556
1557 {
1558 CHECK_API_SCOPE(thread);
1559 TransitionNativeToVM transition(thread);
1560 HANDLESCOPE(thread);
1561 StackZone zone(thread);
1562 {
1563 // Generate a list of strings from Dart code.
1564 std::unique_ptr<Message> message = GetSerialized(lib, "getStringList");
1565 ApiNativeScope scope;
1566 Dart_CObject* root = GetDeserialized(message.get());
1567 EXPECT_NOTNULL(root);
1568 EXPECT_EQ(Dart_CObject_kArray, root->type);
1569 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1570 for (int i = 0; i < kArrayLength; i++) {
1571 Dart_CObject* element = root->value.as_array.values[i];
1572 EXPECT_EQ(root->value.as_array.values[0], element);
1573 EXPECT_EQ(Dart_CObject_kString, element->type);
1574 EXPECT_STREQ("Hello, world!", element->value.as_string);
1575 }
1576 }
1577 {
1578 // Generate a list of medium ints from Dart code.
1579 std::unique_ptr<Message> message = GetSerialized(lib, "getMintList");
1580 ApiNativeScope scope;
1581 Dart_CObject* root = GetDeserialized(message.get());
1582 EXPECT_NOTNULL(root);
1583 EXPECT_EQ(Dart_CObject_kArray, root->type);
1584 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1585 for (int i = 0; i < kArrayLength; i++) {
1586 Dart_CObject* element = root->value.as_array.values[i];
1587 EXPECT_EQ(root->value.as_array.values[0], element);
1588 EXPECT_EQ(Dart_CObject_kInt64, element->type);
1589 EXPECT_EQ(DART_INT64_C(0x7FFFFFFFFFFFFFFF), element->value.as_int64);
1590 }
1591 }
1592 {
1593 // Generate a list of doubles from Dart code.
1594 std::unique_ptr<Message> message = GetSerialized(lib, "getDoubleList");
1595 ApiNativeScope scope;
1596 Dart_CObject* root = GetDeserialized(message.get());
1597 EXPECT_NOTNULL(root);
1598 EXPECT_EQ(Dart_CObject_kArray, root->type);
1599 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1600 Dart_CObject* element = root->value.as_array.values[0];
1601 // Double values are expected to not be canonicalized in messages.
1602 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1603 EXPECT_EQ(3.14, element->value.as_double);
1604 for (int i = 1; i < kArrayLength; i++) {
1605 element = root->value.as_array.values[i];
1606 // Double values are expected to not be canonicalized in messages.
1607 EXPECT_NE(root->value.as_array.values[0], element);
1608 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1609 EXPECT_EQ(3.14, element->value.as_double);
1610 }
1611 }
1612 {
1613 // Generate a list of Uint8Lists from Dart code.
1614 std::unique_ptr<Message> message = GetSerialized(lib, "getTypedDataList");
1615 ApiNativeScope scope;
1616 Dart_CObject* root = GetDeserialized(message.get());
1617 EXPECT_NOTNULL(root);
1618 EXPECT_EQ(Dart_CObject_kArray, root->type);
1619 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1620 for (int i = 0; i < kArrayLength; i++) {
1621 Dart_CObject* element = root->value.as_array.values[i];
1622 EXPECT_EQ(root->value.as_array.values[0], element);
1623 EXPECT_EQ(Dart_CObject_kTypedData, element->type);
1624 EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
1625 EXPECT_EQ(256, element->value.as_typed_data.length);
1626 }
1627 }
1628 {
1629 // Generate a list of Uint8List views from Dart code.
1630 std::unique_ptr<Message> message =
1631 GetSerialized(lib, "getTypedDataViewList");
1632 ApiNativeScope scope;
1633 Dart_CObject* root = GetDeserialized(message.get());
1634 EXPECT_NOTNULL(root);
1635 EXPECT_EQ(Dart_CObject_kArray, root->type);
1636 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1637 for (int i = 0; i < kArrayLength; i++) {
1638 Dart_CObject* element = root->value.as_array.values[i];
1639 EXPECT_EQ(root->value.as_array.values[0], element);
1640 EXPECT_EQ(Dart_CObject_kTypedData, element->type);
1641 EXPECT_EQ(Dart_TypedData_kUint8, element->value.as_typed_data.type);
1642 EXPECT_EQ(128, element->value.as_typed_data.length);
1643 EXPECT_EQ(1, element->value.as_typed_data.values[0]);
1644 EXPECT_EQ(0, element->value.as_typed_data.values[1]);
1645 }
1646 }
1647 {
1648 // Generate a list of objects of different types from Dart code.
1649 std::unique_ptr<Message> message = GetSerialized(lib, "getMixedList");
1650 ApiNativeScope scope;
1651 Dart_CObject* root = GetDeserialized(message.get());
1652 EXPECT_NOTNULL(root);
1653 EXPECT_EQ(Dart_CObject_kArray, root->type);
1654 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1655 Dart_CObject* element = root->value.as_array.values[0];
1656 EXPECT_EQ(Dart_CObject_kString, element->type);
1657 EXPECT_STREQ(".", element->value.as_string);
1658 element = root->value.as_array.values[1];
1659 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1660 EXPECT_EQ(2.72, element->value.as_double);
1661 for (int i = 2; i < kArrayLength; i++) {
1662 Dart_CObject* element = root->value.as_array.values[i];
1663 if ((i % 2) == 0) {
1664 EXPECT_EQ(root->value.as_array.values[0], element);
1665 EXPECT_EQ(Dart_CObject_kString, element->type);
1666 EXPECT_STREQ(".", element->value.as_string);
1667 } else {
1668 // Double values are expected to not be canonicalized in messages.
1669 EXPECT_NE(root->value.as_array.values[1], element);
1670 EXPECT_EQ(Dart_CObject_kDouble, element->type);
1671 EXPECT_EQ(2.72, element->value.as_double);
1672 }
1673 }
1674 }
1675 {
1676 // Generate a list of objects of different types from Dart code.
1677 std::unique_ptr<Message> message = GetSerialized(lib, "getSelfRefList");
1678 ApiNativeScope scope;
1679 Dart_CObject* root = GetDeserialized(message.get());
1680 EXPECT_NOTNULL(root);
1681 EXPECT_EQ(Dart_CObject_kArray, root->type);
1682 EXPECT_EQ(kArrayLength, root->value.as_array.length);
1683 for (int i = 0; i < kArrayLength; i++) {
1684 Dart_CObject* element = root->value.as_array.values[i];
1685 EXPECT_EQ(Dart_CObject_kArray, element->type);
1686 EXPECT_EQ(root, element);
1687 }
1688 }
1689 }
1690 Dart_ExitScope();
1691 Dart_ShutdownIsolate();
1692}
1693
1694static void CheckTypedData(Dart_CObject* object,
1695 Dart_TypedData_Type typed_data_type,
1696 int len) {
1697 EXPECT_EQ(Dart_CObject_kTypedData, object->type);
1698 EXPECT_EQ(typed_data_type, object->value.as_typed_data.type);
1699 EXPECT_EQ(len, object->value.as_typed_data.length);
1700}
1701
1702VM_UNIT_TEST_CASE(DartGeneratedListMessagesWithTypedData) {
1703 static const char* kScriptChars =
1704 "import 'dart:typed_data';\n"
1705 "getTypedDataList() {\n"
1706 " var list = List<dynamic>.filled(13, null);\n"
1707 " var index = 0;\n"
1708 " list[index++] = Int8List(256);\n"
1709 " list[index++] = Uint8List(256);\n"
1710 " list[index++] = Int16List(256);\n"
1711 " list[index++] = Uint16List(256);\n"
1712 " list[index++] = Int32List(256);\n"
1713 " list[index++] = Uint32List(256);\n"
1714 " list[index++] = Int64List(256);\n"
1715 " list[index++] = Uint64List(256);\n"
1716 " list[index++] = Float32List(256);\n"
1717 " list[index++] = Float64List(256);\n"
1718 " list[index++] = Int32x4List(256);\n"
1719 " list[index++] = Float32x4List(256);\n"
1720 " list[index++] = Float64x2List(256);\n"
1721 " return list;\n"
1722 "}\n"
1723 "getTypedDataViewList() {\n"
1724 " var list = List<dynamic>.filled(45, null);\n"
1725 " var index = 0;\n"
1726 " list[index++] = Int8List.view(Int8List(256).buffer);\n"
1727 " list[index++] = Uint8List.view(Uint8List(256).buffer);\n"
1728 " list[index++] = Int16List.view(new Int16List(256).buffer);\n"
1729 " list[index++] = Uint16List.view(new Uint16List(256).buffer);\n"
1730 " list[index++] = Int32List.view(new Int32List(256).buffer);\n"
1731 " list[index++] = Uint32List.view(new Uint32List(256).buffer);\n"
1732 " list[index++] = Int64List.view(new Int64List(256).buffer);\n"
1733 " list[index++] = Uint64List.view(new Uint64List(256).buffer);\n"
1734 " list[index++] = Float32List.view(new Float32List(256).buffer);\n"
1735 " list[index++] = Float64List.view(new Float64List(256).buffer);\n"
1736 " list[index++] = Int32x4List.view(new Int32x4List(256).buffer);\n"
1737 " list[index++] = Float32x4List.view(new Float32x4List(256).buffer);\n"
1738 " list[index++] = Float64x2List.view(new Float64x2List(256).buffer);\n"
1739
1740 " list[index++] = Int8List.view(new Int16List(256).buffer);\n"
1741 " list[index++] = Uint8List.view(new Uint16List(256).buffer);\n"
1742 " list[index++] = Int8List.view(new Int32List(256).buffer);\n"
1743 " list[index++] = Uint8List.view(new Uint32List(256).buffer);\n"
1744 " list[index++] = Int8List.view(new Int64List(256).buffer);\n"
1745 " list[index++] = Uint8List.view(new Uint64List(256).buffer);\n"
1746 " list[index++] = Int8List.view(new Float32List(256).buffer);\n"
1747 " list[index++] = Uint8List.view(new Float32List(256).buffer);\n"
1748 " list[index++] = Int8List.view(new Float64List(256).buffer);\n"
1749 " list[index++] = Uint8List.view(new Float64List(256).buffer);\n"
1750 " list[index++] = Int8List.view(new Int32x4List(256).buffer);\n"
1751 " list[index++] = Uint8List.view(new Int32x4List(256).buffer);\n"
1752 " list[index++] = Int8List.view(new Float32x4List(256).buffer);\n"
1753 " list[index++] = Uint8List.view(new Float32x4List(256).buffer);\n"
1754 " list[index++] = Int8List.view(new Float64x2List(256).buffer);\n"
1755 " list[index++] = Uint8List.view(new Float64x2List(256).buffer);\n"
1756
1757 " list[index++] = Int16List.view(new Int8List(256).buffer);\n"
1758 " list[index++] = Uint16List.view(new Uint8List(256).buffer);\n"
1759 " list[index++] = Int16List.view(new Int32List(256).buffer);\n"
1760 " list[index++] = Uint16List.view(new Uint32List(256).buffer);\n"
1761 " list[index++] = Int16List.view(new Int64List(256).buffer);\n"
1762 " list[index++] = Uint16List.view(new Uint64List(256).buffer);\n"
1763 " list[index++] = Int16List.view(new Float32List(256).buffer);\n"
1764 " list[index++] = Uint16List.view(new Float32List(256).buffer);\n"
1765 " list[index++] = Int16List.view(new Float64List(256).buffer);\n"
1766 " list[index++] = Uint16List.view(new Float64List(256).buffer);\n"
1767 " list[index++] = Int16List.view(new Int32x4List(256).buffer);\n"
1768 " list[index++] = Uint16List.view(new Int32x4List(256).buffer);\n"
1769 " list[index++] = Int16List.view(new Float32x4List(256).buffer);\n"
1770 " list[index++] = Uint16List.view(new Float32x4List(256).buffer);\n"
1771 " list[index++] = Int16List.view(new Float64x2List(256).buffer);\n"
1772 " list[index++] = Uint16List.view(new Float64x2List(256).buffer);\n"
1773 " return list;\n"
1774 "}\n"
1775 "getMultipleTypedDataViewList() {\n"
1776 " var list = List<dynamic>.filled(13, null);\n"
1777 " var index = 0;\n"
1778 " var data = Uint8List(256).buffer;\n"
1779 " list[index++] = Int8List.view(data);\n"
1780 " list[index++] = Uint8List.view(data);\n"
1781 " list[index++] = Int16List.view(data);\n"
1782 " list[index++] = Uint16List.view(data);\n"
1783 " list[index++] = Int32List.view(data);\n"
1784 " list[index++] = Uint32List.view(data);\n"
1785 " list[index++] = Int64List.view(data);\n"
1786 " list[index++] = Uint64List.view(data);\n"
1787 " list[index++] = Float32List.view(data);\n"
1788 " list[index++] = Float64List.view(data);\n"
1789 " list[index++] = Int32x4List.view(data);\n"
1790 " list[index++] = Float32x4List.view(data);\n"
1791 " list[index++] = Float64x2List.view(data);\n"
1792 " return list;\n"
1793 "}\n";
1794
1795 TestCase::CreateTestIsolate();
1796 Thread* thread = Thread::Current();
1797 EXPECT(thread->isolate() != NULL);
1798 Dart_EnterScope();
1799
1800 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
1801 EXPECT_VALID(lib);
1802
1803 {
1804 CHECK_API_SCOPE(thread);
1805 TransitionNativeToVM transition(thread);
1806 HANDLESCOPE(thread);
1807 StackZone zone(thread);
1808 {
1809 // Generate a list of Uint8Lists from Dart code.
1810 std::unique_ptr<Message> message = GetSerialized(lib, "getTypedDataList");
1811 ApiNativeScope scope;
1812 Dart_CObject* root = GetDeserialized(message.get());
1813 EXPECT_NOTNULL(root);
1814 EXPECT_EQ(Dart_CObject_kArray, root->type);
1815 struct {
1816 Dart_TypedData_Type type;
1817 int size;
1818 } expected[] = {
1819 {Dart_TypedData_kInt8, 256}, {Dart_TypedData_kUint8, 256},
1820 {Dart_TypedData_kInt16, 512}, {Dart_TypedData_kUint16, 512},
1821 {Dart_TypedData_kInt32, 1024}, {Dart_TypedData_kUint32, 1024},
1822 {Dart_TypedData_kInt64, 2048}, {Dart_TypedData_kUint64, 2048},
1823 {Dart_TypedData_kFloat32, 1024}, {Dart_TypedData_kFloat64, 2048},
1824 {Dart_TypedData_kInt32x4, 4096}, {Dart_TypedData_kFloat32x4, 4096},
1825 {Dart_TypedData_kFloat64x2, 4096}, {Dart_TypedData_kInvalid, -1}};
1826
1827 int i = 0;
1828 while (expected[i].type != Dart_TypedData_kInvalid) {
1829 CheckTypedData(root->value.as_array.values[i], expected[i].type,
1830 expected[i].size);
1831 i++;
1832 }
1833 EXPECT_EQ(i, root->value.as_array.length);
1834 }
1835 {
1836 // Generate a list of Uint8List views from Dart code.
1837 std::unique_ptr<Message> message =
1838 GetSerialized(lib, "getTypedDataViewList");
1839 ApiNativeScope scope;
1840 Dart_CObject* root = GetDeserialized(message.get());
1841 EXPECT_NOTNULL(root);
1842 EXPECT_EQ(Dart_CObject_kArray, root->type);
1843 struct {
1844 Dart_TypedData_Type type;
1845 int size;
1846 } expected[] = {
1847 {Dart_TypedData_kInt8, 256}, {Dart_TypedData_kUint8, 256},
1848 {Dart_TypedData_kInt16, 512}, {Dart_TypedData_kUint16, 512},
1849 {Dart_TypedData_kInt32, 1024}, {Dart_TypedData_kUint32, 1024},
1850 {Dart_TypedData_kInt64, 2048}, {Dart_TypedData_kUint64, 2048},
1851 {Dart_TypedData_kFloat32, 1024}, {Dart_TypedData_kFloat64, 2048},
1852 {Dart_TypedData_kInt32x4, 4096}, {Dart_TypedData_kFloat32x4, 4096},
1853 {Dart_TypedData_kFloat64x2, 4096},
1854
1855 {Dart_TypedData_kInt8, 512}, {Dart_TypedData_kUint8, 512},
1856 {Dart_TypedData_kInt8, 1024}, {Dart_TypedData_kUint8, 1024},
1857 {Dart_TypedData_kInt8, 2048}, {Dart_TypedData_kUint8, 2048},
1858 {Dart_TypedData_kInt8, 1024}, {Dart_TypedData_kUint8, 1024},
1859 {Dart_TypedData_kInt8, 2048}, {Dart_TypedData_kUint8, 2048},
1860 {Dart_TypedData_kInt8, 4096}, {Dart_TypedData_kUint8, 4096},
1861 {Dart_TypedData_kInt8, 4096}, {Dart_TypedData_kUint8, 4096},
1862 {Dart_TypedData_kInt8, 4096}, {Dart_TypedData_kUint8, 4096},
1863
1864 {Dart_TypedData_kInt16, 256}, {Dart_TypedData_kUint16, 256},
1865 {Dart_TypedData_kInt16, 1024}, {Dart_TypedData_kUint16, 1024},
1866 {Dart_TypedData_kInt16, 2048}, {Dart_TypedData_kUint16, 2048},
1867 {Dart_TypedData_kInt16, 1024}, {Dart_TypedData_kUint16, 1024},
1868 {Dart_TypedData_kInt16, 2048}, {Dart_TypedData_kUint16, 2048},
1869 {Dart_TypedData_kInt16, 4096}, {Dart_TypedData_kUint16, 4096},
1870 {Dart_TypedData_kInt16, 4096}, {Dart_TypedData_kUint16, 4096},
1871 {Dart_TypedData_kInt16, 4096}, {Dart_TypedData_kUint16, 4096},
1872
1873 {Dart_TypedData_kInvalid, -1}};
1874
1875 int i = 0;
1876 while (expected[i].type != Dart_TypedData_kInvalid) {
1877 CheckTypedData(root->value.as_array.values[i], expected[i].type,
1878 expected[i].size);
1879 i++;
1880 }
1881 EXPECT_EQ(i, root->value.as_array.length);
1882 }
1883 {
1884 // Generate a list of Uint8Lists from Dart code.
1885 std::unique_ptr<Message> message =
1886 GetSerialized(lib, "getMultipleTypedDataViewList");
1887 ApiNativeScope scope;
1888 Dart_CObject* root = GetDeserialized(message.get());
1889 EXPECT_NOTNULL(root);
1890 EXPECT_EQ(Dart_CObject_kArray, root->type);
1891 struct {
1892 Dart_TypedData_Type type;
1893 int size;
1894 } expected[] = {
1895 {Dart_TypedData_kInt8, 256}, {Dart_TypedData_kUint8, 256},
1896 {Dart_TypedData_kInt16, 256}, {Dart_TypedData_kUint16, 256},
1897 {Dart_TypedData_kInt32, 256}, {Dart_TypedData_kUint32, 256},
1898 {Dart_TypedData_kInt64, 256}, {Dart_TypedData_kUint64, 256},
1899 {Dart_TypedData_kFloat32, 256}, {Dart_TypedData_kFloat64, 256},
1900 {Dart_TypedData_kInt32x4, 256}, {Dart_TypedData_kFloat32x4, 256},
1901 {Dart_TypedData_kFloat64x2, 256}, {Dart_TypedData_kInvalid, -1}};
1902
1903 int i = 0;
1904 while (expected[i].type != Dart_TypedData_kInvalid) {
1905 CheckTypedData(root->value.as_array.values[i], expected[i].type,
1906 expected[i].size);
1907
1908 // All views point to the same data.
1909 EXPECT_EQ(root->value.as_array.values[0]->value.as_typed_data.values,
1910 root->value.as_array.values[i]->value.as_typed_data.values);
1911 i++;
1912 }
1913 EXPECT_EQ(i, root->value.as_array.length);
1914 }
1915 }
1916 Dart_ExitScope();
1917 Dart_ShutdownIsolate();
1918}
1919
1920VM_UNIT_TEST_CASE(PostCObject) {
1921 // Create a native port for posting from C to Dart
1922 TestIsolateScope __test_isolate__;
1923 const char* kScriptChars =
1924 "import 'dart:isolate';\n"
1925 "main() {\n"
1926 " var messageCount = 0;\n"
1927 " var exception = '';\n"
1928 " var port = new RawReceivePort();\n"
1929 " var sendPort = port.sendPort;\n"
1930 " port.handler = (message) {\n"
1931 " if (messageCount < 9) {\n"
1932 " exception = '$exception${message}';\n"
1933 " } else {\n"
1934 " exception = '$exception${message.length}';\n"
1935 " for (int i = 0; i < message.length; i++) {\n"
1936 " exception = '$exception${message[i]}';\n"
1937 " }\n"
1938 " }\n"
1939 " messageCount++;\n"
1940 " if (messageCount == 10) throw new Exception(exception);\n"
1941 " };\n"
1942 " return sendPort;\n"
1943 "}\n";
1944 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
1945 Dart_EnterScope();
1946
1947 Dart_Handle send_port = Dart_Invoke(lib, NewString("main"), 0, NULL);
1948 EXPECT_VALID(send_port);
1949 Dart_Port port_id;
1950 Dart_Handle result = Dart_SendPortGetId(send_port, &port_id);
1951 ASSERT(!Dart_IsError(result));
1952
1953 // Setup single object message.
1954 Dart_CObject object;
1955
1956 object.type = Dart_CObject_kNull;
1957 EXPECT(Dart_PostCObject(port_id, &object));
1958
1959 object.type = Dart_CObject_kBool;
1960 object.value.as_bool = true;
1961 EXPECT(Dart_PostCObject(port_id, &object));
1962
1963 object.type = Dart_CObject_kBool;
1964 object.value.as_bool = false;
1965 EXPECT(Dart_PostCObject(port_id, &object));
1966
1967 object.type = Dart_CObject_kInt32;
1968 object.value.as_int32 = 123;
1969 EXPECT(Dart_PostCObject(port_id, &object));
1970
1971 object.type = Dart_CObject_kString;
1972 object.value.as_string = const_cast<char*>("456");
1973 EXPECT(Dart_PostCObject(port_id, &object));
1974
1975 object.type = Dart_CObject_kString;
1976 object.value.as_string = const_cast<char*>("æøå");
1977 EXPECT(Dart_PostCObject(port_id, &object));
1978
1979 object.type = Dart_CObject_kString;
1980 object.value.as_string = const_cast<char*>("");
1981 EXPECT(Dart_PostCObject(port_id, &object));
1982
1983 object.type = Dart_CObject_kDouble;
1984 object.value.as_double = 3.14;
1985 EXPECT(Dart_PostCObject(port_id, &object));
1986
1987 object.type = Dart_CObject_kArray;
1988 object.value.as_array.length = 0;
1989 EXPECT(Dart_PostCObject(port_id, &object));
1990
1991 static const int kArrayLength = 10;
1992 Dart_CObject* array = reinterpret_cast<Dart_CObject*>(Dart_ScopeAllocate(
1993 sizeof(Dart_CObject) + sizeof(Dart_CObject*) * kArrayLength)); // NOLINT
1994 array->type = Dart_CObject_kArray;
1995 array->value.as_array.length = kArrayLength;
1996 array->value.as_array.values = reinterpret_cast<Dart_CObject**>(array + 1);
1997 for (int i = 0; i < kArrayLength; i++) {
1998 Dart_CObject* element = reinterpret_cast<Dart_CObject*>(
1999 Dart_ScopeAllocate(sizeof(Dart_CObject)));
2000 element->type = Dart_CObject_kInt32;
2001 element->value.as_int32 = i;
2002 array->value.as_array.values[i] = element;
2003 }
2004 EXPECT(Dart_PostCObject(port_id, array));
2005
2006 result = Dart_RunLoop();
2007 EXPECT(Dart_IsError(result));
2008 EXPECT(Dart_ErrorHasException(result));
2009 EXPECT_SUBSTRING("Exception: nulltruefalse123456æøå3.14[]100123456789\n",
2010 Dart_GetError(result));
2011
2012 Dart_ExitScope();
2013}
2014
2015ISOLATE_UNIT_TEST_CASE(OmittedObjectEncodingLength) {
2016 StackZone zone(Thread::Current());
2017 MessageWriter writer(true);
2018 writer.WriteInlinedObjectHeader(kOmittedObjectId);
2019 // For performance, we'd like single-byte headers when ids are omitted.
2020 // If this starts failing, consider renumbering the snapshot ids.
2021 EXPECT_EQ(1, writer.BytesWritten());
2022
2023 free(writer.buffer());
2024}
2025
2026TEST_CASE(IsKernelNegative) {
2027 EXPECT(!Dart_IsKernel(NULL, 0));
2028
2029 uint8_t buffer[4] = {0, 0, 0, 0};
2030 EXPECT(!Dart_IsKernel(buffer, ARRAY_SIZE(buffer)));
2031}
2032
2033VM_UNIT_TEST_CASE(LegacyErasureDetectionInFullSnapshot) {
2034 const char* kScriptChars =
2035 "class Generic<T> {\n"
2036 " const Generic();\n"
2037 " static const Generic<int> g = const Generic<int>();\n"
2038 " static testMain() => g.runtimeType;\n"
2039 "}\n";
2040
2041 // Start an Isolate, load and execute a script and check if legacy erasure is
2042 // required, preventing to write a full snapshot.
2043 {
2044 TestIsolateScope __test_isolate__;
2045
2046 // Create a test library and Load up a test script in it.
2047 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
2048 EXPECT_VALID(lib);
2049
2050 Thread* thread = Thread::Current();
2051 Isolate* isolate = thread->isolate();
2052 ASSERT(isolate == __test_isolate__.isolate());
2053 TransitionNativeToVM transition(thread);
2054 StackZone zone(thread);
2055 HandleScope scope(thread);
2056
2057 Dart_Handle result = Api::CheckAndFinalizePendingClasses(thread);
2058 Dart_Handle cls;
2059 {
2060 TransitionVMToNative to_native(thread);
2061 EXPECT_VALID(result);
2062
2063 // Invoke a function so that the constant is evaluated.
2064 cls = Dart_GetClass(TestCase::lib(), NewString("Generic"));
2065 result = Dart_Invoke(cls, NewString("testMain"), 0, NULL);
2066 EXPECT_VALID(result);
2067 }
2068 // Verify that legacy erasure is required in strong mode.
2069 Type& type = Type::Handle();
2070 type ^= Api::UnwrapHandle(cls); // Dart_GetClass actually returns a Type.
2071 const Class& clazz = Class::Handle(type.type_class());
2072 const bool required = clazz.RequireLegacyErasureOfConstants(zone.GetZone());
2073 EXPECT(required == isolate->null_safety());
2074
2075 // Verify that snapshot writing succeeds if erasure is not required.
2076 if (!required) {
2077 // Write snapshot with object content.
2078 uint8_t* isolate_snapshot_data_buffer;
2079 FullSnapshotWriter writer(
2080 Snapshot::kFull, NULL, &isolate_snapshot_data_buffer,
2081 &malloc_allocator, NULL, /*image_writer*/ nullptr);
2082 writer.WriteFullSnapshot();
2083 free(isolate_snapshot_data_buffer);
2084 }
2085 }
2086}
2087
2088} // namespace dart
2089